/** * A class which encapsulates a range of columns defining a selection in a grid. * @since 5.1.0 */Ext.define('Ext.grid.selection.Columns', { extend: 'Ext.grid.selection.Selection', type: 'columns', /** * @property {Boolean} isColumns * This property indicates the this selection represents selected columns. * @readonly */ isColumns: true, //------------------------------------------------------------------------- // Base Selection API clone: function() { var me = this, result = new me.self(me.view), columns = me.selectedColumns; if (columns) { result.selectedColumns = Ext.Array.slice(columns); } return result; }, eachRow: function (fn, scope) { var columns = this.selectedColumns; if (columns && columns.length) { this.view.dataSource.each(fn, scope || this); } }, eachColumn: function (fn, scope) { var me = this, view = me.view, columns = me.selectedColumns, len, i, context = new Ext.grid.CellContext(view); if (columns) { len = columns.length; for (i = 0; i < len; i++) { context.setColumn(columns[i]); if (fn.call(scope || me, context.column, context.colIdx) === false) { return false; } } } }, eachCell: function (fn, scope) { var me = this, view = me.view, columns = me.selectedColumns, len, i, context = new Ext.grid.CellContext(view); if (columns) { len = columns.length; // Use Store#each instead of copying the entire dataset into an array and iterating that. view.dataSource.each(function(record) { context.setRow(record); for (i = 0; i < len; i++) { context.setColumn(columns[i]); if (fn.call(scope || me, context, context.colIdx, context.rowIdx) === false) { return false; } } }); } }, //------------------------------------------------------------------------- // Methods unique to this type of Selection /** * Returns `true` if the passed {@link Ext.grid.column.Column column} is selected. * @param {Ext.grid.column.Column} column The column to test. * @return {Boolean} `true` if the passed {@link Ext.grid.column.Column column} is selected. */ contains: function(column) { var selectedColumns = this.selectedColumns; if (column && column.isColumn && selectedColumns && selectedColumns.length) { return Ext.Array.contains(selectedColumns, column); } return false; }, /** * Returns the number of columns selected. * @return {Number} The number of columns selected. */ getCount: function() { var selectedColumns = this.selectedColumns; return selectedColumns ? selectedColumns.length : 0; }, /** * Returns the columns selected. * @return {Ext.grid.column.Column[]} The columns selected. */ getColumns: function() { return this.selectedColumns || []; }, //------------------------------------------------------------------------- privates: { /** * Adds the passed Column to the selection. * @param {Ext.grid.column.Column} column * @private */ add: function(column) { //<debug> if (!column.isColumn) { Ext.raise('Column selection must be passed a grid Column header object'); } //</debug> Ext.Array.include((this.selectedColumns || (this.selectedColumns = [])), column); this.refreshColumns(column); }, /** * @private */ clear: function() { var me = this, prevSelection = me.selectedColumns; if (prevSelection && prevSelection.length) { me.selectedColumns = []; me.refreshColumns.apply(me, prevSelection); } me.setRangeStart(null); }, setRangeStart: function(startColumn) { var me = this, prevSelection = me.getColumns(); me.startColumn = startColumn; if (startColumn != null) { me.selectedColumns = [startColumn]; prevSelection.push(startColumn); me.refreshColumns.apply(me, prevSelection); } }, setRangeEnd: function(endColumn) { var me = this, prevSelection = me.getColumns(), colManager = this.view.ownerGrid.getVisibleColumnManager(), columns = colManager.getColumns(), start = colManager.indexOf(me.startColumn), end = colManager.indexOf(endColumn), i; // Allow looping through columns if (end < start) { i = start; start = end; end = i; } me.selectedColumns = []; for (i = start; i <= end; i++) { me.selectedColumns.push(columns[i]); prevSelection.push(columns[i]); } me.refreshColumns.apply(me, prevSelection); }, /** * @return {Boolean} * @private */ isAllSelected: function() { var selectedColumns = this.selectedColumns; // All selected means all columns, across both views if we are in a locking assembly. return selectedColumns && selectedColumns.length === this.view.ownerGrid.getVisibleColumnManager().getColumns().length; }, /** * @private */ refreshColumns: function(column) { var me = this, view = me.view, rows = view.all, rowIdx, columns = arguments, len = columns.length, colIdx, cellContext = new Ext.grid.CellContext(view), selected = []; if (view.rendered) { for (colIdx = 0; colIdx < len; colIdx++) { selected[colIdx] = me.contains(columns[colIdx]); } for (rowIdx = rows.startIndex; rowIdx <= rows.endIndex; rowIdx++) { cellContext.setRow(rowIdx); for (colIdx = 0; colIdx < len; colIdx++) { // Note colIdx is not the column's visible index. setColumn must be passed the column object cellContext.setColumn(columns[colIdx]); if (selected[colIdx]) { view.onCellSelect(cellContext); } else { view.onCellDeselect(cellContext); } } } } }, /** * Removes the passed Column from the selection. * @param {Ext.grid.column.Column} column * @private */ remove: function(column) { //<debug> if (!column.isColumn) { Ext.raise('Column selection must be passed a grid Column header object'); } //</debug> if (this.selectedColumns) { Ext.Array.remove(this.selectedColumns, column); // Might be being called because of column removal/hiding. // In which case the view will have selected cells removed, so no refresh needed. if (column.getView() && column.isVisible()) { this.refreshColumns(column); } } }, /** * @private */ selectAll: function () { var me = this; me.clear(); me.selectedColumns = me.view.getSelectionModel().lastContiguousColumnRange = me.view.getVisibleColumnManager().getColumns(); me.refreshColumns.apply(me, me.selectedColumns); }, extendRange: function(extensionVector) { var me = this, columns = me.view.getVisibleColumnManager().getColumns(), i; for (i = extensionVector.start.colIdx; i <= extensionVector.end.colIdx; i++) { me.add(columns[i]); } }, reduceRange: function(extensionVector) { var me = this, columns = me.view.getVisibleColumnManager().getColumns(), startIdx = extensionVector.start.colIdx, endIdx = extensionVector.end.colIdx, reduceTo = Math.abs(startIdx - endIdx) + 1, diff = me.selectedColumns.length - reduceTo, i; for (i = diff; i > 0; i--) { me.remove(columns[endIdx + i]); } }, onSelectionFinish: function() { var me = this, range = me.getContiguousSelection(); if (range) { me.view.getSelectionModel().onSelectionFinish(me, new Ext.grid.CellContext(me.view).setPosition(0, range[0]), new Ext.grid.CellContext(me.view).setPosition(me.view.dataSource.getCount() - 1, range[1])); } else { me.view.getSelectionModel().onSelectionFinish(me); } }, /** * @return {Array} `[startColumn, endColumn]` if the selection represents a visually contiguous set of columns. * The SelectionReplicator is only enabled if there is a contiguous block. * @private */ getContiguousSelection: function() { var selection = Ext.Array.sort(this.getColumns(), function(c1, c2) { // Use index *in ownerGrid* so that a locking assembly can order columns correctly return c1.getView().ownerGrid.getVisibleColumnManager().indexOf(c1) - c2.getView().ownerGrid.getVisibleColumnManager().indexOf(c2); }), len = selection.length, i; if (len) { for (i = 1; i < len; i++) { if (selection[i].getVisibleIndex() !== selection[i - 1].getVisibleIndex() + 1) { return false; } } return [selection[0], selection[len - 1]]; } } }});