[Libreoffice-commits] online.git: Branch 'distro/collabora/collabora-online-4-0' - 2 commits - bundled/include kit/ChildSession.cpp kit/ChildSession.hpp loleaflet/css loleaflet/src wsd/ClientSession.cpp wsd/protocol.txt

Ashod Nakashian (via logerrit) logerrit at kemper.freedesktop.org
Fri Oct 18 20:29:23 UTC 2019


 bundled/include/LibreOfficeKit/LibreOfficeKitEnums.h |    2 
 kit/ChildSession.cpp                                 |   35 ++++++++++
 kit/ChildSession.hpp                                 |    1 
 loleaflet/css/partsPreviewControl.css                |    6 +
 loleaflet/src/control/Control.PartsPreview.js        |   61 +++++++++++++++++++
 loleaflet/src/layer/tile/TileLayer.js                |    2 
 wsd/ClientSession.cpp                                |   22 ++++++
 wsd/protocol.txt                                     |   11 +++
 8 files changed, 135 insertions(+), 5 deletions(-)

New commits:
commit 1c93fd7ead50ff16994cf90936602891c0bbc8d8
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Mon Sep 17 07:17:31 2018 -0400
Commit:     Andras Timar <andras.timar at collabora.com>
CommitDate: Fri Oct 18 22:29:18 2019 +0200

    wsd: leaflet: support reordering of slides via drag-and-drop
    
    Change-Id: I1b471ba07dd0a1016a0759de729171ae968262cb
    Reviewed-on: https://gerrit.libreoffice.org/69635
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>
    (cherry picked from commit 021d67f1430ff2a554b65c65d7aee752fed0b77f)
    Reviewed-on: https://gerrit.libreoffice.org/80578
    Reviewed-by: Andras Timar <andras.timar at collabora.com>
    Tested-by: Andras Timar <andras.timar at collabora.com>

diff --git a/bundled/include/LibreOfficeKit/LibreOfficeKitEnums.h b/bundled/include/LibreOfficeKit/LibreOfficeKitEnums.h
index 4f9d668c4..a686cdef4 100644
--- a/bundled/include/LibreOfficeKit/LibreOfficeKitEnums.h
+++ b/bundled/include/LibreOfficeKit/LibreOfficeKitEnums.h
@@ -564,7 +564,7 @@ typedef enum
      * "type" tells the type of the window the action is associated with
      *  - "dialog" - window is a dialog
      *  - "child" - window is a floating window (combo boxes, etc.)
-     *  - "panel" - window is a docked panel (i.e. in the sidebar)
+     *  - "deck" - window is a docked/floating deck (i.e. the sidebar)
      *
      * "action" can take following values:
      * - "created" - window is created in the backend, client can render it now
diff --git a/kit/ChildSession.cpp b/kit/ChildSession.cpp
index 5bec45b48..1e4a81953 100644
--- a/kit/ChildSession.cpp
+++ b/kit/ChildSession.cpp
@@ -227,6 +227,10 @@ bool ChildSession::_handleInput(const char *buffer, int length)
     {
         return selectClientPart(buffer, length, tokens);
     }
+    else if (tokens[0] == "moveselectedclientparts")
+    {
+        return moveSelectedClientParts(buffer, length, tokens);
+    }
     else if (tokens[0] == "setpage")
     {
         return setPage(buffer, length, tokens);
@@ -1823,6 +1827,37 @@ bool ChildSession::selectClientPart(const char* /*buffer*/, int /*length*/, cons
     return true;
 }
 
+bool ChildSession::moveSelectedClientParts(const char* /*buffer*/, int /*length*/, const std::vector<std::string>& tokens)
+{
+    int nPosition;
+    if (tokens.size() < 2 ||
+        !getTokenInteger(tokens[1], "position", nPosition))
+    {
+        sendTextFrame("error: cmd=moveselectedclientparts kind=invalid");
+        return false;
+    }
+
+    std::unique_lock<std::mutex> lock(_docManager.getDocumentMutex());
+
+    getLOKitDocument()->setView(_viewId);
+
+    if (getLOKitDocument()->getDocumentType() != LOK_DOCTYPE_TEXT)
+    {
+        getLOKitDocument()->moveSelectedParts(nPosition, false); // Move, don't duplicate.
+
+        // Get the status to recreate the previews and correctly order parts.
+        const std::string status = LOKitHelper::documentStatus(getLOKitDocument()->get());
+        if (!status.empty())
+            return sendTextFrame("statusupdate: " + status);
+    }
+    else
+    {
+        LOG_WRN("ChildSession::moveSelectedClientParts[" << getName() << "]: error moving parts on text documents.");
+    }
+
+    return true; // Non-fatal to fail.
+}
+
 bool ChildSession::setPage(const char* /*buffer*/, int /*length*/, const std::vector<std::string>& tokens)
 {
     int page;
diff --git a/kit/ChildSession.hpp b/kit/ChildSession.hpp
index ed272f225..2f33e8c63 100644
--- a/kit/ChildSession.hpp
+++ b/kit/ChildSession.hpp
@@ -263,6 +263,7 @@ private:
     bool saveAs(const char* buffer, int length, const std::vector<std::string>& tokens);
     bool setClientPart(const char* buffer, int length, const std::vector<std::string>& tokens);
     bool selectClientPart(const char* buffer, int length, const std::vector<std::string>& tokens);
+    bool moveSelectedClientParts(const char* buffer, int length, const std::vector<std::string>& tokens);
     bool setPage(const char* buffer, int length, const std::vector<std::string>& tokens);
     bool sendWindowCommand(const char* buffer, int length, const std::vector<std::string>& tokens);
     bool signDocumentContent(const char* buffer, int length, const std::vector<std::string>& tokens);
diff --git a/loleaflet/css/partsPreviewControl.css b/loleaflet/css/partsPreviewControl.css
index 438b137d3..66e47c9bb 100644
--- a/loleaflet/css/partsPreviewControl.css
+++ b/loleaflet/css/partsPreviewControl.css
@@ -20,7 +20,7 @@
 
 .preview-img {
 	/* In draw docs, the width of previews are small, but we want a min of 180px to align it with document's left edge */
-        min-width: 180px;
+	min-width: 180px;
 	vertical-align: middle;
 	max-width: 184px;
 	cursor: pointer;
@@ -30,3 +30,7 @@
 .preview-img-selected {
 	border-color: #000000;
 }
+
+.preview-img-dropsite {
+    border-bottom: 2px solid red;
+}
diff --git a/loleaflet/src/control/Control.PartsPreview.js b/loleaflet/src/control/Control.PartsPreview.js
index dc978f39f..78834a6d8 100644
--- a/loleaflet/src/control/Control.PartsPreview.js
+++ b/loleaflet/src/control/Control.PartsPreview.js
@@ -105,6 +105,7 @@ L.Control.PartsPreview = L.Control.extend({
 
 	_createPreview: function (i, hashCode, bottomBound) {
 		var frame = L.DomUtil.create('div', 'preview-frame', this._scrollContainer);
+		this._addDnDHandlers(frame);
 		L.DomUtil.create('span', 'preview-helper', frame);
 
 		var imgClassName = 'preview-img';
@@ -259,6 +260,7 @@ L.Control.PartsPreview = L.Control.extend({
 			for (it = 0; it < parts; it++) {
 				if (this._previewTiles[it].hash !== e.partNames[it]) {
 					this._previewTiles[it].hash = e.partNames[it];
+					this._map.getPreview(it, it, 180, 180, {autoUpdate: this.options.autoUpdate});
 				}
 			}
 		}
@@ -326,7 +328,66 @@ L.Control.PartsPreview = L.Control.extend({
 				}
 			}
 		}
+	},
+
+	_addDnDHandlers: function (elem) {
+		if (elem) {
+			elem.setAttribute('draggable', true);
+			elem.addEventListener('dragstart', this._handleDragStart, false);
+			elem.addEventListener('dragenter', this._handleDragEnter, false)
+			elem.addEventListener('dragover', this._handleDragOver, false);
+			elem.addEventListener('dragleave', this._handleDragLeave, false);
+			elem.addEventListener('drop', this._handleDrop, false);
+			elem.addEventListener('dragend', this._handleDragEnd, false);
+			elem.partsPreview = this;
+		}
+	},
+
+	_handleDragStart: function (e) {
+		// By default we move when dragging, but can
+		// support duplication with ctrl in the future.
+		e.dataTransfer.effectAllowed = 'move';
+	},
+
+	_handleDragOver: function (e) {
+		if (e.preventDefault) {
+			e.preventDefault();
+		}
+
+		// By default we move when dragging, but can
+		// support duplication with ctrl in the future.
+		e.dataTransfer.dropEffect = 'move';
+
+		this.classList.add('preview-img-dropsite');
+		return false;
+	},
+
+	_handleDragEnter: function () {
+	},
+
+	_handleDragLeave: function () {
+		this.classList.remove('preview-img-dropsite');
+	},
+
+	_handleDrop: function (e) {
+		if (e.stopPropagation) {
+			e.stopPropagation();
+		}
+
+		var part = $('#slide-sorter .mCSB_container .preview-frame').index(e.target.parentNode);
+		if (part !== null) {
+			var partId = parseInt(part);
+			this.partsPreview._map._socket.sendMessage('moveselectedclientparts position=' + partId);
+		}
+
+		this.classList.remove('preview-img-dropsite');
+		return false;
+	},
+
+	_handleDragEnd: function () {
+		this.classList.remove('preview-img-dropsite');
 	}
+
 });
 
 L.control.partsPreview = function (options) {
diff --git a/wsd/ClientSession.cpp b/wsd/ClientSession.cpp
index 6a94f9495..19cfb391c 100644
--- a/wsd/ClientSession.cpp
+++ b/wsd/ClientSession.cpp
@@ -164,6 +164,7 @@ bool ClientSession::_handleInput(const char *buffer, int length)
              tokens[0] != "selecttext" &&
              tokens[0] != "setclientpart" &&
              tokens[0] != "selectclientpart" &&
+             tokens[0] != "moveselectedclientparts" &&
              tokens[0] != "setpage" &&
              tokens[0] != "status" &&
              tokens[0] != "statusupdate" &&
@@ -342,6 +343,23 @@ bool ClientSession::_handleInput(const char *buffer, int length)
             }
         }
     }
+    else if (tokens[0] == "moveselectedclientparts")
+    {
+        if(!_isTextDocument)
+        {
+            int nPosition;
+            if (tokens.size() != 2 ||
+                !getTokenInteger(tokens[1], "position", nPosition))
+            {
+                sendTextFrame("error: cmd=moveselectedclientparts kind=syntax");
+                return false;
+            }
+            else
+            {
+                return forwardToChild(std::string(buffer, length), docBroker);
+            }
+        }
+    }
     else if (tokens[0] == "clientzoom")
     {
         int tilePixelWidth, tilePixelHeight, tileTwipWidth, tileTwipHeight;
diff --git a/wsd/protocol.txt b/wsd/protocol.txt
index cb5554e4c..865d3fd1b 100644
--- a/wsd/protocol.txt
+++ b/wsd/protocol.txt
@@ -142,6 +142,10 @@ selectclientpart part=<partNumber>
 
     Informs the server that the client changed the selection state of <partNumber>.
 
+moveselectedclientparts position=<positionNumber>
+
+    Moves the selected parts to a new position.
+
 setpage page=<pageNumber>
 
     Valid only for text documents.
commit 979a824accd4375170dc4b8bf8e5d69009745684
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Mon Sep 17 06:45:57 2018 -0400
Commit:     Andras Timar <andras.timar at collabora.com>
CommitDate: Fri Oct 18 22:29:03 2019 +0200

    wsd: leaflet: support statusupdate: messages to sync clients
    
    This new message is identical to status: except it doesn't
    imply (re)connection. It's unfortunate that status: is
    assumed to be sent only when establishing connection and
    loading a document, so we need a different notification
    that can be sent at any time, without triggering
    initalization logic on the client-side.
    
    Change-Id: I9c804119aec292b873aeed132cc32f13c030d845
    Reviewed-on: https://gerrit.libreoffice.org/69634
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>
    (cherry picked from commit 6dce712ff4680fb7add00ebf6e4b78f61dda3e79)
    Reviewed-on: https://gerrit.libreoffice.org/80577
    Reviewed-by: Andras Timar <andras.timar at collabora.com>
    Tested-by: Andras Timar <andras.timar at collabora.com>

diff --git a/loleaflet/src/layer/tile/TileLayer.js b/loleaflet/src/layer/tile/TileLayer.js
index 11f2995e7..57acac5f6 100644
--- a/loleaflet/src/layer/tile/TileLayer.js
+++ b/loleaflet/src/layer/tile/TileLayer.js
@@ -432,7 +432,7 @@ L.TileLayer = L.GridLayer.extend({
 		else if (textMsg.startsWith('statechanged:')) {
 			this._onStateChangedMsg(textMsg);
 		}
-		else if (textMsg.startsWith('status:')) {
+		else if (textMsg.startsWith('status:') || textMsg.startsWith('statusupdate:')) {
 			this._onStatusMsg(textMsg);
 		}
 		else if (textMsg.startsWith('textselection:')) {
diff --git a/wsd/ClientSession.cpp b/wsd/ClientSession.cpp
index 4014a3e58..6a94f9495 100644
--- a/wsd/ClientSession.cpp
+++ b/wsd/ClientSession.cpp
@@ -166,6 +166,7 @@ bool ClientSession::_handleInput(const char *buffer, int length)
              tokens[0] != "selectclientpart" &&
              tokens[0] != "setpage" &&
              tokens[0] != "status" &&
+             tokens[0] != "statusupdate" &&
              tokens[0] != "tile" &&
              tokens[0] != "tilecombine" &&
              tokens[0] != "uno" &&
@@ -181,6 +182,7 @@ bool ClientSession::_handleInput(const char *buffer, int length)
              tokens[0] != "removesession" &&
              tokens[0] != "renamefile")
     {
+        LOG_ERR("Session [" << getId() << "] got unknown command [" << tokens[0] << "].");
         sendTextFrame("error: cmd=" + tokens[0] + " kind=unknown");
         return false;
     }
@@ -243,7 +245,7 @@ bool ClientSession::_handleInput(const char *buffer, int length)
     {
         return sendFontRendering(buffer, length, tokens, docBroker);
     }
-    else if (tokens[0] == "status")
+    else if (tokens[0] == "status" || tokens[0] == "statusupdate")
     {
         assert(firstLine.size() == static_cast<size_t>(length));
         return forwardToChild(firstLine, docBroker);
diff --git a/wsd/protocol.txt b/wsd/protocol.txt
index a4631c912..cb5554e4c 100644
--- a/wsd/protocol.txt
+++ b/wsd/protocol.txt
@@ -369,11 +369,16 @@ saveas: url=<url> name=<name>
     <name> is the resulting name (without path) that was created on the wopi
     host. It can differ from what was requested in case the file already existed.
 
-status: type=<typeName> parts=<numberOfParts> current=<currentPartNumber> width=<width> height=<height> viewid=<viewId> [partNames]
+status: type=<typeName> parts=<numberOfParts> current=<currentPartNumber> width=<width> height=<height> viewid=<viewId> hiddenparts=<part1,part2,...> selectedparts=<part1,part2,...> [partNames]
 
     <typeName> is 'text, 'spreadsheet', 'presentation', 'drawing' or 'other. Others are numbers.
     if the document has multiple parts and those have names, part names follow separated by '\n'
 
+statusupdate: type=<typeName> parts=<numberOfParts> current=<currentPartNumber> width=<width> height=<height> viewid=<viewId> hiddenparts=<part1,part2,...> selectedparts=<part1,part2,...> [partNames]
+
+    Same as status: but issued whenever the document parts have updated significantly.
+    status: implies document loading. statusupdate: is just an update.
+
 styles: {"styleFamily": ["styles in family"], etc. }
 
 statechanged: <key>=<value>


More information about the Libreoffice-commits mailing list