Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor SaveOrderConfigPanel #7935

Merged
merged 23 commits into from
Aug 5, 2021
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
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