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:
Michael Stahl 2024-10-25 15:02:34 +02:00
parent 0a677d53a6
commit 8f8034177b
30 changed files with 3940 additions and 10 deletions

46
README.yrs Normal file
View 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.

View File

@ -4449,4 +4449,21 @@ $(call gb_LinkTarget_set_include,$(1),\
endef
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:

View File

@ -784,6 +784,7 @@ export WITH_LOCALES=@WITH_LOCALES@
export WITH_MYSPELL_DICTS=@WITH_MYSPELL_DICTS@
export WITH_THEMES=@WITH_THEMES@
export WITH_WEBDAV=@WITH_WEBDAV@
WITH_YRS=@WITH_YRS@
export WORKDIR=@WORKDIR@
export WORKDIR_FOR_BUILD=@WORKDIR_FOR_BUILD@
export WPD_CFLAGS=$(gb_SPACE)@WPD_CFLAGS@

View File

@ -2830,6 +2830,12 @@ AC_ARG_WITH(hamcrest,
--without-junit disables those tests. Not relevant in the --without-java case.]),
,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,
AS_HELP_STRING([--with-perl-home=<abs. path to Perl 5 home>],
[If you have installed Perl 5 Distribution, on your system, please

View File

@ -53,6 +53,7 @@ $(eval $(call gb_CppunitTest_use_externals,editeng_core,\
boost_headers \
icuuc \
libxml2 \
yrs \
))
$(eval $(call gb_CppunitTest_set_include,editeng_core,\

View File

@ -47,6 +47,7 @@ $(eval $(call gb_CppunitTest_use_externals,editeng_editeng,\
boost_headers \
icuuc \
libxml2 \
yrs \
))
$(eval $(call gb_CppunitTest_set_include,editeng_editeng,\

View File

@ -166,6 +166,7 @@ $(eval $(call gb_Library_use_externals,editeng,\
icuuc \
icu_headers \
libxml2 \
yrs \
))
# vim: set noet sw=4 ts=4:

View File

@ -46,6 +46,13 @@
enum class TextRotation;
#if defined(YRS)
class ImpEditEngine;
class IYrsTransactionSupplier;
typedef struct TransactionInner YTransaction;
typedef struct YTextEvent YTextEvent;
#endif
#define CHARPOSGROW 16
#define DEFTAB 720
@ -119,6 +126,19 @@ private:
bool mbModified: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:
EditDoc( SfxItemPool* pItemPool );
~EditDoc();
@ -139,21 +159,19 @@ public:
void CreateDefFont( bool bUseStyles );
const SvxFont& GetDefFont() const { return maDefFont; }
void SetDefTab(sal_uInt16 nTab)
{
mnDefTab = nTab ? nTab : DEFTAB;
}
void SetDefTab(sal_uInt16 nTab);
sal_uInt16 GetDefTab() const
{
return mnDefTab;
}
void SetVertical( bool bVertical ) { mbIsVertical = bVertical; }
void SetVertical(bool bVertical);
bool IsEffectivelyVertical() const;
bool IsTopToBottom() const;
bool GetVertical() const;
void SetRotation( TextRotation nRotation ) { mnRotation = nRotation; }
void SetRotation(TextRotation nRotation);
TextRotation GetRotation() const { return mnRotation; }
void SetFixedCellHeight( bool bUseFixedCellHeight )

File diff suppressed because it is too large Load Diff

View File

@ -524,6 +524,9 @@ public:
class ImpEditEngine : public SfxListener, public svl::StyleSheetUser
{
friend class EditEngine;
#if defined(YRS)
friend class EditDoc;
#endif
typedef EditEngine::ViewsType ViewsType;

View File

@ -90,6 +90,9 @@ void ImpEditEngine::SetStyleSheet( sal_Int32 nPara, SfxStyleSheet* pStyle )
if ( pCurStyle )
EndListening( *pCurStyle );
pNode->SetStyleSheet( pStyle, maStatus.UseCharAttribs() );
#if defined(YRS)
maEditDoc.YrsSetStyle(nPara, pStyle ? pStyle->GetName() : OUString());
#endif
if ( pStyle )
StartListening(*pStyle, DuplicateHandling::Allow);
@ -550,6 +553,9 @@ void ImpEditEngine::SetAttribs( EditSelection aSel, const SfxItemSet& rSet, SetA
{
pNode->GetContentAttribs().GetItems().Put( rItem );
bParaAttribFound = true;
#if defined(YRS)
maEditDoc.YrsSetParaAttr(nNode, rItem);
#endif
}
else
{

View File

@ -37,6 +37,12 @@
#include <editeng/editengdllapi.h>
#if defined(YRS)
class IYrsTransactionSupplier;
typedef struct TransactionInner YTransaction;
typedef struct YTextEvent YTextEvent;
#endif
class EditTextObject;
class EditEngine;
class ImpEditEngine;
@ -403,6 +409,14 @@ public:
/// To inform editeng that negated x document coordinates are in use.
void SetNegativeX(bool bSet);
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

69
include/editeng/yrs.hxx Normal file
View 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: */

View File

@ -44,6 +44,10 @@ $(eval $(call gb_Library_set_include,sfx,\
$(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,\
basegfx \
comphelper \

View File

@ -46,6 +46,10 @@
#include <com/sun/star/lang/XInitialization.hpp>
#include <com/sun/star/uno/XComponentContext.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/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 >() );
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
const OUString sURL = aDescriptor.getOrDefault( u"URL"_ustr, OUString() );
const bool bIsFactoryURL = sURL.startsWith( "private:factory/" );

View File

@ -94,6 +94,7 @@ $(eval $(call gb_Library_use_externals,sw,\
icuuc \
icu_headers \
libxml2 \
yrs \
))
ifneq ($(ENABLE_WASM_STRIP_ACCESSIBILITY),TRUE)

View File

@ -19,6 +19,14 @@
#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
*/
class IDocumentState
@ -47,6 +55,21 @@ public:
virtual bool IsEnableSetModified() const = 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:
virtual ~IDocumentState(){};
};

View File

@ -131,6 +131,9 @@ class SAL_DLLPUBLIC_RTTI SwPostItMgr final : public SfxListener,
SwAnnotationItem* InsertItem( SfxBroadcaster* pItem, bool bCheckExistence, bool bFocus);
void RemoveItem( SfxBroadcaster* pBroadcast );
#if defined(YRS)
public:
#endif
VclPtr<sw::annotation::SwAnnotationWin> GetOrCreateAnnotationWindow(SwAnnotationItem& rItem, bool& rCreated);
public:

File diff suppressed because it is too large Load Diff

View File

@ -21,16 +21,29 @@
#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;
namespace sw {
#if defined(YRS)
class YrsThread;
class YrsTransactionSupplier;
#endif
class DocumentStateManager final : public IDocumentState
{
public:
DocumentStateManager( SwDoc& i_rSwdoc );
~DocumentStateManager();
void SetModified() override;
void ResetModified() override;
@ -55,6 +68,26 @@ private:
bool mbUpdateExpField; //< TRUE: Update expression fields.
bool mbNewDoc ; //< TRUE: new Doc.
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
};
}

View File

@ -1209,6 +1209,22 @@ void SwDocShell::LoadingFinished()
// before <FinishedLoading(..)> is called.
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();
SfxViewFrame* pVFrame = SfxViewFrame::GetFirst(this);
if(pVFrame)

View File

@ -61,6 +61,9 @@
#include <docsh.hxx>
#include <doc.hxx>
#include <IDocumentUndoRedo.hxx>
#if defined(YRS)
#include <IDocumentState.hxx>
#endif
#include <SwUndoField.hxx>
#include <edtwin.hxx>
#include "ShadowOverlayObject.hxx"
@ -206,6 +209,9 @@ void SwAnnotationWin::SetPostItText()
// get text from SwPostItField and insert into our textview
mpOutliner->SetModifyHdl( Link<LinkParamNone*,void>() );
mpOutliner->EnableUndo( false );
#if defined(YRS)
auto const mode = mrView.GetDocShell()->GetDoc()->getIDocumentState().SetYrsMode(IYrsTransactionSupplier::Mode::Replay);
#endif
if( mpField->GetTextObject() )
mpOutliner->SetText( *mpField->GetTextObject() );
else
@ -214,6 +220,9 @@ void SwAnnotationWin::SetPostItText()
GetOutlinerView()->SetStyleSheet(SwResId(STR_POOLCOLL_COMMENT));
GetOutlinerView()->InsertText(sNewText);
}
#if defined(YRS)
mrView.GetDocShell()->GetDoc()->getIDocumentState().SetYrsMode(mode);
#endif
mpOutliner->ClearModifyFlag();
mpOutliner->GetUndoManager().Clear();
@ -256,6 +265,11 @@ void SwAnnotationWin::SetResolved(bool resolved)
UpdateData();
Invalidate();
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()

View File

@ -45,6 +45,9 @@
#include <doc.hxx>
#include <IDocumentSettingAccess.hxx>
#include <IDocumentFieldsAccess.hxx>
#if defined(YRS)
#include <IDocumentState.hxx>
#endif
#include <docstyle.hxx>
#include <fldbas.hxx>
#include <fmtfld.hxx>
@ -517,6 +520,11 @@ void SwPostItMgr::RemoveItem( SfxBroadcaster* pBroadcast )
[&pBroadcast](const std::unique_ptr<SwAnnotationItem>& pField) { return pField->GetBroadcaster() == pBroadcast; });
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);
// tdf#120487 remove from list before dispose, so comment window
// 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->SetReadonly(mbReadOnly);
rItem.mpPostIt = pPostIt;
#if defined(YRS)
SAL_DEBUG("YRS GetOrCreateAnnotationWindow " << rItem.mpPostIt);
#endif
if (mpAnswer)
{
if (pPostIt->GetPostItField()->GetParentPostItId() != 0) //do we really have another note in front of this one

View File

@ -55,6 +55,9 @@
#include <wrtsh.hxx>
#include <AnnotationWin.hxx>
#include <IDocumentDeviceAccess.hxx>
#if defined(YRS)
#include <IDocumentState.hxx>
#endif
#include <redline.hxx>
#include <memory>
@ -199,6 +202,14 @@ OUString SidebarTextControl::RequestHelp(tools::Rectangle& rHelpRect)
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()
{
mrSidebarWin.SetScrollbar();

View File

@ -57,6 +57,9 @@ class SidebarTextControl : public WeldEditView
virtual EditEngine* GetEditEngine() const override;
#if defined(YRS)
virtual void EditViewInvalidate(const tools::Rectangle& rRect) override;
#endif
virtual void EditViewScrollStateChange() override;
void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;

View File

@ -75,6 +75,10 @@
#include <txmsrt.hxx>
#include <unotools/useroptions.hxx>
#include <IDocumentContentOperations.hxx>
#if defined(YRS)
#include <IDocumentState.hxx>
#include <txtfld.hxx>
#endif
#include <translatehelper.hxx>
using namespace com::sun::star::uno;
@ -1524,7 +1528,8 @@ bool SwFieldMgr::InsertField(
// insert
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)
{
@ -1566,6 +1571,21 @@ bool SwFieldMgr::InsertField(
pField.reset();
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;
}

View File

@ -317,7 +317,10 @@ typedef bool (SwWrtShell::*FNSimpleMove)();
int IntelligentCut(SelectionType nSelectionType, bool bCut = true);
// 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 &);
// graphic
void InsertGraphic( const OUString &rPath, const OUString &rFilter,

View File

@ -1027,6 +1027,9 @@ SwView::SwView(SfxViewFrame& _rFrame, SfxViewShell* pOldSh)
// Set DocShell
m_xGlueDocShell.reset(new SwViewGlueDocShell(*this, rDocSh));
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
// be found, because the shell is not known in the SFX management

View File

@ -523,6 +523,17 @@ Reference< XInterface > SwXTextDocument::getCurrentSelection()
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);
}

View File

@ -66,11 +66,18 @@
#include <strings.hrc>
#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();
if(!CanInsert())
return false;
return InsertField2Impl(rField, pAnnotationRange, poAnchorStart);
}
bool SwWrtShell::InsertField2Impl(SwField const& rField,
SwPaM* pAnnotationRange, ::std::optional<SwPosition> *const poAnchorStart)
{
StartAllAction();
SwRewriter aRewriter;
@ -135,7 +142,11 @@ bool SwWrtShell::InsertField2(SwField const& rField, SwPaM* pAnnotationRange)
pAnnotationTextRange->Start()->AdjustContent(-1);
}
IDocumentMarkAccess* pMarksAccess = GetDoc()->getIDocumentMarkAccess();
pMarksAccess->makeAnnotationMark( *pAnnotationTextRange, SwMarkName() );
auto pMark{pMarksAccess->makeAnnotationMark(*pAnnotationTextRange, SwMarkName())};
if (poAnchorStart)
{
poAnchorStart->emplace(pMark->GetMarkStart());
}
}
pAnnotationTextRange.reset();
}