[Libreoffice-commits] online.git: Branch 'distro/collabora/milestone-4' - 30 commits - loleaflet/build loleaflet/debug loleaflet/Makefile loleaflet/README loleaflet/spec loleaflet/src loolwsd/configure.ac loolwsd/LOOLWSD.cpp

Mihai Varga mihai.varga at collabora.com
Mon Sep 7 06:00:34 PDT 2015


 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.varga at 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.varga at 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.varga at 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.varga at 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.varga at 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.varga at 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.varga at 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.varga at 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.varga at 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.varga at 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.varga at 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.varga at 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.varga at 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.varga at 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.varga at 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.varga at 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.varga at 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.varga at 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.varga at 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.varga at 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.varga at 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.varga at 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.varga at 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.varga at 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.varga at 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.varga at 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


More information about the Libreoffice-commits mailing list