diff options
Diffstat (limited to 'webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/Table.js')
-rw-r--r-- | webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/Table.js | 1062 |
1 files changed, 1062 insertions, 0 deletions
diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/Table.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/Table.js new file mode 100644 index 0000000000..360662e718 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/Table.js @@ -0,0 +1,1062 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 by STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) +#require(qx.ui.table.DefaultDataRowRenderer) + +************************************************************************ */ + +/** + * A table. + * + * @param tableModel {qx.ui.table.TableModel} The table + * model to read the data from. + */ +qx.OO.defineClass("qx.ui.table.Table", qx.ui.layout.VerticalBoxLayout, +function(tableModel) { + qx.ui.layout.VerticalBoxLayout.call(this); + + // Create the child widgets + this._scrollerParent = new qx.ui.layout.HorizontalBoxLayout; + this._scrollerParent.setDimension("100%", "1*"); + this._scrollerParent.setSpacing(1); + + this._statusBar = new qx.ui.basic.Label; + this._statusBar.setAppearance("table-focus-statusbar"); + this._statusBar.setDimension("100%", "auto"); + + this.add(this._scrollerParent, this._statusBar); + + this._columnVisibilityBt = new qx.ui.toolbar.Button(null, "widget/table/selectColumnOrder.png"); + this._columnVisibilityBt.addEventListener("execute", this._onColumnVisibilityBtExecuted, this); + + // Create the models + this._selectionManager = new qx.ui.table.SelectionManager; + + this.setSelectionModel(new qx.ui.table.SelectionModel); + this.setTableColumnModel(new qx.ui.table.TableColumnModel); + this.setTableModel(tableModel); + + // Update the status bar + this._updateStatusBar(); + + // create the main meta column + this.setMetaColumnCounts([ -1 ]); + + // Make focusable + this.setTabIndex(1); + this.addEventListener("keydown", this._onkeydown); + this.addEventListener("keypress", this._onkeypress); + this.addEventListener("changeFocused", this._onFocusChanged); + + this._focusedCol = 0; + this._focusedRow = 0; +}); + + +/** The default row renderer to use when {@link #dataRowRenderer} is null. */ +qx.Class.DEFAULT_DATA_ROW_RENDERER = new qx.ui.table.DefaultDataRowRenderer(); + + +/** The selection model. */ +qx.OO.addProperty({ name:"selectionModel", type:"object", instance : "qx.ui.table.SelectionModel" }); + +/** The table model. */ +qx.OO.addProperty({ name:"tableModel", type:"object", instance : "qx.ui.table.TableModel" }); + +/** The table column model. */ +qx.OO.addProperty({ name:"tableColumnModel", type:"object", instance : "qx.ui.table.TableColumnModel" }); + +/** The height of the table rows. */ +qx.OO.addProperty({ name:"rowHeight", type:"number", defaultValue:15 }); + +/** Whether to show the status bar */ +qx.OO.addProperty({ name:"statusBarVisible", type:"boolean", defaultValue:true }); + +/** Whether to show the column visibility button */ +qx.OO.addProperty({ name:"columnVisibilityButtonVisible", type:"boolean", defaultValue:true }); + +/** + * {int[]} The number of columns per meta column. If the last array entry is -1, + * this meta column will get the remaining columns. + */ +qx.OO.addProperty({ name:"metaColumnCounts", type:"object" }); + +/** + * Whether the focus should moved when the mouse is moved over a cell. If false + * the focus is only moved on mouse clicks. + */ +qx.OO.addProperty({ name:"focusCellOnMouseMove", type:"boolean", defaultValue:false }); + +/** + * Whether the table should keep the first visible row complete. If set to false, + * the first row may be rendered partial, depending on the vertical scroll value. + */ +qx.OO.addProperty({ name:"keepFirstVisibleRowComplete", type:"boolean", defaultValue:true }); + +/** + * Whether the table cells should be updated when only the selection or the + * focus changed. This slows down the table update but allows to react on a + * changed selection or a changed focus in a cell renderer. + */ +qx.OO.addProperty({ name:"alwaysUpdateCells", type:"boolean", defaultValue:false }); + +/** The height of the header cells. */ +qx.OO.addProperty({ name:"headerCellHeight", type:"number", defaultValue:16, allowNull:false }); + +/** The renderer to use for styling the rows. */ +qx.OO.addProperty({ name:"dataRowRenderer", type:"object", instance:"qx.ui.table.DataRowRenderer", defaultValue:qx.Class.DEFAULT_DATA_ROW_RENDERER, allowNull:false }); + + +// property modifier +qx.Proto._modifySelectionModel = function(propValue, propOldValue, propData) { + this._selectionManager.setSelectionModel(propValue); + + if (propOldValue != null) { + propOldValue.removeEventListener("changeSelection", this._onSelectionChanged, this); + } + propValue.addEventListener("changeSelection", this._onSelectionChanged, this); + + return true; +} + + +// property modifier +qx.Proto._modifyTableModel = function(propValue, propOldValue, propData) { + this.getTableColumnModel().init(propValue.getColumnCount()); + + if (propOldValue != null) { + propOldValue.removeEventListener(qx.ui.table.TableModel.EVENT_TYPE_META_DATA_CHANGED, this._onTableModelMetaDataChanged, this); + propOldValue.removeEventListener(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED, this._onTableModelDataChanged, this); + } + propValue.addEventListener(qx.ui.table.TableModel.EVENT_TYPE_META_DATA_CHANGED, this._onTableModelMetaDataChanged, this); + propValue.addEventListener(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED, this._onTableModelDataChanged, this); + + return true; +} + + +// property modifier +qx.Proto._modifyTableColumnModel = function(propValue, propOldValue, propData) { + if (propOldValue != null) { + propOldValue.removeEventListener("visibilityChanged", this._onColVisibilityChanged, this); + propOldValue.removeEventListener("widthChanged", this._onColWidthChanged, this); + propOldValue.removeEventListener("orderChanged", this._onColOrderChanged, this); + } + propValue.addEventListener("visibilityChanged", this._onColVisibilityChanged, this); + propValue.addEventListener("widthChanged", this._onColWidthChanged, this); + propValue.addEventListener("orderChanged", this._onColOrderChanged, this); + + return true; +}; + + +// property modifier +qx.Proto._modifyStatusBarVisible = function(propValue, propOldValue, propData) { + this._statusBar.setDisplay(propValue); + + if (propValue) { + this._updateStatusBar(); + } + return true; +}; + + +// property modifier +qx.Proto._modifyColumnVisibilityButtonVisible = function(propValue, propOldValue, propData) { + this._columnVisibilityBt.setDisplay(propValue); + + return true; +}; + + +// property modifier +qx.Proto._modifyMetaColumnCounts = function(propValue, propOldValue, propData) { + var metaColumnCounts = propValue; + var scrollerArr = this._getPaneScrollerArr(); + + // Remove the panes not needed any more + this._cleanUpMetaColumns(metaColumnCounts.length); + + // Update the old panes + var leftX = 0; + for (var i = 0; i < scrollerArr.length; i++) { + var paneScroller = scrollerArr[i]; + var paneModel = paneScroller.getTablePaneModel(); + paneModel.setFirstColumnX(leftX); + paneModel.setMaxColumnCount(metaColumnCounts[i]); + leftX += metaColumnCounts[i]; + } + + // Add the new panes + if (metaColumnCounts.length > scrollerArr.length) { + var selectionModel = this.getSelectionModel(); + var tableModel = this.getTableModel(); + var columnModel = this.getTableColumnModel(); + + for (var i = scrollerArr.length; i < metaColumnCounts.length; i++) { + var paneModel = new qx.ui.table.TablePaneModel(columnModel); + paneModel.setFirstColumnX(leftX); + paneModel.setMaxColumnCount(metaColumnCounts[i]); + leftX += metaColumnCounts[i]; + + var paneScroller = new qx.ui.table.TablePaneScroller(this); + paneScroller.setTablePaneModel(paneModel); + + // Register event listener for vertical scrolling + paneScroller.addEventListener("changeScrollY", this._onScrollY, this); + + this._scrollerParent.add(paneScroller); + } + } + + // Update all meta columns + for (var i = 0; i < scrollerArr.length; i++) { + var paneScroller = scrollerArr[i]; + var isLast = (i == (scrollerArr.length - 1)); + + // Set the right header height + paneScroller.getHeader().setHeight(this.getHeaderCellHeight()); + + // Put the _columnVisibilityBt in the top right corner of the last meta column + paneScroller.setTopRightWidget(isLast ? this._columnVisibilityBt : null); + } + + this._updateScrollerWidths(); + this._updateScrollBarVisibility(); + + return true; +} + + +// property modifier +qx.Proto._modifyFocusCellOnMouseMove = function(propValue, propOldValue, propData) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i].setFocusCellOnMouseMove(propValue); + } + return true; +}; + + +// property modifier +qx.Proto._modifyKeepFirstVisibleRowComplete = function(propValue, propOldValue, propData) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i]._onKeepFirstVisibleRowCompleteChanged(); + } + return true; +}; + + +// property modifier +qx.Proto._modifyHeaderCellHeight = function(propValue, propOldValue, propData) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i].getHeader().setHeight(propValue); + } + return true; +}; + + +/** + * Returns the selection manager. + * + * @return {SelectionManager} the selection manager. + */ +qx.Proto._getSelectionManager = function() { + return this._selectionManager; +}; + + +/** + * Returns an array containing all TablePaneScrollers in this table. + * + * @return {TablePaneScroller[]} all TablePaneScrollers in this table. + */ +qx.Proto._getPaneScrollerArr = function() { + return this._scrollerParent.getChildren(); +} + + +/** + * Returns a TablePaneScroller of this table. + * + * @param metaColumn {int} the meta column to get the TablePaneScroller for. + * @return {TablePaneScroller} the TablePaneScroller. + */ +qx.Proto.getPaneScroller = function(metaColumn) { + return this._getPaneScrollerArr()[metaColumn]; +} + + +/** + * Cleans up the meta columns. + * + * @param fromMetaColumn {int} the first meta column to clean up. All following + * meta columns will be cleaned up, too. All previous meta columns will + * stay unchanged. If 0 all meta columns will be cleaned up. + */ +qx.Proto._cleanUpMetaColumns = function(fromMetaColumn) { + var scrollerArr = this._getPaneScrollerArr(); + if (scrollerArr != null) { + for (var i = scrollerArr.length - 1; i >= fromMetaColumn; i--) { + var paneScroller = scrollerArr[i]; + paneScroller.removeEventListener("changeScrollY", this._onScrollY, this); + this._scrollerParent.remove(paneScroller); + paneScroller.dispose(); + } + } +} + + +/** + * Event handler. Called when the selection has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onSelectionChanged = function(evt) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i]._onSelectionChanged(evt); + } + + this._updateStatusBar(); +} + + +/** + * Event handler. Called when the table model meta data has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onTableModelMetaDataChanged = function(evt) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i]._onTableModelMetaDataChanged(evt); + } + + this._updateStatusBar(); +} + + +/** + * Event handler. Called when the table model data has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onTableModelDataChanged = function(evt) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i]._onTableModelDataChanged(evt); + } + + var rowCount = this.getTableModel().getRowCount(); + if (rowCount != this._lastRowCount) { + this._lastRowCount = rowCount; + + this._updateScrollBarVisibility(); + this._updateStatusBar(); + } +}; + + +/** + * Event handler. Called when a TablePaneScroller has been scrolled vertically. + * + * @param evt {Map} the event. + */ +qx.Proto._onScrollY = function(evt) { + if (! this._internalChange) { + this._internalChange = true; + + // Set the same scroll position to all meta columns + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i].setScrollY(evt.getData()); + } + + this._internalChange = false; + } +} + + +/** + * Event handler. Called when a key was pressed. + * + * @param evt {Map} the event. + */ +qx.Proto._onkeydown = function(evt) { + var identifier = evt.getKeyIdentifier(); + + var consumed = false; + var oldFocusedRow = this._focusedRow; + if (this.isEditing()) { + // Editing mode + if (evt.getModifiers() == 0) { + consumed = true; + switch (identifier) { + case "Enter": + this.stopEditing(); + var oldFocusedRow = this._focusedRow; + this.moveFocusedCell(0, 1); + if (this._focusedRow != oldFocusedRow) { + this.startEditing(); + } + break; + case "Escape": + this.cancelEditing(); + this.focus(); + break; + default: + consumed = false; + break; + } + } + } else { + // No editing mode + + // Handle keys that are independant from the modifiers + consumed = true; + switch (identifier) { + case "Home": + this.setFocusedCell(this._focusedCol, 0, true); + break; + case "End": + var rowCount = this.getTableModel().getRowCount(); + this.setFocusedCell(this._focusedCol, rowCount - 1, true); + break; + default: + consumed = false; + break; + } + + // Handle keys that depend on modifiers + if (evt.getModifiers() == 0) { + consumed = true; + switch (identifier) { + case "F2": + case "Enter": + this.startEditing(); + break; + default: + consumed = false; + break; + } + } else if (evt.getCtrlKey()) { + consumed = true; + switch (identifier) { + case "A": // Ctrl + A + var rowCount = this.getTableModel().getRowCount(); + if (rowCount > 0) { + this.getSelectionModel().setSelectionInterval(0, rowCount - 1); + } + break; + default: + consumed = false; + break; + } + } + } + + if (oldFocusedRow != this._focusedRow) { + // The focus moved -> Let the selection manager handle this event + this._selectionManager.handleMoveKeyDown(this._focusedRow, evt); + } + + if (consumed) { + evt.preventDefault(); + evt.stopPropagation(); + } +}; + + +qx.Proto._onkeypress = function(evt) +{ + if (this.isEditing()) { return } + // No editing mode + var oldFocusedRow = this._focusedRow; + var consumed = true; + + // Handle keys that are independant from the modifiers + var identifier = evt.getKeyIdentifier(); + switch (identifier) { + case "Space": + this._selectionManager.handleSelectKeyDown(this._focusedRow, evt); + break; + + case "Left": + this.moveFocusedCell(-1, 0); + break; + + case "Right": + this.moveFocusedCell(1, 0); + break; + + case "Up": + this.moveFocusedCell(0, -1); + break; + + case "Down": + this.moveFocusedCell(0, 1); + break; + + case "PageUp": + case "PageDown": + var scroller = this.getPaneScroller(0); + var pane = scroller.getTablePane(); + var rowCount = pane.getVisibleRowCount() - 1; + var rowHeight = this.getRowHeight(); + var direction = (identifier == "PageUp") ? -1 : 1; + scroller.setScrollY(scroller.getScrollY() + direction * rowCount * rowHeight); + this.moveFocusedCell(0, direction * rowCount); + break; + + default: + consumed = false; + } + if (oldFocusedRow != this._focusedRow) { + // The focus moved -> Let the selection manager handle this event + this._selectionManager.handleMoveKeyDown(this._focusedRow, evt); + } + + if (consumed) { + evt.preventDefault(); + evt.stopPropagation(); + } +}; + + +/** + * Event handler. Called when the table gets the focus. + */ +qx.Proto._onFocusChanged = function(evt) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i]._onFocusChanged(evt); + } +}; + + +/** + * Event handler. Called when the visibility of a column has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onColVisibilityChanged = function(evt) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i]._onColVisibilityChanged(evt); + } + + this._updateScrollerWidths(); + this._updateScrollBarVisibility(); +} + + +/** + * Event handler. Called when the width of a column has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onColWidthChanged = function(evt) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i]._onColWidthChanged(evt); + } + + this._updateScrollerWidths(); + this._updateScrollBarVisibility(); +} + + +/** + * Event handler. Called when the column order has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onColOrderChanged = function(evt) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i]._onColOrderChanged(evt); + } + + // A column may have been moved between meta columns + this._updateScrollerWidths(); + this._updateScrollBarVisibility(); +} + + +/** + * Gets the TablePaneScroller at a certain x position in the page. If there is + * no TablePaneScroller at this postion, null is returned. + * + * @param pageX {int} the position in the page to check (in pixels). + * @return {TablePaneScroller} the TablePaneScroller or null. + * + * @see TablePaneScrollerPool + */ +qx.Proto.getTablePaneScrollerAtPageX = function(pageX) { + var metaCol = this._getMetaColumnAtPageX(pageX); + return (metaCol != -1) ? this.getPaneScroller(metaCol) : null; +} + + +/** + * Sets the currently focused cell. + * + * @param col {int} the model index of the focused cell's column. + * @param row {int} the model index of the focused cell's row. + * @param scrollVisible {boolean ? false} whether to scroll the new focused cell + * visible. + * + * @see TablePaneScrollerPool + */ +qx.Proto.setFocusedCell = function(col, row, scrollVisible) { + if (!this.isEditing() && (col != this._focusedCol || row != this._focusedRow)) { + this._focusedCol = col; + this._focusedRow = row; + + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i].setFocusedCell(col, row); + } + + if (scrollVisible) { + this.scrollCellVisible(col, row); + } + } +} + + +/** + * Returns the column of the currently focused cell. + * + * @return {int} the model index of the focused cell's column. + */ +qx.Proto.getFocusedColumn = function() { + return this._focusedCol; +}; + + +/** + * Returns the row of the currently focused cell. + * + * @return {int} the model index of the focused cell's column. + */ +qx.Proto.getFocusedRow = function() { + return this._focusedRow; +}; + + +/** + * Moves the focus. + * + * @param deltaX {int} The delta by which the focus should be moved on the x axis. + * @param deltaY {int} The delta by which the focus should be moved on the y axis. + */ +qx.Proto.moveFocusedCell = function(deltaX, deltaY) { + var col = this._focusedCol; + var row = this._focusedRow; + + if (deltaX != 0) { + var columnModel = this.getTableColumnModel(); + var x = columnModel.getVisibleX(col); + var colCount = columnModel.getVisibleColumnCount(); + x = qx.lang.Number.limit(x + deltaX, 0, colCount - 1); + col = columnModel.getVisibleColumnAtX(x); + } + + if (deltaY != 0) { + var tableModel = this.getTableModel(); + row = qx.lang.Number.limit(row + deltaY, 0, tableModel.getRowCount() - 1); + } + + this.setFocusedCell(col, row, true); +} + + +/** + * Scrolls a cell visible. + * + * @param col {int} the model index of the column the cell belongs to. + * @param row {int} the model index of the row the cell belongs to. + */ +qx.Proto.scrollCellVisible = function(col, row) { + var columnModel = this.getTableColumnModel(); + var x = columnModel.getVisibleX(col); + + var metaColumn = this._getMetaColumnAtColumnX(x); + if (metaColumn != -1) { + this.getPaneScroller(metaColumn).scrollCellVisible(col, row); + } +} + + +/** + * Returns whether currently a cell is editing. + * + * @return whether currently a cell is editing. + */ +qx.Proto.isEditing = function() { + if (this._focusedCol != null) { + var x = this.getTableColumnModel().getVisibleX(this._focusedCol); + var metaColumn = this._getMetaColumnAtColumnX(x); + return this.getPaneScroller(metaColumn).isEditing(); + } +} + + +/** + * Starts editing the currently focused cell. Does nothing if already editing + * or if the column is not editable. + * + * @return {boolean} whether editing was started + */ +qx.Proto.startEditing = function() { + if (this._focusedCol != null) { + var x = this.getTableColumnModel().getVisibleX(this._focusedCol); + var metaColumn = this._getMetaColumnAtColumnX(x); + return this.getPaneScroller(metaColumn).startEditing(); + } + return false; +} + + +/** + * Stops editing and writes the editor's value to the model. + */ +qx.Proto.stopEditing = function() { + if (this._focusedCol != null) { + var x = this.getTableColumnModel().getVisibleX(this._focusedCol); + var metaColumn = this._getMetaColumnAtColumnX(x); + this.getPaneScroller(metaColumn).stopEditing(); + } +} + + +/** + * Stops editing without writing the editor's value to the model. + */ +qx.Proto.cancelEditing = function() { + if (this._focusedCol != null) { + var x = this.getTableColumnModel().getVisibleX(this._focusedCol); + var metaColumn = this._getMetaColumnAtColumnX(x); + this.getPaneScroller(metaColumn).cancelEditing(); + } +} + + +/** + * Gets the meta column at a certain x position in the page. If there is no + * meta column at this postion, -1 is returned. + * + * @param pageX {int} the position in the page to check (in pixels). + * @return {int} the index of the meta column or -1. + */ +qx.Proto._getMetaColumnAtPageX = function(pageX) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + var elem = scrollerArr[i].getElement(); + if (pageX >= qx.dom.Location.getPageBoxLeft(elem) + && pageX <= qx.dom.Location.getPageBoxRight(elem)) + { + return i; + } + } + + return -1; +} + + +/** + * Returns the meta column a column is shown in. If the column is not shown at + * all, -1 is returned. + * + * @param visXPos {int} the visible x position of the column. + * @return {int} the meta column the column is shown in. + */ +qx.Proto._getMetaColumnAtColumnX = function(visXPos) { + var metaColumnCounts = this.getMetaColumnCounts(); + var rightXPos = 0; + for (var i = 0; i < metaColumnCounts.length; i++) { + var counts = metaColumnCounts[i]; + rightXPos += counts; + + if (counts == -1 || visXPos < rightXPos) { + return i; + } + } + + return -1; +} + + +/** + * Updates the text shown in the status bar. + */ +qx.Proto._updateStatusBar = function() { + if (this.getStatusBarVisible()) { + var selectedRowCount = this.getSelectionModel().getSelectedCount(); + var rowCount = this.getTableModel().getRowCount(); + + var text; + if (selectedRowCount == 0) { + text = rowCount + ((rowCount == 1) ? " row" : " rows"); + } else { + text = selectedRowCount + " of " + rowCount + + ((rowCount == 1) ? " row" : " rows") + " selected"; + } + this._statusBar.setHtml(text); + } +} + + +/** + * Updates the widths of all scrollers. + */ +qx.Proto._updateScrollerWidths = function() { +/* no longer needed, per Til, and removing it does not appear to add problems. + * qx.ui.core.Widget.flushGlobalQueues(); + */ + + // Give all scrollers except for the last one the wanted width + // (The last one has a flex with) + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + var isLast = (i == (scrollerArr.length - 1)); + var width = isLast ? "1*" : scrollerArr[i].getTablePaneModel().getTotalWidth(); + scrollerArr[i].setWidth(width); + } +} + + +/** + * Updates the visibility of the scrollbars in the meta columns. + */ +qx.Proto._updateScrollBarVisibility = function() { + if (this.isSeeable()) { + var horBar = qx.ui.table.TablePaneScroller.HORIZONTAL_SCROLLBAR; + var verBar = qx.ui.table.TablePaneScroller.VERTICAL_SCROLLBAR; + var scrollerArr = this._getPaneScrollerArr(); + + // Check which scroll bars are needed + var horNeeded = false; + var verNeeded = false; + for (var i = 0; i < scrollerArr.length; i++) { + var isLast = (i == (scrollerArr.length - 1)); + + // Only show the last vertical scrollbar + var bars = scrollerArr[i].getNeededScrollBars(horNeeded, !isLast); + + if (bars & horBar) { + horNeeded = true; + } + if (isLast && (bars & verBar)) { + verNeeded = true; + } + } + + // Set the needed scrollbars + for (var i = 0; i < scrollerArr.length; i++) { + var isLast = (i == (scrollerArr.length - 1)); + + // Only show the last vertical scrollbar + scrollerArr[i].setHorizontalScrollBarVisible(horNeeded); + scrollerArr[i].setVerticalScrollBarVisible(isLast && verNeeded); + } + } +} + + +/** + * Event handler. Called when the column visibiliy button was executed. + */ +qx.Proto._onColumnVisibilityBtExecuted = function() { + if ((this._columnVisibilityMenuCloseTime == null) + || (new Date().getTime() > this._columnVisibilityMenuCloseTime + 200)) + { + this._toggleColumnVisibilityMenu(); + } +} + + +/** + * Toggels the visibility of the menu used to change the visibility of columns. + */ +qx.Proto._toggleColumnVisibilityMenu = function() { + if (this._columnVisibilityMenu == null || !this._columnVisibilityMenu.isSeeable()) { + // Show the menu + + // Create the new menu + var menu = new qx.ui.menu.Menu; + + menu.addEventListener("disappear", function(evt) { + this._columnVisibilityMenuCloseTime = new Date().getTime(); + }, this); + + var tableModel = this.getTableModel(); + var columnModel = this.getTableColumnModel(); + for (var x = 0; x < columnModel.getOverallColumnCount(); x++) { + var col = columnModel.getOverallColumnAtX(x); + var visible = columnModel.isColumnVisible(col); + var cmd = { col:col } + var bt = new qx.ui.menu.CheckBox(tableModel.getColumnName(col), null, visible); + + var handler = this._createColumnVisibilityCheckBoxHandler(col); + bt._handler = handler; + bt.addEventListener("execute", handler, this); + + menu.add(bt); + } + + menu.setParent(this.getTopLevelWidget()); + + this._columnVisibilityMenu = menu; + + // Show the menu + var btElem = this._columnVisibilityBt.getElement(); + menu.setRestrictToPageOnOpen(false); + menu.setTop(qx.dom.Location.getClientBoxBottom(btElem)); + menu.setLeft(-1000); + + // NOTE: We have to show the menu in a timeout, otherwise it won't be shown + // at all. + window.setTimeout(function() { + menu.show(); + qx.ui.core.Widget.flushGlobalQueues(); + + menu.setLeft(qx.dom.Location.getClientBoxRight(btElem) - menu.getOffsetWidth()); + qx.ui.core.Widget.flushGlobalQueues(); + }, 0); + } else { + // hide the menu + menu.hide(); + this._cleanupColumnVisibilityMenu(); + } +} + + +/** + * Cleans up the column visibility menu. + */ +qx.Proto._cleanupColumnVisibilityMenu = function() { + if (this._columnVisibilityMenu != null && ! this._columnVisibilityMenu.getDisposed()) { + this._columnVisibilityMenu.dispose(); + this._columnVisibilityMenu = null; + } +} + + +/** + * Creates a handler for a check box of the column visibility menu. + * + * @param col {int} the model index of column to create the handler for. + */ +qx.Proto._createColumnVisibilityCheckBoxHandler = function(col) { + return function(evt) { + var columnModel = this.getTableColumnModel(); + columnModel.setColumnVisible(col, !columnModel.isColumnVisible(col)); + } +} + + +/** + * Sets the width of a column. + * + * @param col {int} the model index of column. + * @param width {int} the new width in pixels. + */ +qx.Proto.setColumnWidth = function(col, width) { + this.getTableColumnModel().setColumnWidth(col, width); +} + + +// overridden +qx.Proto._changeInnerWidth = function(newValue, oldValue) { + var self = this; + window.setTimeout(function() { + self._updateScrollBarVisibility(); + qx.ui.core.Widget.flushGlobalQueues(); + }, 0); + + return qx.ui.layout.VerticalBoxLayout.prototype._changeInnerWidth.call(this, newValue, oldValue); +} + + +// overridden +qx.Proto._changeInnerHeight = function(newValue, oldValue) { + var self = this; + window.setTimeout(function() { + self._updateScrollBarVisibility(); + qx.ui.core.Widget.flushGlobalQueues(); + }, 0); + + return qx.ui.layout.VerticalBoxLayout.prototype._changeInnerHeight.call(this, newValue, oldValue); +} + + +// overridden +qx.Proto._afterAppear = function() { + qx.ui.layout.VerticalBoxLayout.prototype._afterAppear.call(this); + + this._updateScrollBarVisibility(); +} + + +// overridden +qx.Proto.dispose = function() { + if (this.getDisposed()) { + return true; + } + + if (this._tableModel) { + this._tableModel.removeEventListener(qx.ui.table.TableModel.EVENT_TYPE_META_DATA_CHANGED, this._onTableModelMetaDataChanged, this); + } + + this._columnVisibilityBt.removeEventListener("execute", this._onColumnVisibilityBtExecuted, this); + this._columnVisibilityBt.dispose(); + + this._cleanupColumnVisibilityMenu(); + + this._cleanUpMetaColumns(0); + + var selectionModel = this.getSelectionModel(); + if (selectionModel != null) { + selectionModel.removeEventListener("changeSelection", this._onSelectionChanged, this); + } + + var tableModel = this.getTableModel(); + if (tableModel != null) { + tableModel.removeEventListener(qx.ui.table.TableModel.EVENT_TYPE_META_DATA_CHANGED, this._onTableModelMetaDataChanged, this); + tableModel.removeEventListener(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED, this._onTableModelDataChanged, this); + } + + var tableColumnModel = this.getTableColumnModel(); + if (tableColumnModel) { + tableColumnModel.removeEventListener("visibilityChanged", this._onColVisibilityChanged, this); + tableColumnModel.removeEventListener("widthChanged", this._onColWidthChanged, this); + tableColumnModel.removeEventListener("orderChanged", this._onColOrderChanged, this); + } + + this.removeEventListener("keydown", this._onkeydown); + this.removeEventListener("keypress", this._onkeypress); + + return qx.ui.layout.VerticalBoxLayout.prototype.dispose.call(this); +} |