LOCRDT editeng,sfx2,sw: experimental yrs collab
This can be enabled in configure via --with-yrs=...; see also README.yrs Currently this is hardcoded to run over a local named pipe. Everything related to editengine is implemented in EditDoc and made accessible via its wrapper classes; everything related to communication and accessing sw's comment is implemented in sw::DocumentStateManager. The acceptor starts in SwView::SwView(), once SwPostItMgr exists. There is a hack in SfxFrameLoader_Impl::load() to fetch the document that the accepting soffice has loaded, and load it in the connecting soffice as well. Change-Id: I89476b5864b70f479bcf15989374c1c65b5da9ea Reviewed-on: https://gerrit.libreoffice.org/c/core/+/175652 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
This commit is contained in:
parent
0a677d53a6
commit
8f8034177b
46
README.yrs
Normal file
46
README.yrs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
|
||||||
|
## Experimental Writer comments editing collaboration with yrs
|
||||||
|
|
||||||
|
### How to build
|
||||||
|
|
||||||
|
First, build yrs C FFI bindings:
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone https://github.com/y-crdt/y-crdt.git
|
||||||
|
cd y-crdt
|
||||||
|
git checkout v0.23.1
|
||||||
|
cargo build -p yffi
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, put the yrs build directory in autogen.input:
|
||||||
|
|
||||||
|
`--with-yrs=/path/to/y-crdt`
|
||||||
|
|
||||||
|
### How to run
|
||||||
|
|
||||||
|
To prevent crashes at runtime, set the environment variable
|
||||||
|
EDIT_COMMENT_IN_READONLY_MODE=1 and open documents in read-only mode: only
|
||||||
|
inserting/deleting comments, and editing inside comments will be enabled.
|
||||||
|
|
||||||
|
Currently, communication happens over a hard-coded pipe:
|
||||||
|
|
||||||
|
* start an soffice with YRSACCEPT=1 load a Writer document and it will listen
|
||||||
|
and block until connect
|
||||||
|
(you can also create a new Writer document but that will be boring if all
|
||||||
|
you can do is insert comments into empty doc)
|
||||||
|
|
||||||
|
* start another soffice with a different user profile, create new Writer
|
||||||
|
document, and it will connect and load the document from the other side
|
||||||
|
|
||||||
|
All sorts of paragraph and character formattings should work inside comments.
|
||||||
|
|
||||||
|
Inserting hyperlinks also works, although sadly i wasn't able to figure out
|
||||||
|
how to enable the menu items in read-only mode, so it only works in editable
|
||||||
|
mode.
|
||||||
|
|
||||||
|
Undo/Redo doesn't work at all, it's disabled in readonly mode anyway.
|
||||||
|
|
||||||
|
Switching to editable mode is also possible, but only comment-related editing
|
||||||
|
is synced via yrs, so if other editing operations change the positions of
|
||||||
|
comments, a crash will be inevitable.
|
||||||
|
|
@ -4449,4 +4449,21 @@ $(call gb_LinkTarget_set_include,$(1),\
|
|||||||
endef
|
endef
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq ($(WITH_YRS),)
|
||||||
|
|
||||||
|
define gb_LinkTarget__use_yrs
|
||||||
|
$(call gb_LinkTarget_set_include,$(1),\
|
||||||
|
$$(INCLUDE) \
|
||||||
|
-I$(WITH_YRS)/tests-ffi/include \
|
||||||
|
)
|
||||||
|
$(call gb_LinkTarget_add_defs,$(1),-DYRS)
|
||||||
|
$(call gb_LinkTarget_add_libs,$(1),$(WITH_YRS)/target/debug/libyrs.a)
|
||||||
|
endef
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
gb_LinkTarget__use_yrs :=
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
# vim: set noet sw=4 ts=4:
|
# vim: set noet sw=4 ts=4:
|
||||||
|
@ -784,6 +784,7 @@ export WITH_LOCALES=@WITH_LOCALES@
|
|||||||
export WITH_MYSPELL_DICTS=@WITH_MYSPELL_DICTS@
|
export WITH_MYSPELL_DICTS=@WITH_MYSPELL_DICTS@
|
||||||
export WITH_THEMES=@WITH_THEMES@
|
export WITH_THEMES=@WITH_THEMES@
|
||||||
export WITH_WEBDAV=@WITH_WEBDAV@
|
export WITH_WEBDAV=@WITH_WEBDAV@
|
||||||
|
WITH_YRS=@WITH_YRS@
|
||||||
export WORKDIR=@WORKDIR@
|
export WORKDIR=@WORKDIR@
|
||||||
export WORKDIR_FOR_BUILD=@WORKDIR_FOR_BUILD@
|
export WORKDIR_FOR_BUILD=@WORKDIR_FOR_BUILD@
|
||||||
export WPD_CFLAGS=$(gb_SPACE)@WPD_CFLAGS@
|
export WPD_CFLAGS=$(gb_SPACE)@WPD_CFLAGS@
|
||||||
|
@ -2830,6 +2830,12 @@ AC_ARG_WITH(hamcrest,
|
|||||||
--without-junit disables those tests. Not relevant in the --without-java case.]),
|
--without-junit disables those tests. Not relevant in the --without-java case.]),
|
||||||
,with_hamcrest=yes)
|
,with_hamcrest=yes)
|
||||||
|
|
||||||
|
AC_ARG_WITH(yrs,
|
||||||
|
AS_HELP_STRING([--with-yrs=<absolute path to yrs build>],
|
||||||
|
[Specifies the built yrs git repo for very experimental experiments.]),
|
||||||
|
WITH_YRS=$withval)
|
||||||
|
AC_SUBST(WITH_YRS)
|
||||||
|
|
||||||
AC_ARG_WITH(perl-home,
|
AC_ARG_WITH(perl-home,
|
||||||
AS_HELP_STRING([--with-perl-home=<abs. path to Perl 5 home>],
|
AS_HELP_STRING([--with-perl-home=<abs. path to Perl 5 home>],
|
||||||
[If you have installed Perl 5 Distribution, on your system, please
|
[If you have installed Perl 5 Distribution, on your system, please
|
||||||
|
@ -53,6 +53,7 @@ $(eval $(call gb_CppunitTest_use_externals,editeng_core,\
|
|||||||
boost_headers \
|
boost_headers \
|
||||||
icuuc \
|
icuuc \
|
||||||
libxml2 \
|
libxml2 \
|
||||||
|
yrs \
|
||||||
))
|
))
|
||||||
|
|
||||||
$(eval $(call gb_CppunitTest_set_include,editeng_core,\
|
$(eval $(call gb_CppunitTest_set_include,editeng_core,\
|
||||||
|
@ -47,6 +47,7 @@ $(eval $(call gb_CppunitTest_use_externals,editeng_editeng,\
|
|||||||
boost_headers \
|
boost_headers \
|
||||||
icuuc \
|
icuuc \
|
||||||
libxml2 \
|
libxml2 \
|
||||||
|
yrs \
|
||||||
))
|
))
|
||||||
|
|
||||||
$(eval $(call gb_CppunitTest_set_include,editeng_editeng,\
|
$(eval $(call gb_CppunitTest_set_include,editeng_editeng,\
|
||||||
|
@ -166,6 +166,7 @@ $(eval $(call gb_Library_use_externals,editeng,\
|
|||||||
icuuc \
|
icuuc \
|
||||||
icu_headers \
|
icu_headers \
|
||||||
libxml2 \
|
libxml2 \
|
||||||
|
yrs \
|
||||||
))
|
))
|
||||||
|
|
||||||
# vim: set noet sw=4 ts=4:
|
# vim: set noet sw=4 ts=4:
|
||||||
|
@ -46,6 +46,13 @@
|
|||||||
|
|
||||||
enum class TextRotation;
|
enum class TextRotation;
|
||||||
|
|
||||||
|
#if defined(YRS)
|
||||||
|
class ImpEditEngine;
|
||||||
|
class IYrsTransactionSupplier;
|
||||||
|
typedef struct TransactionInner YTransaction;
|
||||||
|
typedef struct YTextEvent YTextEvent;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define CHARPOSGROW 16
|
#define CHARPOSGROW 16
|
||||||
#define DEFTAB 720
|
#define DEFTAB 720
|
||||||
@ -119,6 +126,19 @@ private:
|
|||||||
bool mbModified:1;
|
bool mbModified:1;
|
||||||
bool mbDisableAttributeExpanding:1;
|
bool mbDisableAttributeExpanding:1;
|
||||||
|
|
||||||
|
#if defined(YRS)
|
||||||
|
OString m_CommentId;
|
||||||
|
IYrsTransactionSupplier * m_pYrsSupplier{nullptr};
|
||||||
|
public:
|
||||||
|
void SetYrsCommentId(IYrsTransactionSupplier *, OString const& rId);
|
||||||
|
void YrsWriteEEState();
|
||||||
|
void YrsReadEEState(YTransaction *, ImpEditEngine & rIEE);
|
||||||
|
void YrsApplyEEDelta(YTransaction *, YTextEvent const* pEvent, ImpEditEngine & rIEE);
|
||||||
|
void YrsSetStyle(sal_Int32 nPara, ::std::u16string_view rStyle);
|
||||||
|
void YrsSetParaAttr(sal_Int32 nPara, SfxPoolItem const& rItem);
|
||||||
|
OString GetYrsCommentId() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EditDoc( SfxItemPool* pItemPool );
|
EditDoc( SfxItemPool* pItemPool );
|
||||||
~EditDoc();
|
~EditDoc();
|
||||||
@ -139,21 +159,19 @@ public:
|
|||||||
void CreateDefFont( bool bUseStyles );
|
void CreateDefFont( bool bUseStyles );
|
||||||
const SvxFont& GetDefFont() const { return maDefFont; }
|
const SvxFont& GetDefFont() const { return maDefFont; }
|
||||||
|
|
||||||
void SetDefTab(sal_uInt16 nTab)
|
void SetDefTab(sal_uInt16 nTab);
|
||||||
{
|
|
||||||
mnDefTab = nTab ? nTab : DEFTAB;
|
|
||||||
}
|
|
||||||
|
|
||||||
sal_uInt16 GetDefTab() const
|
sal_uInt16 GetDefTab() const
|
||||||
{
|
{
|
||||||
return mnDefTab;
|
return mnDefTab;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetVertical( bool bVertical ) { mbIsVertical = bVertical; }
|
void SetVertical(bool bVertical);
|
||||||
|
|
||||||
bool IsEffectivelyVertical() const;
|
bool IsEffectivelyVertical() const;
|
||||||
bool IsTopToBottom() const;
|
bool IsTopToBottom() const;
|
||||||
bool GetVertical() const;
|
bool GetVertical() const;
|
||||||
void SetRotation( TextRotation nRotation ) { mnRotation = nRotation; }
|
void SetRotation(TextRotation nRotation);
|
||||||
TextRotation GetRotation() const { return mnRotation; }
|
TextRotation GetRotation() const { return mnRotation; }
|
||||||
|
|
||||||
void SetFixedCellHeight( bool bUseFixedCellHeight )
|
void SetFixedCellHeight( bool bUseFixedCellHeight )
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -524,6 +524,9 @@ public:
|
|||||||
class ImpEditEngine : public SfxListener, public svl::StyleSheetUser
|
class ImpEditEngine : public SfxListener, public svl::StyleSheetUser
|
||||||
{
|
{
|
||||||
friend class EditEngine;
|
friend class EditEngine;
|
||||||
|
#if defined(YRS)
|
||||||
|
friend class EditDoc;
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef EditEngine::ViewsType ViewsType;
|
typedef EditEngine::ViewsType ViewsType;
|
||||||
|
|
||||||
|
@ -90,6 +90,9 @@ void ImpEditEngine::SetStyleSheet( sal_Int32 nPara, SfxStyleSheet* pStyle )
|
|||||||
if ( pCurStyle )
|
if ( pCurStyle )
|
||||||
EndListening( *pCurStyle );
|
EndListening( *pCurStyle );
|
||||||
pNode->SetStyleSheet( pStyle, maStatus.UseCharAttribs() );
|
pNode->SetStyleSheet( pStyle, maStatus.UseCharAttribs() );
|
||||||
|
#if defined(YRS)
|
||||||
|
maEditDoc.YrsSetStyle(nPara, pStyle ? pStyle->GetName() : OUString());
|
||||||
|
#endif
|
||||||
if ( pStyle )
|
if ( pStyle )
|
||||||
StartListening(*pStyle, DuplicateHandling::Allow);
|
StartListening(*pStyle, DuplicateHandling::Allow);
|
||||||
|
|
||||||
@ -550,6 +553,9 @@ void ImpEditEngine::SetAttribs( EditSelection aSel, const SfxItemSet& rSet, SetA
|
|||||||
{
|
{
|
||||||
pNode->GetContentAttribs().GetItems().Put( rItem );
|
pNode->GetContentAttribs().GetItems().Put( rItem );
|
||||||
bParaAttribFound = true;
|
bParaAttribFound = true;
|
||||||
|
#if defined(YRS)
|
||||||
|
maEditDoc.YrsSetParaAttr(nNode, rItem);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -37,6 +37,12 @@
|
|||||||
#include <editeng/editengdllapi.h>
|
#include <editeng/editengdllapi.h>
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(YRS)
|
||||||
|
class IYrsTransactionSupplier;
|
||||||
|
typedef struct TransactionInner YTransaction;
|
||||||
|
typedef struct YTextEvent YTextEvent;
|
||||||
|
#endif
|
||||||
|
|
||||||
class EditTextObject;
|
class EditTextObject;
|
||||||
class EditEngine;
|
class EditEngine;
|
||||||
class ImpEditEngine;
|
class ImpEditEngine;
|
||||||
@ -403,6 +409,14 @@ public:
|
|||||||
/// To inform editeng that negated x document coordinates are in use.
|
/// To inform editeng that negated x document coordinates are in use.
|
||||||
void SetNegativeX(bool bSet);
|
void SetNegativeX(bool bSet);
|
||||||
bool IsNegativeX() const;
|
bool IsNegativeX() const;
|
||||||
|
|
||||||
|
#if defined(YRS)
|
||||||
|
void SetYrsCommentId(IYrsTransactionSupplier *, OString const& rId);
|
||||||
|
void YrsWriteEEState();
|
||||||
|
void YrsReadEEState(YTransaction *);
|
||||||
|
void YrsApplyEEDelta(YTransaction *, YTextEvent const* pEvent);
|
||||||
|
OString GetYrsCommentId() const;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // INCLUDED_EDITENG_EDITVIEW_HXX
|
#endif // INCLUDED_EDITENG_EDITVIEW_HXX
|
||||||
|
69
include/editeng/yrs.hxx
Normal file
69
include/editeng/yrs.hxx
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
||||||
|
/*
|
||||||
|
* This file is part of the LibreOffice project.
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#if defined(__clang__)
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wextern-c-compat"
|
||||||
|
#endif
|
||||||
|
#include <libyrs.h>
|
||||||
|
#if defined(__clang__)
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <rtl/string.hxx>
|
||||||
|
|
||||||
|
// check input is valid values to find encoding bugs early
|
||||||
|
#define yvalidate(cond) \
|
||||||
|
if (!(cond)) \
|
||||||
|
{ \
|
||||||
|
std::abort(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
struct YOutputDeleter
|
||||||
|
{
|
||||||
|
void operator()(YOutput* const p) const { youtput_destroy(p); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class IYrsTransactionSupplier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class Mode
|
||||||
|
{
|
||||||
|
Edit,
|
||||||
|
Replay
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Mode m_Mode{ Mode::Edit };
|
||||||
|
|
||||||
|
public:
|
||||||
|
IYrsTransactionSupplier() = default;
|
||||||
|
virtual ~IYrsTransactionSupplier() = default;
|
||||||
|
|
||||||
|
Mode SetMode(Mode const mode)
|
||||||
|
{
|
||||||
|
Mode ret = mode;
|
||||||
|
std::swap(ret, m_Mode);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual YDoc* GetYDoc() = 0;
|
||||||
|
virtual Branch* GetCommentMap() = 0;
|
||||||
|
virtual Branch* GetCursorMap() = 0;
|
||||||
|
virtual YTransaction* GetReadTransaction() = 0;
|
||||||
|
virtual YTransaction* GetWriteTransaction() = 0;
|
||||||
|
virtual bool CommitTransaction(bool isForce = false) = 0;
|
||||||
|
virtual OString GenNewCommentId() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
|
@ -44,6 +44,10 @@ $(eval $(call gb_Library_set_include,sfx,\
|
|||||||
|
|
||||||
$(eval $(call gb_Library_add_defs,sfx,-DSFX2_DLLIMPLEMENTATION))
|
$(eval $(call gb_Library_add_defs,sfx,-DSFX2_DLLIMPLEMENTATION))
|
||||||
|
|
||||||
|
ifneq ($(WITH_YRS),)
|
||||||
|
$(eval $(call gb_Library_add_defs,sfx,-DYRS))
|
||||||
|
endif
|
||||||
|
|
||||||
$(eval $(call gb_Library_use_libraries,sfx,\
|
$(eval $(call gb_Library_use_libraries,sfx,\
|
||||||
basegfx \
|
basegfx \
|
||||||
comphelper \
|
comphelper \
|
||||||
|
@ -46,6 +46,10 @@
|
|||||||
#include <com/sun/star/lang/XInitialization.hpp>
|
#include <com/sun/star/lang/XInitialization.hpp>
|
||||||
#include <com/sun/star/uno/XComponentContext.hpp>
|
#include <com/sun/star/uno/XComponentContext.hpp>
|
||||||
#include <com/sun/star/util/XCloseable.hpp>
|
#include <com/sun/star/util/XCloseable.hpp>
|
||||||
|
#if defined(YRS)
|
||||||
|
#include <com/sun/star/io/SequenceInputStream.hpp>
|
||||||
|
#include <com/sun/star/connection/Connector.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <comphelper/getexpandeduri.hxx>
|
#include <comphelper/getexpandeduri.hxx>
|
||||||
#include <comphelper/interaction.hxx>
|
#include <comphelper/interaction.hxx>
|
||||||
@ -627,6 +631,45 @@ sal_Bool SAL_CALL SfxFrameLoader_Impl::load( const Sequence< PropertyValue >& rA
|
|||||||
Reference< XModel2 > xModel = aDescriptor.getOrDefault( u"Model"_ustr, Reference< XModel2 >() );
|
Reference< XModel2 > xModel = aDescriptor.getOrDefault( u"Model"_ustr, Reference< XModel2 >() );
|
||||||
const bool bExternalModel = xModel.is();
|
const bool bExternalModel = xModel.is();
|
||||||
|
|
||||||
|
#if defined(YRS)
|
||||||
|
uno::Reference<connection::XConnection> xConnection;
|
||||||
|
if (!xModel.is() && aDescriptor.getOrDefault(u"URL"_ustr, OUString()) == "private:factory/swriter" && !getenv("YRSACCEPT"))
|
||||||
|
{
|
||||||
|
SAL_DEBUG("YRS connect sfx2");
|
||||||
|
|
||||||
|
// must read this SYNC
|
||||||
|
auto const conn = u"pipe,name=ytest"_ustr;
|
||||||
|
auto const xConnector = css::connection::Connector::create(m_aContext);
|
||||||
|
xConnection = xConnector->connect(conn);
|
||||||
|
uno::Sequence<sal_Int8> buf;
|
||||||
|
if (xConnection->read(buf, 4) != 4)
|
||||||
|
{
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
sal_Int32 const size{static_cast<sal_uInt8>(buf[0])
|
||||||
|
| static_cast<sal_uInt8>(buf[1]) << 8
|
||||||
|
| static_cast<sal_uInt8>(buf[2]) << 16
|
||||||
|
| static_cast<sal_uInt8>(buf[3]) << 24};
|
||||||
|
if (size != 0)
|
||||||
|
{
|
||||||
|
SAL_DEBUG("YRS connect reading file of size " << size);
|
||||||
|
uno::Sequence<sal_Int8> buff(size);
|
||||||
|
if (xConnection->read(buff, size) != size)
|
||||||
|
{
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
uno::Reference<io::XInputStream> const xInStream{
|
||||||
|
io::SequenceInputStream::createStreamFromSequence(m_aContext, buff)};
|
||||||
|
assert(xInStream.is());
|
||||||
|
|
||||||
|
aDescriptor.put(u"URL"_ustr, u"private:stream"_ustr);
|
||||||
|
aDescriptor.put(u"InputStream"_ustr, uno::Any(xInStream));
|
||||||
|
}
|
||||||
|
aDescriptor.put(u"ReadOnly"_ustr, uno::Any(true));
|
||||||
|
aDescriptor.put(u"YrsConnect"_ustr, uno::Any(xConnection));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// check for factory URLs to create a new doc, instead of loading one
|
// check for factory URLs to create a new doc, instead of loading one
|
||||||
const OUString sURL = aDescriptor.getOrDefault( u"URL"_ustr, OUString() );
|
const OUString sURL = aDescriptor.getOrDefault( u"URL"_ustr, OUString() );
|
||||||
const bool bIsFactoryURL = sURL.startsWith( "private:factory/" );
|
const bool bIsFactoryURL = sURL.startsWith( "private:factory/" );
|
||||||
|
@ -94,6 +94,7 @@ $(eval $(call gb_Library_use_externals,sw,\
|
|||||||
icuuc \
|
icuuc \
|
||||||
icu_headers \
|
icu_headers \
|
||||||
libxml2 \
|
libxml2 \
|
||||||
|
yrs \
|
||||||
))
|
))
|
||||||
|
|
||||||
ifneq ($(ENABLE_WASM_STRIP_ACCESSIBILITY),TRUE)
|
ifneq ($(ENABLE_WASM_STRIP_ACCESSIBILITY),TRUE)
|
||||||
|
@ -19,6 +19,14 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#if defined(YRS)
|
||||||
|
#include <com/sun/star/uno/Any.h>
|
||||||
|
#include <editeng/yrs.hxx>
|
||||||
|
#include <optional>
|
||||||
|
struct SwPosition;
|
||||||
|
class SwPostItField;
|
||||||
|
#endif
|
||||||
|
|
||||||
/** Get information about the current document state
|
/** Get information about the current document state
|
||||||
*/
|
*/
|
||||||
class IDocumentState
|
class IDocumentState
|
||||||
@ -47,6 +55,21 @@ public:
|
|||||||
virtual bool IsEnableSetModified() const = 0;
|
virtual bool IsEnableSetModified() const = 0;
|
||||||
virtual void SetEnableSetModified(bool bEnableSetModified) = 0;
|
virtual void SetEnableSetModified(bool bEnableSetModified) = 0;
|
||||||
|
|
||||||
|
#if defined(YRS)
|
||||||
|
virtual void YrsInitAcceptor() = 0;
|
||||||
|
virtual void YrsInitConnector(css::uno::Any const& raConnector) = 0;
|
||||||
|
virtual IYrsTransactionSupplier::Mode SetYrsMode(IYrsTransactionSupplier::Mode mode) = 0;
|
||||||
|
virtual void YrsCommitModified() = 0;
|
||||||
|
|
||||||
|
virtual void YrsNotifySetResolved(OString const& rCommentId, SwPostItField const& rField) = 0;
|
||||||
|
virtual void YrsAddCommentImpl(SwPosition const& rPos, OString const& rCommentId) = 0;
|
||||||
|
virtual void YrsAddComment(SwPosition const& rPos, ::std::optional<SwPosition> oAnchorStart,
|
||||||
|
SwPostItField const& rField, bool isInsert)
|
||||||
|
= 0;
|
||||||
|
virtual void YrsRemoveCommentImpl(rtl::OString const& rCommentId) = 0;
|
||||||
|
virtual void YrsRemoveComment(SwPosition const& rPos, rtl::OString const& rCommentId) = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~IDocumentState(){};
|
virtual ~IDocumentState(){};
|
||||||
};
|
};
|
||||||
|
@ -131,6 +131,9 @@ class SAL_DLLPUBLIC_RTTI SwPostItMgr final : public SfxListener,
|
|||||||
SwAnnotationItem* InsertItem( SfxBroadcaster* pItem, bool bCheckExistence, bool bFocus);
|
SwAnnotationItem* InsertItem( SfxBroadcaster* pItem, bool bCheckExistence, bool bFocus);
|
||||||
void RemoveItem( SfxBroadcaster* pBroadcast );
|
void RemoveItem( SfxBroadcaster* pBroadcast );
|
||||||
|
|
||||||
|
#if defined(YRS)
|
||||||
|
public:
|
||||||
|
#endif
|
||||||
VclPtr<sw::annotation::SwAnnotationWin> GetOrCreateAnnotationWindow(SwAnnotationItem& rItem, bool& rCreated);
|
VclPtr<sw::annotation::SwAnnotationWin> GetOrCreateAnnotationWindow(SwAnnotationItem& rItem, bool& rCreated);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -21,16 +21,29 @@
|
|||||||
|
|
||||||
#include <IDocumentState.hxx>
|
#include <IDocumentState.hxx>
|
||||||
|
|
||||||
|
#if defined(YRS)
|
||||||
|
#include <rtl/ref.hxx>
|
||||||
|
#include <com/sun/star/connection/XAcceptor.hpp>
|
||||||
|
#include <com/sun/star/connection/XConnector.hpp>
|
||||||
|
struct SwPosition;
|
||||||
|
#endif
|
||||||
|
|
||||||
class SwDoc;
|
class SwDoc;
|
||||||
|
|
||||||
|
|
||||||
namespace sw {
|
namespace sw {
|
||||||
|
|
||||||
|
#if defined(YRS)
|
||||||
|
class YrsThread;
|
||||||
|
class YrsTransactionSupplier;
|
||||||
|
#endif
|
||||||
|
|
||||||
class DocumentStateManager final : public IDocumentState
|
class DocumentStateManager final : public IDocumentState
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DocumentStateManager( SwDoc& i_rSwdoc );
|
DocumentStateManager( SwDoc& i_rSwdoc );
|
||||||
|
~DocumentStateManager();
|
||||||
|
|
||||||
void SetModified() override;
|
void SetModified() override;
|
||||||
void ResetModified() override;
|
void ResetModified() override;
|
||||||
@ -55,6 +68,26 @@ private:
|
|||||||
bool mbUpdateExpField; //< TRUE: Update expression fields.
|
bool mbUpdateExpField; //< TRUE: Update expression fields.
|
||||||
bool mbNewDoc ; //< TRUE: new Doc.
|
bool mbNewDoc ; //< TRUE: new Doc.
|
||||||
bool mbInCallModified; //< TRUE: in Set/Reset-Modified link.
|
bool mbInCallModified; //< TRUE: in Set/Reset-Modified link.
|
||||||
|
|
||||||
|
#if defined(YRS)
|
||||||
|
friend class YrsThread;
|
||||||
|
::rtl::Reference<YrsThread> m_pYrsReader;
|
||||||
|
css::uno::Reference<css::connection::XAcceptor> m_xAcceptor;
|
||||||
|
::std::unique_ptr<YrsTransactionSupplier> m_pYrsSupplier;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void YrsInitAcceptor() override;
|
||||||
|
void YrsInitConnector(css::uno::Any const& raConnector) override;
|
||||||
|
IYrsTransactionSupplier::Mode SetYrsMode(IYrsTransactionSupplier::Mode mode) override;
|
||||||
|
void YrsCommitModified() override;
|
||||||
|
|
||||||
|
void YrsNotifySetResolved(OString const& rCommentId, SwPostItField const& rField) override;
|
||||||
|
void YrsAddCommentImpl(SwPosition const& rPos, OString const& rCommentId) override;
|
||||||
|
void YrsAddComment(SwPosition const& rPos, ::std::optional<SwPosition> oAnchorStart,
|
||||||
|
SwPostItField const& rField, bool isInsert) override;
|
||||||
|
void YrsRemoveCommentImpl(OString const& rCommentId) override;
|
||||||
|
void YrsRemoveComment(SwPosition const& rPos, OString const& rCommentId) override;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1209,6 +1209,22 @@ void SwDocShell::LoadingFinished()
|
|||||||
// before <FinishedLoading(..)> is called.
|
// before <FinishedLoading(..)> is called.
|
||||||
const bool bHasDocToStayModified( m_xDoc->getIDocumentState().IsModified() && m_xDoc->getIDocumentLinksAdministration().LinksUpdated() );
|
const bool bHasDocToStayModified( m_xDoc->getIDocumentState().IsModified() && m_xDoc->getIDocumentLinksAdministration().LinksUpdated() );
|
||||||
|
|
||||||
|
#if defined(YRS)
|
||||||
|
#if 0
|
||||||
|
// this doesn't even filter as advertised!
|
||||||
|
auto const args{GetBaseModel()->getArgs2({u"YrsConnect"_ustr})};
|
||||||
|
#endif
|
||||||
|
// when loading, it is only available from SfxMedium, not SfxBaseModel
|
||||||
|
for (auto const& rArg : GetMedium()->GetArgs())
|
||||||
|
{
|
||||||
|
if (rArg.Name == "YrsConnect")
|
||||||
|
{
|
||||||
|
m_xDoc->getIDocumentState().YrsInitConnector(rArg.Value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
FinishedLoading();
|
FinishedLoading();
|
||||||
SfxViewFrame* pVFrame = SfxViewFrame::GetFirst(this);
|
SfxViewFrame* pVFrame = SfxViewFrame::GetFirst(this);
|
||||||
if(pVFrame)
|
if(pVFrame)
|
||||||
|
@ -61,6 +61,9 @@
|
|||||||
#include <docsh.hxx>
|
#include <docsh.hxx>
|
||||||
#include <doc.hxx>
|
#include <doc.hxx>
|
||||||
#include <IDocumentUndoRedo.hxx>
|
#include <IDocumentUndoRedo.hxx>
|
||||||
|
#if defined(YRS)
|
||||||
|
#include <IDocumentState.hxx>
|
||||||
|
#endif
|
||||||
#include <SwUndoField.hxx>
|
#include <SwUndoField.hxx>
|
||||||
#include <edtwin.hxx>
|
#include <edtwin.hxx>
|
||||||
#include "ShadowOverlayObject.hxx"
|
#include "ShadowOverlayObject.hxx"
|
||||||
@ -206,6 +209,9 @@ void SwAnnotationWin::SetPostItText()
|
|||||||
// get text from SwPostItField and insert into our textview
|
// get text from SwPostItField and insert into our textview
|
||||||
mpOutliner->SetModifyHdl( Link<LinkParamNone*,void>() );
|
mpOutliner->SetModifyHdl( Link<LinkParamNone*,void>() );
|
||||||
mpOutliner->EnableUndo( false );
|
mpOutliner->EnableUndo( false );
|
||||||
|
#if defined(YRS)
|
||||||
|
auto const mode = mrView.GetDocShell()->GetDoc()->getIDocumentState().SetYrsMode(IYrsTransactionSupplier::Mode::Replay);
|
||||||
|
#endif
|
||||||
if( mpField->GetTextObject() )
|
if( mpField->GetTextObject() )
|
||||||
mpOutliner->SetText( *mpField->GetTextObject() );
|
mpOutliner->SetText( *mpField->GetTextObject() );
|
||||||
else
|
else
|
||||||
@ -214,6 +220,9 @@ void SwAnnotationWin::SetPostItText()
|
|||||||
GetOutlinerView()->SetStyleSheet(SwResId(STR_POOLCOLL_COMMENT));
|
GetOutlinerView()->SetStyleSheet(SwResId(STR_POOLCOLL_COMMENT));
|
||||||
GetOutlinerView()->InsertText(sNewText);
|
GetOutlinerView()->InsertText(sNewText);
|
||||||
}
|
}
|
||||||
|
#if defined(YRS)
|
||||||
|
mrView.GetDocShell()->GetDoc()->getIDocumentState().SetYrsMode(mode);
|
||||||
|
#endif
|
||||||
|
|
||||||
mpOutliner->ClearModifyFlag();
|
mpOutliner->ClearModifyFlag();
|
||||||
mpOutliner->GetUndoManager().Clear();
|
mpOutliner->GetUndoManager().Clear();
|
||||||
@ -256,6 +265,11 @@ void SwAnnotationWin::SetResolved(bool resolved)
|
|||||||
UpdateData();
|
UpdateData();
|
||||||
Invalidate();
|
Invalidate();
|
||||||
collectUIInformation(u"SETRESOLVED"_ustr,get_id());
|
collectUIInformation(u"SETRESOLVED"_ustr,get_id());
|
||||||
|
#if defined(YRS)
|
||||||
|
mrView.GetDocShell()->GetDoc()->getIDocumentState().YrsNotifySetResolved(
|
||||||
|
GetOutlinerView()->GetEditView().GetYrsCommentId(),
|
||||||
|
*static_cast<SwPostItField const*>(mpFormatField->GetField()));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwAnnotationWin::ToggleResolved()
|
void SwAnnotationWin::ToggleResolved()
|
||||||
|
@ -45,6 +45,9 @@
|
|||||||
#include <doc.hxx>
|
#include <doc.hxx>
|
||||||
#include <IDocumentSettingAccess.hxx>
|
#include <IDocumentSettingAccess.hxx>
|
||||||
#include <IDocumentFieldsAccess.hxx>
|
#include <IDocumentFieldsAccess.hxx>
|
||||||
|
#if defined(YRS)
|
||||||
|
#include <IDocumentState.hxx>
|
||||||
|
#endif
|
||||||
#include <docstyle.hxx>
|
#include <docstyle.hxx>
|
||||||
#include <fldbas.hxx>
|
#include <fldbas.hxx>
|
||||||
#include <fmtfld.hxx>
|
#include <fmtfld.hxx>
|
||||||
@ -517,6 +520,11 @@ void SwPostItMgr::RemoveItem( SfxBroadcaster* pBroadcast )
|
|||||||
[&pBroadcast](const std::unique_ptr<SwAnnotationItem>& pField) { return pField->GetBroadcaster() == pBroadcast; });
|
[&pBroadcast](const std::unique_ptr<SwAnnotationItem>& pField) { return pField->GetBroadcaster() == pBroadcast; });
|
||||||
if (i != mvPostItFields.end())
|
if (i != mvPostItFields.end())
|
||||||
{
|
{
|
||||||
|
#if defined(YRS)
|
||||||
|
mpView->GetDocShell()->GetDoc()->getIDocumentState().YrsRemoveComment(
|
||||||
|
(*i)->GetAnchorPosition(),
|
||||||
|
(*i)->mpPostIt->GetOutlinerView()->GetEditView().GetYrsCommentId());
|
||||||
|
#endif
|
||||||
std::unique_ptr<SwAnnotationItem> p = std::move(*i);
|
std::unique_ptr<SwAnnotationItem> p = std::move(*i);
|
||||||
// tdf#120487 remove from list before dispose, so comment window
|
// tdf#120487 remove from list before dispose, so comment window
|
||||||
// won't be recreated due to the entry still in the list if focus
|
// won't be recreated due to the entry still in the list if focus
|
||||||
@ -900,6 +908,9 @@ VclPtr<SwAnnotationWin> SwPostItMgr::GetOrCreateAnnotationWindow(SwAnnotationIte
|
|||||||
pPostIt->InitControls();
|
pPostIt->InitControls();
|
||||||
pPostIt->SetReadonly(mbReadOnly);
|
pPostIt->SetReadonly(mbReadOnly);
|
||||||
rItem.mpPostIt = pPostIt;
|
rItem.mpPostIt = pPostIt;
|
||||||
|
#if defined(YRS)
|
||||||
|
SAL_DEBUG("YRS GetOrCreateAnnotationWindow " << rItem.mpPostIt);
|
||||||
|
#endif
|
||||||
if (mpAnswer)
|
if (mpAnswer)
|
||||||
{
|
{
|
||||||
if (pPostIt->GetPostItField()->GetParentPostItId() != 0) //do we really have another note in front of this one
|
if (pPostIt->GetPostItField()->GetParentPostItId() != 0) //do we really have another note in front of this one
|
||||||
|
@ -55,6 +55,9 @@
|
|||||||
#include <wrtsh.hxx>
|
#include <wrtsh.hxx>
|
||||||
#include <AnnotationWin.hxx>
|
#include <AnnotationWin.hxx>
|
||||||
#include <IDocumentDeviceAccess.hxx>
|
#include <IDocumentDeviceAccess.hxx>
|
||||||
|
#if defined(YRS)
|
||||||
|
#include <IDocumentState.hxx>
|
||||||
|
#endif
|
||||||
#include <redline.hxx>
|
#include <redline.hxx>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@ -199,6 +202,14 @@ OUString SidebarTextControl::RequestHelp(tools::Rectangle& rHelpRect)
|
|||||||
return OUString();
|
return OUString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(YRS)
|
||||||
|
void SidebarTextControl::EditViewInvalidate(const tools::Rectangle& rRect)
|
||||||
|
{
|
||||||
|
mrDocView.GetDocShell()->GetDoc()->getIDocumentState().YrsCommitModified();
|
||||||
|
return WeldEditView::EditViewInvalidate(rRect);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void SidebarTextControl::EditViewScrollStateChange()
|
void SidebarTextControl::EditViewScrollStateChange()
|
||||||
{
|
{
|
||||||
mrSidebarWin.SetScrollbar();
|
mrSidebarWin.SetScrollbar();
|
||||||
|
@ -57,6 +57,9 @@ class SidebarTextControl : public WeldEditView
|
|||||||
|
|
||||||
virtual EditEngine* GetEditEngine() const override;
|
virtual EditEngine* GetEditEngine() const override;
|
||||||
|
|
||||||
|
#if defined(YRS)
|
||||||
|
virtual void EditViewInvalidate(const tools::Rectangle& rRect) override;
|
||||||
|
#endif
|
||||||
virtual void EditViewScrollStateChange() override;
|
virtual void EditViewScrollStateChange() override;
|
||||||
|
|
||||||
void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
|
void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
|
||||||
|
@ -75,6 +75,10 @@
|
|||||||
#include <txmsrt.hxx>
|
#include <txmsrt.hxx>
|
||||||
#include <unotools/useroptions.hxx>
|
#include <unotools/useroptions.hxx>
|
||||||
#include <IDocumentContentOperations.hxx>
|
#include <IDocumentContentOperations.hxx>
|
||||||
|
#if defined(YRS)
|
||||||
|
#include <IDocumentState.hxx>
|
||||||
|
#include <txtfld.hxx>
|
||||||
|
#endif
|
||||||
#include <translatehelper.hxx>
|
#include <translatehelper.hxx>
|
||||||
|
|
||||||
using namespace com::sun::star::uno;
|
using namespace com::sun::star::uno;
|
||||||
@ -1524,7 +1528,8 @@ bool SwFieldMgr::InsertField(
|
|||||||
// insert
|
// insert
|
||||||
pCurShell->StartAllAction();
|
pCurShell->StartAllAction();
|
||||||
|
|
||||||
bool const isSuccess = pCurShell->InsertField2(*pField, rData.m_oAnnotationRange ? &*rData.m_oAnnotationRange : nullptr);
|
::std::optional<SwPosition> oAnchorStart;
|
||||||
|
bool const isSuccess = pCurShell->InsertField2(*pField, rData.m_oAnnotationRange ? &*rData.m_oAnnotationRange : nullptr, &oAnchorStart);
|
||||||
|
|
||||||
if (isSuccess)
|
if (isSuccess)
|
||||||
{
|
{
|
||||||
@ -1566,6 +1571,21 @@ bool SwFieldMgr::InsertField(
|
|||||||
pField.reset();
|
pField.reset();
|
||||||
|
|
||||||
pCurShell->EndAllAction();
|
pCurShell->EndAllAction();
|
||||||
|
|
||||||
|
#if defined(YRS)
|
||||||
|
if (isSuccess)
|
||||||
|
{
|
||||||
|
// now the SwAnnotationWin are created
|
||||||
|
// shell cursor is behind field
|
||||||
|
SwPosition const pos{pCurShell->GetCursor()->GetPoint()->nContent, -1};
|
||||||
|
pCurShell->GetDoc()->getIDocumentState().YrsAddComment(
|
||||||
|
pos, oAnchorStart,
|
||||||
|
static_cast<SwPostItField const&>(*SwCursorShell::GetTextFieldAtPos(&pos, ::sw::GetTextAttrMode::Default)->GetFormatField().GetField()),
|
||||||
|
true);
|
||||||
|
pCurShell->GetDoc()->getIDocumentState().YrsCommitModified();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return isSuccess;
|
return isSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,7 +317,10 @@ typedef bool (SwWrtShell::*FNSimpleMove)();
|
|||||||
int IntelligentCut(SelectionType nSelectionType, bool bCut = true);
|
int IntelligentCut(SelectionType nSelectionType, bool bCut = true);
|
||||||
|
|
||||||
// edit
|
// edit
|
||||||
SW_DLLPUBLIC bool InsertField2(SwField const &, SwPaM* pAnnotationRange = nullptr);
|
bool InsertField2Impl(SwField const &, SwPaM* pAnnotationRange,
|
||||||
|
::std::optional<SwPosition> *const poAnchorStart);
|
||||||
|
SW_DLLPUBLIC bool InsertField2(SwField const &, SwPaM* pAnnotationRange = nullptr,
|
||||||
|
::std::optional<SwPosition> *const poAnchorStart = nullptr);
|
||||||
SW_DLLPUBLIC void Insert(const OUString &);
|
SW_DLLPUBLIC void Insert(const OUString &);
|
||||||
// graphic
|
// graphic
|
||||||
void InsertGraphic( const OUString &rPath, const OUString &rFilter,
|
void InsertGraphic( const OUString &rPath, const OUString &rFilter,
|
||||||
|
@ -1027,6 +1027,9 @@ SwView::SwView(SfxViewFrame& _rFrame, SfxViewShell* pOldSh)
|
|||||||
// Set DocShell
|
// Set DocShell
|
||||||
m_xGlueDocShell.reset(new SwViewGlueDocShell(*this, rDocSh));
|
m_xGlueDocShell.reset(new SwViewGlueDocShell(*this, rDocSh));
|
||||||
m_pPostItMgr.reset(new SwPostItMgr(this));
|
m_pPostItMgr.reset(new SwPostItMgr(this));
|
||||||
|
#if defined(YRS)
|
||||||
|
m_pWrtShell->GetDoc()->getIDocumentState().YrsInitAcceptor();
|
||||||
|
#endif
|
||||||
|
|
||||||
// Check and process the DocSize. Via the handler, the shell could not
|
// Check and process the DocSize. Via the handler, the shell could not
|
||||||
// be found, because the shell is not known in the SFX management
|
// be found, because the shell is not known in the SFX management
|
||||||
|
@ -523,6 +523,17 @@ Reference< XInterface > SwXTextDocument::getCurrentSelection()
|
|||||||
|
|
||||||
sal_Bool SwXTextDocument::attachResource(const OUString& aURL, const Sequence< beans::PropertyValue >& aArgs)
|
sal_Bool SwXTextDocument::attachResource(const OUString& aURL, const Sequence< beans::PropertyValue >& aArgs)
|
||||||
{
|
{
|
||||||
|
#if defined(YRS)
|
||||||
|
// this is for new document
|
||||||
|
for (auto const& rArg : aArgs)
|
||||||
|
{
|
||||||
|
if (rArg.Name == "YrsConnect")
|
||||||
|
{
|
||||||
|
m_pDocShell->GetDoc()->getIDocumentState().YrsInitConnector(rArg.Value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return SfxBaseModel::attachResource(aURL, aArgs);
|
return SfxBaseModel::attachResource(aURL, aArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,11 +66,18 @@
|
|||||||
#include <strings.hrc>
|
#include <strings.hrc>
|
||||||
#include <officecfg/Office/Common.hxx>
|
#include <officecfg/Office/Common.hxx>
|
||||||
|
|
||||||
bool SwWrtShell::InsertField2(SwField const& rField, SwPaM* pAnnotationRange)
|
bool SwWrtShell::InsertField2(SwField const& rField,
|
||||||
|
SwPaM* pAnnotationRange, ::std::optional<SwPosition> *const poAnchorStart)
|
||||||
{
|
{
|
||||||
ResetCursorStack();
|
ResetCursorStack();
|
||||||
if(!CanInsert())
|
if(!CanInsert())
|
||||||
return false;
|
return false;
|
||||||
|
return InsertField2Impl(rField, pAnnotationRange, poAnchorStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SwWrtShell::InsertField2Impl(SwField const& rField,
|
||||||
|
SwPaM* pAnnotationRange, ::std::optional<SwPosition> *const poAnchorStart)
|
||||||
|
{
|
||||||
StartAllAction();
|
StartAllAction();
|
||||||
|
|
||||||
SwRewriter aRewriter;
|
SwRewriter aRewriter;
|
||||||
@ -135,7 +142,11 @@ bool SwWrtShell::InsertField2(SwField const& rField, SwPaM* pAnnotationRange)
|
|||||||
pAnnotationTextRange->Start()->AdjustContent(-1);
|
pAnnotationTextRange->Start()->AdjustContent(-1);
|
||||||
}
|
}
|
||||||
IDocumentMarkAccess* pMarksAccess = GetDoc()->getIDocumentMarkAccess();
|
IDocumentMarkAccess* pMarksAccess = GetDoc()->getIDocumentMarkAccess();
|
||||||
pMarksAccess->makeAnnotationMark( *pAnnotationTextRange, SwMarkName() );
|
auto pMark{pMarksAccess->makeAnnotationMark(*pAnnotationTextRange, SwMarkName())};
|
||||||
|
if (poAnchorStart)
|
||||||
|
{
|
||||||
|
poAnchorStart->emplace(pMark->GetMarkStart());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pAnnotationTextRange.reset();
|
pAnnotationTextRange.reset();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user