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 java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.extjs.gxt.ui.client.GXT; import com.extjs.gxt.ui.client.Style.HorizontalAlignment; import com.extjs.gxt.ui.client.Style.SortDir; import com.extjs.gxt.ui.client.aria.FocusFrame; import com.extjs.gxt.ui.client.core.DomHelper; import com.extjs.gxt.ui.client.core.DomQuery; import com.extjs.gxt.ui.client.core.El; import com.extjs.gxt.ui.client.core.XDOM; import com.extjs.gxt.ui.client.data.SortInfo; import com.extjs.gxt.ui.client.dnd.StatusProxy; import com.extjs.gxt.ui.client.event.BaseEvent; import com.extjs.gxt.ui.client.event.ColumnHeaderEvent; import com.extjs.gxt.ui.client.event.ComponentEvent; import com.extjs.gxt.ui.client.event.DragEvent; import com.extjs.gxt.ui.client.event.DragListener; import com.extjs.gxt.ui.client.event.Events; import com.extjs.gxt.ui.client.event.Listener; import com.extjs.gxt.ui.client.fx.Draggable; import com.extjs.gxt.ui.client.util.Region; import com.extjs.gxt.ui.client.util.SafeGxt; import com.extjs.gxt.ui.client.widget.BoxComponent; import com.extjs.gxt.ui.client.widget.ComponentHelper; import com.extjs.gxt.ui.client.widget.ComponentManager; import com.extjs.gxt.ui.client.widget.Html; import com.extjs.gxt.ui.client.widget.menu.Menu; import com.extjs.gxt.ui.client.widget.tips.QuickTip; import com.google.gwt.dom.client.AnchorElement; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.ImageElement; import com.google.gwt.dom.client.NodeList; import com.google.gwt.dom.client.Style; import com.google.gwt.safehtml.shared.SafeHtml; 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.FlexTable; import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter; import com.google.gwt.user.client.ui.HTMLTable.RowFormatter; import com.google.gwt.user.client.ui.HasHorizontalAlignment; import com.google.gwt.user.client.ui.Widget; /** * ColumnHeader Component. */ public class ColumnHeader extends BoxComponent { public class GridSplitBar extends BoxComponent { protected int colIndex; protected Draggable d; protected boolean dragging; protected DragListener listener = new DragListener() { @Override public void dragEnd(DragEvent de) { onDragEnd(de); } @Override public void dragStart(DragEvent de) { onDragStart(de); } }; protected int startX; protected void onDragEnd(DragEvent e) { dragging = false; headerDisabled = false; setStyleAttribute("borderLeft", "none"); el().setStyleAttribute("opacity", "0"); el().setWidth(splitterWidth); bar.el().setVisibility(false); int endX = e.getX(); int diff = endX - startX; onColumnSplitterMoved(colIndex, cm.getColumnWidth(colIndex) + diff); } protected void onDragStart(DragEvent e) { headerDisabled = true; dragging = true; setStyleAttribute("borderLeft", "1px solid black"); setStyleAttribute("cursor", "default"); el().setStyleAttribute("opacity", "1"); el().setWidth(1); startX = e.getX(); int cols = cm.getColumnCount(); for (int i = 0, len = cols; i < len; i++) { if (cm.isHidden(i) || !cm.isResizable(i)) continue; Element hd = getHead(i).getElement(); if (hd != null) { Region rr = El.fly(hd).getRegion(); if (startX > rr.right - 5 && startX < rr.right + 5) { colIndex = heads.indexOf(getHead(i)); if (colIndex != -1) break; } } } if (colIndex > -1) { Element c = getHead(colIndex).getElement(); int x = startX; int minx = x - fly((com.google.gwt.user.client.Element) c).getX() - minColumnWidth; int maxx = (container.el().getX() + container.el().getWidth()) - e.getEvent().getClientX(); d.setXConstraint(minx, maxx); } } protected void onMouseMove(Head header, ComponentEvent ce) { int activeHdIndex = heads.indexOf(header); if (dragging || !header.config.isResizable()) { return; } // find the previous column which is not hidden int before = -1; for (int i = activeHdIndex - 1; i >= 0; i--) { if (!cm.isHidden(i)) { before = i; break; } } Event event = ce.getEvent(); int x = event.getClientX(); Region r = header.el().getRegion(); int hw = splitterWidth; el().setY(container.el().getY()); el().setHeight(container.getHeight()); Style ss = getElement().getStyle(); if (x - r.left <= hw && before != -1 && cm.isResizable(before) && !cm.isFixed(before)) { bar.el().setVisibility(true); el().setX(r.left - (hw / 2)); ss.setProperty("cursor", GXT.isSafari ? "e-resize" : "col-resize"); } else if (r.right - x <= hw && cm.isResizable(activeHdIndex) && !cm.isFixed(activeHdIndex)) { bar.el().setVisibility(true); el().setX(r.right - (hw / 2)); ss.setProperty("cursor", GXT.isSafari ? "w-resize" : "col-resize"); } else { bar.el().setVisibility(false); ss.setProperty("cursor", ""); } } @Override protected void onRender(com.google.gwt.user.client.Element target, int index) { super.onRender(target, index); setElement(DOM.createDiv(), target, index); if (GXT.isOpera) { el().setStyleAttribute("cursor", "w-resize"); } else { el().setStyleAttribute("cursor", "col-resize"); } setStyleAttribute("position", "absolute"); setWidth(5); el().setVisibility(false); el().setStyleAttribute("backgroundColor", "white"); el().setStyleAttribute("opacity", "0"); d = new Draggable(this); d.setUseProxy(false); d.setConstrainVertical(true); d.setStartDragDistance(0); d.addDragListener(listener); } } public class Group extends BoxComponent { protected HeaderGroupConfig config; public Group(HeaderGroupConfig config) { this.config = config; config.group = this; groups.add(this); } public void setHtml(SafeHtml html) { el().setInnerHtml(html); } @Override protected void doAttachChildren() { ComponentHelper.doAttach(config.getWidget()); } @Override protected void doDetachChildren() { ComponentHelper.doDetach(config.getWidget()); } @Override protected void onRender(Element target, int index) { setElement(DOM.createDiv(), target, index); setStyleName("x-grid3-hd-inner"); if (config.getWidget() != null) { el().appendChild(config.getWidget().getElement()); } else { el().setInnerHtml(config.getHtml()); } } } public class Head extends BoxComponent { protected int column; protected ColumnConfig config; private AnchorElement btn; private ImageElement img; private int row; private Html text; private Widget widget; public Head(ColumnConfig column) { this.config = column; this.column = cm.indexOf(column); baseStyle = "x-grid3-hd-inner x-grid3-hd-" + column.getId(); if (column.getColumnStyleName() != null) { baseStyle += " " + column.getColumnStyleName(); } heads.add(this); render(DOM.createDiv()); getElement().setAttribute("x-col", column.getId()); } public void activateTrigger(boolean activate) { El e = el().findParent("td", 3); if (e != null) { e.setStyleName("x-grid3-hd-menu-open", activate); } } public Element getTrigger() { return (Element) btn.cast(); } @Override public void onComponentEvent(ComponentEvent ce) { super.onComponentEvent(ce); int type = ce.getEventTypeInt(); switch (type) { case Event.ONMOUSEOVER: onMouseOver(ce); break; case Event.ONMOUSEOUT: onMouseOut(ce); break; case Event.ONMOUSEMOVE: onMouseMove(ce); break; case Event.ONMOUSEDOWN: onHeaderMouseDown(ce, cm.indexOf(config)); break; case Event.ONCLICK: onClick(ce); break; case Event.ONDBLCLICK: onDoubleClick(ce); break; case Event.ONBLUR: FocusFrame.get().unframe(); break; case Event.ONKEYPRESS: onKeyPress(ce); break; } } public void setHeaderHtml(SafeHtml header) { if (text != null) text.setHtml(header); } public void setHeaderText(String text) { setHeaderHtml(SafeGxt.fromNullableString(text)); } public void updateWidth(int width) { if (!config.isHidden()) { El td = el().findParent("td", 3); td.setWidth(width); el().setWidth(width - td.getFrameWidth("lr"), true); Element th = getTableHeader(column); th.getStyle().setPropertyPx("width", width); } } protected void activate() { if (!cm.isMenuDisabled(indexOf(this))) { El td = el().findParent("td", 3); td.addStyleName("x-grid3-hd-over"); int h = td.getHeight(true); el().setHeight(h, true); if (btn != null) { El.fly(btn).setHeight(h, true); } } } protected void deactivate() { if (isRendered()) { el().findParent("td", 3).removeStyleName("x-grid3-hd-over"); } } @Override protected void doAttachChildren() { super.doAttachChildren(); ComponentHelper.doAttach(widget); } @Override protected void doDetachChildren() { super.doDetachChildren(); ComponentHelper.doDetach(widget); } protected void onKeyPress(ComponentEvent ce) { if (GXT.isFocusManagerEnabled() && ce.getKeyCode() == 32) { onHeaderClick(ce, column); } } @Override protected void onRender(Element target, int index) { setElement(DOM.createDiv(), target, index); btn = Document.get().createAnchorElement(); btn.setHref("#"); btn.setClassName("x-grid3-hd-btn"); img = Document.get().createImageElement(); img.setSrc(GXT.BLANK_IMAGE_URL); img.setClassName("x-grid3-sort-icon"); el().dom.appendChild(btn); if (config.getWidget() != null) { Element span = Document.get().createSpanElement().cast(); widget = config.getWidget(); span.appendChild(widget.getElement()); getElement().appendChild(span); } else { text = new Html(config.getHeaderHtml()); text.setTagName("span"); text.render(el().dom); } el().dom.appendChild(img); String tip = config.getToolTip(); if (tip != null) { getElement().setAttribute("qtip", tip); } setAriaRole(config.ariaIgnore ? "presentation" : "columnheader"); setAriaState("aria-haspopup", "true"); setAriaState("aria-owns", getId() + "-menu"); sinkEvents(Event.ONCLICK | Event.ONDBLCLICK | Event.MOUSEEVENTS | Event.FOCUSEVENTS | Event.ONKEYPRESS); } private Element getTableHeader(int columnIndex) { int domIndex = getDomIndexByColumn(columnIndex); NodeList<Element> ths = getTableHeads(); if (ths.getLength() > domIndex) { return ths.getItem(domIndex); } return null; } private NodeList<Element> getTableHeads() { return tbody.getFirstChildElement().getChildNodes().cast(); } private void onClick(ComponentEvent ce) { ce.preventDefault(); if (ce.getTarget() == (Element) btn.cast()) { onDropDownClick(ce, column); } else { onHeaderClick(ce, column); } } private void onDoubleClick(ComponentEvent ce) { onHeaderDoubleClick(ce, column); } private void onMouseMove(ComponentEvent ce) { if (bar != null) bar.onMouseMove(this, ce); } private void onMouseOut(ComponentEvent ce) { deactivate(); } private void onMouseOver(ComponentEvent ce) { if (headerDisabled) { return; } activate(); } } protected GridSplitBar bar; protected ColumnModel cm; protected BoxComponent container; protected List<Group> groups = new ArrayList<Group>(); protected boolean headerDisabled; protected List<Head> heads = new ArrayList<Head>(); protected Menu menu; protected int minColumnWidth = 10; protected Draggable reorderer; protected int rows; protected int splitterWidth = 5; protected FlexTable table = new FlexTable(); private QuickTip quickTip;; /** * Maps actual column indexes to the TABLE TH and TD index. */ protected int[] columnToHead; private Element tbody = Document.get().createTBodyElement().cast(); /** * Creates a new column header. * * @param container the containing component * @param cm the column model */ public ColumnHeader(BoxComponent container, ColumnModel cm) { this.container = container; this.cm = cm; disableTextSelection(true); } /** * Returns the header's container component. * * @return the container component */ public BoxComponent getContainer() { return container; } @Override public Element getElement() { // we need this because of lazy rendering return table.getElement(); } public Head getHead(int column) { return (column > -1 && column < heads.size()) ? heads.get(column) : null; } /** * Returns the minimum column width. * * @return the column width */ public int getMinColumnWidth() { return minColumnWidth; } /** * Returns the splitter width. * * @return the splitter width in pixels. */ public int getSplitterWidth() { return splitterWidth; } /** * Returns the index of the given column head. * * @param head the column head * @return the index */ public int indexOf(Head head) { return heads.indexOf(head); } @Override public boolean isAttached() { if (table != null) { return table.isAttached(); } return false; } @Override public void onBrowserEvent(Event event) { super.onBrowserEvent(event); // Delegate events to the widget. table.onBrowserEvent(event); } @SuppressWarnings("rawtypes") public void refresh() { groups.clear(); heads.clear(); columnToHead = new int[cm.getColumnCount()]; for (int i = 0, mark = 0; i < columnToHead.length; i++) { columnToHead[i] = cm.isHidden(i) ? -1 : mark++; } int cnt = table.getRowCount(); for (int i = 0; i < cnt; i++) { table.removeRow(0); } table.setWidth(cm.getTotalWidth() + "px"); Element body = fly(table.getElement()).selectNode("tbody").dom; table.getElement().insertBefore(tbody, body); removeChildren(tbody); DomHelper.insertHtml("afterBegin", tbody, renderHiddenHeaders(getColumnWidths())); List<HeaderGroupConfig> configs = cm.getHeaderGroups(); FlexCellFormatter cf = table.getFlexCellFormatter(); RowFormatter rf = table.getRowFormatter(); rows = 0; for (HeaderGroupConfig config : configs) { rows = Math.max(rows, config.getRow() + 1); } rows += 1; for (int i = 0; i < rows; i++) { rf.setStyleName(i, "x-grid3-hd-row"); rf.getElement(i).setAttribute("role", "presentation"); } int cols = cm.getColumnCount(); String cellClass = "x-grid3-header" + " " + "x-grid3-hd"; if (rows > 1) { Map<Integer, Integer> map = new HashMap<Integer, Integer>(); for (int i = 0; i < rows - 1; i++) { for (HeaderGroupConfig config : cm.getHeaderGroups()) { int col = config.getColumn(); int row = config.getRow(); Integer start = map.get(row); if (start == null || col < start) { map.put(row, col); } } } } // groups for (HeaderGroupConfig config : cm.getHeaderGroups()) { int col = config.getColumn(); int row = config.getRow(); int rs = config.getRowspan(); int cs = config.getColspan(); Group group = createNewGroup(config); boolean hide = true; if (rows > 1) { for (int i = col; i < (col + cs); i++) { if (!cm.isHidden(i)) { hide = false; } } } if (hide) { continue; } table.setWidget(row, col, group); cf.setStyleName(row, col, cellClass); HorizontalAlignment align = config.getHorizontalAlignment(); if (align == HorizontalAlignment.RIGHT) { cf.setHorizontalAlignment(row, col, HasHorizontalAlignment.ALIGN_RIGHT); } else if (align == HorizontalAlignment.LEFT) { cf.setHorizontalAlignment(row, col, HasHorizontalAlignment.ALIGN_LEFT); } else { cf.setHorizontalAlignment(row, col, HasHorizontalAlignment.ALIGN_CENTER); } int ncs = cs; if (cs > 1) { for (int i = col; i < (col + cs); i++) { if (cm.isHidden(i)) { ncs -= 1; } } } cf.setRowSpan(row, col, rs); cf.setColSpan(row, col, ncs); } for (int i = 0; i < cols; i++) { Head h = createNewHead(cm.getColumn(i)); if (cm.isHidden(i)) { continue; } int rowspan = 1; if (rows > 1) { for (int j = rows - 2; j >= 0; j--) { if (!cm.hasGroup(j, i)) { rowspan += 1; } } } int row; if (rowspan > 1) { row = (rows - 1) - (rowspan - 1); } else { row = rows - 1; } h.row = row; if (rowspan > 1) { table.setWidget(row, i, h); table.getFlexCellFormatter().setRowSpan(row, i, rowspan); } else { table.setWidget(row, i, h); } cf.setStyleName(row, i, "x-grid3-header x-grid3-hd x-grid3-cell x-grid3-td-" + cm.getColumnId(i)); cf.getElement(row, i).setAttribute("role", "presentation"); cf.getElement(row, i).setPropertyInt("gridColumnIndex", i); cf.setStyleName(row, i, "x-grid3-header x-grid3-hd x-grid3-cell x-grid3-td-" + cm.getColumnId(i)); HorizontalAlignment align = cm.getColumnAlignment(i); if (align == HorizontalAlignment.RIGHT) { table.getCellFormatter().setHorizontalAlignment(row, i, HasHorizontalAlignment.ALIGN_RIGHT); table.getCellFormatter().getElement(row, i).getFirstChildElement().getStyle() .setPropertyPx("paddingRight", 16); } else if (align == HorizontalAlignment.CENTER) { table.getCellFormatter().setHorizontalAlignment(row, i, HasHorizontalAlignment.ALIGN_CENTER); } else { table.getCellFormatter().setHorizontalAlignment(row, i, HasHorizontalAlignment.ALIGN_LEFT); } } if (container instanceof Grid) { Grid<?> grid = (Grid) container; SortInfo sortInfo = grid.getStore().getSortState(); if (sortInfo != null && sortInfo.getSortField() != null) { updateSortIcon(grid.getColumnModel().findColumnIndex(sortInfo.getSortField()), sortInfo.getSortDir()); } } cleanCells(); adjustColumnWidths(getColumnWidths()); if (isAttached()) { adjustHeights(); } } /** * Do not call. */ public void release() { ComponentHelper.doDetach(this); if (bar != null && bar.isRendered()) { bar.el().remove(); } } public void setEnableColumnReorder(boolean enable) { if (enable && reorderer == null) { reorderer = new Draggable(this); reorderer.setUseProxy(true); reorderer.setSizeProxyToSource(false); reorderer.setMoveAfterProxyDrag(false); reorderer.setProxy(StatusProxy.get().el()); reorderer.addDragListener(new DragListener() { private Head active; private int newIndex = -1; private Head start; private El statusIndicatorBottom; private El statusIndicatorTop; private StatusProxy statusProxy = StatusProxy.get(); public void dragCancel(DragEvent de) { afterDragEnd(); } public void dragEnd(DragEvent de) { if (statusProxy.getStatus()) { cm.moveColumn(start.column, newIndex); } afterDragEnd(); } public void dragMove(DragEvent de) { de.setX(de.getClientX() + 12 + XDOM.getBodyScrollLeft()); de.setY(de.getClientY() + 12 + XDOM.getBodyScrollTop()); Head h = ComponentManager.get().find(adjustTargetElement(de.getTarget()), Head.class); if (h != null && !h.equals(start)) { HeaderGroupConfig g = cm.getGroup(h.row - 1, h.column); HeaderGroupConfig s = cm.getGroup(start.row - 1, start.column); if ((g == null && s == null) || (g != null && g.equals(s))) { active = h; boolean before = de.getClientX() < active.getAbsoluteLeft() + active.getWidth() / 2; showStatusIndicator(true); if (before) { statusIndicatorTop.alignTo(active.el().dom, "b-tl", new int[] { -1, 0 }); statusIndicatorBottom.alignTo(active.el().dom, "t-bl", new int[] { -1, 0 }); } else { statusIndicatorTop.alignTo(active.el().dom, "b-tr", new int[] { 1, 0 }); statusIndicatorBottom.alignTo(active.el().dom, "t-br", new int[] { 1, 0 }); } int i = active.column; if (!before) { i++; } int aIndex = i; if (start.column < active.column) { aIndex--; } newIndex = i; if (aIndex != start.column) { statusProxy.setStatus(true); } else { showStatusIndicator(false); statusProxy.setStatus(false); } } else { active = null; showStatusIndicator(false); statusProxy.setStatus(false); } } else { active = null; showStatusIndicator(false); statusProxy.setStatus(false); } } public void dragStart(DragEvent de) { Head h = ComponentManager.get().find(de.getTarget(), Head.class); if (h != null && !h.config.isFixed()) { headerDisabled = true; quickTip.disable(); if (bar != null) { bar.hide(); } if (statusIndicatorBottom == null) { statusIndicatorBottom = new El(DOM.createDiv()); statusIndicatorBottom.addStyleName("col-move-bottom"); statusIndicatorTop = new El(DOM.createDiv()); statusIndicatorTop.addStyleName("col-move-top"); } XDOM.getBody().appendChild(statusIndicatorTop.dom); XDOM.getBody().appendChild(statusIndicatorBottom.dom); start = h; statusProxy.setStatus(false); statusProxy.update(start.config.getHeaderHtml()); } else { de.setCancelled(true); } } private Element adjustTargetElement(Element target) { return (Element) (target.getFirstChildElement() != null ? target.getFirstChildElement() : target); } private void afterDragEnd() { start = null; active = null; newIndex = -1; removeStatusIndicator(); headerDisabled = false; if (bar != null) { bar.show(); } quickTip.enable(); } private void removeStatusIndicator() { if (statusIndicatorBottom != null) { statusIndicatorBottom.remove(); statusIndicatorTop.remove(); } } private void showStatusIndicator(boolean show) { if (statusIndicatorBottom != null) { statusIndicatorBottom.setVisibility(show); statusIndicatorTop.setVisibility(show); } } }); } else if (reorderer != null && !enable) { reorderer.release(); reorderer = null; } } /** * True to enable column resizing. * * @param enable true to enable, otherwise false */ public void setEnableColumnResizing(boolean enable) { if (bar == null && enable) { bar = new GridSplitBar(); bar.render(container.getElement()); if (isAttached()) { ComponentHelper.doAttach(bar); } bar.show(); } else if (bar != null && !enable) { ComponentHelper.doDetach(bar); bar.el().remove(); bar = null; } } /** * Sets the column's header HTML. * * @param column the column index * @param headerHtml the header text as HTML */ public void setHeaderHtml(int column, SafeHtml headerHtml) { getHead(column).setHeaderHtml(headerHtml); } /** * Sets the column's header text. * * @param column the column index * @param text the header text */ public void setHeaderText(int column, String text) { getHead(column).setHeaderText(text); } /** * Sets the header's context menu. * * @param menu the context menu */ public void setMenu(Menu menu) { this.menu = menu; } /** * Sets the minimum column width. * * @param minColumnWidth the minimum column width */ public void setMinColumnWidth(int minColumnWidth) { this.minColumnWidth = minColumnWidth; } /** * Sets the splitter width. * * @param splitterWidth the splitter width */ public void setSplitterWidth(int splitterWidth) { this.splitterWidth = splitterWidth; } /** * Shows the column's header context menu. * * @param column the column index */ public void showColumnMenu(final int column) { menu = getContextMenu(column); ComponentEvent ge = createColumnEvent(this, column, menu); if (!container.fireEvent(Events.HeaderContextMenu, ge)) { return; } if (menu != null) { final Head h = getHead(column); menu.setId(h.getId() + "-menu"); h.activateTrigger(true); menu.addListener(Events.Hide, new Listener<BaseEvent>() { public void handleEvent(BaseEvent be) { h.activateTrigger(false); container.focus(); if (GXT.isFocusManagerEnabled()) { selectHeader(column); } } }); menu.show(h.getTrigger(), "tl-bl?"); } } @Override public void sinkEvents(int eventBitsToAdd) { table.sinkEvents(eventBitsToAdd); } public void updateAllColumnWidths() { adjustColumnWidths(getColumnWidths()); } public void updateColumnHidden(int index, boolean hidden) { refresh(); cleanCells(); } public void updateColumnWidth(int column, int width) { if (groups != null && groups.size() > 0) { adjustColumnWidths(getColumnWidths()); return; } Head h = getHead(column); if (h != null) { h.updateWidth(width); } } public void updateSortIcon(int colIndex, SortDir dir) { for (int i = 0; i < heads.size(); i++) { Head h = heads.get(i); if (h.isRendered()) { if (i == colIndex && dir != SortDir.NONE) { h.addStyleName(dir == SortDir.DESC ? "sort-desc" : "sort-asc"); h.removeStyleName(dir != SortDir.DESC ? "sort-desc" : "sort-asc"); h.el().setElementAttribute("aria-sort", dir != SortDir.DESC ? "descending" : "ascending"); // fixes issue with IE initially hiding sort icon on change h.el().repaint(); } else { h.el().removeStyleName("sort-asc", "sort-desc"); h.el().setElementAttribute("aria-sort", "none"); } } } } public void updateTotalWidth(int offset, int width) { if (offset != -1) table.getElement().getParentElement().getStyle().setPropertyPx("width", ++offset); table.getElement().getStyle().setProperty("width", (++width) + "px"); } protected void adjustCellWidth(Element cell, int width) { cell.getStyle().setPropertyPx("width", width); int adj = fly(cell).getFrameWidth("lr"); Element inner = cell.getFirstChildElement().cast(); fly(inner).setWidth(width - adj, true); if (isAttached()) { int before = cell.getOffsetHeight(); fly(inner).setHeight(before, true); int after = cell.getOffsetHeight(); // getting different values when some browsers are zoomed which is // causing the column heights to grow if (after != before) { fly(inner).setHeight(before + (before - after), true); } } } protected void adjustColumnWidths(int[] columnWidths) { NodeList<Element> ths = tbody.getFirstChildElement().getChildNodes().cast(); if (ths == null) { return; } for (int i = 0; i < columnWidths.length; i++) { if (cm.isHidden(i)) { continue; } ths.getItem(getDomIndexByColumn(i)).getStyle().setPropertyPx("width", columnWidths[i]); } cleanCells(); for (int i = 0; i < heads.size(); i++) { Head head = heads.get(i); if (head != null && !head.isRendered()) continue; String id = head.getElement().getAttribute("x-col"); ColumnConfig cc = cm.getColumnById(id); if (cc == null) return; int w = cc.getWidth(); Element cell = head.getElement().getParentElement().cast(); adjustCellWidth(cell, w); } for (int i = 0; i < groups.size(); i++) { Group group = groups.get(i); if (group != null && !group.isRendered()) continue; Element cell = group.getElement().getParentElement().cast(); int colspan = 1; String scolspan = cell.getAttribute("colspan"); if (scolspan != null && !scolspan.equals("")) { colspan = Integer.parseInt(scolspan); } int w = 0; int mark = group.config.getColumn(); for (int k = mark; k < (mark + colspan); k++) { ColumnConfig c = cm.getColumn(k); if (c.isHidden()) { mark++; continue; } w += cm.getColumnWidth(k); } mark += colspan; adjustCellWidth(cell, w); } } protected void adjustHeights() { for (Head head : heads) { if (head.isRendered()) { int h = head.el().getParent().getHeight(); if (h > 0) { head.setHeight(h); } } } } protected void cleanCells() { NodeList<Element> tds = DomQuery.select("tr.x-grid3-hd-row > td", table.getElement()); for (int i = 0; i < tds.getLength(); i++) { Element td = tds.getItem(i); if (!td.hasChildNodes()) { El.fly(td).removeFromParent(); } } } protected ComponentEvent createColumnEvent(ColumnHeader header, int column, Menu menu) { return new ColumnHeaderEvent(header, container, column, menu); } protected Group createNewGroup(HeaderGroupConfig config) { return new Group(config); } protected Head createNewHead(ColumnConfig config) { return new Head(config); } @Override protected void doAttachChildren() { super.doAttachChildren(); ComponentHelper.doAttach(bar); } @Override protected void doDetachChildren() { super.doDetachChildren(); ComponentHelper.doDetach(bar); } protected int getColumnIndexByDom(int domIndex) { assert columnToHead != null && domIndex < columnToHead.length; for (int i = 0; i < columnToHead.length; i++) { if (columnToHead[i] == domIndex) { return i; } } return -1; } protected int[] getColumnWidths() { int colCount = cm.getColumnCount(); int[] columnWidths = new int[colCount]; for (int i = 0; i < colCount; i++) { columnWidths[i] = cm.getColumnWidth(i); } return columnWidths; } protected int getColumnWidths(int start, int end) { int w = 0; for (int i = start; i < end; i++) { if (!cm.isHidden(i)) { w += cm.getColumnWidth(i); } } return w; } protected Menu getContextMenu(int column) { return menu; } protected int getDomIndexByColumn(int column) { assert columnToHead != null && column < columnToHead.length; return columnToHead[column]; } @Override protected void onAttach() { ComponentHelper.doAttach(table); DOM.setEventListener(getElement(), this); doAttachChildren(); onLoad(); adjustHeights(); } protected void onColumnSplitterMoved(int colIndex, int width) { } @Override protected void onDetach() { try { onUnload(); } finally { ComponentHelper.doDetach(table); doDetachChildren(); } onDetachHelper(); } protected void onDropDownClick(ComponentEvent ce, int column) { ce.cancelBubble(); ce.preventDefault(); showColumnMenu(column); } protected void onHeaderClick(ComponentEvent ce, int column) { ComponentEvent evt = createColumnEvent(this, column, menu); evt.setEvent(ce.getEvent()); container.fireEvent(Events.HeaderClick, evt); } protected void onHeaderDoubleClick(ComponentEvent ce, int column) { ComponentEvent evt = createColumnEvent(this, column, menu); evt.setEvent(ce.getEvent()); container.fireEvent(Events.HeaderDoubleClick, evt); } protected void onHeaderMouseDown(ComponentEvent ce, int column) { ComponentEvent evt = createColumnEvent(this, column, menu); evt.setEvent(ce.getEvent()); container.fireEvent(Events.HeaderMouseDown, evt); } protected void onKeyDown(ComponentEvent ce, int index) { } @Override protected void onRender(Element target, int index) { table.setCellPadding(0); table.setCellSpacing(0); table.getElement().getStyle().setProperty("tableLayout", "fixed"); table.getElement().setAttribute("role", "presentation"); table.getElement().getFirstChildElement().setAttribute("role", "presentation"); setElement(table.getElement(), target, index); List<HeaderGroupConfig> configs = cm.getHeaderGroups(); rows = 0; for (HeaderGroupConfig config : configs) { rows = Math.max(rows, config.getRow() + 1); } rows++; quickTip = new QuickTip(this); refresh(); } protected String renderHiddenHeaders(int[] columnWidths) { StringBuffer heads = new StringBuffer(); heads.append("<tr>"); for (int i = 0; i < columnWidths.length; i++) { // unlike GridView, we do NOT render TH's for hidden elements because of // support of // rowspan and colspan with header configs if (cm.isHidden(i)) { continue; } String styles = "height: 0px; width: " + columnWidths[i] + "px;"; heads.append("<th style=\"" + styles + "\"></th>"); } heads.append("</tr>"); return heads.toString(); } protected void selectHeader(int index) { Head h = getHead(index); if (h != null && h.isVisible()) { for (Head head : heads) { head.removeStyleName("x-column-header-sel"); head.deactivate(); } h.addStyleName("x-column-header-sel"); h.activate(); FocusFrame.get().frame(h); container.getAriaSupport().setState("aria-activedescendant", h.getId()); } } private final void removeChildren(Element parent) { Element child = null; while ((child = parent.getFirstChildElement().cast()) != null) { parent.removeChild(child); } String tag = parent.getTagName().toLowerCase(); if (!tag.equals("table") && !tag.equals("tbody") && !tag.equals("tr") && !tag.equals("td")) { parent.setInnerHTML(""); } } }