include/svx/sdr/contact/viewcontact.hxx       |    5 +
 include/svx/sdr/contact/viewobjectcontact.hxx |    5 +
 include/svx/svdedxv.hxx                       |   14 +++-
 sd/source/ui/view/sdview.cxx                  |    6 +
 svx/source/sdr/contact/viewcontact.cxx        |   23 ++++++
 svx/source/sdr/contact/viewobjectcontact.cxx  |   11 +++
 svx/source/svdraw/svdedxv.cxx                 |   87 ++++++++++++++++++++++++++
 svx/source/unodraw/unoshtxt.cxx               |    8 ++
 8 files changed, 157 insertions(+), 2 deletions(-)

New commits:
commit e3fdafaabc198054255fa7c5c34b6beed6915b3b
Author:     Armin Le Grand (allotropia) <[email protected]>
AuthorDate: Thu Feb 29 16:08:29 2024 +0100
Commit:     Armin Le Grand <[email protected]>
CommitDate: Thu Feb 29 23:23:04 2024 +0100

    IASS: Update edited Text in other Views
    
    This was not working for multiple Windows for
    a document, and also not supported for SlideShow
    until now.
    
    If you edit a Text on a Slide (Object, PresObj,
    ...) that text is not yet set at the Model until
    the TextEdit ends. In that situation those changes
    are now propagated to other views visualizing that
    object. This is done with slight slowdown to not
    do it all the time while typing, (currently 350ms,
    grepped from other places in the office).
    
    It will be shown in a running open SlideShow (and
    evtl. trigger an effect at the Object as Preview).
    This will allow to get a good preview for how it
    looks in the SlideShow.
    
    This is also done for further EditViews opened
    for that Document. This was not done before. It
    is fine-tuned to do this only for the Views besides
    the EditView with the running TextEdit to not
    cause slowdowns in that active view - the TextEdit
    is already running on the Overlay to have no
    problems with speed, this needs to be preserved.
    
    I had to fix a multi-view error in the a11y stack
    that implied that only one view exists and thus
    has to have an Outliner - that is wrong for
    multiple views, only one will have one.
    
    Change-Id: I781d32a8fcb8732ee8fcfbae72c02d1f99b6cd06
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164160
    Tested-by: Jenkins
    Reviewed-by: Armin Le Grand <[email protected]>

diff --git a/include/svx/sdr/contact/viewcontact.hxx 
b/include/svx/sdr/contact/viewcontact.hxx
index 7b6d0f3ab2c1..00b7f6253eae 100644
--- a/include/svx/sdr/contact/viewcontact.hxx
+++ b/include/svx/sdr/contact/viewcontact.hxx
@@ -27,6 +27,7 @@
 class SdrLayerIDSet;
 class SdrPage;
 class SdrObject;
+class SdrPageView;
 
 namespace sdr::contact
 {
@@ -122,6 +123,10 @@ public:
     // React on changes of the object of this ViewContact
     virtual void ActionChanged();
 
+    // IASS: helpers for IASS invalidates
+    void ActionChangedIfDifferentPageView(SdrPageView& rSdrPageView);
+    bool hasMultipleViewObjectContacts() const;
+
     // access to the local primitive. This will ensure that the primitive is
     // current in comparing the local one with a fresh created incarnation
     void getViewIndependentPrimitive2DContainer(
diff --git a/include/svx/sdr/contact/viewobjectcontact.hxx 
b/include/svx/sdr/contact/viewobjectcontact.hxx
index 12195a0faa34..8f903d93e04b 100644
--- a/include/svx/sdr/contact/viewobjectcontact.hxx
+++ b/include/svx/sdr/contact/viewobjectcontact.hxx
@@ -24,6 +24,8 @@
 #include <svx/svxdllapi.h>
 #include <drawinglayer/primitive2d/Primitive2DContainer.hxx>
 
+class SdrPageView;
+
 namespace vcl { class Region; }
 
 namespace sdr::animation {
@@ -101,6 +103,9 @@ public:
     // React on changes of the object of this ViewContact
     virtual void ActionChanged();
 
+    // IASS: helper for IASS invalidates
+    void ActionChangedIfDifferentPageView(SdrPageView& rSdrPageView);
+
     // LazyInvalidate handling
     void triggerLazyInvalidate();
 
diff --git a/include/svx/svdedxv.hxx b/include/svx/svdedxv.hxx
index 8ad7f048b682..6c6a37f108a7 100644
--- a/include/svx/svdedxv.hxx
+++ b/include/svx/svdedxv.hxx
@@ -76,8 +76,15 @@ class SVXCORE_DLLPUBLIC SdrObjEditView : public 
SdrGlueEditView, public EditView
     virtual void EditViewCursorRect(const tools::Rectangle& rRect, int 
nExtTextInputWidth) override;
 
     // The OverlayObjects used for visualizing active TextEdit (currently
-    // using TextEditOverlayObject, but not limited to it
+    // using TextEditOverlayObject, but not limited to it)
     sdr::overlay::OverlayObjectList maTEOverlayGroup;
+    Timer                           maTextEditUpdateTimer;
+
+    // IASS: allow reaction to active TextEdit changes
+    DECL_DLLPRIVATE_LINK(ImpModifyHdl, LinkParamNone*, void);
+
+    // IASS: timer-based reaction on TextEdit changes
+    DECL_DLLPRIVATE_LINK(TextEditUpdate, Timer*, void);
 
 protected:
     // TextEdit
@@ -104,10 +111,15 @@ protected:
     bool mbTextEditNewObj : 1;      // current edited object was just recreated
     bool mbQuickTextEditMode : 1;   // persistent(->CrtV). Default=TRUE
     bool mbMacroDown : 1;
+    bool mbInteractiveSlideShow : 1; // IASS
 
     rtl::Reference< sdr::SelectionController > mxSelectionController;
     rtl::Reference< sdr::SelectionController > mxLastSelectionController;
 
+    // check/set if we are in IASS and need to refresh evtl.
+    void setInteractiveSlideShow(bool bNew) { mbInteractiveSlideShow = bNew; }
+    bool isInteractiveSlideShow() const { return mbInteractiveSlideShow; }
+
 private:
     EditUndoManager* mpOldTextEditUndoManager;
     std::unique_ptr<SdrUndoManager> mpLocalTextEditUndoManager;
diff --git a/sd/source/ui/view/sdview.cxx b/sd/source/ui/view/sdview.cxx
index 345ef782ea84..9c4713fcb0ac 100644
--- a/sd/source/ui/view/sdview.cxx
+++ b/sd/source/ui/view/sdview.cxx
@@ -24,6 +24,7 @@
 #include <com/sun/star/linguistic2/XSpellChecker1.hpp>
 
 #include <View.hxx>
+#include <slideshow.hxx>
 #include <avmedia/mediawindow.hxx>
 #include <editeng/outlobj.hxx>
 #include <editeng/unolingu.hxx>
@@ -698,6 +699,11 @@ bool View::SdrBeginTextEdit(
         pOutl->SetDefaultLanguage( 
Application::GetSettings().GetLanguageTag().getLanguageType() );
     }
 
+    // check if we have IASS active and propagate that info to the view with 
the active TextEdit
+    rtl::Reference< SlideShow > 
xSlideshow(SlideShow::GetSlideShow(mpViewSh->GetViewShellBase()));
+    const bool bIASS(xSlideshow.is() && xSlideshow->isRunning() && 
xSlideshow->IsInteractiveSlideshow());
+    setInteractiveSlideShow(bIASS);
+
     bool bReturn = FmFormView::SdrBeginTextEdit(
         pObj, pPV, pWin, bIsNewObj, pOutl,
         pGivenOutlinerView, bDontDeleteOutliner,
diff --git a/svx/source/sdr/contact/viewcontact.cxx 
b/svx/source/sdr/contact/viewcontact.cxx
index 99106d0d6ed0..fcc9a6975380 100644
--- a/svx/source/sdr/contact/viewcontact.cxx
+++ b/svx/source/sdr/contact/viewcontact.cxx
@@ -203,6 +203,29 @@ void ViewContact::ActionChanged()
     }
 }
 
+// IASS: helper for IASS invalidates
+void ViewContact::ActionChangedIfDifferentPageView(SdrPageView& rSdrPageView)
+{
+    const sal_uInt32 nCount(maViewObjectContactVector.size());
+
+    for (sal_uInt32 a(0); a < nCount; a++)
+    {
+        ViewObjectContact* pCandidate = maViewObjectContactVector[a];
+        DBG_ASSERT(pCandidate,
+                   "ViewContact::GetViewObjectContact() invalid 
ViewObjectContactList (!)");
+
+        if (pCandidate)
+        {
+            pCandidate->ActionChangedIfDifferentPageView(rSdrPageView);
+        }
+    }
+}
+
+bool ViewContact::hasMultipleViewObjectContacts() const
+{
+    return maViewObjectContactVector.size() > 1;
+}
+
 // access to SdrObject and/or SdrPage. May return 0L like the default
 // implementations do. Override as needed.
 SdrObject* ViewContact::TryToGetSdrObject() const { return nullptr; }
diff --git a/svx/source/sdr/contact/viewobjectcontact.cxx 
b/svx/source/sdr/contact/viewobjectcontact.cxx
index 2e3ebfd8d3f9..03d6eb4bd10c 100644
--- a/svx/source/sdr/contact/viewobjectcontact.cxx
+++ b/svx/source/sdr/contact/viewobjectcontact.cxx
@@ -250,6 +250,17 @@ void ViewObjectContact::ActionChanged()
     GetObjectContact().setLazyInvalidate(*this);
 }
 
+// IASS: helper for IASS invalidates
+void ViewObjectContact::ActionChangedIfDifferentPageView(SdrPageView& 
rSdrPageView)
+{
+    SdrPageView* pSdrPageView(GetObjectContact().TryToGetSdrPageView());
+
+    // if there is no SdrPageView or different from given one, force
+    // invalidate/repaint
+    if (nullptr == pSdrPageView || pSdrPageView != &rSdrPageView)
+        ActionChanged();
+}
+
 void ViewObjectContact::triggerLazyInvalidate()
 {
     if(!mbLazyInvalidate)
diff --git a/svx/source/svdraw/svdedxv.cxx b/svx/source/svdraw/svdedxv.cxx
index f3f5d4818f20..3685cd55a8ef 100644
--- a/svx/source/svdraw/svdedxv.cxx
+++ b/svx/source/svdraw/svdedxv.cxx
@@ -68,11 +68,15 @@
 #include <textchaincursor.hxx>
 #include <tools/debug.hxx>
 #include <vcl/svapp.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
 
 #include <memory>
 
 SdrObjEditView::SdrObjEditView(SdrModel& rSdrModel, OutputDevice* pOut)
     : SdrGlueEditView(rSdrModel, pOut)
+    , maTEOverlayGroup()
+    , maTextEditUpdateTimer("TextEditUpdateTimer")
+    , mxWeakTextEditObj()
     , mpTextEditPV(nullptr)
     , mpTextEditOutlinerView(nullptr)
     , mpTextEditWin(nullptr)
@@ -80,18 +84,89 @@ SdrObjEditView::SdrObjEditView(SdrModel& rSdrModel, 
OutputDevice* pOut)
     , pMacroObj(nullptr)
     , pMacroPV(nullptr)
     , pMacroWin(nullptr)
+    , aTextEditArea()
+    , aMinTextEditArea()
+    , aOldCalcFieldValueLink()
+    , aMacroDownPos()
     , nMacroTol(0)
     , mbTextEditDontDelete(false)
     , mbTextEditOnlyOneView(false)
     , mbTextEditNewObj(false)
     , mbQuickTextEditMode(true)
     , mbMacroDown(false)
+    , mbInteractiveSlideShow(false)
+    , mxSelectionController()
+    , mxLastSelectionController()
     , mpOldTextEditUndoManager(nullptr)
+    , mpLocalTextEditUndoManager()
 {
+    // init some timer settings (not starting it of course)
+    maTextEditUpdateTimer.SetTimeout(EDIT_UPDATEDATA_TIMEOUT);
+    maTextEditUpdateTimer.SetInvokeHandler(LINK(this, SdrObjEditView, 
TextEditUpdate));
+}
+
+IMPL_LINK_NOARG(SdrObjEditView, ImpModifyHdl, LinkParamNone*, void)
+{
+    // IASS: active TextEdit had a model change. Check and react.
+    if (nullptr == mpTextEditOutliner)
+        // no Outliner, no TextEdit
+        return;
+
+    if (!mxWeakTextEditObj.get().is())
+        // no TextObject, no TextEdit
+        return;
+
+    // reset & restart the timer
+    maTextEditUpdateTimer.SetTimeout(EDIT_UPDATEDATA_TIMEOUT);
+    maTextEditUpdateTimer.Start();
+}
+
+IMPL_LINK_NOARG(SdrObjEditView, TextEditUpdate, Timer*, void)
+{
+    // IASS: text was changed and EDIT_UPDATEDATA_TIMEOUT has passed
+    // since last user input
+    maTextEditUpdateTimer.Stop();
+
+    // be safe: still in TextEdit?
+    if (nullptr == mpTextEditOutliner)
+        // no Outliner, no TextEdit
+        return;
+
+    if (!mxWeakTextEditObj.get().is())
+        // no TextObject, no TextEdit
+        return;
+
+    // lauch an ObjectChange: This is the straightforward method
+    // to get this broadcasted. We do not risk to set the model
+    // unwantedly to changed, we had a text edit going on already.
+    // This is needed for SlideShow since it is not (yet) using the
+    // standard schema with VC/VOC/OC
+    if (isInteractiveSlideShow())
+        mxWeakTextEditObj.get()->BroadcastObjectChange();
+
+    // force repaint for objects with changed text in all views
+    // that are VC/VOC/OC based (SlideShow is not yet)
+    sdr::contact::ViewContact& rVC(mxWeakTextEditObj.get()->GetViewContact());
+
+    if (!rVC.hasMultipleViewObjectContacts())
+        // only one VOC -> this is us
+        return;
+
+    if (nullptr == mpTextEditPV)
+        // should not happen, just invalidate all visualizations
+        rVC.ActionChanged();
+    else
+        // invalidate only visualizations in different views:
+        // this is important to not cause evtl. high repaint costs
+        // in the EditView -> we avoid this by running the TextEdit
+        // on the overlay. NOTE: This is only for better performance,
+        // any repaint will just work fine and do the right thing
+        rVC.ActionChangedIfDifferentPageView(*mpTextEditPV);
 }
 
 SdrObjEditView::~SdrObjEditView()
 {
+    maTextEditUpdateTimer.Stop();
     mpTextEditWin = nullptr; // so there's no ShowCursor in SdrEndTextEdit
     assert(!IsTextEdit());
     if (IsTextEdit())
@@ -1481,6 +1556,12 @@ bool SdrObjEditView::SdrBeginTextEdit(SdrObject* pObj_, 
SdrPageView* pPV, vcl::W
             mpTextEditOutlinerView->ShowCursor();
             mpTextEditOutliner->SetStatusEventHdl(
                 LINK(this, SdrObjEditView, ImpOutlinerStatusEventHdl));
+
+            // IASS: start listening to ModelChanges of TextEdit
+            if (isInteractiveSlideShow()
+                || pTextObj->GetViewContact().hasMultipleViewObjectContacts())
+                mpTextEditOutliner->SetModifyHdl(LINK(this, SdrObjEditView, 
ImpModifyHdl));
+
             if (pTextObj->IsChainable())
             {
                 mpTextEditOutlinerView->SetEndCutPasteLinkHdl(
@@ -1564,6 +1645,9 @@ bool SdrObjEditView::SdrBeginTextEdit(SdrObject* pObj_, 
SdrPageView* pPV, vcl::W
 
 SdrEndTextEditKind SdrObjEditView::SdrEndTextEdit(bool bDontDeleteReally)
 {
+    // IASS: stop evtl. running timer immediately
+    maTextEditUpdateTimer.Stop();
+
     SdrEndTextEditKind eRet = SdrEndTextEditKind::Unchanged;
     rtl::Reference<SdrTextObj> pTEObj = mxWeakTextEditObj.get();
     vcl::Window* pTEWin = mpTextEditWin;
@@ -1682,6 +1766,9 @@ SdrEndTextEditKind SdrObjEditView::SdrEndTextEdit(bool 
bDontDeleteReally)
             pTEOutliner->SetBeginPasteOrDropHdl(Link<PasteOrDropInfos*, 
void>());
             pTEOutliner->SetEndPasteOrDropHdl(Link<PasteOrDropInfos*, void>());
 
+            // IASS: stop listening to ModelChanges of TextEdit
+            pTEOutliner->SetModifyHdl(Link<LinkParamNone*, void>());
+
             const bool bUndo = IsUndoEnabled();
             if (bUndo)
             {
diff --git a/svx/source/unodraw/unoshtxt.cxx b/svx/source/unodraw/unoshtxt.cxx
index e6b958ce4dc0..e445978d98bb 100644
--- a/svx/source/unodraw/unoshtxt.cxx
+++ b/svx/source/unodraw/unoshtxt.cxx
@@ -641,7 +641,13 @@ SvxTextForwarder* SvxTextEditSourceImpl::GetTextForwarder()
     // distinguish the cases
     // a) connected to view, maybe edit mode is active, can work directly on 
the EditOutliner
     // b) background Outliner, reflect changes into ParaOutlinerObject (this 
is exactly the old UNO code)
-    if( HasView() )
+
+    // IASS: testing for HasView() is *not* sufficient - there may be more 
views of one document
+    // open and TextEdit is only active in one of them, or - as with IASS - it 
may even be the view
+    // of the running SlideShow itself which also will have no active TextEdit 
and thus no Outliner.
+    // Thus, to identify the view which indeed does have an outliner (and is 
in TextEdit mode),
+    // also check if it has an active Outliner by using GetTextEditOutliner()
+    if( HasView() && nullptr != mpView->GetTextEditOutliner() )
     {
         if( IsEditMode() != mbForwarderIsEditMode )
         {

Reply via email to