}
.v-table-row,
.v-table-row-odd {
+ background: #fff;
border: 0;
margin: 0;
padding: 0;
.v-treetable .v-checkbox {
display: inline-block;
padding-bottom: 4px;
-}
\ No newline at end of file
+}
+
+.v-treetable .v-table-row .v-table-cell-content,
+.v-treetable .v-table-row-odd .v-table-cell-content {
+ position: relative;
+ z-index: 10;
+}
+
+.v-treetable .v-table-body .v-table-table .v-table-row-animating {
+ zoom:1;
+ z-index:1;
+}
+
+.v-treetable .v-table-body .v-table-table .v-table-row-animating,
+.v-treetable .v-table-body .v-table-table .v-table-row-animating .v-table-cell-content {
+ background:transparent;
+}
+
+.v-treetable-animation-clone {
+ border-spacing: 0;
+ zoom:1;
+}
+
+div.v-treetable-animation-clone-wrapper {
+ position: absolute;
+ z-index: 2;
+ background-color:#fff;
+}
+
+div.v-treetable-animation-clone-wrapper table.v-treetable-animation-clone {
+ background-color:#fff;
+}
+
+div table.v-treetable-animation-clone tr.v-table-row,
+div table.v-treetable-animation-clone tr.v-table-row-odd,
+div table.v-treetable-animation-clone tr.v-table-row td.v-table-cell-content,
+div table.v-treetable-animation-clone tr.v-table-row-odd td.v-table-cell-content {
+ visibility: visible;
+}
.border-blue-2px {\r
border: 2px solid blue;\r
}\r
+\r
+.v-table-row-tables-test-cell-style-red-row,\r
+.v-table-cell-content-tables-test-cell-style-red-row {\r
+ background: #f00;\r
+}
\ No newline at end of file
--- /dev/null
+package com.vaadin.terminal.gwt.client;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.user.client.Element;
+
+public class ComputedStyle {
+
+ protected final JavaScriptObject computedStyle;
+ private final Element elem;
+
+ /**
+ * Gets this element's computed style object which can be used to gather
+ * information about the current state of the rendered node.
+ * <p>
+ * Note that this method is expensive. Wherever possible, reuse the returned
+ * object.
+ *
+ * @param elem
+ * the element
+ * @return the computed style
+ */
+ public ComputedStyle(Element elem) {
+ computedStyle = getComputedStyle(elem);
+ this.elem = elem;
+ }
+
+ private static native JavaScriptObject getComputedStyle(Element elem)
+ /*-{
+ if(elem.nodeType != 1) {
+ return {};
+ }
+
+ if($wnd.document.defaultView && $wnd.document.defaultView.getComputedStyle) {
+ return $wnd.document.defaultView.getComputedStyle(elem, null);
+ }
+
+ if(elem.currentStyle) {
+ return elem.currentStyle;
+ }
+ }-*/;
+
+ /**
+ *
+ * @param name
+ * name of the CSS property in camelCase
+ * @return the value of the property, normalized for across browsers (each
+ * browser returns pixel values whenever possible).
+ */
+ public final native String getProperty(String name)
+ /*-{
+ var cs = this.@com.vaadin.terminal.gwt.client.ComputedStyle::computedStyle;
+ var elem = this.@com.vaadin.terminal.gwt.client.ComputedStyle::elem;
+
+ // Border values need to be checked separately. The width might have a
+ // meaningful value even if the border style is "none". In that case the
+ // value should be 0.
+ if(name.indexOf("border") > -1 && name.indexOf("Width") > -1) {
+ var borderStyleProp = name.substring(0,name.length-5) + "Style";
+ if(cs.getPropertyValue)
+ var borderStyle = cs.getPropertyValue(borderStyleProp);
+ else // IE
+ var borderStyle = cs[borderStyleProp];
+ if(borderStyle == "none")
+ return "0px";
+ }
+
+ if(cs.getPropertyValue) {
+
+ // Convert name to dashed format
+ name = name.replace(/([A-Z])/g, "-$1").toLowerCase();
+ var ret = cs.getPropertyValue(name);
+
+ } else {
+
+ var ret = cs[name];
+ var style = elem.style;
+
+ // From the awesome hack by Dean Edwards
+ // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+ // If we're not dealing with a regular pixel number
+ // but a number that has a weird ending, we need to convert it to pixels
+ if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) {
+ // Remember the original values
+ var left = style.left, rsLeft = elem.runtimeStyle.left;
+
+ // Put in the new values to get a computed value out
+ elem.runtimeStyle.left = this.left;
+ style.left = ret || 0;
+ ret = style.pixelLeft + "px";
+
+ // Revert the changed values
+ style.left = left;
+ elem.runtimeStyle.left = rsLeft;
+ }
+
+ }
+
+ // Normalize margin values. This is not totally valid, but in most cases
+ // it is what the user wants to know.
+ if(name.indexOf("margin") > -1 && ret == "auto") {
+ return "0px";
+ }
+
+ // Some browsers return undefined width and height values as "auto", so
+ // we need to retrieve those ourselves.
+ if (name == "width" && ret == "auto") {
+ ret = elem.clientWidth + "px";
+ } else if (name == "height" && ret == "auto") {
+ ret = elem.clientHeight + "px";
+ }
+
+ return ret;
+
+ }-*/;
+
+ public final int getIntProperty(String name) {
+ return parseInt(getProperty(name)).intValue();
+ }
+
+ /**
+ * Get current margin values from the DOM. The array order is the default
+ * CSS order: top, right, bottom, left.
+ */
+ public final int[] getMargin() {
+ int[] margin = { 0, 0, 0, 0 };
+ margin[0] = getIntProperty("marginTop");
+ margin[1] = getIntProperty("marginRight");
+ margin[2] = getIntProperty("marginBottom");
+ margin[3] = getIntProperty("marginLeft");
+ return margin;
+ }
+
+ /**
+ * Get current padding values from the DOM. The array order is the default
+ * CSS order: top, right, bottom, left.
+ */
+ public final int[] getPadding() {
+ int[] padding = { 0, 0, 0, 0 };
+ padding[0] = getIntProperty("paddingTop");
+ padding[1] = getIntProperty("paddingRight");
+ padding[2] = getIntProperty("paddingBottom");
+ padding[3] = getIntProperty("paddingLeft");
+ return padding;
+ }
+
+ /**
+ * Get current border values from the DOM. The array order is the default
+ * CSS order: top, right, bottom, left.
+ */
+ public final int[] getBorder() {
+ int[] border = { 0, 0, 0, 0 };
+ border[0] = getIntProperty("borderTopWidth");
+ border[1] = getIntProperty("borderRightWidth");
+ border[2] = getIntProperty("borderBottomWidth");
+ border[3] = getIntProperty("borderLeftWidth");
+ return border;
+ }
+
+ /**
+ * Takes a String value e.g. "12px" and parses that to int 12.
+ *
+ * @param String
+ * a value starting with a number
+ * @return int the value from the string before any non-numeric characters.
+ * If the value cannot be parsed to a number, returns
+ * <code>null</code>.
+ */
+ public static native Integer parseInt(final String value)
+ /*-{
+ var number = parseInt(value, 10);
+ if (isNaN(number))
+ return null;
+ else
+ return @java.lang.Integer::valueOf(I)(number);
+ }-*/;
+
+}
UIDL partialRowUpdates = uidl.getChildByTagName("urows");
if (partialRowUpdates != null || partialRowAdditions != null) {
updateRowsInBody(partialRowUpdates);
- addRowsToBody(partialRowAdditions);
+ addAndRemoveRows(partialRowAdditions);
} else {
UIDL rowData = uidl.getChildByTagName("rows");
if (rowData != null) {
scrollBody.renderRows(uidl, firstRow, reqRows);
- updateCache();
+ discardRowsOutsideCacheWindow();
}
private void updateRowsInBody(UIDL partialRowUpdates) {
scrollBody.unlinkRows(firstRowIx, count);
scrollBody.insertRows(partialRowUpdates, firstRowIx, count);
- updateCache();
+ discardRowsOutsideCacheWindow();
}
- private void updateCache() {
+ /**
+ * Updates the internal cache by unlinking rows that fall outside of the
+ * caching window.
+ */
+ protected void discardRowsOutsideCacheWindow() {
final int optimalFirstRow = (int) (firstRowInViewPort - pageLength
* cache_rate);
boolean cont = true;
scrollBody.restoreRowVisibility();
}
- private void addRowsToBody(UIDL partialRowAdditions) {
+ /**
+ * Inserts rows in the table body or removes them from the table body based
+ * on the commands in the UIDL.
+ *
+ * @param partialRowAdditions
+ * the UIDL containing row updates.
+ */
+ protected void addAndRemoveRows(UIDL partialRowAdditions) {
if (partialRowAdditions == null) {
return;
}
}
}
- updateCache();
+ discardRowsOutsideCacheWindow();
}
/**
}
}
- protected void insertRows(UIDL rowData, int firstIndex, int rows) {
+ /**
+ * Inserts rows as provided in the rowData starting at firstIndex.
+ *
+ * @param rowData
+ * @param firstIndex
+ * @param rows
+ * the number of rows
+ * @return a list of the rows added.
+ */
+ protected List<VScrollTableRow> insertRows(UIDL rowData,
+ int firstIndex, int rows) {
aligns = tHead.getColumnAlignments();
final Iterator<?> it = rowData.getChildIterator();
+ List<VScrollTableRow> insertedRows = new ArrayList<VScrollTableRow>();
if (firstIndex == lastRendered + 1) {
while (it.hasNext()) {
final VScrollTableRow row = prepareRow((UIDL) it.next());
addRow(row);
+ insertedRows.add(row);
lastRendered++;
}
fixSpacers();
}
for (i = 0; i < rows; i++) {
addRowBeforeFirstRendered(rowArray[i]);
+ insertedRows.add(rowArray[i]);
firstRendered--;
}
} else {
// insert in the middle
int realIx = firstIndex - firstRendered;
while (it.hasNext()) {
- insertRowAt(prepareRow((UIDL) it.next()), realIx);
+ VScrollTableRow row = prepareRow((UIDL) it.next());
+ insertRowAt(row, realIx);
+ insertedRows.add(row);
lastRendered++;
realIx++;
}
fixSpacers();
}
+ return insertedRows;
}
protected void insertRowsDeleteBelow(UIDL rowData, int firstIndex,
package com.vaadin.terminal.gwt.client.ui;
+import java.util.ArrayList;
import java.util.Iterator;
+import java.util.List;
+import com.google.gwt.animation.client.Animation;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.ImageElement;
import com.google.gwt.dom.client.SpanElement;
+import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.dom.client.Style.Visibility;
import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.ComputedStyle;
import com.vaadin.terminal.gwt.client.RenderSpace;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.VConsole;
private int colIndexOfHierarchy;
private String collapsedRowKey;
private VTreeTableScrollBody scrollBody;
+ private boolean animationsEnabled;
@Override
public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
widget = (FocusableScrollPanel) getWidget(1);
scrollPosition = widget.getScrollPosition();
}
+ animationsEnabled = uidl.getBooleanAttribute("animate");
colIndexOfHierarchy = uidl
.hasAttribute(ATTRIBUTE_HIERARCHY_COLUMN_INDEX) ? uidl
.getIntAttribute(ATTRIBUTE_HIERARCHY_COLUMN_INDEX) : 0;
return scrollBody;
}
+ /*
+ * Overridden to allow animation of expands and collapses of nodes.
+ */
+ @Override
+ protected void addAndRemoveRows(UIDL partialRowAdditions) {
+ if (partialRowAdditions == null) {
+ return;
+ }
+
+ if (animationsEnabled && browserSupportsAnimation()) {
+ if (partialRowAdditions.hasAttribute("hide")) {
+ scrollBody.unlinkRowsAnimatedAndUpdateCacheWhenFinished(
+ partialRowAdditions.getIntAttribute("firstprowix"),
+ partialRowAdditions.getIntAttribute("numprows"));
+ } else {
+ scrollBody.insertRowsAnimated(partialRowAdditions,
+ partialRowAdditions.getIntAttribute("firstprowix"),
+ partialRowAdditions.getIntAttribute("numprows"));
+ discardRowsOutsideCacheWindow();
+ }
+ } else {
+ super.addAndRemoveRows(partialRowAdditions);
+ }
+ }
+
+ private boolean browserSupportsAnimation() {
+ BrowserInfo bi = BrowserInfo.get();
+ return !(bi.isIE6() || bi.isIE7() || bi.isSafari4());
+ }
+
class VTreeTableScrollBody extends VScrollTable.VScrollTableBody {
private int identWidth = -1;
next.setIdent();
}
}
+
+ protected void unlinkRowsAnimatedAndUpdateCacheWhenFinished(
+ final int firstIndex, final int rows) {
+ List<VScrollTableRow> rowsToDelete = new ArrayList<VScrollTableRow>();
+ for (int ix = firstIndex; ix < firstIndex + rows; ix++) {
+ VScrollTableRow row = getRowByRowIndex(ix);
+ if (row != null) {
+ rowsToDelete.add(row);
+ }
+ }
+ RowCollapseAnimation anim = new RowCollapseAnimation(rowsToDelete) {
+ @Override
+ protected void onComplete() {
+ super.onComplete();
+ // Actually unlink the rows and update the cache after the
+ // animation is done.
+ unlinkRows(firstIndex, rows);
+ discardRowsOutsideCacheWindow();
+ ensureCacheFilled();
+ }
+ };
+ anim.run(150);
+ }
+
+ protected List<VScrollTableRow> insertRowsAnimated(UIDL rowData,
+ int firstIndex, int rows) {
+ List<VScrollTableRow> insertedRows = insertRows(rowData,
+ firstIndex, rows);
+ RowExpandAnimation anim = new RowExpandAnimation(insertedRows);
+ anim.run(150);
+ return insertedRows;
+ }
+
+ /**
+ * Prepares the table for animation by copying the background colors of
+ * all TR elements to their respective TD elements if the TD element is
+ * transparent. This is needed, since if TDs have transparent
+ * backgrounds, the rows sliding behind them are visible.
+ */
+ private class AnimationPreparator {
+ private final int lastItemIx;
+
+ public AnimationPreparator(int lastItemIx) {
+ this.lastItemIx = lastItemIx;
+ }
+
+ public void prepareTableForAnimation() {
+ int ix = lastItemIx;
+ VScrollTableRow row = null;
+ while ((row = getRowByRowIndex(ix)) != null) {
+ copyTRBackgroundsToTDs(row);
+ --ix;
+ }
+ }
+
+ private void copyTRBackgroundsToTDs(VScrollTableRow row) {
+ Element tr = row.getElement();
+ ComputedStyle cs = new ComputedStyle(tr);
+ String backgroundAttachment = cs
+ .getProperty("backgroundAttachment");
+ String backgroundClip = cs.getProperty("backgroundClip");
+ String backgroundColor = cs.getProperty("backgroundColor");
+ String backgroundImage = cs.getProperty("backgroundImage");
+ String backgroundOrigin = cs.getProperty("backgroundOrigin");
+ for (int ix = 0; ix < tr.getChildCount(); ix++) {
+ Element td = tr.getChild(ix).cast();
+ if (!elementHasBackground(td)) {
+ td.getStyle().setProperty("backgroundAttachment",
+ backgroundAttachment);
+ td.getStyle().setProperty("backgroundClip",
+ backgroundClip);
+ td.getStyle().setProperty("backgroundColor",
+ backgroundColor);
+ td.getStyle().setProperty("backgroundImage",
+ backgroundImage);
+ td.getStyle().setProperty("backgroundOrigin",
+ backgroundOrigin);
+ }
+ }
+ }
+
+ private boolean elementHasBackground(Element element) {
+ ComputedStyle cs = new ComputedStyle(element);
+ String clr = cs.getProperty("backgroundColor");
+ String img = cs.getProperty("backgroundImage");
+ return !("rgba(0, 0, 0, 0)".equals(clr.trim())
+ || "transparent".equals(clr.trim()) || img == null);
+ }
+
+ public void restoreTableAfterAnimation() {
+ int ix = lastItemIx;
+ VScrollTableRow row = null;
+ while ((row = getRowByRowIndex(ix)) != null) {
+ restoreStyleForTDsInRow(row);
+
+ --ix;
+ }
+ }
+
+ private void restoreStyleForTDsInRow(VScrollTableRow row) {
+ Element tr = row.getElement();
+ for (int ix = 0; ix < tr.getChildCount(); ix++) {
+ Element td = tr.getChild(ix).cast();
+ td.getStyle().clearProperty("backgroundAttachment");
+ td.getStyle().clearProperty("backgroundClip");
+ td.getStyle().clearProperty("backgroundColor");
+ td.getStyle().clearProperty("backgroundImage");
+ td.getStyle().clearProperty("backgroundOrigin");
+ }
+ }
+ }
+
+ /**
+ * Animates row expansion using the GWT animation framework.
+ *
+ * The idea is as follows:
+ *
+ * 1. Insert all rows normally
+ *
+ * 2. Insert a newly created DIV containing a new TABLE element below
+ * the DIV containing the actual scroll table body.
+ *
+ * 3. Clone the rows that were inserted in step 1 and attach the clones
+ * to the new TABLE element created in step 2.
+ *
+ * 4. The new DIV from step 2 is absolutely positioned so that the last
+ * inserted row is just behind the row that was expanded.
+ *
+ * 5. Hide the contents of the originally inserted rows by setting the
+ * DIV.v-table-cell-wrapper to display:none;.
+ *
+ * 6. Set the height of the originally inserted rows to 0.
+ *
+ * 7. The animation loop slides the DIV from step 2 downwards, while at
+ * the same pace growing the height of each of the inserted rows from 0
+ * to full height. The first inserted row grows from 0 to full and after
+ * this the second row grows from 0 to full, etc until all rows are full
+ * height.
+ *
+ * 8. Remove the DIV from step 2
+ *
+ * 9. Restore display:block; to the DIV.v-table-cell-wrapper elements.
+ *
+ * 10. DONE
+ */
+ private class RowExpandAnimation extends Animation {
+
+ private final List<VScrollTableRow> rows;
+ private Element cloneDiv;
+ private Element cloneTable;
+ private AnimationPreparator preparator;
+
+ public RowExpandAnimation(List<VScrollTableRow> rows) {
+ this.rows = rows;
+ buildAndInsertAnimatingDiv();
+ preparator = new AnimationPreparator(rows.get(0).getIndex() - 1);
+ preparator.prepareTableForAnimation();
+ for (VScrollTableRow row : rows) {
+ cloneAndAppendRow(row);
+ row.addStyleName("v-table-row-animating");
+ setCellWrapperDivsToDisplayNone(row);
+ row.setHeight(getInitialHeight());
+ }
+ }
+
+ protected String getInitialHeight() {
+ return "0px";
+ }
+
+ private void cloneAndAppendRow(VScrollTableRow row) {
+ Element clonedTR = null;
+ clonedTR = row.getElement().cloneNode(true).cast();
+ clonedTR.getStyle().setVisibility(Visibility.VISIBLE);
+ cloneTable.appendChild(clonedTR);
+ }
+
+ protected double getBaseOffset() {
+ return rows.get(0).getAbsoluteTop()
+ - rows.get(0).getParent().getAbsoluteTop()
+ - rows.size() * getRowHeight();
+ }
+
+ private void buildAndInsertAnimatingDiv() {
+ cloneDiv = DOM.createDiv();
+ cloneDiv.addClassName("v-treetable-animation-clone-wrapper");
+ cloneTable = DOM.createTable();
+ cloneTable.addClassName("v-treetable-animation-clone");
+ cloneDiv.appendChild(cloneTable);
+ insertAnimatingDiv();
+ }
+
+ private void insertAnimatingDiv() {
+ Element tableBody = getElement().cast();
+ Element tableBodyParent = tableBody.getParentElement().cast();
+ tableBodyParent.insertAfter(cloneDiv, tableBody);
+ }
+
+ @Override
+ protected void onUpdate(double progress) {
+ animateDiv(progress);
+ animateRowHeights(progress);
+ }
+
+ private void animateDiv(double progress) {
+ double offset = calculateDivOffset(progress, getRowHeight());
+
+ cloneDiv.getStyle().setTop(getBaseOffset() + offset, Unit.PX);
+ }
+
+ private void animateRowHeights(double progress) {
+ double rh = getRowHeight();
+ double vlh = calculateHeightOfAllVisibleLines(progress, rh);
+ int ix = 0;
+
+ while (ix < rows.size()) {
+ double height = vlh < rh ? vlh : rh;
+ rows.get(ix).setHeight(height + "px");
+ vlh -= height;
+ ix++;
+ }
+ }
+
+ protected double calculateHeightOfAllVisibleLines(double progress,
+ double rh) {
+ return rows.size() * rh * progress;
+ }
+
+ protected double calculateDivOffset(double progress, double rh) {
+ return progress * rows.size() * rh;
+ }
+
+ @Override
+ protected void onComplete() {
+ preparator.restoreTableAfterAnimation();
+ for (VScrollTableRow row : rows) {
+ resetCellWrapperDivsDisplayProperty(row);
+ row.removeStyleName("v-table-row-animating");
+ }
+ Element tableBodyParent = (Element) getElement()
+ .getParentElement();
+ tableBodyParent.removeChild(cloneDiv);
+ }
+
+ private void setCellWrapperDivsToDisplayNone(VScrollTableRow row) {
+ Element tr = row.getElement();
+ for (int ix = 0; ix < tr.getChildCount(); ix++) {
+ getWrapperDiv(tr, ix).getStyle().setDisplay(Display.NONE);
+ }
+ }
+
+ private Element getWrapperDiv(Element tr, int tdIx) {
+ Element td = tr.getChild(tdIx).cast();
+ return td.getChild(0).cast();
+ }
+
+ private void resetCellWrapperDivsDisplayProperty(VScrollTableRow row) {
+ Element tr = row.getElement();
+ for (int ix = 0; ix < tr.getChildCount(); ix++) {
+ getWrapperDiv(tr, ix).getStyle().clearProperty("display");
+ }
+ }
+
+ }
+
+ /**
+ * This is the inverse of the RowExpandAnimation and is implemented by
+ * extending it and overriding the calculation of offsets and heights.
+ */
+ private class RowCollapseAnimation extends RowExpandAnimation {
+
+ private final List<VScrollTableRow> rows;
+
+ public RowCollapseAnimation(List<VScrollTableRow> rows) {
+ super(rows);
+ this.rows = rows;
+ }
+
+ @Override
+ protected String getInitialHeight() {
+ return getRowHeight() + "px";
+ }
+
+ @Override
+ protected double getBaseOffset() {
+ return getRowHeight();
+ }
+
+ @Override
+ protected double calculateHeightOfAllVisibleLines(double progress,
+ double rh) {
+ return rows.size() * rh * (1 - progress);
+ }
+
+ @Override
+ protected double calculateDivOffset(double progress, double rh) {
+ return -super.calculateDivOffset(progress, rh);
+ }
+ }
}
/**
* Table cell specific style generator
*/
private CellStyleGenerator cellStyleGenerator = null;
-
+
/**
* Table cell specific tooltip generator
*/
target.addAttribute("style-" + columnIdMap.key(columnId),
cellStyle);
}
- }
-
+ }
+
if ((iscomponent[currentColumn] || iseditable)
&& Component.class.isInstance(cells[CELL_FIRSTCOL
+ currentColumn][indexInRowbuffer])) {
c.paint(target);
}
} else {
- target.addText((String) cells[CELL_FIRSTCOL + currentColumn][indexInRowbuffer]);
- paintCellTooltips(target, itemId, columnId);
+ target.addText((String) cells[CELL_FIRSTCOL + currentColumn][indexInRowbuffer]);
+ paintCellTooltips(target, itemId, columnId);
}
}
target.endTag("tr");
}
-
- private void paintCellTooltips(PaintTarget target, Object itemId, Object columnId) throws PaintException {
- if(itemDescriptionGenerator != null) {
- String itemDescription = itemDescriptionGenerator.generateDescription(this, itemId, columnId);
- if(itemDescription != null && !itemDescription.equals("")) {
- target.addAttribute("descr-" + columnIdMap.key(columnId), itemDescription);
- }
- }
+
+ private void paintCellTooltips(PaintTarget target, Object itemId,
+ Object columnId) throws PaintException {
+ if (itemDescriptionGenerator != null) {
+ String itemDescription = itemDescriptionGenerator
+ .generateDescription(this, itemId, columnId);
+ if (itemDescription != null && !itemDescription.equals("")) {
+ target.addAttribute("descr-" + columnIdMap.key(columnId),
+ itemDescription);
+ }
+ }
}
-
- private void paintRowTooltips(PaintTarget target, Object itemId ) throws PaintException {
- if(itemDescriptionGenerator != null) {
- String rowDescription = itemDescriptionGenerator.generateDescription(this, itemId, null);
- if(rowDescription != null && !rowDescription.equals("")){
- target.addAttribute("rowdescr", rowDescription);
- }
+
+ private void paintRowTooltips(PaintTarget target, Object itemId)
+ throws PaintException {
+ if (itemDescriptionGenerator != null) {
+ String rowDescription = itemDescriptionGenerator
+ .generateDescription(this, itemId, null);
+ if (rowDescription != null && !rowDescription.equals("")) {
+ target.addAttribute("rowdescr", rowDescription);
+ }
}
}
if (rowStyle != null && !rowStyle.equals("")) {
target.addAttribute("rowstyle", rowStyle);
}
- }
-
- paintRowTooltips(target, itemId);
-
- paintRowAttributes(target, itemId);
+ }
+
+ paintRowTooltips(target, itemId);
+
+ paintRowAttributes(target, itemId);
}
protected void paintRowHeader(PaintTarget target, Object[][] cells,
*/
public void setCellStyleGenerator(CellStyleGenerator cellStyleGenerator) {
this.cellStyleGenerator = cellStyleGenerator;
- requestRepaint();
+ refreshRenderedCells();
}
/**
removeListener(VScrollTable.COLUMN_REORDER_EVENT_ID,
ColumnReorderEvent.class, listener);
}
-
+
/**
- * Set the item description generator which generates tooltips
- * for cells and rows in the Table
+ * Set the item description generator which generates tooltips for cells and
+ * rows in the Table
*
* @param generator
- * The generator to use or null to disable
+ * The generator to use or null to disable
*/
- public void setItemDescriptionGenerator(ItemDescriptionGenerator generator){
+ public void setItemDescriptionGenerator(ItemDescriptionGenerator generator) {
if (generator != itemDescriptionGenerator) {
itemDescriptionGenerator = generator;
refreshRenderedCells();
}
}
-
+
/**
- * Get the item description generator which generates tooltips
- * for cells and rows in the Table.
+ * Get the item description generator which generates tooltips for cells and
+ * rows in the Table.
*/
- public ItemDescriptionGenerator getItemDescriptionGenerator(){
- return itemDescriptionGenerator;
+ public ItemDescriptionGenerator getItemDescriptionGenerator() {
+ return itemDescriptionGenerator;
}
}
private Object focusedRowId = null;
private Object hierarchyColumnId;
private Object toggledItemId;
+ private boolean animationsEnabled;
private ContainerStrategy getContainerStrategy() {
if (cStrategy == null) {
target.addAttribute("focusedRow", itemIdMapper.key(focusedRowId));
focusedRowId = null;
}
+ target.addAttribute("animate", animationsEnabled);
if (hierarchyColumnId != null) {
Object[] visibleColumns2 = getVisibleColumns();
for (int i = 0; i < visibleColumns2.length; i++) {
fireEvent(new CollapseEvent(this, itemId));
}
+ /**
+ * @return true if animations are enabled
+ */
+ public boolean isAnimationsEnabled() {
+ return animationsEnabled;
+ }
+
+ /**
+ * Animations can be enabled by passing true to this method. Currently
+ * expanding rows slide in from the top and collapsing rows slide out the
+ * same way. NOTE! not supported in Internet Explorer 6 or 7.
+ *
+ * @param animationsEnabled
+ * true or false whether to enable animations or not.
+ */
+ public void setAnimationsEnabled(boolean animationsEnabled) {
+ this.animationsEnabled = animationsEnabled;
+ requestRepaint();
+ }
+
}
import com.vaadin.ui.Button;\r
import com.vaadin.ui.Label;\r
import com.vaadin.ui.Table;\r
+import com.vaadin.ui.Table.CellStyleGenerator;\r
import com.vaadin.ui.Table.ColumnGenerator;\r
import com.vaadin.ui.Table.ColumnResizeEvent;\r
import com.vaadin.ui.Table.ColumnResizeListener;\r
\r
}\r
};\r
+\r
+ private class CellStyleInfo {\r
+ private final String styleName;\r
+ private final Object itemId;\r
+ private final Object propertyId;\r
+\r
+ public CellStyleInfo(String styleName, Object itemId, Object propertyId) {\r
+ this.styleName = styleName;\r
+ this.itemId = itemId;\r
+ this.propertyId = propertyId;\r
+ }\r
+\r
+ public boolean appliesTo(Object itemId, Object propertyId) {\r
+ return (this.itemId != null && this.itemId.equals(itemId))\r
+ && (this.propertyId == propertyId || (this.propertyId != null && this.propertyId\r
+ .equals(propertyId)));\r
+ }\r
+ }\r
+\r
+ private Command<T, CellStyleInfo> cellStyleCommand = new Command<T, CellStyleInfo>() {\r
+\r
+ public void execute(T c, final CellStyleInfo cellStyleInfo, Object data) {\r
+ if (cellStyleInfo == null) {\r
+ c.setCellStyleGenerator(null);\r
+ } else {\r
+ c.setCellStyleGenerator(new CellStyleGenerator() {\r
+\r
+ public String getStyle(Object itemId, Object propertyId) {\r
+ if (cellStyleInfo.appliesTo(itemId, propertyId)) {\r
+ return cellStyleInfo.styleName;\r
+ }\r
+ return null;\r
+ }\r
+ });\r
+ }\r
+ }\r
+ };\r
+\r
private Command<T, Boolean> setSortEnabledCommand = new Command<T, Boolean>() {\r
\r
public void execute(T c, Boolean value, Object data) {\r
\r
createColumnHeaderMode(CATEGORY_FEATURES);\r
createAddGeneratedColumnAction(CATEGORY_FEATURES);\r
+ createCellStyleAction(CATEGORY_FEATURES);\r
\r
createBooleanAction("Sort enabled", CATEGORY_FEATURES, true,\r
setSortEnabledCommand);\r
"", false));\r
}\r
\r
+ private void createCellStyleAction(String categoryFeatures) {\r
+ LinkedHashMap<String, CellStyleInfo> options = new LinkedHashMap<String, CellStyleInfo>();\r
+ options.put("None", null);\r
+ options.put("Red row", new CellStyleInfo(\r
+ "tables-test-cell-style-red-row", "Item 2", null));\r
+ options.put("Red cell", new CellStyleInfo(\r
+ "tables-test-cell-style-red-row", "Item 2", "Property 2"));\r
+ createSelectAction("Cell style generator", categoryFeatures, options,\r
+ "None", cellStyleCommand, true);\r
+ }\r
+\r
private void createColumnHeaderMode(String category) {\r
LinkedHashMap<String, Integer> columnHeaderModeOptions = new LinkedHashMap<String, Integer>();\r
columnHeaderModeOptions.put("Hidden", Table.COLUMN_HEADER_MODE_HIDDEN);\r
\r
// TODO:\r
// setCurrentPageFirstItemIndex()\r
- // Cell style generator\r
// Editable\r
// Cache rate\r
// CurrentPageFirstItemId\r
--- /dev/null
+package com.vaadin.tests.components.treetable;
+
+import com.vaadin.data.Container.Hierarchical;
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.AbstractComponent;
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.Layout;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.TreeTable;
+
+public class ExpandAnimationsInChameleon extends TestBase {
+
+ @Override
+ protected void setup() {
+ Layout grid = getGridLayout();
+
+ TreeTable t = getTreeTable(null);
+ grid.addComponent(t);
+
+ t = getTreeTable("small");
+ grid.addComponent(t);
+
+ t = getTreeTable("big");
+ grid.addComponent(t);
+
+ t = getTreeTable("striped");
+ grid.addComponent(t);
+
+ t = getTreeTable("small striped");
+ grid.addComponent(t);
+
+ t = getTreeTable("big striped");
+ grid.addComponent(t);
+
+ t = getTreeTable("strong");
+ grid.addComponent(t);
+
+ t = getTreeTable("small strong");
+ grid.addComponent(t);
+
+ t = getTreeTable("big strong");
+ grid.addComponent(t);
+
+ t = getTreeTable("borderless");
+ grid.addComponent(t);
+
+ t = getTreeTable("striped");
+ t.setColumnHeaderMode(Table.COLUMN_HEADER_MODE_HIDDEN);
+ t.setCaption(t.getCaption() + ", hidden headers");
+ grid.addComponent(t);
+
+ addComponent(grid);
+ }
+
+ GridLayout getGridLayout() {
+ GridLayout grid = new GridLayout(3, 1) {
+ @Override
+ public void addComponent(Component c) {
+ super.addComponent(c);
+ setComponentAlignment(c, Alignment.MIDDLE_CENTER);
+ if (c.getStyleName() != "") {
+ ((AbstractComponent) c).setDescription(c.getClass()
+ .getSimpleName()
+ + ".addStyleName(\""
+ + c.getStyleName() + "\")");
+ } else {
+ ((AbstractComponent) c).setDescription("new "
+ + c.getClass().getSimpleName() + "()");
+ }
+ }
+ };
+ grid.setWidth("100%");
+ grid.setSpacing(true);
+ grid.setMargin(true);
+ grid.setStyleName("preview-grid");
+ return grid;
+ }
+
+ public TreeTable getTreeTable(String style) {
+ TreeTable t = new TreeTable();
+ t.setAnimationsEnabled(true);
+ t.setWidth("250px");
+ t.setPageLength(5);
+ t.setSelectable(true);
+ t.setColumnCollapsingAllowed(true);
+ t.setColumnReorderingAllowed(true);
+
+ if (style != null) {
+ t.setStyleName(style);
+ t.setCaption("Table.addStyleName(\"" + style + "\")");
+ }
+
+ t.addContainerProperty("First", String.class, null);
+ t.addContainerProperty("Second", String.class, null);
+ t.addContainerProperty("Third", String.class, null);
+
+ for (int j = 1; j < 100; j++) {
+ t.addItem(new Object[] { "Foo " + j, "Bar " + j, "Lorem " + j }, j);
+ }
+ Hierarchical hc = t.getContainerDataSource();
+ hc.setChildrenAllowed(2, true);
+ for (int j = 4; j < 100; j++) {
+ hc.setParent(j, 2);
+ }
+
+ t.setColumnIcon("Third", new ThemeResource(
+ "../runo/icons/16/document.png"));
+ t.select(1);
+
+ return t;
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Colors should be correct while animating expands/collapses";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 6723;
+ }
+
+}
--- /dev/null
+<?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>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.treetable.TreeTableTest?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstreetableTreeTableTest::PID_Smenu#item0</td>
+ <td>27,4</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstreetableTreeTableTest::Root/VOverlay[0]/VMenuBar[0]#item8</td>
+ <td>49,10</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstreetableTreeTableTest::Root/VOverlay[1]/VMenuBar[0]#item5</td>
+ <td>104,7</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstreetableTreeTableTest::Root/VOverlay[2]/VMenuBar[0]#item1</td>
+ <td>40,10</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>redrow</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstreetableTreeTableTest::PID_StestComponent/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>10,4</td>
+</tr>
+<tr>
+ <td>pause</td>
+ <td></td>
+ <td>200</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>redrowexpanded</td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
createListeners(CATEGORY_LISTENERS);\r
// createItemStyleGenerator(CATEGORY_FEATURES);\r
\r
+ createBooleanAction("Animate collapse/expand", CATEGORY_STATE, false,\r
+ animationCommand);\r
+\r
// TODO: DropHandler\r
// TODO: DragMode\r
// TODO: ActionHandler\r
}\r
};\r
\r
+ protected Command<TreeTable, Boolean> animationCommand = new Command<TreeTable, Boolean>() {\r
+\r
+ public void execute(TreeTable c, Boolean enabled, Object data) {\r
+ c.setAnimationsEnabled(enabled);\r
+ }\r
+ };\r
+\r
public void nodeCollapse(CollapseEvent event) {\r
log(event.getClass().getSimpleName() + ": " + event.getItemId());\r
}\r