loleaflet/Makefile | 2 loleaflet/README | 22 loleaflet/build/deps.js | 19 loleaflet/debug/document/document_simple_example.html | 21 loleaflet/spec/loleaflet/loleafletSpec.js | 23 loleaflet/spec/tilebench/TileBenchSpec.js | 30 loleaflet/src/control/Buttons.js | 4 loleaflet/src/control/Control.Parts.js | 6 loleaflet/src/control/Control.PartsPreview.js | 8 loleaflet/src/control/Control.Search.js | 2 loleaflet/src/control/Control.Tabs.js | 4 loleaflet/src/control/Parts.js | 56 + loleaflet/src/control/Permission.js | 4 loleaflet/src/control/Search.js | 4 loleaflet/src/core/Socket.js | 204 +++++ loleaflet/src/layer/Layer.js | 5 loleaflet/src/layer/tile/CalcTileLayer.js | 126 +++ loleaflet/src/layer/tile/GridLayer.js | 90 -- loleaflet/src/layer/tile/ImpressTileLayer.js | 156 ++++ loleaflet/src/layer/tile/TileLayer.js | 685 ++++++------------ loleaflet/src/layer/tile/WriterTileLayer.js | 158 ++++ loleaflet/src/map/Map.js | 40 - loleaflet/src/map/handler/Map.DoubleClickZoom.js | 2 loleaflet/src/map/handler/Map.Mouse.js | 4 loolwsd/LOOLWSD.cpp | 11 loolwsd/configure.ac | 2 26 files changed, 1051 insertions(+), 637 deletions(-)
New commits: commit c60b89b9a87a31a687cd4a5d4e5f811628e52435 Author: Mihai Varga <mihai.va...@collabora.com> Date: Mon Sep 7 15:56:47 2015 +0300 loolwsd: copy /etc/hosts when running the server diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp index 2f86e50..8e76a80 100644 --- a/loolwsd/LOOLWSD.cpp +++ b/loolwsd/LOOLWSD.cpp @@ -869,6 +869,11 @@ void LOOLWSD::desktopMain() { resolv.copyTo(Path(jail, "/etc").toString()); } + File hosts("/etc/hosts"); + if (hosts.exists()) + { + hosts.copyTo(Path(jail, "/etc").toString()); + } #ifdef __linux // Create the urandom and random devices File(Path(jail, "/dev")).createDirectory(); commit e1d2db5cec5eda60b37e5511a3b72b740b9f9125 Author: Mihai Varga <mihai.va...@collabora.com> Date: Mon Sep 7 11:45:36 2015 +0300 loleaflet: bump version after tarball diff --git a/loleaflet/Makefile b/loleaflet/Makefile index 2d2ea05..e21333b 100644 --- a/loleaflet/Makefile +++ b/loleaflet/Makefile @@ -3,7 +3,7 @@ # ("micro") part: Between releases odd, even for releases (no other # changes inbetween). -VERSION=1.1.38 +VERSION=1.1.39 # Version number of the bundled 'draw' thing DRAW_VERSION=0.2.4 commit 2e660ebfd0689e523d48c6534c25ea11092c7e07 Author: Mihai Varga <mihai.va...@collabora.com> Date: Mon Sep 7 11:45:23 2015 +0300 lolealfet: bump version beforetarball diff --git a/loleaflet/Makefile b/loleaflet/Makefile index aa5021a..2d2ea05 100644 --- a/loleaflet/Makefile +++ b/loleaflet/Makefile @@ -3,7 +3,7 @@ # ("micro") part: Between releases odd, even for releases (no other # changes inbetween). -VERSION=1.1.37 +VERSION=1.1.38 # Version number of the bundled 'draw' thing DRAW_VERSION=0.2.4 commit 2d4b34ef1e7edd3205466ad4b989b9b0d9119f23 Author: Mihai Varga <mihai.va...@collabora.com> Date: Mon Sep 7 11:38:49 2015 +0300 lolealfet: don't prefetch if map is undefined This happens when the map is removed and some hooks still remain diff --git a/loleaflet/src/layer/tile/GridLayer.js b/loleaflet/src/layer/tile/GridLayer.js index 95469d5..844736a 100644 --- a/loleaflet/src/layer/tile/GridLayer.js +++ b/loleaflet/src/layer/tile/GridLayer.js @@ -897,6 +897,9 @@ L.GridLayer = L.Layer.extend({ }, _resetPreFetching: function (resetBorder) { + if (!this._map) { + return; + } clearInterval(this._tilesPreFetcher); clearTimeout(this._preFetchIdle); if (resetBorder) { commit 428357fee1a5365c44f426f58606c0db2662be1c Author: Mihai Varga <mihai.va...@collabora.com> Date: Mon Sep 7 11:38:34 2015 +0300 loleaflet: We don't have styles yet diff --git a/loleaflet/src/core/Socket.js b/loleaflet/src/core/Socket.js index 4e2846f..57852d7 100644 --- a/loleaflet/src/core/Socket.js +++ b/loleaflet/src/core/Socket.js @@ -52,7 +52,6 @@ L.Socket = { } this.socket.send(msg); this.socket.send('status'); - this.socket.send('styles'); for (var i = 0; i < this._msgQueue.length; i++) { this.socket.send(this._msgQueue[i].msg); L.Log.log(this._msgQueue[i].msg, this._msgQueue[i].coords); commit feb629081905ecd4258167c8efe38577a4a53f46 Author: Mihai Varga <mihai.va...@collabora.com> Date: Thu Sep 3 10:33:20 2015 +0300 loleaflet: hide selection when switching thorugh cached parts diff --git a/loleaflet/src/control/Parts.js b/loleaflet/src/control/Parts.js index 040d909..55d4c9b 100644 --- a/loleaflet/src/control/Parts.js +++ b/loleaflet/src/control/Parts.js @@ -31,9 +31,9 @@ L.Map.include({ docType: docLayer._docType }); L.Socket.sendMessage('setclientpart part=' + docLayer._selectedPart); + docLayer._clearSelections(); docLayer._update(); docLayer._pruneTiles(); - docLayer._clearSelections(); docLayer._prevSelectedPartNeedsUpdate = true; if (docLayer._invalidatePreview) { docLayer._invalidatePreview(); diff --git a/loleaflet/src/layer/tile/CalcTileLayer.js b/loleaflet/src/layer/tile/CalcTileLayer.js index 7550ddb..d405e2d 100644 --- a/loleaflet/src/layer/tile/CalcTileLayer.js +++ b/loleaflet/src/layer/tile/CalcTileLayer.js @@ -91,7 +91,6 @@ L.CalcTileLayer = L.TileLayer.extend({ if (part !== this._selectedPart) { this._selectedPart = part; this._update(); - this._clearSelections(); this._map.fire('setpart', {selectedPart: this._selectedPart}); } }, diff --git a/loleaflet/src/layer/tile/ImpressTileLayer.js b/loleaflet/src/layer/tile/ImpressTileLayer.js index 2acc5c3..1717cf3 100644 --- a/loleaflet/src/layer/tile/ImpressTileLayer.js +++ b/loleaflet/src/layer/tile/ImpressTileLayer.js @@ -97,7 +97,6 @@ L.ImpressTileLayer = L.TileLayer.extend({ if (part !== this._selectedPart) { this._selectedPart = part; this._update(); - this._clearSelections(); this._map.fire('setpart', {selectedPart: this._selectedPart}); } }, diff --git a/loleaflet/src/layer/tile/TileLayer.js b/loleaflet/src/layer/tile/TileLayer.js index 8e89c1e..010d3f3 100644 --- a/loleaflet/src/layer/tile/TileLayer.js +++ b/loleaflet/src/layer/tile/TileLayer.js @@ -105,7 +105,6 @@ L.TileLayer = L.GridLayer.extend({ map._fadeAnimated = false; this._viewReset(); map.on('drag resize zoomend', this._updateScrollOffset, this); - map.on('clearselection', this._clearSelections, this); map.on('copy', this._onCopy, this); map.on('zoomend', this._onUpdateCursor, this); map.on('dragstart', this._onDragStart, this); @@ -300,7 +299,7 @@ L.TileLayer = L.GridLayer.extend({ _onTextSelectionMsg: function (textMsg) { var strTwips = textMsg.match(/\d+/g); - this._clearSelections(); + this._selections.clearLayers(); if (strTwips != null) { var rectangles = []; var selectionCenter = new L.Point(0, 0); @@ -437,7 +436,16 @@ L.TileLayer = L.GridLayer.extend({ }, _clearSelections: function () { + // hide the cursor + this._isCursorOverlayVisible = false; + this._onUpdateCursor(); + // hide the text selection this._selections.clearLayers(); + // hide the selection handles + this._onUpdateTextSelection(); + // hide the graphic selection + this._graphicSelection = null; + this._onUpdateGraphicSelection(); }, _postMouseEvent: function(type, x, y, count) { @@ -533,7 +541,7 @@ L.TileLayer = L.GridLayer.extend({ // Update group layer selection handler. _onUpdateGraphicSelection: function () { - if (!this._isEmptyRectangle(this._graphicSelection)) { + if (this._graphicSelection && !this._isEmptyRectangle(this._graphicSelection)) { if (this._graphicMarker) { this._graphicMarker.off('editstart editend', this._onGraphicEdit, this); this._map.removeLayer(this._graphicMarker); commit 59bf3c169d5f4acffea207576782718741132b74 Author: Mihai Varga <mihai.va...@collabora.com> Date: Thu Sep 3 09:49:55 2015 +0300 loleaflet: don't handle mouse events before the doc is loaded diff --git a/loleaflet/src/map/handler/Map.Mouse.js b/loleaflet/src/map/handler/Map.Mouse.js index 9049084..a5f58f1 100644 --- a/loleaflet/src/map/handler/Map.Mouse.js +++ b/loleaflet/src/map/handler/Map.Mouse.js @@ -25,6 +25,10 @@ L.Map.Mouse = L.Handler.extend({ _onMouseEvent: function (e) { var docLayer = this._map._docLayer; + if (!docLayer) { + // document not yet loaded + return; + } if (docLayer._graphicMarker && docLayer._graphicMarker.isDragged) { return; } commit 25cc20693edc7ed7287dd938fd719af65664f5af Author: Mihai Varga <mihai.va...@collabora.com> Date: Thu Sep 3 09:34:16 2015 +0300 loleaflet: don't prefetch in tilebench diff --git a/loleaflet/spec/tilebench/TileBenchSpec.js b/loleaflet/spec/tilebench/TileBenchSpec.js index 926a100..7fb85de 100644 --- a/loleaflet/spec/tilebench/TileBenchSpec.js +++ b/loleaflet/spec/tilebench/TileBenchSpec.js @@ -49,6 +49,7 @@ describe('TileBench', function () { map.on('statusindicator', L.bind(function (e) { if (e.statusType === 'alltilesloaded') { map.fire('requestloksession'); + map._docLayer._preFetchTiles = function () {}; done(); } }, done)); commit 5d9ea2eb14f5b1eded96f542a33c24dd70deec9e Author: Mihai Varga <mihai.va...@collabora.com> Date: Wed Sep 2 20:00:42 2015 +0300 loleaflet: moved img decoding in L.Socket This gives a better tile loading time by 10ms diff --git a/loleaflet/src/core/Socket.js b/loleaflet/src/core/Socket.js index 781c25b..4e2846f 100644 --- a/loleaflet/src/core/Socket.js +++ b/loleaflet/src/core/Socket.js @@ -84,6 +84,15 @@ L.Socket = { textMsg = String.fromCharCode.apply(null, imgBytes); } } + else { + var data = imgBytes.subarray(index + 1); + // read the tile data + var strBytes = ''; + for (var i = 0; i < data.length; i++) { + strBytes += String.fromCharCode(data[i]); + } + var img = 'data:image/png;base64,' + window.btoa(strBytes); + } if (textMsg.startsWith('status:') && !this._map._docLayer) { // first status message, we need to create the document layer @@ -112,7 +121,7 @@ L.Socket = { this._map.addLayer(docLayer); } if (this._map._docLayer) { - this._map._docLayer._onMessage(textMsg, imgBytes, index); + this._map._docLayer._onMessage(textMsg, img); } }, diff --git a/loleaflet/src/layer/tile/TileLayer.js b/loleaflet/src/layer/tile/TileLayer.js index 12af0b8..8e89c1e 100644 --- a/loleaflet/src/layer/tile/TileLayer.js +++ b/loleaflet/src/layer/tile/TileLayer.js @@ -174,7 +174,7 @@ L.TileLayer = L.GridLayer.extend({ return tile; }, - _onMessage: function (textMsg, imgBytes, index) { + _onMessage: function (textMsg, img) { if (textMsg.startsWith('cursorvisible:')) { this._onCursorVisibleMsg(textMsg); } @@ -221,7 +221,7 @@ L.TileLayer = L.GridLayer.extend({ this._onTextSelectionStartMsg(textMsg); } else if (textMsg.startsWith('tile:')) { - this._onTileMsg(textMsg, imgBytes, index); + this._onTileMsg(textMsg, img); } }, @@ -378,22 +378,13 @@ L.TileLayer = L.GridLayer.extend({ } }, - _onTileMsg: function (textMsg, imgBytes, index) { + _onTileMsg: function (textMsg, img) { var command = L.Socket.parseServerCmd(textMsg); var coords = this._twipsToCoords(command); coords.z = command.zoom; coords.part = command.part; - var data = imgBytes.subarray(index + 1); - - // read the tile data - var strBytes = ''; - for (var i = 0; i < data.length; i++) { - strBytes += String.fromCharCode(data[i]); - } - var key = this._tileCoordsToKey(coords); var tile = this._tiles[key]; - var img = 'data:image/png;base64,' + window.btoa(strBytes); if (command.id !== undefined) { this._map.fire('tilepreview', { tile: img, commit ce5b5f9fb56d1c88b94affaa17b722bf6be9a5ae Author: Mihai Varga <mihai.va...@collabora.com> Date: Wed Sep 2 19:50:24 2015 +0300 loleaflet: fixed typo and removed return value diff --git a/loleaflet/src/core/Socket.js b/loleaflet/src/core/Socket.js index b9bf086..781c25b 100644 --- a/loleaflet/src/core/Socket.js +++ b/loleaflet/src/core/Socket.js @@ -17,7 +17,6 @@ L.Socket = { this.socket.onopen = L.bind(this._onOpen, this); this.socket.onmessage = L.bind(this._onMessage, this); this.socket.binaryType = 'arraybuffer'; - return this.socket; }, close: function () { @@ -29,7 +28,7 @@ L.Socket = { sendMessage: function (msg, coords) { var socketState = this.socket.readyState; if (socketState === 2 || socketState === 3) { - this._socket = this.connect(this._map); + this.connect(this._map); this._msgQueue.push({msg: msg, coords: coords}); } commit a416bf27e7d0727f690dbdb6bbbd0cb0d0bfecf5 Author: Mihai Varga <mihai.va...@collabora.com> Date: Wed Sep 2 18:16:59 2015 +0300 loleaflet: sometimes the graphic marker is not created It was reported to me but I couldn't reproduce. I suspect some invalid coordinates diff --git a/loleaflet/src/layer/tile/TileLayer.js b/loleaflet/src/layer/tile/TileLayer.js index fffba11..12af0b8 100644 --- a/loleaflet/src/layer/tile/TileLayer.js +++ b/loleaflet/src/layer/tile/TileLayer.js @@ -548,6 +548,10 @@ L.TileLayer = L.GridLayer.extend({ this._map.removeLayer(this._graphicMarker); } this._graphicMarker = L.rectangle(this._graphicSelection, {fill: false}); + if (!this._graphicMarker) { + this._map.fire('error', {msg: 'Graphic marker initialization'}); + return; + } this._graphicMarker.editing.enable(); this._graphicMarker.on('editstart editend', this._onGraphicEdit, this); this._map.addLayer(this._graphicMarker); commit f9633c967dbadba64c16f99ad9a307b154ebf941 Author: Mihai Varga <mihai.va...@collabora.com> Date: Wed Sep 2 18:09:08 2015 +0300 loleaflet: updated the tests to reflect the new map initialization Conflicts: loleaflet/spec/loadtest/LoadTestSpec.js loleaflet/spec/tilebench/TileBenchSpec.js diff --git a/loleaflet/spec/loleaflet/loleafletSpec.js b/loleaflet/spec/loleaflet/loleafletSpec.js index 2d0edf5..fd16985 100644 --- a/loleaflet/spec/loleaflet/loleafletSpec.js +++ b/loleaflet/spec/loleaflet/loleafletSpec.js @@ -15,34 +15,11 @@ describe('TileBench', function () { before(function () { // initialize the map and load the document map = L.map('map', { - center: [0, 0], - zoom: 10, - minZoom: 1, - maxZoom: 20, server: 'ws://localhost:9980', - doubleClickZoom: false - }); - - var docLayer = new L.TileLayer('', { doc: 'file:///home/mihai/Desktop/test_docs/eval.odt', - useSocket : true, edit: false, readOnly: false }); - - docLayer.sendMessage = L.bind(function (msg, coords) { - var now = Date.now(); - if (msg.startsWith('tile')) { - msg += ' timestamp=' + now; - } - L.Log.log(msg, L.OUTGOING, coords, now); - this._map.socket.send(msg); - }, docLayer); - - // don't pre-fetch tiles - docLayer._preFetchTiles = L.Util.falseFn; - - map.addLayer(docLayer); }); afterEach(function () { diff --git a/loleaflet/spec/tilebench/TileBenchSpec.js b/loleaflet/spec/tilebench/TileBenchSpec.js index a31a0b6..926a100 100644 --- a/loleaflet/spec/tilebench/TileBenchSpec.js +++ b/loleaflet/spec/tilebench/TileBenchSpec.js @@ -16,36 +16,23 @@ describe('TileBench', function () { before(function () { // initialize the map and load the document map = L.map('map', { - center: [0, 0], - zoom: 10, - minZoom: 1, - maxZoom: 20, server: 'ws://localhost:9980', - doubleClickZoom: false - }); - - var docLayer = new L.TileLayer('', { doc: 'file:///home/mihai/Desktop/test_docs/eval.odt', - useSocket : true, edit: false, readOnly: false }); // add a timestamp to tile messages so we can identify // the response - docLayer.sendMessage = L.bind(function (msg, coords) { + L.Socket.sendMessage = L.bind(function (msg, coords) { var now = Date.now(); if (msg.startsWith('tile')) { msg += ' timestamp=' + now; } L.Log.log(msg, L.OUTGOING, coords, now); - this._map.socket.send(msg); - }, docLayer); - - // don't pre-fetch tiles - docLayer._preFetchTiles = L.Util.falseFn; + this.socket.send(msg); + }, L.Socket); - map.addLayer(docLayer); map.addControl(L.control.scroll()); }); @@ -54,16 +41,14 @@ describe('TileBench', function () { }); after(function () { - map.socket.onclose = undefined; - map.socket.onerror = undefined; - map.socket.close(); + map.remove(); }); describe('Benchmarking', function () { it('Load all new tiles', function (done) { map.on('statusindicator', L.bind(function (e) { if (e.statusType === 'alltilesloaded') { - loadCount += 1; + map.fire('requestloksession'); done(); } }, done)); @@ -92,7 +77,7 @@ describe('TileBench', function () { var y = Math.floor(docLayer._docHeightTwips / docLayer._tileHeightTwips); var coords = new L.Point(x, y); coords.z = map.getZoom(); - coords.part = docLayer._currentPart; + coords.part = docLayer._selectedPart; var key = docLayer._tileCoordsToKey(coords); if (docLayer._tiles[key]) { // the tile is already here, the whole document is loaded @@ -104,7 +89,7 @@ describe('TileBench', function () { for (var i = 0; i < keyInput.length; i++) { setTimeout(L.bind(function () { - map._docLayer.sendMessage(keyInput[this][1]); + L.Socket.sendMessage(keyInput[this][1]); }, i), keyInput[i][0]); } }); commit e2cecbc2076042e029107f3f4c2f4100b55ce83c Author: Mihai Varga <mihai.va...@collabora.com> Date: Wed Sep 2 17:23:33 2015 +0300 loleaflet: autoupdate previews from the preview control diff --git a/loleaflet/src/control/Control.PartsPreview.js b/loleaflet/src/control/Control.PartsPreview.js index 1bec8a4..4112d01 100644 --- a/loleaflet/src/control/Control.PartsPreview.js +++ b/loleaflet/src/control/Control.PartsPreview.js @@ -3,6 +3,10 @@ */ L.Control.PartsPreview = L.Control.extend({ + options: { + autoUpdate: true + }, + onAdd: function (map) { this._previewInitialized = false; this._previewTiles = {}; @@ -42,7 +46,7 @@ L.Control.PartsPreview = L.Control.extend({ .on(img, 'click', L.DomEvent.stop) .on(img, 'click', this._setPart, this) .on(img, 'click', this._refocusOnMap, this); - this._map.getPartPreview(i, i, 180, 180); + this._map.getPartPreview(i, i, 180, 180, {autoUpdate: this.options.autoUpdate}); } this._previewInitialized = true; } @@ -57,7 +61,7 @@ L.Control.PartsPreview = L.Control.extend({ _updatePart: function (e) { if (e.docType === 'presentation') { - this._map.getPartPreview(e.part, e.part, 180, 180); + this._map.getPartPreview(e.part, e.part, 180, 180, {autoUpdate: this.options.autoUpdate}); } }, commit e2a67ba62da7dc3fde89259d6e06c19dbd3c86c7 Author: Mihai Varga <mihai.va...@collabora.com> Date: Wed Sep 2 17:21:35 2015 +0300 loleaflet: impress preview invalidation diff --git a/loleaflet/src/layer/tile/ImpressTileLayer.js b/loleaflet/src/layer/tile/ImpressTileLayer.js index 2a437ef..2acc5c3 100644 --- a/loleaflet/src/layer/tile/ImpressTileLayer.js +++ b/loleaflet/src/layer/tile/ImpressTileLayer.js @@ -86,6 +86,10 @@ L.ImpressTileLayer = L.TileLayer.extend({ this._lastValidPart = command.part; this._map.fire('updatepart', {part: command.part, docType: this._docType}); } + + // 1s after the last invalidation, update the preview + clearTimeout(this._previewInvalidator); + this._previewInvalidator = setTimeout(L.bind(this._invalidatePreview, this), 1000); }, _onSetPartMsg: function (textMsg) { @@ -124,6 +128,30 @@ L.ImpressTileLayer = L.TileLayer.extend({ this._preFetchPart = this._selectedPart; this._preFetchBorder = null; } - } + } + }, + + _invalidatePreview: function () { + if (this._map._docPreviews) { + // invalidate part previews + for (var key in this._map._docPreviews) { + var preview = this._map._docPreviews[key]; + if (preview.part === this._selectedPart || + (preview.part === this._prevSelectedPart && this._prevSelectedPartNeedsUpdate)) { + // if the current part needs its preview updated OR + // the part has been changed and we need to update the previous part preview + if (preview.part === this._prevSelectedPart) { + this._prevSelectedPartNeedsUpdate = false; + } + if (preview.autoUpdate) { + this._map.getPartPreview(preview.id, preview.part, preview.maxWidth, preview.maxHeight, + {autoUpdate: true}); + } + else { + this._map.fire('invalidatepreview', {id: preview.id}); + } + } + } + } } }); commit f8fc4559469045ceb501ed023b713c1f6c069a64 Author: Mihai Varga <mihai.va...@collabora.com> Date: Wed Sep 2 17:21:19 2015 +0300 loleaflet: writer preview invalidation diff --git a/loleaflet/src/layer/tile/WriterTileLayer.js b/loleaflet/src/layer/tile/WriterTileLayer.js index 68260a1..fe85e9d 100644 --- a/loleaflet/src/layer/tile/WriterTileLayer.js +++ b/loleaflet/src/layer/tile/WriterTileLayer.js @@ -79,6 +79,13 @@ L.WriterTileLayer = L.TileLayer.extend({ delete this._tileCache[key]; } } + if (!this._previewInvalidations) { + this._previewInvalidations = []; + } + this._previewInvalidations.push(invalidBounds); + // 1s after the last invalidation, update the preview + clearTimeout(this._previewInvalidator); + this._previewInvalidator = setTimeout(L.bind(this._invalidatePreview, this), 1000); }, _onSetPartMsg: function (textMsg) { @@ -111,5 +118,41 @@ L.WriterTileLayer = L.TileLayer.extend({ this._resetPreFetching(true); this._update(); } + }, + + _invalidatePreview: function () { + // invalidate writer page previews + if (this._map._docPreviews && this._previewInvalidations) { + var toInvalidate = {}; + for (var i = 0; i < this._previewInvalidations.length; i++) { + var invalidBounds = this._previewInvalidations[i]; + var invalidPixBounds = new L.Bounds( + invalidBounds.min.divideBy(this.options.tileWidthTwips).multiplyBy(this._tileSize), + invalidBounds.max.divideBy(this.options.tileWidthTwips).multiplyBy(this._tileSize)); + + for (var key in this._map._docPreviews) { + // find preview tiles that need to be updated and add them in a set + var preview = this._map._docPreviews[key]; + var bounds = new L.Bounds(new L.Point(preview.x, preview.y), + new L.Point(preview.x + preview.width, preview.y + preview.height)); + if (invalidPixBounds.intersects(bounds)) { + toInvalidate[key] = true; + } + } + + for (key in toInvalidate) { + // update invalid preview tiles + preview = this._map._docPreviews[key]; + if (preview.autoUpdate) { + this._map.getDocPreview(preview.id, preview.maxWidth, preview.maxHeight, + preview.x, preview.y, preview.width, preview.height, {autoUpdate: true}); + } + else { + this._map.fire('invalidatepreview', {id: preview.id}); + } + } + } + } + this._previewInvalidations = []; } }); commit 9b84f3787c9f097423a1955ee59d8b3dcbffc530 Author: Mihai Varga <mihai.va...@collabora.com> Date: Wed Sep 2 17:12:02 2015 +0300 loleaflet: option for automatically updating the previews diff --git a/loleaflet/README b/loleaflet/README index 5ce2b41..672dc0f 100644 --- a/loleaflet/README +++ b/loleaflet/README @@ -89,10 +89,11 @@ Buttons like Bold, Italic, Strike through etc. Parts (like slides in presentation, or sheets in spreadsheets): - API: map.setPart('next' | 'prev' | partNumber) - map.getPartPreview(id, part, maxWidth, maxHeight) where: + map.getPartPreview(id, part, maxWidth, maxHeight, [options]) where: + id = the ID of the request so that the response can be identified + maxWidth / maxHeight are the desired dimensions of the preview, a smaller image might be returned in order to keep the original ratio of the document + + options = {autoUpdate: true} - automatically updates the previews map.getNumberOfParts() map.getCurrentPartNumber() - events: @@ -101,6 +102,8 @@ Parts (like slides in presentation, or sheets in spreadsheets): + e.parts == the number of parts that the document has + e.docType == 'text' | 'spreadsheet' | 'presentation' | 'drawing' | 'other' + [e.partNames] if present, part names (e.g. sheet names) + map.on('invalidatepreview', function (e) {}) + + e.id = the preview's id Statusindicator (when the document is loading): - events @@ -160,17 +163,20 @@ Writer pages: map.goToPage(page) map.getNumberOfPages() map.getCurrentPageNumber() - map.getDocPreview(id, maxWidth, maxHeight, x, y, width, height) + map.getDocPreview(id, maxWidth, maxHeight, x, y, width, height, [options]) + id = the ID of the request so that the response can be identified + maxWidth / maxHeight are the desired dimensions of the preview, a smaller image might be returned in order to keep the original ratio of the document + x/y = starting position, where to get the preview from + + options = {autoUpdate: true} - automatically updates the previews - events map.on('pagenumberchanged', function (e) {}) where: + e.currentPage = the page on which the cursor lies + e.pages = number of pages + e.docType = document type, should be 'text' + map.on('invalidatepreview', function (e) {}) + + e.id = the preview's id Error: - events diff --git a/loleaflet/src/control/Parts.js b/loleaflet/src/control/Parts.js index 08e1c89..040d909 100644 --- a/loleaflet/src/control/Parts.js +++ b/loleaflet/src/control/Parts.js @@ -4,6 +4,7 @@ L.Map.include({ setPart: function (part) { var docLayer = this._docLayer; + docLayer._prevSelectedPart = docLayer._selectedPart; if (part === 'prev') { if (docLayer._selectedPart > 0) { docLayer._selectedPart -= 1; @@ -33,9 +34,19 @@ L.Map.include({ docLayer._update(); docLayer._pruneTiles(); docLayer._clearSelections(); + docLayer._prevSelectedPartNeedsUpdate = true; + if (docLayer._invalidatePreview) { + docLayer._invalidatePreview(); + } }, - getPartPreview: function (id, part, maxWidth, maxHeight) { + getPartPreview: function (id, part, maxWidth, maxHeight, options) { + if (!this._docPreviews) { + this._docPreviews = {}; + } + var autoUpdate = options ? options.autoUpdate : false; + this._docPreviews[id] = {id: id, part: part, maxWidth: maxWidth, maxHeight: maxHeight, autoUpdate: autoUpdate}; + var docLayer = this._docLayer; var docRatio = docLayer._docWidthTwips / docLayer._docHeightTwips; var imgRatio = maxWidth / maxHeight; @@ -56,7 +67,14 @@ L.Map.include({ 'id=' + id); }, - getDocPreview: function (id, maxWidth, maxHeight, x, y, width, height) { + getDocPreview: function (id, maxWidth, maxHeight, x, y, width, height, options) { + if (!this._docPreviews) { + this._docPreviews = {}; + } + var autoUpdate = options ? options.autoUpdate : false; + this._docPreviews[id] = {id: id, maxWidth: maxWidth, maxHeight: maxHeight, x: x, y: y, + width: width, height: height, autoUpdate: autoUpdate}; + var docLayer = this._docLayer; var docRatio = width / height; var imgRatio = maxWidth / maxHeight; @@ -83,6 +101,12 @@ L.Map.include({ 'id=' + id); }, + removePreviewUpdate: function (id) { + if (this._docPreviews && this._docPreviews[id]) { + this._docPreviews[id].autoUpdate = false; + } + }, + goToPage: function (page) { var docLayer = this._docLayer; if (page === 'prev') { commit dcabc24a03af1ae2a31020e8ff268040a623d861 Author: Mihai Varga <mihai.va...@collabora.com> Date: Wed Sep 2 15:14:00 2015 +0300 loleaflet: setPart msg is now handled separately diff --git a/loleaflet/src/layer/tile/CalcTileLayer.js b/loleaflet/src/layer/tile/CalcTileLayer.js index 4a0d1fb..7550ddb 100644 --- a/loleaflet/src/layer/tile/CalcTileLayer.js +++ b/loleaflet/src/layer/tile/CalcTileLayer.js @@ -86,6 +86,16 @@ L.CalcTileLayer = L.TileLayer.extend({ } }, + _onSetPartMsg: function (textMsg) { + var part = parseInt(textMsg.match(/\d+/g)[0]); + if (part !== this._selectedPart) { + this._selectedPart = part; + this._update(); + this._clearSelections(); + this._map.fire('setpart', {selectedPart: this._selectedPart}); + } + }, + _onStatusMsg: function (textMsg) { var command = L.Socket.parseServerCmd(textMsg); if (command.width && command.height && this._documentInfo !== textMsg) { @@ -106,6 +116,7 @@ L.CalcTileLayer = L.TileLayer.extend({ docType: this._docType, partNames: partNames }); + this._resetPreFetching(true); this._update(); if (this._preFetchPart !== this._selectedPart) { this._preFetchPart = this._selectedPart; diff --git a/loleaflet/src/layer/tile/ImpressTileLayer.js b/loleaflet/src/layer/tile/ImpressTileLayer.js index d9eddf1..2a437ef 100644 --- a/loleaflet/src/layer/tile/ImpressTileLayer.js +++ b/loleaflet/src/layer/tile/ImpressTileLayer.js @@ -88,31 +88,42 @@ L.ImpressTileLayer = L.TileLayer.extend({ } }, + _onSetPartMsg: function (textMsg) { + var part = parseInt(textMsg.match(/\d+/g)[0]); + if (part !== this._selectedPart) { + this._selectedPart = part; + this._update(); + this._clearSelections(); + this._map.fire('setpart', {selectedPart: this._selectedPart}); + } + }, + _onStatusMsg: function (textMsg) { var command = L.Socket.parseServerCmd(textMsg); if (command.width && command.height && this._documentInfo !== textMsg) { this._docWidthTwips = command.width; - this._docHeightTwips = command.height; - this._docType = command.type; - this._updateMaxBounds(true); - this._documentInfo = textMsg; - this._parts = command.parts; - this._selectedPart = command.selectedPart; - L.Socket.sendMessage('setclientpart part=' + this._selectedPart); - var partNames = textMsg.match(/[^\r\n]+/g); - // only get the last matches - partNames = partNames.slice(partNames.length - this._parts); - this._map.fire('updateparts', { - selectedPart: this._selectedPart, - parts: this._parts, - docType: this._docType, - partNames: partNames - }); - this._update(); - if (this._preFetchPart !== this._selectedPart) { - this._preFetchPart = this._selectedPart; - this._preFetchBorder = null; - } + this._docHeightTwips = command.height; + this._docType = command.type; + this._updateMaxBounds(true); + this._documentInfo = textMsg; + this._parts = command.parts; + this._selectedPart = command.selectedPart; + L.Socket.sendMessage('setclientpart part=' + this._selectedPart); + var partNames = textMsg.match(/[^\r\n]+/g); + // only get the last matches + partNames = partNames.slice(partNames.length - this._parts); + this._map.fire('updateparts', { + selectedPart: this._selectedPart, + parts: this._parts, + docType: this._docType, + partNames: partNames + }); + this._resetPreFetching(true); + this._update(); + if (this._preFetchPart !== this._selectedPart) { + this._preFetchPart = this._selectedPart; + this._preFetchBorder = null; + } } } }); diff --git a/loleaflet/src/layer/tile/TileLayer.js b/loleaflet/src/layer/tile/TileLayer.js index dbd40bf..fffba11 100644 --- a/loleaflet/src/layer/tile/TileLayer.js +++ b/loleaflet/src/layer/tile/TileLayer.js @@ -271,24 +271,6 @@ L.TileLayer = L.GridLayer.extend({ this._map.fire('search', {originalPhrase: originalPhrase, count: 0}); }, - _onSetPartMsg: function (textMsg) { - var part = parseInt(textMsg.match(/\d+/g)[0]); - if (part !== this._selectedPart && this._docType !== 'text') { - this._selectedPart = part; - this._update(); - this._clearSelections(); - this._map.fire('setpart', {selectedPart: this._selectedPart}); - } - else if (this._docType === 'text') { - this._currentPage = part; - this._map.fire('pagenumberchanged', { - currentPage: part, - pages: this._pages, - docType: this._docType - }); - } - }, - _onStateChangedMsg: function (textMsg) { var unoMsg = textMsg.substr(14); var unoCmd = unoMsg.match('.uno:(.*)=')[1]; diff --git a/loleaflet/src/layer/tile/WriterTileLayer.js b/loleaflet/src/layer/tile/WriterTileLayer.js index 178c8e6..68260a1 100644 --- a/loleaflet/src/layer/tile/WriterTileLayer.js +++ b/loleaflet/src/layer/tile/WriterTileLayer.js @@ -81,9 +81,18 @@ L.WriterTileLayer = L.TileLayer.extend({ } }, + _onSetPartMsg: function (textMsg) { + var part = parseInt(textMsg.match(/\d+/g)[0]); + this._currentPage = part; + this._map.fire('pagenumberchanged', { + currentPage: part, + pages: this._pages, + docType: this._docType + }); + }, + _onStatusMsg: function (textMsg) { var command = L.Socket.parseServerCmd(textMsg); - console.log(textMsg); if (command.width && command.height && this._documentInfo !== textMsg) { this._docWidthTwips = command.width; this._docHeightTwips = command.height; @@ -99,6 +108,7 @@ L.WriterTileLayer = L.TileLayer.extend({ pages: this._pages, docType: this._docType }); + this._resetPreFetching(true); this._update(); } } commit 6bef2d4bbb3f8cbcbeaf9691809f68772c549b21 Author: Mihai Varga <mihai.va...@collabora.com> Date: Wed Sep 2 14:28:02 2015 +0300 loleaflet: the status msg is handled now separately diff --git a/loleaflet/src/layer/tile/CalcTileLayer.js b/loleaflet/src/layer/tile/CalcTileLayer.js index 687d03a..4a0d1fb 100644 --- a/loleaflet/src/layer/tile/CalcTileLayer.js +++ b/loleaflet/src/layer/tile/CalcTileLayer.js @@ -84,5 +84,33 @@ L.CalcTileLayer = L.TileLayer.extend({ delete this._tileCache[key]; } } + }, + + _onStatusMsg: function (textMsg) { + var command = L.Socket.parseServerCmd(textMsg); + if (command.width && command.height && this._documentInfo !== textMsg) { + this._docWidthTwips = command.width; + this._docHeightTwips = command.height; + this._docType = command.type; + this._updateMaxBounds(true); + this._documentInfo = textMsg; + this._parts = command.parts; + this._selectedPart = command.selectedPart; + L.Socket.sendMessage('setclientpart part=' + this._selectedPart); + var partNames = textMsg.match(/[^\r\n]+/g); + // only get the last matches + partNames = partNames.slice(partNames.length - this._parts); + this._map.fire('updateparts', { + selectedPart: this._selectedPart, + parts: this._parts, + docType: this._docType, + partNames: partNames + }); + this._update(); + if (this._preFetchPart !== this._selectedPart) { + this._preFetchPart = this._selectedPart; + this._preFetchBorder = null; + } + } } }); diff --git a/loleaflet/src/layer/tile/ImpressTileLayer.js b/loleaflet/src/layer/tile/ImpressTileLayer.js index ba2f765..d9eddf1 100644 --- a/loleaflet/src/layer/tile/ImpressTileLayer.js +++ b/loleaflet/src/layer/tile/ImpressTileLayer.js @@ -86,5 +86,33 @@ L.ImpressTileLayer = L.TileLayer.extend({ this._lastValidPart = command.part; this._map.fire('updatepart', {part: command.part, docType: this._docType}); } + }, + + _onStatusMsg: function (textMsg) { + var command = L.Socket.parseServerCmd(textMsg); + if (command.width && command.height && this._documentInfo !== textMsg) { + this._docWidthTwips = command.width; + this._docHeightTwips = command.height; + this._docType = command.type; + this._updateMaxBounds(true); + this._documentInfo = textMsg; + this._parts = command.parts; + this._selectedPart = command.selectedPart; + L.Socket.sendMessage('setclientpart part=' + this._selectedPart); + var partNames = textMsg.match(/[^\r\n]+/g); + // only get the last matches + partNames = partNames.slice(partNames.length - this._parts); + this._map.fire('updateparts', { + selectedPart: this._selectedPart, + parts: this._parts, + docType: this._docType, + partNames: partNames + }); + this._update(); + if (this._preFetchPart !== this._selectedPart) { + this._preFetchPart = this._selectedPart; + this._preFetchBorder = null; + } + } } }); diff --git a/loleaflet/src/layer/tile/TileLayer.js b/loleaflet/src/layer/tile/TileLayer.js index 6b30a3a..dbd40bf 100644 --- a/loleaflet/src/layer/tile/TileLayer.js +++ b/loleaflet/src/layer/tile/TileLayer.js @@ -298,47 +298,6 @@ L.TileLayer = L.GridLayer.extend({ } }, - _onStatusMsg: function (textMsg) { - var command = L.Socket.parseServerCmd(textMsg); - if (command.width && command.height && this._documentInfo !== textMsg) { - this._docWidthTwips = command.width; - this._docHeightTwips = command.height; - this._docType = command.type; - this._updateMaxBounds(true); - this._documentInfo = textMsg; - this._parts = command.parts; - this._selectedPart = command.selectedPart; - if (this._docType === 'text') { - this._selectedPart = 0; - this._parts = 1; - this._currentPage = command.selectedPart; - this._pages = command.parts; - this._map.fire('pagenumberchanged', { - currentPage: this._currentPage, - pages: this._pages, - docType: this._docType - }); - } - else { - L.Socket.sendMessage('setclientpart part=' + this._selectedPart); - var partNames = textMsg.match(/[^\r\n]+/g); - // only get the last matches - partNames = partNames.slice(partNames.length - this._parts); - this._map.fire('updateparts', { - selectedPart: this._selectedPart, - parts: this._parts, - docType: this._docType, - partNames: partNames - }); - } - this._update(); - if (this._preFetchPart !== this._selectedPart) { - this._preFetchPart = this._selectedPart; - this._preFetchBorder = null; - } - } - }, - _onStatusIndicatorMsg: function (textMsg) { if (textMsg.startsWith('statusindicatorstart:')) { this._map.fire('statusindicator', {statusType : 'start'}); diff --git a/loleaflet/src/layer/tile/WriterTileLayer.js b/loleaflet/src/layer/tile/WriterTileLayer.js index e2dde74..178c8e6 100644 --- a/loleaflet/src/layer/tile/WriterTileLayer.js +++ b/loleaflet/src/layer/tile/WriterTileLayer.js @@ -79,5 +79,27 @@ L.WriterTileLayer = L.TileLayer.extend({ delete this._tileCache[key]; } } + }, + + _onStatusMsg: function (textMsg) { + var command = L.Socket.parseServerCmd(textMsg); + console.log(textMsg); + if (command.width && command.height && this._documentInfo !== textMsg) { + this._docWidthTwips = command.width; + this._docHeightTwips = command.height; + this._docType = command.type; + this._updateMaxBounds(true); + this._documentInfo = textMsg; + this._selectedPart = 0; + this._parts = 1; + this._currentPage = command.selectedPart; + this._pages = command.parts; + this._map.fire('pagenumberchanged', { + currentPage: this._currentPage, + pages: this._pages, + docType: this._docType + }); + this._update(); + } } }); commit 6e7260f899a107b7886556fb0b0ef1825f60adc4 Author: Mihai Varga <mihai.va...@collabora.com> Date: Wed Sep 2 14:27:29 2015 +0300 loleaflet: fixed typo diff --git a/loleaflet/build/deps.js b/loleaflet/build/deps.js index 08959c2..8b7348c 100644 --- a/loleaflet/build/deps.js +++ b/loleaflet/build/deps.js @@ -63,7 +63,7 @@ var deps = { deps: ['TileLayer'] }, - WriterTileLayer: { + CalcTileLayer: { src: ['layer/tile/CalcTileLayer.js'], desc: 'Calc tile layer.', deps: ['TileLayer'] diff --git a/loleaflet/src/core/Socket.js b/loleaflet/src/core/Socket.js index b25cf1c..b9bf086 100644 --- a/loleaflet/src/core/Socket.js +++ b/loleaflet/src/core/Socket.js @@ -90,13 +90,13 @@ L.Socket = { // first status message, we need to create the document layer var command = this.parseServerCmd(textMsg); var docLayer = null; - if (command.style === 'text') { + if (command.type === 'text') { docLayer = new L.WriterTileLayer('', { edit: this._map.options.edit, readOnly: this._map.options.readOnly }); } - else if (command.style === 'spreadsheet') { + else if (command.type === 'spreadsheet') { docLayer = new L.CalcTileLayer('', { edit: this._map.options.edit, readOnly: this._map.options.readOnly commit 00dcd25e60544b83579472a98c7124d6ef03845f Author: Mihai Varga <mihai.va...@collabora.com> Date: Wed Sep 2 13:57:34 2015 +0300 loleaflet: tile invalidation is now handled in the 3 components diff --git a/loleaflet/src/layer/tile/CalcTileLayer.js b/loleaflet/src/layer/tile/CalcTileLayer.js index 1a1795a..687d03a 100644 --- a/loleaflet/src/layer/tile/CalcTileLayer.js +++ b/loleaflet/src/layer/tile/CalcTileLayer.js @@ -3,4 +3,86 @@ */ L.CalcTileLayer = L.TileLayer.extend({ + + _onInvalidateTilesMsg: function (textMsg) { + var command = L.Socket.parseServerCmd(textMsg); + if (command.x === undefined || command.y === undefined || command.part === undefined) { + var strTwips = textMsg.match(/\d+/g); + command.x = parseInt(strTwips[0]); + command.y = parseInt(strTwips[1]); + command.width = parseInt(strTwips[2]); + command.height = parseInt(strTwips[3]); + command.part = this._currentPart; + } + if (this._docType === 'text') { + command.part = 0; + } + var topLeftTwips = new L.Point(command.x, command.y); + var offset = new L.Point(command.width, command.height); + var bottomRightTwips = topLeftTwips.add(offset); + var invalidBounds = new L.Bounds(topLeftTwips, bottomRightTwips); + var visibleTopLeft = this._latLngToTwips(this._map.getBounds().getNorthWest()); + var visibleBottomRight = this._latLngToTwips(this._map.getBounds().getSouthEast()); + var visibleArea = new L.Bounds(visibleTopLeft, visibleBottomRight); + var toRequest = []; + + for (var key in this._tiles) { + var coords = this._tiles[key].coords; + var tileTopLeft = this._coordsToTwips(coords); + var tileBottomRight = new L.Point(this._tileWidthTwips, this._tileHeightTwips); + var bounds = new L.Bounds(tileTopLeft, tileTopLeft.add(tileBottomRight)); + if (invalidBounds.intersects(bounds) && coords.part === command.part) { + if (this._tiles[key]._invalidCount) { + this._tiles[key]._invalidCount += 1; + } + else { + this._tiles[key]._invalidCount = 1; + } + if (visibleArea.intersects(bounds)) { + var msg = 'tile ' + + 'part=' + coords.part + ' ' + + 'width=' + this._tileSize + ' ' + + 'height=' + this._tileSize + ' ' + + 'tileposx=' + tileTopLeft.x + ' ' + + 'tileposy=' + tileTopLeft.y + ' ' + + 'tilewidth=' + this._tileWidthTwips + ' ' + + 'tileheight=' + this._tileHeightTwips; + toRequest.push({msg: msg, key: key, coords: coords}); + } + else { + // tile outside of the visible area, just remove it + this._preFetchBorder = null; + this._removeTile(key); + } + } + } + + // Sort tiles so that we request those closer to the cursor first + var cursorPos = this._map.project(this._visibleCursor.getNorthWest()); + cursorPos = cursorPos.divideBy(this._tileSize); + toRequest.sort(function(x, y) {return x.coords.distanceTo(cursorPos) - y.coords.distanceTo(cursorPos);}); + for (var i = 0; i < toRequest.length; i++) { + L.Socket.sendMessage(toRequest[i].msg, toRequest[i].key); + } + + for (key in this._tileCache) { + // compute the rectangle that each tile covers in the document based + // on the zoom level + coords = this._keyToTileCoords(key); + if (coords.part !== command.part) { + continue; + } + var scale = this._map.getZoomScale(coords.z); + topLeftTwips = new L.Point( + this.options.tileWidthTwips / scale * coords.x, + this.options.tileHeightTwips / scale * coords.y); + bottomRightTwips = topLeftTwips.add(new L.Point( + this.options.tileWidthTwips / scale, + this.options.tileHeightTwips / scale)); + bounds = new L.Bounds(topLeftTwips, bottomRightTwips); + if (invalidBounds.intersects(bounds)) { + delete this._tileCache[key]; + } + } + } }); diff --git a/loleaflet/src/layer/tile/ImpressTileLayer.js b/loleaflet/src/layer/tile/ImpressTileLayer.js index a2d1fbf..ba2f765 100644 --- a/loleaflet/src/layer/tile/ImpressTileLayer.js +++ b/loleaflet/src/layer/tile/ImpressTileLayer.js @@ -2,6 +2,89 @@ * Impress tile layer is used to display a presentation document */ - L.ImpressTileLayer = L.TileLayer.extend({ + + _onInvalidateTilesMsg: function (textMsg) { + var command = L.Socket.parseServerCmd(textMsg); + if (command.x === undefined || command.y === undefined || command.part === undefined) { + var strTwips = textMsg.match(/\d+/g); + command.x = parseInt(strTwips[0]); + command.y = parseInt(strTwips[1]); + command.width = parseInt(strTwips[2]); + command.height = parseInt(strTwips[3]); + command.part = this._currentPart; + } + var topLeftTwips = new L.Point(command.x, command.y); + var offset = new L.Point(command.width, command.height); + var bottomRightTwips = topLeftTwips.add(offset); + var invalidBounds = new L.Bounds(topLeftTwips, bottomRightTwips); + var visibleTopLeft = this._latLngToTwips(this._map.getBounds().getNorthWest()); + var visibleBottomRight = this._latLngToTwips(this._map.getBounds().getSouthEast()); + var visibleArea = new L.Bounds(visibleTopLeft, visibleBottomRight); + var toRequest = []; + + for (var key in this._tiles) { + var coords = this._tiles[key].coords; + var tileTopLeft = this._coordsToTwips(coords); + var tileBottomRight = new L.Point(this._tileWidthTwips, this._tileHeightTwips); + var bounds = new L.Bounds(tileTopLeft, tileTopLeft.add(tileBottomRight)); + if (invalidBounds.intersects(bounds) && coords.part === command.part) { + if (this._tiles[key]._invalidCount) { + this._tiles[key]._invalidCount += 1; + } + else { + this._tiles[key]._invalidCount = 1; + } + if (visibleArea.intersects(bounds)) { + var msg = 'tile ' + + 'part=' + coords.part + ' ' + + 'width=' + this._tileSize + ' ' + + 'height=' + this._tileSize + ' ' + + 'tileposx=' + tileTopLeft.x + ' ' + + 'tileposy=' + tileTopLeft.y + ' ' + + 'tilewidth=' + this._tileWidthTwips + ' ' + + 'tileheight=' + this._tileHeightTwips; + toRequest.push({msg: msg, key: key, coords: coords}); + } + else { + // tile outside of the visible area, just remove it + this._preFetchBorder = null; + this._removeTile(key); + } + } + } + + // Sort tiles so that we request those closer to the cursor first + var cursorPos = this._map.project(this._visibleCursor.getNorthWest()); + cursorPos = cursorPos.divideBy(this._tileSize); + toRequest.sort(function(x, y) {return x.coords.distanceTo(cursorPos) - y.coords.distanceTo(cursorPos);}); + for (var i = 0; i < toRequest.length; i++) { + L.Socket.sendMessage(toRequest[i].msg, toRequest[i].key); + } + + for (key in this._tileCache) { + // compute the rectangle that each tile covers in the document based + // on the zoom level + coords = this._keyToTileCoords(key); + if (coords.part !== command.part) { + continue; + } + var scale = this._map.getZoomScale(coords.z); + topLeftTwips = new L.Point( + this.options.tileWidthTwips / scale * coords.x, + this.options.tileHeightTwips / scale * coords.y); + bottomRightTwips = topLeftTwips.add(new L.Point( + this.options.tileWidthTwips / scale, + this.options.tileHeightTwips / scale)); + bounds = new L.Bounds(topLeftTwips, bottomRightTwips); + if (invalidBounds.intersects(bounds)) { + delete this._tileCache[key]; + } + } + if (command.part === this._currentPart && + command.part !== this._lastValidPart) { + this._lastValidPart = command.part; + this._map.fire('updatepart', {part: command.part, docType: this._docType}); + } + } }); diff --git a/loleaflet/src/layer/tile/TileLayer.js b/loleaflet/src/layer/tile/TileLayer.js index 9f9176b..6b30a3a 100644 --- a/loleaflet/src/layer/tile/TileLayer.js +++ b/loleaflet/src/layer/tile/TileLayer.js @@ -266,94 +266,6 @@ L.TileLayer = L.GridLayer.extend({ this._onUpdateCursor(); }, - _onInvalidateTilesMsg: function (textMsg) { - var command = L.Socket.parseServerCmd(textMsg); - if (command.x === undefined || command.y === undefined || command.part === undefined) { - var strTwips = textMsg.match(/\d+/g); - command.x = parseInt(strTwips[0]); - command.y = parseInt(strTwips[1]); - command.width = parseInt(strTwips[2]); - command.height = parseInt(strTwips[3]); - command.part = this._selectedPart; - } - if (this._docType === 'text') { - command.part = 0; - } - var topLeftTwips = new L.Point(command.x, command.y); - var offset = new L.Point(command.width, command.height); - var bottomRightTwips = topLeftTwips.add(offset); - var invalidBounds = new L.Bounds(topLeftTwips, bottomRightTwips); - var visibleTopLeft = this._latLngToTwips(this._map.getBounds().getNorthWest()); - var visibleBottomRight = this._latLngToTwips(this._map.getBounds().getSouthEast()); - var visibleArea = new L.Bounds(visibleTopLeft, visibleBottomRight); - var toRequest = []; - - for (var key in this._tiles) { - var coords = this._tiles[key].coords; - var tileTopLeft = this._coordsToTwips(coords); - var tileBottomRight = new L.Point(this._tileWidthTwips, this._tileHeightTwips); - var bounds = new L.Bounds(tileTopLeft, tileTopLeft.add(tileBottomRight)); - if (invalidBounds.intersects(bounds) && coords.part === command.part) { - if (this._tiles[key]._invalidCount) { - this._tiles[key]._invalidCount += 1; - } - else { - this._tiles[key]._invalidCount = 1; - } - if (visibleArea.intersects(bounds)) { - var msg = 'tile ' + - 'part=' + coords.part + ' ' + - 'width=' + this._tileSize + ' ' + - 'height=' + this._tileSize + ' ' + - 'tileposx=' + tileTopLeft.x + ' ' + - 'tileposy=' + tileTopLeft.y + ' ' + - 'tilewidth=' + this._tileWidthTwips + ' ' + - 'tileheight=' + this._tileHeightTwips; - toRequest.push({msg: msg, key: key, coords: coords}); - } - else { - // tile outside of the visible area, just remove it - this._preFetchBorder = null; - this._removeTile(key); - } - } - } - - // Sort tiles so that we request those closer to the cursor first - var cursorPos = this._map.project(this._visibleCursor.getNorthWest()); - cursorPos = cursorPos.divideBy(this._tileSize); - toRequest.sort(function(x, y) {return x.coords.distanceTo(cursorPos) - y.coords.distanceTo(cursorPos);}); - for (var i = 0; i < toRequest.length; i++) { - L.Socket.sendMessage(toRequest[i].msg, toRequest[i].key); - } - - for (key in this._tileCache) { - // compute the rectangle that each tile covers in the document based - // on the zoom level - coords = this._keyToTileCoords(key); - if (coords.part !== command.part) { - continue; - } - var scale = this._map.getZoomScale(coords.z); - topLeftTwips = new L.Point( - this.options.tileWidthTwips / scale * coords.x, - this.options.tileHeightTwips / scale * coords.y); - bottomRightTwips = topLeftTwips.add(new L.Point( - this.options.tileWidthTwips / scale, - this.options.tileHeightTwips / scale)); - bounds = new L.Bounds(topLeftTwips, bottomRightTwips); - if (invalidBounds.intersects(bounds)) { - delete this._tileCache[key]; - } - } - if (command.part === this._selectedPart && - command.part !== this._lastValidPart) { - this._lastValidPart = command.part; - this._map.fire('updatepart', {part: command.part, docType: this._docType}); - } - - }, - _onSearchNotFoundMsg: function (textMsg) { var originalPhrase = textMsg.substring(16); this._map.fire('search', {originalPhrase: originalPhrase, count: 0}); diff --git a/loleaflet/src/layer/tile/WriterTileLayer.js b/loleaflet/src/layer/tile/WriterTileLayer.js index 6eb0258..e2dde74 100644 --- a/loleaflet/src/layer/tile/WriterTileLayer.js +++ b/loleaflet/src/layer/tile/WriterTileLayer.js @@ -3,4 +3,81 @@ */ L.WriterTileLayer = L.TileLayer.extend({ + + _onInvalidateTilesMsg: function (textMsg) { + var command = L.Socket.parseServerCmd(textMsg); + if (command.x === undefined || command.y === undefined || command.part === undefined) { + var strTwips = textMsg.match(/\d+/g); + command.x = parseInt(strTwips[0]); + command.y = parseInt(strTwips[1]); + command.width = parseInt(strTwips[2]); + command.height = parseInt(strTwips[3]); + command.part = this._currentPart; + } + command.part = 0; + var topLeftTwips = new L.Point(command.x, command.y); + var offset = new L.Point(command.width, command.height); + var bottomRightTwips = topLeftTwips.add(offset); + var invalidBounds = new L.Bounds(topLeftTwips, bottomRightTwips); + var visibleTopLeft = this._latLngToTwips(this._map.getBounds().getNorthWest()); + var visibleBottomRight = this._latLngToTwips(this._map.getBounds().getSouthEast()); + var visibleArea = new L.Bounds(visibleTopLeft, visibleBottomRight); + var toRequest = []; + + for (var key in this._tiles) { + var coords = this._tiles[key].coords; + var tileTopLeft = this._coordsToTwips(coords); + var tileBottomRight = new L.Point(this._tileWidthTwips, this._tileHeightTwips); + var bounds = new L.Bounds(tileTopLeft, tileTopLeft.add(tileBottomRight)); + if (invalidBounds.intersects(bounds) && coords.part === command.part) { + if (this._tiles[key]._invalidCount) { + this._tiles[key]._invalidCount += 1; + } + else { + this._tiles[key]._invalidCount = 1; + } + if (visibleArea.intersects(bounds)) { + var msg = 'tile ' + + 'part=' + coords.part + ' ' + + 'width=' + this._tileSize + ' ' + + 'height=' + this._tileSize + ' ' + + 'tileposx=' + tileTopLeft.x + ' ' + + 'tileposy=' + tileTopLeft.y + ' ' + + 'tilewidth=' + this._tileWidthTwips + ' ' + + 'tileheight=' + this._tileHeightTwips; + toRequest.push({msg: msg, key: key, coords: coords}); + } + else { + // tile outside of the visible area, just remove it + this._preFetchBorder = null; + this._removeTile(key); + } + } + } + + // Sort tiles so that we request those closer to the cursor first + var cursorPos = this._map.project(this._visibleCursor.getNorthWest()); + cursorPos = cursorPos.divideBy(this._tileSize); + toRequest.sort(function(x, y) {return x.coords.distanceTo(cursorPos) - y.coords.distanceTo(cursorPos);}); + for (var i = 0; i < toRequest.length; i++) { + L.Socket.sendMessage(toRequest[i].msg, toRequest[i].key); + } + + for (key in this._tileCache) { + // compute the rectangle that each tile covers in the document based + // on the zoom level + coords = this._keyToTileCoords(key); + var scale = this._map.getZoomScale(coords.z); + topLeftTwips = new L.Point( + this.options.tileWidthTwips / scale * coords.x, + this.options.tileHeightTwips / scale * coords.y); + bottomRightTwips = topLeftTwips.add(new L.Point( + this.options.tileWidthTwips / scale, + this.options.tileHeightTwips / scale)); + bounds = new L.Bounds(topLeftTwips, bottomRightTwips); + if (invalidBounds.intersects(bounds)) { + delete this._tileCache[key]; + } + } + } }); commit 6e74a351ba05765a7c2934c133915f8991cb2697 Author: Mihai Varga <mihai.va...@collabora.com> Date: Wed Sep 2 12:28:37 2015 +0300 loleaflet: renamed 'currentPart' to 'selectedPart' diff --git a/loleaflet/src/control/Control.Parts.js b/loleaflet/src/control/Control.Parts.js index 9fc0b16..4a24e78 100644 --- a/loleaflet/src/control/Control.Parts.js +++ b/loleaflet/src/control/Control.Parts.js @@ -62,17 +62,17 @@ L.Control.Parts = L.Control.extend({ _updateDisabled: function (e) { var className = 'leaflet-disabled'; var parts = e.parts; - var currentPart = e.currentPart; + var selectedPart = e.selectedPart; var docType = e.docType; if (docType === 'text') { return; } - if (currentPart === 0) { + if (selectedPart === 0) { L.DomUtil.addClass(this._prevPartButton, className); } else { L.DomUtil.removeClass(this._prevPartButton, className); } - if (currentPart === parts - 1) { + if (selectedPart === parts - 1) { L.DomUtil.addClass(this._nextPartButton, className); } else { L.DomUtil.removeClass(this._nextPartButton, className); diff --git a/loleaflet/src/control/Control.Tabs.js b/loleaflet/src/control/Control.Tabs.js index cce0de9..b5ce57d 100644 --- a/loleaflet/src/control/Control.Tabs.js +++ b/loleaflet/src/control/Control.Tabs.js @@ -15,7 +15,7 @@ L.Control.Tabs = L.Control.extend({ _updateDisabled: function (e) { var parts = e.parts; - var currentPart = e.currentPart; + var selectedPart = e.selectedPart; var docType = e.docType; var partNames = e.partNames; if (docType === 'text') { @@ -47,7 +47,7 @@ L.Control.Tabs = L.Control.extend({ for (var key in this._spreadsheetTabs) { var part = parseInt(key.match(/\d+/g)[0]); L.DomUtil.removeClass(this._spreadsheetTabs[key], 'selected'); - if (part === currentPart) { + if (part === selectedPart) { L.DomUtil.addClass(this._spreadsheetTabs[key], 'selected'); } } diff --git a/loleaflet/src/control/Parts.js b/loleaflet/src/control/Parts.js index 7089cfb..08e1c89 100644 --- a/loleaflet/src/control/Parts.js +++ b/loleaflet/src/control/Parts.js @@ -5,17 +5,17 @@ L.Map.include({ setPart: function (part) { var docLayer = this._docLayer; if (part === 'prev') { - if (docLayer._currentPart > 0) { - docLayer._currentPart -= 1; + if (docLayer._selectedPart > 0) { + docLayer._selectedPart -= 1; } } else if (part === 'next') { - if (docLayer._currentPart < docLayer._parts - 1) { - docLayer._currentPart += 1; + if (docLayer._selectedPart < docLayer._parts - 1) { + docLayer._selectedPart += 1; } } else if (typeof (part) === 'number' && part >= 0 && part < docLayer._parts) { - docLayer._currentPart = part; + docLayer._selectedPart = part; } else { return; @@ -25,11 +25,11 @@ L.Map.include({ L.Socket.sendMessage('resetselection'); } this.fire('updateparts', { - currentPart: docLayer._currentPart, + selectedPart: docLayer._selectedPart, parts: docLayer._parts, docType: docLayer._docType }); - L.Socket.sendMessage('setclientpart part=' + docLayer._currentPart); + L.Socket.sendMessage('setclientpart part=' + docLayer._selectedPart); docLayer._update(); docLayer._pruneTiles(); docLayer._clearSelections(); @@ -114,7 +114,7 @@ L.Map.include({ }, getCurrentPartNumber: function () { - return this._docLayer._currentPart; + return this._docLayer._selectedPart; }, getDocSize: function () { diff --git a/loleaflet/src/core/Socket.js b/loleaflet/src/core/Socket.js index 5e49874..b25cf1c 100644 --- a/loleaflet/src/core/Socket.js +++ b/loleaflet/src/core/Socket.js @@ -160,7 +160,7 @@ L.Socket = { command.parts = parseInt(tokens[i].substring(6)); } else if (tokens[i].substring(0, 8) === 'current=') { - command.currentPart = parseInt(tokens[i].substring(8)); + command.selectedPart = parseInt(tokens[i].substring(8)); } else if (tokens[i].substring(0, 3) === 'id=') { // remove newline characters diff --git a/loleaflet/src/layer/tile/GridLayer.js b/loleaflet/src/layer/tile/GridLayer.js index d46eeec..95469d5 100644 --- a/loleaflet/src/layer/tile/GridLayer.js +++ b/loleaflet/src/layer/tile/GridLayer.js @@ -466,7 +466,7 @@ L.GridLayer = L.Layer.extend({ for (var key in this._tiles) { if (this._keyToTileCoords(key).z !== zoom || - this._keyToTileCoords(key).part !== this._currentPart) { + this._keyToTileCoords(key).part !== this._selectedPart) { this._tiles[key].current = false; } } @@ -478,7 +478,7 @@ L.GridLayer = L.Layer.extend({ for (var i = tileRange.min.x; i <= tileRange.max.x; i++) { var coords = new L.Point(i, j); coords.z = zoom; - coords.part = this._currentPart; + coords.part = this._selectedPart; if (!this._isValidTile(coords)) { continue; } @@ -615,7 +615,7 @@ L.GridLayer = L.Layer.extend({ var tilePos = this._getTilePos(coords), key = this._tileCoordsToKey(coords); - if (coords.part === this._currentPart) { + if (coords.part === this._selectedPart) { var tile = this.createTile(this._wrapCoords(coords), L.bind(this._tileReady, this, coords)); this._initTile(tile); @@ -656,7 +656,7 @@ L.GridLayer = L.Layer.extend({ 'tileposy=' + twips.y + ' ' + 'tilewidth=' + this._tileWidthTwips + ' ' + 'tileheight=' + this._tileHeightTwips; - if (coords.part !== this._currentPart) { + if (coords.part !== this._selectedPart) { msg += ' prefetch=true'; } L.Socket.sendMessage(msg, key); @@ -766,7 +766,7 @@ L.GridLayer = L.Layer.extend({ } if (!this._preFetchBorder) { - if (this._currentPart !== this._preFetchPart) { + if (this._selectedPart !== this._preFetchPart) { // all tiles from the new part have to be pre-fetched var tileBorder = this._preFetchBorder = new L.Bounds(new L.Point(0, 0), new L.Point(0, 0)); } @@ -851,36 +851,36 @@ L.GridLayer = L.Layer.extend({ tileBorder.max.x * this._tileWidthTwips < this._docWidthTwips || tileBorder.max.y * this._tileHeightTwips < this._docHeightTwips) && this.options.preFetchOtherParts) { - var diff = this._preFetchPart - this._currentPart; - if (diff === 0 && this._currentPart < this._parts - 1) { + var diff = this._preFetchPart - this._selectedPart; + if (diff === 0 && this._selectedPart < this._parts - 1) { this._preFetchPart += 1; this._preFetchBorder = null; } - else if (diff === 0 && this._currentPart > 0) { + else if (diff === 0 && this._selectedPart > 0) { this._preFetchPart -= 1; this._preFetchBorder = null; } else if (diff > 0) { - if (this._currentPart - diff >= 0) { + if (this._selectedPart - diff >= 0) { // lower part number - this._preFetchPart = this._currentPart - diff; + this._preFetchPart = this._selectedPart - diff; this._preFetchBorder = null; } - else if (this._currentPart + diff + 1 < this._parts) { + else if (this._selectedPart + diff + 1 < this._parts) { // higher part number - this._preFetchPart = this._currentPart + diff + 1; + this._preFetchPart = this._selectedPart + diff + 1; this._preFetchBorder = null; } } else if (diff < 0) { - if (this._currentPart - diff + 1 < this._parts) { + if (this._selectedPart - diff + 1 < this._parts) { // higher part number - this._preFetchPart = this._currentPart - diff + 1; + this._preFetchPart = this._selectedPart - diff + 1; this._preFetchBorder = null; } - else if (this._currentPart + diff - 1 >= 0) { + else if (this._selectedPart + diff - 1 >= 0) { // lower part number - this._preFetchPart = this._currentPart + diff - 1; + this._preFetchPart = this._selectedPart + diff - 1; this._preFetchBorder = null; } } @@ -904,7 +904,7 @@ L.GridLayer = L.Layer.extend({ } var interval = 750; var idleTime = 5000; - this._preFetchPart = this._currentPart; + this._preFetchPart = this._selectedPart; this._preFetchIdle = setTimeout(L.bind(function () { this._tilesPreFetcher = setInterval(L.bind(this._preFetchTiles, this), interval); }, this), idleTime); diff --git a/loleaflet/src/layer/tile/TileLayer.js b/loleaflet/src/layer/tile/TileLayer.js index 06927ab..9f9176b 100644 --- a/loleaflet/src/layer/tile/TileLayer.js +++ b/loleaflet/src/layer/tile/TileLayer.js @@ -274,7 +274,7 @@ L.TileLayer = L.GridLayer.extend({ command.y = parseInt(strTwips[1]); command.width = parseInt(strTwips[2]); command.height = parseInt(strTwips[3]); - command.part = this._currentPart; + command.part = this._selectedPart; } if (this._docType === 'text') { command.part = 0; @@ -346,7 +346,7 @@ L.TileLayer = L.GridLayer.extend({ delete this._tileCache[key]; } } - if (command.part === this._currentPart && + if (command.part === this._selectedPart && command.part !== this._lastValidPart) { this._lastValidPart = command.part; this._map.fire('updatepart', {part: command.part, docType: this._docType}); @@ -361,11 +361,11 @@ L.TileLayer = L.GridLayer.extend({ _onSetPartMsg: function (textMsg) { var part = parseInt(textMsg.match(/\d+/g)[0]); - if (part !== this._currentPart && this._docType !== 'text') { - this._currentPart = part; + if (part !== this._selectedPart && this._docType !== 'text') { + this._selectedPart = part; this._update(); this._clearSelections(); - this._map.fire('setpart', {currentPart: this._currentPart}); + this._map.fire('setpart', {selectedPart: this._selectedPart}); } else if (this._docType === 'text') { this._currentPage = part; @@ -395,11 +395,11 @@ L.TileLayer = L.GridLayer.extend({ this._updateMaxBounds(true); this._documentInfo = textMsg; this._parts = command.parts; - this._currentPart = command.currentPart; + this._selectedPart = command.selectedPart; if (this._docType === 'text') { - this._currentPart = 0; + this._selectedPart = 0; this._parts = 1; - this._currentPage = command.currentPart; + this._currentPage = command.selectedPart; this._pages = command.parts; this._map.fire('pagenumberchanged', { currentPage: this._currentPage, @@ -408,20 +408,20 @@ L.TileLayer = L.GridLayer.extend({ }); } else { - L.Socket.sendMessage('setclientpart part=' + this._currentPart); + L.Socket.sendMessage('setclientpart part=' + this._selectedPart); var partNames = textMsg.match(/[^\r\n]+/g); // only get the last matches partNames = partNames.slice(partNames.length - this._parts); this._map.fire('updateparts', { - currentPart: this._currentPart, + selectedPart: this._selectedPart, parts: this._parts, docType: this._docType, partNames: partNames }); } this._update(); - if (this._preFetchPart !== this._currentPart) { - this._preFetchPart = this._currentPart; + if (this._preFetchPart !== this._selectedPart) { + this._preFetchPart = this._selectedPart; this._preFetchBorder = null; } } commit 5d35d050e0391fa4450862fdc7b338cf2de7978a Author: Mihai Varga <mihai.va...@collabora.com> Date: Wed Sep 2 12:04:13 2015 +0300 loleaflet: alphabetically ordered the server commands diff --git a/loleaflet/src/layer/tile/TileLayer.js b/loleaflet/src/layer/tile/TileLayer.js index 36f0156..06927ab 100644 --- a/loleaflet/src/layer/tile/TileLayer.js +++ b/loleaflet/src/layer/tile/TileLayer.js @@ -178,21 +178,24 @@ L.TileLayer = L.GridLayer.extend({ if (textMsg.startsWith('cursorvisible:')) { this._onCursorVisibleMsg(textMsg); } - else if (textMsg.startsWith('invalidatecursor:')) { - this._onInvalidateCursorMsg(textMsg); - } - else if (textMsg.startsWith('textselectionstart:')) { - this._onTextSelectionStartMsg(textMsg); - } - else if (textMsg.startsWith('textselectionend:')) { - this._onTextSelectionEndMsg(textMsg); + else if (textMsg.startsWith('error:')) { + this._onErrorMsg(textMsg); } else if (textMsg.startsWith('graphicselection:')) { this._onGraphicSelectionMsg(textMsg); } + else if (textMsg.startsWith('invalidatecursor:')) { + this._onInvalidateCursorMsg(textMsg); + } else if (textMsg.startsWith('invalidatetiles:') && !textMsg.match('EMPTY')) { this._onInvalidateTilesMsg(textMsg); } + else if (textMsg.startsWith('searchnotfound:')) { + this._onSearchNotFoundMsg(textMsg); + } + else if (textMsg.startsWith('setpart:')) { + this._onSetPartMsg(textMsg); + } else if (textMsg.startsWith('statechanged:')) { this._onStateChangedMsg(textMsg); } @@ -202,8 +205,8 @@ L.TileLayer = L.GridLayer.extend({ else if (textMsg.startsWith('statusindicator')) { this._onStatusIndicatorMsg(textMsg); } - else if (textMsg.startsWith('tile:')) { - this._onTileMsg(textMsg, imgBytes, index); + else if (textMsg.startsWith('styles:')) { + this._onStylesMsg(textMsg); } else if (textMsg.startsWith('textselection:')) { this._onTextSelectionMsg(textMsg); @@ -211,17 +214,14 @@ L.TileLayer = L.GridLayer.extend({ else if (textMsg.startsWith('textselectioncontent:')) { this._onTextSelectionContentMsg(textMsg); } - else if (textMsg.startsWith('setpart:')) { - this._onSetPartMsg(textMsg); - } - else if (textMsg.startsWith('searchnotfound:')) { - this._onSearchNotFoundMsg(textMsg); + else if (textMsg.startsWith('textselectionend:')) { + this._onTextSelectionEndMsg(textMsg); } - else if (textMsg.startsWith('styles:')) { - this._onStylesMsg(textMsg); + else if (textMsg.startsWith('textselectionstart:')) { + this._onTextSelectionStartMsg(textMsg); } - else if (textMsg.startsWith('error:')) { - this._onErrorMsg(textMsg); + else if (textMsg.startsWith('tile:')) { + this._onTileMsg(textMsg, imgBytes, index); } }, commit c921432ad02f299234c974644d38a6cc5dddbae3 Author: Mihai Varga <mihai.va...@collabora.com> Date: Wed Sep 2 11:59:38 2015 +0300 loleaflet: modularized the onMessage method Conflicts: loleaflet/src/layer/tile/TileLayer.js diff --git a/loleaflet/src/layer/tile/TileLayer.js b/loleaflet/src/layer/tile/TileLayer.js index 1f60b48..36f0156 100644 --- a/loleaflet/src/layer/tile/TileLayer.js +++ b/loleaflet/src/layer/tile/TileLayer.js @@ -176,198 +176,259 @@ L.TileLayer = L.GridLayer.extend({ _onMessage: function (textMsg, imgBytes, index) { if (textMsg.startsWith('cursorvisible:')) { - var command = textMsg.match('cursorvisible: true'); - this._isCursorVisible = command ? true : false; - this._isCursorOverlayVisible = true; - this._onUpdateCursor(); + this._onCursorVisibleMsg(textMsg); } else if (textMsg.startsWith('invalidatecursor:')) { - var strTwips = textMsg.match(/\d+/g); - var topLeftTwips = new L.Point(parseInt(strTwips[0]), parseInt(strTwips[1])); - var offset = new L.Point(parseInt(strTwips[2]), parseInt(strTwips[3])); - var bottomRightTwips = topLeftTwips.add(offset); - this._visibleCursor = new L.LatLngBounds( - this._twipsToLatLng(topLeftTwips, this._map.getZoom()), - this._twipsToLatLng(bottomRightTwips, this._map.getZoom())); - this._isCursorOverlayVisible = true; - this._onUpdateCursor(); + this._onInvalidateCursorMsg(textMsg); } else if (textMsg.startsWith('textselectionstart:')) { - strTwips = textMsg.match(/\d+/g); - if (strTwips != null) { - topLeftTwips = new L.Point(parseInt(strTwips[0]), parseInt(strTwips[1])); - offset = new L.Point(parseInt(strTwips[2]), parseInt(strTwips[3])); - bottomRightTwips = topLeftTwips.add(offset); - this._textSelectionStart = new L.LatLngBounds( - this._twipsToLatLng(topLeftTwips, this._map.getZoom()), - this._twipsToLatLng(bottomRightTwips, this._map.getZoom())); - } - else { - this._textSelectionStart = new L.LatLngBounds(new L.LatLng(0, 0), new L.LatLng(0, 0)); - } + this._onTextSelectionStartMsg(textMsg); } else if (textMsg.startsWith('textselectionend:')) { - strTwips = textMsg.match(/\d+/g); - if (strTwips != null) { - topLeftTwips = new L.Point(parseInt(strTwips[0]), parseInt(strTwips[1])); - offset = new L.Point(parseInt(strTwips[2]), parseInt(strTwips[3])); - bottomRightTwips = topLeftTwips.add(offset); - this._textSelectionEnd = new L.LatLngBounds( - this._twipsToLatLng(topLeftTwips, this._map.getZoom()), - this._twipsToLatLng(bottomRightTwips, this._map.getZoom())); - } - else { - this._textSelectionEnd = new L.LatLngBounds(new L.LatLng(0, 0), new L.LatLng(0, 0)); - } + this._onTextSelectionEndMsg(textMsg); } else if (textMsg.startsWith('graphicselection:')) { - if (textMsg.match('EMPTY')) { - this._graphicSelection = new L.LatLngBounds(new L.LatLng(0, 0), new L.LatLng(0, 0)); - } - else { - strTwips = textMsg.match(/\d+/g); - topLeftTwips = new L.Point(parseInt(strTwips[0]), parseInt(strTwips[1])); - offset = new L.Point(parseInt(strTwips[2]), parseInt(strTwips[3])); - bottomRightTwips = topLeftTwips.add(offset); - this._graphicSelection = new L.LatLngBounds( - this._twipsToLatLng(topLeftTwips, this._map.getZoom()), - this._twipsToLatLng(bottomRightTwips, this._map.getZoom())); - } - - this._onUpdateGraphicSelection(); + this._onGraphicSelectionMsg(textMsg); } else if (textMsg.startsWith('invalidatetiles:') && !textMsg.match('EMPTY')) { - command = L.Socket.parseServerCmd(textMsg); - if (command.x === undefined || command.y === undefined || command.part === undefined) { - strTwips = textMsg.match(/\d+/g); - command.x = parseInt(strTwips[0]); - command.y = parseInt(strTwips[1]); - command.width = parseInt(strTwips[2]); - command.height = parseInt(strTwips[3]); - command.part = this._currentPart; - } - if (this._docType === 'text') { - command.part = 0; - } - topLeftTwips = new L.Point(command.x, command.y); - offset = new L.Point(command.width, command.height); - bottomRightTwips = topLeftTwips.add(offset); - var invalidBounds = new L.Bounds(topLeftTwips, bottomRightTwips); - var visibleTopLeft = this._latLngToTwips(this._map.getBounds().getNorthWest()); - var visibleBottomRight = this._latLngToTwips(this._map.getBounds().getSouthEast()); - var visibleArea = new L.Bounds(visibleTopLeft, visibleBottomRight); - var toRequest = []; - - for (var key in this._tiles) { - var coords = this._tiles[key].coords; - var tileTopLeft = this._coordsToTwips(coords); - var tileBottomRight = new L.Point(this._tileWidthTwips, this._tileHeightTwips); - var bounds = new L.Bounds(tileTopLeft, tileTopLeft.add(tileBottomRight)); - if (invalidBounds.intersects(bounds) && coords.part === command.part) { - if (this._tiles[key]._invalidCount) { - this._tiles[key]._invalidCount += 1; - } - else { - this._tiles[key]._invalidCount = 1; - } - if (visibleArea.intersects(bounds)) { - var msg = 'tile ' + - 'part=' + coords.part + ' ' + - 'width=' + this._tileSize + ' ' + - 'height=' + this._tileSize + ' ' + - 'tileposx=' + tileTopLeft.x + ' ' + - 'tileposy=' + tileTopLeft.y + ' ' + - 'tilewidth=' + this._tileWidthTwips + ' ' + - 'tileheight=' + this._tileHeightTwips; - toRequest.push({msg: msg, key: key, coords: coords}); - } - else { - // tile outside of the visible area, just remove it - this._preFetchBorder = null; - this._removeTile(key); - } - } - } - var cursorPos = this._map.project(this._visibleCursor.getNorthWest()); - cursorPos = cursorPos.divideBy(this._tileSize); - toRequest.sort(function(x, y) {return x.coords.distanceTo(cursorPos) - y.coords.distanceTo(cursorPos);}); - for (var i = 0; i < toRequest.length; i++) { - L.Socket.sendMessage(toRequest[i].msg, toRequest[i].key); - } - for (key in this._tileCache) { - // compute the rectangle that each tile covers in the document based - // on the zoom level - coords = this._keyToTileCoords(key); - if (coords.part !== command.part) { - continue; - } - var scale = this._map.getZoomScale(coords.z); - topLeftTwips = new L.Point( - this.options.tileWidthTwips / scale * coords.x, - this.options.tileHeightTwips / scale * coords.y); - bottomRightTwips = topLeftTwips.add(new L.Point( - this.options.tileWidthTwips / scale, - this.options.tileHeightTwips / scale)); - bounds = new L.Bounds(topLeftTwips, bottomRightTwips); - if (invalidBounds.intersects(bounds)) { - delete this._tileCache[key]; - } - } - if (command.part === this._currentPart && - command.part !== this._lastValidPart) { - this._lastValidPart = command.part; - this._map.fire('updatepart', {part: command.part, docType: this._docType}); - } + this._onInvalidateTilesMsg(textMsg); } else if (textMsg.startsWith('statechanged:')) { - var unoMsg = textMsg.substr(14); - var unoCmd = unoMsg.match('.uno:(.*)=')[1]; - var state = unoMsg.match('.*=(.*)')[1]; - if (unoCmd && state) { - this._map.fire('commandstatechanged', {unoCmd : unoCmd, state : state}); - } + this._onStateChangedMsg(textMsg); } else if (textMsg.startsWith('status:')) { - command = L.Socket.parseServerCmd(textMsg); - if (command.width && command.height && this._documentInfo !== textMsg) { - this._docWidthTwips = command.width; - this._docHeightTwips = command.height; - this._docType = command.type; - this._updateMaxBounds(true); - this._documentInfo = textMsg; - this._parts = command.parts; - this._currentPart = command.currentPart; - if (this._docType === 'text') { - this._currentPart = 0; - this._parts = 1; - this._currentPage = command.currentPart; - this._pages = command.parts; - this._map.fire('pagenumberchanged', { - currentPage: this._currentPage, - pages: this._pages, - docType: this._docType - }); + this._onStatusMsg(textMsg); + } + else if (textMsg.startsWith('statusindicator')) { + this._onStatusIndicatorMsg(textMsg); + } + else if (textMsg.startsWith('tile:')) { + this._onTileMsg(textMsg, imgBytes, index); + } + else if (textMsg.startsWith('textselection:')) { + this._onTextSelectionMsg(textMsg); + } + else if (textMsg.startsWith('textselectioncontent:')) { + this._onTextSelectionContentMsg(textMsg); + } + else if (textMsg.startsWith('setpart:')) { + this._onSetPartMsg(textMsg); + } + else if (textMsg.startsWith('searchnotfound:')) { + this._onSearchNotFoundMsg(textMsg); + } + else if (textMsg.startsWith('styles:')) { + this._onStylesMsg(textMsg); + } + else if (textMsg.startsWith('error:')) { + this._onErrorMsg(textMsg); + } + }, + + _onCursorVisibleMsg: function(textMsg) { + var command = textMsg.match('cursorvisible: true'); + this._isCursorVisible = command ? true : false; + this._isCursorOverlayVisible = true; + this._onUpdateCursor(); + }, + + _onErrorMsg: function (textMsg) { + var command = L.Socket.parseServerCmd(textMsg); + this._map.fire('error', {cmd: command.errorCmd, kind: command.errorKind}); + }, + + _onGraphicSelectionMsg: function (textMsg) { + if (textMsg.match('EMPTY')) { + this._graphicSelection = new L.LatLngBounds(new L.LatLng(0, 0), new L.LatLng(0, 0)); + } + else { + var strTwips = textMsg.match(/\d+/g); + var topLeftTwips = new L.Point(parseInt(strTwips[0]), parseInt(strTwips[1])); + var offset = new L.Point(parseInt(strTwips[2]), parseInt(strTwips[3])); + var bottomRightTwips = topLeftTwips.add(offset); + this._graphicSelection = new L.LatLngBounds( + this._twipsToLatLng(topLeftTwips, this._map.getZoom()), + this._twipsToLatLng(bottomRightTwips, this._map.getZoom())); + } + + this._onUpdateGraphicSelection(); + }, + + _onInvalidateCursorMsg: function (textMsg) { + var strTwips = textMsg.match(/\d+/g); + var topLeftTwips = new L.Point(parseInt(strTwips[0]), parseInt(strTwips[1])); + var offset = new L.Point(parseInt(strTwips[2]), parseInt(strTwips[3])); + var bottomRightTwips = topLeftTwips.add(offset); + this._visibleCursor = new L.LatLngBounds( + this._twipsToLatLng(topLeftTwips, this._map.getZoom()), + this._twipsToLatLng(bottomRightTwips, this._map.getZoom())); + this._isCursorOverlayVisible = true; + this._onUpdateCursor(); + }, + + _onInvalidateTilesMsg: function (textMsg) { + var command = L.Socket.parseServerCmd(textMsg); + if (command.x === undefined || command.y === undefined || command.part === undefined) { + var strTwips = textMsg.match(/\d+/g); + command.x = parseInt(strTwips[0]); + command.y = parseInt(strTwips[1]); + command.width = parseInt(strTwips[2]); + command.height = parseInt(strTwips[3]); + command.part = this._currentPart; + } + if (this._docType === 'text') { + command.part = 0; + } + var topLeftTwips = new L.Point(command.x, command.y); + var offset = new L.Point(command.width, command.height); + var bottomRightTwips = topLeftTwips.add(offset); + var invalidBounds = new L.Bounds(topLeftTwips, bottomRightTwips); + var visibleTopLeft = this._latLngToTwips(this._map.getBounds().getNorthWest()); + var visibleBottomRight = this._latLngToTwips(this._map.getBounds().getSouthEast()); + var visibleArea = new L.Bounds(visibleTopLeft, visibleBottomRight); + var toRequest = []; + + for (var key in this._tiles) { + var coords = this._tiles[key].coords; + var tileTopLeft = this._coordsToTwips(coords); + var tileBottomRight = new L.Point(this._tileWidthTwips, this._tileHeightTwips); + var bounds = new L.Bounds(tileTopLeft, tileTopLeft.add(tileBottomRight)); + if (invalidBounds.intersects(bounds) && coords.part === command.part) { + if (this._tiles[key]._invalidCount) { + this._tiles[key]._invalidCount += 1; } else { - L.Socket.sendMessage('setclientpart part=' + this._currentPart); - var partNames = textMsg.match(/[^\r\n]+/g); - // only get the last matches - partNames = partNames.slice(partNames.length - this._parts); - this._map.fire('updateparts', { - currentPart: this._currentPart, - parts: this._parts, - docType: this._docType, - partNames: partNames - }); + this._tiles[key]._invalidCount = 1; + } + if (visibleArea.intersects(bounds)) { + var msg = 'tile ' + + 'part=' + coords.part + ' ' + + 'width=' + this._tileSize + ' ' + + 'height=' + this._tileSize + ' ' + + 'tileposx=' + tileTopLeft.x + ' ' + + 'tileposy=' + tileTopLeft.y + ' ' + + 'tilewidth=' + this._tileWidthTwips + ' ' + + 'tileheight=' + this._tileHeightTwips; + toRequest.push({msg: msg, key: key, coords: coords}); } - this._update(); - if (this._preFetchPart !== this._currentPart) { - this._preFetchPart = this._currentPart; + else { + // tile outside of the visible area, just remove it this._preFetchBorder = null; + this._removeTile(key); } } } - else if (textMsg.startsWith('statusindicatorstart:')) { + + // Sort tiles so that we request those closer to the cursor first + var cursorPos = this._map.project(this._visibleCursor.getNorthWest()); + cursorPos = cursorPos.divideBy(this._tileSize); + toRequest.sort(function(x, y) {return x.coords.distanceTo(cursorPos) - y.coords.distanceTo(cursorPos);}); + for (var i = 0; i < toRequest.length; i++) { + L.Socket.sendMessage(toRequest[i].msg, toRequest[i].key); + } + + for (key in this._tileCache) { + // compute the rectangle that each tile covers in the document based + // on the zoom level + coords = this._keyToTileCoords(key); + if (coords.part !== command.part) { + continue; + } + var scale = this._map.getZoomScale(coords.z); + topLeftTwips = new L.Point( + this.options.tileWidthTwips / scale * coords.x, + this.options.tileHeightTwips / scale * coords.y); + bottomRightTwips = topLeftTwips.add(new L.Point( + this.options.tileWidthTwips / scale, + this.options.tileHeightTwips / scale)); + bounds = new L.Bounds(topLeftTwips, bottomRightTwips); + if (invalidBounds.intersects(bounds)) { + delete this._tileCache[key]; + } + } + if (command.part === this._currentPart && + command.part !== this._lastValidPart) { + this._lastValidPart = command.part; + this._map.fire('updatepart', {part: command.part, docType: this._docType}); + } + + }, + + _onSearchNotFoundMsg: function (textMsg) { + var originalPhrase = textMsg.substring(16); + this._map.fire('search', {originalPhrase: originalPhrase, count: 0}); + }, + + _onSetPartMsg: function (textMsg) { + var part = parseInt(textMsg.match(/\d+/g)[0]); + if (part !== this._currentPart && this._docType !== 'text') { + this._currentPart = part; + this._update(); + this._clearSelections(); + this._map.fire('setpart', {currentPart: this._currentPart}); + } + else if (this._docType === 'text') { + this._currentPage = part; + this._map.fire('pagenumberchanged', { + currentPage: part, + pages: this._pages, + docType: this._docType + }); + } + }, + + _onStateChangedMsg: function (textMsg) { + var unoMsg = textMsg.substr(14); + var unoCmd = unoMsg.match('.uno:(.*)=')[1]; + var state = unoMsg.match('.*=(.*)')[1]; + if (unoCmd && state) { + this._map.fire('commandstatechanged', {unoCmd : unoCmd, state : state}); + } + }, + + _onStatusMsg: function (textMsg) { + var command = L.Socket.parseServerCmd(textMsg); + if (command.width && command.height && this._documentInfo !== textMsg) { + this._docWidthTwips = command.width; + this._docHeightTwips = command.height; + this._docType = command.type; + this._updateMaxBounds(true); + this._documentInfo = textMsg; + this._parts = command.parts; + this._currentPart = command.currentPart; + if (this._docType === 'text') { + this._currentPart = 0; + this._parts = 1; + this._currentPage = command.currentPart; + this._pages = command.parts; + this._map.fire('pagenumberchanged', { + currentPage: this._currentPage, + pages: this._pages, + docType: this._docType + }); + } + else { + L.Socket.sendMessage('setclientpart part=' + this._currentPart); + var partNames = textMsg.match(/[^\r\n]+/g); + // only get the last matches + partNames = partNames.slice(partNames.length - this._parts); + this._map.fire('updateparts', { + currentPart: this._currentPart, + parts: this._parts, + docType: this._docType, + partNames: partNames + }); + } + this._update(); + if (this._preFetchPart !== this._currentPart) { + this._preFetchPart = this._currentPart; + this._preFetchBorder = null; + } + } + }, + + _onStatusIndicatorMsg: function (textMsg) { + if (textMsg.startsWith('statusindicatorstart:')) { this._map.fire('statusindicator', {statusType : 'start'}); } else if (textMsg.startsWith('statusindicatorsetvalue:')) { @@ -377,123 +438,136 @@ L.TileLayer = L.GridLayer.extend({ else if (textMsg.startsWith('statusindicatorfinish:')) { this._map.fire('statusindicator', {statusType : 'finish'}); } - else if (textMsg.startsWith('tile:')) { - command = L.Socket.parseServerCmd(textMsg); - coords = this._twipsToCoords(command); - coords.z = command.zoom; - coords.part = command.part; - var data = imgBytes.subarray(index + 1); - - // read the tile data - var strBytes = ''; - for (i = 0; i < data.length; i++) { - strBytes += String.fromCharCode(data[i]); - } + }, - key = this._tileCoordsToKey(coords); - var tile = this._tiles[key]; - var img = 'data:image/png;base64,' + window.btoa(strBytes); - if (command.id !== undefined) { - this._map.fire('tilepreview', { - tile: img, - id: command.id, - width: command.width, - height: command.height, - part: command.part, - docType: this._docType - }); + _onStylesMsg: function (textMsg) { + this._docStyles = JSON.parse(textMsg.substring(8)); + this._map.fire('updatestyles', {styles: this._docStyles}); + }, + + _onTextSelectionMsg: function (textMsg) { + var strTwips = textMsg.match(/\d+/g); + this._clearSelections(); + if (strTwips != null) { + var rectangles = []; + var selectionCenter = new L.Point(0, 0); + for (var i = 0; i < strTwips.length; i += 4) { + var topLeftTwips = new L.Point(parseInt(strTwips[i]), parseInt(strTwips[i + 1])); + var offset = new L.Point(parseInt(strTwips[i + 2]), parseInt(strTwips[i + 3])); + var topRightTwips = topLeftTwips.add(new L.Point(offset.x, 0)); + var bottomLeftTwips = topLeftTwips.add(new L.Point(0, offset.y)); + var bottomRightTwips = topLeftTwips.add(offset); + rectangles.push([bottomLeftTwips, bottomRightTwips, topLeftTwips, topRightTwips]); + selectionCenter = selectionCenter.add(topLeftTwips); + selectionCenter = selectionCenter.add(offset.divideBy(2)); } - else if (tile) { - if (this._tiles[key]._invalidCount > 0) { - this._tiles[key]._invalidCount -= 1; - } - if (!tile.loaded) { - this._emptyTilesCount -= 1; - if (this._emptyTilesCount === 0) { - this._map.fire('statusindicator', {statusType: 'alltilesloaded'}); - } - } - tile.el.src = img; + // average of all rectangles' centers + selectionCenter = selectionCenter.divideBy(strTwips.length / 4); + selectionCenter = this._twipsToLatLng(selectionCenter); + if (!this._map.getBounds().contains(selectionCenter)) { + var center = this._map.project(selectionCenter); + center = center.subtract(this._map.getSize().divideBy(2)); + center.x = Math.round(center.x < 0 ? 0 : center.x); + center.y = Math.round(center.y < 0 ? 0 : center.y); + this._map.fire('scrollto', {x: center.x, y: center.y}); } - else if (command.preFetch === 'true') { - this._emptyTilesCount -= 1; - this._tileCache[key] = img; + + var polygons = L.PolyUtil.rectanglesToPolygons(rectangles, this); + for (i = 0; i < polygons.length; i++) { + var selection = new L.Polygon(polygons[i], { + pointerEvents: 'none', + fillColor: '#43ACE8', + fillOpacity: 0.25, + weight: 2, + opacity: 0.25}); + this._selections.addLayer(selection); + } + if (this._selectionContentRequest) { + clearTimeout(this._selectionContentRequest); } - L.Log.log(textMsg, L.INCOMING, key); + this._selectionContentRequest = setTimeout(L.bind(function () { + L.Socket.sendMessage('gettextselection mimetype=text/plain;charset=utf-8');}, this), 100); } - else if (textMsg.startsWith('textselection:')) { - strTwips = textMsg.match(/\d+/g); - this._clearSelections(); - if (strTwips != null) { - var rectangles = []; - var selectionCenter = new L.Point(0, 0); - for (i = 0; i < strTwips.length; i += 4) { - topLeftTwips = new L.Point(parseInt(strTwips[i]), parseInt(strTwips[i + 1])); - offset = new L.Point(parseInt(strTwips[i + 2]), parseInt(strTwips[i + 3])); - var topRightTwips = topLeftTwips.add(new L.Point(offset.x, 0)); - var bottomLeftTwips = topLeftTwips.add(new L.Point(0, offset.y)); - bottomRightTwips = topLeftTwips.add(offset); - rectangles.push([bottomLeftTwips, bottomRightTwips, topLeftTwips, topRightTwips]); - selectionCenter = selectionCenter.add(topLeftTwips); - selectionCenter = selectionCenter.add(offset.divideBy(2)); - } - // average of all rectangles' centers - selectionCenter = selectionCenter.divideBy(strTwips.length / 4); - selectionCenter = this._twipsToLatLng(selectionCenter); - if (!this._map.getBounds().contains(selectionCenter)) { - var center = this._map.project(selectionCenter); - center = center.subtract(this._map.getSize().divideBy(2)); - center.x = center.x < 0 ? 0 : center.x; - center.y = center.y < 0 ? 0 : center.y; - this._map.fire('scrollto', {x: center.x, y: center.y}); - } + this._onUpdateTextSelection(); + }, - var polygons = L.PolyUtil.rectanglesToPolygons(rectangles, this); - for (i = 0; i < polygons.length; i++) { - var selection = new L.Polygon(polygons[i], { - pointerEvents: 'none', - fillColor: '#43ACE8', - fillOpacity: 0.25, - weight: 2, - opacity: 0.25}); - this._selections.addLayer(selection); - } - if (this._selectionContentRequest) { - clearTimeout(this._selectionContentRequest); - } - this._selectionContentRequest = setTimeout(L.bind(function () { - L.Socket.sendMessage('gettextselection mimetype=text/plain;charset=utf-8');}, this), 100); - } - this._onUpdateTextSelection(); + _onTextSelectionContentMsg: function (textMsg) { + this._selectionTextContent = textMsg.substr(22); + }, + + _onTextSelectionEndMsg: function (textMsg) { + var strTwips = textMsg.match(/\d+/g); + if (strTwips != null) { + var topLeftTwips = new L.Point(parseInt(strTwips[0]), parseInt(strTwips[1])); + var offset = new L.Point(parseInt(strTwips[2]), parseInt(strTwips[3])); + var bottomRightTwips = topLeftTwips.add(offset); + this._textSelectionEnd = new L.LatLngBounds( + this._twipsToLatLng(topLeftTwips, this._map.getZoom()), + this._twipsToLatLng(bottomRightTwips, this._map.getZoom())); } - else if (textMsg.startsWith('textselectioncontent:')) { - this._selectionTextContent = textMsg.substr(22); + else { + this._textSelectionEnd = new L.LatLngBounds(new L.LatLng(0, 0), new L.LatLng(0, 0)); } - else if (textMsg.startsWith('setpart:')) { - var part = parseInt(textMsg.match(/\d+/g)[0]); - if (part !== this._currentPart && this._docType !== 'text') { - this._currentPart = part; - this._update(); - this._clearSelections(); - this._map.fire('setpart', {currentPart: this._currentPart}); + }, + + _onTextSelectionStartMsg: function (textMsg) { + var strTwips = textMsg.match(/\d+/g); + if (strTwips != null) { + var topLeftTwips = new L.Point(parseInt(strTwips[0]), parseInt(strTwips[1])); + var offset = new L.Point(parseInt(strTwips[2]), parseInt(strTwips[3])); + var bottomRightTwips = topLeftTwips.add(offset); + this._textSelectionStart = new L.LatLngBounds( + this._twipsToLatLng(topLeftTwips, this._map.getZoom()), + this._twipsToLatLng(bottomRightTwips, this._map.getZoom())); + } + else { + this._textSelectionStart = new L.LatLngBounds(new L.LatLng(0, 0), new L.LatLng(0, 0)); + } + }, + + _onTileMsg: function (textMsg, imgBytes, index) { + var command = L.Socket.parseServerCmd(textMsg); + var coords = this._twipsToCoords(command); + coords.z = command.zoom; + coords.part = command.part; + var data = imgBytes.subarray(index + 1); + + // read the tile data + var strBytes = ''; + for (var i = 0; i < data.length; i++) { + strBytes += String.fromCharCode(data[i]); + } + + var key = this._tileCoordsToKey(coords); + var tile = this._tiles[key]; + var img = 'data:image/png;base64,' + window.btoa(strBytes); + if (command.id !== undefined) { + this._map.fire('tilepreview', { + tile: img, + id: command.id, + width: command.width, + height: command.height, + part: command.part, + docType: this._docType + }); + } + else if (tile) { + if (this._tiles[key]._invalidCount > 0) { + this._tiles[key]._invalidCount -= 1; } - else if (this._docType === 'text') { - this._currentPage = part; - this._map.fire('pagenumberchanged', { - currentPage: part, - pages: this._pages, - docType: this._docType - }); + if (!tile.loaded) { + this._emptyTilesCount -= 1; + if (this._emptyTilesCount === 0) { + this._map.fire('statusindicator', {statusType: 'alltilesloaded'}); + } } + tile.el.src = img; } - else if (textMsg.startsWith('searchnotfound:')) { - var originalPhrase = textMsg.substring(16); - this._map.fire('search', {originalPhrase: originalPhrase, count: 0}); - } - else if (textMsg.startsWith('error:')) { - command = L.Socket.parseServerCmd(textMsg); - this._map.fire('error', {cmd: command.errorCmd, kind: command.errorKind}); + else if (command.preFetch === 'true') { + this._tileCache[key] = img; } + L.Log.log(textMsg, L.INCOMING, key); + }, _tileOnLoad: function (done, tile) { @@ -542,8 +616,6 @@ L.TileLayer = L.GridLayer.extend({ ' x=' + x + ' y=' + y); }, - - // Is rRectangle empty? _isEmptyRectangle: function (aBounds) { return aBounds.getSouthWest().equals(new L.LatLng(0, 0)) && aBounds.getNorthEast().equals(new L.LatLng(0, 0)); commit 837d92f33dcafb0664c1ae57b8ca3d39f6d552f8 Author: Mihai Varga <mihai.va...@collabora.com> Date: Wed Sep 2 10:47:19 2015 +0300 loleaflet: first splitting of TileLayer into 3 components diff --git a/loleaflet/build/deps.js b/loleaflet/build/deps.js index 5fe8271..08959c2 100644 --- a/loleaflet/build/deps.js +++ b/loleaflet/build/deps.js @@ -51,6 +51,24 @@ var deps = { deps: ['TileLayer'] }, + WriterTileLayer: { + src: ['layer/tile/WriterTileLayer.js'], + desc: 'Writer tile layer.', + deps: ['TileLayer'] + }, + + ImpressTileLayer: { + src: ['layer/tile/ImpressTileLayer.js'], + desc: 'Impress tile layer.', + deps: ['TileLayer'] + }, + + WriterTileLayer: { + src: ['layer/tile/CalcTileLayer.js'], + desc: 'Calc tile layer.', + deps: ['TileLayer'] + }, + ImageOverlay: { src: ['layer/ImageOverlay.js'], desc: 'Used to display an image over a particular rectangular area of the map.' diff --git a/loleaflet/src/core/Socket.js b/loleaflet/src/core/Socket.js index 78cb922..5e49874 100644 --- a/loleaflet/src/core/Socket.js +++ b/loleaflet/src/core/Socket.js @@ -89,13 +89,32 @@ L.Socket = { if (textMsg.startsWith('status:') && !this._map._docLayer) { // first status message, we need to create the document layer var command = this.parseServerCmd(textMsg); - this._map._docLayer = new L.TileLayer('', { - edit: this._map.options.edit, - readOnly: this._map.options.readOnly - }); - this._map.addLayer(this._map._docLayer); + var docLayer = null; + if (command.style === 'text') { + docLayer = new L.WriterTileLayer('', { + edit: this._map.options.edit, + readOnly: this._map.options.readOnly + }); + } + else if (command.style === 'spreadsheet') { + docLayer = new L.CalcTileLayer('', { + edit: this._map.options.edit, + readOnly: this._map.options.readOnly + }); + } + else { + docLayer = new L.ImpressTileLayer('', { + edit: this._map.options.edit, + readOnly: this._map.options.readOnly + }); + } + + this._map._docLayer = docLayer; + this._map.addLayer(docLayer); + } + if (this._map._docLayer) { + this._map._docLayer._onMessage(textMsg, imgBytes, index); } - this._map._docLayer._onMessage(textMsg, imgBytes, index); }, _onSocketError: function () { diff --git a/loleaflet/src/layer/tile/CalcTileLayer.js b/loleaflet/src/layer/tile/CalcTileLayer.js new file mode 100644 index 0000000..1a1795a --- /dev/null +++ b/loleaflet/src/layer/tile/CalcTileLayer.js @@ -0,0 +1,6 @@ +/* + * Calc tile layer is used to display a spreadsheet document + */ + +L.CalcTileLayer = L.TileLayer.extend({ +}); diff --git a/loleaflet/src/layer/tile/ImpressTileLayer.js b/loleaflet/src/layer/tile/ImpressTileLayer.js new file mode 100644 index 0000000..a2d1fbf --- /dev/null +++ b/loleaflet/src/layer/tile/ImpressTileLayer.js @@ -0,0 +1,7 @@ +/* + * Impress tile layer is used to display a presentation document + */ + + +L.ImpressTileLayer = L.TileLayer.extend({ +}); diff --git a/loleaflet/src/layer/tile/WriterTileLayer.js b/loleaflet/src/layer/tile/WriterTileLayer.js new file mode 100644 index 0000000..6eb0258 --- /dev/null +++ b/loleaflet/src/layer/tile/WriterTileLayer.js @@ -0,0 +1,6 @@ +/* + * Writer tile layer is used to display a text document + */ + +L.WriterTileLayer = L.TileLayer.extend({ +}); commit a98137a6d5df5eb652f45e41d83a860a5f654f8a Author: Mihai Varga <mihai.va...@collabora.com> Date: Tue Sep 1 18:15:43 2015 +0300 loleaflet: README update diff --git a/loleaflet/README b/loleaflet/README index 0ce0f70..5ce2b41 100644 --- a/loleaflet/README +++ b/loleaflet/README @@ -193,15 +193,11 @@ Implementation details Loading a document: The map should have the following options: - - center at [0, 0] this will try to place the [0, 0] point in the middle of the - map, but it will be moved in the top left corner when the maxBounds are set - - zoom = defautl zoom value, zooming in and out will refer to this value - server address - - The layer (actual document) should have the following options: - - doc = path to the document that will be loaded - - useSocket = tells the map the tiles will be received from a websocket - connection. If this parameter is false, an image will be loaded in each tile + - doc - path to the document that will be loaded + - edit = the initial permission + - readOnly - whether the document is read only + - [timestamp] - optionally provided for remote documents How zooming works: The zoom level goes from 1 to 20 (those limits can be changed) and the initial commit affb12ceb5a1cb78106a994c72cbf57f69e7c92c Author: Mihai Varga <mihai.va...@collabora.com> Date: Tue Sep 1 17:53:44 2015 +0300 loleaflet: moved the socket init/communication to core/Socket.js The socket is now available through the L.Socket object which now also ... etc. - the rest is truncated _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits