org.openelis.ui.widget.tree.StaticView.java Source code

Java tutorial

Introduction

Here is the source code for org.openelis.ui.widget.tree.StaticView.java

Source

/**
 * Exhibit A - UIRF Open-source Based Public Software License.
 * 
 * The contents of this file are subject to the UIRF Open-source Based Public
 * Software License(the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * openelis.uhl.uiowa.edu
 * 
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.
 * 
 * The Original Code is OpenELIS code.
 * 
 * The Initial Developer of the Original Code is The University of Iowa.
 * Portions created by The University of Iowa are Copyright 2006-2008. All
 * Rights Reserved.
 * 
 * Contributor(s): ______________________________________.
 * 
 * Alternatively, the contents of this file marked "Separately-Licensed" may be
 * used under the terms of a UIRF Software license ("UIRF Software License"), in
 * which case the provisions of a UIRF Software License are applicable instead
 * of those above.
 */
package org.openelis.ui.widget.tree;

import java.util.ArrayList;
import java.util.HashMap;

import org.openelis.ui.common.data.QueryData;
import org.openelis.ui.resources.TableCSS;
import org.openelis.ui.resources.TreeCSS;
import org.openelis.ui.resources.UIResources;
import org.openelis.ui.widget.Balloon;
import org.openelis.ui.widget.CSSUtils;
import org.openelis.ui.widget.DragItem;
import org.openelis.ui.widget.table.CellEditor;
import org.openelis.ui.widget.table.CellRenderer;
import org.openelis.ui.widget.table.Container;
import org.openelis.ui.widget.table.FlexTable;
import org.openelis.ui.widget.table.Row;
import org.openelis.ui.widget.table.event.CellMouseOutEvent;
import org.openelis.ui.widget.table.event.CellMouseOverEvent;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ScrollEvent;
import com.google.gwt.event.dom.client.ScrollHandler;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.uibinder.client.UiTemplate;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.HTMLTable;
import com.google.gwt.user.client.ui.LayoutPanel;
import com.google.gwt.user.client.ui.NativeVerticalScrollbar;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.UIObject;
import com.google.gwt.user.client.ui.Widget;

/**
 * Composite GWT widget to draw and handle logic for displaying a Table. All
 * methods are protected and only used by the Table widget itself.
 * 
 * @author tschmidt
 * 
 */
public class StaticView extends ViewInt {
    @UiTemplate("staticView.ui.xml")
    interface ViewUiBinder extends UiBinder<Widget, StaticView> {
    };

    public static final ViewUiBinder uiBinder = GWT.create(ViewUiBinder.class);

    /**
     * Reference to Table this View is used in
     */
    protected Tree tree;

    /**
     * Table used to draw Table flexTable
     */
    @UiField
    protected FlexTable flexTable;

    /**
     * Table used to draw Header flexTable for the table
     */
    @UiField(provided = true)
    protected Header header;

    /**
     * Scrollable area that contains flexTable and possibly header for
     * horizontal scroll.
     */
    @UiField
    protected ScrollPanel scrollView;

    @UiField
    protected LayoutPanel inner;

    /**
     * Flag used to determine if the table has been attached to know when to do
     * layout for the first time.
     */
    protected boolean attached, sized;

    protected int indent = 18;

    /**
     * Container to hold the widget for formatting and spacing
     */
    private Container container;

    protected TreeCSS css;

    protected StaticView source = this;

    /**
     * Constructor that takes a reference to the table that will use this view
     * 
     * @param tree
     */
    public StaticView(Tree tre) {
        header = new Header(tre);

        initWidget(uiBinder.createAndBindUi(this));

        this.tree = tre;

        setCSS(UIResources.INSTANCE.tree());

        container = new Container();
        container.setStyleName(css.TreeCellContainer());

        scrollView.addScrollHandler(new ScrollHandler() {

            @Override
            public void onScroll(ScrollEvent event) {
                DOM.setStyleAttribute(header.getElement(), "left",
                        (0 - scrollView.getHorizontalScrollPosition()) + "px");
            }
        });

        flexTable.addCellMouseOutHandler(new CellMouseOutEvent.Handler() {

            @Override
            public void onCellMouseOut(CellMouseOutEvent event) {
                if (tree.balloonTimer != null)
                    tree.balloonTimer.cancel();
                Balloon.hide();
            }
        });

    }

    @UiHandler("flexTable")
    protected void handleClick(ClickEvent event) {
        int r, c;

        // if x < 0 the user moused out of table before letting up button
        // ignore event in this case
        if (event.getX() < 0)
            return;

        c = flexTable.getCellForEvent(event).getCellIndex();
        r = flexTable.getCellForEvent(event).getRowIndex();

        Element cell = event.getNativeEvent().getEventTarget().cast();

        if (cell.getClassName().equals(css.treeOpenImage()) || cell.getClassName().equals(css.treeClosedImage())) {
            tree.toggle(flexTable.getRowForEvent(event.getNativeEvent()), event.getNativeEvent());
            //event.stopPropagation();
            return;
        }

        if (tree.fireCellClickedEvent(r, c, event.isControlKeyDown(), event.isShiftKeyDown()))
            tree.startEditing(r, c, event.getNativeEvent());
    }

    /**
     * Method that will layout the table view and is called on first time
     * attached and when attributes affecting layout are changed in the table
     */
    protected void layout() {

        com.google.gwt.dom.client.Node colgroup;

        /*
         * If View is not attached to DOM yet get out. onAttach will call
         * layout() the first time this widget attached.
         */

        if (!attached)
            return;

        colgroup = flexTable.getElement().getElementsByTagName("colgroup").getItem(0);

        if (colgroup != null) {
            while (colgroup.getChildCount() > tree.getColumnCount())
                colgroup.removeChild(colgroup.getChild(0));
        }

        for (int c = 0; c < tree.getColumnCount(); c++) {
            flexTable.getColumnFormatter().setWidth(c, tree.getColumnAt(c).getWidth() + "px");
            if (tree.getColumnAt(c).getStyle() != null)
                flexTable.getColumnFormatter().setStyleName(c, tree.getColumnAt(c).getStyle());
        }

        flexTable.setWidth(tree.getTotalColumnWidth() + "px");
        flexTable.setHeight("1px");
        DOM.setStyleAttribute(flexTable.getElement(), "backgroundColor", "transparent");

        // ********** Create and attach Header **************
        if (tree.hasHeader()) {
            UIObject.setVisible(inner.getWidgetContainerElement(header), true);
            header.setVisible(true);
            header.layout();
            inner.setWidgetTopBottom(scrollView, CSSUtils.getHeight(header), Unit.PX, 0, Unit.PX);
        } else {
            UIObject.setVisible(inner.getWidgetContainerElement(header), false);
            header.setVisible(false);
            inner.setWidgetTopBottom(scrollView, 0, Unit.PX, 0, Unit.PX);
        }
    }

    /**
     * This method is called when a column width is changed. It will resize the
     * columns to there currently set width.
     */
    protected void resize() {

        for (int c = 0; c < tree.getColumnCount(); c++)
            flexTable.getColumnFormatter().setWidth(c, tree.getColumnAt(c).getWidth() + "px");
        flexTable.setWidth(tree.getTotalColumnWidth() + "px");
    }

    /**
     * Will create the the necessary visible rows for the flexTable table
     * depending on what is needed at the time. If model.size() < visibleRows
     * then the number of rows created will equal model.size() else the number
     * visibleRows will be created for the flexTable table.
     */
    private void createRow(int rc) {
        flexTable.insertRow(rc);
        flexTable.getRowFormatter().getElement(rc).setAttribute("height", tree.getRowHeight() + "px");
        flexTable.getRowFormatter().getElement(rc).setAttribute("index", "" + rc);

        if (tree.getDragController() != null)
            tree.dragController.makeDraggable(new DragItem(tree, flexTable.getRowFormatter().getElement(rc)));
    }

    /**
     * This method will redraw the table from the startRow to the endRow that
     * are passed in as params. Rows are passed as -1,-1 the entire view will be
     * drawn.
     * 
     * @param smr
     * @param emr
     */
    protected void renderView(int smr, int emr) {
        int r, startMax;

        tree.finishEditing();

        if (smr < 0)
            smr = 0;

        if (emr < 0)
            emr = tree.getRowCount() - 1;

        startMax = scrollView.getMaximumVerticalScrollPosition();

        /*
         * Create/Load Rows in the flexTable table
         */
        for (r = smr; r <= emr; r++) {
            /*
             * Create table row if needed
             */
            if (r >= flexTable.getRowCount()) {
                createRow(flexTable.getRowCount());
                /*
                 * ColumnFormatter is not available until first row is inserted
                 * so call resize after that
                 */
                if (r == 0)
                    resize();
            }

            for (int c = 0; c < tree.getColumnCount(); c++)
                renderCell(r, c);

            applyRowStyle(r);
        }

        while (flexTable.getRowCount() > tree.getRowCount())
            flexTable.removeRow(tree.getRowCount());

        adjustForScroll(startMax);

        if (!tree.fixScrollBar && !sized) {
            Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() {
                @Override
                public void execute() {
                    if (flexTable.getOffsetHeight() < scrollView.getOffsetHeight())
                        tree.getParent().setHeight(CSSUtils.getHeight(flexTable) + "px");
                    sized = true;
                }

            });
        }

    }

    protected void bulkRender() {
        CellRenderer renderer;
        String style;
        Node node;

        SafeHtmlBuilder tb = new SafeHtmlBuilder();

        for (int r = 0; r < tree.getRowCount(); r++) {
            node = tree.getNodeAt(r);
            style = node.getStyle(r);
            tb.appendHtmlConstant("<tr height='" + tree.getRowHeight() + "px' index='" + r + "'"
                    + (style != null ? " class='" + style + "'>" : ">"));
            for (int c = 0; c < tree.getColumnCount(); c++) {

                if (c < tree.getNodeDefinition(node.getType()).size()) {
                    renderer = tree.getCellRenderer(r, c);
                    if (c == 0) {
                        Grid treeGrid = getTreeCell(node, r, c);
                        renderer.render(treeGrid, 0, treeGrid.getCellCount(0) - 1, tree.getValueAt(r, c));
                        tb.appendHtmlConstant("<td>");
                        tb.appendHtmlConstant(treeGrid.getElement().getString());
                        tb.appendHtmlConstant("</td>");
                    } else {
                        tb.appendHtmlConstant("<td>");
                        tb.append(renderer.bulkRender(tree.getValueAt(r, c)));
                        tb.appendHtmlConstant("</td>");
                    }
                } else {
                    tb.appendHtmlConstant("<td/>");
                }
            }
            tb.appendHtmlConstant("</tr>");
        }

        flexTable.getElement().getElementsByTagName("tbody").getItem(0).setInnerSafeHtml(tb.toSafeHtml());

        Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() {
            @Override
            public void execute() {
                adjustForScroll(0);
            }
        });
    }

    protected void addNodes(int start, int end) {
        int startMax = scrollView.getMaximumVerticalScrollPosition();

        for (int r = start; r <= end; r++) {
            createRow(r);

            for (int c = 0; c < tree.getColumnCount(); c++)
                renderCell(r, c);

            applyRowStyle(r);
        }

        adjustForScroll(startMax);

    }

    protected void addColumn(int c) {
        for (int i = 0; i < flexTable.getRowCount(); i++) {
            flexTable.insertCell(i, c);
        }
        layout();
        for (int i = 0; i < flexTable.getRowCount(); i++) {
            renderCell(i, c);
        }
    }

    protected void removeColumn(int c) {
        for (int i = 0; i < flexTable.getRowCount(); i++) {
            flexTable.removeCell(i, c);
        }
        layout();
    }

    protected void removeNodes(int start, int count) {
        int startMax = scrollView.getMaximumVerticalScrollPosition();
        for (int r = 0; r < count; r++) {
            flexTable.removeRow(start);
        }

        adjustForScroll(startMax);
    }

    protected void removeAllNodes() {
        flexTable.removeAllRows();
    }

    protected void renderSelections(int start, int end) {

        for (int r = start; r <= end; r++) {
            if (tree.isNodeSelected(r))
                flexTable.getRowFormatter().addStyleName(r, css.Selection());
            else
                flexTable.getRowFormatter().removeStyleName(r, css.Selection());
        }

    }

    protected void renderExceptions(int start, int end) {
        start = start < 0 ? 0 : start;
        end = end < 0 ? flexTable.getRowCount() - 1 : end;

        for (int r = start; r <= end; r++) {
            for (int c = 0; c < tree.getColumnCount(); c++) {
                if (tree.hasExceptions(r, c)) {
                    flexTable.getCellFormatter().addStyleName(r, c,
                            Balloon.isWarning(tree.getEndUserExceptions(r, c), tree.getValidateExceptions(r, c))
                                    ? css.InputWarning()
                                    : css.InputError());
                    flexTable.addCellMouseOverHandler(new CellMouseOverEvent.Handler(r, c) {

                        @Override
                        public void onCellMouseOver(CellMouseOverEvent event) {
                            int x, y;

                            Element td = flexTable.getCellFormatter().getElement(event.getRow(), event.getCol());

                            y = td.getAbsoluteTop();
                            x = td.getAbsoluteLeft() + (td.getOffsetWidth() / 2);

                            tree.drawExceptions(event.getRow(), event.getCol(), x, y);
                        }

                    });
                } else {
                    flexTable.getCellFormatter().removeStyleName(r, c, css.InputWarning());
                    flexTable.getCellFormatter().removeStyleName(r, c, css.InputError());
                    flexTable.removeHandler(r, c);
                }
            }
        }
    }

    protected void bulkExceptions(HashMap<Node, HashMap<Integer, ArrayList<Exception>>> exceptions) {
        for (Node node : exceptions.keySet()) {
            int r = tree.getNodeViewIndex(node);
            for (int c : exceptions.get(node).keySet()) {
                flexTable.getCellFormatter().addStyleName(r, c,
                        Balloon.isWarning(tree.getEndUserExceptions(r, c), tree.getValidateExceptions(r, c))
                                ? css.InputWarning()
                                : css.InputError());
                flexTable.addCellMouseOverHandler(new CellMouseOverEvent.Handler(r, c) {
                    @Override
                    public void onCellMouseOver(CellMouseOverEvent event) {
                        tree.drawExceptions(event.getRow(), event.getCol(), event.getX(), event.getY());
                    }

                });
            }
        }
    }

    /**
     * This method will apply either a style that is set in the Row getStyle
     * method or the selection style if the row is selected
     */
    protected void applyRowStyle(int r) {
        String style;

        if (r >= tree.getRowCount())
            return;

        style = tree.getNodeAt(r).getStyle(r);
        if (style != null)
            flexTable.getRowFormatter().setStyleName(r, style);

        if (tree.isNodeSelected(r))
            flexTable.getRowFormatter().addStyleName(r, css.Selection());
        else
            flexTable.getRowFormatter().removeStyleName(r, css.Selection());
    }

    /**
     * Applies the selection style to a table row
     * 
     * @param r
     */
    protected void applySelectionStyle(int r) {
        int rc;

        rc = r;
        if (rc > -1)
            flexTable.getRowFormatter().addStyleName(rc, css.Selection());

    }

    /**
     * Removes the Selection style from a table row
     * 
     * @param r
     */
    protected void applyUnselectionStyle(int r) {
        int rc;

        rc = r;
        if (rc > -1)
            flexTable.getRowFormatter().removeStyleName(rc, css.Selection());

    }

    protected void renderCell(int r, int c) {
        CellRenderer renderer;
        HTMLTable table;
        int row, col, level;
        Node node;

        node = tree.getNodeAt(r);
        level = tree.showRoot() ? node.getLevel() : node.getLevel() - 1;

        if (c < tree.getNodeDefinition(node.getType()).size())
            renderer = tree.getCellRenderer(r, c);
        else {
            flexTable.setText(r, c, "");
            flexTable.getCellFormatter().removeStyleName(r, c, css.InputError());
            return;
        }

        table = flexTable;
        row = r;
        col = c;

        if (c == 0) {
            if (flexTable.getCellCount(r) == 0) {
                SafeHtmlBuilder tb = new SafeHtmlBuilder();
                Grid treeGrid = getTreeCell(node, r, c);
                renderer.render(treeGrid, 0, treeGrid.getCellCount(0) - 1, tree.getValueAt(r, c));
                tb.appendHtmlConstant("<td>");
                tb.appendHtmlConstant(treeGrid.getElement().getString());
                tb.appendHtmlConstant("</td>");
                flexTable.setHTML(r, c, treeGrid.getElement().getString());
            } else {
                if (!node.isLeaf()) {
                    if (level == 0)
                        flexTable.getCellFormatter().getElement(r, c).getElementsByTagName("td").getItem(0)
                                .getStyle().setDisplay(Display.NONE);
                    if (node.isOpen)
                        flexTable.getCellFormatter().getElement(r, c).getElementsByTagName("td").getItem(1)
                                .setClassName(css.treeOpenImage());
                    else
                        flexTable.getCellFormatter().getElement(r, c).getElementsByTagName("td").getItem(1)
                                .setClassName(css.treeClosedImage());
                } else {
                    if (level == 0) {
                        flexTable.getCellFormatter().getElement(r, c).getElementsByTagName("td").getItem(0)
                                .getStyle().setProperty("display", "table-cell");
                    }
                    flexTable.getCellFormatter().getElement(r, c).getElementsByTagName("td").getItem(1)
                            .setClassName("");
                }
                if (node.getImage() != null) {
                    flexTable.getCellFormatter().getElement(r, c).getElementsByTagName("td").getItem(2)
                            .setClassName(node.getImage());
                    flexTable.getCellFormatter().getElement(r, c).getElementsByTagName("td").getItem(2).getStyle()
                            .setProperty("display", "table-cell");
                } else
                    flexTable.getCellFormatter().getElement(r, c).getElementsByTagName("td").getItem(2).getStyle()
                            .setProperty("display", "none");
                flexTable.getCellFormatter().getElement(r, c).getElementsByTagName("td").getItem(3)
                        .setInnerSafeHtml(renderer.bulkRender(tree.getValueAt(r, c)));
            }
        } else {
            if (tree.getQueryMode())
                renderer.renderQuery(table, row, col, (QueryData) tree.getValueAt(r, c));
            else
                renderer.render(table, row, col, tree.getValueAt(r, c));
        }
        if (tree.hasExceptions(r, c)) {
            flexTable.getCellFormatter().addStyleName(r, c,
                    Balloon.isWarning(tree.getEndUserExceptions(r, c), tree.getValidateExceptions(r, c))
                            ? css.InputWarning()
                            : css.InputError());
            flexTable.addCellMouseOverHandler(new CellMouseOverEvent.Handler(r, c) {
                @Override
                public void onCellMouseOver(CellMouseOverEvent event) {
                    tree.drawExceptions(event.getRow(), event.getCol(), event.getX(), event.getY());
                }

            });
        } else {
            flexTable.getCellFormatter().removeStyleName(r, c, css.InputError());
            flexTable.getCellFormatter().removeStyleName(r, c, css.InputWarning());
            flexTable.removeHandler(r, c);
        }

    }

    /**
     * Will put the passed cell into edit mode making sure the the cell is
     * compeltely visible first
     * 
     * @param r
     * @param c
     * @param value
     * @param event
     */
    protected void startEditing(int r, final int c, Object value, NativeEvent event) {
        container.dettach();
        if (c > 0) {
            container.setWidth((tree.getColumnAt(c).getWidth() - 4));
            container.setHeight((tree.getRowHeight() - 4));
            flexTable.setWidget(r, c, container);
        } else {
            Element tableCell = flexTable.getCellFormatter().getElement(r, c).getElementsByTagName("td").getItem(3);
            if (tableCell.hasChildNodes())
                tableCell.removeChild(tableCell.getChild(0));

            tableCell.appendChild(container.getElement());
            container.attach();

            int width = tableCell.getOffsetWidth() - 3;
            if (width > 0)
                container.setWidth(width);
            container.setHeight(tree.getRowHeight() - 5);
        }

        if (tree.getQueryMode())
            tree.getCellEditor(r, c).startEditingQuery((QueryData) tree.getValueAt(r, c), container, event);
        else
            tree.getCellEditor(r, c).startEditing(tree.getValueAt(r, c), container, event);
    }

    /**
     * Returns the value of the CellEditor
     * 
     * @param r
     * @param c
     * @return
     */
    protected Object finishEditing(int r, int c) {
        CellEditor cellEditor;

        cellEditor = tree.getCellEditor(r, c);

        return cellEditor.finishEditing();
    }

    /**
     * This method will re-adjust the scrollbar height based on number of rows
     * in the model
     */
    protected void adjustScrollBarHeight() {

    }

    /**
     * Method will scroll the table to make sure the passed row is included in
     * the view
     * 
     * @param r
     * @return
     */
    protected boolean scrollToVisible(int r) {

        if (scrollView.getMaximumVerticalScrollPosition() == 0)
            return false;

        if (isRowVisible(r))
            return false;

        int hPos = scrollView.getHorizontalScrollPosition();

        DOM.scrollIntoView(flexTable.getRowFormatter().getElement(r));

        scrollView.setHorizontalScrollPosition(hPos);

        return true;
    }

    /**
     * Method will scroll the view up or down by the passed number of rows. Pass
     * negative value to scroll up.
     * 
     * @param n
     */
    protected void scrollBy(int n) {

    }

    /**
     * Returns true if the passed row is drawn in the current view
     * 
     * @param r
     * @return
     */
    protected boolean isRowVisible(int r) {
        Element row = flexTable.getRowFormatter().getElement(r);
        int top = row.getOffsetTop();
        int height = row.getOffsetHeight();

        return top >= scrollView.getVerticalScrollPosition()
                && ((top + height) <= scrollView.getVerticalScrollPosition() + CSSUtils.getHeight(scrollView));
    }

    /**
     * Method is overridden from Composite so that layout() can be deferred
     * until it is attached to the DOM
     */
    @Override
    protected void onAttach() {

        super.onAttach();

        if (attached)
            return;

        attached = true;
        layout();
        flexTable.setVisible(false);
        Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() {

            @Override
            public void execute() {
                flexTable.setVisible(true);
                Element svEl = inner.getWidgetContainerElement(scrollView);
                if (scrollView.getMaximumVerticalScrollPosition() == 0)
                    tree.setWidth(CSSUtils.getWidth(svEl) - 1);
                else
                    tree.setWidth(CSSUtils.getWidth(svEl) - NativeVerticalScrollbar.getNativeScrollbarWidth() - 1);

                if (CSSUtils.getWidth((svEl)) > 0) {
                    tree.setWidth(CSSUtils.getWidth(svEl) - 2);
                    scrollView.setWidth(
                            CSSUtils.getWidth(svEl) - CSSUtils.getAddedBorderWidth(tree.getElement()) + "px");
                }

                if (CSSUtils.getHeight(svEl) > 0) {
                    scrollView.setHeight(CSSUtils.getHeight(svEl) - CSSUtils.getHeight(header)
                            - CSSUtils.getAddedBorderHeight(tree.getElement()) + "px");

                }

            }
        });

    }

    /**
     * Returns the Header for this view
     * 
     * @return
     */
    protected Header getHeader() {
        return header;
    }

    /**
     * Returns the actual drawn row height on the screen
     */
    protected int getRowHeight() {
        return tree.rowHeight;
    }

    public void setCSS(TreeCSS css) {
        css.ensureInjected();

        for (int i = 0; i < flexTable.getRowCount(); i++) {
            if (flexTable.getRowFormatter().getStyleName(i).contains(this.css.Selection())) {
                flexTable.getRowFormatter().removeStyleName(i, this.css.Selection());
                flexTable.getRowFormatter().addStyleName(i, css.Selection());
            }
            for (int j = 0; j < flexTable.getCellCount(i); j++) {
                if (flexTable.getCellFormatter().getStyleName(i, j).contains(this.css.InputError())) {
                    flexTable.getCellFormatter().removeStyleName(i, j, this.css.InputError());
                    flexTable.getCellFormatter().addStyleName(i, j, css.InputError());
                }
                if (flexTable.getCellFormatter().getStyleName(i, j).contains(this.css.InputWarning())) {
                    flexTable.getCellFormatter().removeStyleName(i, j, this.css.InputWarning());
                    flexTable.getCellFormatter().addStyleName(i, j, css.InputWarning());
                }
            }
        }

        this.css = css;

        flexTable.setStyleName(css.Tree());

    }

    @Override
    protected int rowHeight() {
        return 0;
    }

    @Override
    FlexTable table() {
        return flexTable;
    }

    @Override
    ScrollPanel scrollView() {
        return scrollView;
    }

    @Override
    TableCSS css() {
        return css;
    }

    @Override
    void selectAll() {
        for (int i = 0; i < flexTable.getRowCount(); i++) {
            applySelectionStyle(i);
        }
    }

    @Override
    public void onResize() {
        super.onResize();

        Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() {

            @Override
            public void execute() {
                Element svEl = inner.getWidgetContainerElement(scrollView);

                if (CSSUtils.getWidth(svEl) > 0) {

                    scrollView.setWidth(
                            CSSUtils.getWidth(svEl) - CSSUtils.getAddedBorderWidth(tree.getElement()) + "px");

                    if (CSSUtils.getHeight(inner) > 0) {
                        int height = CSSUtils.getHeight(inner) - CSSUtils.getHeight(header)
                                - CSSUtils.getAddedBorderHeight(tree.getElement());
                        /*
                         * This check is here only for Unit Testing.  If not done Unit test on the
                         * table will fail here with assertion check from the widget.
                         */
                        if (height > 0)
                            scrollView.setHeight(height + "px");
                    }

                    if (scrollView.getMaximumVerticalScrollPosition() == 0)
                        tree.setWidth(CSSUtils.getWidth(svEl) - 2);
                    else
                        tree.setWidth(
                                CSSUtils.getWidth(svEl) - NativeVerticalScrollbar.getNativeScrollbarWidth() - 2);

                }
            }
        });

    }

    private void adjustForScroll(int before) {
        if (before == 0 && scrollView.getMaximumVerticalScrollPosition() > 0)
            tree.setWidth((tree.getOffsetWidth() - NativeVerticalScrollbar.getNativeScrollbarWidth() - 2) + "px");
        else if (before > 0 && scrollView.getMaximumVerticalScrollPosition() == 0)
            tree.setWidth(tree.getOffsetWidth() - 2 + "px");
    }

    protected TreeGrid getTreeCell(Node node, int row, int col) {
        TreeGrid grid = null;
        int level;
        String image;
        Widget widget;
        AbsolutePanel lineDiv, line;

        image = node.getImage();
        level = tree.showRoot() ? node.getLevel() : node.getLevel() - 1;

        /**
         * Seems something has changed in GWT jars where we need to create a new TreeGrid everytime to ensure that the correct tree grid is displayed
         * May need to revisit if performance is compromised. 
         */
        //grid = (widget = flexTable.getWidget(row, col)) instanceof TreeGrid ? (TreeGrid)widget : new TreeGrid(level);

        grid = new TreeGrid(level);

        // Set the new tree grid into table when drawing first time otherwise re-use grid;
        //if(widget != grid)   
        flexTable.setWidget(row, col, grid);

        if (!node.isLeaf()) {
            if (node.isOpen)
                grid.getCellFormatter().setStyleName(0, 1, css.treeOpenImage());
            else
                grid.getCellFormatter().setStyleName(0, 1, css.treeClosedImage());
        }

        //if at top level of tree set line cell to invisible;
        if (level == 0) {
            grid.getCellFormatter().setWidth(0, 0, "15px");
            if (!node.isLeaf()) {
                grid.getCellFormatter().setVisible(0, 0, false);
            }
        } else {
            /*
             * Create div to draw lines and set cell to appropiate width
             */
            grid.getCellFormatter().setWidth(0, 0, (level * 15) + "px");

            lineDiv = new AbsolutePanel();

            lineDiv.setWidth("100%");
            lineDiv.setHeight(tree.rowHeight + "px");

            grid.setWidget(0, 0, lineDiv);

            int i = 0;

            //Loop for drawing lines
            while (i < level) {

                // Check if lines lower then current node level should be drawn
                if (i + 1 < level) {
                    Node parent = node.getParent();
                    while (parent != tree.root && parent.getParent().getLastChild() == parent)
                        parent = parent.getParent();
                    if (parent.getParent() == tree.root) {
                        i++;
                        continue;
                    }
                }

                // Draw vertical for all levels up to current level
                if (i < level) {
                    line = new AbsolutePanel();

                    line.getElement().getStyle().setWidth(1, Unit.PX);
                    line.getElement().getStyle().setBackgroundColor("black");
                    if (node.getParent().getLastChild() == node && i + 1 == level) {
                        line.getElement().getStyle().setHeight(tree.rowHeight / 2, Unit.PX);
                        line.getElement().getStyle().setTop(-((tree.rowHeight / 2) - 1), Unit.PX);
                    } else
                        line.getElement().getStyle().setHeight(tree.rowHeight, Unit.PX);

                    lineDiv.add(line, (i * 15) + 8, 0);

                }

                //If loop is on current level then draw dash to node
                if (i + 1 == level) {
                    line = new AbsolutePanel();

                    line.getElement().getStyle().setWidth(5, Unit.PX);
                    line.getElement().getStyle().setBackgroundColor("black");
                    line.getElement().getStyle().setHeight(1, Unit.PX);
                    lineDiv.add(line, (i * 15) + 8, (tree.rowHeight / 2));

                }

                i++;
            }
        }

        // Draw node image if one is set in the model
        if (image != null) {
            grid.getCellFormatter().setStyleName(0, 2, image);
            grid.getCellFormatter().getElement(0, 2).getStyle().setProperty("display", "table-cell");
        } else
            grid.getCellFormatter().setVisible(0, 2, false);

        return grid;
    }

    protected class TreeGrid extends Grid {

        public TreeGrid(Element grid) {
            claimElement(grid);
        }

        public TreeGrid(int level) {
            super(1, 4);
            addStyleName(css.TreeCell());
            setWidth("100%");
            getCellFormatter().setWidth(0, 3, "100%");
            setCellPadding(0);
            setCellSpacing(0);
        }

        public TreeGrid(String html) {
            getElement().setInnerHTML(html);
        }
    }

}