SelectionColumns do that now automatically. Colspanned cells get ignored Change-Id: Ie427ba8df43ad84786c381def8cec216297feb06tags/7.4.0.beta1
public void setColumnWidth(int index, int px) | public void setColumnWidth(int index, int px) | ||||
throws IllegalArgumentException; | throws IllegalArgumentException; | ||||
/** | |||||
* Sets the column width to as wide as the widest currently visible content | |||||
* in that column. | |||||
* | |||||
* @param index | |||||
* the index of the column for which to calculate the width. | |||||
* @throws IllegalArgumentException | |||||
* if {@code index} is not a valid column index, or if any cell | |||||
* in the given column is a part of a colspan range | |||||
*/ | |||||
public void setColumnWidthToContent(int index) | |||||
throws IllegalArgumentException; | |||||
/** | /** | ||||
* Returns the user-defined width of a column. | * Returns the user-defined width of a column. | ||||
* | * |
} | } | ||||
} | } | ||||
protected abstract class AbstractRowContainer implements RowContainer { | |||||
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; | private EscalatorUpdater updater = EscalatorUpdater.NULL; | ||||
private int rows; | private int rows; | ||||
*/ | */ | ||||
if (isAttached()) { | if (isAttached()) { | ||||
paintInsertRows(index, numberOfRows); | paintInsertRows(index, numberOfRows); | ||||
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. | |||||
*/ | |||||
columnAutoWidthAssignScheduler.reschedule(); | |||||
} | |||||
} | } | ||||
} | } | ||||
int getMaxCellWidth(int colIndex) throws IllegalArgumentException { | int getMaxCellWidth(int colIndex) throws IllegalArgumentException { | ||||
int maxCellWidth = -1; | int maxCellWidth = -1; | ||||
assert isAttached() : "Can't measure max width of cell, since Escalator is not attached to the DOM."; | |||||
NodeList<TableRowElement> rows = root.getRows(); | NodeList<TableRowElement> rows = root.getRows(); | ||||
for (int row = 0; row < rows.getLength(); row++) { | for (int row = 0; row < rows.getLength(); row++) { | ||||
TableRowElement rowElement = rows.getItem(row); | TableRowElement rowElement = rows.getItem(row); | ||||
colIndex); | colIndex); | ||||
if (cellIsPartOfSpan(cellOriginal)) { | if (cellIsPartOfSpan(cellOriginal)) { | ||||
throw new IllegalArgumentException("Encountered a column " | |||||
+ "spanned cell in column " + colIndex + "."); | |||||
continue; | |||||
} | } | ||||
/* | /* | ||||
private int definedWidth = -1; | private int definedWidth = -1; | ||||
private int calculatedWidth = DEFAULT_COLUMN_WIDTH_PX; | private int 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(int px) { | public void setWidth(int px) { | ||||
definedWidth = px; | definedWidth = px; | ||||
calculatedWidth = (px >= 0) ? px : DEFAULT_COLUMN_WIDTH_PX; | |||||
if (px < 0) { | |||||
if (isAttached()) { | |||||
calculateWidth(); | |||||
} else { | |||||
/* | |||||
* the column's width is calculated at Escalator.onLoad | |||||
* via measureIfNeeded! | |||||
*/ | |||||
measuringRequested = true; | |||||
} | |||||
} else { | |||||
calculatedWidth = px; | |||||
} | |||||
} | } | ||||
public int getDefinedWidth() { | public int getDefinedWidth() { | ||||
return definedWidth; | return definedWidth; | ||||
} | } | ||||
/** | |||||
* Returns the actual width in the DOM. | |||||
* | |||||
* @return the width in pixels in the DOM. Returns -1 if the column | |||||
* needs measuring, but has not been yet measured | |||||
*/ | |||||
public int getCalculatedWidth() { | public int getCalculatedWidth() { | ||||
return calculatedWidth; | |||||
/* | |||||
* This might return an untrue value (e.g. during init/onload), | |||||
* since we haven't had a proper chance to actually calculate | |||||
* widths yet. | |||||
* | |||||
* This is fixed during Escalator.onLoad, by the call to | |||||
* "measureIfNeeded", which fixes "everything". | |||||
*/ | |||||
if (!measuringRequested) { | |||||
return calculatedWidth; | |||||
} else { | |||||
return -1; | |||||
} | |||||
} | |||||
/** | |||||
* Checks if the column needs measuring, and then measures it. | |||||
* <p> | |||||
* Called by {@link Escalator#onLoad()}. | |||||
*/ | |||||
public boolean measureAndSetWidthIfNeeded() { | |||||
assert isAttached() : "Column.measureIfNeeded() was called even though Escalator was not attached!"; | |||||
if (measuringRequested) { | |||||
measuringRequested = false; | |||||
setWidth(definedWidth); | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
private void calculateWidth() { | |||||
calculatedWidth = getMaxCellWidth(columns.indexOf(this)); | |||||
} | |||||
public void widthIsFinalized() { | |||||
columnAutoWidthAssignScheduler.cancel(); | |||||
widthHasBeenFinalized = true; | |||||
} | |||||
public boolean isWidthFinalized() { | |||||
return widthHasBeenFinalized; | |||||
} | } | ||||
} | } | ||||
body.paintInsertColumns(index, numberOfColumns, frozen); | body.paintInsertColumns(index, numberOfColumns, frozen); | ||||
footer.paintInsertColumns(index, numberOfColumns, frozen); | footer.paintInsertColumns(index, numberOfColumns, frozen); | ||||
// fix autowidth | |||||
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(); | |||||
} | |||||
} | |||||
// Adjust scrollbar | // Adjust scrollbar | ||||
int pixelsToInsertedColumn = columnConfiguration | int pixelsToInsertedColumn = columnConfiguration | ||||
.getCalculatedColumnsWidth(Range.withLength(0, index)); | .getCalculatedColumnsWidth(Range.withLength(0, index)); | ||||
checkValidColumnIndex(index); | checkValidColumnIndex(index); | ||||
columns.get(index).setWidth(px); | columns.get(index).setWidth(px); | ||||
columns.get(index).widthIsFinalized(); | |||||
widthsArray = null; | widthsArray = null; | ||||
/* | /* | ||||
return columns.get(index).getCalculatedWidth(); | return columns.get(index).getCalculatedWidth(); | ||||
} | } | ||||
@Override | |||||
public void setColumnWidthToContent(int index) | |||||
throws IllegalArgumentException { | |||||
if (index < 0 || index >= getColumnCount()) { | |||||
throw new IllegalArgumentException(index | |||||
+ " is not a valid index for a column"); | |||||
} | |||||
int maxWidth = getMaxCellWidth(index); | |||||
if (maxWidth == -1) { | |||||
return; | |||||
} | |||||
setCalculatedColumnWidth(index, maxWidth); | |||||
header.reapplyColumnWidths(); | |||||
footer.reapplyColumnWidths(); | |||||
body.reapplyColumnWidths(); | |||||
} | |||||
private int getMaxCellWidth(int colIndex) | private int getMaxCellWidth(int colIndex) | ||||
throws IllegalArgumentException { | throws IllegalArgumentException { | ||||
int headerWidth = header.getMaxCellWidth(colIndex); | int headerWidth = header.getMaxCellWidth(colIndex); | ||||
int bodyWidth = body.getMaxCellWidth(colIndex); | int bodyWidth = body.getMaxCellWidth(colIndex); | ||||
int footerWidth = footer.getMaxCellWidth(colIndex); | int footerWidth = footer.getMaxCellWidth(colIndex); | ||||
return Math.max(headerWidth, Math.max(bodyWidth, footerWidth)); | |||||
int maxWidth = Math.max(headerWidth, | |||||
Math.max(bodyWidth, footerWidth)); | |||||
assert maxWidth > 0 : "Got a negative max width for a column, which should be impossible."; | |||||
return maxWidth; | |||||
} | } | ||||
/** | /** | ||||
int sum = 0; | int sum = 0; | ||||
for (int i = columns.getStart(); i < columns.getEnd(); i++) { | for (int i = columns.getStart(); i < columns.getEnd(); i++) { | ||||
sum += getColumnWidthActual(i); | |||||
int columnWidthActual = getColumnWidthActual(i); | |||||
sum += columnWidthActual; | |||||
} | } | ||||
return sum; | return sum; | ||||
} | } | ||||
void setCalculatedColumnWidth(int index, int width) { | |||||
columns.get(index).calculatedWidth = width; | |||||
widthsArray = null; | |||||
} | |||||
int[] getCalculatedColumnWidths() { | int[] getCalculatedColumnWidths() { | ||||
if (widthsArray == null || widthsArray.length != getColumnCount()) { | if (widthsArray == null || widthsArray.length != getColumnCount()) { | ||||
widthsArray = new int[getColumnCount()]; | widthsArray = new int[getColumnCount()]; | ||||
} | } | ||||
}; | }; | ||||
private final ColumnAutoWidthAssignScheduler columnAutoWidthAssignScheduler = new ColumnAutoWidthAssignScheduler(); | |||||
private static native double getPreciseWidth(Element element) | private static native double getPreciseWidth(Element element) | ||||
/*-{ | /*-{ | ||||
if (element.getBoundingClientRect) { | if (element.getBoundingClientRect) { | ||||
* rows. | * rows. | ||||
*/ | */ | ||||
boolean columnsChanged = false; | |||||
for (ColumnConfigurationImpl.Column column : columnConfiguration.columns) { | |||||
boolean columnChanged = column.measureAndSetWidthIfNeeded(); | |||||
if (columnChanged) { | |||||
columnsChanged = true; | |||||
} | |||||
} | |||||
if (columnsChanged) { | |||||
header.reapplyColumnWidths(); | |||||
body.reapplyColumnWidths(); | |||||
footer.reapplyColumnWidths(); | |||||
} | |||||
scroller.attachScrollListener(verticalScrollbar.getElement()); | scroller.attachScrollListener(verticalScrollbar.getElement()); | ||||
scroller.attachScrollListener(horizontalScrollbar.getElement()); | scroller.attachScrollListener(horizontalScrollbar.getElement()); | ||||
scroller.attachMousewheelListener(getElement()); | scroller.attachMousewheelListener(getElement()); | ||||
return null; | return null; | ||||
} | } | ||||
/** | |||||
* Forces the escalator to recalculate the widths of its columns. | |||||
* <p> | |||||
* All columns that haven't been assigned an explicit width will be resized | |||||
* to fit all currently visible contents. | |||||
* | |||||
* @see ColumnConfiguration#setColumnWidth(int, int) | |||||
*/ | |||||
public void calculateColumnWidths() { | |||||
boolean widthsHaveChanged = false; | |||||
for (int colIndex = 0; colIndex < columnConfiguration.getColumnCount(); colIndex++) { | |||||
if (columnConfiguration.getColumnWidth(colIndex) >= 0) { | |||||
continue; | |||||
} | |||||
final int oldColumnWidth = columnConfiguration | |||||
.getColumnWidthActual(colIndex); | |||||
int maxColumnWidth = 0; | |||||
maxColumnWidth = Math.max(maxColumnWidth, | |||||
header.calculateMaxColWidth(colIndex)); | |||||
maxColumnWidth = Math.max(maxColumnWidth, | |||||
body.calculateMaxColWidth(colIndex)); | |||||
maxColumnWidth = Math.max(maxColumnWidth, | |||||
footer.calculateMaxColWidth(colIndex)); | |||||
Logger.getLogger("Escalator.calculateColumnWidths").info( | |||||
"#" + colIndex + ": " + maxColumnWidth + "px"); | |||||
if (oldColumnWidth != maxColumnWidth) { | |||||
columnConfiguration.setCalculatedColumnWidth(colIndex, | |||||
maxColumnWidth); | |||||
widthsHaveChanged = true; | |||||
} | |||||
} | |||||
if (widthsHaveChanged) { | |||||
header.reapplyColumnWidths(); | |||||
body.reapplyColumnWidths(); | |||||
footer.reapplyColumnWidths(); | |||||
recalculateElementSizes(); | |||||
} | |||||
} | |||||
@Override | @Override | ||||
public void setStylePrimaryName(String style) { | public void setStylePrimaryName(String style) { | ||||
super.setStylePrimaryName(style); | super.setStylePrimaryName(style); | ||||
@Override | @Override | ||||
public boolean isWorkPending() { | public boolean isWorkPending() { | ||||
return body.domSorter.waiting; | |||||
return body.domSorter.waiting | |||||
|| columnAutoWidthAssignScheduler.isScheduled; | |||||
} | } | ||||
@Override | @Override |
import com.vaadin.client.ui.grid.sort.SortEvent; | import com.vaadin.client.ui.grid.sort.SortEvent; | ||||
import com.vaadin.client.ui.grid.sort.SortHandler; | import com.vaadin.client.ui.grid.sort.SortHandler; | ||||
import com.vaadin.client.ui.grid.sort.SortOrder; | import com.vaadin.client.ui.grid.sort.SortOrder; | ||||
import com.vaadin.shared.ui.grid.GridColumnState; | |||||
import com.vaadin.shared.ui.grid.GridConstants; | import com.vaadin.shared.ui.grid.GridConstants; | ||||
import com.vaadin.shared.ui.grid.GridStaticCellType; | import com.vaadin.shared.ui.grid.GridStaticCellType; | ||||
import com.vaadin.shared.ui.grid.HeightMode; | import com.vaadin.shared.ui.grid.HeightMode; | ||||
}); | }); | ||||
header.getDefaultRow().getCell(this).setWidget(checkBox); | header.getDefaultRow().getCell(this).setWidget(checkBox); | ||||
} | } | ||||
setWidth(-1); | |||||
initDone = true; | initDone = true; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
private final class AsyncWidthAutodetectRunner { | |||||
private static final int POLLING_PERIOD_MS = 50; | |||||
private final Timer timer = new Timer() { | |||||
@Override | |||||
public void run() { | |||||
/* Detaching the column from the grid should've cancelled */ | |||||
assert grid != null : "Column was detached from Grid before width autodetection completed"; | |||||
/* | |||||
* setting a positive value for the width should've | |||||
* cancelled | |||||
*/ | |||||
assert widthUser < 0 : "User defined width is not negative (to indicate autodetection) anymore!"; | |||||
if (!grid.dataIsBeingFetched) { | |||||
setWidthForce(widthUser); | |||||
} else { | |||||
timer.schedule(POLLING_PERIOD_MS); | |||||
return; | |||||
} | |||||
} | |||||
}; | |||||
/** | |||||
* Schedules an width autodetection. | |||||
* <p> | |||||
* It's not done immediately in case we're retrieving some lazy | |||||
* data, that will affect the appropriate width of the cells. | |||||
*/ | |||||
public void reschedule() { | |||||
/* | |||||
* Check immediately. This will be _actually_ rescheduled if | |||||
* things don't work out. Otherwise, autodetectionage will | |||||
* happen. | |||||
*/ | |||||
timer.schedule(0); | |||||
} | |||||
public void stop() { | |||||
timer.cancel(); | |||||
} | |||||
public boolean isRunning() { | |||||
return timer.isRunning(); | |||||
} | |||||
} | |||||
/** | /** | ||||
* the column is associated with | * the column is associated with | ||||
*/ | */ | ||||
private Grid<T> grid; | private Grid<T> grid; | ||||
/** | /** | ||||
* Width of column in pixels | |||||
* Should the column be visible in the grid | |||||
*/ | */ | ||||
private int width = 100; | |||||
private boolean visible = true; | |||||
/** Width of column in pixels as {@link #setWidth(int)} has been called */ | |||||
private int widthUser = GridColumnState.DEFAULT_COLUMN_WIDTH_PX; | |||||
/** | /** | ||||
* Renderer for rendering a value into the cell | * Renderer for rendering a value into the cell | ||||
private String headerText = ""; | private String headerText = ""; | ||||
private final AsyncWidthAutodetectRunner asyncAutodetectWidth = new AsyncWidthAutodetectRunner(); | |||||
/** | /** | ||||
* Constructs a new column with a simple TextRenderer. | * Constructs a new column with a simple TextRenderer. | ||||
*/ | */ | ||||
this.grid = grid; | this.grid = grid; | ||||
if (grid != null) { | if (grid != null) { | ||||
updateHeader(); | updateHeader(); | ||||
} else { | |||||
asyncAutodetectWidth.stop(); | |||||
} | } | ||||
} | } | ||||
* @return the column itself | * @return the column itself | ||||
*/ | */ | ||||
public GridColumn<C, T> setWidth(int pixels) { | public GridColumn<C, T> setWidth(int pixels) { | ||||
width = pixels; | |||||
widthUser = pixels; | |||||
if (pixels < 0) { | |||||
setWidthAutodetect(); | |||||
} else { | |||||
setWidthAbsolute(pixels); | |||||
} | |||||
return (GridColumn<C, T>) this; | |||||
} | |||||
private void setWidthAutodetect() { | |||||
if (grid != null) { | if (grid != null) { | ||||
int index = grid.indexOfColumn((GridColumn<?, T>) this); | |||||
ColumnConfiguration conf = grid.escalator | |||||
.getColumnConfiguration(); | |||||
conf.setColumnWidth(index, pixels); | |||||
asyncAutodetectWidth.reschedule(); | |||||
} | } | ||||
return (GridColumn<C, T>) this; | |||||
/* | |||||
* It's okay if the colum isn't attached to a grid immediately. The | |||||
* width will be re-set once it gets attached. | |||||
*/ | |||||
} | |||||
private void setWidthAbsolute(int pixels) { | |||||
asyncAutodetectWidth.stop(); | |||||
if (grid != null) { | |||||
setWidthForce(pixels); | |||||
} | |||||
} | |||||
private void setWidthForce(int pixels) { | |||||
int index = grid.columns.indexOf(this); | |||||
ColumnConfiguration conf = grid.escalator.getColumnConfiguration(); | |||||
conf.setColumnWidth(index, pixels); | |||||
} | } | ||||
/** | /** | ||||
* Returns the pixel width of the column | |||||
* Returns the pixel width of the column as given by the user. | |||||
* <p> | |||||
* <em>Note:</em> If a negative value was given to | |||||
* {@link #setWidth(int)}, that same negative value is returned here. | |||||
* | * | ||||
* @return pixel width of the column | |||||
* @return pixel width of the column, or a negative number if the column | |||||
* width has been automatically calculated. | |||||
* @see #setWidth(int) | |||||
* @see #getWidthActual() | |||||
*/ | */ | ||||
public int getWidth() { | public int getWidth() { | ||||
return width; | |||||
return widthUser; | |||||
} | |||||
/** | |||||
* Returns the effective pixel width of the column. | |||||
* <p> | |||||
* This differs from {@link #getWidth()} only when the column has been | |||||
* automatically resized. | |||||
* | |||||
* @return pixel width of the column. | |||||
*/ | |||||
public int getWidthActual() { | |||||
return grid.escalator.getColumnConfiguration() | |||||
.getColumnWidthActual(grid.columns.indexOf(this)); | |||||
} | } | ||||
void reapplyWidth() { | void reapplyWidth() { | ||||
setWidth(width); | |||||
setWidth(getWidth()); | |||||
} | } | ||||
/** | /** | ||||
return getClass().getSimpleName() + "[" + details.trim() + "]"; | return getClass().getSimpleName() + "[" + details.trim() + "]"; | ||||
} | } | ||||
boolean widthCalculationPending() { | |||||
return asyncAutodetectWidth.isRunning(); | |||||
} | |||||
} | } | ||||
protected class BodyUpdater implements EscalatorUpdater { | protected class BodyUpdater implements EscalatorUpdater { | ||||
body.removeRows(newSize, oldSize - newSize); | body.removeRows(newSize, oldSize - newSize); | ||||
} | } | ||||
dataIsBeingFetched = true; | |||||
Range visibleRowRange = escalator.getVisibleRowRange(); | Range visibleRowRange = escalator.getVisibleRowRange(); | ||||
dataSource.ensureAvailability(visibleRowRange.getStart(), | dataSource.ensureAvailability(visibleRowRange.getStart(), | ||||
visibleRowRange.length()); | visibleRowRange.length()); | ||||
cellFocusHandler.offsetRangeBy(1); | cellFocusHandler.offsetRangeBy(1); | ||||
selectionColumn = new SelectionColumn(selectColumnRenderer); | selectionColumn = new SelectionColumn(selectColumnRenderer); | ||||
// FIXME: this needs to be done elsewhere, requires design... | |||||
selectionColumn.setWidth(40); | |||||
addColumnSkipSelectionColumnCheck(selectionColumn, 0); | addColumnSkipSelectionColumnCheck(selectionColumn, 0); | ||||
selectionColumn.initDone(); | selectionColumn.initDone(); | ||||
} else { | } else { | ||||
Scheduler.get().scheduleFinally(new ScheduledCommand() { | Scheduler.get().scheduleFinally(new ScheduledCommand() { | ||||
@Override | @Override | ||||
public void execute() { | public void execute() { | ||||
handler.onDataAvailable(new DataAvailableEvent( | |||||
currentDataAvailable)); | |||||
if (!dataIsBeingFetched) { | |||||
handler.onDataAvailable(new DataAvailableEvent( | |||||
currentDataAvailable)); | |||||
} | |||||
} | } | ||||
}); | }); | ||||
return addHandler(handler, DataAvailableEvent.TYPE); | return addHandler(handler, DataAvailableEvent.TYPE); | ||||
@Override | @Override | ||||
public boolean isWorkPending() { | public boolean isWorkPending() { | ||||
return escalator.isWorkPending() || dataIsBeingFetched; | |||||
return escalator.isWorkPending() || dataIsBeingFetched | |||||
|| anyColumnIsBeingResized(); | |||||
} | |||||
private boolean anyColumnIsBeingResized() { | |||||
for (AbstractGridColumn<?, ?> column : columns) { | |||||
if (column.widthCalculationPending()) { | |||||
return true; | |||||
} | |||||
} | |||||
return false; | |||||
} | } | ||||
/** | /** |
*/ | */ | ||||
package com.vaadin.client.ui.grid; | package com.vaadin.client.ui.grid; | ||||
/** | /** | ||||
* Represents a column in the {@link Grid}. | * Represents a column in the {@link Grid}. | ||||
* | * |
*/ | */ | ||||
public class GridColumnState implements Serializable { | public class GridColumnState implements Serializable { | ||||
public static final int DEFAULT_COLUMN_WIDTH_PX = -1; | |||||
/** | /** | ||||
* Id used by grid connector to map server side column with client side | * Id used by grid connector to map server side column with client side | ||||
* column | * column | ||||
public String id; | public String id; | ||||
/** | /** | ||||
* Column width in pixels. Default column width is 100px. | |||||
* Column width in pixels. Default column width is | |||||
* {@value #DEFAULT_COLUMN_WIDTH_PX}. | |||||
*/ | */ | ||||
public int width = 100; | |||||
public int width = DEFAULT_COLUMN_WIDTH_PX; | |||||
/** | /** | ||||
* The connector for the renderer used to render the cells in this column. | * The connector for the renderer used to render the cells in this column. |
/* | |||||
* Copyright 2000-2014 Vaadin Ltd. | |||||
* | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |||||
* use this file except in compliance with the License. You may obtain a copy of | |||||
* the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |||||
* License for the specific language governing permissions and limitations under | |||||
* the License. | |||||
*/ | |||||
package com.vaadin.tests.components.grid; | |||||
import static org.junit.Assert.assertEquals; | |||||
import org.junit.Before; | |||||
import org.junit.Test; | |||||
import org.openqa.selenium.By; | |||||
import org.openqa.selenium.WebElement; | |||||
import com.vaadin.tests.tb3.MultiBrowserTest; | |||||
@SuppressWarnings("boxing") | |||||
public abstract class AbstractGridColumnAutoWidthTest extends MultiBrowserTest { | |||||
public static final int TOTAL_MARGIN_PX = 13; | |||||
@Before | |||||
public void before() { | |||||
openTestURL(); | |||||
} | |||||
@Test | |||||
public void testNarrowHeaderWideBody() { | |||||
WebElement[] col = getColumn(1); | |||||
int headerWidth = col[0].getSize().getWidth(); | |||||
int bodyWidth = col[1].getSize().getWidth(); | |||||
int colWidth = col[2].getSize().getWidth() - TOTAL_MARGIN_PX; | |||||
assertLessThan("header should've been narrower than body", headerWidth, | |||||
bodyWidth); | |||||
assertEquals("column should've been roughly as wide as the body", | |||||
bodyWidth, colWidth, 5); | |||||
} | |||||
@Test | |||||
public void testWideHeaderNarrowBody() { | |||||
WebElement[] col = getColumn(2); | |||||
int headerWidth = col[0].getSize().getWidth(); | |||||
int bodyWidth = col[1].getSize().getWidth(); | |||||
int colWidth = col[2].getSize().getWidth() - TOTAL_MARGIN_PX; | |||||
assertGreater("header should've been wider than body", headerWidth, | |||||
bodyWidth); | |||||
assertEquals("column should've been roughly as wide as the header", | |||||
headerWidth, colWidth, 5); | |||||
} | |||||
@Test | |||||
public void testTooNarrowColumn() { | |||||
WebElement[] col = getColumn(3); | |||||
int headerWidth = col[0].getSize().getWidth(); | |||||
int colWidth = col[2].getSize().getWidth() - TOTAL_MARGIN_PX; | |||||
assertLessThan("column should've been narrower than content", colWidth, | |||||
headerWidth); | |||||
} | |||||
@Test | |||||
public void testTooWideColumn() { | |||||
WebElement[] col = getColumn(4); | |||||
int headerWidth = col[0].getSize().getWidth(); | |||||
int colWidth = col[2].getSize().getWidth() - TOTAL_MARGIN_PX; | |||||
assertGreater("column should've been wider than content", colWidth, | |||||
headerWidth); | |||||
} | |||||
private WebElement[] getColumn(int i) { | |||||
WebElement[] col = new WebElement[3]; | |||||
col[0] = getDriver().findElement( | |||||
By.xpath("//thead//th[" + (i + 1) + "]/span")); | |||||
col[1] = getDriver().findElement( | |||||
By.xpath("//tbody//td[" + (i + 1) + "]/span")); | |||||
col[2] = getDriver().findElement( | |||||
By.xpath("//tbody//td[" + (i + 1) + "]")); | |||||
return col; | |||||
} | |||||
} |
/* | |||||
* Copyright 2000-2014 Vaadin Ltd. | |||||
* | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |||||
* use this file except in compliance with the License. You may obtain a copy of | |||||
* the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |||||
* License for the specific language governing permissions and limitations under | |||||
* the License. | |||||
*/ | |||||
package com.vaadin.tests.components.grid; | |||||
import com.vaadin.data.Container; | |||||
import com.vaadin.data.util.IndexedContainer; | |||||
import com.vaadin.server.VaadinRequest; | |||||
import com.vaadin.tests.components.AbstractTestUI; | |||||
import com.vaadin.ui.Grid; | |||||
import com.vaadin.ui.Grid.Column; | |||||
import com.vaadin.ui.Grid.SelectionMode; | |||||
import com.vaadin.ui.components.grid.renderers.HtmlRenderer; | |||||
public class GridColumnAutoWidth extends AbstractTestUI { | |||||
@Override | |||||
protected void setup(VaadinRequest request) { | |||||
Grid grid = new Grid(createContainer()); | |||||
grid.getColumn("fixed width narrow").setWidth(50); | |||||
grid.getColumn("fixed width wide").setWidth(200); | |||||
for (Object propertyId : grid.getContainerDataSource() | |||||
.getContainerPropertyIds()) { | |||||
Column column = grid.getColumn(propertyId); | |||||
column.setRenderer(new HtmlRenderer()); | |||||
grid.getHeaderRow(0).getCell(propertyId) | |||||
.setHtml("<span>" + column.getHeaderCaption() + "</span>"); | |||||
} | |||||
grid.setSelectionMode(SelectionMode.NONE); | |||||
grid.setWidth("700px"); | |||||
addComponent(grid); | |||||
} | |||||
private static Container.Indexed createContainer() { | |||||
IndexedContainer c = new IndexedContainer(); | |||||
c.addContainerProperty("equal width", String.class, | |||||
"<span>equal width</span>"); | |||||
c.addContainerProperty("short", String.class, | |||||
"<span>a very long cell content</span>"); | |||||
c.addContainerProperty("a very long header content", String.class, | |||||
"<span>short</span>"); | |||||
c.addContainerProperty("fixed width narrow", String.class, | |||||
"<span>fixed width narrow</span>"); | |||||
c.addContainerProperty("fixed width wide", String.class, | |||||
"<span>fixed width wide</span>"); | |||||
c.addItem(); | |||||
return c; | |||||
} | |||||
} |
/* | |||||
* Copyright 2000-2014 Vaadin Ltd. | |||||
* | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |||||
* use this file except in compliance with the License. You may obtain a copy of | |||||
* the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |||||
* License for the specific language governing permissions and limitations under | |||||
* the License. | |||||
*/ | |||||
package com.vaadin.tests.components.grid; | |||||
import com.vaadin.annotations.Widgetset; | |||||
import com.vaadin.server.VaadinRequest; | |||||
import com.vaadin.tests.components.AbstractTestUI; | |||||
import com.vaadin.tests.widgetset.TestingWidgetSet; | |||||
import com.vaadin.ui.AbstractComponent; | |||||
@Widgetset(TestingWidgetSet.NAME) | |||||
public class GridColumnAutoWidthClient extends AbstractTestUI { | |||||
public static class GridColumnAutoWidthClientComponent extends | |||||
AbstractComponent { | |||||
} | |||||
@Override | |||||
protected void setup(VaadinRequest request) { | |||||
addComponent(new GridColumnAutoWidthClientComponent()); | |||||
} | |||||
} |
/* | |||||
* Copyright 2000-2014 Vaadin Ltd. | |||||
* | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |||||
* use this file except in compliance with the License. You may obtain a copy of | |||||
* the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |||||
* License for the specific language governing permissions and limitations under | |||||
* the License. | |||||
*/ | |||||
package com.vaadin.tests.components.grid; | |||||
import com.vaadin.tests.annotations.TestCategory; | |||||
@TestCategory("grid") | |||||
public class GridColumnAutoWidthClientTest extends | |||||
AbstractGridColumnAutoWidthTest { | |||||
@Override | |||||
protected Class<?> getUIClass() { | |||||
return GridColumnAutoWidthClient.class; | |||||
} | |||||
} |
/* | |||||
* Copyright 2000-2014 Vaadin Ltd. | |||||
* | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |||||
* use this file except in compliance with the License. You may obtain a copy of | |||||
* the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |||||
* License for the specific language governing permissions and limitations under | |||||
* the License. | |||||
*/ | |||||
package com.vaadin.tests.components.grid; | |||||
import com.vaadin.tests.annotations.TestCategory; | |||||
@TestCategory("grid") | |||||
public class GridColumnAutoWidthServerTest extends | |||||
AbstractGridColumnAutoWidthTest { | |||||
@Override | |||||
protected Class<?> getUIClass() { | |||||
return GridColumnAutoWidth.class; | |||||
} | |||||
} |
protected static final String REMOVE_50_ROWS_FROM_ALMOST_BOTTOM = "Remove 50 rows from almost bottom"; | protected static final String REMOVE_50_ROWS_FROM_ALMOST_BOTTOM = "Remove 50 rows from almost bottom"; | ||||
protected static final String ADD_ONE_OF_EACH_ROW = "Add one of each row"; | protected static final String ADD_ONE_OF_EACH_ROW = "Add one of each row"; | ||||
protected static final String RESIZE_FIRST_COLUMN_TO_MAX_WIDTH = "Resize first column to max width"; | protected static final String RESIZE_FIRST_COLUMN_TO_MAX_WIDTH = "Resize first column to max width"; | ||||
protected static final String RESIZE_FIRST_COLUMN_TO_100PX = "Resize first column to 100 px"; | |||||
protected static final String HEADER_ROWS = "Header Rows"; | protected static final String HEADER_ROWS = "Header Rows"; | ||||
protected static final String BODY_ROWS = "Body Rows"; | protected static final String BODY_ROWS = "Body Rows"; |
} | } | ||||
private void assertCellPresent(String content) { | private void assertCellPresent(String content) { | ||||
assertNotNull(findByXPath("//td[text()='" + content + "']")); | |||||
assertNotNull("A cell with content \"" + content | |||||
+ "\" should've been found", findByXPath("//td[text()='" | |||||
+ content + "']")); | |||||
} | } | ||||
private void assertCellNotPresent(String content) { | private void assertCellNotPresent(String content) { | ||||
assertNull(findByXPath("//td[text()='" + content + "']")); | |||||
assertNull("A cell with content \"" + content | |||||
+ "\" should've not been found", findByXPath("//td[text()='" | |||||
+ content + "']")); | |||||
} | } | ||||
private void scrollToTop() { | private void scrollToTop() { | ||||
} | } | ||||
private Object executeScript(String script, Object args) { | private Object executeScript(String script, Object args) { | ||||
@SuppressWarnings("hiding") | |||||
final WebDriver driver = getDriver(); | final WebDriver driver = getDriver(); | ||||
if (driver instanceof JavascriptExecutor) { | if (driver instanceof JavascriptExecutor) { | ||||
final JavascriptExecutor je = (JavascriptExecutor) driver; | final JavascriptExecutor je = (JavascriptExecutor) driver; |
int width = getGridElement().getCell(0, col).getSize().getWidth(); | int width = getGridElement().getCell(0, col).getSize().getWidth(); | ||||
if (col <= 6) { | if (col <= 6) { | ||||
// Growing column widths | // Growing column widths | ||||
assertEquals(50 + col * 25, width); | |||||
} else { | |||||
assertEquals(100, width); | |||||
int expectedWidth = 50 + col * 25; | |||||
assertEquals("column " + col + " has incorrect width", | |||||
expectedWidth, width); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
assertEquals(200, width); | assertEquals(200, width); | ||||
selectMenuPath("Component", "Columns", "Column 0", "Width", "auto"); | selectMenuPath("Component", "Columns", "Column 0", "Width", "auto"); | ||||
width = getGridElement().getCell(0, 0).getSize().getWidth(); | |||||
assertEquals(100, width); | |||||
int autoWidth = getGridElement().getCell(0, 0).getSize().getWidth(); | |||||
assertLessThan("Automatic sizing should've shrunk the column", | |||||
autoWidth, width); | |||||
} | } | ||||
@Test | @Test |
openTestURL(); | openTestURL(); | ||||
populate(); | populate(); | ||||
int singleCellWidth = getWidth(getBodyCell(0, 0)); | |||||
int doubleCellWidth = singleCellWidth * 2; | |||||
int firstCellWidth = getWidth(getBodyCell(0, 0)); | |||||
int secondCellWidth = getWidth(getBodyCell(0, 1)); | |||||
int doubleCellWidth = firstCellWidth + secondCellWidth; | |||||
selectMenuPath(FEATURES, COLUMN_SPANNING, COLSPAN_NORMAL); | selectMenuPath(FEATURES, COLUMN_SPANNING, COLSPAN_NORMAL); | ||||
openTestURL(); | openTestURL(); | ||||
selectMenuPath(GENERAL, POPULATE_COLUMN_ROW); | selectMenuPath(GENERAL, POPULATE_COLUMN_ROW); | ||||
selectMenuPath(COLUMNS_AND_ROWS, COLUMNS, RESIZE_FIRST_COLUMN_TO_100PX); | |||||
int originalWidth = getBodyCell(0, 0).getSize().getWidth(); | int originalWidth = getBodyCell(0, 0).getSize().getWidth(); | ||||
assertEquals(100, originalWidth); | |||||
selectMenuPath(COLUMNS_AND_ROWS, COLUMNS, | selectMenuPath(COLUMNS_AND_ROWS, COLUMNS, | ||||
RESIZE_FIRST_COLUMN_TO_MAX_WIDTH); | RESIZE_FIRST_COLUMN_TO_MAX_WIDTH); | ||||
int newWidth = getBodyCell(0, 0).getSize().getWidth(); | int newWidth = getBodyCell(0, 0).getSize().getWidth(); |
cell = getGridElement().getCell(0, 1); | cell = getGridElement().getCell(0, 1); | ||||
assertEquals(150, cell.getSize().getWidth()); | assertEquals(150, cell.getSize().getWidth()); | ||||
// Set first column to be auto sized (defaults to 100px currently) | |||||
selectMenuPath("Component", "Columns", "Column 0", "Column 0 Width", | selectMenuPath("Component", "Columns", "Column 0", "Column 0 Width", | ||||
"Auto"); | "Auto"); | ||||
// since the column 0 was previously 200, it should've shrunk when | |||||
// autoresizing. | |||||
cell = getGridElement().getCell(0, 0); | cell = getGridElement().getCell(0, 0); | ||||
assertEquals(100, cell.getSize().getWidth()); | |||||
assertLessThan("", cell.getSize().getWidth(), 200); | |||||
} | } | ||||
@Test | @Test |
@Override | @Override | ||||
public void execute() { | public void execute() { | ||||
escalator.getColumnConfiguration() | escalator.getColumnConfiguration() | ||||
.setColumnWidthToContent(0); | |||||
.setColumnWidth(0, -1); | |||||
} | } | ||||
}, menupath); | }, menupath); | ||||
addMenuCommand("Resize first column to 100 px", new ScheduledCommand() { | |||||
@Override | |||||
public void execute() { | |||||
escalator.getColumnConfiguration().setColumnWidth(0, 100); | |||||
} | |||||
}, menupath); | |||||
} | } | ||||
private void createHeaderRowsMenu() { | private void createHeaderRowsMenu() { |
return columnConfiguration.getColumnWidthActual(index); | return columnConfiguration.getColumnWidthActual(index); | ||||
} | } | ||||
@Override | |||||
public void setColumnWidthToContent(int index) | |||||
throws IllegalArgumentException { | |||||
int oldWidth = columnConfiguration.getColumnWidthActual(index); | |||||
columnConfiguration.setColumnWidthToContent(index); | |||||
int newWidth = columnConfiguration.getColumnWidthActual(index); | |||||
logWidget.log("Changed column " + index + " width from " + oldWidth | |||||
+ "px to " + newWidth + "px"); | |||||
logWidget.updateDebugLabel(); | |||||
} | |||||
@Override | @Override | ||||
public void refreshColumns(int index, int numberOfColumns) | public void refreshColumns(int index, int numberOfColumns) | ||||
throws IndexOutOfBoundsException, IllegalArgumentException { | throws IndexOutOfBoundsException, IllegalArgumentException { |
/* | |||||
* Copyright 2000-2014 Vaadin Ltd. | |||||
* | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |||||
* use this file except in compliance with the License. You may obtain a copy of | |||||
* the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |||||
* License for the specific language governing permissions and limitations under | |||||
* the License. | |||||
*/ | |||||
package com.vaadin.tests.widgetset.client.grid; | |||||
import com.google.gwt.core.client.GWT; | |||||
import com.google.gwt.user.client.ui.Widget; | |||||
import com.vaadin.client.ui.AbstractComponentConnector; | |||||
import com.vaadin.shared.ui.Connect; | |||||
import com.vaadin.tests.components.grid.GridColumnAutoWidthClient.GridColumnAutoWidthClientComponent; | |||||
@Connect(GridColumnAutoWidthClientComponent.class) | |||||
public class GridColumnAutoWidthClientConnector extends | |||||
AbstractComponentConnector { | |||||
@Override | |||||
public Widget getWidget() { | |||||
return GWT.create(GridColumnAutoWidthClientWidget.class); | |||||
} | |||||
} |
/* | |||||
* Copyright 2000-2014 Vaadin Ltd. | |||||
* | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |||||
* use this file except in compliance with the License. You may obtain a copy of | |||||
* the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |||||
* License for the specific language governing permissions and limitations under | |||||
* the License. | |||||
*/ | |||||
package com.vaadin.tests.widgetset.client.grid; | |||||
import java.util.ArrayList; | |||||
import java.util.Arrays; | |||||
import java.util.List; | |||||
import com.vaadin.client.ui.grid.Grid; | |||||
import com.vaadin.client.ui.grid.Grid.SelectionMode; | |||||
import com.vaadin.client.ui.grid.GridColumn; | |||||
import com.vaadin.client.ui.grid.datasources.ListDataSource; | |||||
import com.vaadin.client.ui.grid.renderers.HtmlRenderer; | |||||
public class GridColumnAutoWidthClientWidget extends | |||||
PureGWTTestApplication<Grid<List<String>>> { | |||||
private Grid<List<String>> grid; | |||||
private class Col extends GridColumn<String, List<String>> { | |||||
public Col(String header) { | |||||
super(header, new HtmlRenderer()); | |||||
} | |||||
@Override | |||||
public String getValue(List<String> row) { | |||||
int index = grid.getColumns().indexOf(this); | |||||
return "<span>" + String.valueOf(row.get(index)) + "</span>"; | |||||
} | |||||
} | |||||
protected GridColumnAutoWidthClientWidget() { | |||||
super(new Grid<List<String>>()); | |||||
grid = getTestedWidget(); | |||||
grid.setSelectionMode(SelectionMode.NONE); | |||||
grid.setWidth("700px"); | |||||
List<List<String>> list = new ArrayList<List<String>>(); | |||||
list.add(Arrays.asList("equal length", "a very long cell content", | |||||
"short", "fixed width narrow", "fixed width wide")); | |||||
grid.setDataSource(new ListDataSource<List<String>>(list)); | |||||
addColumn("equal length"); | |||||
addColumn("short"); | |||||
addColumn("a very long header content"); | |||||
addColumn("fixed width narrow").setWidth(50); | |||||
addColumn("fixed width wide").setWidth(200); | |||||
addNorth(grid, 400); | |||||
} | |||||
private Col addColumn(String header) { | |||||
Col column = (Col) grid.addColumn(new Col(header)); | |||||
grid.getHeaderRow(0).getCell(column) | |||||
.setHtml("<span>" + header + "</span>"); | |||||
return column; | |||||
} | |||||
} |