Kaydet (Commit) 83b7bfc0 authored tarafından Tamás Zolnai's avatar Tamás Zolnai

sw lok: View jumps to cursor position even if it is moved by an other view.

Scrolling is done twice. Once in SwCursorShell::UpdateCursor() by
SCROLLWIN flag. Here we can check the actual viewid and avoid scrolling
if the cursor is move by an other user.
The second instance in the LO online code, for it we need to pass the
viewid identifying the view which moved the cursor.

Change-Id: I033274f88ce41acbb632e2aeb0d986ab11cd2d52
Reviewed-on: https://gerrit.libreoffice.org/52220Tested-by: 's avatarJenkins <ci@libreoffice.org>
Reviewed-by: 's avatarTamás Zolnai <tamas.zolnai@collabora.com>
üst 602774ae
......@@ -29,6 +29,8 @@ static bool g_bTiledAnnotations(true);
static bool g_bRangeHeaders(false);
static bool g_bViewIdForVisCursorInvalidation(false);
static bool g_bLocalRendering(false);
static LanguageTag g_aLanguageTag("en-US", true);
......@@ -88,6 +90,16 @@ void setRangeHeaders(bool bRangeHeaders)
g_bRangeHeaders = bRangeHeaders;
}
void setViewIdForVisCursorInvalidation(bool bViewIdForVisCursorInvalidation)
{
g_bViewIdForVisCursorInvalidation = bViewIdForVisCursorInvalidation;
}
bool isViewIdForVisCursorInvalidation()
{
return g_bViewIdForVisCursorInvalidation;
}
bool isRangeHeaders()
{
return g_bRangeHeaders;
......
......@@ -3514,6 +3514,8 @@ static void lo_setOptionalFeatures(LibreOfficeKit* pThis, unsigned long long con
comphelper::LibreOfficeKit::setTiledAnnotations(false);
if (features & LOK_FEATURE_RANGE_HEADERS)
comphelper::LibreOfficeKit::setRangeHeaders(true);
if (features & LOK_FEATURE_VIEWID_IN_VISCURSOR_INVALIDATION_CALLBACK)
comphelper::LibreOfficeKit::setViewIdForVisCursorInvalidation(true);
}
static void lo_setDocumentPassword(LibreOfficeKit* pThis,
......
......@@ -42,6 +42,7 @@
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
#include <comphelper/string.hxx>
#include <comphelper/lok.hxx>
#include <sfx2/lokhelper.hxx>
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
......@@ -1112,7 +1113,7 @@ void ImpEditView::ShowCursor( bool bGotoCursor, bool bForceVisCursor )
}
else
{
mpViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR, sRect.getStr());
SfxLokHelper::notifyVisCursorInvalidation(mpViewShell, sRect);
mpViewShell->NotifyOtherViews(LOK_CALLBACK_INVALIDATE_VIEW_CURSOR, "rectangle", sRect);
}
}
......
......@@ -84,7 +84,13 @@ typedef enum
/**
* Enable range based header data
*/
LOK_FEATURE_RANGE_HEADERS = (1ULL << 4)
LOK_FEATURE_RANGE_HEADERS = (1ULL << 4),
/**
* Request to have the active view's Id as the 1st value in the
* LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR payload.
*/
LOK_FEATURE_VIEWID_IN_VISCURSOR_INVALIDATION_CALLBACK = (1ULL << 5)
}
LibreOfficeKitOptionalFeatures;
......
......@@ -67,6 +67,12 @@ COMPHELPER_DLLPUBLIC void setRangeHeaders(bool bTiledAnnotations);
/// Check if range based header data is enabled
COMPHELPER_DLLPUBLIC bool isRangeHeaders();
/// Check whether clients want viewId in visible cursor invalidation payload.
COMPHELPER_DLLPUBLIC bool isViewIdForVisCursorInvalidation();
/// Set whether clients want viewId in visible cursor invalidation payload.
COMPHELPER_DLLPUBLIC void setViewIdForVisCursorInvalidation(bool bViewIdForVisCursorInvalidation);
/// Update the current LOK's language.
COMPHELPER_DLLPUBLIC void setLanguageTag(const LanguageTag& languageTag);
/// Get the current LOK's language.
......
......@@ -50,6 +50,8 @@ public:
const std::vector<vcl::LOKPayloadItem>& rPayload = std::vector<vcl::LOKPayloadItem>());
/// Emits a LOK_CALLBACK_INVALIDATE_TILES, but tweaks it according to setOptionalFeatures() if needed.
static void notifyInvalidation(SfxViewShell const* pThisView, const OString& rPayload);
/// Emits a LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR, but tweaks it according to setOptionalFeatures() if needed.
static void notifyVisCursorInvalidation(OutlinerViewShell const* pThisView, const OString& rRectangle);
/// Notifies all views with the given type and payload.
static void notifyAllViews(int nType, const OString& rPayload);
/// A special value to signify 'infinity'.
......
......@@ -1163,13 +1163,25 @@ callback (gpointer pData)
break;
case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
{
priv->m_aVisibleCursor = payloadToRectangle(pDocView, pCallback->m_aPayload.c_str());
std::stringstream aStream(pCallback->m_aPayload);
boost::property_tree::ptree aTree;
boost::property_tree::read_json(aStream, aTree);
const std::string& rRectangle = aTree.get<std::string>("rectangle");
int nViewId = aTree.get<int>("viewId");
priv->m_aVisibleCursor = payloadToRectangle(pDocView, rRectangle.c_str());
priv->m_bCursorOverlayVisible = true;
g_signal_emit(pDocView, doc_view_signals[CURSOR_CHANGED], 0,
std::cerr << nViewId;
std::cerr << priv->m_nViewId;
if(nViewId == priv->m_nViewId)
{
g_signal_emit(pDocView, doc_view_signals[CURSOR_CHANGED], 0,
priv->m_aVisibleCursor.x,
priv->m_aVisibleCursor.y,
priv->m_aVisibleCursor.width,
priv->m_aVisibleCursor.height);
}
gtk_widget_queue_draw(GTK_WIDGET(pDocView));
}
break;
......@@ -2701,6 +2713,7 @@ static gboolean lok_doc_view_initable_init (GInitable *initable, GCancellable* /
return FALSE;
}
priv->m_nLOKFeatures |= LOK_FEATURE_PART_IN_INVALIDATION_CALLBACK;
priv->m_nLOKFeatures |= LOK_FEATURE_VIEWID_IN_VISCURSOR_INVALIDATION_CALLBACK;
priv->m_pOffice->pClass->setOptionalFeatures(priv->m_pOffice, priv->m_nLOKFeatures);
return TRUE;
......
......@@ -17,6 +17,7 @@
#include <sfx2/viewfrm.hxx>
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
#include <comphelper/lok.hxx>
#include <editeng/outliner.hxx>
#include <shellimpl.hxx>
......@@ -199,6 +200,21 @@ void SfxLokHelper::notifyInvalidation(SfxViewShell const* pThisView, const OStri
pThisView->libreOfficeKitViewCallback(LOK_CALLBACK_INVALIDATE_TILES, aBuf.makeStringAndClear().getStr());
}
void SfxLokHelper::notifyVisCursorInvalidation(OutlinerViewShell const* pThisView, const OString& rRectangle)
{
OString sPayload;
if (comphelper::LibreOfficeKit::isViewIdForVisCursorInvalidation())
{
sPayload = OString("{ \"viewId\": \"") + OString::number(SfxLokHelper::getView()) +
"\", \"rectangle\": \"" + rRectangle + "\" }";
}
else
{
sPayload = rRectangle;
}
pThisView->libreOfficeKitViewCallback(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR, sPayload.getStr());
}
void SfxLokHelper::notifyAllViews(int nType, const OString& rPayload)
{
const auto payload = rPayload.getStr();
......
......@@ -106,6 +106,7 @@ public:
void testIMESupport();
void testSplitNodeRedlineCallback();
void testDeleteNodeRedlineCallback();
void testVisCursorInvalidation();
CPPUNIT_TEST_SUITE(SwTiledRenderingTest);
CPPUNIT_TEST(testRegisterCallback);
......@@ -160,6 +161,7 @@ public:
CPPUNIT_TEST(testIMESupport);
CPPUNIT_TEST(testSplitNodeRedlineCallback);
CPPUNIT_TEST(testDeleteNodeRedlineCallback);
CPPUNIT_TEST(testVisCursorInvalidation);
CPPUNIT_TEST_SUITE_END();
private:
......@@ -672,6 +674,7 @@ class ViewCallback
{
public:
bool m_bOwnCursorInvalidated;
int m_nOwnCursorInvalidatedBy;
bool m_bOwnCursorAtOrigin;
tools::Rectangle m_aOwnCursor;
bool m_bViewCursorInvalidated;
......@@ -693,6 +696,7 @@ public:
ViewCallback()
: m_bOwnCursorInvalidated(false),
m_nOwnCursorInvalidatedBy(-1),
m_bOwnCursorAtOrigin(false),
m_bViewCursorInvalidated(false),
m_bOwnSelectionSet(false),
......@@ -726,7 +730,18 @@ public:
{
m_bOwnCursorInvalidated = true;
uno::Sequence<OUString> aSeq = comphelper::string::convertCommaSeparated(OUString::fromUtf8(aPayload));
OString sRect;
if(comphelper::LibreOfficeKit::isViewIdForVisCursorInvalidation())
{
std::stringstream aStream(pPayload);
boost::property_tree::ptree aTree;
boost::property_tree::read_json(aStream, aTree);
sRect = aTree.get_child("rectangle").get_value<std::string>().c_str();
m_nOwnCursorInvalidatedBy = aTree.get_child("viewId").get_value<int>();
}
else
sRect = aPayload;
uno::Sequence<OUString> aSeq = comphelper::string::convertCommaSeparated(OUString::fromUtf8(sRect));
if (OString("EMPTY") == pPayload)
return;
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(4), aSeq.getLength());
......@@ -2276,6 +2291,86 @@ void SwTiledRenderingTest::testDeleteNodeRedlineCallback()
comphelper::LibreOfficeKit::setActive(false);
}
void SwTiledRenderingTest::testVisCursorInvalidation()
{
comphelper::LibreOfficeKit::setActive();
SwXTextDocument* pXTextDocument = createDoc("dummy.fodt");
ViewCallback aView1;
SfxViewShell::Current()->registerLibreOfficeKitViewCallback(&ViewCallback::callback, &aView1);
int nView1 = SfxLokHelper::getView();
SfxLokHelper::createView();
int nView2 = SfxLokHelper::getView();
ViewCallback aView2;
SfxViewShell::Current()->registerLibreOfficeKitViewCallback(&ViewCallback::callback, &aView2);
Scheduler::ProcessEventsToIdle();
// Move visible cursor in the first view
SfxLokHelper::setView(nView1);
Scheduler::ProcessEventsToIdle();
aView1.m_bOwnCursorInvalidated = false;
aView1.m_bViewCursorInvalidated = false;
aView2.m_bOwnCursorInvalidated = false;
aView2.m_bViewCursorInvalidated = false;
pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_RIGHT);
pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, KEY_RIGHT);
Scheduler::ProcessEventsToIdle();
CPPUNIT_ASSERT(!aView1.m_bViewCursorInvalidated);
CPPUNIT_ASSERT(aView1.m_bOwnCursorInvalidated);
CPPUNIT_ASSERT(aView2.m_bViewCursorInvalidated);
CPPUNIT_ASSERT(!aView2.m_bOwnCursorInvalidated);
// Insert text in the second view which moves the other view's cursor too
SfxLokHelper::setView(nView2);
aView1.m_bOwnCursorInvalidated = false;
aView1.m_bViewCursorInvalidated = false;
aView2.m_bOwnCursorInvalidated = false;
aView2.m_bViewCursorInvalidated = false;
pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'x', 0);
pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 'x', 0);
Scheduler::ProcessEventsToIdle();
CPPUNIT_ASSERT(aView1.m_bViewCursorInvalidated);
CPPUNIT_ASSERT(aView1.m_bOwnCursorInvalidated);
CPPUNIT_ASSERT(aView2.m_bViewCursorInvalidated);
CPPUNIT_ASSERT(aView2.m_bOwnCursorInvalidated);
// Do the same as before, but set the related compatibility flag first
SfxLokHelper::setView(nView2);
comphelper::LibreOfficeKit::setViewIdForVisCursorInvalidation(true);
aView1.m_bOwnCursorInvalidated = false;
aView1.m_bViewCursorInvalidated = false;
aView2.m_bOwnCursorInvalidated = false;
aView2.m_bViewCursorInvalidated = false;
pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'x', 0);
pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 'x', 0);
Scheduler::ProcessEventsToIdle();
CPPUNIT_ASSERT(aView1.m_bViewCursorInvalidated);
CPPUNIT_ASSERT(aView1.m_bOwnCursorInvalidated);
CPPUNIT_ASSERT_EQUAL(nView2, aView1.m_nOwnCursorInvalidatedBy);
CPPUNIT_ASSERT(aView2.m_bViewCursorInvalidated);
CPPUNIT_ASSERT(aView2.m_bOwnCursorInvalidated);
CPPUNIT_ASSERT_EQUAL(nView2, aView2.m_nOwnCursorInvalidatedBy);
comphelper::LibreOfficeKit::setViewIdForVisCursorInvalidation(false);
mxComponent->dispose();
mxComponent.clear();
comphelper::LibreOfficeKit::setActive(false);
}
CPPUNIT_TEST_SUITE_REGISTRATION(SwTiledRenderingTest);
CPPUNIT_PLUGIN_IMPLEMENT();
......
......@@ -1411,6 +1411,13 @@ void SwCursorShell::UpdateCursor( sal_uInt16 eFlags, bool bIdleEnd )
SET_CURR_SHELL( this );
ClearUpCursors();
bool bScrollWin = eFlags & SwCursorShell::SCROLLWIN;
// Don't scroll to the cursor if it's moved by an other view
if(comphelper::LibreOfficeKit::isActive())
{
bScrollWin = SfxLokHelper::getView() != SfxLokHelper::getView(GetSfxViewShell());
}
if (ActionPend())
{
if ( eFlags & SwCursorShell::READONLY )
......@@ -1553,7 +1560,7 @@ void SwCursorShell::UpdateCursor( sal_uInt16 eFlags, bool bIdleEnd )
m_pVisibleCursor->Hide(); // always hide visible Cursor
// scroll Cursor to visible area
if( (eFlags & SwCursorShell::SCROLLWIN) &&
if( bScrollWin &&
(HasSelection() || eFlags & SwCursorShell::READONLY ||
!IsCursorReadonly()) )
{
......@@ -1811,7 +1818,7 @@ void SwCursorShell::UpdateCursor( sal_uInt16 eFlags, bool bIdleEnd )
}
// scroll Cursor to visible area
if( m_bHasFocus && eFlags & SwCursorShell::SCROLLWIN &&
if( m_bHasFocus && bScrollWin&&
(HasSelection() || eFlags & SwCursorShell::READONLY ||
!IsCursorReadonly() || GetViewOptions()->IsSelectionInReadonly()) )
{
......@@ -1823,7 +1830,7 @@ void SwCursorShell::UpdateCursor( sal_uInt16 eFlags, bool bIdleEnd )
m_bSVCursorVis = bSav;
}
} while( eFlags & SwCursorShell::SCROLLWIN );
} while( bScrollWin );
if( m_pBlockCursor )
RefreshBlockCursor();
......
......@@ -214,13 +214,15 @@ void SwVisibleCursor::SetPosAndShow(SfxViewShell const * pViewShell)
if (pViewShell)
{
if (pViewShell == m_pCursorShell->GetSfxViewShell())
pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR, sRect.getStr());
{
SfxLokHelper::notifyVisCursorInvalidation(pViewShell, sRect);
}
else
SfxLokHelper::notifyOtherView(m_pCursorShell->GetSfxViewShell(), pViewShell, LOK_CALLBACK_INVALIDATE_VIEW_CURSOR, "rectangle", sRect);
}
else
{
m_pCursorShell->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR, sRect.getStr());
SfxLokHelper::notifyVisCursorInvalidation(m_pCursorShell->GetSfxViewShell(), sRect);
SfxLokHelper::notifyOtherViews(m_pCursorShell->GetSfxViewShell(), LOK_CALLBACK_INVALIDATE_VIEW_CURSOR, "rectangle", sRect);
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment