loleaflet/src/control/Control.ColumnHeader.js | 21 +++- loleaflet/src/control/Control.Header.js | 30 ++++++ loleaflet/src/control/Control.RowHeader.js | 21 +++- loleaflet/src/control/Control.Scroll.js | 4 loleaflet/src/layer/CalcGridLines.js | 15 ++- loleaflet/src/layer/tile/CalcTileLayer.js | 112 ++++++++++++++++++++------ loleaflet/src/map/Map.js | 2 7 files changed, 160 insertions(+), 45 deletions(-)
New commits: commit dc862d358522315c857044debf11eeceb1fc936b Author: Dennis Francis <dennis.fran...@collabora.com> AuthorDate: Fri May 15 08:12:03 2020 +0530 Commit: Dennis Francis <dennis.fran...@collabora.com> CommitDate: Sun Jul 5 09:57:59 2020 +0200 use SheetGeometry data to draw headers/gridlines if enabled Change-Id: If146512a50c24f5fd81f6df7e0a3746f70bf21f9 Reviewed-on: https://gerrit.libreoffice.org/c/online/+/97944 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Dennis Francis <dennis.fran...@collabora.com> diff --git a/loleaflet/src/control/Control.ColumnHeader.js b/loleaflet/src/control/Control.ColumnHeader.js index a2846f78e..254a4df41 100644 --- a/loleaflet/src/control/Control.ColumnHeader.js +++ b/loleaflet/src/control/Control.ColumnHeader.js @@ -193,7 +193,7 @@ L.Control.ColumnHeader = L.Control.Header.extend({ }, _updateColumnHeader: function () { - this._map._docLayer.requestViewRowColumnData({x: this._map._getTopLeftPoint().x, y: 0, offset: {x: undefined, y: 0}}); + this._map._docLayer.refreshViewData({x: this._map._getTopLeftPoint().x, y: 0, offset: {x: undefined, y: 0}}); }, drawHeaderEntry: function (entry, isOver, isHighlighted, isCurrent) { @@ -376,8 +376,10 @@ L.Control.ColumnHeader = L.Control.Header.extend({ }, viewRowColumnHeaders: function (e) { - if (e.data.columns && e.data.columns.length > 0) { - this.fillColumns(e.data.columns, e.data.columnGroups, e.converter, e.context); + var dataInEvent = (e.data && e.data.columns && e.data.columns.length > 0); + if (dataInEvent || e.updatecolumns) { + dataInEvent ? this.fillColumns(e.data.columns, e.data.columnGroups, e.converter, e.context) : + this.fillColumns(undefined, undefined, e.converter, e.context); this._onUpdateCurrentColumn(e.cursor); if (e.selection && e.selection.hasSelection) { this._onUpdateSelection(e.selection); @@ -389,7 +391,7 @@ L.Control.ColumnHeader = L.Control.Header.extend({ }, fillColumns: function (columns, colGroups, converter, context) { - if (columns.length < 2) + if (columns && columns.length < 2) return; var canvas = this._canvas; @@ -413,21 +415,28 @@ L.Control.ColumnHeader = L.Control.Header.extend({ this._lastMouseOverIndex = undefined; } + var sheetGeometry = this._map._docLayer.sheetGeometry; + var columnsGeometry = sheetGeometry ? sheetGeometry.getColumnsGeometry() : undefined; + // create data structure for column widths - this._tickMap = new L.Control.Header.GapTickMap(this._map, columns); + this._tickMap = new L.Control.Header.GapTickMap(this._map, columns, columnsGeometry); this._startOffset = this._tickMap.getStartOffset(); // setup conversion routine this.converter = L.Util.bind(converter, context); // create group array - this._groupLevels = parseInt(columns[0].groupLevels); + this._groupLevels = columns ? parseInt(columns[0].groupLevels): + sheetGeometry.getColumnGroupLevels(); this._groups = this._groupLevels ? new Array(this._groupLevels) : null; // collect group controls data if (colGroups !== undefined && this._groups) { this._collectGroupsData(colGroups); } + else if (sheetGeometry) { + this._collectGroupsData(sheetGeometry.getColumnGroupsDataInView()); + } if (this._groups) { this.resize(this._computeOutlineWidth() + this._borderWidth + this._headerHeight); diff --git a/loleaflet/src/control/Control.Header.js b/loleaflet/src/control/Control.Header.js index 5aeac06da..3ef4bb2e0 100644 --- a/loleaflet/src/control/Control.Header.js +++ b/loleaflet/src/control/Control.Header.js @@ -804,7 +804,35 @@ L.Control.Header.colHeaderHeight = undefined; */ L.Control.Header.GapTickMap = L.Class.extend({ - initialize: function (map, ticks) { + initialize: function (map, ticks, dimensionGeometry) { + + if (dimensionGeometry) { + // Until .uno:ViewRowColumnHeaders is not phased out, we need to live with + // GapTickMap datastructure to avoid an invasive refactoring. + // L.SheetGeometry and L.SheetDimension datastructures can directly provide + // position/size of any row/column intuitively without using unnecessary + // terminologies like (1-based) Gap and (0-based) Tick. + var dimrange = dimensionGeometry.getViewElementRange(); + var start = Math.max(0, dimrange.start - 2); + var startData = dimensionGeometry.getElementData(start); + var startText = start ? start + 1 : 0; + var endText = Math.min(dimensionGeometry.getMaxIndex(), dimrange.end + 2) + 1; + + this._minTickIdx = startText; + this._maxTickIdx = endText; + this._startOffset = start ? startData.startpos + startData.size : 0; + this._tilePixelScale = 1; // We already have everything in css px. + + ticks = start ? [] : [0]; + dimensionGeometry.forEachInRange(start, + this._maxTickIdx - 1, function (idx, data) { + ticks[idx + 1] = data.startpos + data.size; + }); + + this._ticks = ticks; + + return; + } var gapSize; this._ticks = []; diff --git a/loleaflet/src/control/Control.RowHeader.js b/loleaflet/src/control/Control.RowHeader.js index afbba3c45..820f2205b 100644 --- a/loleaflet/src/control/Control.RowHeader.js +++ b/loleaflet/src/control/Control.RowHeader.js @@ -186,7 +186,7 @@ L.Control.RowHeader = L.Control.Header.extend({ }, _updateRowHeader: function () { - this._map._docLayer.requestViewRowColumnData({x: 0, y: this._map._getTopLeftPoint().y, offset: {x: 0, y: undefined}}); + this._map._docLayer.refreshViewData({x: 0, y: this._map._getTopLeftPoint().y, offset: {x: 0, y: undefined}}); }, drawHeaderEntry: function (entry, isOver, isHighlighted, isCurrent) { @@ -365,8 +365,10 @@ L.Control.RowHeader = L.Control.Header.extend({ }, viewRowColumnHeaders: function (e) { - if (e.data.rows && e.data.rows.length) { - this.fillRows(e.data.rows, e.data.rowGroups, e.converter, e.context); + var dataInEvent = (e.data && e.data.rows && e.data.rows.length); + if (dataInEvent || e.updaterows) { + dataInEvent ? this.fillRows(e.data.rows, e.data.rowGroups, e.converter, e.context) : + this.fillRows(undefined, undefined, e.converter, e.context); this._onUpdateCurrentRow(e.cursor); if (e.selection && e.selection.hasSelection) { this._onUpdateSelection(e.selection); @@ -378,7 +380,7 @@ L.Control.RowHeader = L.Control.Header.extend({ }, fillRows: function (rows, rowGroups, converter, context) { - if (rows.length < 2) + if (rows && rows.length < 2) return; var canvas = this._canvas; @@ -394,21 +396,28 @@ L.Control.RowHeader = L.Control.Header.extend({ this._lastMouseOverIndex = undefined; } + var sheetGeometry = this._map._docLayer.sheetGeometry; + var rowsGeometry = sheetGeometry ? sheetGeometry.getRowsGeometry() : undefined; + // create data structure for row heights - this._tickMap = new L.Control.Header.GapTickMap(this._map, rows); + this._tickMap = new L.Control.Header.GapTickMap(this._map, rows, rowsGeometry); this._startOffset = this._tickMap.getStartOffset(); // setup conversion routine this.converter = L.Util.bind(converter, context); // create group array - this._groupLevels = parseInt(rows[0].groupLevels); + this._groupLevels = rows ? parseInt(rows[0].groupLevels) : + sheetGeometry.getRowGroupLevels(); this._groups = this._groupLevels ? new Array(this._groupLevels) : null; // collect group controls data if (rowGroups !== undefined && this._groups) { this._collectGroupsData(rowGroups); } + else if (sheetGeometry) { + this._collectGroupsData(sheetGeometry.getRowGroupsDataInView()); + } if (this._groups) { this.resize(this._computeOutlineWidth() + this._borderWidth + this._headerWidth); diff --git a/loleaflet/src/control/Control.Scroll.js b/loleaflet/src/control/Control.Scroll.js index e3f9cf4dc..cb323e1c7 100644 --- a/loleaflet/src/control/Control.Scroll.js +++ b/loleaflet/src/control/Control.Scroll.js @@ -114,7 +114,7 @@ L.Control.Scroll = L.Control.extend({ return; } - this._map._docLayer.requestViewRowColumnData({ x: newLeft, y: newTop, offset: offset}); + this._map._docLayer.refreshViewData({ x: newLeft, y: newTop, offset: offset}); this._prevScrollY = newTop; this._prevScrollX = newLeft; @@ -267,7 +267,7 @@ L.Control.Scroll = L.Control.extend({ offset.y = 1; } if (e.updateHeaders && this._map._docLayer._docType === 'spreadsheet') { - this._map._docLayer.requestViewRowColumnData({x: e.x, y: e.y, offset: offset}); + this._map._docLayer.refreshViewData({x: e.x, y: e.y, offset: offset}); } this._map.fire('scrolloffset', offset); this._ignoreScroll = null; diff --git a/loleaflet/src/layer/CalcGridLines.js b/loleaflet/src/layer/CalcGridLines.js index 4b4e58d3a..37492b606 100644 --- a/loleaflet/src/layer/CalcGridLines.js +++ b/loleaflet/src/layer/CalcGridLines.js @@ -78,8 +78,13 @@ L.CalcGridLines = L.LayerGroup.extend({ // into map coordinate units var pixelToMapUnitRatio = this._map.options.crs.scale(this._map.getZoom()); - if (ev.data.columns && ev.data.columns.length) { - ticks = new L.Control.Header.GapTickMap(this._map, ev.data.columns); + var colDataInEvent = ev.data && ev.data.columns && ev.data.columns.length; + var rowDataInEvent = ev.data && ev.data.rows && ev.data.rows.length; + + if (colDataInEvent || ev.updatecolumns) { + var columnsData = colDataInEvent ? ev.data.columns : undefined; + var columnsGeometry = colDataInEvent ? undefined : this._map._docLayer.sheetGeometry.getColumnsGeometry(); + ticks = new L.Control.Header.GapTickMap(this._map, columnsData, columnsGeometry); this._colLines.clearLayers(); ticks.forEachTick(function(idx, pos) { @@ -92,8 +97,10 @@ L.CalcGridLines = L.LayerGroup.extend({ }.bind(this)); } - if (ev.data.rows && ev.data.rows.length) { - ticks = new L.Control.Header.GapTickMap(this._map, ev.data.rows); + if (rowDataInEvent || ev.updaterows) { + var rowsData = rowDataInEvent ? ev.data.rows : undefined; + var rowsGeometry = rowDataInEvent ? undefined : this._map._docLayer.sheetGeometry.getRowsGeometry(); + ticks = new L.Control.Header.GapTickMap(this._map, rowsData, rowsGeometry); this._rowLines.clearLayers(); ticks.forEachTick(function(idx, pos) { diff --git a/loleaflet/src/layer/tile/CalcTileLayer.js b/loleaflet/src/layer/tile/CalcTileLayer.js index 6ed8ae4b4..2252f2116 100644 --- a/loleaflet/src/layer/tile/CalcTileLayer.js +++ b/loleaflet/src/layer/tile/CalcTileLayer.js @@ -5,6 +5,10 @@ /* global */ L.CalcTileLayer = L.TileLayer.extend({ + options: { + sheetGeometryDataEnabled: false + }, + STD_EXTRA_WIDTH: 113, /* 2mm extra for optimal width, * 0.1986cm with TeX points, * 0.1993cm with PS points. */ @@ -264,13 +268,16 @@ L.CalcTileLayer = L.TileLayer.extend({ } } } else if (textMsg.startsWith('invalidateheader: column')) { - this.requestViewRowColumnData({x: this._map._getTopLeftPoint().x, y: 0, offset: {x: undefined, y: 0}}); + this.refreshViewData({x: this._map._getTopLeftPoint().x, y: 0, + offset: {x: undefined, y: 0}}, true /* sheetGeometryChanged */); this._map._socket.sendMessage('commandvalues command=.uno:ViewAnnotationsPosition'); } else if (textMsg.startsWith('invalidateheader: row')) { - this.requestViewRowColumnData({x: 0, y: this._map._getTopLeftPoint().y, offset: {x: 0, y: undefined}}); + this.refreshViewData({x: 0, y: this._map._getTopLeftPoint().y, + offset: {x: 0, y: undefined}}, true /* sheetGeometryChanged */); this._map._socket.sendMessage('commandvalues command=.uno:ViewAnnotationsPosition'); } else if (textMsg.startsWith('invalidateheader: all')) { - this.requestViewRowColumnData({x: this._map._getTopLeftPoint().x, y: this._map._getTopLeftPoint().y, offset: {x: undefined, y: undefined}}); + this.refreshViewData({x: this._map._getTopLeftPoint().x, y: this._map._getTopLeftPoint().y, + offset: {x: undefined, y: undefined}}, true /* sheetGeometryChanged */); this._map._socket.sendMessage('commandvalues command=.uno:ViewAnnotationsPosition'); } else { L.TileLayer.prototype._onMessage.call(this, textMsg, img); @@ -360,15 +367,17 @@ L.CalcTileLayer = L.TileLayer.extend({ if (part !== this._selectedPart && !this.isHiddenPart(part)) { this._map.setPart(part, true); this._map.fire('setpart', {selectedPart: this._selectedPart}); - // TODO: test it! - this.requestViewRowColumnData(); + this.refreshViewData(undefined, true /* sheetGeometryChanged */); } }, _onZoomRowColumns: function () { this._sendClientZoom(); - // TODO: test it! - this.requestViewRowColumnData(); + if (this.sheetGeometry) { + this.sheetGeometry.setTileGeometryData(this._tileWidthTwips, this._tileHeightTwips, + this._tileSize, this._tilePixelScale); + } + this.refreshViewData(); this._map._socket.sendMessage('commandvalues command=.uno:ViewAnnotationsPosition'); }, @@ -454,8 +463,13 @@ L.CalcTileLayer = L.TileLayer.extend({ } }, - // This send .uno:ViewRowColumnHeaders command to core with the new view coordinates. - requestViewRowColumnData: function (coordinatesData) { + // This initiates a selective repainting of row/col headers and + // gridlines based on the settings of coordinatesData.offset. This + // should be called whenever the view area changes (scrolling, panning, + // zooming, cursor moving out of view-area etc.). Depending on the + // active sheet geometry data-source, it may ask core to send current + // view area's data or the global data on geometry changes. + refreshViewData: function (coordinatesData, sheetGeometryChanged) { // There are places that call this function with no arguments to indicate that the // command arguments should be the current map area coordinates. @@ -475,32 +489,57 @@ L.CalcTileLayer = L.TileLayer.extend({ topLeftPoint.y = this._map._getTopLeftPoint().y; } + var updateRows = true; + var updateCols = true; + if (offset.x === 0) { - topLeftPoint.x = -1; - sizePx.x = 0; + updateCols = false; + if (!this.options.sheetGeometryDataEnabled) { + topLeftPoint.x = -1; + sizePx.x = 0; + } } if (offset.y === 0) { - topLeftPoint.y = -1; - sizePx.y = 0; + updateRows = false; + if (!this.options.sheetGeometryDataEnabled) { + topLeftPoint.y = -1; + sizePx.y = 0; + } } var pos = this._pixelsToTwips(topLeftPoint); var size = this._pixelsToTwips(sizePx); - var payload = 'commandvalues command=.uno:ViewRowColumnHeaders?x=' + Math.round(pos.x) + '&y=' + Math.round(pos.y) + - '&width=' + Math.round(size.x) + '&height=' + Math.round(size.y); - if (coordinatesData.outline) { - payload += '&columnOutline=' + coordinatesData.outline.column + '&groupLevel=' + coordinatesData.outline.level - + '&groupIndex=' + coordinatesData.outline.index + '&groupHidden=' + coordinatesData.outline.hidden; + if (!this.options.sheetGeometryDataEnabled) { + this.requestViewRowColumnData(pos, size); + return; + } + + if (sheetGeometryChanged || !this.sheetGeometry) { + this.requestSheetGeometryData( + {columns: updateCols, rows: updateRows}); + return; } + this.sheetGeometry.setViewArea(pos, size); + this._updateHeadersGridLines(undefined, updateCols, updateRows); + }, + + // This send .uno:ViewRowColumnHeaders command to core with the new view coordinates (tile-twips). + requestViewRowColumnData: function (pos, size) { + + var payload = 'commandvalues command=.uno:ViewRowColumnHeaders?x=' + Math.round(pos.x) + '&y=' + Math.round(pos.y) + + '&width=' + Math.round(size.x) + '&height=' + Math.round(size.y); + this._map._socket.sendMessage(payload); }, // sends the .uno:SheetGeometryData command optionally with arguments. - requestSheetGeomtryData: function (flags) { + requestSheetGeometryData: function (flags) { var unoCmd = '.uno:SheetGeometryData'; - var haveArgs = (typeof flags == 'object' && (flags.columns === true || flags.rows === true)); + var haveArgs = (typeof flags == 'object' && + (flags.columns === true || flags.rows === true) && + (flags.columns !== flags.rows)); var payload = 'commandvalues command=' + unoCmd; if (haveArgs) { @@ -533,9 +572,15 @@ L.CalcTileLayer = L.TileLayer.extend({ this._map._socket.sendMessage(payload); }, - _handleViewRowColumnHeadersMsg: function (jsonMsgObj) { + // Sends a notification to the row/col header and gridline controls that + // they need repainting. + // viewAreaData is the parsed .uno:ViewRowColumnHeaders JSON if that source is used. + // else it should be undefined. + _updateHeadersGridLines: function (viewAreaData, updateCols, updateRows) { this._map.fire('viewrowcolumnheaders', { - data: jsonMsgObj, + data: viewAreaData, + updaterows: updateRows, + updatecolumns: updateCols, cursor: this._getCursorPosSize(), selection: this._getSelectionHeaderData(), converter: this._twipsToPixels, @@ -544,8 +589,17 @@ L.CalcTileLayer = L.TileLayer.extend({ }, _handleSheetGeometryDataMsg: function (jsonMsgObj) { - // TODO: use the L.SheetGeometry datastructure - this._map.sheetGeomData = jsonMsgObj; + if (!this.sheetGeometry) { + this.sheetGeometry = new L.SheetGeometry(jsonMsgObj, + this._tileWidthTwips, this._tileHeightTwips, + this._tileSize, this._tilePixelScale); + } + + this.sheetGeometry.update(jsonMsgObj); + this.sheetGeometry.setViewArea(this._pixelsToTwips(this._map._getTopLeftPoint()), + this._pixelsToTwips(this._map.getSize())); + this._updateHeadersGridLines(undefined, true /* updateCols */, + true /* updateRows */); }, _onCommandValuesMsg: function (textMsg) { @@ -560,7 +614,7 @@ L.CalcTileLayer = L.TileLayer.extend({ var comment; if (values.commandName === '.uno:ViewRowColumnHeaders') { - this._handleViewRowColumnHeadersMsg(values); + this._updateHeadersGridLines(values); } else if (values.commandName === '.uno:SheetGeometryData') { this._handleSheetGeometryDataMsg(values); @@ -697,6 +751,14 @@ L.SheetGeometry = L.Class.extend({ return true; }, + getColumnsGeometry: function () { + return this._columns; + }, + + getRowsGeometry: function () { + return this._rows; + }, + // returns an object with keys 'start' and 'end' indicating the // column range in the current view area. getViewColumnRange: function () { diff --git a/loleaflet/src/map/Map.js b/loleaflet/src/map/Map.js index dbc376765..0cd8f9282 100644 --- a/loleaflet/src/map/Map.js +++ b/loleaflet/src/map/Map.js @@ -324,7 +324,7 @@ L.Map = L.Evented.extend({ this._socket.sendMessage('commandvalues command=.uno:LanguageStatus'); this._socket.sendMessage('commandvalues command=.uno:ViewAnnotations'); if (this._docLayer._docType === 'spreadsheet') { - this._docLayer.requestViewRowColumnData(); + this._docLayer.refreshViewData(); } this._docLayer._getToolbarCommandsValues(); }, _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits