From 5b40508c3b03e38a9016ada3ad5fbebb996fc588 Mon Sep 17 00:00:00 2001 From: Carl Christian Snethlage Date: Fri, 10 Jan 2020 23:17:17 +0100 Subject: [PATCH 1/9] Converted GroupDialog to mvvm pattern --- .../org/jabref/gui/groups/GroupDialog.fxml | 118 +++++ .../org/jabref/gui/groups/GroupDialog.java | 4 +- .../jabref/gui/groups/GroupDialogView.java | 148 ++++++ .../gui/groups/GroupDialogViewModel.java | 493 ++++++++++++++++++ .../jabref/gui/groups/GroupTreeViewModel.java | 4 +- src/main/resources/l10n/JabRef_en.properties | 6 +- 6 files changed, 768 insertions(+), 5 deletions(-) create mode 100644 src/main/java/org/jabref/gui/groups/GroupDialog.fxml create mode 100644 src/main/java/org/jabref/gui/groups/GroupDialogView.java create mode 100644 src/main/java/org/jabref/gui/groups/GroupDialogViewModel.java diff --git a/src/main/java/org/jabref/gui/groups/GroupDialog.fxml b/src/main/java/org/jabref/gui/groups/GroupDialog.fxml new file mode 100644 index 00000000000..e1a106660d1 --- /dev/null +++ b/src/main/java/org/jabref/gui/groups/GroupDialog.fxml @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/org/jabref/gui/groups/GroupDialog.java b/src/main/java/org/jabref/gui/groups/GroupDialog.java deleted file mode 100644 index 79ba208797e..00000000000 --- a/src/main/java/org/jabref/gui/groups/GroupDialog.java +++ /dev/null @@ -1,662 +0,0 @@ -package org.jabref.gui.groups; - -import java.io.IOException; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -import javafx.beans.value.ObservableValue; -import javafx.event.ActionEvent; -import javafx.event.EventHandler; -import javafx.geometry.Insets; -import javafx.geometry.Orientation; -import javafx.scene.Node; -import javafx.scene.control.Button; -import javafx.scene.control.ButtonType; -import javafx.scene.control.CheckBox; -import javafx.scene.control.ColorPicker; -import javafx.scene.control.Label; -import javafx.scene.control.RadioButton; -import javafx.scene.control.ScrollPane; -import javafx.scene.control.ScrollPane.ScrollBarPolicy; -import javafx.scene.control.Separator; -import javafx.scene.control.TextField; -import javafx.scene.control.Toggle; -import javafx.scene.control.ToggleGroup; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Priority; -import javafx.scene.layout.StackPane; -import javafx.scene.layout.VBox; -import javafx.scene.text.Font; -import javafx.scene.text.FontPosture; -import javafx.scene.text.TextFlow; - -import org.jabref.Globals; -import org.jabref.JabRefGUI; -import org.jabref.gui.BasePanel; -import org.jabref.gui.DialogService; -import org.jabref.gui.icon.IconTheme; -import org.jabref.gui.search.rules.describer.SearchDescribers; -import org.jabref.gui.util.BaseDialog; -import org.jabref.gui.util.FileDialogConfiguration; -import org.jabref.logic.auxparser.DefaultAuxParser; -import org.jabref.logic.l10n.Localization; -import org.jabref.logic.search.SearchQuery; -import org.jabref.logic.util.StandardFileType; -import org.jabref.logic.util.io.FileUtil; -import org.jabref.model.database.BibDatabase; -import org.jabref.model.entry.Keyword; -import org.jabref.model.entry.field.FieldFactory; -import org.jabref.model.entry.field.StandardField; -import org.jabref.model.groups.AbstractGroup; -import org.jabref.model.groups.AutomaticGroup; -import org.jabref.model.groups.AutomaticKeywordGroup; -import org.jabref.model.groups.AutomaticPersonsGroup; -import org.jabref.model.groups.ExplicitGroup; -import org.jabref.model.groups.GroupHierarchyType; -import org.jabref.model.groups.GroupTreeNode; -import org.jabref.model.groups.RegexKeywordGroup; -import org.jabref.model.groups.SearchGroup; -import org.jabref.model.groups.TexGroup; -import org.jabref.model.groups.WordKeywordGroup; -import org.jabref.model.metadata.MetaData; -import org.jabref.preferences.JabRefPreferences; - -// import com.jfoenix.controls.JFXColorPicker; - -/** - * Dialog for creating or modifying groups. Operates directly on the Vector - * containing group information. - */ -class GroupDialog extends BaseDialog { - - private static final int INDEX_EXPLICIT_GROUP = 0; - private static final int INDEX_KEYWORD_GROUP = 1; - private static final int INDEX_SEARCH_GROUP = 2; - private static final int INDEX_AUTO_GROUP = 3; - private static final int INDEX_TEX_GROUP = 4; - - // for all types - private final TextField nameField = new TextField(); - private final TextField descriptionField = new TextField(); - //private final JFXColorPicker colorField = new JFXColorPicker(); - private final ColorPicker colorField = new ColorPicker(); - 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")); - private final RadioButton searchRadioButton = new RadioButton(Localization.lang("Dynamically group entries by a free-form search expression")); - private final RadioButton autoRadioButton = new RadioButton(Localization.lang("Automatically create groups")); - private final RadioButton texRadioButton = new RadioButton(Localization.lang("Group containing entries cited in a given TeX file")); - private final RadioButton independentButton = new RadioButton(Localization.lang("Independent group: When selected, view only this group's entries")); - private final RadioButton intersectionButton = new RadioButton(Localization.lang("Refine supergroup: When selected, view entries contained in both this group and its supergroup")); - private final RadioButton unionButton = new RadioButton(Localization.lang("Include subgroups: When selected, view entries contained in this group or its subgroups")); - private final DialogService dialogService; - private final JabRefPreferences prefs; - private final BasePanel basePanel; - - // for KeywordGroup - private final TextField keywordGroupSearchTerm = new TextField(); - private final TextField keywordGroupSearchField = new TextField(); - private final CheckBox keywordGroupCaseSensitive = new CheckBox(Localization.lang("Case sensitive")); - private final CheckBox keywordGroupRegExp = new CheckBox(Localization.lang("regular expression")); - - // for SearchGroup - private final TextField searchGroupSearchExpression = new TextField(); - private final CheckBox searchGroupCaseSensitive = new CheckBox(Localization.lang("Case sensitive")); - private final CheckBox searchGroupRegExp = new CheckBox(Localization.lang("regular expression")); - - // for AutoGroup - private final RadioButton autoGroupKeywordsOption = new RadioButton(Localization.lang("Generate groups from keywords in a BibTeX field")); - private final TextField autoGroupKeywordsField = new TextField(); - private final TextField autoGroupKeywordsDeliminator = new TextField(); - private final TextField autoGroupKeywordsHierarchicalDeliminator = new TextField(); - private final RadioButton autoGroupPersonsOption = new RadioButton(Localization.lang("Generate groups for author last names")); - private final TextField autoGroupPersonsField = new TextField(); - - // for TexGroup - private final TextField texGroupFilePath = new TextField(); - private final Button texGroupBrowseButton = new Button("Browse"); - private final HBox texGroupHBox = new HBox(10); - - // for all types - private final TextFlow descriptionTextFlow = new TextFlow(); - private final StackPane optionsPanel = new StackPane(); - - - /** - * Shows a group add/edit dialog. - * - * @param editedGroup The group being edited, or null if a new group is to be - * created. - */ - public GroupDialog(DialogService dialogService, BasePanel basePanel, JabRefPreferences prefs, AbstractGroup editedGroup) { - - if (editedGroup == null) { - this.setTitle(Localization.lang("Add subgroup")); - } else { - this.setTitle(Localization.lang("Edit group")); - } - - explicitRadioButton.setSelected(true); - - descriptionTextFlow.setMinWidth(585); - descriptionTextFlow.setPrefWidth(585); - descriptionTextFlow.setMinHeight(180); - descriptionTextFlow.setPrefHeight(180); - - this.dialogService = dialogService; - this.prefs = prefs; - this.basePanel = basePanel; - - // set default values (overwritten if editedGroup != null) - keywordGroupSearchField.setText(prefs.get(JabRefPreferences.GROUPS_DEFAULT_FIELD)); - - // configure elements - ToggleGroup groupType = new ToggleGroup(); - explicitRadioButton.setToggleGroup(groupType); - keywordsRadioButton.setToggleGroup(groupType); - searchRadioButton.setToggleGroup(groupType); - autoRadioButton.setToggleGroup(groupType); - texRadioButton.setToggleGroup(groupType); - - // Build individual layout cards for each group - VBox explicitPanel = createOptionsExplicitGroup(); - explicitPanel.setVisible(true); - 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 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 descriptionPane = new ScrollPane(descriptionTextFlow); - descriptionPane.setHbarPolicy(ScrollBarPolicy.AS_NEEDED); - descriptionPane.setVbarPolicy(ScrollBarPolicy.AS_NEEDED); - - // create layout - HBox mainPanel = new HBox(15); - getDialogPane().setContent(mainPanel); - mainPanel.setPadding(new Insets(5, 15, 5, 15)); - mainPanel.getChildren().setAll( - new VBox(5, - generalPanel, - new VBox(5, - new Label(Localization.lang("Type")), - selectPanel - ) - ), - new Separator(Orientation.VERTICAL), - new VBox(5, - new VBox( - new Label(Localization.lang("Options")), - optionsPanel - ), - new Label(Localization.lang("Description")), - descriptionPane - ) - ); - - updateComponents(); - - // add listeners - groupType.selectedToggleProperty().addListener((ObservableValue ov, Toggle old_Toggle, - Toggle new_Toggle) -> { - int select = INDEX_EXPLICIT_GROUP; - if (groupType.getSelectedToggle() == explicitRadioButton) { - select = INDEX_EXPLICIT_GROUP; - } else if (groupType.getSelectedToggle() == keywordsRadioButton) { - select = INDEX_KEYWORD_GROUP; - } else if (groupType.getSelectedToggle() == searchRadioButton) { - select = INDEX_SEARCH_GROUP; - } else if (groupType.getSelectedToggle() == autoRadioButton) { - select = INDEX_AUTO_GROUP; - } else if (groupType.getSelectedToggle() == texRadioButton) { - select = INDEX_TEX_GROUP; - } - for (Node n : optionsPanel.getChildren()) { - n.setVisible(false); - } - optionsPanel.getChildren().get(select).setVisible(true); - updateComponents(); - }); - - setResultConverter(button -> { - if (button == ButtonType.OK) { - AbstractGroup resultingGroup = null; - try { - String groupName = nameField.getText().trim(); - if (explicitRadioButton.isSelected()) { - Character keywordDelimiter = Globals.prefs.getKeywordDelimiter(); - if (groupName.contains(Character.toString(keywordDelimiter))) { - dialogService.showWarningDialogAndWait(null, Localization.lang("The group name contains the keyword separator \"%0\" and thus probably does not work as expected.", Character.toString(keywordDelimiter))); - } - - Optional rootGroup = basePanel.getBibDatabaseContext().getMetaData().getGroups(); - if (rootGroup.isPresent()) { - int groupsWithSameName = rootGroup.get().findChildrenSatisfying(group -> group.getName().equals(groupName)).size(); - boolean warnAboutSameName = false; - if ((editedGroup == null) && (groupsWithSameName > 0)) { - // New group but there is already one group with the same name - warnAboutSameName = true; - } - if ((editedGroup != null) && !editedGroup.getName().equals(groupName) && (groupsWithSameName > 0)) { - // Edit group, changed name to something that is already present - warnAboutSameName = true; - } - - if (warnAboutSameName) { - dialogService.showErrorDialogAndWait(Localization.lang("There exists already a group with the same name.", Character.toString(keywordDelimiter))); - return null; - } - } - - resultingGroup = new ExplicitGroup(groupName, getContext(), - keywordDelimiter); - } else if (keywordsRadioButton.isSelected()) { - // regex is correct, otherwise OK would have been disabled - // therefore I don't catch anything here - if (keywordGroupRegExp.isSelected()) { - resultingGroup = new RegexKeywordGroup(groupName, getContext(), - FieldFactory.parseField(keywordGroupSearchField.getText().trim()), keywordGroupSearchTerm.getText().trim(), - keywordGroupCaseSensitive.isSelected()); - } else { - resultingGroup = new WordKeywordGroup(groupName, getContext(), - FieldFactory.parseField(keywordGroupSearchField.getText().trim()), keywordGroupSearchTerm.getText().trim(), - keywordGroupCaseSensitive.isSelected(), Globals.prefs.getKeywordDelimiter(), false); - } - } else if (searchRadioButton.isSelected()) { - resultingGroup = new SearchGroup(groupName, getContext(), searchGroupSearchExpression.getText().trim(), - isCaseSensitive(), isRegex()); - } else if (autoRadioButton.isSelected()) { - if (autoGroupKeywordsOption.isSelected()) { - resultingGroup = new AutomaticKeywordGroup( - groupName, getContext(), - FieldFactory.parseField(autoGroupKeywordsField.getText().trim()), - autoGroupKeywordsDeliminator.getText().charAt(0), - autoGroupKeywordsHierarchicalDeliminator.getText().charAt(0)); - } else { - resultingGroup = new AutomaticPersonsGroup(groupName, getContext(), - FieldFactory.parseField(autoGroupPersonsField.getText().trim())); - } - } else if (texRadioButton.isSelected()) { - resultingGroup = TexGroup.create(groupName, getContext(), - Paths.get(texGroupFilePath.getText().trim()), new DefaultAuxParser(new BibDatabase()), Globals.getFileUpdateMonitor(), basePanel.getBibDatabaseContext().getMetaData()); - } - - resultingGroup.setColor(colorField.getValue()); - resultingGroup.setDescription(descriptionField.getText()); - resultingGroup.setIconName(iconField.getText()); - return resultingGroup; - } catch (IllegalArgumentException | IOException exception) { - dialogService.showErrorDialogAndWait(exception.getLocalizedMessage(), exception); - return null; - } - } - return null; - }); - - nameField.textProperty().addListener((observable, oldValue, newValue) -> updateComponents()); - keywordGroupSearchTerm.textProperty().addListener((observable, oldValue, newValue) -> updateComponents()); - searchGroupSearchExpression.textProperty().addListener((observable, oldValue, newValue) -> updateComponents()); - - EventHandler actionHandler = (ActionEvent e) -> updateComponents(); - nameField.setOnAction(actionHandler); - descriptionField.setOnAction(actionHandler); - iconField.setOnAction(actionHandler); - keywordGroupSearchField.setOnAction(actionHandler); - keywordGroupSearchTerm.setOnAction(actionHandler); - keywordGroupCaseSensitive.setOnAction(actionHandler); - keywordGroupRegExp.setOnAction(actionHandler); - searchGroupSearchExpression.setOnAction(actionHandler); - searchGroupRegExp.setOnAction(actionHandler); - - // configure for current type - if (editedGroup == null) { - // creating new group -> defaults! - colorField.setValue(IconTheme.getDefaultGroupColor()); - explicitRadioButton.setSelected(true); - setContext(GroupHierarchyType.INDEPENDENT); - } else { - nameField.setText(editedGroup.getName()); - colorField.setValue(editedGroup.getColor().orElse(IconTheme.getDefaultGroupColor())); - descriptionField.setText(editedGroup.getDescription().orElse("")); - iconField.setText(editedGroup.getIconName().orElse("")); - setContext(editedGroup.getHierarchicalContext()); - - if (editedGroup.getClass() == WordKeywordGroup.class) { - WordKeywordGroup group = (WordKeywordGroup) editedGroup; - keywordGroupSearchField.setText(group.getSearchField().getName()); - keywordGroupSearchTerm.setText(group.getSearchExpression()); - keywordGroupCaseSensitive.setSelected(group.isCaseSensitive()); - keywordGroupRegExp.setSelected(false); - keywordsRadioButton.setSelected(true); - } else if (editedGroup.getClass() == RegexKeywordGroup.class) { - RegexKeywordGroup group = (RegexKeywordGroup) editedGroup; - keywordGroupSearchField.setText(group.getSearchField().getName()); - keywordGroupSearchTerm.setText(group.getSearchExpression()); - keywordGroupCaseSensitive.setSelected(group.isCaseSensitive()); - keywordGroupRegExp.setSelected(true); - keywordsRadioButton.setSelected(true); - } else if (editedGroup.getClass() == SearchGroup.class) { - SearchGroup group = (SearchGroup) editedGroup; - searchGroupSearchExpression.setText(group.getSearchExpression()); - searchGroupCaseSensitive.setSelected(group.isCaseSensitive()); - searchGroupRegExp.setSelected(group.isRegularExpression()); - searchRadioButton.setSelected(true); - } else if (editedGroup.getClass() == ExplicitGroup.class) { - explicitRadioButton.setSelected(true); - } else if (editedGroup instanceof AutomaticGroup) { - autoRadioButton.setSelected(true); - - if (editedGroup.getClass() == AutomaticKeywordGroup.class) { - AutomaticKeywordGroup group = (AutomaticKeywordGroup) editedGroup; - autoGroupKeywordsDeliminator.setText(group.getKeywordDelimiter().toString()); - autoGroupKeywordsHierarchicalDeliminator.setText(group.getKeywordHierarchicalDelimiter().toString()); - autoGroupKeywordsField.setText(group.getField().getName()); - } else if (editedGroup.getClass() == AutomaticPersonsGroup.class) { - AutomaticPersonsGroup group = (AutomaticPersonsGroup) editedGroup; - autoGroupPersonsField.setText(group.getField().getName()); - } - } else if (editedGroup.getClass() == TexGroup.class) { - texRadioButton.setSelected(true); - - TexGroup group = (TexGroup) editedGroup; - texGroupFilePath.setText(group.getFilePath().toString()); - } - } - getDialogPane().getScene().getWindow().sizeToScene(); - } - - public GroupDialog(DialogService dialogService) { - this(dialogService, JabRefGUI.getMainFrame().getCurrentBasePanel(), Globals.prefs, null); - } - - public GroupDialog(DialogService dialogService, AbstractGroup editedGroup) { - this(dialogService, JabRefGUI.getMainFrame().getCurrentBasePanel(), Globals.prefs, editedGroup); - } - - private VBox createOptionsTexGroup() { - VBox texPanel = new VBox(); - texPanel.setVisible(false); - texPanel.getChildren().add(new Label(Localization.lang("Aux file"))); - texGroupBrowseButton.setOnAction((ActionEvent e) -> openBrowseDialog()); - texGroupHBox.getChildren().add(texGroupFilePath); - texGroupHBox.getChildren().add(texGroupBrowseButton); - HBox.setHgrow(texGroupFilePath, Priority.ALWAYS); - texPanel.getChildren().add(texGroupHBox); - 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(StandardField.AUTHOR.getName()); - 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(); - if (!okEnabled) { - setDescription(Localization.lang("Please enter a name for the group.")); - getDialogPane().lookupButton(ButtonType.OK).setDisable(true); - return; - } - String s1; - String s2; - if (keywordsRadioButton.isSelected()) { - s1 = keywordGroupSearchField.getText().trim(); - okEnabled = okEnabled && s1.matches("\\w+"); - s2 = keywordGroupSearchTerm.getText().trim(); - okEnabled = okEnabled && !s2.isEmpty(); - if (okEnabled) { - if (keywordGroupRegExp.isSelected()) { - try { - Pattern.compile(s2); - setDescription(GroupDescriptions.getDescriptionForPreview(s1, s2, keywordGroupCaseSensitive.isSelected(), - keywordGroupRegExp.isSelected())); - } catch (PatternSyntaxException e) { - okEnabled = false; - setDescription(GroupDescriptions.formatRegexException(s2, e)); - } - } else { - setDescription(GroupDescriptions.getDescriptionForPreview(s1, s2, keywordGroupCaseSensitive.isSelected(), - keywordGroupRegExp.isSelected())); - } - } else { - setDescription(Localization.lang( - "Please enter the field to search (e.g. keywords) and the keyword to search it for (e.g. electrical).")); - } - setNameFontItalic(true); - } else if (searchRadioButton.isSelected()) { - s1 = searchGroupSearchExpression.getText().trim(); - okEnabled = okEnabled & !s1.isEmpty(); - if (okEnabled) { - setDescription(GroupDescriptions.fromTextFlowToHTMLString(SearchDescribers.getSearchDescriberFor( - new SearchQuery(s1, isCaseSensitive(), isRegex())) - .getDescription())); - - if (isRegex()) { - try { - Pattern.compile(s1); - } catch (PatternSyntaxException e) { - okEnabled = false; - setDescription(GroupDescriptions.formatRegexException(s1, e)); - } - } - } else { - setDescription(Localization - .lang("Please enter a search term. For example, to search all fields for Smith, enter:

" - + "smith

" - + "To search the field Author for Smith and the field Title for electrical, enter:

" - + "author=smith and title=electrical")); - } - setNameFontItalic(true); - } else if (explicitRadioButton.isSelected()) { - setDescription(GroupDescriptions.getDescriptionForPreview()); - setNameFontItalic(false); - } - getDialogPane().lookupButton(ButtonType.OK).setDisable(!okEnabled); - } - - private void openBrowseDialog() { - FileDialogConfiguration fileDialogConfiguration = new FileDialogConfiguration.Builder() - .addExtensionFilter(StandardFileType.AUX) - .withDefaultExtension(StandardFileType.AUX) - .withInitialDirectory(Globals.prefs.get(JabRefPreferences.WORKING_DIRECTORY)).build(); - dialogService.showFileOpenDialog(fileDialogConfiguration).ifPresent(file -> texGroupFilePath.setText(relativize(file.toAbsolutePath()).toString())); - } - - private Path relativize(Path path) { - List fileDirectories = getFileDirectoriesAsPaths(); - return FileUtil.relativize(path, fileDirectories); - } - - private List getFileDirectoriesAsPaths() { - List fileDirs = new ArrayList<>(); - MetaData metaData = basePanel.getBibDatabaseContext().getMetaData(); - metaData.getLaTexFileDirectory(prefs.getFilePreferences().getUser()) - .ifPresent(laTexFileDirectory -> fileDirs.add(laTexFileDirectory)); - - return fileDirs; - } - - private boolean isRegex() { - return searchGroupRegExp.isSelected(); - } - - private boolean isCaseSensitive() { - return searchGroupCaseSensitive.isSelected(); - } - - private void setDescription(String description) { - descriptionTextFlow.getChildren().setAll(GroupDescriptions.createFormattedDescription(description)); - } - - /** - * Sets the font of the name entry field. - */ - private void setNameFontItalic(boolean italic) { - Font f = nameField.getFont(); - if (italic) { - Font.font(f.getFamily(), FontPosture.ITALIC, f.getSize()); - } else { - Font.font(f.getFamily(), FontPosture.REGULAR, f.getSize()); - } - } - - /** - * Returns the int representing the selected hierarchical group context. - */ - private GroupHierarchyType getContext() { - if (independentButton.isSelected()) { - return GroupHierarchyType.INDEPENDENT; - } - if (intersectionButton.isSelected()) { - return GroupHierarchyType.REFINING; - } - if (unionButton.isSelected()) { - return GroupHierarchyType.INCLUDING; - } - return GroupHierarchyType.INDEPENDENT; // default - } - - private void setContext(GroupHierarchyType context) { - switch (context) { - case INDEPENDENT: - independentButton.setSelected(true); - break; - case REFINING: - intersectionButton.setSelected(true); - break; - case INCLUDING: - unionButton.setSelected(true); - break; - } - } -} diff --git a/src/main/java/org/jabref/gui/groups/GroupDialogView.java b/src/main/java/org/jabref/gui/groups/GroupDialogView.java index eb7b84e1d14..57643a7ab68 100644 --- a/src/main/java/org/jabref/gui/groups/GroupDialogView.java +++ b/src/main/java/org/jabref/gui/groups/GroupDialogView.java @@ -1,10 +1,6 @@ package org.jabref.gui.groups; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - import javafx.application.Platform; -import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.ButtonType; import javafx.scene.control.CheckBox; @@ -12,19 +8,15 @@ import javafx.scene.control.ComboBox; import javafx.scene.control.RadioButton; import javafx.scene.control.TextField; -import javafx.scene.input.KeyEvent; -import javafx.scene.text.TextFlow; import org.jabref.Globals; import org.jabref.JabRefGUI; import org.jabref.gui.BasePanel; import org.jabref.gui.DialogService; -import org.jabref.gui.search.rules.describer.SearchDescribers; import org.jabref.gui.util.BaseDialog; import org.jabref.gui.util.IconValidationDecorator; import org.jabref.gui.util.ViewModelListCellFactory; import org.jabref.logic.l10n.Localization; -import org.jabref.logic.search.SearchQuery; import org.jabref.model.groups.AbstractGroup; import org.jabref.model.groups.GroupHierarchyType; import org.jabref.preferences.JabRefPreferences; @@ -67,17 +59,11 @@ public class GroupDialogView extends BaseDialog { @FXML private TextField texGroupFilePath; - // Description text - @FXML private TextFlow hintTextFlow; - private final ControlsFxVisualizer validationVisualizer = new ControlsFxVisualizer(); private final GroupDialogViewModel viewModel; - private final boolean showHints; - public GroupDialogView(DialogService dialogService, BasePanel basePanel, JabRefPreferences prefs, AbstractGroup editedGroup) { viewModel = new GroupDialogViewModel(dialogService, basePanel, prefs, editedGroup); - this.showHints = prefs.getBoolean(JabRefPreferences.SHOW_ADVANCED_HINTS); ViewLoader.view(this) .load() @@ -86,14 +72,9 @@ public GroupDialogView(DialogService dialogService, BasePanel basePanel, JabRefP if (editedGroup == null) { this.setTitle(Localization.lang("Add subgroup")); } else { - this.setTitle(Localization.lang("Edit group")); + this.setTitle(Localization.lang("Edit group") + " " + editedGroup.getName()); } - if (showHints) { - hintTextFlow.setPrefHeight(0d); - } - hintTextFlow.setVisible(showHints); - setResultConverter(viewModel::resultConverter); getDialogPane().getButtonTypes().setAll(ButtonType.OK, ButtonType.CANCEL); @@ -170,8 +151,6 @@ public void initialize() { texGroupFilePath.textProperty().bindBidirectional(viewModel.texGroupFilePathProperty()); - hintTextFlow.accessibleTextProperty().bindBidirectional(viewModel.hintTextProperty()); - validationVisualizer.setDecoration(new IconValidationDecorator()); Platform.runLater(() -> { validationVisualizer.initVisualization(viewModel.nameValidationStatus(), nameField); @@ -183,25 +162,14 @@ public void initialize() { validationVisualizer.initVisualization(viewModel.keywordSearchTermEmptyValidationStatus(), keywordGroupSearchTerm); }); - // ToDo: This comes straight from hell - - nameField.textProperty().addListener((obs, oldval, newval) -> updateComponents()); - keywordGroupSearchTerm.textProperty().addListener((obs, oldval, newval) -> updateComponents()); - searchGroupSearchTerm.textProperty().addListener((obs, oldval, newval) -> updateComponents()); - - nameField.addEventHandler(KeyEvent.KEY_RELEASED, e -> updateComponents()); - descriptionField.addEventHandler(KeyEvent.KEY_RELEASED, e -> updateComponents()); - iconField.addEventHandler(KeyEvent.KEY_RELEASED, e -> updateComponents()); - keywordGroupSearchField.addEventHandler(KeyEvent.KEY_RELEASED, e -> updateComponents()); - keywordGroupSearchTerm.addEventHandler(KeyEvent.KEY_RELEASED, e -> updateComponents()); - keywordGroupCaseSensitive.addEventHandler(ActionEvent.ANY, e -> updateComponents()); - keywordGroupRegex.addEventHandler(ActionEvent.ANY, e -> updateComponents()); - searchGroupSearchTerm.addEventHandler(ActionEvent.ANY, e -> updateComponents()); - searchGroupCaseSensitive.addEventHandler(ActionEvent.ANY, e -> updateComponents()); - searchGroupRegex.addEventHandler(ActionEvent.ANY, e -> updateComponents()); - - // NPE - // getDialogPane().lookupButton(ButtonType.OK).disableProperty().bind(viewModel.validationStatus().validProperty().not()); + // Binding to the validProperty throws an NPE, so we have to work around this issue + viewModel.validationStatus().validProperty().addListener((obs, oldValue, newValue) -> { + if (newValue) { + getDialogPane().lookupButton(ButtonType.OK).setDisable(false); + } else { + getDialogPane().lookupButton(ButtonType.OK).setDisable(true); + } + }); } @FXML @@ -209,64 +177,8 @@ private void texGroupBrowse() { viewModel.texGroupBrowse(); } - // ToDo: The following lines NEED to be changed! - - private void updateComponents() { - if (!showHints) { - return; - } - - String searchField; - String searchTerm; - if (keywordsRadioButton.isSelected()) { - searchField = keywordGroupSearchField.getText().trim(); - searchTerm = keywordGroupSearchTerm.getText().trim(); - if (searchField.matches("\\w+") && !searchTerm.isEmpty()) { - if (keywordGroupRegex.isSelected()) { - try { - Pattern.compile(searchTerm); - setDescription(GroupDescriptions.getDescriptionForPreview(searchField, searchTerm, keywordGroupCaseSensitive.isSelected(), - keywordGroupRegex.isSelected())); - } catch (PatternSyntaxException e) { - setDescription(GroupDescriptions.formatRegexException(searchTerm, e)); - } - } else { - setDescription(GroupDescriptions.getDescriptionForPreview(searchField, searchTerm, keywordGroupCaseSensitive.isSelected(), - keywordGroupRegex.isSelected())); - } - } else { - setDescription(Localization.lang( - "Please enter the field to search (e.g. keywords) and the keyword to search it for (e.g. electrical).")); - } - } else if (searchRadioButton.isSelected()) { - searchTerm = searchGroupSearchTerm.getText().trim(); - if (!searchTerm.isEmpty()) { - setDescription(GroupDescriptions.fromTextFlowToHTMLString(SearchDescribers - .getSearchDescriberFor(new SearchQuery( - searchTerm, - searchGroupCaseSensitive.isSelected(), - searchGroupRegex.isSelected())) - .getDescription())); - if (searchGroupRegex.isSelected()) { - try { - Pattern.compile(searchTerm); - } catch (PatternSyntaxException e) { - setDescription(GroupDescriptions.formatRegexException(searchTerm, e)); - } - } - } else { - setDescription(Localization - .lang("Please enter a search term. For example, to search all fields for Smith, enter:

" - + "smith

" - + "To search the field Author for Smith and the field Title for electrical, enter:

" - + "author=smith and title=electrical")); - } - } else if (explicitRadioButton.isSelected()) { - setDescription(GroupDescriptions.getDescriptionForPreview()); - } - } - - private void setDescription(String description) { - hintTextFlow.getChildren().setAll(GroupDescriptions.createFormattedDescription(description)); + @FXML + private void openHelp() { + viewModel.openHelpPage(); } } diff --git a/src/main/java/org/jabref/gui/groups/GroupDialogViewModel.java b/src/main/java/org/jabref/gui/groups/GroupDialogViewModel.java index 2034d81a05c..4d3101be4d6 100644 --- a/src/main/java/org/jabref/gui/groups/GroupDialogViewModel.java +++ b/src/main/java/org/jabref/gui/groups/GroupDialogViewModel.java @@ -24,9 +24,11 @@ import org.jabref.Globals; import org.jabref.gui.BasePanel; import org.jabref.gui.DialogService; +import org.jabref.gui.help.HelpAction; import org.jabref.gui.icon.IconTheme; import org.jabref.gui.util.FileDialogConfiguration; import org.jabref.logic.auxparser.DefaultAuxParser; +import org.jabref.logic.help.HelpFile; import org.jabref.logic.l10n.Localization; import org.jabref.logic.util.StandardFileType; import org.jabref.logic.util.io.FileUtil; @@ -89,9 +91,6 @@ public class GroupDialogViewModel { private final StringProperty texGroupFilePathProperty = new SimpleStringProperty(""); - // Description text - private final StringProperty hintTextProperty = new SimpleStringProperty(""); - private Validator nameValidator; private Validator nameContainsDelimiterValidator; private Validator sameNameValidator; @@ -99,7 +98,7 @@ public class GroupDialogViewModel { private Validator keywordSearchTermEmptyValidator; private Validator searchRegexValidator; private Validator searchSearchTermEmptyValidator; - private CompositeValidator validator; + private CompositeValidator validator = new CompositeValidator(); private final DialogService dialogService; private final JabRefPreferences preferences; @@ -173,11 +172,10 @@ private void setupValidation() { return false; } }, - ValidationMessage.error(String.format("%s > %n %s %n %n %s %n %s", + ValidationMessage.error(String.format("%s > %n %s %n %n %s", Localization.lang("Searching for keywords"), Localization.lang("Keywords"), - Localization.lang("Invalid regular expression:"), - keywordGroupSearchTermProperty.getValue()))); + Localization.lang("Invalid regular expression.")))); keywordSearchTermEmptyValidator = new FunctionBasedValidator<>( keywordGroupSearchTermProperty, @@ -206,10 +204,9 @@ private void setupValidation() { return false; } }, - ValidationMessage.error(String.format("%s > %n %s %n %s", + ValidationMessage.error(String.format("%s > %n %s", Localization.lang("Free search expression"), - Localization.lang("Invalid regular expression:"), - searchGroupSearchTermProperty.getValue()))); + Localization.lang("Invalid regular expression.")))); searchSearchTermEmptyValidator = new FunctionBasedValidator<>( searchGroupSearchTermProperty, @@ -219,7 +216,7 @@ private void setupValidation() { Localization.lang("Search term is empty.") ))); - validator = new CompositeValidator(nameValidator,sameNameValidator); + validator.addValidators(nameValidator, sameNameValidator); typeSearchProperty.addListener((obs,oldVal,newVal) -> { if (newVal) { @@ -336,51 +333,32 @@ public void setValues() { groupHierarchySelectedProperty.setValue(editedGroup.getHierarchicalContext()); if (editedGroup.getClass() == WordKeywordGroup.class) { + typeKeywordsProperty.setValue(true); + WordKeywordGroup group = (WordKeywordGroup) editedGroup; keywordGroupSearchFieldProperty.setValue(group.getSearchField().getName()); keywordGroupSearchTermProperty.setValue(group.getSearchExpression()); keywordGroupCaseSensitiveProperty.setValue(group.isCaseSensitive()); keywordGroupRegexProperty.setValue(false); - - typeExplicitProperty.setValue(false); - typeKeywordsProperty.setValue(true); - typeSearchProperty.setValue(false); - typeAutoProperty.setValue(false); - typeTexProperty.setValue(false); } else if (editedGroup.getClass() == RegexKeywordGroup.class) { + typeKeywordsProperty.setValue(true); + RegexKeywordGroup group = (RegexKeywordGroup) editedGroup; keywordGroupSearchFieldProperty.setValue(group.getSearchField().getName()); keywordGroupSearchTermProperty.setValue(group.getSearchExpression()); keywordGroupCaseSensitiveProperty.setValue(group.isCaseSensitive()); keywordGroupRegexProperty.setValue(true); - - typeExplicitProperty.setValue(false); - typeKeywordsProperty.setValue(true); - typeSearchProperty.setValue(false); - typeAutoProperty.setValue(false); - typeTexProperty.setValue(false); } else if (editedGroup.getClass() == SearchGroup.class) { + typeSearchProperty.setValue(true); + SearchGroup group = (SearchGroup) editedGroup; searchGroupSearchTermProperty.setValue(group.getSearchExpression()); searchGroupCaseSensitiveProperty.setValue(group.isCaseSensitive()); searchGroupRegexProperty.setValue(group.isRegularExpression()); - - typeExplicitProperty.setValue(false); - typeKeywordsProperty.setValue(false); - typeSearchProperty.setValue(true); - typeAutoProperty.setValue(false); - typeTexProperty.setValue(false); } else if (editedGroup.getClass() == ExplicitGroup.class) { typeExplicitProperty.setValue(true); - typeKeywordsProperty.setValue(false); - typeSearchProperty.setValue(false); - typeAutoProperty.setValue(false); } else if (editedGroup instanceof AutomaticGroup) { - typeExplicitProperty.setValue(false); - typeKeywordsProperty.setValue(false); - typeSearchProperty.setValue(false); typeAutoProperty.setValue(true); - typeTexProperty.setValue(false); if (editedGroup.getClass() == AutomaticKeywordGroup.class) { AutomaticKeywordGroup group = (AutomaticKeywordGroup) editedGroup; @@ -392,10 +370,6 @@ public void setValues() { autoGroupPersonsFieldProperty.setValue(group.getField().getName()); } } else if (editedGroup.getClass() == TexGroup.class) { - typeExplicitProperty.setValue(false); - typeKeywordsProperty.setValue(false); - typeSearchProperty.setValue(false); - typeAutoProperty.setValue(false); typeTexProperty.setValue(true); TexGroup group = (TexGroup) editedGroup; @@ -415,6 +389,10 @@ public void texGroupBrowse() { )); } + public void openHelpPage() { + HelpAction.openHelpPage(HelpFile.GROUPS); + } + private List getFileDirectoriesAsPaths() { List fileDirs = new ArrayList<>(); MetaData metaData = basePanel.getBibDatabaseContext().getMetaData(); @@ -488,6 +466,4 @@ private List getFileDirectoriesAsPaths() { public StringProperty autoGroupPersonsFieldProperty() { return autoGroupPersonsFieldProperty; } public StringProperty texGroupFilePathProperty() { return texGroupFilePathProperty; } - - public StringProperty hintTextProperty() { return hintTextProperty; } } diff --git a/src/main/java/org/jabref/logic/help/HelpFile.java b/src/main/java/org/jabref/logic/help/HelpFile.java index 6e5ce34fc12..b08b088c510 100644 --- a/src/main/java/org/jabref/logic/help/HelpFile.java +++ b/src/main/java/org/jabref/logic/help/HelpFile.java @@ -10,6 +10,7 @@ public enum HelpFile { CONTENTS(""), // this is always the index ENTRY_EDITOR("general/entryeditor"), STRING_EDITOR("setup/stringeditor"), + GROUPS("finding-sorting-and-cleaning-entries/groups#groups-structure-creating-and-removing-groups"), SPECIAL_FIELDS("fields/specialfields"), BIBTEX_KEY_PATTERN("setup/bibtexkeypatterns"), OWNER("fields/owner"), diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index f04e3bae199..bc2ccc8a1fd 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -49,8 +49,6 @@ Added\ group\ "%0".=Added group "%0". Added\ string=Added string -Additionally,\ entries\ whose\ %0\ field\ does\ not\ contain\ %1\ can\ be\ assigned\ manually\ to\ this\ group\ by\ selecting\ them\ then\ using\ either\ drag\ and\ drop\ or\ the\ context\ menu.\ This\ process\ adds\ the\ term\ %1\ to\ each\ entry's\ %0\ field.\ Entries\ can\ be\ removed\ manually\ from\ this\ group\ by\ selecting\ them\ then\ using\ the\ context\ menu.\ This\ process\ removes\ the\ term\ %1\ from\ each\ entry's\ %0\ field.=Additionally, entries whose %0 field does not contain %1 can be assigned manually to this group by selecting them then using either drag and drop or the context menu. This process adds the term %1 to each entry's %0 field. Entries can be removed manually from this group by selecting them then using the context menu. This process removes the term %1 from each entry's %0 field. - Advanced=Advanced All\ entries=All entries All\ entries\ of\ this\ type\ will\ be\ declared\ typeless.\ Continue?=All entries of this type will be declared typeless. Continue? @@ -290,11 +288,8 @@ Enter\ URL\ to\ download=Enter URL to download entries=entries -Entries\ cannot\ be\ manually\ assigned\ to\ or\ removed\ from\ this\ group.=Entries cannot be manually assigned to or removed from this group. - Entries\ exported\ to\ clipboard=Entries exported to clipboard - entry=entry Entry\ editor=Entry editor @@ -639,10 +634,6 @@ File\ has\ no\ attached\ annotations=File has no attached annotations Please\ enter\ a\ name\ for\ the\ group.=Please enter a name for the group. -Please\ enter\ a\ search\ term.\ For\ example,\ to\ search\ all\ fields\ for\ Smith,\ enter\:

smith

To\ search\ the\ field\ Author\ for\ Smith\ and\ the\ field\ Title\ for\ electrical,\ enter\:

author\=smith\ and\ title\=electrical=Please enter a search term. For example, to search all fields for Smith, enter:

smith

To search the field Author for Smith and the field Title for electrical, enter:

author=smith and title=electrical - -Please\ enter\ the\ field\ to\ search\ (e.g.\ keywords)\ and\ the\ keyword\ to\ search\ it\ for\ (e.g.\ electrical).=Please enter the field to search (e.g. keywords) and the keyword to search it for (e.g. electrical). - Please\ enter\ the\ string's\ label=Please enter the string's label Please\ restart\ JabRef\ for\ preferences\ to\ take\ effect.=Please restart JabRef for preferences to take effect. @@ -874,20 +865,12 @@ The\ label\ of\ the\ string\ cannot\ contain\ the\ '\#'\ character.=The label of The\ output\ option\ depends\ on\ a\ valid\ import\ option.=The output option depends on a valid import option. -The\ regular\ expression\ %0\ is\ invalid\:=The regular expression %0 is invalid: - The\ search\ is\ case\ insensitive.=The search is case insensitive. The\ search\ is\ case\ sensitive.=The search is case sensitive. There\ are\ possible\ duplicates\ (marked\ with\ an\ icon)\ that\ haven't\ been\ resolved.\ Continue?=There are possible duplicates (marked with an icon) that haven't been resolved. Continue? -This\ group\ contains\ entries\ based\ on\ manual\ assignment.\ Entries\ can\ be\ assigned\ to\ this\ group\ by\ selecting\ them\ then\ using\ either\ drag\ and\ drop\ or\ the\ context\ menu.\ Entries\ can\ be\ removed\ from\ this\ group\ by\ selecting\ them\ then\ using\ the\ context\ menu.=This group contains entries based on manual assignment. Entries can be assigned to this group by selecting them then using either drag and drop or the context menu. Entries can be removed from this group by selecting them then using the context menu. - -This\ group\ contains\ entries\ whose\ %0\ field\ contains\ the\ keyword\ %1=This group contains entries whose %0 field contains the keyword %1 - -This\ group\ contains\ entries\ whose\ %0\ field\ contains\ the\ regular\ expression\ %1=This group contains entries whose %0 field contains the regular expression %1 - This\ operation\ requires\ all\ selected\ entries\ to\ have\ BibTeX\ keys\ defined.=This operation requires all selected entries to have BibTeX keys defined. This\ operation\ requires\ one\ or\ more\ entries\ to\ be\ selected.=This operation requires one or more entries to be selected. @@ -1027,8 +1010,6 @@ Could\ not\ save,\ file\ locked\ by\ another\ JabRef\ instance.=Could not save, Metadata\ change=Metadata change The\ following\ metadata\ changed\:=The following metadata changed: -Generate\ groups\ for\ author\ last\ names=Generate groups for author last names -Generate\ groups\ from\ keywords\ in\ a\ BibTeX\ field=Generate groups from keywords in a BibTeX field Enforce\ legal\ characters\ in\ BibTeX\ keys=Enforce legal characters in BibTeX keys Unable\ to\ create\ backup=Unable to create backup @@ -1222,7 +1203,7 @@ Not\ connected\ to\ any\ Writer\ document.\ Please\ make\ sure\ a\ document\ is\ Removed\ all\ subgroups\ of\ group\ "%0".=Removed all subgroups of group "%0". To\ disable\ the\ memory\ stick\ mode\ rename\ or\ remove\ the\ jabref.xml\ file\ in\ the\ same\ folder\ as\ JabRef.=To disable the memory stick mode rename or remove the jabref.xml file in the same folder as JabRef. Unable\ to\ connect.\ One\ possible\ reason\ is\ that\ JabRef\ and\ OpenOffice/LibreOffice\ are\ not\ both\ running\ in\ either\ 32\ bit\ mode\ or\ 64\ bit\ mode.=Unable to connect. One possible reason is that JabRef and OpenOffice/LibreOffice are not both running in either 32 bit mode or 64 bit mode. -Delimiter\ character(s)\:=Delimiter character(s): +Delimiter(s)=Delimiter(s) When\ downloading\ files,\ or\ moving\ linked\ files\ to\ the\ file\ directory,\ prefer\ the\ BIB\ file\ location\ rather\ than\ the\ file\ directory\ set\ above=When downloading files, or moving linked files to the file directory, prefer the BIB file location rather than the file directory set above Your\ style\ file\ specifies\ the\ character\ format\ '%0',\ which\ is\ undefined\ in\ your\ current\ OpenOffice/LibreOffice\ document.=Your style file specifies the character format '%0', which is undefined in your current OpenOffice/LibreOffice document. Your\ style\ file\ specifies\ the\ paragraph\ format\ '%0',\ which\ is\ undefined\ in\ your\ current\ OpenOffice/LibreOffice\ document.=Your style file specifies the paragraph format '%0', which is undefined in your current OpenOffice/LibreOffice document. @@ -1941,7 +1922,6 @@ Server\ Timezone\:=Server Timezone\: Remember\ Password=Remember Password Use\ SSL=Use SSL Move\ preprint\ information\ from\ 'URL'\ and\ 'journal'\ field\ to\ the\ 'eprint'\ field=Move preprint information from 'URL' and 'journal' field to the 'eprint' field -Type=Type Customize\ Export\ Formats=Customize Export Formats Export\ name=Export name Main\ layout\ file\:=Main layout file\: @@ -2104,8 +2084,6 @@ Dismiss=Dismiss Mark\ all\ changes\ as\ accepted=Mark all changes as accepted Unmark\ all\ changes=Unmark all changes -Invalid\ regular\ expression\:=Invalid regular expression: - Independent=Independent Intersection=Intersection Union=Union @@ -2116,3 +2094,4 @@ Free\ search\ expression=Free search expression Specified\ keywords=Specified keywords Cited\ entries=Cited entries Search\ term\ is\ empty.=Search term is empty. +Invalid\ regular\ expression.=Invalid regular expression. From 84bece2a2a60c1f4d42816cb80bde92583a5336c Mon Sep 17 00:00:00 2001 From: Carl Christian Snethlage Date: Sun, 19 Jan 2020 00:07:27 +0100 Subject: [PATCH 5/9] Minor visual adjustments --- src/main/java/org/jabref/gui/Base.css | 2 +- .../org/jabref/gui/groups/GroupDialog.fxml | 26 ++++++++++++------- src/main/resources/l10n/JabRef_en.properties | 2 +- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/jabref/gui/Base.css b/src/main/java/org/jabref/gui/Base.css index 8392be71d72..c136404b276 100644 --- a/src/main/java/org/jabref/gui/Base.css +++ b/src/main/java/org/jabref/gui/Base.css @@ -311,7 +311,7 @@ .button { -fx-background-color: transparent; - -fx-border-color: rgba(0, 0, 0, 0.23); + -fx-border-color: -fx-outer-border; /* rgba(0, 0, 0, 0.23); */ -fx-border-width: 1px; -fx-border-radius: 4px; -fx-padding: 0.5em 1em 0.5em 1em; diff --git a/src/main/java/org/jabref/gui/groups/GroupDialog.fxml b/src/main/java/org/jabref/gui/groups/GroupDialog.fxml index 8b2b424ccf5..7fc0e3ffbf4 100644 --- a/src/main/java/org/jabref/gui/groups/GroupDialog.fxml +++ b/src/main/java/org/jabref/gui/groups/GroupDialog.fxml @@ -89,7 +89,7 @@ - + - + - + - @@ -129,7 +137,7 @@ - diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 8fa2298153b..e5d81ddaab3 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -343,7 +343,7 @@ field=field Field\ name=Field name Field\ names\ are\ not\ allowed\ to\ contain\ white\ space\ or\ the\ following\ characters=Field names are not allowed to contain white space or the following characters -Field\ to\ group\ by\:=Field to group by: +Field\ to\ group\ by=Field to group by File=File From 3579f6e71acd757b12acb691c30fa29b2528e136 Mon Sep 17 00:00:00 2001 From: Carl Christian Snethlage Date: Sun, 19 Jan 2020 00:18:43 +0100 Subject: [PATCH 6/9] forgotten l10n resources --- 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 e5d81ddaab3..4d0d676e0d4 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -2095,3 +2095,5 @@ Specified\ keywords=Specified keywords Cited\ entries=Cited entries Search\ term\ is\ empty.=Search term is empty. Invalid\ regular\ expression.=Invalid regular expression. +Keyword\ delimiter=Keyword delimiter +Hierarchical\ keyword\ delimiter=Hierarchical keyword delimiter From 64c3c6e9a91713fd7198a12376bc98bbafa080a0 Mon Sep 17 00:00:00 2001 From: Carl Christian Snethlage Date: Tue, 21 Jan 2020 12:12:41 +0100 Subject: [PATCH 7/9] Minor refactoring, and changed comment --- src/main/java/org/jabref/gui/groups/GroupDialogViewModel.java | 2 +- .../java/org/jabref/gui/maintable/MainTableColumnFactory.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/groups/GroupDialogViewModel.java b/src/main/java/org/jabref/gui/groups/GroupDialogViewModel.java index 4d3101be4d6..a4c36108322 100644 --- a/src/main/java/org/jabref/gui/groups/GroupDialogViewModel.java +++ b/src/main/java/org/jabref/gui/groups/GroupDialogViewModel.java @@ -113,7 +113,7 @@ public GroupDialogViewModel(DialogService dialogService, BasePanel basePanel, Ja this.basePanel = basePanel; this.editedGroup = editedGroup; - this.keywordDelimiter = Globals.prefs.getKeywordDelimiter(); + this.keywordDelimiter = preferences.getKeywordDelimiter(); setupValidation(); setValues(); diff --git a/src/main/java/org/jabref/gui/maintable/MainTableColumnFactory.java b/src/main/java/org/jabref/gui/maintable/MainTableColumnFactory.java index d927845200a..bde67b260aa 100644 --- a/src/main/java/org/jabref/gui/maintable/MainTableColumnFactory.java +++ b/src/main/java/org/jabref/gui/maintable/MainTableColumnFactory.java @@ -131,7 +131,7 @@ private void setExactWidth(TableColumn column, double width) { } /** - * Creates a text column to display any standard field. + * Creates a column with a continous number */ private TableColumn createIndexColumn(MainTableColumnModel columnModel) { TableColumn column = new MainTableColumn<>(columnModel); From a7db26ee64b178e359d69be7bc676b709b0d46b8 Mon Sep 17 00:00:00 2001 From: Carl Christian Snethlage Date: Sat, 25 Jan 2020 21:40:37 +0100 Subject: [PATCH 8/9] Refactored constructors, PreferencesService and some minor improvements. --- .../org/jabref/gui/groups/GroupDialog.fxml | 21 ++-- .../jabref/gui/groups/GroupDialogView.java | 63 +++------- .../gui/groups/GroupDialogViewModel.java | 36 +++--- .../org/jabref/gui/groups/GroupTreeView.java | 5 +- .../jabref/gui/groups/GroupTreeViewModel.java | 119 ++++++++++-------- 5 files changed, 119 insertions(+), 125 deletions(-) diff --git a/src/main/java/org/jabref/gui/groups/GroupDialog.fxml b/src/main/java/org/jabref/gui/groups/GroupDialog.fxml index 7fc0e3ffbf4..797af93a1ad 100644 --- a/src/main/java/org/jabref/gui/groups/GroupDialog.fxml +++ b/src/main/java/org/jabref/gui/groups/GroupDialog.fxml @@ -39,9 +39,20 @@ + + - diff --git a/src/main/java/org/jabref/gui/groups/GroupDialogView.java b/src/main/java/org/jabref/gui/groups/GroupDialogView.java index 57643a7ab68..67b7122c553 100644 --- a/src/main/java/org/jabref/gui/groups/GroupDialogView.java +++ b/src/main/java/org/jabref/gui/groups/GroupDialogView.java @@ -1,5 +1,7 @@ package org.jabref.gui.groups; +import java.util.EnumMap; + import javafx.application.Platform; import javafx.fxml.FXML; import javafx.scene.control.ButtonType; @@ -9,17 +11,15 @@ import javafx.scene.control.RadioButton; import javafx.scene.control.TextField; -import org.jabref.Globals; -import org.jabref.JabRefGUI; -import org.jabref.gui.BasePanel; import org.jabref.gui.DialogService; import org.jabref.gui.util.BaseDialog; import org.jabref.gui.util.IconValidationDecorator; import org.jabref.gui.util.ViewModelListCellFactory; import org.jabref.logic.l10n.Localization; +import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.groups.AbstractGroup; import org.jabref.model.groups.GroupHierarchyType; -import org.jabref.preferences.JabRefPreferences; +import org.jabref.preferences.PreferencesService; import com.airhacks.afterburner.views.ViewLoader; import de.saxsys.mvvmfx.utils.validation.visualization.ControlsFxVisualizer; @@ -59,11 +59,14 @@ public class GroupDialogView extends BaseDialog { @FXML private TextField texGroupFilePath; + private final EnumMap hierarchyText = new EnumMap<>(GroupHierarchyType.class); + private final EnumMap hierarchyToolTip = new EnumMap<>(GroupHierarchyType.class); + private final ControlsFxVisualizer validationVisualizer = new ControlsFxVisualizer(); private final GroupDialogViewModel viewModel; - public GroupDialogView(DialogService dialogService, BasePanel basePanel, JabRefPreferences prefs, AbstractGroup editedGroup) { - viewModel = new GroupDialogViewModel(dialogService, basePanel, prefs, editedGroup); + public GroupDialogView(DialogService dialogService, BibDatabaseContext currentDatabase, PreferencesService preferencesService, AbstractGroup editedGroup) { + viewModel = new GroupDialogViewModel(dialogService, currentDatabase, preferencesService, editedGroup); ViewLoader.view(this) .load() @@ -76,54 +79,26 @@ public GroupDialogView(DialogService dialogService, BasePanel basePanel, JabRefP } setResultConverter(viewModel::resultConverter); - getDialogPane().getButtonTypes().setAll(ButtonType.OK, ButtonType.CANCEL); - - getDialogPane().getScene().getWindow().sizeToScene(); - } - - public GroupDialogView(DialogService dialogService, AbstractGroup editedGroup) { - this(dialogService, JabRefGUI.getMainFrame().getCurrentBasePanel(), Globals.prefs, editedGroup); - } - - public GroupDialogView(DialogService dialogService) { - this(dialogService, JabRefGUI.getMainFrame().getCurrentBasePanel(), Globals.prefs, null); - } - - private String getHierarchyDisplayText(GroupHierarchyType type) { - switch (type) { - case INCLUDING: - return Localization.lang("Union"); - case REFINING: - return Localization.lang("Intersection"); - default: - case INDEPENDENT: - return Localization.lang("Independent"); - } - } - - private String getHierarchyToolTip(GroupHierarchyType type) { - switch (type) { - case INCLUDING: - return Localization.lang("Include subgroups: When selected, view entries contained in this group or its subgroups"); - case REFINING: - return Localization.lang("Refine supergroup: When selected, view entries contained in both this group and its supergroup"); - default: - case INDEPENDENT: - return Localization.lang("Independent group: When selected, view only this group's entries"); - } } @FXML public void initialize() { + hierarchyText.put(GroupHierarchyType.INCLUDING, Localization.lang("Union")); + hierarchyToolTip.put(GroupHierarchyType.INCLUDING, Localization.lang("Include subgroups: When selected, view entries contained in this group or its subgroups")); + hierarchyText.put(GroupHierarchyType.REFINING, Localization.lang("Intersection")); + hierarchyToolTip.put(GroupHierarchyType.REFINING, Localization.lang("Refine supergroup: When selected, view entries contained in both this group and its supergroup")); + hierarchyText.put(GroupHierarchyType.INDEPENDENT, Localization.lang("Independent")); + hierarchyToolTip.put(GroupHierarchyType.INDEPENDENT, Localization.lang("Independent group: When selected, view only this group's entries")); + nameField.textProperty().bindBidirectional(viewModel.nameProperty()); descriptionField.textProperty().bindBidirectional(viewModel.descriptionProperty()); iconField.textProperty().bindBidirectional(viewModel.iconProperty()); colorField.valueProperty().bindBidirectional(viewModel.colorFieldProperty()); hierarchicalContextCombo.itemsProperty().bind(viewModel.groupHierarchyListProperty()); new ViewModelListCellFactory() - .withText(this::getHierarchyDisplayText) - .withStringTooltip(this::getHierarchyToolTip) + .withText(hierarchyText::get) + .withStringTooltip(hierarchyToolTip::get) .install(hierarchicalContextCombo); hierarchicalContextCombo.valueProperty().bindBidirectional(viewModel.groupHierarchySelectedProperty()); @@ -162,7 +137,7 @@ public void initialize() { validationVisualizer.initVisualization(viewModel.keywordSearchTermEmptyValidationStatus(), keywordGroupSearchTerm); }); - // Binding to the validProperty throws an NPE, so we have to work around this issue + // Binding to the button throws a NPE, since it doesn't exist yet. Working around. viewModel.validationStatus().validProperty().addListener((obs, oldValue, newValue) -> { if (newValue) { getDialogPane().lookupButton(ButtonType.OK).setDisable(false); diff --git a/src/main/java/org/jabref/gui/groups/GroupDialogViewModel.java b/src/main/java/org/jabref/gui/groups/GroupDialogViewModel.java index a4c36108322..47a2c88f52f 100644 --- a/src/main/java/org/jabref/gui/groups/GroupDialogViewModel.java +++ b/src/main/java/org/jabref/gui/groups/GroupDialogViewModel.java @@ -22,7 +22,6 @@ import javafx.scene.paint.Color; import org.jabref.Globals; -import org.jabref.gui.BasePanel; import org.jabref.gui.DialogService; import org.jabref.gui.help.HelpAction; import org.jabref.gui.icon.IconTheme; @@ -33,6 +32,7 @@ import org.jabref.logic.util.StandardFileType; import org.jabref.logic.util.io.FileUtil; import org.jabref.model.database.BibDatabase; +import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.field.FieldFactory; import org.jabref.model.groups.AbstractGroup; import org.jabref.model.groups.AutomaticGroup; @@ -47,7 +47,7 @@ import org.jabref.model.groups.WordKeywordGroup; import org.jabref.model.metadata.MetaData; import org.jabref.model.strings.StringUtil; -import org.jabref.preferences.JabRefPreferences; +import org.jabref.preferences.PreferencesService; import de.saxsys.mvvmfx.utils.validation.CompositeValidator; import de.saxsys.mvvmfx.utils.validation.FunctionBasedValidator; @@ -101,20 +101,16 @@ public class GroupDialogViewModel { private CompositeValidator validator = new CompositeValidator(); private final DialogService dialogService; - private final JabRefPreferences preferences; - private final BasePanel basePanel; + private final PreferencesService preferencesService; + private final BibDatabaseContext currentDatabase; private final AbstractGroup editedGroup; - private final Character keywordDelimiter; - - public GroupDialogViewModel(DialogService dialogService, BasePanel basePanel, JabRefPreferences preferences, AbstractGroup editedGroup) { + public GroupDialogViewModel(DialogService dialogService, BibDatabaseContext currentDatabase, PreferencesService preferencesService, AbstractGroup editedGroup) { this.dialogService = dialogService; - this.preferences = preferences; - this.basePanel = basePanel; + this.preferencesService = preferencesService; + this.currentDatabase = currentDatabase; this.editedGroup = editedGroup; - this.keywordDelimiter = preferences.getKeywordDelimiter(); - setupValidation(); setValues(); } @@ -127,17 +123,17 @@ private void setupValidation() { nameContainsDelimiterValidator = new FunctionBasedValidator<>( nameProperty, - name -> !name.contains(Character.toString(keywordDelimiter)), + name -> !name.contains(Character.toString(preferencesService.getKeywordDelimiter())), ValidationMessage.warning( Localization.lang( "The group name contains the keyword separator \"%0\" and thus probably does not work as expected.", - Character.toString(keywordDelimiter) + Character.toString(preferencesService.getKeywordDelimiter()) ))); sameNameValidator = new FunctionBasedValidator<>( nameProperty, name -> { - Optional rootGroup = basePanel.getBibDatabaseContext().getMetaData().getGroups(); + Optional rootGroup = currentDatabase.getMetaData().getGroups(); if (rootGroup.isPresent()) { int groupsWithSameName = rootGroup.get().findChildrenSatisfying(group -> group.getName().equals(name)).size(); if ((editedGroup == null) && (groupsWithSameName > 0)) { @@ -250,7 +246,7 @@ public AbstractGroup resultConverter(ButtonType button) { resultingGroup = new ExplicitGroup( groupName, groupHierarchySelectedProperty.getValue(), - keywordDelimiter); + preferencesService.getKeywordDelimiter()); } else if (typeKeywordsProperty.getValue()) { if (keywordGroupRegexProperty.getValue()) { resultingGroup = new RegexKeywordGroup( @@ -266,7 +262,7 @@ public AbstractGroup resultConverter(ButtonType button) { FieldFactory.parseField(keywordGroupSearchFieldProperty.getValue().trim()), keywordGroupSearchTermProperty.getValue().trim(), keywordGroupCaseSensitiveProperty.getValue(), - keywordDelimiter, + preferencesService.getKeywordDelimiter(), false); } } else if (typeSearchProperty.getValue()) { @@ -297,7 +293,7 @@ public AbstractGroup resultConverter(ButtonType button) { Paths.get(texGroupFilePathProperty.getValue().trim()), new DefaultAuxParser(new BibDatabase()), Globals.getFileUpdateMonitor(), - basePanel.getBibDatabaseContext().getMetaData()); + currentDatabase.getMetaData()); } if (resultingGroup != null) { @@ -382,7 +378,7 @@ public void texGroupBrowse() { FileDialogConfiguration fileDialogConfiguration = new FileDialogConfiguration.Builder() .addExtensionFilter(StandardFileType.AUX) .withDefaultExtension(StandardFileType.AUX) - .withInitialDirectory(Globals.prefs.get(JabRefPreferences.WORKING_DIRECTORY)).build(); + .withInitialDirectory(preferencesService.getWorkingDir()).build(); dialogService.showFileOpenDialog(fileDialogConfiguration) .ifPresent(file -> texGroupFilePathProperty.setValue( FileUtil.relativize(file.toAbsolutePath(), getFileDirectoriesAsPaths()).toString() @@ -395,8 +391,8 @@ public void openHelpPage() { private List getFileDirectoriesAsPaths() { List fileDirs = new ArrayList<>(); - MetaData metaData = basePanel.getBibDatabaseContext().getMetaData(); - metaData.getLaTexFileDirectory(preferences.getFilePreferences().getUser()).ifPresent(fileDirs::add); + MetaData metaData = currentDatabase.getMetaData(); + metaData.getLaTexFileDirectory(preferencesService.getFilePreferences().getUser()).ifPresent(fileDirs::add); return fileDirs; } diff --git a/src/main/java/org/jabref/gui/groups/GroupTreeView.java b/src/main/java/org/jabref/gui/groups/GroupTreeView.java index b410e6be80d..aad18e6af6d 100644 --- a/src/main/java/org/jabref/gui/groups/GroupTreeView.java +++ b/src/main/java/org/jabref/gui/groups/GroupTreeView.java @@ -45,6 +45,7 @@ import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; import org.jabref.model.groups.AllEntriesGroup; +import org.jabref.preferences.PreferencesService; import org.controlsfx.control.textfield.CustomTextField; import org.controlsfx.control.textfield.TextFields; @@ -67,6 +68,8 @@ public class GroupTreeView { @Inject private StateManager stateManager; @Inject private DialogService dialogService; @Inject private TaskExecutor taskExecutor; + @Inject private PreferencesService preferencesService; + private GroupTreeViewModel viewModel; private CustomLocalDragboard localDragboard; @@ -75,7 +78,7 @@ public class GroupTreeView { @FXML public void initialize() { this.localDragboard = GUIGlobals.localDragboard; - viewModel = new GroupTreeViewModel(stateManager, dialogService, taskExecutor, localDragboard); + viewModel = new GroupTreeViewModel(stateManager, dialogService, preferencesService, taskExecutor, localDragboard); // Set-up groups tree groupTree.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); diff --git a/src/main/java/org/jabref/gui/groups/GroupTreeViewModel.java b/src/main/java/org/jabref/gui/groups/GroupTreeViewModel.java index 85b710f8539..d0b77597aad 100644 --- a/src/main/java/org/jabref/gui/groups/GroupTreeViewModel.java +++ b/src/main/java/org/jabref/gui/groups/GroupTreeViewModel.java @@ -29,6 +29,7 @@ import org.jabref.model.groups.ExplicitGroup; import org.jabref.model.groups.GroupTreeNode; import org.jabref.model.metadata.MetaData; +import org.jabref.preferences.PreferencesService; import org.fxmisc.easybind.EasyBind; @@ -38,6 +39,7 @@ public class GroupTreeViewModel extends AbstractViewModel { private final ListProperty selectedGroups = new SimpleListProperty<>(FXCollections.observableArrayList()); private final StateManager stateManager; private final DialogService dialogService; + private final PreferencesService preferences; private final TaskExecutor taskExecutor; private final CustomLocalDragboard localDragboard; private final ObjectProperty> filterPredicate = new SimpleObjectProperty<>(); @@ -47,9 +49,10 @@ public class GroupTreeViewModel extends AbstractViewModel { .compareToIgnoreCase(v2.getName()); private Optional currentDatabase; - public GroupTreeViewModel(StateManager stateManager, DialogService dialogService, TaskExecutor taskExecutor, CustomLocalDragboard localDragboard) { + public GroupTreeViewModel(StateManager stateManager, DialogService dialogService, PreferencesService preferencesService, TaskExecutor taskExecutor, CustomLocalDragboard localDragboard) { this.stateManager = Objects.requireNonNull(stateManager); this.dialogService = Objects.requireNonNull(dialogService); + this.preferences = Objects.requireNonNull(preferencesService); this.taskExecutor = Objects.requireNonNull(taskExecutor); this.localDragboard = Objects.requireNonNull(localDragboard); @@ -142,69 +145,83 @@ private void onActiveDatabaseChanged(Optional newDatabase) { * Opens "New Group Dialog" and add the resulting group to the specified group */ public void addNewSubgroup(GroupNodeViewModel parent) { - Optional newGroup = dialogService.showCustomDialogAndWait(new GroupDialogView(dialogService)); - newGroup.ifPresent(group -> { - parent.addSubgroup(group); + currentDatabase.ifPresent(database -> { + Optional newGroup = dialogService.showCustomDialogAndWait(new GroupDialogView( + dialogService, + database, + preferences, + null)); - // TODO: Add undo - //UndoableAddOrRemoveGroup undo = new UndoableAddOrRemoveGroup(parent, new GroupTreeNodeViewModel(newGroupNode), UndoableAddOrRemoveGroup.ADD_NODE); - //panel.getUndoManager().addEdit(undo); + newGroup.ifPresent(group -> { + parent.addSubgroup(group); - // TODO: Expand parent to make new group visible - //parent.expand(); + // TODO: Add undo + //UndoableAddOrRemoveGroup undo = new UndoableAddOrRemoveGroup(parent, new GroupTreeNodeViewModel(newGroupNode), UndoableAddOrRemoveGroup.ADD_NODE); + //panel.getUndoManager().addEdit(undo); - dialogService.notify(Localization.lang("Added group \"%0\".", group.getName())); - writeGroupChangesToMetaData(); + // TODO: Expand parent to make new group visible + //parent.expand(); + + dialogService.notify(Localization.lang("Added group \"%0\".", group.getName())); + writeGroupChangesToMetaData(); + }); }); } private void writeGroupChangesToMetaData() { - currentDatabase.get().getMetaData().setGroups(rootGroup.get().getGroupNode()); + currentDatabase.ifPresent(database -> database.getMetaData().setGroups(rootGroup.get().getGroupNode())); } /** * Opens "Edit Group Dialog" and changes the given group to the edited one. */ public void editGroup(GroupNodeViewModel oldGroup) { - Optional newGroup = dialogService - .showCustomDialogAndWait(new GroupDialogView(dialogService, oldGroup.getGroupNode().getGroup())); - newGroup.ifPresent(group -> { - // TODO: Keep assignments - boolean keepPreviousAssignments = dialogService.showConfirmationDialogAndWait( - Localization.lang("Change of Grouping Method"), - Localization.lang("Assign the original group's entries to this group?")); - // WarnAssignmentSideEffects.warnAssignmentSideEffects(newGroup, panel.frame()); - boolean removePreviousAssignments = (oldGroup.getGroupNode().getGroup() instanceof ExplicitGroup) - && (group instanceof ExplicitGroup); - - oldGroup.getGroupNode().setGroup( - group, - keepPreviousAssignments, - removePreviousAssignments, - stateManager.getEntriesInCurrentDatabase()); - - // TODO: Add undo - // Store undo information. - // AbstractUndoableEdit undoAddPreviousEntries = null; - // UndoableModifyGroup undo = new UndoableModifyGroup(GroupSelector.this, groupsRoot, node, newGroup); - // if (undoAddPreviousEntries == null) { - // panel.getUndoManager().addEdit(undo); - //} else { - // NamedCompound nc = new NamedCompound("Modify Group"); - // nc.addEdit(undo); - // nc.addEdit(undoAddPreviousEntries); - // nc.end();/ - // panel.getUndoManager().addEdit(nc); - //} - //if (!addChange.isEmpty()) { - // undoAddPreviousEntries = UndoableChangeEntriesOfGroup.getUndoableEdit(null, addChange); - //} - - dialogService.notify(Localization.lang("Modified group \"%0\".", group.getName())); - writeGroupChangesToMetaData(); - - // This is ugly but we have no proper update mechanism in place to propagate the changes, so redraw everything - refresh(); + currentDatabase.ifPresent(database -> { + Optional newGroup = dialogService.showCustomDialogAndWait(new GroupDialogView( + dialogService, + database, + preferences, + oldGroup.getGroupNode().getGroup())); + + newGroup.ifPresent(group -> { + // TODO: Keep assignments + boolean keepPreviousAssignments = dialogService.showConfirmationDialogAndWait( + Localization.lang("Change of Grouping Method"), + Localization.lang("Assign the original group's entries to this group?")); + // WarnAssignmentSideEffects.warnAssignmentSideEffects(newGroup, panel.frame()); + boolean removePreviousAssignments = (oldGroup.getGroupNode().getGroup() instanceof ExplicitGroup) + && (group instanceof ExplicitGroup); + + oldGroup.getGroupNode().setGroup( + group, + keepPreviousAssignments, + removePreviousAssignments, + database.getEntries()); + // stateManager.getEntriesInCurrentDatabase()); + + // TODO: Add undo + // Store undo information. + // AbstractUndoableEdit undoAddPreviousEntries = null; + // UndoableModifyGroup undo = new UndoableModifyGroup(GroupSelector.this, groupsRoot, node, newGroup); + // if (undoAddPreviousEntries == null) { + // panel.getUndoManager().addEdit(undo); + //} else { + // NamedCompound nc = new NamedCompound("Modify Group"); + // nc.addEdit(undo); + // nc.addEdit(undoAddPreviousEntries); + // nc.end();/ + // panel.getUndoManager().addEdit(nc); + //} + //if (!addChange.isEmpty()) { + // undoAddPreviousEntries = UndoableChangeEntriesOfGroup.getUndoableEdit(null, addChange); + //} + + dialogService.notify(Localization.lang("Modified group \"%0\".", group.getName())); + writeGroupChangesToMetaData(); + + // This is ugly but we have no proper update mechanism in place to propagate the changes, so redraw everything + refresh(); + }); }); } From 584abaca4f72a11dd02f07cbdc3312b92e7dd661 Mon Sep 17 00:00:00 2001 From: Carl Christian Snethlage Date: Sat, 25 Jan 2020 21:56:27 +0100 Subject: [PATCH 9/9] Fixed Test --- .../java/org/jabref/gui/groups/GroupTreeViewModelTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/jabref/gui/groups/GroupTreeViewModelTest.java b/src/test/java/org/jabref/gui/groups/GroupTreeViewModelTest.java index 6e90070a69b..40d37af02b4 100644 --- a/src/test/java/org/jabref/gui/groups/GroupTreeViewModelTest.java +++ b/src/test/java/org/jabref/gui/groups/GroupTreeViewModelTest.java @@ -15,6 +15,7 @@ import org.jabref.model.groups.ExplicitGroup; import org.jabref.model.groups.GroupHierarchyType; import org.jabref.model.groups.WordKeywordGroup; +import org.jabref.preferences.PreferencesService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -34,7 +35,7 @@ public void setUp() throws Exception { stateManager = new StateManager(); stateManager.activeDatabaseProperty().setValue(Optional.of(databaseContext)); taskExecutor = new CurrentThreadTaskExecutor(); - groupTree = new GroupTreeViewModel(stateManager, mock(DialogService.class), taskExecutor, new CustomLocalDragboard()); + groupTree = new GroupTreeViewModel(stateManager, mock(DialogService.class), mock(PreferencesService.class), taskExecutor, new CustomLocalDragboard()); } @Test