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

Implement better scaling of main table showing entries #644

Draft
wants to merge 38 commits into
base: main
Choose a base branch
from
Draft
Changes from 1 commit
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
a1a5ccc
Implement better scaling of main table showing entries
koppor Dec 12, 2020
e91bb8d
Fix number
koppor Dec 14, 2020
8f522df
Remove resizeColumnsToFit
koppor Dec 14, 2020
1acd12e
Fix checkstyle
koppor Dec 14, 2020
c8caa13
Merge branch 'master' into fix-967
koppor Dec 17, 2020
f5e2d9f
Add smart resize if content fits into table width
koppor Dec 17, 2020
bcea66c
Address some comments
koppor Dec 18, 2020
6da49b2
WIP
koppor Dec 21, 2020
dfac705
Speedup processResources
koppor Dec 21, 2020
057ae9f
Merge branch 'speedup-process-resources' into fix-967
koppor Dec 21, 2020
8834fb6
Try path without ./ at the beginning
koppor Dec 21, 2020
5b6f0d8
Output java error on console, too
koppor Dec 21, 2020
fd80c30
Use LOGGER instead of System.err
koppor Dec 21, 2020
c64b5e3
Merge branch 'fix-output-with-wrong-jdk-version' into fix-967
koppor Dec 21, 2020
9f56fd5
Merge branch 'speedup-process-resources' into fix-967
koppor Dec 21, 2020
d15e90f
Fix scroll bar still present
koppor Dec 21, 2020
7de21ad
MinWidth to 80
koppor Dec 21, 2020
8c7cd7a
Merge branch 'master' into fix-967
koppor Dec 21, 2020
f7186f3
Merge branch 'fix-967' of github.com:JabRef/jabref into fix-967
koppor Dec 21, 2020
80557f2
WIP (does not work)
koppor Dec 22, 2020
043a0cc
Merge remote-tracking branch 'origin/master' into fix-967
koppor Dec 29, 2020
c3b02e3
Fix ordering in CHANGELOG.md
koppor Dec 29, 2020
fd118a6
WIP
koppor Dec 29, 2020
f0788f6
WIP - "User changed column size in a way that window can contain all …
koppor Dec 29, 2020
a1633a1
Add documentation on implementation idea
koppor Jan 2, 2021
73d5448
Refine description (and change TableColumnBase to TableColumn)
koppor Jan 3, 2021
f75831d
Cases I0 to I3
koppor Jan 3, 2021
c417d7d
First proposal of case names
koppor Jan 3, 2021
496e505
WIP: Reimplement logic according to comments
koppor Jan 6, 2021
466731f
Merge remote-tracking branch 'origin/master' into fix-967
koppor Jan 7, 2021
caf1e23
WIP
koppor Jan 7, 2021
63af8fd
Merge remote-tracking branch 'origin/master' into fix-967
koppor Jan 10, 2021
274e109
Resizing of colomms works
koppor Jan 10, 2021
910c592
Use EPSILON_MARGIN also for "content has fit into table before"
koppor Jan 10, 2021
513c68c
Merge branch 'master' into fix-967
koppor Jan 21, 2021
286e7f9
Merge remote-tracking branch 'upstream/master' into fix-967
calixtus Feb 6, 2021
caf7232
Merge branch 'main' into fix-967
koppor Oct 14, 2021
609f6a2
Merge branch 'main' into fix-967
koppor Oct 18, 2021
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
Prev Previous commit
Next Next commit
Address some comments
Co-authored-by: Dominik Voigt <[email protected]>
koppor and DominikVoigt committed Dec 18, 2020
commit bcea66cf7f32deb48170ba39847c6bc28bb50862
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@

public class ColumnPreferences {

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

17 changes: 7 additions & 10 deletions src/main/java/org/jabref/gui/maintable/MainTableColumnFactory.java
Original file line number Diff line number Diff line change
@@ -78,7 +78,6 @@ public MainTableColumnFactory(BibDatabaseContext database,
List<TableColumn<BibEntryTableViewModel, ?>> columns = new ArrayList<>();

columnPreferences.getColumns().forEach(column -> {

switch (column.getType()) {
case INDEX:
columns.add(createIndexColumn(column));
@@ -113,18 +112,16 @@ public MainTableColumnFactory(BibDatabaseContext database,
if (!column.getQualifier().isBlank()) {
TableColumn<BibEntryTableViewModel, ?> fieldColumn = createFieldColumn(column);
columns.add(fieldColumn);
fieldColumn.setPrefWidth(ColumnPreferences.DEFAULT_COLUMN_WIDTH);
if (column.getQualifier().equalsIgnoreCase(StandardField.YEAR.getName())) {
// 60 is chosen, because of the optimal width of a four digit field
setExactWidth(fieldColumn, 60);
// 60 is chosen, because of the optimal width of a four digit number
fieldColumn.setPrefWidth(60);
} else if (column.getQualifier().equalsIgnoreCase(InternalField.TYPE_HEADER.getName())) {
// 80 is chosen, because of the optimal width of the entry type
setExactWidth(fieldColumn, 90);
} else if (column.getQualifier().equalsIgnoreCase(StandardField.KEY.getName())) {
// The citation key is smaller than the other fields
// The other option is to set a max width. However, we think that some users have loooooong keys, they want to see
fieldColumn.setMinWidth(ColumnPreferences.DEFAULT_COLUMN_WIDTH / 2);
// 90 is chosen, because of the optimal width of the entry type
fieldColumn.setPrefWidth(90);
} else {
fieldColumn.setMinWidth(ColumnPreferences.DEFAULT_COLUMN_WIDTH);
fieldColumn.setMinWidth(ColumnPreferences.DEFAULT_COLUMN_MIN_WIDTH);
fieldColumn.setPrefWidth(ColumnPreferences.DEFAULT_COLUMN_WIDTH);
}
}
break;
158 changes: 101 additions & 57 deletions src/main/java/org/jabref/gui/maintable/SmartConstrainedResizePolicy.java
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumnBase;
@@ -24,49 +25,68 @@ public class SmartConstrainedResizePolicy implements Callback<TableView.ResizeFe
private static final Logger LOGGER = LoggerFactory.getLogger(SmartConstrainedResizePolicy.class);

private Map<TableColumnBase, Double> expansionShare = new HashMap<>();
List<? extends TableColumn<?, ?>> resizableColumns;
private TableColumn lastModifiedColumn = null;

@Override
public Boolean call(TableView.ResizeFeatures prop) {
if (prop.getColumn() == null) {
TableColumn column = prop.getColumn();
if (column == null) {
// happens at initialization and at window resize
LOGGER.debug("Table is fully rendered");
TableView<?> table = prop.getTable();
resizableColumns = table.getVisibleLeafColumns().stream()
.filter(TableColumnBase::isResizable)
.collect(Collectors.toList());
// This way, the proportions of the columns are kept during resize of the window
determineWidthShare(prop.getTable());
return rearrangeColumns(prop.getTable());
determineExpansionShare();

// Rearrange columns if content fits into displayed table
// Otherwise, the default is good enough
if (contentFitsIntoTable(table)) {
return rearrangeColumns(table);
}
return false;
} else {
if (!column.equals(lastModifiedColumn)) {
lastModifiedColumn = column;
// This way, the proportions of the columns are kept during resize of the window
determineExpansionShare();
}
return constrainedResize(prop);
}
}

private boolean contentFitsIntoTable(TableView<?> table) {
Double tableWidth = getContentWidth(table);
List<? extends TableColumnBase<?, ?>> visibleLeafColumns = table.getVisibleLeafColumns();
Double currentTableContentWidth = visibleLeafColumns.stream().mapToDouble(TableColumnBase::getWidth).sum();
return tableWidth >= currentTableContentWidth;
}

/**
* Determines the share of the total width each column has
*/
private void determineWidthShare(TableView table) {
private void determineExpansionShare() {
// We need to store the initial preferred width, because "setWidth()" does not exist
// There is only "setMinWidth", "setMaxWidth", and "setPrefWidth

Double totalInitialPreferredWidths;
List<? extends TableColumnBase<?, ?>> visibleLeafColumns = table.getVisibleLeafColumns();
totalInitialPreferredWidths = visibleLeafColumns.stream()
.filter(TableColumnBase::isResizable)
.mapToDouble(TableColumnBase::getPrefWidth).sum();
for (TableColumnBase<?, ?> column : visibleLeafColumns) {
if (column.isResizable()) {
expansionShare.put(column, column.getPrefWidth() / totalInitialPreferredWidths);
} else {
expansionShare.put(column, 0d);
}
Double allResizableColumnsWidth = resizableColumns.stream().mapToDouble(TableColumnBase::getPrefWidth).sum();
for (TableColumnBase<?, ?> column : resizableColumns) {
expansionShare.put(column, column.getPrefWidth() / allResizableColumnsWidth);
}
}

/**
* Determines the new width of the column based on the requested delta. It respects the min and max width of the column.
* <br>
* This method is also called if the table content is wider than the window. Thus, it does not respect the overall table width;
* "just" the width constraints of the given column
*
* @param column The column the resize is requested
* @param delta The delta requested
* @return the new size, Optional.empty() if no resize is possible
*/
private Optional<Double> determineNewWidth(TableColumn<?, ?> column, Double delta) {
private Optional<Double> determineNewWidth(TableColumnBase<?, ?> column, Double delta) {
// This is com.sun.javafx.scene.control.skin.Utils.boundedSize with more comments and Optionals

// Calculate newWidth based on delta and constraint of the column
@@ -98,71 +118,95 @@ private Boolean constrainedResize(TableView.ResizeFeatures<?> prop) {
TableView<?> table = prop.getTable();
Double tableWidth = getContentWidth(table);
List<? extends TableColumnBase<?, ?>> visibleLeafColumns = table.getVisibleLeafColumns();
Double requiredWidth = visibleLeafColumns.stream().mapToDouble(TableColumnBase::getWidth).sum();
// The current able content width contains all visible columns: the resizable ones and the non-resizable ones
Double currentTableContentWidth = visibleLeafColumns.stream().mapToDouble(TableColumnBase::getWidth).sum();
Double delta = prop.getDelta();

TableColumn<?, ?> userChosenColumnToResize = prop.getColumn();

boolean columnsCanFitTable = requiredWidth + delta < tableWidth;
boolean columnsCanFitTable = currentTableContentWidth + delta < tableWidth;
if (columnsCanFitTable) {
LOGGER.debug("User shrunk column in that way thus that window can contain all the columns");
if (requiredWidth >= tableWidth) {
LOGGER.debug("Before, the content did not fit. Rearrange everything.");
LOGGER.debug("User window size in that way thus that window can contain all the columns");
if (currentTableContentWidth >= tableWidth) {
LOGGER.debug("Before, the content did not fit. Now it fits. Rearrange everything.");
return rearrangeColumns(table);
}
LOGGER.debug("Everything already fit. We distribute the delta now.");

// Content does already fit
// We "just" need to readjust the column widths
determineNewWidth(userChosenColumnToResize, delta)
.ifPresent(newWidth -> {
double currentWidth = userChosenColumnToResize.getWidth();
Double deltaToApply = newWidth - currentWidth;
for (TableColumnBase<?, ?> col : visibleLeafColumns) {
Double share = expansionShare.get(col);
Double newSize;
if (col.equals(prop.getColumn())) {
// The column resized by the user gets the delta;
newSize = newWidth;
} else {
// The columns not explicitly resized by the user get the negative delta
newSize = col.getWidth() - share * deltaToApply;
}
newSize = Math.min(newSize, col.getMaxWidth());
col.setPrefWidth(newSize);
}
});
return true;
Optional<Double> newWidthOptional = determineNewWidth(userChosenColumnToResize, delta);
newWidthOptional.ifPresent(newWidth -> {
distributeDelta(table, userChosenColumnToResize, newWidth);
});
return newWidthOptional.isPresent();
}

LOGGER.debug("Window smaller than content");

determineNewWidth(userChosenColumnToResize, delta).ifPresent(newWidth ->
userChosenColumnToResize.setPrefWidth(newWidth));
return true;
Optional<Double> newWidth = determineNewWidth(userChosenColumnToResize, delta);
newWidth.ifPresent(userChosenColumnToResize::setPrefWidth);
return newWidth.isPresent();
}

private void distributeDelta(TableView<?> table, TableColumnBase userChosenColumnToResize, Double newWidth) {
userChosenColumnToResize.setPrefWidth(newWidth);

List<? extends TableColumn<?, ?>> columnsToResize = resizableColumns.stream().filter(col -> !col.equals(userChosenColumnToResize)).collect(Collectors.toList());

Double tableWidth = table.getWidth();
Double newContentWidth;

do
{
// in case the userChosenColumnToResize got bigger, the remaining available width will get below 0 --> other columns need to be shrunk
Double remainingAvailableWidth = tableWidth - getContentWidth(table);
LOGGER.debug("Distributing delta {}", remainingAvailableWidth);
for (TableColumnBase<?, ?> col : columnsToResize) {
double share = expansionShare.get(col);
determineNewWidth(col, share * remainingAvailableWidth)
// in case we can do something, do it
// otherwise, the next loop iteration will distribute it
.ifPresent(col::setPrefWidth);
}
newContentWidth = getContentWidth(table);
} while (Math.abs(tableWidth - newContentWidth) > 5d);
}

/**
* Rearranges the widths of all columns according to their shares (proportional to their preferred widths)
*/
private Boolean rearrangeColumns(TableView<?> table) {
Double tableWidth = getContentWidth(table);
List<? extends TableColumnBase<?, ?>> visibleLeafColumns = table.getVisibleLeafColumns();

Double remainingAvailableWidth = tableWidth - getSumMinWidthOfColumns(table);
Double initialContentWidth = getContentWidth(table);

for (TableColumnBase<?, ?> col : visibleLeafColumns) {
double share = expansionShare.get(col);
double newSize = col.getMinWidth() + share * remainingAvailableWidth;
// Implementation idea:
// Each column has to have at least the minimum width
// First, set the minimum width of all columns
// Then, there is available non-assigned space
// Distribute this space in a fair way to all resizable columns

// Just to make sure that we are staying under the total table width (due to rounding errors)
newSize -= 2;
for (TableColumnBase<?, ?> col : resizableColumns) {
col.setPrefWidth(col.getMinWidth());
}

newSize = Math.min(newSize, col.getMaxWidth());
Double tableWidth = table.getWidth();
Double newContentWidth;
do
{
Double remainingAvailableWidth = Math.max(0, tableWidth - getContentWidth(table));
LOGGER.debug("Distributing delta {}", remainingAvailableWidth);
for (TableColumnBase<?, ?> col : resizableColumns) {
double share = expansionShare.get(col);
// Precondition in our case: col has to have minimum width
determineNewWidth(col, share * remainingAvailableWidth)
// in case we can do something, do it
// otherwise, the next loop iteration will distribute it
.ifPresent(col::setPrefWidth);
}
newContentWidth = getContentWidth(table);
} while (Math.abs(tableWidth - newContentWidth) > 5d);

col.setPrefWidth(newSize);
}
return true;
return (Math.floor(initialContentWidth - newContentWidth) != 0d);
}

/**