Browse Source

major refactoring and cleaning related to column width handling in scrolltable. Hardcoded margins now removed and most things ought to be possible to define with CSS. fixes #2417

svn changeset:7512/svn branch:6.0
tags/6.7.0.beta1
Matti Tahvonen 15 years ago
parent
commit
dc250f61b6

+ 40
- 10
WebContent/ITMILL/themes/default/styles.css View File





/* ./WebContent/ITMILL/themes/default/table/table.css */ /* ./WebContent/ITMILL/themes/default/table/table.css */

/* Table theme building instructions
*
* Toolkit scroll table is very complex widget with dozens of features. These
* features set some limitations for theme builder. To keep things working, it
* is safest to try to just override values used in default theme and comfort to
* these instructions.
*
*
* Table cells in body:
* - padding/border for cells is to be defined for td elements (class name: .i-table-cell-content)
* - in default theme there are no borders, but they should work. Just set border-right or border-bottom
* - no padding or border is allowed for div inside cells (class name : .i-table-cell-wrapper) element
* - background is allowed for both elements
*
* Table headers:
* - table cells in header contain .i-table-resizer and
* .i-table-caption-container div elements, which are both floated to right
* - to align header caption to body content resizer width + .i-table-caption-container
* padding right should be equal to content cells padding-right and border-right.
* - Possible cell border in header must be themed into column resizer.
*
*/

.i-table { .i-table {
overflow: hidden; overflow: hidden;
text-align: left /* Force default alignment */ text-align: left /* Force default alignment */


.i-table-header table, .i-table-header table,
.i-table-table { .i-table-table {
border-collapse: collapse;
margin: 0; margin: 0;
padding: 0; padding: 0;
border: 0; border: 0;
border-spacing:0;
} }


.i-table-header td,
.i-table-table td {
.i-table-header td {
margin: 0; margin: 0;
padding: 0; padding: 0;
border: 0; border: 0;
.i-table-resizer { .i-table-resizer {
display: block; display: block;
height: 36px; height: 36px;
width:4px;
float: right; float: right;
background: transparent url(table/img/resizer-bg.png) repeat-y 50% 50%; background: transparent url(table/img/resizer-bg.png) repeat-y 50% 50%;
cursor: col-resize; cursor: col-resize;
font-size: 15px; font-size: 15px;
padding-top: 9px; padding-top: 9px;
text-shadow: #ffffff 2px 2px 0; text-shadow: #ffffff 2px 2px 0;
/* To align captions and content to same place resizer width + caption
* container padding-right must be equal to table cell
* padding-right + border-righ
*/
padding-right:2px;
} }


.i-table-header-cell-asc .i-table-caption-container { .i-table-header-cell-asc .i-table-caption-container {
background: transparent url(table/img/header-bg-over.png) repeat-x; background: transparent url(table/img/header-bg-over.png) repeat-x;
} }



.i-table-body { .i-table-body {
background: #fff; background: #fff;
border: 1px solid #b6bbbc; border: 1px solid #b6bbbc;
background: #57a7ed; background: #57a7ed;
color: #fff; color: #fff;
} }
.i-table-row td,
.i-table-row-odd td {
padding: 0;
}

.i-table-cell-content { .i-table-cell-content {
padding-top: 3px;
padding-left: 3px;
padding-right: 5px;
border-right:1px solid #f6f7f7;
}

.i-table-cell-wrapper {
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
padding: 3px 0 3px 3px;
margin-right: 5px;
line-height: 23px; line-height: 23px;
} }



+ 40
- 10
WebContent/ITMILL/themes/default/table/table.css View File


/* Table theme building instructions
*
* Toolkit scroll table is very complex widget with dozens of features. These
* features set some limitations for theme builder. To keep things working, it
* is safest to try to just override values used in default theme and comfort to
* these instructions.
*
*
* Table cells in body:
* - padding/border for cells is to be defined for td elements (class name: .i-table-cell-content)
* - in default theme there are no borders, but they should work. Just set border-right or border-bottom
* - no padding or border is allowed for div inside cells (class name : .i-table-cell-wrapper) element
* - background is allowed for both elements
*
* Table headers:
* - table cells in header contain .i-table-resizer and
* .i-table-caption-container div elements, which are both floated to right
* - to align header caption to body content resizer width + .i-table-caption-container
* padding right should be equal to content cells padding-right and border-right.
* - Possible cell border in header must be themed into column resizer.
*
*/

.i-table { .i-table {
overflow: hidden; overflow: hidden;
text-align: left /* Force default alignment */ text-align: left /* Force default alignment */


.i-table-header table, .i-table-header table,
.i-table-table { .i-table-table {
border-collapse: collapse;
margin: 0; margin: 0;
padding: 0; padding: 0;
border: 0; border: 0;
border-spacing:0;
} }


.i-table-header td,
.i-table-table td {
.i-table-header td {
margin: 0; margin: 0;
padding: 0; padding: 0;
border: 0; border: 0;
.i-table-resizer { .i-table-resizer {
display: block; display: block;
height: 36px; height: 36px;
width:4px;
float: right; float: right;
background: transparent url(img/resizer-bg.png) repeat-y 50% 50%; background: transparent url(img/resizer-bg.png) repeat-y 50% 50%;
cursor: col-resize; cursor: col-resize;
font-size: 15px; font-size: 15px;
padding-top: 9px; padding-top: 9px;
text-shadow: #ffffff 2px 2px 0; text-shadow: #ffffff 2px 2px 0;
/* To align captions and content to same place resizer width + caption
* container padding-right must be equal to table cell
* padding-right + border-righ
*/
padding-right:2px;
} }


.i-table-header-cell-asc .i-table-caption-container { .i-table-header-cell-asc .i-table-caption-container {
background: transparent url(img/header-bg-over.png) repeat-x; background: transparent url(img/header-bg-over.png) repeat-x;
} }



.i-table-body { .i-table-body {
background: #fff; background: #fff;
border: 1px solid #b6bbbc; border: 1px solid #b6bbbc;
background: #57a7ed; background: #57a7ed;
color: #fff; color: #fff;
} }
.i-table-row td,
.i-table-row-odd td {
padding: 0;
}

.i-table-cell-content { .i-table-cell-content {
padding-top: 3px;
padding-left: 3px;
padding-right: 5px;
border-right:1px solid #f6f7f7;
}

.i-table-cell-wrapper {
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
padding: 3px 0 3px 3px;
margin-right: 5px;
line-height: 23px; line-height: 23px;
} }



+ 7
- 1
WebContent/ITMILL/themes/sampler/table/styles.css View File

background-color: #ffd; background-color: #ffd;
font-family: monospace; font-family: monospace;
margin: 0px; margin: 0px;
}
}

.i-table .i-icon {
/* explicitly set icon width for fast browsers
* to properly detect row header width */
width: 16px;
}

+ 182
- 153
src/com/itmill/toolkit/terminal/gwt/client/ui/IScrollTable.java View File

import java.util.Set; import java.util.Set;
import java.util.Vector; import java.util.Vector;


import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.NodeList;
import com.google.gwt.dom.client.TableCellElement;
import com.google.gwt.dom.client.TableRowElement;
import com.google.gwt.dom.client.TableSectionElement;
import com.google.gwt.user.client.Command; import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.DeferredCommand; import com.google.gwt.user.client.DeferredCommand;
*/ */
boolean recalcWidths = false; boolean recalcWidths = false;


int scrollbarWidthReservedInColumn = -1;
int scrollbarWidthReserved = -1;
boolean relativeWidth = false;

private final ArrayList<Panel> lazyUnregistryBag = new ArrayList<Panel>(); private final ArrayList<Panel> lazyUnregistryBag = new ArrayList<Panel>();
private String height; private String height;
private String width = ""; private String width = "";
return; return;
} }


if (uidl.hasAttribute("width")) {
relativeWidth = uidl.getStringAttribute("width").endsWith("%");
}

// we may have pending cache row fetch, cancel it. See #2136 // we may have pending cache row fetch, cancel it. See #2136
rowRequestHandler.cancel(); rowRequestHandler.cancel();


while (headCells.hasNext()) { while (headCells.hasNext()) {
final HeaderCell hCell = (HeaderCell) headCells.next(); final HeaderCell hCell = (HeaderCell) headCells.next();
int w = hCell.getWidth(); int w = hCell.getWidth();
if (w > 0) {
if (hCell.isDefinedWidth()) {
// server has defined column width explicitly // server has defined column width explicitly
totalExplicitColumnsWidths += w; totalExplicitColumnsWidths += w;
} else { } else {
if (hCell.getExpandRatio() > 0) { if (hCell.getExpandRatio() > 0) {
expandRatioDivider += hCell.getExpandRatio(); expandRatioDivider += hCell.getExpandRatio();
w = IScrollTableBody.CELL_EXTRA_WIDTH
+ IScrollTableBody.CELL_CONTENT_PADDING;
w = 0;
} else { } else {
// get and store greater of header width and column width, // get and store greater of header width and column width,
// and // and
// store it as a minimumn natural col width // store it as a minimumn natural col width
final int hw = hCell.getOffsetWidth();
final int cw = tBody.getColWidth(i);
w = (hw > cw ? hw : cw) + IScrollTableBody.CELL_EXTRA_WIDTH;
w = hCell.getNaturalColumnWidth(i);
} }
hCell.setNaturalMinimumColumnWidth(w); hCell.setNaturalMinimumColumnWidth(w);
} }
// fix "natural" width if width not set // fix "natural" width if width not set
if (width == null || "".equals(width)) { if (width == null || "".equals(width)) {
int w = total; int w = total;
w += tBody.getCellExtraWidth() * visibleColOrder.length;
w += getScrollbarWidth(); w += getScrollbarWidth();
setContentWidth(w); setContentWidth(w);
} }
int availW = tBody.getAvailableWidth(); int availW = tBody.getAvailableWidth();
// Hey IE, are you really sure about this? // Hey IE, are you really sure about this?
availW = tBody.getAvailableWidth(); availW = tBody.getAvailableWidth();
availW -= tBody.getCellExtraWidth() * visibleColOrder.length;


// FIXME this may fail if pagelenth does not correlate well with actual
// height (via setHeight())
boolean verticalScrollbarVisible = (pageLength < totalRows);

if (verticalScrollbarVisible) {
// There will be a vertical scrollbar and its width is not included
// in availW
availW -= Util.getNativeScrollbarSize();
if (!(height != null && !height.equals(""))) {
if (pageLength < totalRows) {
availW -= Util.getNativeScrollbarSize();
}
} }


boolean needsReLayout = false; boolean needsReLayout = false;


if (availW > total) { if (availW > total) {
// natural size is smaller than available space // natural size is smaller than available space
int extraSpace = availW - total;
int totalWidthR = total - totalExplicitColumnsWidths;
final int extraSpace = availW - total;
final int totalWidthR = total - totalExplicitColumnsWidths;
if (totalWidthR > 0) { if (totalWidthR > 0) {
needsReLayout = true; needsReLayout = true;
/*
* If the table has a relative width and there is enough space
* for a scrollbar we reserve this in the last column
*/
int scrollbarWidth = getScrollbarWidth();
scrollbarWidth = Util.getNativeScrollbarSize();
if (!verticalScrollbarVisible && relativeWidth
&& totalWidthR >= scrollbarWidth) {

scrollbarWidthReserved = scrollbarWidth + 1; //
int columnindex = tHead.getVisibleCellCount() - 1;
widths[columnindex] += scrollbarWidthReserved;
HeaderCell headerCell = tHead.getHeaderCell(columnindex);
if (headerCell.getWidth() == -1) {
totalWidthR += scrollbarWidthReserved;
headerCell.setNaturalMinimumColumnWidth(headerCell
.getNaturalColumnWidth()
+ scrollbarWidthReserved);
}
extraSpace -= scrollbarWidthReserved;
scrollbarWidthReservedInColumn = columnindex;
}

if (expandRatioDivider > 0) { if (expandRatioDivider > 0) {
// visible columns have some active expand ratios, excess // visible columns have some active expand ratios, excess
// space is divided according to them // space is divided according to them
i = 0; i = 0;
while (headCells.hasNext()) { while (headCells.hasNext()) {
HeaderCell hCell = (HeaderCell) headCells.next(); HeaderCell hCell = (HeaderCell) headCells.next();
if (hCell.getWidth() == -1) {
if (!hCell.isDefinedWidth()) {
int w = widths[i]; int w = widths[i];
final int newSpace = extraSpace * w / totalWidthR; final int newSpace = extraSpace * w / totalWidthR;
w += newSpace; w += newSpace;


public class HeaderCell extends Widget { public class HeaderCell extends Widget {


private static final int DRAG_WIDGET_WIDTH = 4;

private static final int MINIMUM_COL_WIDTH = 20;

Element td = DOM.createTD(); Element td = DOM.createTD();


Element captionContainer = DOM.createDiv(); Element captionContainer = DOM.createDiv();


private int width = -1; private int width = -1;


private int naturalWidth = 0;
private int naturalWidth = -1;


private char align = ALIGN_LEFT; private char align = ALIGN_LEFT;




DOM.setElementProperty(colResizeWidget, "className", CLASSNAME DOM.setElementProperty(colResizeWidget, "className", CLASSNAME
+ "-resizer"); + "-resizer");
DOM.setStyleAttribute(colResizeWidget, "width", DRAG_WIDGET_WIDTH
+ "px");
DOM.sinkEvents(colResizeWidget, Event.MOUSEEVENTS); DOM.sinkEvents(colResizeWidget, Event.MOUSEEVENTS);


setText(headerText); setText(headerText);
DOM.setStyleAttribute(captionContainer, "width", ""); DOM.setStyleAttribute(captionContainer, "width", "");
setWidth(""); setWidth("");
} else { } else {
DOM.setStyleAttribute(captionContainer, "width", (w
- DRAG_WIDGET_WIDTH - 4)
+ "px");
setWidth(w + "px");
captionContainer.getStyle().setPropertyPx("width", w);

/*
* if we already have tBody, set the header width properly, if
* not defer it. IE will fail with complex float in table header
* unless TD width is not explicitly set.
*/
if (tBody != null) {
int tdWidth = width + tBody.getCellExtraWidth();
setWidth(tdWidth + "px");
} else {
DeferredCommand.addCommand(new Command() {
public void execute() {
int tdWidth = width + tBody.getCellExtraWidth();
setWidth(tdWidth + "px");
}
});
}
} }
} }


} }


int newWidth = originalWidth + deltaX; int newWidth = originalWidth + deltaX;
if (newWidth < MINIMUM_COL_WIDTH) {
newWidth = MINIMUM_COL_WIDTH;
if (newWidth < tBody.getCellExtraWidth()) {
newWidth = tBody.getCellExtraWidth();
} }
setColWidth(colIndex, newWidth, true); setColWidth(colIndex, newWidth, true);
} }
* If column is resized by user or the width is defined by server the * If column is resized by user or the width is defined by server the
* actual width is returned. Else the natural min width is returned. * actual width is returned. Else the natural min width is returned.
* *
* @param columnIndex
* column index hint, if -1 (unknown) it will be detected
*
* @return * @return
*/ */
public int getNaturalColumnWidth() {
public int getNaturalColumnWidth(int columnIndex) {
if (isDefinedWidth()) { if (isDefinedWidth()) {
return width; return width;
} else { } else {
if (naturalWidth == 0) {
if (naturalWidth < 0) {
// This is recently revealed column. Try to detect a proper // This is recently revealed column. Try to detect a proper
// value (greater of header and data // value (greater of header and data
// cols) // cols)
final int hw = getOffsetWidth();
int i = 0;
for (Iterator<Widget> it = tHead.iterator(); it.hasNext(); i++) {
if (it.next() == this) {
break;

final int hw = ((Element) getElement().getLastChild())
.getOffsetWidth()
+ tBody.getCellExtraWidth();
if (columnIndex < 0) {
columnIndex = 0;
for (Iterator<Widget> it = tHead.iterator(); it
.hasNext(); columnIndex++) {
if (it.next() == this) {
break;
}
} }
} }
final int cw = tBody.getColWidth(i);
naturalWidth = (hw > cw ? hw : cw)
+ IScrollTableBody.CELL_EXTRA_WIDTH;

final int cw = tBody.getColWidth(columnIndex);
naturalWidth = (hw > cw ? hw : cw);
} }
return naturalWidth; return naturalWidth;
} }
private int focusedSlot = -1; private int focusedSlot = -1;


public TableHead() { public TableHead() {
if (BrowserInfo.get().isIE()) {
table.setPropertyInt("cellSpacing", 0);
}

DOM.setStyleAttribute(hTableWrapper, "overflow", "hidden"); DOM.setStyleAttribute(hTableWrapper, "overflow", "hidden");
DOM.setElementProperty(hTableWrapper, "className", CLASSNAME DOM.setElementProperty(hTableWrapper, "className", CLASSNAME
+ "-header"); + "-header");
* Returns column alignments for visible columns * Returns column alignments for visible columns
*/ */
public char[] getColumnAlignments() { public char[] getColumnAlignments() {
final Iterator it = visibleCells.iterator();
final Iterator<Widget> it = visibleCells.iterator();
final char[] aligns = new char[visibleCells.size()]; final char[] aligns = new char[visibleCells.size()];
int colIndex = 0; int colIndex = 0;
while (it.hasNext()) { while (it.hasNext()) {
*/ */
public class IScrollTableBody extends Panel { public class IScrollTableBody extends Panel {


public static final int CELL_EXTRA_WIDTH = 20;

public static final int DEFAULT_ROW_HEIGHT = 24; public static final int DEFAULT_ROW_HEIGHT = 24;


/**
* Amount of padding inside one table cell (this is reduced from the
* "cellContent" element's width). You may override this in your own
* widgetset.
*/
public static final int CELL_CONTENT_PADDING = 8;

private int rowHeight = -1; private int rowHeight = -1;


private final List<Widget> renderedRows = new Vector<Widget>(); private final List<Widget> renderedRows = new Vector<Widget>();


private boolean initDone = false;
/**
* Due some optimizations row height measuring is deferred and initial
* set of rows is rendered detached. Flag set on when table body has
* been attached in dom and rowheight has been measured.
*/
private boolean tBodyMeasurementsDone = false;


Element preSpacer = DOM.createDiv(); Element preSpacer = DOM.createDiv();
Element postSpacer = DOM.createDiv(); Element postSpacer = DOM.createDiv();


Element container = DOM.createDiv(); Element container = DOM.createDiv();


Element tBody = DOM.createTBody();
TableSectionElement tBodyElement = Document.get().createTBodyElement();
Element table = DOM.createTable(); Element table = DOM.createTable();


private int firstRendered; private int firstRendered;


IScrollTableBody() { IScrollTableBody() {
constructDOM(); constructDOM();

setElement(container); setElement(container);
} }


private void constructDOM() { private void constructDOM() {
DOM.setElementProperty(table, "className", CLASSNAME + "-table"); DOM.setElementProperty(table, "className", CLASSNAME + "-table");
if (BrowserInfo.get().isIE()) {
table.setPropertyInt("cellSpacing", 0);
}
DOM.setElementProperty(preSpacer, "className", CLASSNAME DOM.setElementProperty(preSpacer, "className", CLASSNAME
+ "-row-spacer"); + "-row-spacer");
DOM.setElementProperty(postSpacer, "className", CLASSNAME DOM.setElementProperty(postSpacer, "className", CLASSNAME
+ "-row-spacer"); + "-row-spacer");


DOM.appendChild(table, tBody);
table.appendChild(tBodyElement);
DOM.appendChild(container, preSpacer); DOM.appendChild(container, preSpacer);
DOM.appendChild(container, table); DOM.appendChild(container, table);
DOM.appendChild(container, postSpacer); DOM.appendChild(container, postSpacer);
} }


public int getAvailableWidth() { public int getAvailableWidth() {
return DOM.getElementPropertyInt(preSpacer, "offsetWidth");
return preSpacer.getOffsetWidth();
} }


public void renderInitialRows(UIDL rowData, int firstIndex, int rows) { public void renderInitialRows(UIDL rowData, int firstIndex, int rows) {
firstRendered = firstIndex; firstRendered = firstIndex;
lastRendered = firstIndex + rows - 1; lastRendered = firstIndex + rows - 1;
final Iterator it = rowData.getChildIterator();
final Iterator<?> it = rowData.getChildIterator();
aligns = tHead.getColumnAlignments(); aligns = tHead.getColumnAlignments();
while (it.hasNext()) { while (it.hasNext()) {
final IScrollTableRow row = new IScrollTableRow((UIDL) it final IScrollTableRow row = new IScrollTableRow((UIDL) it
public void renderRows(UIDL rowData, int firstIndex, int rows) { public void renderRows(UIDL rowData, int firstIndex, int rows) {
// FIXME REVIEW // FIXME REVIEW
aligns = tHead.getColumnAlignments(); aligns = tHead.getColumnAlignments();
final Iterator it = rowData.getChildIterator();
final Iterator<?> it = rowData.getChildIterator();
if (firstIndex == lastRendered + 1) { if (firstIndex == lastRendered + 1) {
while (it.hasNext()) { while (it.hasNext()) {
final IScrollTableRow row = createRow((UIDL) it.next()); final IScrollTableRow row = createRow((UIDL) it.next());
rowRequestHandler.setReqFirstRow(lastRendered + 1); rowRequestHandler.setReqFirstRow(lastRendered + 1);
rowRequestHandler.setReqRows(reactLastRow - lastRendered - 1); rowRequestHandler.setReqRows(reactLastRow - lastRendered - 1);
rowRequestHandler.deferRowFetch(1); rowRequestHandler.deferRowFetch(1);
} else if (IScrollTable.this.tBody.getFirstRendered() > reactFirstRow) {
} else if (tBody.getFirstRendered() > reactFirstRow) {
/* /*
* Branch for fetching cache above visible area. * Branch for fetching cache above visible area.
* *
final Element cell = DOM.getChild(row.getElement(), i); final Element cell = DOM.getChild(row.getElement(), i);
final int w = IScrollTable.this final int w = IScrollTable.this
.getColWidth(getColKeyByIndex(i)); .getColWidth(getColKeyByIndex(i));
DOM.setStyleAttribute(DOM.getFirstChild(cell), "width",
(w - CELL_CONTENT_PADDING) + "px");
DOM.setStyleAttribute(cell, "width", w + "px");
cell.getFirstChildElement().getStyle()
.setPropertyPx("width", w);
cell.getStyle().setPropertyPx("width", w);
} }
return row; return row;
} }
if (row.isSelected()) { if (row.isSelected()) {
row.addStyleName("i-selected"); row.addStyleName("i-selected");
} }
DOM.insertChild(tBody, row.getElement(), 0);
tBodyElement.insertBefore(row.getElement(), tBodyElement
.getFirstChild());
adopt(row); adopt(row);
renderedRows.add(0, row); renderedRows.add(0, row);
} }
if (row.isSelected()) { if (row.isSelected()) {
row.addStyleName("i-selected"); row.addStyleName("i-selected");
} }
DOM.appendChild(tBody, row.getElement());
tBodyElement.appendChild(row.getElement());
adopt(row); adopt(row);
renderedRows.add(row); renderedRows.add(row);
} }
final IScrollTableRow toBeRemoved = (IScrollTableRow) renderedRows final IScrollTableRow toBeRemoved = (IScrollTableRow) renderedRows
.get(index); .get(index);
lazyUnregistryBag.add(toBeRemoved); lazyUnregistryBag.add(toBeRemoved);
DOM.removeChild(tBody, toBeRemoved.getElement());
tBodyElement.removeChild(toBeRemoved.getElement());
orphan(toBeRemoved); orphan(toBeRemoved);
renderedRows.remove(index); renderedRows.remove(index);
fixSpacers(); fixSpacers();
} }


public int getRowHeight(boolean forceUpdate) { public int getRowHeight(boolean forceUpdate) {
if (initDone && !forceUpdate) {
if (tBodyMeasurementsDone && !forceUpdate) {
return rowHeight; return rowHeight;
} else { } else {
if (DOM.getChildCount(tBody) > 0) {
rowHeight = getTableHeight() / DOM.getChildCount(tBody);

if (tBodyElement.getRows().getLength() > 0) {
rowHeight = getTableHeight()
/ tBodyElement.getRows().getLength();
} else { } else {
return DEFAULT_ROW_HEIGHT; return DEFAULT_ROW_HEIGHT;
} }
initDone = true;
tBodyMeasurementsDone = true;
return rowHeight; return rowHeight;
} }
} }
return table.getOffsetHeight(); return table.getOffsetHeight();
} }


/**
* Returns the width available for column content.
*
* @param i
* @return
*/
public int getColWidth(int i) { public int getColWidth(int i) {
if (initDone) {
final Element e = DOM.getChild(DOM.getChild(tBody, 0), i);
return DOM.getElementPropertyInt(e, "offsetWidth");
if (tBodyMeasurementsDone) {
final Element wrapper = (Element) tBodyElement
.getFirstChildElement().getChildNodes().getItem(i)
.getFirstChild();
return wrapper.getOffsetWidth();
} else { } else {
return 0; return 0;
} }
} }


/**
* Sets the content width of a column.
*
* Due IE limitation, we must set the width to a wrapper elements inside
* table cells (with overflow hidden, which does not work on td
* elements).
*
* To get this work properly crossplatform, we will also set the width
* of td.
*
* @param colIndex
* @param w
*/
public void setColWidth(int colIndex, int w) { public void setColWidth(int colIndex, int w) {
final int rows = DOM.getChildCount(tBody);
NodeList<TableRowElement> rows2 = tBodyElement.getRows();
final int rows = rows2.getLength();
for (int i = 0; i < rows; i++) { for (int i = 0; i < rows; i++) {
final Element cell = DOM.getChild(DOM.getChild(tBody, i),
colIndex);
DOM.setStyleAttribute(DOM.getFirstChild(cell), "width",
(w - CELL_CONTENT_PADDING) + "px");
DOM.setStyleAttribute(cell, "width", w + "px");
TableRowElement row = rows2.getItem(i);
TableCellElement cell = row.getCells().getItem(colIndex);
cell.getFirstChildElement().getStyle()
.setPropertyPx("width", w);
cell.getStyle().setPropertyPx("width", w);
} }
} }


private int cellExtraWidth = -1;
private int cellMarginLeft = -1;

/**
* Method to return the space used for cell paddings + border.
*/
private int getCellExtraWidth() {
if (cellExtraWidth < 0) {
detectExtrawidth();
}
return cellExtraWidth;
}

private void detectExtrawidth() {
com.google.gwt.dom.client.Element firstTD = tBodyElement
.getFirstChildElement().getFirstChildElement();
com.google.gwt.dom.client.Element wrapper = firstTD
.getFirstChildElement();
cellExtraWidth = firstTD.getOffsetWidth()
- wrapper.getOffsetWidth();
cellMarginLeft = wrapper.getOffsetLeft();
}

private void reLayoutComponents() { private void reLayoutComponents() {
for (Widget w : this) { for (Widget w : this) {
IScrollTableRow r = (IScrollTableRow) w; IScrollTableRow r = (IScrollTableRow) w;
public void moveCol(int oldIndex, int newIndex) { public void moveCol(int oldIndex, int newIndex) {


// loop all rows and move given index to its new place // loop all rows and move given index to its new place
final Iterator rows = iterator();
final Iterator<?> rows = iterator();
while (rows.hasNext()) { while (rows.hasNext()) {
final IScrollTableRow row = (IScrollTableRow) rows.next(); final IScrollTableRow row = (IScrollTableRow) rows.next();


public class IScrollTableRow extends Panel implements ActionOwner, public class IScrollTableRow extends Panel implements ActionOwner,
Container { Container {


Vector childWidgets = new Vector();
Vector<Widget> childWidgets = new Vector<Widget>();
private boolean selected = false; private boolean selected = false;
private final int rowKey; private final int rowKey;
private List<UIDL> pendingComponentPaints; private List<UIDL> pendingComponentPaints;
actionKeys = uidl.getStringArrayAttribute("al"); actionKeys = uidl.getStringArrayAttribute("al");
} }


final Iterator cells = uidl.getChildIterator();
final Iterator<?> cells = uidl.getChildIterator();
while (cells.hasNext()) { while (cells.hasNext()) {
final Object cell = cells.next(); final Object cell = cells.next();
visibleColumnIndex++; visibleColumnIndex++;
if (style != null && !style.equals("")) { if (style != null && !style.equals("")) {
className += " " + CLASSNAME + "-cell-content-" + style; className += " " + CLASSNAME + "-cell-content-" + style;
} }
DOM.setElementProperty(container, "className", className);
td.setClassName(className);
container.setClassName(CLASSNAME + "-cell-wrapper");
if (textIsHTML) { if (textIsHTML) {
DOM.setInnerHTML(container, text);
container.setInnerHTML(text);
} else { } else {
DOM.setInnerText(container, text);
container.setInnerText(text);
} }
if (align != ALIGN_LEFT) { if (align != ALIGN_LEFT) {
switch (align) { switch (align) {
case ALIGN_CENTER: case ALIGN_CENTER:
DOM.setStyleAttribute(container, "textAlign", "center");
container.getStyle().setProperty("textAlign", "center");
break; break;
case ALIGN_RIGHT: case ALIGN_RIGHT:
default: default:
DOM.setStyleAttribute(container, "textAlign", "right");
container.getStyle().setProperty("textAlign", "right");
break; break;
} }
} }
DOM.appendChild(td, container);
DOM.appendChild(getElement(), td);
td.appendChild(container);
getElement().appendChild(td);
} }


public void addCell(Widget w, char align, String style) { public void addCell(Widget w, char align, String style) {
if (style != null && !style.equals("")) { if (style != null && !style.equals("")) {
className += " " + CLASSNAME + "-cell-content-" + style; className += " " + CLASSNAME + "-cell-content-" + style;
} }
DOM.setElementProperty(container, "className", className);
td.setClassName(className);
container.setClassName(CLASSNAME + "-cell-wrapper");
// TODO most components work with this, but not all (e.g. // TODO most components work with this, but not all (e.g.
// Select) // Select)
// Old comment: make widget cells respect align. // Old comment: make widget cells respect align.
if (align != ALIGN_LEFT) { if (align != ALIGN_LEFT) {
switch (align) { switch (align) {
case ALIGN_CENTER: case ALIGN_CENTER:
DOM.setStyleAttribute(container, "textAlign", "center");
container.getStyle().setProperty("textAlign", "center");
break; break;
case ALIGN_RIGHT: case ALIGN_RIGHT:
default: default:
DOM.setStyleAttribute(container, "textAlign", "right");
container.getStyle().setProperty("textAlign", "right");
break; break;
} }
} }
DOM.appendChild(td, container);
DOM.appendChild(getElement(), td);
td.appendChild(container);
getElement().appendChild(td);
// ensure widget not attached to another element (possible tBody // ensure widget not attached to another element (possible tBody
// change) // change)
w.removeFromParent(); w.removeFromParent();
DOM.appendChild(container, w.getElement());
container.appendChild(w.getElement());
adopt(w); adopt(w);
childWidgets.add(w); childWidgets.add(w);
} }


public Iterator iterator() {
public Iterator<Widget> iterator() {
return childWidgets.iterator(); return childWidgets.iterator();
} }


HeaderCell headerCell = tHead.getHeaderCell(i); HeaderCell headerCell = tHead.getHeaderCell(i);
if (headerCell != null) { if (headerCell != null) {
if (initializedAndAttached) { if (initializedAndAttached) {
w = headerCell.getWidth() - CELL_CONTENT_PADDING;
w = headerCell.getWidth();
} else { } else {
// header offset width is not absolutely correct value, // header offset width is not absolutely correct value,
// but
// a best guess (expecting similar content in all
// but a best guess (expecting similar content in all
// columns -> // columns ->
// if one component is relative width so are others) // if one component is relative width so are others)
w = headerCell.getOffsetWidth() - CELL_CONTENT_PADDING;
w = headerCell.getOffsetWidth() - getCellExtraWidth();
} }
} }
return new RenderSpace(w, getRowHeight()); return new RenderSpace(w, getRowHeight());


this.width = width; this.width = width;
if (width != null && !"".equals(width)) { if (width != null && !"".equals(width)) {
int oldWidth = getOffsetWidth();
super.setWidth(width); super.setWidth(width);
int newWidth = getOffsetWidth();

if (scrollbarWidthReservedInColumn != -1 && oldWidth > newWidth
&& (oldWidth - newWidth) < scrollbarWidthReserved) {
int col = scrollbarWidthReservedInColumn;
String colKey = getColKeyByIndex(col);
setColWidth(scrollbarWidthReservedInColumn, getColWidth(colKey)
- (oldWidth - newWidth), false);
scrollbarWidthReservedInColumn = -1;
}

int innerPixels = getOffsetWidth() - getBorderWidth(); int innerPixels = getOffsetWidth() - getBorderWidth();
if (innerPixels < 0) { if (innerPixels < 0) {
innerPixels = 0; innerPixels = 0;
int usedMinimumWidth = 0; int usedMinimumWidth = 0;
int totalExplicitColumnsWidths = 0; int totalExplicitColumnsWidths = 0;
float expandRatioDivider = 0; float expandRatioDivider = 0;
int colIndex = 0;
while (headCells.hasNext()) { while (headCells.hasNext()) {
final HeaderCell hCell = (HeaderCell) headCells.next(); final HeaderCell hCell = (HeaderCell) headCells.next();
usedMinimumWidth += hCell.getNaturalColumnWidth();
if (hCell.isDefinedWidth()) { if (hCell.isDefinedWidth()) {
totalExplicitColumnsWidths += hCell.getWidth(); totalExplicitColumnsWidths += hCell.getWidth();
usedMinimumWidth += hCell.getWidth();
} else { } else {
totalExplicitColumnsWidths += hCell.getNaturalColumnWidth();
usedMinimumWidth += hCell.getNaturalColumnWidth(colIndex);
expandRatioDivider += hCell.getExpandRatio(); expandRatioDivider += hCell.getExpandRatio();
} }
colIndex++;
} }


int availW = tBody.getAvailableWidth(); int availW = tBody.getAvailableWidth();
// Hey IE, are you really sure about this? // Hey IE, are you really sure about this?
availW = tBody.getAvailableWidth(); availW = tBody.getAvailableWidth();
availW -= tBody.getCellExtraWidth() * visibleColOrder.length;


int extraSpace = availW - usedMinimumWidth; int extraSpace = availW - usedMinimumWidth;
if (extraSpace < 0) { if (extraSpace < 0) {
extraSpace = 0; extraSpace = 0;
} }
int totalWidthR = usedMinimumWidth - totalExplicitColumnsWidths;
if (totalWidthR < 0) {
totalWidthR = 0;
}

int totalUndefinedNaturaWidths = usedMinimumWidth
- totalExplicitColumnsWidths;


// we have some space that can be divided optimally // we have some space that can be divided optimally
HeaderCell hCell; HeaderCell hCell;
int i = 0;
colIndex = 0;
headCells = tHead.iterator(); headCells = tHead.iterator();
while (headCells.hasNext()) { while (headCells.hasNext()) {
hCell = (HeaderCell) headCells.next(); hCell = (HeaderCell) headCells.next();
if (!hCell.isDefinedWidth()) { if (!hCell.isDefinedWidth()) {
int w = hCell.getNaturalColumnWidth();
int w = hCell.getNaturalColumnWidth(colIndex);
int newSpace; int newSpace;
if (expandRatioDivider > 0) { if (expandRatioDivider > 0) {
// divide excess space by expand ratios // divide excess space by expand ratios
newSpace = (int) (w + extraSpace newSpace = (int) (w + extraSpace
* hCell.getExpandRatio() / expandRatioDivider); * hCell.getExpandRatio() / expandRatioDivider);
} else { } else {
if (totalWidthR != 0) {
if (totalUndefinedNaturaWidths != 0) {
// divide relatively to natural column widths // divide relatively to natural column widths
newSpace = w + extraSpace * w / totalWidthR;
newSpace = w + extraSpace * w
/ totalUndefinedNaturaWidths;
} else { } else {
newSpace = w; newSpace = w;
} }
} }
setColWidth(i, newSpace, false);
setColWidth(colIndex, newSpace, false);
} }
i++;
colIndex++;
} }
Util.runWebkitOverflowAutoFix(bodyContainer.getElement()); Util.runWebkitOverflowAutoFix(bodyContainer.getElement());
tBody.reLayoutComponents(); tBody.reLayoutComponents();

Loading…
Cancel
Save