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
|
||||
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:
|
||||
|
@ -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@
|
||||
|
@ -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
|
||||
|
@ -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,\
|
||||
|
@ -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,\
|
||||
|
@ -166,6 +166,7 @@ $(eval $(call gb_Library_use_externals,editeng,\
|
||||
icuuc \
|
||||
icu_headers \
|
||||
libxml2 \
|
||||
yrs \
|
||||
))
|
||||
|
||||
# vim: set noet sw=4 ts=4:
|
||||
|
@ -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
@ -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;
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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
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))
|
||||
|
||||
ifneq ($(WITH_YRS),)
|
||||
$(eval $(call gb_Library_add_defs,sfx,-DYRS))
|
||||
endif
|
||||
|
||||
$(eval $(call gb_Library_use_libraries,sfx,\
|
||||
basegfx \
|
||||
comphelper \
|
||||
|
@ -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/" );
|
||||
|
@ -94,6 +94,7 @@ $(eval $(call gb_Library_use_externals,sw,\
|
||||
icuuc \
|
||||
icu_headers \
|
||||
libxml2 \
|
||||
yrs \
|
||||
))
|
||||
|
||||
ifneq ($(ENABLE_WASM_STRIP_ACCESSIBILITY),TRUE)
|
||||
|
@ -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(){};
|
||||
};
|
||||
|
@ -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
@ -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
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user