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;
}
}
- 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;
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);
}
}
}
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;
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>();
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
@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();
}
};
- private final ColumnAutoWidthAssignScheduler columnAutoWidthAssignScheduler = new ColumnAutoWidthAssignScheduler();
-
/**
* Creates a new Escalator widget instance.
*/
@Override
public boolean isWorkPending() {
- return body.domSorter.waiting
- || columnAutoWidthAssignScheduler.isScheduled
- || verticalScrollbar.isWorkPending()
+ return body.domSorter.waiting || verticalScrollbar.isWorkPending()
|| horizontalScrollbar.isWorkPending();
}
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;
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;
} 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();