aboutsummaryrefslogtreecommitdiffstats
path: root/client/src/com/vaadin
diff options
context:
space:
mode:
authorHenrik Paul <henrik@vaadin.com>2015-01-28 13:40:00 +0200
committerHenrik Paul <henrik@vaadin.com>2015-02-04 15:09:28 +0200
commit7cffb158ceab46df983e9ff81326e360f9e5235d (patch)
tree45cfa3cc89520513278820a4ed914f04e42d8c00 /client/src/com/vaadin
parent103b177475e0029abed00eec68e752492feafa61 (diff)
downloadvaadin-framework-7cffb158ceab46df983e9ff81326e360f9e5235d.tar.gz
vaadin-framework-7cffb158ceab46df983e9ff81326e360f9e5235d.zip
Speeds up column adding in Grid (#16474)
Grid.onStateChange is now about 40% faster when adding columns, and setting several column widths has now way less overhead. Change-Id: I7bd900324207bfb2543a1a90390665b90206aefd
Diffstat (limited to 'client/src/com/vaadin')
-rw-r--r--client/src/com/vaadin/client/widget/escalator/ColumnConfiguration.java19
-rw-r--r--client/src/com/vaadin/client/widgets/Escalator.java127
-rw-r--r--client/src/com/vaadin/client/widgets/Grid.java93
3 files changed, 120 insertions, 119 deletions
diff --git a/client/src/com/vaadin/client/widget/escalator/ColumnConfiguration.java b/client/src/com/vaadin/client/widget/escalator/ColumnConfiguration.java
index af49dcd64f..76f6a55b8a 100644
--- a/client/src/com/vaadin/client/widget/escalator/ColumnConfiguration.java
+++ b/client/src/com/vaadin/client/widget/escalator/ColumnConfiguration.java
@@ -16,7 +16,7 @@
package com.vaadin.client.widget.escalator;
-import com.vaadin.client.widgets.Escalator;
+import java.util.Map;
/**
* A representation of the columns in an instance of {@link Escalator}.
@@ -141,6 +141,23 @@ public interface ColumnConfiguration {
public double getColumnWidth(int index) throws IllegalArgumentException;
/**
+ * Sets widths for a set of columns.
+ *
+ * @param indexWidthMap
+ * a map from column index to its respective width to be set. If
+ * the given width for a column index is negative, the column is
+ * resized-to-fit.
+ * @throws IllegalArgumentException
+ * if {@code indexWidthMap} is {@code null}
+ * @throws IllegalArgumentException
+ * if any column index in {@code indexWidthMap} is invalid
+ * @throws NullPointerException
+ * If any value in the map is <code>null</code>
+ */
+ public void setColumnWidths(Map<Integer, Double> indexWidthMap)
+ throws IllegalArgumentException;
+
+ /**
* Returns the actual width of a column.
*
* @param index
diff --git a/client/src/com/vaadin/client/widgets/Escalator.java b/client/src/com/vaadin/client/widgets/Escalator.java
index 6a8fb311b1..94b6efc0d7 100644
--- a/client/src/com/vaadin/client/widgets/Escalator.java
+++ b/client/src/com/vaadin/client/widgets/Escalator.java
@@ -16,11 +16,13 @@
package com.vaadin.client.widgets;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -1161,47 +1163,6 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
}
}
- private class ColumnAutoWidthAssignScheduler {
- private boolean isScheduled = false;
- private final ScheduledCommand widthCommand = new ScheduledCommand() {
- @Override
- public void execute() {
- if (!isScheduled) {
- return;
- }
-
- isScheduled = false;
-
- ColumnConfigurationImpl cc = columnConfiguration;
- for (int col = 0; col < cc.getColumnCount(); col++) {
- ColumnConfigurationImpl.Column column = cc.columns.get(col);
- if (!column.isWidthFinalized()) {
- cc.setColumnWidth(col, -1);
- column.widthIsFinalized();
- }
- }
- }
- };
-
- /**
- * Calculates the widths of all uncalculated cells once the javascript
- * execution is done.
- * <p>
- * This method makes sure that any duplicate requests in the same cycle
- * are ignored.
- */
- public void reschedule() {
- if (!isScheduled) {
- isScheduled = true;
- Scheduler.get().scheduleFinally(widthCommand);
- }
- }
-
- public void cancel() {
- isScheduled = false;
- }
- }
-
protected abstract class AbstractRowContainer implements RowContainer {
private EscalatorUpdater updater = EscalatorUpdater.NULL;
@@ -1422,14 +1383,18 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
if (rows == numberOfRows) {
/*
* We are inserting the first rows in this container. We
- * potentially need to autocalculate the widths for the
- * cells for the first time.
- *
- * To make sure that can take the entire dataset into
- * account, we'll do this deferredly, so that each container
- * section gets populated before we start calculating.
+ * potentially need to set the widths for the cells for the
+ * first time.
*/
- columnAutoWidthAssignScheduler.reschedule();
+ Map<Integer, Double> colWidths = new HashMap<Integer, Double>();
+ Double width = Double
+ .valueOf(ColumnConfigurationImpl.Column.DEFAULT_COLUMN_WIDTH_PX);
+ for (int i = 0; i < getColumnConfiguration()
+ .getColumnCount(); i++) {
+ Integer col = Integer.valueOf(i);
+ colWidths.put(col, width);
+ }
+ getColumnConfiguration().setColumnWidths(colWidths);
}
}
}
@@ -3808,19 +3773,12 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
private class ColumnConfigurationImpl implements ColumnConfiguration {
public class Column {
- private static final int DEFAULT_COLUMN_WIDTH_PX = 100;
+ public static final double DEFAULT_COLUMN_WIDTH_PX = 100;
private double definedWidth = -1;
private double calculatedWidth = DEFAULT_COLUMN_WIDTH_PX;
private boolean measuringRequested = false;
- /**
- * If a column has been created (either via insertRow or
- * insertColumn), it will be given an arbitrary width, and only then
- * a width will be defined.
- */
- private boolean widthHasBeenFinalized = false;
-
public void setWidth(double px) {
definedWidth = px;
@@ -3884,15 +3842,6 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
private void calculateWidth() {
calculatedWidth = getMaxCellWidth(columns.indexOf(this));
}
-
- public void widthIsFinalized() {
- columnAutoWidthAssignScheduler.cancel();
- widthHasBeenFinalized = true;
- }
-
- public boolean isWidthFinalized() {
- return widthHasBeenFinalized;
- }
}
private final List<Column> columns = new ArrayList<Column>();
@@ -4082,13 +4031,17 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
body.paintInsertColumns(index, numberOfColumns, frozen);
footer.paintInsertColumns(index, numberOfColumns, frozen);
- // fix autowidth
+ // fix initial width
if (header.getRowCount() > 0 || body.getRowCount() > 0
|| footer.getRowCount() > 0) {
- for (int col = index; col < index + numberOfColumns; col++) {
- getColumnConfiguration().setColumnWidth(col, -1);
- columnConfiguration.columns.get(col).widthIsFinalized();
+
+ Map<Integer, Double> colWidths = new HashMap<Integer, Double>();
+ Double width = Double.valueOf(Column.DEFAULT_COLUMN_WIDTH_PX);
+ for (int i = index; i < index + numberOfColumns; i++) {
+ Integer col = Integer.valueOf(i);
+ colWidths.put(col, width);
}
+ getColumnConfiguration().setColumnWidths(colWidths);
}
// Adjust scrollbar
@@ -4170,16 +4123,30 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
@Override
public void setColumnWidth(int index, double px)
throws IllegalArgumentException {
- checkValidColumnIndex(index);
+ setColumnWidths(Collections.singletonMap(Integer.valueOf(index),
+ Double.valueOf(px)));
+ }
- columns.get(index).setWidth(px);
- columns.get(index).widthIsFinalized();
- widthsArray = null;
+ @Override
+ public void setColumnWidths(Map<Integer, Double> indexWidthMap)
+ throws IllegalArgumentException {
- /*
- * TODO [[optimize]]: only modify the elements that are actually
- * modified.
- */
+ if (indexWidthMap == null) {
+ throw new IllegalArgumentException("indexWidthMap was null");
+ }
+
+ if (indexWidthMap.isEmpty()) {
+ return;
+ }
+
+ for (Entry<Integer, Double> entry : indexWidthMap.entrySet()) {
+ int index = entry.getKey().intValue();
+ double width = entry.getValue().doubleValue();
+ checkValidColumnIndex(index);
+ columns.get(index).setWidth(width);
+ }
+
+ widthsArray = null;
header.reapplyColumnWidths();
body.reapplyColumnWidths();
footer.reapplyColumnWidths();
@@ -4373,8 +4340,6 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
}
};
- private final ColumnAutoWidthAssignScheduler columnAutoWidthAssignScheduler = new ColumnAutoWidthAssignScheduler();
-
/**
* Creates a new Escalator widget instance.
*/
@@ -5144,9 +5109,7 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
@Override
public boolean isWorkPending() {
- return body.domSorter.waiting
- || columnAutoWidthAssignScheduler.isScheduled
- || verticalScrollbar.isWorkPending()
+ return body.domSorter.waiting || verticalScrollbar.isWorkPending()
|| horizontalScrollbar.isWorkPending();
}
diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java
index ea69968a75..e112d868b4 100644
--- a/client/src/com/vaadin/client/widgets/Grid.java
+++ b/client/src/com/vaadin/client/widgets/Grid.java
@@ -22,6 +22,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -2217,21 +2218,67 @@ public class Grid<T> extends ResizeComposite implements
rescheduleCount = 0;
assert !dataIsBeingFetched : "Trying to calculate column widths even though data is still being fetched.";
- /*
- * At this point we assume that no data is being fetched anymore.
- * Everything's rendered in the DOM. Now we just make sure
- * everything fits as it should.
- */
+
+ if (columnsAreGuaranteedToBeWiderThanGrid()) {
+ applyColumnWidths();
+ } else {
+ applyColumnWidthsWithExpansion();
+ }
+ }
+
+ private boolean columnsAreGuaranteedToBeWiderThanGrid() {
+ double freeSpace = escalator.getInnerWidth();
+ for (Column<?, ?> column : getColumns()) {
+ if (column.getWidth() >= 0) {
+ freeSpace -= column.getWidth();
+ } else if (column.getMinimumWidth() >= 0) {
+ freeSpace -= column.getMinimumWidth();
+ }
+ }
+ return freeSpace < 0;
+ }
+
+ @SuppressWarnings("boxing")
+ private void applyColumnWidths() {
+
+ /* Step 1: Apply all column widths as they are. */
+
+ Map<Integer, Double> selfWidths = new LinkedHashMap<Integer, Double>();
+ List<Column<?, T>> columns = getColumns();
+ for (int index = 0; index < columns.size(); index++) {
+ selfWidths.put(index, columns.get(index).getWidth());
+ }
+ Grid.this.escalator.getColumnConfiguration().setColumnWidths(
+ selfWidths);
/*
- * Quick optimization: if the sum of fixed widths and minimum widths
- * is greater than the grid can display, we already know that things
- * will be squeezed and no expansion will happen.
+ * Step 2: Make sure that each column ends up obeying their min/max
+ * width constraints if defined as autowidth. If constraints are
+ * violated, fix it.
*/
- if (gridWasTooNarrowAndEverythingWasFixedAlready()) {
- return;
+
+ Map<Integer, Double> constrainedWidths = new LinkedHashMap<Integer, Double>();
+ for (int index = 0; index < columns.size(); index++) {
+ Column<?, T> column = columns.get(index);
+
+ boolean hasAutoWidth = column.getWidth() < 0;
+ if (!hasAutoWidth) {
+ continue;
+ }
+
+ // TODO: bug: these don't honor the CSS max/min. :(
+ double actualWidth = column.getWidthActual();
+ if (actualWidth < getMinWidth(column)) {
+ constrainedWidths.put(index, column.getMinimumWidth());
+ } else if (actualWidth > getMaxWidth(column)) {
+ constrainedWidths.put(index, column.getMaximumWidth());
+ }
}
+ Grid.this.escalator.getColumnConfiguration().setColumnWidths(
+ constrainedWidths);
+ }
+ private void applyColumnWidthsWithExpansion() {
boolean someColumnExpands = false;
int totalRatios = 0;
double reservedPixels = 0;
@@ -2416,32 +2463,6 @@ public class Grid<T> extends ResizeComposite implements
} while (minWidthsCausedReflows);
}
- private boolean gridWasTooNarrowAndEverythingWasFixedAlready() {
- double freeSpace = escalator.getInnerWidth();
- for (Column<?, ?> column : getColumns()) {
- if (column.getWidth() >= 0) {
- freeSpace -= column.getWidth();
- } else if (column.getMinimumWidth() >= 0) {
- freeSpace -= column.getMinimumWidth();
- }
- }
-
- if (freeSpace < 0) {
- for (Column<?, ?> column : getColumns()) {
- column.doSetWidth(column.getWidth());
-
- boolean wasFixedWidth = column.getWidth() <= 0;
- boolean newWidthIsSmallerThanMinWidth = column
- .getWidthActual() < getMinWidth(column);
- if (wasFixedWidth && newWidthIsSmallerThanMinWidth) {
- column.doSetWidth(column.getMinimumWidth());
- }
- }
- }
-
- return freeSpace < 0;
- }
-
private int getExpandRatio(Column<?, ?> column,
boolean someColumnExpands) {
int expandRatio = column.getExpandRatio();