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

Persistent column sortorder #5730

Merged
merged 10 commits into from
Dec 16, 2019
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `#
- We changed the save action buttons to be easier to understand. [#5565](https://github.com/JabRef/jabref/issues/5565)
- We made the columns for groups, files and uri in the main table reorderable and merged the clickable icon columns for uri, url, doi and eprint. [#5544](https://github.com/JabRef/jabref/pull/5544)
- We reduced the number of write actions performed when autosave is enabled [#5679](https://github.com/JabRef/jabref/issues/5679)
- We made the column sort order in the main table persistent [#5730](https://github.com/JabRef/jabref/pull/5730)

### Fixed

Expand Down
19 changes: 6 additions & 13 deletions src/main/java/org/jabref/gui/maintable/ColumnPreferences.java
Original file line number Diff line number Diff line change
@@ -1,32 +1,25 @@
package org.jabref.gui.maintable;

import java.util.List;
import java.util.Map;

import javafx.scene.control.TableColumn.SortType;

public class ColumnPreferences {

public static final double DEFAULT_WIDTH = 100;
public static final double DEFAULT_COLUMN_WIDTH = 100;
public static final double ICON_COLUMN_WIDTH = 16 + 12; // add some additional space to improve appearance

private final List<MainTableColumnModel> columns;
private final boolean extraFileColumnsEnabled;
private final Map<String, SortType> columnSortType;
private final List<MainTableColumnModel> columnSortOrder;

public ColumnPreferences(List<MainTableColumnModel> columns, boolean extraFileColumnsEnabled, Map<String, SortType> columnSortType) {
public ColumnPreferences(List<MainTableColumnModel> columns, List<MainTableColumnModel> columnSortOrder) {
this.columns = columns;
this.extraFileColumnsEnabled = extraFileColumnsEnabled;
this.columnSortType = columnSortType;
this.columnSortOrder = columnSortOrder;
}

public boolean getExtraFileColumnsEnabled() { return extraFileColumnsEnabled; }

public List<MainTableColumnModel> getColumns() {
return columns;
}

public Map<String, SortType> getSortTypesForColumns() {
return columnSortType;
public List<MainTableColumnModel> getColumnSortOrder() {
return columnSortOrder;
}
}
18 changes: 9 additions & 9 deletions src/main/java/org/jabref/gui/maintable/MainTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,15 @@ public MainTable(MainTableDataModel model, JabRefFrame frame,
.setOnMouseDragEntered(this::handleOnDragEntered)
.install(this);

/*for (Entry<String, SortType> entries : preferences.getColumnPreferences().getSortTypesForColumns().entrySet()) {
Optional<TableColumn<BibEntryTableViewModel, ?>> column = this.getColumns().stream().filter(col -> entries.getKey().equals(col.getText())).findFirst();
column.ifPresent(col -> {
col.setSortType(entries.getValue());
this.getSortOrder().add(col);
});
}*/

if (preferences.resizeColumnsToFit()) {
this.getSortOrder().clear();
preferences.getColumnPreferences().getColumnSortOrder().forEach(columnModel ->
this.getColumns().stream()
.map(column -> (MainTableColumn<?>) column)
.filter(column -> column.getModel().equals(columnModel))
.findFirst()
.ifPresent(column -> this.getSortOrder().add(column)));

if (preferences.getResizeColumnsToFit()) {
this.setColumnResizePolicy(new SmartConstrainedResizePolicy());
}
this.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/org/jabref/gui/maintable/MainTableColumn.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.jabref.gui.maintable;

import javafx.beans.value.ObservableValue;
import javafx.scene.control.TableColumn;

import org.jabref.gui.util.BindingsHelper;
Expand All @@ -16,6 +17,12 @@ public MainTableColumn(MainTableColumnModel model) {
model.widthProperty(),
value -> this.setPrefWidth(model.widthProperty().getValue()),
value -> model.widthProperty().setValue(this.getWidth()));

BindingsHelper.bindBidirectional(
this.sortTypeProperty(),
(ObservableValue<SortType>) model.sortTypeProperty(),
value -> this.setSortType(model.sortTypeProperty().getValue()),
value -> model.sortTypeProperty().setValue(this.getSortType()));
}

public MainTableColumnModel getModel() { return model; }
Expand Down
86 changes: 49 additions & 37 deletions src/main/java/org/jabref/gui/maintable/MainTableColumnModel.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.jabref.gui.maintable;

import java.util.EnumSet;
import java.util.Objects;

import javafx.beans.property.DoubleProperty;
Expand All @@ -9,6 +10,7 @@
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.control.TableColumn;

import org.jabref.gui.util.FieldsUtil;
import org.jabref.logic.l10n.Localization;
Expand All @@ -35,6 +37,8 @@ public enum Type {
NORMALFIELD("field"),
SPECIALFIELD("special", Localization.lang("Special"));

public static final EnumSet<Type> ICON_COLUMNS = EnumSet.of(EXTRAFILE,FILES,GROUPS,LINKED_IDENTIFIER);

private String name;
private String displayName;

Expand Down Expand Up @@ -67,35 +71,54 @@ public static Type fromString(String text) {
}
}

private final ObjectProperty<Type> typeProperty;
private final StringProperty qualifierProperty;
private final DoubleProperty widthProperty;
private final ObjectProperty<Type> typeProperty = new SimpleObjectProperty<>();
private final StringProperty qualifierProperty = new SimpleStringProperty();
private final DoubleProperty widthProperty = new SimpleDoubleProperty();
private final ObjectProperty<TableColumn.SortType> sortTypeProperty = new SimpleObjectProperty<>();

/**
* This is used by the preferences dialog, to initialize available columns the user can add to the table.
*
* @param type the {@code MainTableColumnModel.Type} of the column, e.g. "NORMALFIELD" or "GROUPS"
* @param type the {@code MainTableColumnModel.Type} of the column, e.g. "NORMALFIELD" or "EXTRAFILE"
* @param qualifier the stored qualifier of the column, e.g. "author/editor"
*/
public MainTableColumnModel(Type type, String qualifier, double width) {
public MainTableColumnModel(Type type, String qualifier) {
Objects.requireNonNull(type);
typeProperty = new SimpleObjectProperty<>(type);
qualifierProperty = new SimpleStringProperty(qualifier);
widthProperty = new SimpleDoubleProperty(width);
}
Objects.requireNonNull(qualifier);

public MainTableColumnModel(Type type, String qualifier) {
this(type, qualifier, ColumnPreferences.DEFAULT_WIDTH);
}
this.typeProperty.setValue(type);
this.qualifierProperty.setValue(qualifier);
this.sortTypeProperty.setValue(TableColumn.SortType.ASCENDING);

public MainTableColumnModel(Type type, double width) {
this(type, "", width);
if (Type.ICON_COLUMNS.contains(type)) {
this.widthProperty.setValue(ColumnPreferences.ICON_COLUMN_WIDTH);
} else {
this.widthProperty.setValue(ColumnPreferences.DEFAULT_COLUMN_WIDTH);
}
}

/**
* This is used by the preferences dialog, to initialize available basic icon columns, the user can add to the table.
*
* @param type the {@code MainTableColumnModel.Type} of the column, e.g. "GROUPS" or "LINKED_IDENTIFIER"
*/
public MainTableColumnModel(Type type) {
this(type, "");
}

/**
* This is used by the preference migrations.
*
* @param type the {@code MainTableColumnModel.Type} of the column, e.g. "NORMALFIELD" or "GROUPS"
* @param qualifier the stored qualifier of the column, e.g. "author/editor"
* @param width the stored width of the column
*/
public MainTableColumnModel(Type type, String qualifier, double width) {
this(type, qualifier);

this.widthProperty.setValue(width);
}

public Type getType() { return typeProperty.getValue(); }

public String getQualifier() { return qualifierProperty.getValue(); }
Expand All @@ -109,10 +132,7 @@ public String getName() {
}

public String getDisplayName() {
if ((typeProperty.getValue() == Type.GROUPS
|| typeProperty.getValue() == Type.FILES
|| typeProperty.getValue() == Type.LINKED_IDENTIFIER)
&& qualifierProperty.getValue().isBlank()) {
if (Type.ICON_COLUMNS.contains(typeProperty.getValue()) && qualifierProperty.getValue().isBlank()) {
return typeProperty.getValue().getDisplayName();
} else {
return FieldsUtil.getNameWithType(FieldFactory.parseField(qualifierProperty.getValue()));
Expand All @@ -121,12 +141,14 @@ public String getDisplayName() {

public StringProperty nameProperty() { return new ReadOnlyStringWrapper(getDisplayName()); }

public double getWidth() {
return widthProperty.get();
}
public double getWidth() { return widthProperty.getValue(); }

public DoubleProperty widthProperty() { return widthProperty; }

public TableColumn.SortType getSortType() { return sortTypeProperty.getValue(); }

public ObjectProperty<TableColumn.SortType> sortTypeProperty() { return sortTypeProperty; }

public boolean equals(Object o) {
if (this == o) {
return true;
Expand All @@ -149,23 +171,11 @@ public int hashCode() {
}

/**
* This is used by JabRefPreferences, to create a new ColumnModel out ouf the stored preferences.
* This creates a new {@code MainTableColumnModel} out of a given string
*
* @param rawColumnName the stored name of the column, e.g. "field:author"
* @param width the stored width of the column
*/
public static MainTableColumnModel parse(String rawColumnName, Double width) {
MainTableColumnModel columnModel = parse(rawColumnName);

Objects.requireNonNull(width);
columnModel.widthProperty().setValue(width);
return columnModel;
}

/**
* This is used by the preferences dialog, to allow the user to type in a field he wants to add to the table.
* @param rawColumnName the name of the column, e.g. "field:author", or "author"
*
* @param rawColumnName the stored name of the column, e.g. "field:author", or "author"
* @return A new {@code MainTableColumnModel}
*/
public static MainTableColumnModel parse(String rawColumnName) {
Objects.requireNonNull(rawColumnName);
Expand All @@ -174,7 +184,9 @@ public static MainTableColumnModel parse(String rawColumnName) {
Type type = Type.fromString(splittedName[0]);
String qualifier = "";

if (type == Type.NORMALFIELD || type == Type.SPECIALFIELD || type == Type.EXTRAFILE) {
if (type == Type.NORMALFIELD
|| type == Type.SPECIALFIELD
|| type == Type.EXTRAFILE) {
if (splittedName.length == 1) {
qualifier = splittedName[0]; // By default the rawColumnName is parsed as NORMALFIELD
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,21 @@
public class MainTablePreferences {
private final ColumnPreferences columnPreferences;
private final boolean resizeColumnsToFit;
private final boolean extraFileColumnsEnabled;

public MainTablePreferences(ColumnPreferences columnPreferences, boolean resizeColumnsToFit) {
public MainTablePreferences(ColumnPreferences columnPreferences, boolean resizeColumnsToFit, boolean extraFileColumnsEnabled) {
this.columnPreferences = columnPreferences;
this.resizeColumnsToFit = resizeColumnsToFit;
this.extraFileColumnsEnabled = extraFileColumnsEnabled;
}

public ColumnPreferences getColumnPreferences() {
return columnPreferences;
}

public boolean resizeColumnsToFit() {
public boolean getResizeColumnsToFit() {
return resizeColumnsToFit;
}

public boolean getExtraFileColumnsEnabled() { return extraFileColumnsEnabled; }
}
Original file line number Diff line number Diff line change
@@ -1,63 +1,45 @@
package org.jabref.gui.maintable;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;

import javafx.collections.ListChangeListener;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.SortType;
import javafx.beans.InvalidationListener;

import org.jabref.preferences.JabRefPreferences;

/**
* Keep track of changes made to the columns, like reordering or resizing.
*
* Keep track of changes made to the columns (reordering, resorting, resizing).
*/
public class PersistenceVisualStateTable {

private final MainTable mainTable;
private final JabRefPreferences preferences;
private final Map<String, SortType> columnsSortOrder = new LinkedHashMap<>();

public PersistenceVisualStateTable(final MainTable mainTable, JabRefPreferences preferences) {
this.mainTable = mainTable;
this.preferences = preferences;

mainTable.getColumns().addListener(this::onColumnsChanged);
mainTable.getColumns().forEach(col -> {
MainTableColumn column = (MainTableColumn) col;
col.sortTypeProperty().addListener(obs -> updateColumnSortType(column.getModel().getName(), column.getSortType()));
});
mainTable.getColumns().forEach(col -> col.widthProperty().addListener(obs -> updateColumnPreferences()));
mainTable.getColumns().addListener((InvalidationListener) obs -> updateColumnPreferences());
mainTable.getSortOrder().addListener((InvalidationListener) obs -> updateColumnPreferences());

}

private void onColumnsChanged(ListChangeListener.Change<? extends TableColumn<BibEntryTableViewModel, ?>> change) {
boolean changed = false;
while (change.next()) {
changed = true;
}

if (changed) {
updateColumnPreferences();
}

}

private void updateColumnSortType(String text, SortType sortType) {
columnsSortOrder.put(text, sortType);
preferences.setMainTableColumnSortType(columnsSortOrder);
// As we store the ColumnModels of the MainTable, we need to add the listener to the ColumnModel properties,
// since the value is bound to the model after the listener to the column itself is called.
mainTable.getColumns().forEach(col ->
((MainTableColumn<?>) col).getModel().widthProperty().addListener(obs -> updateColumnPreferences()));
mainTable.getColumns().forEach(col ->
((MainTableColumn<?>) col).getModel().sortTypeProperty().addListener(obs -> updateColumnPreferences()));
}

/**
* Store shown columns and their width in preferences.
* Store shown columns, their width and their sortType in preferences.
*/
private void updateColumnPreferences() {
ColumnPreferences oldColumnPreferences = preferences.getColumnPreferences();
preferences.storeColumnPreferences(new ColumnPreferences(
mainTable.getColumns().stream().map(column -> ((MainTableColumn) column).getModel()).collect(Collectors.toList()),
oldColumnPreferences.getExtraFileColumnsEnabled(),
columnsSortOrder));
mainTable.getColumns().stream()
.map(column -> ((MainTableColumn<?>) column).getModel())
.collect(Collectors.toList()),
mainTable.getSortOrder().stream()
.map(column -> ((MainTableColumn<?>) column).getModel())
.collect(Collectors.toList())
));
}
}
Loading