Skip to content

Commit

Permalink
Refactor SaveOrderConfigPanel (#7935)
Browse files Browse the repository at this point in the history
* Initial

* Added and fixed tests, changed glyphs

* Moved row to arguments

* Work in progress

* Extracted button method

* Fixed moving criteria up and down

* Fixed tests

* Fixed tests

* Fixed Checkstyle

* Fixed tests

* Fixed fix and reworded

* l10n

* Moved ExportOrderConfigPanel to ImportExportTab

* Added criteria limit to preferences

* Added criteria limit to preferences

* Removed LinkedList

* Removed more LinkedLists

* Removed more LinkedLists

* Checkstyle

* Fix linting issue in CHANGELOG

Co-authored-by: Oliver Kopp <kopp.dev@gmail.com>
  • Loading branch information
calixtus and koppor authored Aug 5, 2021
1 parent 2142ade commit 3a44c69
Show file tree
Hide file tree
Showing 20 changed files with 507 additions and 449 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve
- We slightly changed the layout of the Journal tab in the preferences for ui consistency. [#7937](https://github.com/JabRef/jabref/pull/7937)
- The JabRefHost on Windows now writes a temporary file and calls `-importToOpen` instead of passing the bibtex via `-importBibtex`. [#7374](https://github.com/JabRef/jabref/issues/7374), [JabRef Browser Ext #274](https://github.com/JabRef/JabRef-Browser-Extension/issues/274)
- We merged the barely used ImportSettingsTab and the CustomizationTab in the preferences into one single tab and moved the option to allow Integers in Edition Fields in Bibtex-Mode to the EntryEditor tab. [#7849](https://github.com/JabRef/jabref/pull/7849)
- We moved the export order in the preferences from `File` to `Import and Export`. [#7935](https://github.com/JabRef/jabref/pull/7935)
- We reworked the export order in the preferences and the save order in the library preferences. You can now set more than three sort criteria in your library preferences. [#7935](https://github.com/JabRef/jabref/pull/7935)

### Fixed

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.Label?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.ToggleGroup?>
<?import javafx.scene.control.Tooltip?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<?import org.jabref.gui.icon.JabRefIconView?>
<fx:root prefWidth="650.0" spacing="10.0" type="VBox"
xmlns="http://javafx.com/javafx/8.0.212" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="org.jabref.gui.commonfxcontrols.SaveOrderConfigPanel">
Expand All @@ -23,38 +23,25 @@
<RadioButton fx:id="exportInSpecifiedOrder"
text="%Use specified order" toggleGroup="$saveOrderToggleGroup"/>

<GridPane hgap="10.0" vgap="4.0">
<GridPane fx:id="sortCriterionList" hgap="10.0" vgap="4.0" maxWidth="450.0"
disable="${!exportInSpecifiedOrder.selected}">
<columnConstraints>
<ColumnConstraints hgrow="NEVER" minWidth="25.0" maxWidth="25.0"/>
<ColumnConstraints hgrow="SOMETIMES" percentWidth="30.0"/>
<ColumnConstraints hgrow="NEVER" minWidth="40.0" maxWidth="40.0"/>
<ColumnConstraints hgrow="SOMETIMES"/>
<ColumnConstraints hgrow="SOMETIMES" halignment="LEFT"/>
<ColumnConstraints hgrow="NEVER" minWidth="30.0" maxWidth="30.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="30.0" vgrow="SOMETIMES"/>
<RowConstraints minHeight="30.0" vgrow="SOMETIMES"/>
<RowConstraints minHeight="30.0" vgrow="SOMETIMES"/>
</rowConstraints>

<Label text="%Primary sort criterion" GridPane.columnIndex="1" GridPane.rowIndex="0"
disable="${!exportInSpecifiedOrder.selected}"/>
<Label text="%Secondary sort criterion" GridPane.columnIndex="1" GridPane.rowIndex="1"
disable="${!exportInSpecifiedOrder.selected}"/>
<Label text="%Tertiary sort criterion" GridPane.columnIndex="1" GridPane.rowIndex="2"
disable="${!exportInSpecifiedOrder.selected}"/>

<ComboBox fx:id="savePriSort" editable="true" GridPane.columnIndex="2" GridPane.rowIndex="0"
disable="${!exportInSpecifiedOrder.selected}"/>
<ComboBox fx:id="saveSecSort" editable="true" GridPane.columnIndex="2" GridPane.rowIndex="1"
disable="${!exportInSpecifiedOrder.selected}"/>
<ComboBox fx:id="saveTerSort" editable="true" GridPane.columnIndex="2" GridPane.rowIndex="2"
disable="${!exportInSpecifiedOrder.selected}"/>

<CheckBox fx:id="savePriDesc" disable="${!exportInSpecifiedOrder.selected}" mnemonicParsing="false"
text="%Descending" GridPane.columnIndex="3" GridPane.rowIndex="0"/>
<CheckBox fx:id="saveSecDesc" disable="${!exportInSpecifiedOrder.selected}" mnemonicParsing="false"
text="%Descending" GridPane.columnIndex="3" GridPane.rowIndex="1"/>
<CheckBox fx:id="saveTerDesc" disable="${!exportInSpecifiedOrder.selected}" mnemonicParsing="false"
text="%Descending" GridPane.columnIndex="3" GridPane.rowIndex="2"/>
<padding>
<Insets left="30.0"/>
</padding>
</GridPane>
<Button fx:id="addButton" onAction="#addCriterion" styleClass="icon-button" disable="${!exportInSpecifiedOrder.selected}"
maxWidth="450.0" prefWidth="450.0">
<graphic>
<JabRefIconView glyph="ADD_NOBOX"/>
</graphic>
<tooltip>
<Tooltip text="Add"/>
</tooltip>
</Button>
</fx:root>
177 changes: 125 additions & 52 deletions src/main/java/org/jabref/gui/commonfxcontrols/SaveOrderConfigPanel.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,28 @@
package org.jabref.gui.commonfxcontrols;

import java.util.List;
import java.util.stream.Collectors;

import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ListProperty;
import javafx.beans.property.ObjectProperty;
import javafx.collections.ListChangeListener;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.RadioButton;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;

import org.jabref.gui.icon.IconTheme;
import org.jabref.gui.icon.JabRefIconView;
import org.jabref.gui.util.FieldsUtil;
import org.jabref.gui.util.ViewModelListCellFactory;
import org.jabref.logic.l10n.Localization;
import org.jabref.model.entry.field.Field;

import com.airhacks.afterburner.views.ViewLoader;
Expand All @@ -20,12 +32,8 @@ public class SaveOrderConfigPanel extends VBox {
@FXML private RadioButton exportInSpecifiedOrder;
@FXML private RadioButton exportInTableOrder;
@FXML private RadioButton exportInOriginalOrder;
@FXML private ComboBox<Field> savePriSort;
@FXML private ComboBox<Field> saveSecSort;
@FXML private ComboBox<Field> saveTerSort;
@FXML private CheckBox savePriDesc;
@FXML private CheckBox saveSecDesc;
@FXML private CheckBox saveTerDesc;
@FXML private GridPane sortCriterionList;
@FXML private Button addButton;

private SaveOrderConfigPanelViewModel viewModel;

Expand All @@ -43,77 +51,142 @@ private void initialize() {
exportInTableOrder.selectedProperty().bindBidirectional(viewModel.saveInTableOrderProperty());
exportInSpecifiedOrder.selectedProperty().bindBidirectional(viewModel.saveInSpecifiedOrderProperty());

new ViewModelListCellFactory<Field>()
.withText(FieldsUtil::getNameWithType)
.install(savePriSort);
savePriSort.itemsProperty().bindBidirectional(viewModel.primarySortFieldsProperty());
savePriSort.valueProperty().bindBidirectional(viewModel.savePrimarySortSelectedValueProperty());
savePriSort.setConverter(FieldsUtil.fieldStringConverter);

new ViewModelListCellFactory<Field>()
.withText(FieldsUtil::getNameWithType)
.install(saveSecSort);
saveSecSort.itemsProperty().bindBidirectional(viewModel.secondarySortFieldsProperty());
saveSecSort.valueProperty().bindBidirectional(viewModel.saveSecondarySortSelectedValueProperty());
saveSecSort.setConverter(FieldsUtil.fieldStringConverter);
viewModel.sortCriteriaProperty().addListener((ListChangeListener<SortCriterionViewModel>) change -> {
while (change.next()) {
if (change.wasReplaced()) {
clearCriterionRow(change.getFrom());
createCriterionRow(change.getAddedSubList().get(0), change.getFrom());
} else if (change.wasAdded()) {
for (SortCriterionViewModel criterionViewModel : change.getAddedSubList()) {
int row = change.getFrom() + change.getAddedSubList().indexOf(criterionViewModel);
createCriterionRow(criterionViewModel, row);
}
} else if (change.wasRemoved()) {
for (SortCriterionViewModel criterionViewModel : change.getRemoved()) {
clearCriterionRow(change.getFrom());
}
}
}
});
}

private void createCriterionRow(SortCriterionViewModel criterionViewModel, int row) {
sortCriterionList.getChildren().stream()
.filter(item -> GridPane.getRowIndex(item) >= row)
.forEach(item -> {
GridPane.setRowIndex(item, GridPane.getRowIndex(item) + 1);
if (item instanceof Label label) {
label.setText(String.valueOf(GridPane.getRowIndex(item) + 1));
}
});

Label label = new Label(String.valueOf(row + 1));
sortCriterionList.add(label, 0, row);

ComboBox<Field> field = new ComboBox<>(viewModel.sortableFieldsProperty());
field.setMaxWidth(Double.MAX_VALUE);
new ViewModelListCellFactory<Field>()
.withText(FieldsUtil::getNameWithType)
.install(saveTerSort);
saveTerSort.itemsProperty().bindBidirectional(viewModel.tertiarySortFieldsProperty());
saveTerSort.valueProperty().bindBidirectional(viewModel.saveTertiarySortSelectedValueProperty());
saveTerSort.setConverter(FieldsUtil.fieldStringConverter);

savePriDesc.selectedProperty().bindBidirectional(viewModel.savePrimaryDescPropertySelected());
saveSecDesc.selectedProperty().bindBidirectional(viewModel.saveSecondaryDescPropertySelected());
saveTerDesc.selectedProperty().bindBidirectional(viewModel.saveTertiaryDescPropertySelected());
.install(field);
field.setConverter(FieldsUtil.fieldStringConverter);
field.itemsProperty().bindBidirectional(viewModel.sortableFieldsProperty());
field.valueProperty().bindBidirectional(criterionViewModel.fieldProperty());
sortCriterionList.add(field, 1, row);
GridPane.getHgrow(field);

CheckBox descending = new CheckBox(Localization.lang("Descending"));
descending.selectedProperty().bindBidirectional(criterionViewModel.descendingProperty());
sortCriterionList.add(descending, 2, row);

HBox hBox = new HBox();
hBox.getChildren().addAll(createRowButtons(criterionViewModel));
sortCriterionList.add(hBox, 3, row);
}

public BooleanProperty saveInOriginalProperty() {
return viewModel.saveInOriginalProperty();
private List<Node> createRowButtons(SortCriterionViewModel criterionViewModel) {
Button remove = new Button("", new JabRefIconView(IconTheme.JabRefIcons.REMOVE_NOBOX));
remove.getStyleClass().addAll("icon-button", "narrow");
remove.setPrefHeight(20.0);
remove.setPrefWidth(20.0);
remove.setOnAction(event -> removeCriterion(criterionViewModel));

Button moveUp = new Button("", new JabRefIconView(IconTheme.JabRefIcons.LIST_MOVE_UP));
moveUp.getStyleClass().addAll("icon-button", "narrow");
moveUp.setPrefHeight(20.0);
moveUp.setPrefWidth(20.0);
moveUp.setOnAction(event -> moveCriterionUp(criterionViewModel));

Button moveDown = new Button("", new JabRefIconView(IconTheme.JabRefIcons.LIST_MOVE_DOWN));
moveDown.getStyleClass().addAll("icon-button", "narrow");
moveDown.setPrefHeight(20.0);
moveDown.setPrefWidth(20.0);
moveDown.setOnAction(event -> moveCriterionDown(criterionViewModel));

return List.of(moveUp, moveDown, remove);
}

public BooleanProperty saveInTableOrderProperty() {
return viewModel.saveInTableOrderProperty();
private void clearCriterionRow(int row) {
List<Node> criterionRow = sortCriterionList.getChildren().stream()
.filter(item -> GridPane.getRowIndex(item) == row)
.collect(Collectors.toList());
sortCriterionList.getChildren().removeAll(criterionRow);

sortCriterionList.getChildren().stream()
.filter(item -> GridPane.getRowIndex(item) > row)
.forEach(item -> {
GridPane.setRowIndex(item, GridPane.getRowIndex(item) - 1);
if (item instanceof Label label) {
label.setText(String.valueOf(GridPane.getRowIndex(item) + 1));
}
});
}

public BooleanProperty saveInSpecifiedOrderProperty() {
return viewModel.saveInSpecifiedOrderProperty();
public void setCriteriaLimit(int limit) {
addButton.disableProperty().unbind();
addButton.disableProperty().bind(
Bindings.createBooleanBinding(
() -> viewModel.sortCriteriaProperty().size() >= limit || !exportInSpecifiedOrder.selectedProperty().get(),
viewModel.sortCriteriaProperty().sizeProperty(),
exportInSpecifiedOrder.selectedProperty()));
}

public ListProperty<Field> primarySortFieldsProperty() {
return viewModel.primarySortFieldsProperty();
@FXML
public void addCriterion() {
viewModel.addCriterion();
}

public ListProperty<Field> secondarySortFieldsProperty() {
return viewModel.secondarySortFieldsProperty();
@FXML
public void moveCriterionUp(SortCriterionViewModel criterionViewModel) {
viewModel.moveCriterionUp(criterionViewModel);
}

public ListProperty<Field> tertiarySortFieldsProperty() {
return viewModel.tertiarySortFieldsProperty();
@FXML
public void moveCriterionDown(SortCriterionViewModel criterionViewModel) {
viewModel.moveCriterionDown(criterionViewModel);
}

public ObjectProperty<Field> savePrimarySortSelectedValueProperty() {
return viewModel.savePrimarySortSelectedValueProperty();
@FXML
public void removeCriterion(SortCriterionViewModel criterionViewModel) {
viewModel.removeCriterion(criterionViewModel);
}

public ObjectProperty<Field> saveSecondarySortSelectedValueProperty() {
return viewModel.saveSecondarySortSelectedValueProperty();
public BooleanProperty saveInOriginalProperty() {
return viewModel.saveInOriginalProperty();
}

public ObjectProperty<Field> saveTertiarySortSelectedValueProperty() {
return viewModel.saveTertiarySortSelectedValueProperty();
public BooleanProperty saveInTableOrderProperty() {
return viewModel.saveInTableOrderProperty();
}

public BooleanProperty savePrimaryDescPropertySelected() {
return viewModel.savePrimaryDescPropertySelected();
public BooleanProperty saveInSpecifiedOrderProperty() {
return viewModel.saveInSpecifiedOrderProperty();
}

public BooleanProperty saveSecondaryDescPropertySelected() {
return viewModel.saveSecondaryDescPropertySelected();
public ListProperty<Field> sortableFieldsProperty() {
return viewModel.sortableFieldsProperty();
}

public BooleanProperty saveTertiaryDescPropertySelected() {
return viewModel.saveTertiaryDescPropertySelected();
public ListProperty<SortCriterionViewModel> sortCriteriaProperty() {
return viewModel.sortCriteriaProperty();
}
}
Loading

0 comments on commit 3a44c69

Please sign in to comment.