Java tutorial
/* * Sencha GXT 2.3.1 - Sencha for GWT * Copyright(c) 2007-2013, Sencha, Inc. * licensing@sencha.com * * http://www.sencha.com/products/gxt/license/ */ package com.extjs.gxt.ui.client.widget.grid; import com.extjs.gxt.ui.client.GXT; import com.extjs.gxt.ui.client.Style; import com.extjs.gxt.ui.client.Style.HorizontalAlignment; import com.extjs.gxt.ui.client.Style.SortDir; import com.extjs.gxt.ui.client.core.DomHelper; import com.extjs.gxt.ui.client.core.El; import com.extjs.gxt.ui.client.core.XDOM; import com.extjs.gxt.ui.client.data.BaseModel; import com.extjs.gxt.ui.client.data.ModelData; import com.extjs.gxt.ui.client.data.PagingLoadConfig; import com.extjs.gxt.ui.client.data.SortInfo; import com.extjs.gxt.ui.client.event.*; import com.extjs.gxt.ui.client.js.JsArray; import com.extjs.gxt.ui.client.store.ListStore; import com.extjs.gxt.ui.client.store.Record; import com.extjs.gxt.ui.client.store.StoreEvent; import com.extjs.gxt.ui.client.store.StoreListener; import com.extjs.gxt.ui.client.util.*; import com.extjs.gxt.ui.client.widget.Component; import com.extjs.gxt.ui.client.widget.ComponentHelper; import com.extjs.gxt.ui.client.widget.menu.CheckMenuItem; import com.extjs.gxt.ui.client.widget.menu.Menu; import com.extjs.gxt.ui.client.widget.menu.MenuItem; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.dom.client.*; import com.google.gwt.i18n.client.DateTimeFormat; import com.google.gwt.safehtml.shared.SafeHtml; import com.google.gwt.safehtml.shared.SafeHtmlUtils; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.AbstractImagePrototype; import com.google.gwt.user.client.ui.Widget; import java.util.*; /** * This class encapsulates the user interface of an {@link Grid}. Methods of * this class may be used to access user interface elements to enable special * display effects. Do not change the DOM structure of the user interface. </p> * <p /> * This class does not provide ways to manipulate the underlying data. The data * model of a Grid is held in an {@link ListStore}. */ public class GridView extends BaseObservable { /** * Icons used by Grid which can be overridden as needed. s */ public class GridViewImages { private AbstractImagePrototype columns = GXT.IMAGES.grid_columns(); private AbstractImagePrototype sortAsc = GXT.IMAGES.grid_sortAsc(); private AbstractImagePrototype sortDesc = GXT.IMAGES.grid_sortDesc(); public AbstractImagePrototype getColumns() { return columns; } public AbstractImagePrototype getSortAsc() { return sortAsc; } public AbstractImagePrototype getSortDesc() { return sortDesc; } public void setColumns(AbstractImagePrototype columnsIcon) { this.columns = columnsIcon; } public void setSortAsc(AbstractImagePrototype sortAscIcon) { this.sortAsc = sortAscIcon; } public void setSortDesc(AbstractImagePrototype sortDescIcon) { this.sortDesc = sortDescIcon; } } private static JavaScriptObject colRe; protected int activeHdIndex; protected boolean autoFill; protected int borderWidth = 2; protected ColumnModel cm; protected Listener<ColumnModelEvent> columnListener; protected boolean deferEmptyText; protected ListStore<ModelData> ds; // elements protected El el, mainWrap, mainHd, innerHd, scroller, mainBody, focusEl; protected SafeHtml emptyText = SafeGxt.NO_BREAK_SPACE; protected boolean enableHdMenu = true; // config protected boolean enableRowBody; protected boolean focusEnabled = true; protected ColumnFooter footer; protected boolean forceFit; protected Grid<ModelData> grid; protected ColumnHeader header; protected int headerColumnIndex; protected boolean headerDisabled; protected GridViewImages images; protected int lastViewWidth; protected StoreListener<ModelData> listener; protected Element overRow; protected boolean preventScrollToTopOnRefresh; protected int scrollOffset = XDOM.getScrollBarWidth(); protected boolean selectable = false; protected SortInfo sortState; protected int splitterWidth = 5; protected GridTemplates templates; protected boolean userResized; // we first render grid with a vbar, and remove as needed protected boolean vbar = true; protected GridViewConfig viewConfig; protected List<List<Widget>> widgetList = new ArrayList<List<Widget>>(); private DelayedTask addTask = new DelayedTask(new Listener<BaseEvent>() { public void handleEvent(BaseEvent be) { calculateVBar(false); refreshFooterData(); } }); private boolean adjustForHScroll = true; private String cellSelector = "td.x-grid3-cell"; private int cellSelectorDepth = 4; private DelayedTask removeTask = new DelayedTask(new Listener<BaseEvent>() { public void handleEvent(BaseEvent be) { calculateVBar(false); applyEmptyText(); refreshFooterData(); processRows(0, false); } }); private String rowSelector = "div.x-grid3-row"; private int rowSelectorDepth = 10; private boolean showDirtyCells = true; private boolean showInvalidCells; /** * Ensured the current row and column is visible. * * @param row the row index * @param col the column index * @param hscroll true to scroll horizontally if needed * @return the calculated point */ public Point ensureVisible(int row, int col, boolean hscroll) { if (grid == null || !grid.isViewReady() || row < 0 || row > ds.getCount()) { return null; } if (col == -1) { col = 0; } Element rowEl = getRow(row); Element cellEl = null; if (!(!hscroll && col == 0)) { while (cm.isHidden(col)) { col++; } cellEl = getCell(row, col); } if (rowEl == null) { return null; } Element c = scroller.dom; int ctop = 0; Element p = rowEl, stope = el.dom; while (p != null && p != stope) { ctop += p.getOffsetTop(); p = p.getOffsetParent().cast(); } ctop -= mainHd.dom.getOffsetHeight(); int cbot = ctop + rowEl.getOffsetHeight(); int ch = c.getOffsetHeight(); int stop = c.getScrollTop(); int sbot = stop + ch; if (ctop < stop) { c.setScrollTop(ctop); } else if (cbot > sbot) { if (hscroll && (cm.getTotalWidth() > scroller.getWidth() - scrollOffset)) { cbot += scrollOffset; } c.setScrollTop(cbot -= ch); } if (hscroll && cellEl != null) { int cleft = cellEl.getOffsetLeft(); int cright = cleft + cellEl.getOffsetWidth(); int sleft = c.getScrollLeft(); int sright = sleft + c.getOffsetWidth(); if (cleft < sleft) { c.setScrollLeft(cleft); } else if (cright > sright) { c.setScrollLeft(cright - scroller.getStyleWidth()); } } return cellEl != null ? fly(cellEl).getXY() : new Point(c.getScrollLeft(), fly(rowEl).getY()); } /** * Returns the cell. * * @param elem the cell element or a child element * @return the cell element */ public Element findCell(Element elem) { if (elem == null) { return null; } return fly(elem).findParentElement(cellSelector, cellSelectorDepth); } /** * Returns the cell index. * * @param elem the cell or child element * @param requiredStyle an optional required style name * @return the cell index or -1 if not found */ public int findCellIndex(Element elem, String requiredStyle) { Element cell = findCell(elem); if (cell != null && (requiredStyle == null || fly(cell).hasStyleName(requiredStyle))) { return getCellIndex(cell); } return -1; } /** * Returns the row element. * * @param el the row element or any child element * @return the matching row element */ public Element findRow(Element el) { if (el == null) { return null; } return fly(el).findParentElement(rowSelector, rowSelectorDepth); } /** * Returns the row index. * * @param elem the row or child of the row element * @return the index */ public int findRowIndex(Element elem) { Element r = findRow(elem); return r != null ? r.getPropertyInt("rowIndex") : -1; } /** * Focus the cell and scrolls into view. * * @param rowIndex the row index * @param colIndex the column index * @param hscroll true to scroll horizontally */ public void focusCell(int rowIndex, int colIndex, boolean hscroll) { Point xy = ensureVisible(rowIndex, colIndex, hscroll); if (xy != null) { focusEl.setXY(xy); if (focusEnabled) { focusGrid(); } } } /** * Focus the row and scrolls into view. * * @param rowIndex the row index */ public void focusRow(int rowIndex) { focusCell(rowIndex, 0, true); } /** * Returns the grid's body element. * * @return the body element */ public El getBody() { return scroller; } /** * Returns the grid's <TD> HtmlElement at the specified coordinates. * * @param row the row index in which to find the cell * @param col the column index of the cell * @return the <TD> at the specified coordinates */ public Element getCell(int row, int col) { // ROW DIV TABLE TR TD Element rowEl = getRow(row); return (Element) ((rowEl != null && rowEl.hasChildNodes()) ? rowEl.getFirstChild().getFirstChild().getFirstChild().getChildNodes().getItem(col) : null); } /** * Returns the cell selector depth. * * @return the cell selector depth */ public int getCellSelectorDepth() { return cellSelectorDepth; } /** * Returns the editor parent element. * * @return the editor element */ public Element getEditorParent() { return scroller.dom; } /** * Returns the empty text. * * @return the empty text */ public SafeHtml getEmptyText() { return emptyText; } /** * Returns the grid's column header. * * @return the header */ public ColumnHeader getHeader() { return header; } /** * Returns the <TD> HtmlElement which represents the Grid's header cell for * the specified column index. * * @param index the column index * @return the <TD> element. */ public Element getHeaderCell(int index) { return mainHd.dom.getElementsByTagName("td").getItem(index); } /** * Returns the images used by grid. * * @return the images */ public GridViewImages getImages() { if (images == null) { images = new GridViewImages(); } return images; } /** * Return the <TR> HtmlElement which represents a Grid row for the * specified index. * * @param row the row index * @return the <TR> element */ public Element getRow(int row) { if (row < 0) { return null; } return getRows().getItem(row); } /** * Return the <TR> HtmlElement which represents a Grid row for the * specified model. * * @param m the model * @return the <TR> element */ public Element getRow(ModelData m) { return getRow(ds.indexOf(m)); } /** * Returns the row selector depth. * * @return the row selector depth */ public int getRowSelectorDepth() { return rowSelectorDepth; } /** * Returns the scroll element. * * @return the scroll element */ public El getScroller() { return scroller; } /** * Returns the current scroll state. * * @return the scroll state */ public Point getScrollState() { return new Point(scroller.getScrollLeft(), scroller.getScrollTop()); } /** * Returns the view config. * * @return the view config */ public GridViewConfig getViewConfig() { return viewConfig; } /** * Returns the widget at the current location. * * @param rowIndex the row index * @param colIndex the column index * @return the widget or null */ public Widget getWidget(int rowIndex, int colIndex) { List<Widget> map = rowIndex < widgetList.size() ? widgetList.get(rowIndex) : null; return map != null && colIndex < map.size() ? map.get(colIndex) : null; } /** * Returns true if the grid width will be adjusted based on visibility of * horizontal scroll bar. * * @return true if adjusting */ public boolean isAdjustForHScroll() { return adjustForHScroll; } /** * Returns true if auto fill is enabled. * * @return true for auto fill */ public boolean isAutoFill() { return autoFill; } /** * Returns true if force fit is enabled. * * @return true for force fit */ public boolean isForceFit() { return forceFit; } /** * Returns true if dirty cell markers are enabled. * * @return true of dirty cell markers */ public boolean isShowDirtyCells() { return showDirtyCells; } /** * Returns true if invalid cell markers are enabled. * * @return true if enabled */ public boolean isShowInvalidCells() { return showInvalidCells; } /** * Returns true if sorting is enabled. * * @return true for sorting */ public boolean isSortingEnabled() { return !headerDisabled; } public void layout() { layout(false); } /** * Rebuilds the grid using its current configuration and data. * * @param headerToo true to refresh the header */ public void refresh(boolean headerToo) { if (grid != null && grid.isViewReady()) { stopEditing(); detachWidgets(0, -1, true); if (!preventScrollToTopOnRefresh) { scrollToTop(); } mainBody.setInnerHtml(renderRows(0, -1)); if (headerToo) { sortState = null; header.release(); newColumnHeader(); renderHeader(); if (grid.isAttached()) { ComponentHelper.doAttach(header); } header.setEnableColumnResizing(grid.isColumnResize()); header.setEnableColumnReorder(grid.isColumnReordering()); } processRows(0, true); renderWidgets(0, -1); if (footer != null) { ComponentHelper.doDetach(footer); footer.el().removeFromParent(); } if (cm.getAggregationRows().size() > 0) { footer = new ColumnFooter(grid, cm); renderFooter(); if (grid.isAttached()) { ComponentHelper.doAttach(footer); } } calculateVBar(true); updateHeaderSortState(); applyEmptyText(); constrainFocusElement(); fireEvent(Events.Refresh); } } /** * Scrolls the grid to the top. */ public void scrollToTop() { scroller.setScrollTop(0); scroller.setScrollLeft(0); } /** * True to adjust the grid width when the horizontal scrollbar is hidden and * visible (defaults to true). * * @param adjustForHScroll true to adjust for horizontal scroll bar */ public void setAdjustForHScroll(boolean adjustForHScroll) { this.adjustForHScroll = adjustForHScroll; } /** * True to auto expand the columns to fit the grid <b>when the grid is * created</b>. * * @param autoFill true to expand */ public void setAutoFill(boolean autoFill) { this.autoFill = autoFill; } /** * The number of levels to search for cells in event delegation (defaults to * 4). * * @param cellSelectorDepth the cell selector depth */ public void setCellSelectorDepth(int cellSelectorDepth) { this.cellSelectorDepth = cellSelectorDepth; } /** * Default text to display in the grid body when no rows are available * (defaults to ''). * * @param emptyText the empty text */ public void setEmptyText(SafeHtml emptyText) { this.emptyText = emptyText; } public void setEmptyText(String emptyText) { setEmptyText(SafeGxt.fromNullableString(emptyText)); } /** * True to auto expand/contract the size of the columns to fit the grid width * and prevent horizontal scrolling. * * @param forceFit true to force fit */ public void setForceFit(boolean forceFit) { this.forceFit = forceFit; } /** * The number of levels to search for rows in event delegation (defaults to * 10). * * @param rowSelectorDepth the row selector depth */ public void setRowSelectorDepth(int rowSelectorDepth) { this.rowSelectorDepth = rowSelectorDepth; } /** * True to display a red triangle in the upper left corner of any cells which * are "dirty" as defined by any existing records in the data store (defaults * to true). * * @param showDirtyCells true to display the dirty flag */ public void setShowDirtyCells(boolean showDirtyCells) { this.showDirtyCells = showDirtyCells; } /** * True to enabled invalid cell markers (defaults to false). * * @param showInvalidCells true to enable */ public void setShowInvalidCells(boolean showInvalidCells) { this.showInvalidCells = showInvalidCells; } /** * True to allow column sorting when the user clicks a column (defaults to * true). * * @param sortable true for sortable columns */ public void setSortingEnabled(boolean sortable) { this.headerDisabled = !sortable; } /** * Sets the view config. * * @param viewConfig the view config */ public void setViewConfig(GridViewConfig viewConfig) { this.viewConfig = viewConfig; } protected void addRowStyle(Element elem, String style) { if (elem != null) { fly(elem).addStyleName(style); } } protected void afterRender() { mainBody.setInnerHtml(renderRows(0, -1)); renderWidgets(0, -1); processRows(0, true); if (footer != null && grid.getLazyRowRender() > 0) { footer.refresh(); } int sh = scroller.getHeight(); int dh = mainBody.getHeight(); boolean vbar = dh < sh; if (vbar) { this.vbar = !vbar; lastViewWidth = -1; layout(); } applyEmptyText(); } protected void applyEmptyText() { if (emptyText == null) { emptyText = SafeGxt.NO_BREAK_SPACE; } if (!hasRows()) { mainBody.setInnerHtml(SafeHtmlUtils .fromTrustedString("<div class='x-grid-empty'>" + emptyText.asString() + "</div>")); } syncHScroll(); } protected void autoExpand(boolean preventUpdate) { if (!userResized && grid.getAutoExpandColumn() != null) { int tw = cm.getTotalWidth(false); int aw = grid.getWidth(true) - getScrollAdjust(); if (tw != aw) { int ci = cm.getIndexById(grid.getAutoExpandColumn()); assert ci != Style.DEFAULT : "auto expand column not found"; if (cm.isHidden(ci)) { return; } int currentWidth = cm.getColumnWidth(ci); int cw = Math.min(Math.max(((aw - tw) + currentWidth), grid.getAutoExpandMin()), grid.getAutoExpandMax()); if (cw != currentWidth) { cm.setColumnWidth(ci, cw, true); if (!preventUpdate) { updateColumnWidth(ci, cw); } } } } } protected void calculateVBar(boolean force) { if (force) { resize(); } int sh = scroller.getHeight(); int dh = mainBody.getHeight(); boolean vbar = dh > sh; if (force || this.vbar != vbar) { this.vbar = vbar; lastViewWidth = -1; layout(true); } } @SuppressWarnings({ "rawtypes", "unchecked" }) protected GridEvent<?> createComponentEvent(Event event) { return new GridEvent(grid, event); } protected Menu createContextMenu(final int colIndex) { final Menu menu = new Menu(); if (cm.isSortable(colIndex)) { MenuItem item = new MenuItem(); item.setHtml(GXT.MESSAGES.gridView_sortAscText()); item.setIcon(getImages().getSortAsc()); item.addSelectionListener(new SelectionListener<MenuEvent>() { public void componentSelected(MenuEvent ce) { doSort(colIndex, SortDir.ASC); } }); menu.add(item); item = new MenuItem(); item.setHtml(GXT.MESSAGES.gridView_sortDescText()); item.setIcon(getImages().getSortDesc()); item.addSelectionListener(new SelectionListener<MenuEvent>() { public void componentSelected(MenuEvent ce) { doSort(colIndex, SortDir.DESC); } }); menu.add(item); } MenuItem columns = new MenuItem(); columns.setHtml(GXT.MESSAGES.gridView_columnsText()); columns.setIcon(getImages().getColumns()); columns.setData("gxt-columns", "true"); final Menu columnMenu = new Menu(); int cols = cm.getColumnCount(); for (int i = 0; i < cols; i++) { if (shouldNotCount(i, false)) { continue; } final int fcol = i; final CheckMenuItem check = new CheckMenuItem(); check.setHideOnClick(false); check.setHtml(cm.getColumnHeader(i)); check.setChecked(!cm.isHidden(i)); check.addSelectionListener(new SelectionListener<MenuEvent>() { public void componentSelected(MenuEvent ce) { cm.setHidden(fcol, !cm.isHidden(fcol)); restrictMenu(columnMenu); } }); columnMenu.add(check); } restrictMenu(columnMenu); columns.setEnabled(columnMenu.getItemCount() > 0); columns.setSubMenu(columnMenu); menu.add(columns); return menu; } protected void detachWidget(int rowIndex, boolean remove) { List<Widget> m = rowIndex < widgetList.size() ? widgetList.get(rowIndex) : null; if (m != null) { for (Widget w : m) { ComponentHelper.doDetach(w); if (w != null) { El.fly(w.getElement()).removeFromParent(); } } if (remove) { widgetList.remove(rowIndex); } } } protected void detachWidgets(int startRow, int endRow, boolean remove) { if (endRow == -1) { endRow = widgetList.size() - 1; } for (int i = endRow; i >= startRow; i--) { detachWidget(i, remove); } } protected void doAttach() { ComponentHelper.doAttach(header); ComponentHelper.doAttach(footer); resize(); renderWidgets(0, -1); } protected void doDetach() { ComponentHelper.doDetach(header); ComponentHelper.doDetach(footer); detachWidgets(0, -1, false); } protected String doRender(List<ColumnData> cs, List<ModelData> rows, int startRow, int colCount, boolean stripe) { int last = colCount - 1; String tstyle = "width:" + getTotalWidth() + "px;"; StringBuilder buf = new StringBuilder(); for (int j = 0; j < rows.size(); j++) { ModelData model = (ModelData) rows.get(j); model = prepareData(model); Record r = ds.hasRecord(model) ? ds.getRecord(model) : null; int rowBodyColSpanCount = colCount; if (enableRowBody) { if (grid.getSelectionModel() instanceof CheckBoxSelectionModel<?>) { CheckBoxSelectionModel<?> sm = (CheckBoxSelectionModel<?>) grid.getSelectionModel(); if (cm.getColumnById(sm.getColumn().getId()) != null) { rowBodyColSpanCount--; } } for (ColumnConfig c : cm.getColumns()) { if (c instanceof RowNumberer) { rowBodyColSpanCount--; } } } int rowIndex = (j + startRow); if (GXT.isAriaEnabled()) { buf.append("<div role=\"row\" aria-level=\"2\" class=\"x-grid3-row "); } else { buf.append("<div class=\"x-grid3-row "); } if (stripe && ((rowIndex + 1) % 2 == 0)) { buf.append(" x-grid3-row-alt"); } if (!selectable) { buf.append(" x-unselectable-single"); } if (showDirtyCells && r != null && r.isDirty()) { buf.append(" x-grid3-dirty-row"); } if (viewConfig != null) { buf.append(" "); buf.append(viewConfig.getRowStyle(model, rowIndex, ds)); } buf.append("\" style=\""); buf.append(tstyle); buf.append("\" id=\""); buf.append(grid.getId()); buf.append("_"); buf.append(ds.getKeyProvider() != null ? ds.getKeyProvider().getKey(model) : XDOM.getUniqueId()); buf.append("\" unselectable=\""); buf.append(selectable ? "off" : "on"); buf.append( "\"><table class=x-grid3-row-table role=presentation border=0 cellspacing=0 cellpadding=0 style=\""); buf.append(tstyle); buf.append("\"><tbody role=presentation><tr role=presentation>"); widgetList.add(rowIndex, new ArrayList<Widget>()); for (int i = 0; i < colCount; i++) { ColumnData c = cs.get(i); c.css = c.css == null ? "" : c.css; SafeHtml rv = getRenderedValue(c, rowIndex, i, model, c.name); String role = "gridcell"; if (GXT.isAriaEnabled()) { ColumnConfig cc = cm.getColumn(i); if (cc.isRowHeader()) { role = "rowheader"; } } String attr = c.cellAttr != null ? c.cellAttr : ""; String cellAttr = c.cellAttr != null ? c.cellAttr : ""; buf.append("<td id=\"" + XDOM.getUniqueId() + "\" role=\"" + role + "\" class=\"x-grid3-col x-grid3-cell x-grid3-td-"); buf.append(c.id); buf.append(" "); buf.append(i == 0 ? "x-grid-cell-first " : (i == last ? "x-grid3-cell-last " : "")); if (c.css != null) { buf.append(c.css); } if (showInvalidCells && r != null && !r.isValid(c.name)) { buf.append(" x-grid3-invalid-cell"); } if (showDirtyCells && r != null && r.getChanges().containsKey(c.name)) { buf.append(" x-grid3-dirty-cell"); } buf.append("\" style=\""); buf.append(c.style); buf.append("\" "); buf.append(cellAttr); buf.append("><div unselectable=\""); buf.append(selectable ? "off" : "on"); buf.append("\" class=\"x-grid3-cell-inner x-grid3-col-"); buf.append(c.id); buf.append("\" "); buf.append(attr); buf.append(">"); buf.append(rv.asString()); buf.append("</div></td>"); } buf.append("</tr>"); if (enableRowBody) { buf.append("<tr class=x-grid3-row-body-tr style=\"\"><td colspan="); buf.append(rowBodyColSpanCount); buf.append(" class=x-grid3-body-cell><div class=x-grid3-row-body>${body}</div></td></tr>"); } buf.append("</tbody></table></div>"); } return buf.toString(); } protected void doSort(int colIndex, SortDir sortDir) { ds.sort(cm.getDataIndex(colIndex), sortDir); } protected void fitColumns(boolean preventRefresh, boolean onlyExpand, int omitColumn) { int tw = cm.getTotalWidth(false); int aw = grid.el().getWidth(true) - getScrollAdjust(); if (aw <= 0) { aw = grid.el().getStyleWidth(); } if (aw < 20 || aw > 2000) { // not initialized, so don't screw up the // default widths return; } int extra = (int) aw - tw; if (extra == 0) { return; } int colCount = cm.getColumnCount(); Stack<Integer> cols = new Stack<Integer>(); int width = 0; int w; for (int i = 0; i < colCount; i++) { w = cm.getColumnWidth(i); if (!cm.isHidden(i) && !cm.isFixed(i) && i != omitColumn) { cols.push(i); cols.push(w); width += w; } } double frac = ((double) (extra)) / width; while (cols.size() > 0) { w = cols.pop(); int i = cols.pop(); int ww = Math.max(grid.getMinColumnWidth(), (int) Math.floor(w + w * frac)); cm.setColumnWidth(i, ww, true); } tw = getTotalWidth(); if (tw > aw) { width = 0; for (int i = 0; i < colCount; i++) { w = cm.getColumnWidth(i); if (!cm.isHidden(i) && !cm.isFixed(i) && w > grid.getMinColumnWidth()) { cols.push(i); cols.push(w); width += w; } } frac = ((double) (aw - tw)) / width; while (cols.size() > 0) { w = cols.pop(); int i = cols.pop(); int ww = Math.max(grid.getMinColumnWidth(), (int) Math.floor(w + w * frac)); cm.setColumnWidth(i, ww, true); } } if (!preventRefresh) { updateAllColumnWidths(); } } protected El fly(Element elem) { return El.fly(elem, "grid"); } protected void focusGrid() { focusEl.setFocus(true); } protected int getCellIndex(Element elem) { if (elem != null) { String id = getCellIndexId(elem); if (id != null) { return cm.getIndexById(id); } } return -1; } protected List<ColumnData> getColumnData() { int colCount = cm.getColumnCount(); List<ColumnData> cs = new ArrayList<ColumnData>(); for (int i = 0; i < colCount; i++) { String name = cm.getDataIndex(i); ColumnData data = new ColumnData(); data.name = name == null ? cm.getColumnId(i) : name; data.renderer = cm.getRenderer(i); data.id = cm.getColumnId(i); data.style = getColumnStyle(i, false); cs.add(data); } return cs; } protected String getColumnStyle(int colIndex, boolean isHeader) { String style = !isHeader ? cm.getColumnStyle(colIndex) : ""; if (style == null) style = ""; style += "width:" + (getColumnWidth(colIndex)) + "px;"; if (cm.isHidden(colIndex)) { style += "display:none;"; } HorizontalAlignment align = cm.getColumnAlignment(colIndex); if (align != null) { style += "text-align:" + align.name() + ";"; } return style; } protected int getColumnWidth(int col) { int w = cm.getColumnWidth(col); return (El.isBorderBoxTableFixed() ? w : (w - borderWidth > 0 ? w - borderWidth : 0)); } protected int getOffsetWidth() { return (getTotalWidth() + getScrollAdjust()); } protected SafeHtml getRenderedValue(ColumnData data, int rowIndex, int colIndex, ModelData m, String property) { GridCellRenderer<ModelData> r = cm.getRenderer(colIndex); List<Widget> rowMap = widgetList.get(rowIndex); rowMap.add(colIndex, null); if (r != null) { SafeHtml o = r.render(ds.getAt(rowIndex), property, data, rowIndex, colIndex, ds, grid); if (o != null) { return o; } } Object val = m.get(property); SafeHtml html = null; ColumnConfig c = cm.getColumn(colIndex); if (val != null) { if (val instanceof Number && c.getNumberFormat() != null) { Number n = (Number) val; html = SafeHtmlUtils.fromTrustedString(c.getNumberFormat().format(n.doubleValue())); } else if (val instanceof Date && c.getDateTimeFormat() != null) { DateTimeFormat dtf = c.getDateTimeFormat(); html = SafeHtmlUtils.fromTrustedString(dtf.format((Date) val)); } else { String valString = val.toString(); if (valString != null) { html = SafeHtmlUtils.fromString(valString); } } } return SafeGxt.emptyToNbSpace(html); } protected NodeList<Element> getRows() { if (!hasRows()) { return new JsArray().getJsObject().cast(); } return mainBody.dom.getChildNodes().cast(); } protected int getScrollAdjust() { return adjustForHScroll ? (scroller != null ? (vbar ? scrollOffset : 2) : scrollOffset) : scrollOffset; } protected SortInfo getSortState() { return ds.getSortState(); } protected int getTotalWidth() { return cm.getTotalWidth(); } protected Element getWidgetCell(int row, int cell) { Element cellEl = getCell(row, cell); if (cellEl != null) { return cellEl.getFirstChildElement(); } return null; } @SuppressWarnings({ "unchecked", "rawtypes" }) protected void handleComponentEvent(GridEvent ge) { switch (ge.getEventTypeInt()) { case Event.ONMOUSEMOVE: Element row = getRow(ge.getRowIndex()); if (overRow != null && row == null) { onRowOut(overRow); } else if (row != null && overRow != row) { if (overRow != null) { onRowOut(overRow); } onRowOver(row); } break; case Event.ONMOUSEOVER: EventTarget from = ge.getEvent().getRelatedEventTarget(); if (from == null || (Element.is(from) && !DOM.isOrHasChild(grid.getElement(), (com.google.gwt.user.client.Element) Element.as(from)))) { Element r = getRow(ge.getRowIndex()); if (r != null) { onRowOver(r); } } break; case Event.ONMOUSEOUT: EventTarget to = ge.getEvent().getRelatedEventTarget(); if (to == null || (Element.is(to) && !DOM.isOrHasChild(grid.getElement(), (com.google.gwt.user.client.Element) Element.as(to)))) { if (overRow != null) { onRowOut(overRow); } } break; case Event.ONMOUSEDOWN: onMouseDown(ge); break; case Event.ONSCROLL: if (scroller.isOrHasChild(ge.getTarget())) { syncScroll(); } break; } } protected boolean hasRows() { if (mainBody == null) { return false; } Element e = mainBody.dom.getFirstChildElement(); return e != null && !"x-grid-empty".equals(e.getClassName()); } /** * Initializes the view. * * @param grid the grid */ @SuppressWarnings({ "unchecked", "rawtypes" }) protected void init(final Grid grid) { this.grid = grid; this.cm = grid.getColumnModel(); selectable = !grid.isDisableTextSelection(); initListeners(); initTemplates(); initData(grid.getStore(), cm); initUI(grid); newColumnHeader(); if (cm.getAggregationRows().size() > 0) { footer = new ColumnFooter(grid, cm); } } /** * Initializes the data. * * @param ds the data store * @param cm the column model */ @SuppressWarnings({ "unchecked", "rawtypes" }) protected void initData(ListStore ds, ColumnModel cm) { if (this.ds != null) { this.ds.removeStoreListener(listener); } if (ds != null) { ds.addStoreListener(listener); } this.ds = ds; if (this.cm != null) { this.cm.removeListener(Events.HiddenChange, columnListener); this.cm.removeListener(Events.HeaderChange, columnListener); this.cm.removeListener(Events.WidthChange, columnListener); this.cm.removeListener(Events.ColumnMove, columnListener); } if (cm != null) { cm.addListener(Events.HiddenChange, columnListener); cm.addListener(Events.HeaderChange, columnListener); cm.addListener(Events.WidthChange, columnListener); cm.addListener(Events.ColumnMove, columnListener); } this.cm = cm; } protected void initElements() { NodeList<Node> cs = grid.getElement().getFirstChild().getChildNodes(); el = grid.el().firstChild(); mainWrap = new El((com.google.gwt.user.client.Element) cs.getItem(0)); mainHd = mainWrap.firstChild(); if (grid.isHideHeaders()) { mainHd.setVisible(false); } innerHd = mainHd.firstChild(); scroller = mainWrap.getChild(1); scroller.addEventsSunk(Event.ONSCROLL); if (forceFit) { scroller.setStyleAttribute("overflowX", "hidden"); } mainBody = scroller.firstChild(); focusEl = scroller.getChild(1); grid.swallowEvent(Events.OnClick, focusEl.dom, true); } protected void initListeners() { listener = new StoreListener<ModelData>() { @Override public void storeAdd(StoreEvent<ModelData> se) { onAdd(ds, se.getModels(), se.getIndex()); } @Override public void storeBeforeDataChanged(StoreEvent<ModelData> se) { onBeforeDataChanged(se); } @Override public void storeClear(StoreEvent<ModelData> se) { onClear(se); } @Override public void storeDataChanged(StoreEvent<ModelData> se) { onDataChanged(se); } @Override public void storeFilter(StoreEvent<ModelData> se) { onDataChanged(se); } @Override public void storeRemove(StoreEvent<ModelData> se) { onRemove(ds, se.getModel(), se.getIndex(), false); } @Override public void storeUpdate(StoreEvent<ModelData> se) { onUpdate(ds, se.getModel()); } }; columnListener = new Listener<ColumnModelEvent>() { public void handleEvent(ColumnModelEvent e) { if (grid.isViewReady()) { EventType type = e.getType(); if (type == Events.HiddenChange) { onHiddenChange(cm, e.getColIndex(), e.isHidden()); } else if (type == Events.HeaderChange) { onHeaderChange(e.getColIndex(), e.getHeader()); } else if (type == Events.WidthChange) { onColumnWidthChange(e.getColIndex(), e.getWidth()); } else if (type == Events.ColumnMove) { onColumnMove(e.getColIndex()); } } } }; } protected void initTemplates() { templates = GWT.create(GridTemplates.class); } protected void initUI(final Grid<ModelData> grid) { } protected void insertRows(ListStore<ModelData> store, int firstRow, int lastRow, boolean isUpdate) { Element e = mainBody.dom.getFirstChildElement(); if (e != null && !hasRows()) { mainBody.dom.setInnerHTML(""); } SafeHtml html = renderRows(firstRow, lastRow); Element before = getRow(firstRow); if (before != null) { DomHelper.insertBefore((com.google.gwt.user.client.Element) before, html.asString()); } else { DomHelper.insertHtml("beforeEnd", mainBody.dom, html.asString()); } if (!isUpdate) { processRows(firstRow, false); } } protected void layout(boolean skipResize) { if (mainBody == null) { return; } El c = grid.el(); Size csize = c.getStyleSize(); int vw = csize.width; int vh = 0; if (vw < 10 || csize.height < 20) { return; } if (!skipResize) { resize(); } if (forceFit || autoFill) { if (lastViewWidth != vw) { fitColumns(false, false, -1); header.updateTotalWidth(getOffsetWidth(), getTotalWidth()); if (footer != null) { footer.updateTotalWidth(getOffsetWidth(), getTotalWidth()); } lastViewWidth = vw; } } else { autoExpand(false); header.updateTotalWidth(getOffsetWidth(), getTotalWidth()); if (footer != null) { footer.updateTotalWidth(getOffsetWidth(), getTotalWidth()); } syncHeaderScroll(); } templateOnLayout(vw, vh); } protected ColumnHeader newColumnHeader() { header = new ColumnHeader(grid, cm) { @SuppressWarnings("unchecked") @Override protected ComponentEvent createColumnEvent(ColumnHeader header, int column, Menu menu) { GridEvent<ModelData> event = (GridEvent<ModelData>) GridView.this.createComponentEvent(null); event.setColIndex(column); event.setMenu(menu); return event; } @Override protected Menu getContextMenu(int column) { return createContextMenu(column); } @Override protected void onColumnSplitterMoved(int colIndex, int width) { super.onColumnSplitterMoved(colIndex, width); GridView.this.onColumnSplitterMoved(colIndex, width); } @Override protected void onHeaderClick(ComponentEvent ce, int column) { super.onHeaderClick(ce, column); GridView.this.onHeaderClick(grid, column); } @Override protected void onKeyDown(ComponentEvent ce, int index) { ce.cancelBubble(); if (grid.getSelectionModel() instanceof CellSelectionModel<?>) { CellSelectionModel<?> csm = (CellSelectionModel<?>) grid.getSelectionModel(); csm.selectCell(0, index); } else { grid.getSelectionModel().select(0, false); } } }; header.setSplitterWidth(splitterWidth); header.setMinColumnWidth(grid.getMinColumnWidth()); return header; } protected void notifyHide() { } protected void notifyShow() { } protected void onAdd(ListStore<ModelData> store, List<ModelData> models, int index) { if (grid != null && grid.isViewReady()) { insertRows(store, index, index + (models.size() - 1), false); renderWidgets(index, index + (models.size() - 1)); addTask.delay(10); } } protected void onBeforeDataChanged(StoreEvent<ModelData> se) { if (grid != null && grid.isLoadMask()) { grid.mask(GXT.MESSAGES.loadMask_msg()); } } protected void onCellDeselect(int row, int col) { Element cell = getCell(row, col); if (cell != null) { fly(cell).removeStyleName("x-grid3-cell-selected"); if (GXT.isAriaEnabled()) { cell.setAttribute("aria-selected", "false"); } } } protected void onCellSelect(int row, int col) { Element cell = getCell(row, col); if (cell != null) { fly(cell).addStyleName("x-grid3-cell-selected"); if (GXT.isAriaEnabled()) { cell.setAttribute("aria-selected", "true"); grid.setAriaState("aria-activedescendant", cell.getId()); } } } protected void onClear(StoreEvent<ModelData> se) { refresh(false); } protected void onClick(GridEvent<ModelData> ce) { Element row = findRow(ce.getTarget()); if (row != null) { ce.setRowIndex(findRowIndex(row)); grid.fireEvent(Events.RowClick, ce); } } protected void onColumnMove(int newIndex) { boolean pScroll = preventScrollToTopOnRefresh; preventScrollToTopOnRefresh = true; refresh(true); preventScrollToTopOnRefresh = pScroll; templateAfterMove(newIndex); } @SuppressWarnings("unchecked") protected void onColumnSplitterMoved(int colIndex, int width) { stopEditing(); userResized = true; width = Math.max(grid.getMinColumnWidth(), width); cm.setColumnWidth(colIndex, width); GridEvent<ModelData> e = (GridEvent<ModelData>) createComponentEvent(null); e.setColIndex(colIndex); e.setWidth(width); grid.fireEvent(Events.ColumnResize, e); } protected void onColumnWidthChange(int column, int width) { if (forceFit) { fitColumns(false, false, column); header.updateTotalWidth(getOffsetWidth(), getTotalWidth()); } else { updateColumnWidth(column, width); header.updateTotalWidth(getOffsetWidth(), getTotalWidth()); if (GXT.isIE) { syncHeaderScroll(); } } if (grid.isStateful()) { Map<String, Object> state = grid.getState(); state.put("width" + cm.getColumnId(column), width); grid.saveState(); } } protected void onDataChanged(StoreEvent<ModelData> se) { refresh(false); if (grid != null && grid.isLoadMask()) { if (grid.isEnabled()) { grid.unmask(); } else { grid.mask(); } } if (grid != null && grid.isStateful() && ds != null && ds.getLoadConfig() != null && ds.getLoadConfig() instanceof PagingLoadConfig) { PagingLoadConfig config = (PagingLoadConfig) ds.getLoadConfig(); Map<String, Object> state = grid.getState(); state.put("offset", config.getOffset()); state.put("limit", config.getLimit()); grid.saveState(); } } protected void onHeaderChange(int column, SafeHtml text) { header.setHeaderHtml(column, text); } protected void onHeaderClick(Grid<ModelData> grid, int column) { this.headerColumnIndex = column; if (!headerDisabled && cm.isSortable(column)) { doSort(column, null); } } protected void onHiddenChange(ColumnModel cm, int col, boolean hidden) { updateColumnHidden(col, hidden); if (grid.isStateful()) { Map<String, Object> state = grid.getState(); state.put("hidden" + cm.getColumnId(col), hidden); grid.saveState(); } } protected void onHighlightRow(int rowIndex, boolean highlight) { Element row = getRow(rowIndex); if (row != null) { if (highlight) { addRowStyle(row, "x-grid3-highlightrow"); if (GXT.isAriaEnabled()) { grid.setAriaState("aria-activedescendant", row.getId()); } } else { removeRowStyle(row, "x-grid3-highlightrow"); } } } protected void onMouseDown(GridEvent<ModelData> ge) { } protected void onRemove(ListStore<ModelData> ds, ModelData m, int index, boolean isUpdate) { if (grid != null && grid.isViewReady()) { detachWidget(index, true); removeRow(index); if (!isUpdate) { removeTask.delay(10); } else { removeTask.delay(0); } constrainFocusElement(); } } protected void onRowDeselect(int rowIndex) { Element row = getRow(rowIndex); if (row != null) { removeRowStyle(row, "x-grid3-row-selected"); removeRowStyle(row, "x-grid3-highlightrow"); if (GXT.isAriaEnabled()) { row.setAttribute("aria-selected", "false"); } } } protected void onRowOut(Element row) { if (grid.isTrackMouseOver()) { removeRowStyle(row, "x-grid3-row-over"); overRow = null; } } protected void onRowOver(Element row) { if (grid.isTrackMouseOver()) { addRowStyle(row, "x-grid3-row-over"); overRow = row; } } protected void onRowSelect(int rowIndex) { Element row = getRow(rowIndex); if (row != null) { onRowOut(row); addRowStyle(row, "x-grid3-row-selected"); if (GXT.isAriaEnabled()) { row.setAttribute("aria-selected", "true"); grid.getElement().setAttribute("aria-activedescendant", row.getId()); } } } protected void onUpdate(ListStore<ModelData> store, ModelData model) { refreshRow(store.indexOf(model)); } protected ModelData prepareData(ModelData model) { if (grid.getModelProcessor() != null) { boolean silent = false; if (model instanceof BaseModel) { silent = ((BaseModel) model).isSilent(); ((BaseModel) model).setSilent(true); } ModelData m = grid.getModelProcessor().prepareData(model); if (model instanceof BaseModel) { ((BaseModel) model).setSilent(silent); } return m; } return model; } protected void processRows(int startRow, boolean skipStripe) { if (ds.getCount() < 1) { return; } skipStripe = skipStripe || !grid.isStripeRows(); NodeList<Element> rows = getRows(); String cls = "x-grid3-row-alt"; for (int i = 0, len = rows.getLength(); i < len; i++) { Element row = rows.getItem(i); row.setPropertyInt("rowIndex", i); if (!skipStripe) { boolean isAlt = (i + 1) % 2 == 0; boolean hasAlt = row.getClassName() != null && row.getClassName().indexOf(cls) != -1; if (isAlt == hasAlt) { continue; } if (isAlt) { El.fly(row).addStyleName(cls); } else { El.fly(row).removeStyleName(cls); } } } } @SuppressWarnings("unchecked") protected void refreshRow(int row) { if (grid != null && grid.isViewReady()) { ModelData m = ds.getAt(row); if (m != null) { // do not change focus on refresh // handles situation with changing cell value with field binding focusEnabled = false; insertRows(ds, row, row, true); getRow(row).setPropertyInt("rowIndex", row); onRemove(ds, m, row + 1, true); renderWidgets(row, row); GridEvent<ModelData> e = (GridEvent<ModelData>) createComponentEvent(null); e.setRowIndex(row); e.setModel(ds.getAt(row)); fireEvent(Events.RowUpdated, e); focusEnabled = true; } } } protected void removeRow(int row) { Element r = getRow(row); if (r != null) { fly(r).removeFromParent(); } } protected void removeRowStyle(Element row, String style) { fly(row).removeStyleName(style); } protected void render() { renderUI(); grid.sinkEvents(Event.ONCLICK | Event.ONDBLCLICK | Event.MOUSEEVENTS | Event.FOCUSEVENTS); } protected void renderFooter() { if (!footer.isRendered()) { footer.disableTextSelection(true); footer.render(mainWrap.dom); } else { mainWrap.appendChild(footer.getElement()); } } protected void renderHeader() { El head = grid.el().selectNode(".x-grid3-hh"); head.removeChildren(); if (!header.isRendered()) { header.render(head.dom); } else { head.appendChild(header.getElement()); } } protected SafeHtml renderRows(int startRow, int endRow) { int colCount = cm.getColumnCount(); if (ds.getCount() < 1) { return SafeHtmlUtils.EMPTY_SAFE_HTML; } List<ColumnData> cs = getColumnData(); if (endRow == -1) { endRow = ds.getCount() - 1; } List<ModelData> rs = ds.getRange(startRow, endRow); return SafeHtmlUtils.fromTrustedString(doRender(cs, rs, startRow, colCount, grid.isStripeRows())); } protected void renderUI() { String h = "<div class='x-grid3-hh' role='row'></div>"; String body = templates.body(""); String html = templates.master(body, h); grid.getElement().setInnerHTML(html); renderHeader(); initElements(); header.setEnableColumnResizing(grid.isColumnResize()); header.setEnableColumnReorder(grid.isColumnReordering()); if (footer != null) { renderFooter(); } updateHeaderSortState(); } protected void renderWidgets(int startRow, int endRow) { if (grid.isViewReady()) { if (endRow == -1) { endRow = widgetList.size() - 1; } for (int i = startRow; i <= endRow; i++) { List<Widget> m = i < widgetList.size() ? widgetList.get(i) : null; if (m != null) { for (int j = 0; j < grid.getColumnModel().getColumnCount(); j++) { Widget w = j < m.size() ? m.get(j) : null; if (w != null) { Element cell = getWidgetCell(i, j); if (cell != null) { if (w.getElement().getParentElement() != cell) { fly(cell).removeChildren(); cell.appendChild(w.getElement()); } if (grid.isAttached()) { ComponentHelper.doAttach(w); } } } } } } } } protected void resize() { if (mainBody == null) { return; } El c = grid.el(); Size csize = c.getStyleSize(); int vw = csize.width; int vh = 0; if (vw < 10 || csize.height < 20) { return; } if (grid.isAutoHeight()) { el.setWidth(csize.width); scroller.setWidth(vw); } else { el.setSize(csize.width, csize.height); } int hdHeight = innerHd.getHeight(); vh = csize.height - hdHeight; if (footer != null) { vh -= footer.getHeight(); } if (!grid.isAutoHeight()) { scroller.setSize(vw, vh); } if (innerHd != null) { innerHd.setWidth(vw); } if (footer != null) { footer.setWidth(vw); } } protected void restoreScroll(Point state) { if (state.y < scroller.getWidth()) { scroller.setScrollLeft(state.x); } if (state.x < scroller.getHeight()) { scroller.setScrollTop(state.y); } } protected void stopEditing() { if (grid.editSupport != null) { grid.editSupport.stopEditing(true); } } protected void syncHeaderScroll() { int sl = scroller.getScrollLeft(); innerHd.setScrollLeft(sl); // second time for IE (1/2 time first fails, other browsers ignore) innerHd.setScrollLeft(sl); if (footer != null) { footer.el().setScrollLeft(sl); footer.el().setScrollLeft(sl); } } protected void syncHScroll() { if (!hasRows()) { El child = mainBody.firstChild(); if (child != null) { child.setWidth(cm.getTotalWidth(), true); } } } @SuppressWarnings("unchecked") protected void syncScroll() { syncHeaderScroll(); int scrollLeft = scroller.getScrollLeft(); int scrollTop = scroller.getScrollTop(); GridEvent<ModelData> ge = (GridEvent<ModelData>) createComponentEvent(null); ge.setScrollLeft(scrollLeft); ge.setScrollTop(scrollTop); constrainFocusElement(); grid.fireEvent(Events.BodyScroll, ge); } protected void templateAfterMove(int index) { // template method } protected void templateOnAllColumnWidthsUpdated(List<Integer> ws, int tw) { // template method } protected void templateOnColumnHiddenUpdated(int col, boolean hidden, int tw) { // template method } protected void templateOnColumnWidthUpdated(int col, int w, int tw) { // template method } protected void templateOnLayout(int vw, int vh) { // template method } protected void templateUpdateColumnText(int col, String text) { // template method } protected void updateAllColumnWidths() { int tw = getTotalWidth(); int clen = cm.getColumnCount(); Stack<Integer> ws = new Stack<Integer>(); header.updateAllColumnWidths(); for (int i = 0; i < clen; i++) { ws.push(getColumnWidth(i)); if (footer != null) { footer.updateColumnWidth(i, cm.getColumnWidth(i)); } } NodeList<Element> ns = getRows(); for (int i = 0, len = ns.getLength(); i < len; i++) { Element row = ns.getItem(i); row.getStyle().setPropertyPx("width", tw); if (row.getFirstChild() != null) { row.getFirstChildElement().getStyle().setPropertyPx("width", tw); TableSectionElement e = row.getFirstChild().cast(); TableRowElement nodeList = e.getRows().getItem(0); for (int j = 0; j < clen; j++) { ((Element) nodeList.getChildNodes().getItem(j)).getStyle().setPropertyPx("width", ws.get(j)); } } } templateOnAllColumnWidthsUpdated(ws, tw); syncHScroll(); } protected void updateColumnHidden(int index, boolean hidden) { int tw = getTotalWidth(); String display = hidden ? "none" : ""; El.fly(innerHd.dom.getFirstChildElement()).setWidth(getOffsetWidth()); El.fly(innerHd.dom.getFirstChildElement().getFirstChildElement()).setWidth(tw); header.updateColumnHidden(index, hidden); if (footer != null) { footer.updateTotalWidth(getOffsetWidth(), tw); footer.updateColumnHidden(index, hidden); } NodeList<Element> ns = getRows(); for (int i = 0, len = ns.getLength(); i < len; i++) { Element elem = ns.getItem(i); elem.getStyle().setProperty("width", tw + "px"); TableSectionElement e = (TableSectionElement) elem.getFirstChild(); if (e != null) { e.getStyle().setProperty("width", tw + "px"); Element cell = e.getRows().getItem(0).getChildNodes().getItem(index).cast(); cell.getStyle().setProperty("display", display); } } templateOnColumnHiddenUpdated(index, hidden, tw); lastViewWidth = -1; layout(); syncHScroll(); } protected void updateColumnWidth(int col, int width) { int tw = getTotalWidth(); int w = getColumnWidth(col); header.updateTotalWidth(-1, tw); header.updateColumnWidth(col, width); if (footer != null) { footer.updateTotalWidth(getOffsetWidth(), tw); footer.updateColumnWidth(col, width); } NodeList<Element> ns = getRows(); for (int i = 0, len = ns.getLength(); i < len; i++) { Element row = ns.getItem(i); row.getStyle().setPropertyPx("width", tw); if (row.getFirstChild() != null) { row.getFirstChildElement().getStyle().setPropertyPx("width", tw); TableSectionElement e = row.getFirstChild().cast(); ((Element) e.getRows().getItem(0).getChildNodes().getItem(col)).getStyle().setPropertyPx("width", w); } } templateOnColumnWidthUpdated(col, w, tw); syncHScroll(); } @SuppressWarnings("unchecked") protected void updateHeaderSortState() { SortInfo state = getSortState(); if (state == null || Util.isEmptyString(state.getSortField())) { return; } if (sortState == null || (!sortState.getSortField().equals(state.getSortField())) || sortState.getSortDir() != state.getSortDir()) { GridEvent<ModelData> e = (GridEvent<ModelData>) createComponentEvent(null); e.setSortInfo(state); sortState = new SortInfo(state.getSortField(), state.getSortDir()); int sortColumn = cm.findColumnIndex(state.getSortField()); if (sortColumn != -1) { updateSortIcon(sortColumn, sortState.getSortDir()); } if (grid.isStateful()) { Map<String, Object> st = grid.getState(); st.put("sortField", sortState.getSortField()); st.put("sortDir", sortState.getSortDir().toString()); grid.saveState(); } grid.fireEvent(Events.SortChange, e); } } protected void updateSortIcon(int colIndex, SortDir dir) { header.updateSortIcon(colIndex, dir); } private native String getCellIndexId(Element elem) /*-{ if (!@com.extjs.gxt.ui.client.widget.grid.GridView::colRe) { @com.extjs.gxt.ui.client.widget.grid.GridView::colRe = new RegExp( "x-grid3-td-([^\\s]+)"); } if (elem) { var m = elem.className .match(@com.extjs.gxt.ui.client.widget.grid.GridView::colRe); if (m && m[1]) { return m[1]; } } return null; }-*/; private void refreshFooterData() { if (footer != null) { footer.refresh(); } } private void restrictMenu(Menu columns) { int count = 0; for (int i = 0, len = cm.getColumnCount(); i < len; i++) { if (!shouldNotCount(i, true)) { count++; } } if (count == 1) { for (Component item : columns.getItems()) { CheckMenuItem ci = (CheckMenuItem) item; if (ci.isChecked()) { ci.disable(); } } } else { for (Component item : columns.getItems()) { item.enable(); } } } private boolean shouldNotCount(int columnIndex, boolean includeHidden) { return cm.getColumnHeader(columnIndex) == null || cm.getColumnHeader(columnIndex).equals("") || (includeHidden && cm.isHidden(columnIndex)) || cm.isFixed(columnIndex); } private void constrainFocusElement() { int scrollLeft = scroller.dom.getScrollLeft(); int scrollTop = scroller.dom.getScrollTop(); int left = scroller.getWidth(true) / 2 + scrollLeft; int top = scroller.getHeight(true) / 2 + scrollTop; focusEl.setLeftTop(left, top); } }