Skip to content

Commit

Permalink
Add hide button for user comments (JabRef#10610)
Browse files Browse the repository at this point in the history
* Place BibTeX comment field first (and use JDK21 data structure)

- Place all user comments togehter (and BibTeX standard comment first)
- Switch from Set to StructuredSet

* Enable "Add" button

* Fix codestyle

* Hide user comment button
remove from grid

todo move to prefs

* Add new property for hiding/showing comment tabs
move entry editor preferences

* Add new property for hiding/showing comment tabs
move entry editor preferences

* wire checkbox/button to preferences

* fix checkstyle

* Move back

* fix

* fix test

* Fix logic - and adapt tests

---------

Co-authored-by: Christoph <[email protected]>
  • Loading branch information
koppor and Siedlerchr authored Dec 4, 2023
1 parent b08e78c commit 67e25a0
Show file tree
Hide file tree
Showing 20 changed files with 248 additions and 107 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
- We replaced "SearchAll" in Web Search by "Search Selected". [#10556](https://github.com/JabRef/jabref/issues/10556)
- Short DOI formatter now checks, if the value is already formatted. If so, it returns the value instead of calling the ShortDOIService again. [#10589](https://github.com/JabRef/jabref/issues/10589)
- We upgraded to JavaFX 21.0.1. As a consequence JabRef requires now macOS 11 or later and GTK 3.8 or later on Linux [10627](https://github.com/JabRef/jabref/pull/10627).
- A user-specific comment fields is not enabled by default, but can be enabled using the "Add" button. [#10424](https://github.com/JabRef/jabref/issues/10424)
- We upgraded to Lucene 9.9 for the fulltext search. The search index will be rebuild. [#10686](https://github.com/JabRef/jabref/pull/10686)

### Fixed
Expand Down
96 changes: 80 additions & 16 deletions src/main/java/org/jabref/gui/entryeditor/CommentsTab.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
package org.jabref.gui.entryeditor;

import java.util.Comparator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.Optional;
import java.util.SequencedSet;
import java.util.stream.Collectors;

import javax.swing.undo.UndoManager;

import javafx.collections.ObservableList;
import javafx.geometry.VPos;
import javafx.scene.control.Button;
import javafx.scene.layout.Priority;
import javafx.scene.layout.RowConstraints;

import org.jabref.gui.DialogService;
import org.jabref.gui.StateManager;
import org.jabref.gui.autocompleter.SuggestionProviders;
import org.jabref.gui.fieldeditors.FieldEditorFX;
import org.jabref.gui.fieldeditors.FieldNameLabel;
import org.jabref.gui.icon.IconTheme;
import org.jabref.gui.theme.ThemeManager;
import org.jabref.gui.util.TaskExecutor;
Expand All @@ -28,6 +37,10 @@ public class CommentsTab extends FieldsEditorTab {
public static final String NAME = "Comments";

private final String defaultOwner;
private final UserSpecificCommentField userSpecificCommentField;

private final EntryEditorPreferences entryEditorPreferences;

public CommentsTab(PreferencesService preferences,
BibDatabaseContext databaseContext,
SuggestionProviders suggestionProviders,
Expand All @@ -54,38 +67,89 @@ public CommentsTab(PreferencesService preferences,
this.defaultOwner = preferences.getOwnerPreferences().getDefaultOwner();
setText(Localization.lang("Comments"));
setGraphic(IconTheme.JabRefIcons.COMMENT.getGraphicNode());

userSpecificCommentField = new UserSpecificCommentField(defaultOwner);
entryEditorPreferences = preferences.getEntryEditorPreferences();
}

@Override
protected Set<Field> determineFieldsToShow(BibEntry entry) {
UserSpecificCommentField defaultCommentField = new UserSpecificCommentField(defaultOwner);
protected SequencedSet<Field> determineFieldsToShow(BibEntry entry) {
SequencedSet<Field> comments = new LinkedHashSet<>();

// As default: Show BibTeX comment field and the user-specific comment field of the default owner
Set<Field> comments = new LinkedHashSet<>(Set.of(defaultCommentField, StandardField.COMMENT));
// First comes the standard comment field
comments.add(StandardField.COMMENT);

comments.addAll(entry.getFields().stream()
.filter(field -> field instanceof UserSpecificCommentField ||
field.getName().toLowerCase().contains("comment"))
.collect(Collectors.toSet()));
// Also show comment field of the current user (if enabled in the preferences)
if (entry.hasField(userSpecificCommentField) || entryEditorPreferences.shouldShowUserCommentsFields()) {
comments.add(userSpecificCommentField);
}

// Show all non-empty comment fields (otherwise, they are completely hidden)
comments.addAll(entry.getFields().stream()
.filter(field -> (field instanceof UserSpecificCommentField && !field.equals(userSpecificCommentField))
|| field.getName().toLowerCase().contains("comment"))
.sorted(Comparator.comparing(Field::getName))
.collect(Collectors.toCollection(LinkedHashSet::new)));
return comments;
}

/**
* Comment editors: three times size of button
*/
private void setCompressedRowLayout() {
int numberOfComments = gridPane.getRowCount() - 1;
double totalWeight = numberOfComments * 3 + 1;

RowConstraints commentConstraint = new RowConstraints();
commentConstraint.setVgrow(Priority.ALWAYS);
commentConstraint.setValignment(VPos.TOP);
double commentHeightPercent = 3.0 / totalWeight * 100.0;
commentConstraint.setPercentHeight(commentHeightPercent);

RowConstraints buttonConstraint = new RowConstraints();
buttonConstraint.setVgrow(Priority.ALWAYS);
buttonConstraint.setValignment(VPos.TOP);
double addButtonHeightPercent = 1.0 / totalWeight * 100.0;
buttonConstraint.setPercentHeight(addButtonHeightPercent);

ObservableList<RowConstraints> rowConstraints = gridPane.getRowConstraints();
rowConstraints.clear();
for (int i = 1; i <= numberOfComments; i++) {
rowConstraints.add(commentConstraint);
}
rowConstraints.add(buttonConstraint);
}

@Override
protected void setupPanel(BibEntry entry, boolean compressed) {
super.setupPanel(entry, compressed);

Optional<FieldEditorFX> fieldEditorForUserDefinedComment = editors.entrySet().stream().filter(f -> f.getKey().getName().contains(defaultOwner)).map(Map.Entry::getValue).findFirst();
for (Map.Entry<Field, FieldEditorFX> fieldEditorEntry : editors.entrySet()) {
Field field = fieldEditorEntry.getKey();
FieldEditorFX editor = fieldEditorEntry.getValue();

if (field instanceof UserSpecificCommentField) {
if (field.getName().contains(defaultOwner)) {
editor.getNode().setDisable(false);
}
} else {
editor.getNode().setDisable(!field.getName().equals(StandardField.COMMENT.getName()));
}
boolean isStandardBibtexComment = field == StandardField.COMMENT;
boolean isDefaultOwnerComment = field.equals(userSpecificCommentField);
boolean shouldBeEnabled = isStandardBibtexComment || isDefaultOwnerComment;
editor.getNode().setDisable(!shouldBeEnabled);
}

// Show "Hide" button only if user-specific comment field is empty. Otherwise, it is a strange UI, because the
// button would just disappear and no change **in the current** editor would be made
if (entryEditorPreferences.shouldShowUserCommentsFields() && !entry.hasField(userSpecificCommentField)) {
Button hideDefaultOwnerCommentButton = new Button(Localization.lang("Hide user comments"));
hideDefaultOwnerCommentButton.setOnAction(e -> {
var labelForField = gridPane.getChildren().stream().filter(s -> s instanceof FieldNameLabel).filter(x -> ((FieldNameLabel) x).getText().equals(userSpecificCommentField.getDisplayName())).findFirst();
labelForField.ifPresent(label -> gridPane.getChildren().remove(label));
fieldEditorForUserDefinedComment.ifPresent(f -> gridPane.getChildren().remove(f.getNode()));
editors.remove(userSpecificCommentField);

entryEditorPreferences.setShowUserCommentsFields(false);
setupPanel(entry, false);
});
gridPane.add(hideDefaultOwnerCommentButton, 1, gridPane.getRowCount(), 2, 1);
setCompressedRowLayout();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package org.jabref.gui.entryeditor;

import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Optional;
import java.util.Set;
import java.util.SequencedSet;
import java.util.stream.Collectors;

import javax.swing.undo.UndoManager;
Expand Down Expand Up @@ -59,14 +59,14 @@ public DeprecatedFieldsTab(BibDatabaseContext databaseContext,
}

@Override
protected Set<Field> determineFieldsToShow(BibEntry entry) {
protected SequencedSet<Field> determineFieldsToShow(BibEntry entry) {
BibDatabaseMode mode = databaseContext.getMode();
Optional<BibEntryType> entryType = entryTypesManager.enrich(entry.getType(), mode);
if (entryType.isPresent()) {
return entryType.get().getDeprecatedFields(mode).stream().filter(field -> !entry.getField(field).isEmpty()).collect(Collectors.toSet());
return entryType.get().getDeprecatedFields(mode).stream().filter(field -> !entry.getField(field).isEmpty()).collect(Collectors.toCollection(LinkedHashSet::new));
} else {
// Entry type unknown -> treat all fields as required
return Collections.emptySet();
// Entry type unknown -> treat all fields as required (thus no optional fields)
return new LinkedHashSet<>();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public static JournalPopupEnabled fromString(String status) {
private final BooleanProperty autoLinkFiles;
private final ObjectProperty<JournalPopupEnabled> enablementStatus;
private final BooleanProperty shouldShowSciteTab;
private final BooleanProperty showUserCommentsFields;

public EntryEditorPreferences(Map<String, Set<Field>> entryEditorTabList,
Map<String, Set<Field>> defaultEntryEditorTabList,
Expand All @@ -60,7 +61,8 @@ public EntryEditorPreferences(Map<String, Set<Field>> entryEditorTabList,
double dividerPosition,
boolean autolinkFilesEnabled,
JournalPopupEnabled journalPopupEnabled,
boolean showSciteTab) {
boolean showSciteTab,
boolean showUserCommentsFields) {

this.entryEditorTabList = new SimpleMapProperty<>(FXCollections.observableMap(entryEditorTabList));
this.defaultEntryEditorTabList = new SimpleMapProperty<>(FXCollections.observableMap(defaultEntryEditorTabList));
Expand All @@ -74,6 +76,7 @@ public EntryEditorPreferences(Map<String, Set<Field>> entryEditorTabList,
this.autoLinkFiles = new SimpleBooleanProperty(autolinkFilesEnabled);
this.enablementStatus = new SimpleObjectProperty<>(journalPopupEnabled);
this.shouldShowSciteTab = new SimpleBooleanProperty(showSciteTab);
this.showUserCommentsFields = new SimpleBooleanProperty(showUserCommentsFields);
}

public ObservableMap<String, Set<Field>> getEntryEditorTabs() {
Expand Down Expand Up @@ -211,4 +214,16 @@ public BooleanProperty shouldShowLSciteTabProperty() {
public void setShouldShowSciteTab(boolean shouldShowSciteTab) {
this.shouldShowSciteTab.set(shouldShowSciteTab);
}

public boolean shouldShowUserCommentsFields() {
return showUserCommentsFields.get();
}

public BooleanProperty showUserCommentsFieldsProperty() {
return showUserCommentsFields;
}

public void setShowUserCommentsFields(boolean showUserCommentsFields) {
this.showUserCommentsFields.set(showUserCommentsFields);
}
}
76 changes: 41 additions & 35 deletions src/main/java/org/jabref/gui/entryeditor/FieldsEditorTab.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.SequencedSet;
import java.util.stream.Stream;

import javax.swing.undo.UndoManager;

import javafx.collections.ObservableList;
import javafx.geometry.VPos;
import javafx.scene.Node;
import javafx.scene.Parent;
Expand Down Expand Up @@ -47,6 +48,7 @@
abstract class FieldsEditorTab extends EntryEditorTab {
protected final BibDatabaseContext databaseContext;
protected final Map<Field, FieldEditorFX> editors = new LinkedHashMap<>();
protected GridPane gridPane;
private final boolean isCompressed;
private final SuggestionProviders suggestionProviders;
private final DialogService dialogService;
Expand All @@ -59,7 +61,6 @@ abstract class FieldsEditorTab extends EntryEditorTab {
private PreviewPanel previewPanel;
private final UndoManager undoManager;
private Collection<Field> fields = new ArrayList<>();
private GridPane gridPane;

public FieldsEditorTab(boolean compressed,
BibDatabaseContext databaseContext,
Expand Down Expand Up @@ -107,36 +108,22 @@ protected void setupPanel(BibEntry entry, boolean compressed) {

fields = determineFieldsToShow(entry);

List<Label> labels = new ArrayList<>();
for (Field field : fields) {
FieldEditorFX fieldEditor = FieldEditors.getForField(
field,
taskExecutor,
dialogService,
journalAbbreviationRepository,
preferences,
databaseContext,
entry.getType(),
suggestionProviders,
undoManager);
fieldEditor.bindToEntry(entry);

editors.put(field, fieldEditor);
labels.add(new FieldNameLabel(field));
}
List<Label> labels = fields
.stream()
.map(field -> createLabelAndEditor(entry, field))
.toList();

ColumnConstraints columnExpand = new ColumnConstraints();
columnExpand.setHgrow(Priority.ALWAYS);

ColumnConstraints columnDoNotContract = new ColumnConstraints();
columnDoNotContract.setMinWidth(Region.USE_PREF_SIZE);
int rows;
if (compressed) {
rows = (int) Math.ceil((double) fields.size() / 2);
int rows = (int) Math.ceil((double) fields.size() / 2);

addColumn(gridPane, 0, labels.subList(0, rows));
addColumn(gridPane, 3, labels.subList(rows, labels.size()));
addColumn(gridPane, 1, editors.values().stream().map(FieldEditorFX::getNode).limit(rows));
addColumn(gridPane, 3, labels.subList(rows, labels.size()));
addColumn(gridPane, 4, editors.values().stream().map(FieldEditorFX::getNode).skip(rows));

columnExpand.setPercentWidth(40);
Expand All @@ -154,23 +141,39 @@ protected void setupPanel(BibEntry entry, boolean compressed) {
}
}

protected Label createLabelAndEditor(BibEntry entry, Field field) {
FieldEditorFX fieldEditor = FieldEditors.getForField(
field,
taskExecutor,
dialogService,
journalAbbreviationRepository,
preferences,
databaseContext,
entry.getType(),
suggestionProviders,
undoManager);
fieldEditor.bindToEntry(entry);
editors.put(field, fieldEditor);
return new FieldNameLabel(field);
}

private void setRegularRowLayout(GridPane gridPane) {
double totalWeight = fields.stream()
.mapToDouble(field -> editors.get(field).getWeight())
.sum();

List<RowConstraints> constraints = new ArrayList<>();
for (Field field : fields) {
RowConstraints rowExpand = new RowConstraints();
rowExpand.setVgrow(Priority.ALWAYS);
rowExpand.setValignment(VPos.TOP);
rowExpand.setPercentHeight(100 * editors.get(field).getWeight() / totalWeight);
constraints.add(rowExpand);
}
List<RowConstraints> constraints = fields
.stream()
.map(field -> {
RowConstraints rowExpand = new RowConstraints();
rowExpand.setVgrow(Priority.ALWAYS);
rowExpand.setValignment(VPos.TOP);
rowExpand.setPercentHeight(100 * editors.get(field).getWeight() / totalWeight);
return rowExpand;
}).toList();
gridPane.getRowConstraints().addAll(constraints);
}

private void setCompressedRowLayout(GridPane gridPane, int rows) {
protected static void setCompressedRowLayout(GridPane gridPane, int rows) {
RowConstraints rowExpand = new RowConstraints();
rowExpand.setVgrow(Priority.ALWAYS);
rowExpand.setValignment(VPos.TOP);
Expand All @@ -179,8 +182,11 @@ private void setCompressedRowLayout(GridPane gridPane, int rows) {
} else {
rowExpand.setPercentHeight(100 / (double) rows);
}

ObservableList<RowConstraints> rowConstraints = gridPane.getRowConstraints();
rowConstraints.clear();
for (int i = 0; i < rows; i++) {
gridPane.getRowConstraints().add(rowExpand);
rowConstraints.add(rowExpand);
}
}

Expand Down Expand Up @@ -218,7 +224,7 @@ protected void previousPreviewStyle() {
}
}

protected abstract Set<Field> determineFieldsToShow(BibEntry entry);
protected abstract SequencedSet<Field> determineFieldsToShow(BibEntry entry);

public Collection<Field> getShownFields() {
return fields;
Expand All @@ -229,7 +235,7 @@ private void initPanel() {
gridPane = new GridPane();
gridPane.getStyleClass().add("editorPane");

// Warp everything in a scroll-pane
// Wrap everything in a scroll-pane
ScrollPane scrollPane = new ScrollPane();
scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED);
Expand Down
Loading

0 comments on commit 67e25a0

Please sign in to comment.