[Libreoffice-commits] online.git: kit/ChildSession.cpp kit/ChildSession.hpp

Tomaž Vajngerl tomaz.vajngerl at collabora.co.uk
Mon Jan 2 14:47:07 UTC 2017


 kit/ChildSession.cpp |  105 +++++++++++++++++++++++++++++++--------------------
 kit/ChildSession.hpp |   42 +++++++++++++++++++-
 2 files changed, 104 insertions(+), 43 deletions(-)

New commits:
commit 5d22bd5c958ff8bd75014b8e47ab7743dfaf455d
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
Date:   Mon Jan 2 14:21:49 2017 +0100

    Update cursor positions on active user - record events per view
    
    When the user becomes inactive, we have to record events, that are
    important to restore the user's document viewport when he becomes
    active again.
    We currently don't discriminate view events so events with different
    view ID are considered as the same event and thus get overwritten.
    The effect of this is that only the last cursor or selection of a
    different view (different user working on a document) is updated
    when the user becomes active again.
    With this we discriminate view events and record them per view ID.
    When the user becomes active again, we replay them for all views.
    
    Change-Id: I0c6b9209f4d592d88fb23227c4de41084b8cd736

diff --git a/kit/ChildSession.cpp b/kit/ChildSession.cpp
index 90d6367..611731b 100644
--- a/kit/ChildSession.cpp
+++ b/kit/ChildSession.cpp
@@ -116,20 +116,32 @@ bool ChildSession::_handleInput(const char *buffer, int length)
             sendTextFrame("setpart: part=" + std::to_string(curPart));
         }
 
-        //TODO: Is the order of these important?
-        for (const auto& pair : _lastDocEvents)
+        for (const auto& viewPair : _stateRecorder._recordedViewEvents)
         {
-            const auto typeName = LOKitHelper::kitCallbackTypeToString(pair.first);
-            LOG_TRC("Replaying missed event: " << typeName << ": " << pair.second);
-            loKitCallback(pair.first, pair.second);
+                for (const auto& eventPair : viewPair.second)
+                {
+                    const RecordedEvent& event = eventPair.second;
+                    LOG_TRC("Replaying missed view event: " <<  viewPair.first << " " << LOKitHelper::kitCallbackTypeToString(event._type)
+                                                            << ": " << event._payload);
+                    loKitCallback(event._type, event._payload);
+                }
+        }
+
+        for (const auto& eventPair : _stateRecorder._recordedEvents)
+        {
+            const RecordedEvent& event = eventPair.second;
+            LOG_TRC("Replaying missed event: " << LOKitHelper::kitCallbackTypeToString(event._type) << ": " << event._payload);
+            loKitCallback(event._type, event._payload);
         }
 
-        for (const auto& pair : _lastDocStates)
+        for (const auto& pair : _stateRecorder._recordedStates)
         {
-            LOG_TRC("Replaying missed state-change: STATE_CHANGED: " << pair.second);
+            LOG_TRC("Replaying missed state-change: " << pair.second);
             loKitCallback(LOK_CALLBACK_STATE_CHANGED, pair.second);
         }
 
+        _stateRecorder.clear();
+
         LOG_TRC("Finished replaying messages.");
     }
 
@@ -970,6 +982,50 @@ bool ChildSession::setPage(const char* /*buffer*/, int /*length*/, StringTokeniz
     return true;
 }
 
+/* If the user is inactive we have to remember important events so that when
+ * the user becomes active again, we can replay the events.
+ */
+void ChildSession::rememberEventsForInactiveUser(const int nType, const std::string& rPayload)
+{
+    if (nType == LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR ||
+        nType == LOK_CALLBACK_CURSOR_VISIBLE ||
+        nType == LOK_CALLBACK_TEXT_SELECTION ||
+        nType == LOK_CALLBACK_TEXT_SELECTION_START ||
+        nType == LOK_CALLBACK_TEXT_SELECTION_END ||
+        nType == LOK_CALLBACK_CELL_FORMULA ||
+        nType == LOK_CALLBACK_CELL_CURSOR ||
+        nType == LOK_CALLBACK_GRAPHIC_SELECTION ||
+        nType == LOK_CALLBACK_DOCUMENT_SIZE_CHANGED)
+    {
+        auto lock(getLock());
+        _stateRecorder.recordEvent(nType, rPayload);
+    }
+    else if (nType == LOK_CALLBACK_INVALIDATE_VIEW_CURSOR ||
+        nType == LOK_CALLBACK_TEXT_VIEW_SELECTION ||
+        nType == LOK_CALLBACK_CELL_VIEW_CURSOR ||
+        nType == LOK_CALLBACK_GRAPHIC_VIEW_SELECTION ||
+        nType == LOK_CALLBACK_VIEW_CURSOR_VISIBLE ||
+        nType == LOK_CALLBACK_VIEW_LOCK)
+    {
+        auto lock(getLock());
+        Poco::JSON::Parser parser;
+
+        auto root = parser.parse(rPayload).extract<Poco::JSON::Object::Ptr>();
+        int viewId = root->getValue<int>("viewId");
+        _stateRecorder.recordViewEvent(viewId, nType, rPayload);
+    }
+    else if (nType == LOK_CALLBACK_STATE_CHANGED)
+    {
+        std::string name;
+        std::string value;
+        if (LOOLProtocol::parseNameValuePair(rPayload, name, value, '='))
+        {
+            auto lock(getLock());
+            _stateRecorder.recordState(name, value);
+        }
+    }
+}
+
 void ChildSession::loKitCallback(const int nType, const std::string& rPayload)
 {
     const auto typeName = LOKitHelper::kitCallbackTypeToString(nType);
@@ -988,40 +1044,7 @@ void ChildSession::loKitCallback(const int nType, const std::string& rPayload)
     }
     else if (!isActive())
     {
-        // Cache important notifications to replay them when our client
-        // goes inactive and loses them.
-        if (nType == LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR ||
-            nType == LOK_CALLBACK_CURSOR_VISIBLE ||
-            nType == LOK_CALLBACK_CELL_CURSOR ||
-            nType == LOK_CALLBACK_CELL_FORMULA ||
-            nType == LOK_CALLBACK_GRAPHIC_SELECTION ||
-            nType == LOK_CALLBACK_TEXT_SELECTION ||
-            nType == LOK_CALLBACK_TEXT_SELECTION_START ||
-            nType == LOK_CALLBACK_TEXT_SELECTION_END ||
-            nType == LOK_CALLBACK_DOCUMENT_SIZE_CHANGED ||
-            nType == LOK_CALLBACK_INVALIDATE_VIEW_CURSOR ||
-            nType == LOK_CALLBACK_TEXT_VIEW_SELECTION ||
-            nType == LOK_CALLBACK_CELL_VIEW_CURSOR ||
-            nType == LOK_CALLBACK_GRAPHIC_VIEW_SELECTION ||
-            nType == LOK_CALLBACK_VIEW_CURSOR_VISIBLE ||
-            nType == LOK_CALLBACK_VIEW_LOCK)
-        {
-            auto lock(getLock());
-
-            _lastDocEvents[nType] = rPayload;
-        }
-
-        if (nType == LOK_CALLBACK_STATE_CHANGED)
-        {
-            std::string name;
-            std::string value;
-            if (LOOLProtocol::parseNameValuePair(rPayload, name, value, '='))
-            {
-                auto lock(getLock());
-
-                _lastDocStates[name] = rPayload;
-            }
-        }
+        rememberEventsForInactiveUser(nType, rPayload);
 
         // Pass save notifications through.
         if (nType != LOK_CALLBACK_UNO_COMMAND_RESULT || rPayload.find(".uno:Save") == std::string::npos)
diff --git a/kit/ChildSession.hpp b/kit/ChildSession.hpp
index c41426a..d88ba8b 100644
--- a/kit/ChildSession.hpp
+++ b/kit/ChildSession.hpp
@@ -11,6 +11,7 @@
 #define INCLUDED_CHILDSESSION_HPP
 
 #include <mutex>
+#include <unordered_map>
 
 #define LOK_USE_UNSTABLE_API
 #include <LibreOfficeKit/LibreOfficeKit.hxx>
@@ -59,6 +60,41 @@ public:
     virtual bool sendTextFrame(const std::string& message) = 0;
 };
 
+struct RecordedEvent
+{
+    int _type;
+    std::string _payload;
+};
+
+class StateRecorder
+{
+public:
+    std::unordered_map<std::string, std::string> _recordedStates;
+    std::unordered_map<int, std::unordered_map<int, RecordedEvent>> _recordedViewEvents;
+    std::unordered_map<int, RecordedEvent> _recordedEvents;
+
+    void recordEvent(const int type, const std::string& payload)
+    {
+        _recordedEvents[type] = {type, payload};
+    }
+
+    void recordViewEvent(const int viewId, const int type, const std::string& payload)
+    {
+        _recordedViewEvents[viewId][type] = {type, payload};
+    }
+
+    void recordState(const std::string& name, const std::string& value)
+    {
+        _recordedStates[name] = value;
+    }
+
+    void clear()
+    {
+        _recordedEvents.clear();
+        _recordedViewEvents.clear();
+    }
+};
+
 /// Represents a session to the WSD process, in a Kit process. Note that this is not a singleton.
 class ChildSession final : public Session
 {
@@ -118,6 +154,8 @@ private:
     bool setClientPart(const char* buffer, int length, Poco::StringTokenizer& tokens);
     bool setPage(const char* buffer, int length, Poco::StringTokenizer& tokens);
 
+    void rememberEventsForInactiveUser(const int nType, const std::string& rPayload);
+
     virtual void disconnect() override;
     virtual bool _handleInput(const char* buffer, int length) override;
 
@@ -137,8 +175,8 @@ private:
     bool _isDocLoaded;
 
     std::string _docType;
-    std::map<std::string, std::string> _lastDocStates;
-    std::map<int, std::string> _lastDocEvents;
+
+    StateRecorder _stateRecorder;
 
     /// Synchronize _loKitDocument access.
     /// This should be owned by Document.


More information about the Libreoffice-commits mailing list