/* * Ext GWT - Ext for GWT * Copyright(c) 2007-2009, Ext JS, LLC. * licensing@extjs.com * * http://extjs.com/license */ package com.extjs.gxt.ui.client.widget.treetable; import com.extjs.gxt.ui.client.Style.SortDir; import com.extjs.gxt.ui.client.core.XDOM; import com.extjs.gxt.ui.client.event.BaseEvent; import com.extjs.gxt.ui.client.event.ComponentEvent; import com.extjs.gxt.ui.client.event.ContainerEvent; import com.extjs.gxt.ui.client.event.EventType; import com.extjs.gxt.ui.client.event.Listener; import com.extjs.gxt.ui.client.event.TreeTableEvent; import com.extjs.gxt.ui.client.util.DelayedTask; import com.extjs.gxt.ui.client.util.Size; import com.extjs.gxt.ui.client.util.StyleTemplate; import com.extjs.gxt.ui.client.widget.ComponentHelper; import com.extjs.gxt.ui.client.widget.table.BaseTable; import com.extjs.gxt.ui.client.widget.table.TableColumn; import com.extjs.gxt.ui.client.widget.table.TableColumnModel; import com.extjs.gxt.ui.client.widget.table.TableHeader; import com.extjs.gxt.ui.client.widget.tree.Tree; import com.extjs.gxt.ui.client.widget.tree.TreeItem; import com.extjs.gxt.ui.client.widget.treegrid.TreeGrid; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Event; /** * A hierarchical tree widget with support for additional columns. The tree * contains a hierarchy of <code>TreeTableItems</code> that the user can open, * close, and select. * * <dl> * <dt><b>Events:</b></dt> * * <dd><b>CellClick</b> : TreeTableEvent(treeTable, item, rowIndex, cellIndex)<br> * <div>Fires after a cell has been clicked.</div> * <ul> * <li>treeTable : tree table</li> * <li>item : item represented by the cell</li> * <li>rowIndex : the item's depth</li> * <li>cellIndex : the cell index</li> * </ul> * </dd> * * <dd><b>CellDoubleClick</b> : TreeTableEvent(treeTable, item, rowIndex, * cellIndex)<br> * <div>Fires after a cell has been double clicked.</div> * <ul> * <li>treeTable : tree table</li> * <li>item : item represented by the cell</li> * <li>rowIndex : the item's depth</li> * <li>cellIndex : the cell index</li> * </ul> * </dd> * * <dd><b>RowClick</b> : TreeTableEvent(treeTable, item, rowIndex, cellIndex)<br> * <div>Fires after a cell has been clicked.</div> * <ul> * <li>treeTable : tree table</li> * <li>item : item that represents the row</li> * <li>rowIndex : the item's depth</li> * <li>cellIndex : the cell index</li> * </ul> * </dd> * * <dd><b>RowDoubleClick</b> : TreeTableEvent(treeTable, item, rowIndex, * cellIndex)<br> * <div>Fires after a cell has been double clicked.</div> * <ul> * <li>treeTable : tree table</li> * <li>item : item that represents the row</li> * <li>rowIndex : the item's depth</li> * <li>cellIndex : the cell index</li> * </ul> * </dd> * </dl> * * @deprecated see @link {@link TreeGrid} */ public class TreeTable extends Tree implements BaseTable { protected StyleTemplate styleTemplate = null; protected TreeTableHeader header; protected TreeTableColumnModel cm; protected TreeTableView view; private boolean columnContextMenu; private boolean horizontalScroll = true; private int lastLeft; private Size lastSize; private DelayedTask scrollTask = new DelayedTask(new Listener<BaseEvent>() { public void handleEvent(BaseEvent be) { header.updateSplitBars(); } }); /** * Creates a new single select tree table. A column model must be set before * the table is rendered. */ public TreeTable() { } /** * Creates a new tree table with the given column model. * * @param cm the tree table column model */ public TreeTable(TreeTableColumnModel cm) { this.cm = cm; } @Override public boolean fireEvent(EventType type, ComponentEvent ce) { // handle case where events are disabled why animating expand / collapse boolean d = isDisabledEvents(); disableEvents(false); boolean result = super.fireEvent(type, ce); disableEvents(d); return result; } /** * Returns the column at the specified index. * * @param index the column index * @return the column */ public TableColumn getColumn(int index) { return cm.getColumn(index); } /** * Returns the column with the given id. * * @param id the column id * @return the column */ public TableColumn getColumn(String id) { return cm.getColumn(id); } /** * Returns the column context menu enabed state. * * @return <code>true</code> if enabled, <code>false</code> otherwise. */ public boolean getColumnContextMenu() { return !columnContextMenu; } /** * Returns the number of columns contained in the table. * * @return the number of columns */ public int getColumnCount() { return cm.getColumnCount(); } /** * Returns the table's column model. * * @return the column model */ public TableColumnModel getColumnModel() { return cm; } /** * Returns true if horizontal scrolling is enabled * * @return the horizontal scroll state */ public boolean getHorizontalScroll() { return horizontalScroll; } /** * Returns the tree table's header. * * @return the table header */ public TableHeader getTableHeader() { if (header == null) { header = new TreeTableHeader(this); } return header; } public void onBrowserEvent(Event event) { super.onBrowserEvent(event); int type = DOM.eventGetType(event); if (type == Event.ONSCROLL) { int left = view.getScrollEl().getScrollLeft(); if (left == lastLeft) { return; } lastLeft = left; header.el().setLeft(-left); scrollTask.delay(400); } } @Override public void recalculate() { onResize(getOffsetWidth(), getOffsetHeight()); } /** * Scrolls the item into view. * * @param item the item */ public void scrollIntoView(TreeTableItem item) { item.el().scrollIntoView(view.getScrollEl().dom, false); } /** * Sets whether the table header context menu is displayed (defaults to true). * * @param columnContextMenu the column context menu sate */ public void setColumnContextMenu(boolean columnContextMenu) { this.columnContextMenu = columnContextMenu; } /** * True to display a horizonatal scroll bar when needed (defaults to true). * * @param horizontalScroll the horizontal scroll state */ public void setHorizontalScroll(boolean horizontalScroll) { this.horizontalScroll = horizontalScroll; } /** * Sets the tree table's header. Should only be called when providing a custom * tree table header. Has no effect if called after the table has been * rendered. * * @param header the table header */ public void setTableHeader(TreeTableHeader header) { if (!isRendered()) { this.header = header; } } /** * Sets the tree table's view. Provides a way to provide specialized views. * table views. * * @param view the view */ public void setView(TreeTableView view) { this.view = view; } /** * Sorts the tree table using the specified column index. * * @param index the column index * @param direction the direction to sort (NONE, ASC, DESC) */ public void sort(int index, SortDir direction) { } @Override protected ComponentEvent createComponentEvent(Event event) { Element target = null; TreeItem item = null; if (event != null) { target = event.getEventTarget().cast(); item = (TreeItem) findItem(target); } TreeTableEvent te = new TreeTableEvent(this, item); if (view != null && event != null && item != null) { te.setCellIndex(view.findCellIndex(target)); te.setRowIndex(item.getDepth()); } return te; } @Override @SuppressWarnings("unchecked") protected ContainerEvent createContainerEvent(TreeItem item) { return new TreeTableEvent(this, item); } @Override protected void createRootItem() { root = new RootTreeTableItem(this); } protected void doAttachChildren() { ComponentHelper.doAttach(header); } protected void doDetachChildren() { ComponentHelper.doDetach(header); } @SuppressWarnings("unchecked") protected String getRenderedValue(TreeTableItem item, int column, Object value) { TreeTableColumn col = (TreeTableColumn) cm.getColumn(column); if (col.getRenderer() != null) { return col.getRenderer().render(item, col.getId(), value); } else { if (value != null) { return value.toString(); } return null; } } /** * Returns the tree table's view. * * @return the view */ protected TreeTableView getView() { if (view == null) { view = new TreeTableView(); } return view; } @Override protected void onRender(Element target, int index) { setElement(DOM.createDiv()); setStyleName("my-treetbl"); el().insertInto(target, index); root.render(DOM.createDiv()); DOM.appendChild(getElement(), root.getElement()); ((RootTreeTableItem) root).renderChildren(); cm.setTable(this); ((TreeTableItem) root).setValues(new String[getColumnCount()]); el().removeChildren(); header = (TreeTableHeader) getTableHeader(); header.render(el().dom); header.init(this); DOM.appendChild(getElement(), header.getElement()); if (styleTemplate == null) { Element style = DOM.createElement("style"); DOM.setElementProperty(style, "id", getId() + "-cols-style"); DOM.appendChild(XDOM.getHead(), style); styleTemplate = new StyleTemplate(style); } for (int i = 0, n = cm.getColumnCount(); i < n; i++) { TreeTableColumn c = (TreeTableColumn) cm.getColumn(i); int w = cm.getWidthInPixels(c.getIndex()); styleTemplate.set("." + getId() + "-col-" + i, "width:" + w + "px;"); } view = getView(); view.init(this); view.render(); disableTextSelection(true); el().setTabIndex(0); sinkEvents(Event.ONCLICK | Event.ONDBLCLICK | Event.MOUSEEVENTS | Event.KEYEVENTS | Event.ONSCROLL); } protected void onResize(int width, int height) { super.onResize(width, height); int h = width; int w = height; if (lastSize != null) { if (lastSize.width == w && lastSize.height == h) { return; } } lastSize = new Size(w, h); header.resizeColumns(false, true); } }