Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
- We added autofocus and clipboard prefill to the commit message field in the Git Commit dialog. [#16340](https://github.com/JabRef/jabref/issues/16340)
- We added OCR engine selection to the OCR preferences, allowing users to choose the engine they want to use. [#16455](https://github.com/JabRef/jabref/pull/16455)
- We added BibTeX syntax highlighting to the Source tab and Import entries dialog. [#15897](https://github.com/JabRef/jabref/issues/15897)
- We added an option to include currently selected entries when creating a new explicit group. [#16588](https://github.com/JabRef/jabref/pull/16588)

### Changed

Expand Down
7 changes: 7 additions & 0 deletions docs/requirements/ux.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,11 @@ When a user activates a large library, automatic group construction and group-co

Needs: impl

### Creating a new explicit group can reuse the current selection
`req~ux.groups.create-explicit-from-selection~1`

When a user creates a new explicit group, JabRef should allow reusing the currently selected entries for that group and should keep the newly created group selected afterwards.

Needs: impl

<!-- markdownlint-disable-file MD022 -->
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ public class GroupDialogView extends BaseDialog<AbstractGroup> {
@FXML private RadioButton entryTypeRadioButton;

// Option Groups
@FXML private CheckBox explicitIncludeSelected;

@FXML private TextField keywordGroupSearchTerm;
@FXML private TextField keywordGroupSearchField;
@FXML private CheckBox keywordGroupCaseSensitive;
Expand Down Expand Up @@ -214,6 +216,9 @@ public void initialize() {
texRadioButton.selectedProperty().bindBidirectional(viewModel.typeTexProperty());
entryTypeRadioButton.selectedProperty().bindBidirectional(viewModel.typeEntryTypeProperty());

explicitIncludeSelected.selectedProperty().bindBidirectional(viewModel.explicitIncludeSelectedProperty());
explicitIncludeSelected.disableProperty().bind(viewModel.editingGroupProperty().or(viewModel.selectedEntriesAvailableProperty().not()));

keywordGroupSearchTerm.textProperty().bindBidirectional(viewModel.keywordGroupSearchTermProperty());
keywordGroupSearchField.textProperty().bindBidirectional(viewModel.keywordGroupSearchFieldProperty());
keywordGroupCaseSensitive.selectedProperty().bindBidirectional(viewModel.keywordGroupCaseSensitiveProperty());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ public class GroupDialogViewModel {
private final BooleanProperty typeTexProperty = new SimpleBooleanProperty();
private final BooleanProperty typeEntryTypeProperty = new SimpleBooleanProperty();

// Explicit Groups
private final BooleanProperty explicitIncludeSelectedProperty = new SimpleBooleanProperty(false);
private final BooleanProperty editingGroupProperty = new SimpleBooleanProperty(false);
private final BooleanProperty selectedEntriesAvailableProperty = new SimpleBooleanProperty(false);

// Option Groups
private final StringProperty keywordGroupSearchTermProperty = new SimpleStringProperty("");
private final StringProperty keywordGroupSearchFieldProperty = new SimpleStringProperty("");
Expand Down Expand Up @@ -306,10 +311,15 @@ public AbstractGroup resultConverter(ButtonType button) {
try {
String groupName = nameProperty.getValue().trim();
if (Boolean.TRUE.equals(typeExplicitProperty.getValue())) {
resultingGroup = new ExplicitGroup(
// [impl->req~ux.groups.create-explicit-from-selection~1]
ExplicitGroup explicitGroup = new ExplicitGroup(
groupName,
groupHierarchySelectedProperty.getValue(),
preferences.getBibEntryPreferences().getKeywordSeparator());
if (Boolean.TRUE.equals(explicitIncludeSelectedProperty.getValue())) {
explicitGroup.add(stateManager.getSelectedEntries());
}
Comment thread
qodo-free-for-open-source-projects[bot] marked this conversation as resolved.
resultingGroup = explicitGroup;
} else if (Boolean.TRUE.equals(typeKeywordsProperty.getValue())) {
if (Boolean.TRUE.equals(keywordGroupRegexProperty.getValue())) {
resultingGroup = new RegexKeywordGroup(
Expand Down Expand Up @@ -413,6 +423,7 @@ public AbstractGroup resultConverter(ButtonType button) {

public void setValues() {
groupHierarchyListProperty.setValue(FXCollections.observableArrayList(GroupHierarchyType.values()));
selectedEntriesAvailableProperty.set(!stateManager.getSelectedEntries().isEmpty());

if (editedGroup == null) {
// creating new group -> defaults!
Expand All @@ -428,6 +439,7 @@ public void setValues() {
parentNode.getGroup().getColor().ifPresent(color -> colorUseProperty.setValue(true));
}
typeExplicitProperty.setValue(true);
explicitIncludeSelectedProperty.setValue(selectedEntriesAvailableProperty.get() && preferences.getGroupsPreferences().shouldAutoIncludeSelectedEntries());
groupHierarchySelectedProperty.setValue(preferences.getGroupsPreferences().getDefaultHierarchicalContext());
autoGroupKeywordsOptionProperty.setValue(Boolean.TRUE);

Expand All @@ -436,6 +448,7 @@ public void setValues() {
dateGroupOptionProperty.setValue(DateGranularity.YEAR);
dateGroupIncludeEmptyProperty.setValue(false);
} else {
editingGroupProperty.set(true);
nameProperty.setValue(editedGroup.getName());
colorUseProperty.setValue(editedGroup.getColor().isPresent());
colorProperty.setValue(editedGroup.getColor().map(Color::valueOf).orElse(IconTheme.DEFAULT_GROUP_COLOR));
Expand Down Expand Up @@ -625,6 +638,18 @@ public BooleanProperty typeEntryTypeProperty() {
return typeEntryTypeProperty;
}

public BooleanProperty explicitIncludeSelectedProperty() {
return explicitIncludeSelectedProperty;
}

public BooleanProperty editingGroupProperty() {
return editingGroupProperty;
}

public BooleanProperty selectedEntriesAvailableProperty() {
return selectedEntriesAvailableProperty;
}

public StringProperty keywordGroupSearchTermProperty() {
return keywordGroupSearchTermProperty;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -511,8 +511,9 @@ private void updateSelection(List<TreeItem<GroupNodeViewModel>> newSelectedGroup
}
}

// [impl->req~ux.groups.create-explicit-from-selection~1]
private void selectNode(GroupNodeViewModel value) {
selectNode(value, false);
selectNode(value, true);
}

private void selectNode(GroupNodeViewModel value, boolean expandParents) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ public void addNewSubgroup(GroupNodeViewModel parent, GroupDialogHeader groupDia

newGroup.ifPresent(group -> {
GroupTreeNode newSubgroup = parent.addSubgroup(group);
// [impl->req~ux.groups.create-explicit-from-selection~1]
selectedGroups.setAll(new GroupNodeViewModel(database, stateManager, taskExecutor, newSubgroup, localDragboard, preferences));

// TODO: Add undo
Expand Down
18 changes: 18 additions & 0 deletions jabgui/src/main/java/org/jabref/gui/groups/GroupsPreferences.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public class GroupsPreferences {
private final SetProperty<GroupViewMode> groupViewMode;
private final BooleanProperty shouldAutoAssignGroup;
private final BooleanProperty shouldDisplayGroupCount;
private final BooleanProperty shouldAutoIncludeSelectedEntries;
private final ObjectProperty<GroupHierarchyType> defaultHierarchicalContext;
private final BooleanProperty showAiChatButton;

Expand All @@ -27,12 +28,14 @@ public GroupsPreferences(boolean viewModeIntersection,
boolean viewModeInvert,
boolean shouldAutoAssignGroup,
boolean shouldDisplayGroupCount,
boolean shouldAutoIncludeSelectedEntries,
GroupHierarchyType defaultHierarchicalContext,
boolean showAiChatButton) {

this.groupViewMode = new SimpleSetProperty<>(FXCollections.observableSet());
this.shouldAutoAssignGroup = new SimpleBooleanProperty(shouldAutoAssignGroup);
this.shouldDisplayGroupCount = new SimpleBooleanProperty(shouldDisplayGroupCount);
this.shouldAutoIncludeSelectedEntries = new SimpleBooleanProperty(shouldAutoIncludeSelectedEntries);
this.defaultHierarchicalContext = new SimpleObjectProperty<>(defaultHierarchicalContext);
this.showAiChatButton = new SimpleBooleanProperty(showAiChatButton);

Expand All @@ -54,6 +57,7 @@ private GroupsPreferences() {
false, // Default view mode invert
true, // Default auto assign group
true, // Default display group content
true, // Default include selected entries in new explicit groups
GroupHierarchyType.INDEPENDENT, // Default hierarchical context
true // Default view mode for the AI chat button
);
Expand All @@ -63,11 +67,13 @@ private GroupsPreferences() {
public GroupsPreferences(EnumSet<GroupViewMode> groupViewMode,
boolean shouldAutoAssignGroup,
boolean shouldDisplayGroupCount,
boolean shouldAutoIncludeSelectedEntries,
GroupHierarchyType defaultHierarchicalContext,
boolean showAiChatButton) {
this.groupViewMode = new SimpleSetProperty<>(FXCollections.observableSet(groupViewMode));
this.shouldAutoAssignGroup = new SimpleBooleanProperty(shouldAutoAssignGroup);
this.shouldDisplayGroupCount = new SimpleBooleanProperty(shouldDisplayGroupCount);
this.shouldAutoIncludeSelectedEntries = new SimpleBooleanProperty(shouldAutoIncludeSelectedEntries);
this.defaultHierarchicalContext = new SimpleObjectProperty<>(defaultHierarchicalContext);
this.showAiChatButton = new SimpleBooleanProperty(showAiChatButton);
}
Expand Down Expand Up @@ -119,6 +125,18 @@ public void setDisplayGroupCount(boolean shouldDisplayGroupCount) {
this.shouldDisplayGroupCount.set(shouldDisplayGroupCount);
}

public boolean shouldAutoIncludeSelectedEntries() {
return shouldAutoIncludeSelectedEntries.getValue();
}

public BooleanProperty autoIncludeSelectedEntriesProperty() {
return shouldAutoIncludeSelectedEntries;
}

public void setAutoIncludeSelectedEntries(boolean shouldAutoIncludeSelectedEntries) {
this.shouldAutoIncludeSelectedEntries.set(shouldAutoIncludeSelectedEntries);
}

public GroupHierarchyType getDefaultHierarchicalContext() {
return defaultHierarchicalContext.get();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ public class JabRefGuiPreferences extends JabRefCliPreferences implements GuiPre
// region GroupsPreferences
private static final String AUTO_ASSIGN_GROUP = "autoAssignGroup";
private static final String DISPLAY_GROUP_COUNT = "displayGroupCount";
private static final String AUTO_INCLUDE_SELECTED_ENTRIES = "autoIncludeSelectedEntries";
// The view mode spans the three GROUP_VIEW_* flags above; this synthetic key is never written to the backing store
// and only serves as the binding's reporting key in getPreferences()/getDefaults() (see bindMap/PUSH_APPLICATIONS_PATHS_KEY).
private static final String GROUP_VIEW_MODE = "groupViewMode";
Expand Down Expand Up @@ -769,6 +770,7 @@ public GroupsPreferences getGroupsPreferences() {
getBoolean(GROUP_VIEW_INVERT, defaultValues.groupViewModeProperty().contains(GroupViewMode.INVERT)),
getBoolean(AUTO_ASSIGN_GROUP, defaultValues.shouldAutoAssignGroup()),
getBoolean(DISPLAY_GROUP_COUNT, defaultValues.shouldDisplayGroupCount()),
getBoolean(AUTO_INCLUDE_SELECTED_ENTRIES, defaultValues.shouldAutoIncludeSelectedEntries()),
GroupHierarchyType.safeValueOf(get(DEFAULT_HIERARCHICAL_CONTEXT, defaultValues.getDefaultHierarchicalContext().name())),
getBoolean(GROUP_SHOW_AI_CHAT, defaultValues.showAiChatButton())
);
Expand All @@ -778,6 +780,7 @@ public GroupsPreferences getGroupsPreferences() {
() -> getGroupViewModes(defaultValues));
bindBoolean(groupsPreferences.autoAssignGroupProperty(), AUTO_ASSIGN_GROUP, defaultValues.shouldAutoAssignGroup());
bindBoolean(groupsPreferences.displayGroupCountProperty(), DISPLAY_GROUP_COUNT, defaultValues.shouldDisplayGroupCount());
bindBoolean(groupsPreferences.autoIncludeSelectedEntriesProperty(), AUTO_INCLUDE_SELECTED_ENTRIES, defaultValues.shouldAutoIncludeSelectedEntries());
bindObject(groupsPreferences.defaultHierarchicalContextProperty(), DEFAULT_HIERARCHICAL_CONTEXT, defaultValues.getDefaultHierarchicalContext(),
GroupHierarchyType::name, GroupHierarchyType::safeValueOf);
bindBoolean(groupsPreferences.showAiChatButtonProperty(), GROUP_SHOW_AI_CHAT, defaultValues.showAiChatButton());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ private void buildView() {
.radio(Localization.lang("Display only entries belonging to all selected groups"), viewModel.groupViewModeIntersectionProperty())
.radio(Localization.lang("Display all entries belonging to one or more of the selected groups"), viewModel.groupViewModeUnionProperty()))
.checkbox(Localization.lang("Automatically assign new entry to selected groups"), viewModel.autoAssignGroupProperty())
.checkbox(Localization.lang("Automatically include selected entries when a new group is created"), viewModel.autoIncludeSelectedEntriesProperty())
.checkbox(Localization.lang("Display count of items in group"), viewModel.displayGroupCount())
.checkbox(Localization.lang("Show 'AI chat' in the context menu"), viewModel.showAiChatButtonProperty()))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public class GroupsTabViewModel implements PreferenceTabViewModel {
private final BooleanProperty groupViewModeUnionProperty = new SimpleBooleanProperty();
private final BooleanProperty autoAssignGroupProperty = new SimpleBooleanProperty();
private final BooleanProperty displayGroupCountProperty = new SimpleBooleanProperty();
private final BooleanProperty autoIncludeSelectedEntriesProperty = new SimpleBooleanProperty();
private final BooleanProperty showAiChatButtonProperty = new SimpleBooleanProperty();

private final GroupsPreferences groupsPreferences;
Expand All @@ -32,6 +33,7 @@ public void setValues() {
}
autoAssignGroupProperty.setValue(groupsPreferences.shouldAutoAssignGroup());
displayGroupCountProperty.setValue(groupsPreferences.shouldDisplayGroupCount());
autoIncludeSelectedEntriesProperty.setValue(groupsPreferences.shouldAutoIncludeSelectedEntries());
showAiChatButtonProperty.setValue(groupsPreferences.showAiChatButton());
}

Expand All @@ -40,6 +42,7 @@ public void storeSettings() {
groupsPreferences.setGroupViewMode(GroupViewMode.INTERSECTION, groupViewModeIntersectionProperty.getValue());
groupsPreferences.setAutoAssignGroup(autoAssignGroupProperty.getValue());
groupsPreferences.setDisplayGroupCount(displayGroupCountProperty.getValue());
groupsPreferences.setAutoIncludeSelectedEntries(autoIncludeSelectedEntriesProperty.getValue());
groupsPreferences.setShowAiChatButton(showAiChatButtonProperty.getValue());
}

Expand All @@ -59,6 +62,10 @@ public BooleanProperty displayGroupCount() {
return displayGroupCountProperty;
}

public BooleanProperty autoIncludeSelectedEntriesProperty() {
return autoIncludeSelectedEntriesProperty;
}

public BooleanProperty showAiChatButtonProperty() {
return showAiChatButtonProperty;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@
</VBox>
<Separator orientation="VERTICAL"/>
<StackPane HBox.hgrow="ALWAYS">
<VBox visible="${explicitRadioButton.selected}" spacing="10.0">
<CheckBox fx:id="explicitIncludeSelected" text="%Include selected entries in created group"/>
</VBox>
<VBox visible="${keywordsRadioButton.selected}" spacing="10.0">
<VBox>
<Label text="%Field"/>
Expand Down
Loading
Loading