summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--client/src/com/vaadin/client/ui/VScrollTable.java508
-rw-r--r--client/src/com/vaadin/client/ui/VTreeTable.java38
-rw-r--r--client/src/com/vaadin/client/ui/table/TableConnector.java1
-rw-r--r--uitest/src/com/vaadin/tests/components/treetable/TreeTableExtraScrollBarWithChildren.html69
-rw-r--r--uitest/src/com/vaadin/tests/components/treetable/TreeTableExtraScrollbarWithChildren.java92
5 files changed, 626 insertions, 82 deletions
diff --git a/client/src/com/vaadin/client/ui/VScrollTable.java b/client/src/com/vaadin/client/ui/VScrollTable.java
index 75d67b82d6..c76dd38d8f 100644
--- a/client/src/com/vaadin/client/ui/VScrollTable.java
+++ b/client/src/com/vaadin/client/ui/VScrollTable.java
@@ -1191,6 +1191,39 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
return totalRows;
}
+ /**
+ * Returns the extra space that is given to the header column when column
+ * width is determined by header text.
+ *
+ * @return extra space in pixels
+ */
+ private int getHeaderPadding() {
+ return scrollBody.getCellExtraWidth();
+ }
+
+ /**
+ * This method exists for the needs of {@link VTreeTable} only. Not part of
+ * the official API, <b>extend at your own risk</b>. May be removed or
+ * replaced in the future.
+ *
+ * @return index of TreeTable's hierarchy column, or -1 if not applicable
+ */
+ protected int getHierarchyColumnIndex() {
+ return -1;
+ }
+
+ /**
+ * For internal use only. May be removed or replaced in the future.
+ */
+ public void updateMaxIndent() {
+ int oldIndent = scrollBody.getMaxIndent();
+ scrollBody.calculateMaxIndent();
+ if (oldIndent != scrollBody.getMaxIndent()) {
+ // indent updated, headers might need adjusting
+ triggerLazyColumnAdjustment(true);
+ }
+ }
+
/** For internal use only. May be removed or replaced in the future. */
public void focusRowFromBody() {
if (selectedRowKeys.size() == 1) {
@@ -1382,6 +1415,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* amount of rows in data set
*/
public void updateBody(UIDL uidl, int firstRow, int reqRows) {
+ int oldIndent = scrollBody.getMaxIndent();
if (uidl == null || reqRows < 1) {
// container is empty, remove possibly existing rows
if (firstRow <= 0) {
@@ -1399,6 +1433,11 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
scrollBody.renderRows(uidl, firstRow, reqRows);
discardRowsOutsideCacheWindow();
+ scrollBody.calculateMaxIndent();
+ if (oldIndent != scrollBody.getMaxIndent()) {
+ // indent updated, headers might need adjusting
+ headerChangedDuringUpdate = true;
+ }
}
/** For internal use only. May be removed or replaced in the future. */
@@ -1591,31 +1630,55 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
return tHead.getHeaderCell(index).getColKey();
}
- private void setColWidth(int colIndex, int w, boolean isDefinedWidth) {
+ /**
+ * Note: not part of the official API, extend at your own risk. May be
+ * removed or replaced in the future.
+ *
+ * Sets the indicated column's width for headers and scrollBody alike.
+ *
+ * @param colIndex
+ * index of the modified column
+ * @param w
+ * new width (may be subject to modifications if doesn't meet
+ * minimum requirements)
+ * @param isDefinedWidth
+ * disables expand ratio if set true
+ */
+ protected void setColWidth(int colIndex, int w, boolean isDefinedWidth) {
final HeaderCell hcell = tHead.getHeaderCell(colIndex);
// Make sure that the column grows to accommodate the sort indicator if
// necessary.
- if (w < hcell.getMinWidth()) {
- w = hcell.getMinWidth();
+ // get min width with no indent or padding
+ int minWidth = hcell.getMinWidth(false, false);
+ if (w < minWidth) {
+ w = minWidth;
}
- // Set header column width
+ // Set header column width WITHOUT INDENT
hcell.setWidth(w, isDefinedWidth);
+ // Set footer column width likewise
+ FooterCell fcell = tFoot.getFooterCell(colIndex);
+ fcell.setWidth(w, isDefinedWidth);
+
// Ensure indicators have been taken into account
tHead.resizeCaptionContainer(hcell);
+ // Make sure that the body column grows to accommodate the indent if
+ // necessary.
+ // get min width with indent, no padding
+ minWidth = hcell.getMinWidth(true, false);
+ if (w < minWidth) {
+ w = minWidth;
+ }
+
// Set body column width
scrollBody.setColWidth(colIndex, w);
-
- // Set footer column width
- FooterCell fcell = tFoot.getFooterCell(colIndex);
- fcell.setWidth(w, isDefinedWidth);
}
private int getColWidth(String colKey) {
- return tHead.getHeaderCell(colKey).getWidth();
+ return tHead.getHeaderCell(colKey).getWidthWithIndent();
}
/**
@@ -1813,22 +1876,37 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
tHead.enableBrowserIntelligence();
tFoot.enableBrowserIntelligence();
+ int hierarchyColumnIndent = scrollBody != null ? scrollBody
+ .getMaxIndent() : 0;
+ HeaderCell hierarchyHeaderWithExpandRatio = null;
+
// first loop: collect natural widths
while (headCells.hasNext()) {
final HeaderCell hCell = (HeaderCell) headCells.next();
final FooterCell fCell = (FooterCell) footCells.next();
+ boolean needsIndent = hierarchyColumnIndent > 0
+ && hCell.isHierarchyColumn();
int w = hCell.getWidth();
if (hCell.isDefinedWidth()) {
// server has defined column width explicitly
+ if (needsIndent && w < hierarchyColumnIndent) {
+ // hierarchy indent overrides explicitly set width
+ w = hierarchyColumnIndent;
+ }
totalExplicitColumnsWidths += w;
} else {
if (hCell.getExpandRatio() > 0) {
expandRatioDivider += hCell.getExpandRatio();
w = 0;
+ if (needsIndent && w < hierarchyColumnIndent) {
+ hierarchyHeaderWithExpandRatio = hCell;
+ // don't add to widths here, because will be included in
+ // the expand ratio space if there's enough of it
+ }
} else {
// get and store greater of header width and column width,
- // and
- // store it as a minimumn natural col width
+ // and store it as a minimum natural column width (these
+ // already contain the indent if any)
int headerWidth = hCell.getNaturalColumnWidth(i);
int footerWidth = fCell.getNaturalColumnWidth(i);
w = headerWidth > footerWidth ? headerWidth : footerWidth;
@@ -1840,6 +1918,9 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
total += w;
i++;
}
+ if (hierarchyHeaderWithExpandRatio != null) {
+ total += hierarchyColumnIndent;
+ }
tHead.disableBrowserIntelligence();
tFoot.disableBrowserIntelligence();
@@ -1871,13 +1952,24 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
if (availW > total) {
// natural size is smaller than available space
- final int extraSpace = availW - total;
+ int extraSpace = availW - total;
+ if (hierarchyHeaderWithExpandRatio != null) {
+ /*
+ * add the indent's space back to ensure each column gets an
+ * even share according to the expand ratios (note: if the
+ * allocated space isn't enough for the hierarchy column it
+ * shall be treated like a defined width column and the indent
+ * space gets removed from the extra space again)
+ */
+ extraSpace += hierarchyColumnIndent;
+ }
final int totalWidthR = total - totalExplicitColumnsWidths;
int checksum = 0;
if (extraSpace == 1) {
// We cannot divide one single pixel so we give it the first
// undefined column
+ // no need to worry about indent here
headCells = tHead.iterator();
i = 0;
checksum = availW;
@@ -1891,6 +1983,22 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
}
} else if (expandRatioDivider > 0) {
+ boolean setIndentToHierarchyHeader = false;
+ if (hierarchyHeaderWithExpandRatio != null) {
+ // ensure first that the hierarchyColumn gets at least the
+ // space allocated for indent
+ final int newSpace = Math
+ .round((extraSpace * (hierarchyHeaderWithExpandRatio
+ .getExpandRatio() / expandRatioDivider)));
+ if (newSpace < hierarchyColumnIndent) {
+ // not enough space for indent, remove indent from the
+ // extraSpace again and handle hierarchy column's header
+ // separately
+ setIndentToHierarchyHeader = true;
+ extraSpace -= hierarchyColumnIndent;
+ }
+ }
+
// visible columns have some active expand ratios, excess
// space is divided according to them
headCells = tHead.iterator();
@@ -1899,9 +2007,17 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
HeaderCell hCell = (HeaderCell) headCells.next();
if (hCell.getExpandRatio() > 0) {
int w = widths[i];
- final int newSpace = Math.round((extraSpace * (hCell
- .getExpandRatio() / expandRatioDivider)));
- w += newSpace;
+ if (setIndentToHierarchyHeader
+ && hierarchyHeaderWithExpandRatio.equals(hCell)) {
+ // hierarchy column's header is no longer part of
+ // the expansion divide and only gets indent
+ w += hierarchyColumnIndent;
+ } else {
+ final int newSpace = Math
+ .round((extraSpace * (hCell
+ .getExpandRatio() / expandRatioDivider)));
+ w += newSpace;
+ }
widths[i] = w;
}
checksum += widths[i];
@@ -1911,6 +2027,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
// no expand ratios defined, we will share extra space
// relatively to "natural widths" among those without
// explicit width
+ // no need to worry about indent here, it's already included
headCells = tHead.iterator();
i = 0;
while (headCells.hasNext()) {
@@ -1946,7 +2063,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
}
} else {
- // bodys size will be more than available and scrollbar will appear
+ // body's size will be more than available and scrollbar will appear
}
// last loop: set possibly modified values or reset if new tBody
@@ -2046,8 +2163,8 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
}
/**
- * Note, this method is not official api although declared as protected.
- * Extend at you own risk.
+ * Note: this method is not part of official API although declared as
+ * protected. Extend at your own risk.
*
* @return true if content area will have scrollbars visible.
*/
@@ -2430,6 +2547,16 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
expandRatio = 0;
}
+ /**
+ * Sets width to the header cell. This width should not include any
+ * possible indent modifications that are present in
+ * {@link VScrollTableBody#getMaxIndent()}.
+ *
+ * @param w
+ * required width of the cell sans indentations
+ * @param ensureDefinedWidth
+ * disables expand ratio if required
+ */
public void setWidth(int w, boolean ensureDefinedWidth) {
if (ensureDefinedWidth) {
definedWidth = true;
@@ -2453,15 +2580,23 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* unless TD width is not explicitly set.
*/
if (scrollBody != null) {
- int tdWidth = width + scrollBody.getCellExtraWidth();
+ int maxIndent = scrollBody.getMaxIndent();
+ if (w < maxIndent && isHierarchyColumn()) {
+ w = maxIndent;
+ }
+ int tdWidth = w + scrollBody.getCellExtraWidth();
setWidth(tdWidth + "px");
} else {
Scheduler.get().scheduleDeferred(new Command() {
@Override
public void execute() {
- int tdWidth = width
- + scrollBody.getCellExtraWidth();
+ int maxIndent = scrollBody.getMaxIndent();
+ int tdWidth = width;
+ if (tdWidth < maxIndent && isHierarchyColumn()) {
+ tdWidth = maxIndent;
+ }
+ tdWidth += scrollBody.getCellExtraWidth();
setWidth(tdWidth + "px");
}
});
@@ -2484,10 +2619,45 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
return definedWidth && width >= 0;
}
+ /**
+ * This method exists for the needs of {@link VTreeTable} only.
+ *
+ * Returns the pixels width of the header cell. This includes the
+ * indent, if applicable.
+ *
+ * @return The width in pixels
+ */
+ protected int getWidthWithIndent() {
+ if (scrollBody != null && isHierarchyColumn()) {
+ int maxIndent = scrollBody.getMaxIndent();
+ if (maxIndent > width) {
+ return maxIndent;
+ }
+ }
+ return width;
+ }
+
+ /**
+ * Returns the pixels width of the header cell.
+ *
+ * @return The width in pixels
+ */
public int getWidth() {
return width;
}
+ /**
+ * This method exists for the needs of {@link VTreeTable} only.
+ *
+ * @return <code>true</code> if this is hierarcyColumn's header cell,
+ * <code>false</code> otherwise
+ */
+ private boolean isHierarchyColumn() {
+ int hierarchyColumnIndex = getHierarchyColumnIndex();
+ return hierarchyColumnIndex >= 0
+ && tHead.visibleCells.indexOf(this) == hierarchyColumnIndex;
+ }
+
public void setText(String headerText) {
DOM.setInnerHTML(captionContainer, headerText);
}
@@ -2742,7 +2912,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
DOM.setCapture(getElement());
dragStartX = DOM.eventGetClientX(event);
colIndex = getColIndexByKey(cid);
- originalWidth = getWidth();
+ originalWidth = getWidthWithIndent();
DOM.eventPreventDefault(event);
break;
case Event.ONMOUSEUP:
@@ -2774,8 +2944,11 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
tHead.disableAutoColumnWidthCalculation(this);
int newWidth = originalWidth + deltaX;
- if (newWidth < getMinWidth()) {
- newWidth = getMinWidth();
+ // get min width with indent, no padding
+ int minWidth = getMinWidth(true, false);
+ if (newWidth < minWidth) {
+ // already includes indent if any
+ newWidth = minWidth;
}
setColWidth(colIndex, newWidth, true);
triggerLazyColumnAdjustment(false);
@@ -2787,12 +2960,37 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
}
}
- public int getMinWidth() {
- int cellExtraWidth = 0;
+ /**
+ * Returns the smallest possible cell width in pixels.
+ *
+ * @param includeIndent
+ * - width should include hierarchy column indent if
+ * applicable (VTreeTable only)
+ * @param includeCellExtraWidth
+ * - width should include paddings etc.
+ * @return
+ */
+ private int getMinWidth(boolean includeIndent,
+ boolean includeCellExtraWidth) {
+ int minWidth = sortIndicator.getOffsetWidth();
if (scrollBody != null) {
- cellExtraWidth += scrollBody.getCellExtraWidth();
+ // check the need for indent before adding paddings etc.
+ if (includeIndent && isHierarchyColumn()) {
+ int maxIndent = scrollBody.getMaxIndent();
+ if (minWidth < maxIndent) {
+ minWidth = maxIndent;
+ }
+ }
+ if (includeCellExtraWidth) {
+ minWidth += scrollBody.getCellExtraWidth();
+ }
}
- return cellExtraWidth + sortIndicator.getOffsetWidth();
+ return minWidth;
+ }
+
+ public int getMinWidth() {
+ // get min width with padding, no indent
+ return getMinWidth(false, true);
}
public String getCaption() {
@@ -2823,16 +3021,20 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* @return
*/
public int getNaturalColumnWidth(int columnIndex) {
+ final int iw = columnIndex == getHierarchyColumnIndex() ? scrollBody
+ .getMaxIndent() : 0;
if (isDefinedWidth()) {
+ if (iw > width) {
+ return iw;
+ }
return width;
} else {
if (naturalWidth < 0) {
// This is recently revealed column. Try to detect a proper
- // value (greater of header and data
- // cols)
+ // value (greater of header and data columns)
int hw = captionContainer.getOffsetWidth()
- + scrollBody.getCellExtraWidth();
+ + getHeaderPadding();
if (BrowserInfo.get().isGecko()) {
hw += sortIndicator.getOffsetWidth();
}
@@ -2848,7 +3050,13 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
final int cw = scrollBody.getColWidth(columnIndex);
naturalWidth = (hw > cw ? hw : cw);
}
- return naturalWidth;
+ if (iw > naturalWidth) {
+ // indent is temporary value, naturalWidth shouldn't be
+ // updated
+ return iw;
+ } else {
+ return naturalWidth;
+ }
}
}
@@ -2945,32 +3153,49 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
public void resizeCaptionContainer(HeaderCell cell) {
HeaderCell lastcell = getHeaderCell(visibleCells.size() - 1);
+ int columnSelectorOffset = columnSelector.getOffsetWidth();
- // Measure column widths
- int columnTotalWidth = 0;
- for (Widget w : visibleCells) {
- columnTotalWidth += w.getOffsetWidth();
- }
-
- if (cell == lastcell
- && columnSelector.getOffsetWidth() > 0
- && columnTotalWidth >= div.getOffsetWidth()
- - columnSelector.getOffsetWidth()
+ if (cell == lastcell && columnSelectorOffset > 0
&& !hasVerticalScrollbar()) {
- // Ensure column caption is visible when placed under the column
- // selector widget by shifting and resizing the caption.
- int offset = 0;
- int diff = div.getOffsetWidth() - columnTotalWidth;
- if (diff < columnSelector.getOffsetWidth() && diff > 0) {
- // If the difference is less than the column selectors width
- // then just offset by the
- // difference
- offset = columnSelector.getOffsetWidth() - diff;
+
+ // Measure column widths
+ int columnTotalWidth = 0;
+ for (Widget w : visibleCells) {
+ int cellExtraWidth = w.getOffsetWidth();
+ if (scrollBody != null
+ && visibleCells.indexOf(w) == getHierarchyColumnIndex()
+ && cellExtraWidth < scrollBody.getMaxIndent()) {
+ // indent must be taken into consideration even if it
+ // hasn't been applied yet
+ columnTotalWidth += scrollBody.getMaxIndent();
+ } else {
+ columnTotalWidth += cellExtraWidth;
+ }
+ }
+
+ int divOffset = div.getOffsetWidth();
+ if (columnTotalWidth >= divOffset - columnSelectorOffset) {
+ /*
+ * Ensure column caption is visible when placed under the
+ * column selector widget by shifting and resizing the
+ * caption.
+ */
+ int offset = 0;
+ int diff = divOffset - columnTotalWidth;
+ if (diff < columnSelectorOffset && diff > 0) {
+ /*
+ * If the difference is less than the column selectors
+ * width then just offset by the difference
+ */
+ offset = columnSelectorOffset - diff;
+ } else {
+ // Else offset by the whole column selector
+ offset = columnSelectorOffset;
+ }
+ lastcell.resizeCaptionContainer(offset);
} else {
- // Else offset by the whole column selector
- offset = columnSelector.getOffsetWidth();
+ cell.resizeCaptionContainer(0);
}
- lastcell.resizeCaptionContainer(offset);
} else {
cell.resizeCaptionContainer(0);
}
@@ -3033,10 +3258,14 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
// Make sure to accomodate for the sort indicator if
// necessary.
int width = Integer.parseInt(widthStr);
- if (width < c.getMinWidth()) {
- width = c.getMinWidth();
+ int widthWithoutAddedIndent = width;
+
+ // get min width with indent, no padding
+ int minWidth = c.getMinWidth(true, false);
+ if (width < minWidth) {
+ width = minWidth;
}
- if (width != c.getWidth() && scrollBody != null) {
+ if (scrollBody != null && width != c.getWidthWithIndent()) {
// Do a more thorough update if a column is resized from
// the server *after* the header has been properly
// initialized
@@ -3052,7 +3281,13 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
});
refreshContentWidths = true;
} else {
- c.setWidth(width, true);
+ // get min width with no indent or padding
+ minWidth = c.getMinWidth(false, false);
+ if (widthWithoutAddedIndent < minWidth) {
+ widthWithoutAddedIndent = minWidth;
+ }
+ // save min width without indent
+ c.setWidth(widthWithoutAddedIndent, true);
}
} else if (recalcWidths) {
c.setUndefinedWidth();
@@ -3507,12 +3742,14 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
}
/**
- * Sets the width of the cell
+ * Sets the width of the cell. This width should not include any
+ * possible indent modifications that are present in
+ * {@link VScrollTableBody#getMaxIndent()}.
*
* @param w
* The width of the cell
* @param ensureDefinedWidth
- * Ensures the the given width is not recalculated
+ * Ensures that the given width is not recalculated
*/
public void setWidth(int w, boolean ensureDefinedWidth) {
@@ -3549,7 +3786,13 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* unless TD width is not explicitly set.
*/
if (scrollBody != null) {
- int tdWidth = width + scrollBody.getCellExtraWidth()
+ int maxIndent = scrollBody.getMaxIndent();
+ if (w < maxIndent
+ && tFoot.visibleCells.indexOf(this) == getHierarchyColumnIndex()) {
+ // ensure there's room for the indent
+ w = maxIndent;
+ }
+ int tdWidth = w + scrollBody.getCellExtraWidth()
- borderWidths;
setWidth(Math.max(tdWidth, 0) + "px");
} else {
@@ -3557,8 +3800,14 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
@Override
public void execute() {
- int tdWidth = width
- + scrollBody.getCellExtraWidth()
+ int tdWidth = width;
+ int maxIndent = scrollBody.getMaxIndent();
+ if (tdWidth < maxIndent
+ && tFoot.visibleCells.indexOf(this) == getHierarchyColumnIndex()) {
+ // ensure there's room for the indent
+ tdWidth = maxIndent;
+ }
+ tdWidth += scrollBody.getCellExtraWidth()
- borderWidths;
setWidth(Math.max(tdWidth, 0) + "px");
}
@@ -3571,6 +3820,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* Sets the width to undefined
*/
public void setUndefinedWidth() {
+ definedWidth = false;
setWidth(-1, false);
}
@@ -3585,7 +3835,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
}
/**
- * Returns the pixels width of the footer cell
+ * Returns the pixels width of the footer cell.
*
* @return The width in pixels
*/
@@ -3699,7 +3949,12 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* @return
*/
public int getNaturalColumnWidth(int columnIndex) {
+ final int iw = columnIndex == getHierarchyColumnIndex() ? scrollBody
+ .getMaxIndent() : 0;
if (isDefinedWidth()) {
+ if (iw > width) {
+ return iw;
+ }
return width;
} else {
if (naturalWidth < 0) {
@@ -3708,7 +3963,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
// cols)
final int hw = ((Element) getElement().getLastChild())
- .getOffsetWidth() + scrollBody.getCellExtraWidth();
+ .getOffsetWidth() + getHeaderPadding();
if (columnIndex < 0) {
columnIndex = 0;
for (Iterator<Widget> it = tHead.iterator(); it
@@ -3721,7 +3976,11 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
final int cw = scrollBody.getColWidth(columnIndex);
naturalWidth = (hw > cw ? hw : cw);
}
- return naturalWidth;
+ if (iw > naturalWidth) {
+ return iw;
+ } else {
+ return naturalWidth;
+ }
}
}
@@ -4627,6 +4886,28 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
return cellExtraWidth;
}
+ /**
+ * This method exists for the needs of {@link VTreeTable} only. May be
+ * removed or replaced in the future.</br> </br> Returns the maximum
+ * indent of the hierarcyColumn, if applicable.
+ *
+ * @see {@link VScrollTable#getHierarchyColumnIndex()}
+ *
+ * @return maximum indent in pixels
+ */
+ protected int getMaxIndent() {
+ return 0;
+ }
+
+ /**
+ * This method exists for the needs of {@link VTreeTable} only. May be
+ * removed or replaced in the future.</br> </br> Calculates the maximum
+ * indent of the hierarcyColumn, if applicable.
+ */
+ protected void calculateMaxIndent() {
+ // NOP
+ }
+
private void detectExtrawidth() {
NodeList<TableRowElement> rows = tBodyElement.getRows();
if (rows.getLength() == 0) {
@@ -4806,8 +5087,23 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
protected void setCellWidth(int cellIx, int width) {
final Element cell = DOM.getChild(getElement(), cellIx);
- cell.getFirstChildElement().getStyle()
- .setPropertyPx("width", width);
+ Style wrapperStyle = cell.getFirstChildElement().getStyle();
+ int wrapperWidth = width;
+ if (BrowserInfo.get().isWebkit()
+ || BrowserInfo.get().isOpera10()) {
+ /*
+ * Some versions of Webkit and Opera ignore the width
+ * definition of zero width table cells. Instead, use 1px
+ * and compensate with a negative margin.
+ */
+ if (width == 0) {
+ wrapperWidth = 1;
+ wrapperStyle.setMarginRight(-1, Unit.PX);
+ } else {
+ wrapperStyle.clearMarginRight();
+ }
+ }
+ wrapperStyle.setPropertyPx("width", wrapperWidth);
cell.getStyle().setPropertyPx("width", width);
}
@@ -5866,7 +6162,8 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
@Override
public void execute() {
if (showRowHeaders) {
- setCellWidth(0, tHead.getHeaderCell(0).getWidth());
+ setCellWidth(0, tHead.getHeaderCell(0)
+ .getWidthWithIndent());
calcAndSetSpanWidthOnCell(1);
} else {
calcAndSetSpanWidthOnCell(0);
@@ -6100,14 +6397,35 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
int totalExplicitColumnsWidths = 0;
float expandRatioDivider = 0;
int colIndex = 0;
+
+ int hierarchyColumnIndent = scrollBody.getMaxIndent();
+ int hierarchyColumnIndex = getHierarchyColumnIndex();
+ HeaderCell hierarchyHeaderInNeedOfFurtherHandling = null;
+
while (headCells.hasNext()) {
final HeaderCell hCell = (HeaderCell) headCells.next();
+ boolean hasIndent = hierarchyColumnIndent > 0
+ && hCell.isHierarchyColumn();
if (hCell.isDefinedWidth()) {
- totalExplicitColumnsWidths += hCell.getWidth();
- usedMinimumWidth += hCell.getWidth();
+ // get width without indent to find out whether adjustments
+ // are needed (requires special handling further ahead)
+ int w = hCell.getWidth();
+ if (hasIndent && w < hierarchyColumnIndent) {
+ // enforce indent if necessary
+ w = hierarchyColumnIndent;
+ hierarchyHeaderInNeedOfFurtherHandling = hCell;
+ }
+ totalExplicitColumnsWidths += w;
+ usedMinimumWidth += w;
} else {
- usedMinimumWidth += hCell.getNaturalColumnWidth(colIndex);
+ // natural width already includes indent if any
+ int naturalColumnWidth = hCell
+ .getNaturalColumnWidth(colIndex);
+ usedMinimumWidth += naturalColumnWidth;
expandRatioDivider += hCell.getExpandRatio();
+ if (hasIndent) {
+ hierarchyHeaderInNeedOfFurtherHandling = hCell;
+ }
}
colIndex++;
}
@@ -6152,6 +6470,28 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
int totalUndefinedNaturalWidths = usedMinimumWidth
- totalExplicitColumnsWidths;
+ if (hierarchyHeaderInNeedOfFurtherHandling != null
+ && !hierarchyHeaderInNeedOfFurtherHandling.isDefinedWidth()) {
+ // ensure the cell gets enough space for the indent
+ int w = hierarchyHeaderInNeedOfFurtherHandling
+ .getNaturalColumnWidth(hierarchyColumnIndex);
+ int newSpace = Math.round(w + (float) extraSpace * (float) w
+ / totalUndefinedNaturalWidths);
+ if (newSpace >= hierarchyColumnIndent) {
+ // no special handling required
+ hierarchyHeaderInNeedOfFurtherHandling = null;
+ } else {
+ // treat as a defined width column of indent's width
+ totalExplicitColumnsWidths += hierarchyColumnIndent;
+ usedMinimumWidth -= w - hierarchyColumnIndent;
+ totalUndefinedNaturalWidths = usedMinimumWidth
+ - totalExplicitColumnsWidths;
+ expandRatioDivider += hierarchyHeaderInNeedOfFurtherHandling
+ .getExpandRatio();
+ extraSpace = Math.max(availW - usedMinimumWidth, 0);
+ }
+ }
+
// we have some space that can be divided optimally
HeaderCell hCell;
colIndex = 0;
@@ -6167,7 +6507,10 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
newSpace = Math.round((w + extraSpace
* hCell.getExpandRatio() / expandRatioDivider));
} else {
- if (totalUndefinedNaturalWidths != 0) {
+ if (hierarchyHeaderInNeedOfFurtherHandling == hCell) {
+ // still exists, so needs exactly the indent's width
+ newSpace = hierarchyColumnIndent;
+ } else if (totalUndefinedNaturalWidths != 0) {
// divide relatively to natural column widths
newSpace = Math.round(w + (float) extraSpace
* (float) w / totalUndefinedNaturalWidths);
@@ -6177,8 +6520,21 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
}
checksum += newSpace;
setColWidth(colIndex, newSpace, false);
+
} else {
- checksum += hCell.getWidth();
+ if (hierarchyHeaderInNeedOfFurtherHandling == hCell) {
+ // defined with enforced into indent width
+ checksum += hierarchyColumnIndent;
+ setColWidth(colIndex, hierarchyColumnIndent, false);
+ } else {
+ int cellWidth = hCell.getWidthWithIndent();
+ checksum += cellWidth;
+ if (hCell.isHierarchyColumn()) {
+ // update in case the indent has changed
+ // (not detectable earlier)
+ setColWidth(colIndex, cellWidth, true);
+ }
+ }
}
colIndex++;
}
@@ -6194,8 +6550,8 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
while (headCells.hasNext()) {
HeaderCell hc = (HeaderCell) headCells.next();
if (!hc.isDefinedWidth()) {
- setColWidth(colIndex,
- hc.getWidth() + availW - checksum, false);
+ setColWidth(colIndex, hc.getWidthWithIndent() + availW
+ - checksum, false);
break;
}
colIndex++;
diff --git a/client/src/com/vaadin/client/ui/VTreeTable.java b/client/src/com/vaadin/client/ui/VTreeTable.java
index f65198865c..097b9c7ab2 100644
--- a/client/src/com/vaadin/client/ui/VTreeTable.java
+++ b/client/src/com/vaadin/client/ui/VTreeTable.java
@@ -122,8 +122,14 @@ public class VTreeTable extends VScrollTable {
}
}
+ @Override
+ protected int getHierarchyColumnIndex() {
+ return colIndexOfHierarchy + (showRowHeaders ? 1 : 0);
+ }
+
public class VTreeTableScrollBody extends VScrollTable.VScrollTableBody {
private int indentWidth = -1;
+ private int maxIndent = 0;
VTreeTableScrollBody() {
super();
@@ -232,6 +238,11 @@ public class VTreeTable extends VScrollTable {
treeSpacer.getParentElement().getStyle()
.setPaddingLeft(getIndent(), Unit.PX);
treeSpacer.getStyle().setWidth(getIndent(), Unit.PX);
+ int colWidth = getColWidth(getHierarchyColumnIndex());
+ if (colWidth > 0 && getIndent() > colWidth) {
+ VTreeTable.this.setColWidth(getHierarchyColumnIndex(),
+ getIndent(), false);
+ }
}
}
@@ -277,16 +288,12 @@ public class VTreeTable extends VScrollTable {
// hierarchy column
int indent = getIndent();
if (indent != -1) {
- width = Math.max(width - getIndent(), 0);
+ width = Math.max(width - indent, 0);
}
}
super.setCellWidth(cellIx, width);
}
- private int getHierarchyColumnIndex() {
- return colIndexOfHierarchy + (showRowHeaders ? 1 : 0);
- }
-
private int getIndent() {
return (depth + 1) * getIndentWidth();
}
@@ -323,7 +330,8 @@ public class VTreeTable extends VScrollTable {
@Override
public void execute() {
if (showRowHeaders) {
- setCellWidth(0, tHead.getHeaderCell(0).getWidth());
+ setCellWidth(0, tHead.getHeaderCell(0)
+ .getWidthWithIndent());
calcAndSetSpanWidthOnCell(1);
} else {
calcAndSetSpanWidthOnCell(0);
@@ -421,6 +429,22 @@ public class VTreeTable extends VScrollTable {
return indentWidth;
}
+ @Override
+ protected int getMaxIndent() {
+ return maxIndent;
+ }
+
+ @Override
+ protected void calculateMaxIndent() {
+ int maxIndent = 0;
+ Iterator<Widget> iterator = iterator();
+ while (iterator.hasNext()) {
+ VTreeTableRow next = (VTreeTableRow) iterator.next();
+ maxIndent = Math.max(maxIndent, next.getIndent());
+ }
+ this.maxIndent = maxIndent;
+ }
+
private void detectIndent(VTreeTableRow vTreeTableRow) {
indentWidth = vTreeTableRow.treeSpacer.getOffsetWidth();
if (indentWidth == 0) {
@@ -432,6 +456,7 @@ public class VTreeTable extends VScrollTable {
VTreeTableRow next = (VTreeTableRow) iterator.next();
next.setIndent();
}
+ calculateMaxIndent();
}
protected void unlinkRowsAnimatedAndUpdateCacheWhenFinished(
@@ -471,6 +496,7 @@ public class VTreeTable extends VScrollTable {
RowExpandAnimation anim = new RowExpandAnimation(insertedRows);
anim.run(150);
}
+ scrollBody.calculateMaxIndent();
return insertedRows;
}
diff --git a/client/src/com/vaadin/client/ui/table/TableConnector.java b/client/src/com/vaadin/client/ui/table/TableConnector.java
index c967642059..fc31cdf8ea 100644
--- a/client/src/com/vaadin/client/ui/table/TableConnector.java
+++ b/client/src/com/vaadin/client/ui/table/TableConnector.java
@@ -176,6 +176,7 @@ public class TableConnector extends AbstractHasComponentsConnector implements
// amount of rows)
getWidget().scrollBody.setLastRendered(getWidget().scrollBody
.getLastRendered());
+ getWidget().updateMaxIndent();
} else {
getWidget().postponeSanityCheckForLastRendered = false;
UIDL rowData = uidl.getChildByTagName("rows");
diff --git a/uitest/src/com/vaadin/tests/components/treetable/TreeTableExtraScrollBarWithChildren.html b/uitest/src/com/vaadin/tests/components/treetable/TreeTableExtraScrollBarWithChildren.html
new file mode 100644
index 0000000000..611e7a5994
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/treetable/TreeTableExtraScrollBarWithChildren.html
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>TreeTableExtraScrollbar</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">TreeTableExtraScrollbar</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.treetable.TreeTableExtraScrollbarWithChildren?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>button</td>
+ <td></td>
+</tr>
+<tr>
+ <td>pause</td>
+ <td>300</td>
+ <td></td>
+</tr>
+<!-- screenCapture should not have a horizontal scrollbar, and the columns should be the same width in body and headers -->
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>expanded</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>button</td>
+ <td></td>
+</tr>
+<tr>
+ <td>pause</td>
+ <td>300</td>
+ <td></td>
+</tr>
+<!-- screenCapture should not have a horizontal scrollbar, the columns should be back to original width in body and headers, and vertical scrollbar shouldn't have left an empty space -->
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>collapsed</td>
+</tr>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.treetable.TreeTableExtraScrollbarWithChildren</td>
+ <td></td>
+</tr>
+<tr>
+ <td>pause</td>
+ <td>300</td>
+ <td></td>
+</tr>
+<!-- screenCapture should not have changed -->
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>refreshed</td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/treetable/TreeTableExtraScrollbarWithChildren.java b/uitest/src/com/vaadin/tests/components/treetable/TreeTableExtraScrollbarWithChildren.java
new file mode 100644
index 0000000000..cad33e242f
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/treetable/TreeTableExtraScrollbarWithChildren.java
@@ -0,0 +1,92 @@
+package com.vaadin.tests.components.treetable;
+
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Notification;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.TreeTable;
+
+public class TreeTableExtraScrollbarWithChildren extends TestBase {
+
+ @Override
+ protected String getDescription() {
+ return "Arrow calculation should not cause a horizontal scrollbar"
+ + " if there is enough space for the final contents.";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 10513;
+ }
+
+ @Override
+ protected void setup() {
+ HorizontalLayout layout = new HorizontalLayout();
+ layout.setWidth("300px");
+ layout.setHeight("300px");
+
+ final TreeTable table = new TreeTable();
+ table.setSizeFull();
+
+ table.addGeneratedColumn("parameterId", new HierarchyColumnGenerator());
+ table.addGeneratedColumn("wordingTextId", new TypeColumnGenerator());
+ table.addGeneratedColumn("parameterTypeId", new TypeColumnGenerator());
+
+ table.setColumnWidth("parameterId", 26);
+
+ table.addItem(new TestObject("name 1", "value 1"));
+ table.addItem(new TestObject("name 2", "value 2"));
+ table.addItem(new TestObject("name 3", "value 3"));
+ table.addItem(new TestObject("name 4", "value 4"));
+ table.addItem(new TestObject("name 5", "value 5"));
+ final TestObject parent = new TestObject("name 6", "value 6");
+ table.addItem(parent);
+ table.setFooterVisible(true);
+ for (int i = 1; i <= 10; ++i) {
+ TestObject child = new TestObject("name 6-" + i, "value 6-" + i);
+ table.addItem(child);
+ table.setParent(child, parent);
+ }
+ table.setVisibleColumns(new Object[] { "wordingTextId", "parameterId",
+ "parameterTypeId" });
+ table.setColumnHeaders(new String[] { "", "", "" });
+ table.setHierarchyColumn("parameterId");
+
+ layout.addComponent(table);
+
+ Button button = new Button("Toggle");
+ button.setId("button");
+ button.addClickListener(new ClickListener() {
+
+ public void buttonClick(ClickEvent event) {
+ table.setCollapsed(parent, !table.isCollapsed(parent));
+ Notification.show("collapsed: " + table.isCollapsed(parent));
+ }
+ });
+
+ addComponent(layout);
+ addComponent(button);
+ }
+
+ private class HierarchyColumnGenerator implements Table.ColumnGenerator {
+ public Object generateCell(Table table, Object itemId, Object columnId) {
+ Label label = new Label("this should be mostly hidden");
+ label.setSizeUndefined();
+ return label;
+ }
+ }
+
+ private class TypeColumnGenerator implements Table.ColumnGenerator {
+ public Object generateCell(Table table, Object itemId, Object columnId) {
+ if (itemId instanceof TestObject) {
+ return new Label(((TestObject) itemId).getValue());
+ }
+ return null;
+ }
+ }
+
+}