[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-5.1' - 3 commits - include/sfx2 sc/inc sc/qa sc/source

Marco Cecchetti marco.cecchetti at collabora.com
Fri Sep 30 16:26:20 UTC 2016


 include/sfx2/lokhelper.hxx                   |   21 +++
 sc/inc/scmod.hxx                             |    2 
 sc/qa/unit/tiledrendering/tiledrendering.cxx |  111 +++++++++++++++++
 sc/source/ui/app/inputhdl.cxx                |   16 +-
 sc/source/ui/app/scmod.cxx                   |    5 
 sc/source/ui/inc/tabview.hxx                 |    3 
 sc/source/ui/inc/tabvwsh.hxx                 |    3 
 sc/source/ui/view/gridwin4.cxx               |   86 +++++++++++++
 sc/source/ui/view/tabview3.cxx               |  170 +++++++++++++++++++++++++++
 sc/source/ui/view/tabview5.cxx               |   20 +++
 sc/source/ui/view/tabvwsh4.cxx               |   22 +++
 sc/source/ui/view/tabvwsh5.cxx               |   11 +
 sc/source/ui/view/viewdata.cxx               |   48 +++++++
 13 files changed, 499 insertions(+), 19 deletions(-)

New commits:
commit feb25b3ca32b8d4077927d2e6251dc84a5830e60
Author: Marco Cecchetti <marco.cecchetti at collabora.com>
Date:   Wed Sep 28 12:20:10 2016 +0200

    Calc: implemented parallel cell text editing
    
    Change-Id: If8cc7a637cee6ba66813d55b25160fee13a2a219

diff --git a/include/sfx2/lokhelper.hxx b/include/sfx2/lokhelper.hxx
index 6e25044..0c118fb 100644
--- a/include/sfx2/lokhelper.hxx
+++ b/include/sfx2/lokhelper.hxx
@@ -11,8 +11,10 @@
 #define INCLUDED_SFX2_LOKHELPER_HXX
 
 #include <sfx2/dllapi.h>
+#include <sfx2/viewsh.hxx>
 #include <cstddef>
 #include <rtl/string.hxx>
+#include <comphelper/lok.hxx>
 
 class SfxViewShell;
 
@@ -31,7 +33,9 @@ public:
     static std::size_t getViewsCount();
     /// Get viewIds of all existing views.
     static bool getViewIds(int* pArray, size_t nSize);
-
+    /// Iterate over any view shell, except pThisViewShell, passing it to the f function.
+    template<typename ViewShellType, typename FunctionType>
+    static void forEachOtherView(ViewShellType* pThisViewShell, FunctionType f);
     /// Invoke the LOK callback of all views except pThisView, with a payload of rKey-rPayload.
     static void notifyOtherViews(SfxViewShell* pThisView, int nType, const OString& rKey, const OString& rPayload);
     /// Same as notifyOtherViews(), but works on a selected "other" view, not on all of them.
@@ -40,6 +44,21 @@ public:
     static void notifyInvalidation(SfxViewShell* pThisView, const OString& rPayload);
 };
 
+template<typename ViewShellType, typename FunctionType>
+void SfxLokHelper::forEachOtherView(ViewShellType* pThisViewShell, FunctionType f)
+{
+    SfxViewShell* pViewShell = SfxViewShell::GetFirst();
+    while (pViewShell)
+    {
+        ViewShellType* pOtherViewShell = dynamic_cast<ViewShellType*>(pViewShell);
+        if (pOtherViewShell != nullptr && pOtherViewShell != pThisViewShell)
+        {
+            f(pOtherViewShell);
+        }
+        pViewShell = SfxViewShell::GetNext(*pViewShell);
+    }
+}
+
 #endif
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/qa/unit/tiledrendering/tiledrendering.cxx b/sc/qa/unit/tiledrendering/tiledrendering.cxx
index 6f4fd48..3479c29 100644
--- a/sc/qa/unit/tiledrendering/tiledrendering.cxx
+++ b/sc/qa/unit/tiledrendering/tiledrendering.cxx
@@ -63,6 +63,7 @@ public:
     void testUndoShells();
     void testCreateViewGraphicSelection();
     void testTextEditViews();
+    void testTextEditViewInvalidations();
     void testGraphicInvalidate();
 
     CPPUNIT_TEST_SUITE(ScTiledRenderingTest);
@@ -78,6 +79,7 @@ public:
     CPPUNIT_TEST(testUndoShells);
     CPPUNIT_TEST(testCreateViewGraphicSelection);
     CPPUNIT_TEST(testTextEditViews);
+    CPPUNIT_TEST(testTextEditViewInvalidations);
     CPPUNIT_TEST(testGraphicInvalidate);
     CPPUNIT_TEST_SUITE_END();
 
@@ -364,6 +366,7 @@ public:
     bool m_bGraphicSelection;
     bool m_bGraphicViewSelection;
     bool m_bFullInvalidateTiles;
+    bool m_bInvalidateTiles;
     bool m_bViewLock;
 
     ViewCallback()
@@ -372,6 +375,7 @@ public:
           m_bTextViewSelectionInvalidated(false),
           m_bGraphicViewSelection(false),
           m_bFullInvalidateTiles(false),
+          m_bInvalidateTiles(false),
           m_bViewLock(false)
     {
     }
@@ -425,6 +429,10 @@ public:
             {
                 m_bFullInvalidateTiles = true;
             }
+            else
+            {
+                m_bInvalidateTiles = true;
+            }
         }
         }
     }
@@ -669,6 +677,56 @@ void ScTiledRenderingTest::testTextEditViews()
     comphelper::LibreOfficeKit::setActive(false);
 }
 
+void ScTiledRenderingTest::testTextEditViewInvalidations()
+{
+    comphelper::LibreOfficeKit::setActive();
+
+    ScModelObj* pModelObj = createDoc("small.ods");
+    CPPUNIT_ASSERT(pModelObj);
+    ScViewData* pViewData = ScDocShell::GetViewData();
+    CPPUNIT_ASSERT(pViewData);
+
+    // view #1
+    ViewCallback aView1;
+    int nView1 = SfxLokHelper::getView();
+    SfxViewShell::Current()->registerLibreOfficeKitViewCallback(&ViewCallback::callback, &aView1);
+    CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData));
+
+    // view #2
+    SfxLokHelper::createView();
+    ViewCallback aView2;
+    pModelObj->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
+    SfxViewShell::Current()->registerLibreOfficeKitViewCallback(&ViewCallback::callback, &aView2);
+
+    // text edit a cell in view #1
+    SfxLokHelper::setView(nView1);
+    aView2.m_bInvalidateTiles = false;
+    pModelObj->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'x', 0);
+    pModelObj->postKeyEvent(LOK_KEYEVENT_KEYUP, 'x', 0);
+    Scheduler::ProcessEventsToIdle();
+    CPPUNIT_ASSERT(lcl_hasEditView(*pViewData));
+    CPPUNIT_ASSERT(aView2.m_bInvalidateTiles);
+
+    // view #3
+    SfxLokHelper::createView();
+    ViewCallback aView3;
+    pModelObj->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
+    SfxViewShell::Current()->registerLibreOfficeKitViewCallback(&ViewCallback::callback, &aView3);
+
+    // text edit a cell in view #1
+    SfxLokHelper::setView(nView1);
+    aView3.m_bInvalidateTiles = false;
+    pModelObj->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'y', 0);
+    pModelObj->postKeyEvent(LOK_KEYEVENT_KEYUP, 'y', 0);
+    Scheduler::ProcessEventsToIdle();
+    CPPUNIT_ASSERT(aView3.m_bInvalidateTiles);
+
+    mxComponent->dispose();
+    mxComponent.clear();
+
+    comphelper::LibreOfficeKit::setActive(false);
+}
+
 void ScTiledRenderingTest::testCreateViewGraphicSelection()
 {
     // Load a document
diff --git a/sc/source/ui/inc/tabview.hxx b/sc/source/ui/inc/tabview.hxx
index 0e21f09..d2cc7fc 100644
--- a/sc/source/ui/inc/tabview.hxx
+++ b/sc/source/ui/inc/tabview.hxx
@@ -447,6 +447,9 @@ public:
 
     void            InvalidateAttribs();
 
+    void            OnLibreOfficeKitTabChanged();
+    void            AddEditViewToOtherView(SfxViewShell* pViewShell, ScSplitPos eWhich);
+    void            RemoveEditViewFromOtherView(SfxViewShell* pViewShell, ScSplitPos eWhich);
     void            MakeEditView( ScEditEngineDefaulter* pEngine, SCCOL nCol, SCROW nRow );
     void            KillEditView( bool bNoPaint );
     void            UpdateEditView();
diff --git a/sc/source/ui/view/gridwin4.cxx b/sc/source/ui/view/gridwin4.cxx
index 1ff4dc4..1adf3f0 100644
--- a/sc/source/ui/view/gridwin4.cxx
+++ b/sc/source/ui/view/gridwin4.cxx
@@ -967,6 +967,92 @@ void ScGridWindow::DrawContent(OutputDevice &rDevice, const ScTableInfo& rTableI
             pCrsr->Show();
     }
 
+
+    if (comphelper::LibreOfficeKit::isActive())
+    {
+        ScTabViewShell* pThisViewShell = pViewData->GetViewShell();
+        SfxViewShell* pViewShell = SfxViewShell::GetFirst();
+
+        while (pViewShell)
+        {
+            if (pViewShell != pThisViewShell)
+            {
+                ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
+                if (pTabViewShell)
+                {
+                    ScViewData& rOtherViewData = pTabViewShell->GetViewData();
+                    ScSplitPos eOtherWhich = rOtherViewData.GetEditActivePart();
+
+                    bool bOtherEditMode = rOtherViewData.HasEditView(eOtherWhich);
+                    SCCOL nCol1 = rOtherViewData.GetEditStartCol();
+                    SCROW nRow1 = rOtherViewData.GetEditStartRow();
+                    SCCOL nCol2 = rOtherViewData.GetEditEndCol();
+                    SCROW nRow2 = rOtherViewData.GetEditEndRow();
+                    bOtherEditMode = bOtherEditMode
+                            && ( nCol2 >= nX1 && nCol1 <= nX2 && nRow2 >= nY1 && nRow1 <= nY2 );
+                    if (bOtherEditMode && rOtherViewData.GetRefTabNo() == nTab)
+                    {
+                        EditView* pOtherEditView = rOtherViewData.GetEditView(eOtherWhich);
+                        Point aOtherScrPos = rOtherViewData.GetScrPos( nX1, nY1, eOtherWhich );
+                        if ( bLayoutRTL )
+                        {
+                            long nEndPixel = pViewData->GetScrPos( nX2+1, maVisibleRange.mnRow1, eWhich ).X();
+                            aOtherScrPos.X() = nEndPixel + 1;
+                        }
+
+                        long nScreenX = aOutputData.nScrX;
+                        long nScreenY = aOutputData.nScrY;
+                        long nScreenW = aOutputData.GetScrW();
+                        long nScreenH = aOutputData.GetScrH();
+
+                        rDevice.SetLineColor();
+                        rDevice.SetFillColor(pEditView->GetBackgroundColor());
+                        Point aStart = rOtherViewData.GetScrPos( nCol1, nRow1, eOtherWhich );
+                        Point aEnd = rOtherViewData.GetScrPos( nCol2+1, nRow2+1, eOtherWhich );
+
+                        // don't overwrite grid
+                        long nLayoutSign = bLayoutRTL ? -1 : 1;
+                        aEnd.X() -= 2 * nLayoutSign;
+                        aEnd.Y() -= 2;
+
+                        Rectangle aBackground(aStart, aEnd);
+
+                        aBackground += Point(nScreenX, nScreenY);
+                        rDevice.SetMapMode(aDrawMode);
+
+
+                        // paint the background
+                        rDevice.DrawRect(rDevice.PixelToLogic(aBackground));
+
+                        if (bIsTiledRendering)
+                        {
+                            auto aOrigin = aOriginalMode.GetOrigin();
+                            aOrigin.setX(aOrigin.getX() / TWIPS_PER_PIXEL + nScrX);
+                            aOrigin.setY(aOrigin.getY() / TWIPS_PER_PIXEL + nScrY);
+                            static const double twipFactor = 15 * 1.76388889; // 26.45833335
+                            aOrigin = Point(aOrigin.getX() * twipFactor,
+                                            aOrigin.getY() * twipFactor);
+                            MapMode aNew = rDevice.GetMapMode();
+                            aNew.SetOrigin(aOrigin);
+                            rDevice.SetMapMode(aNew);
+                        }
+
+                        pOtherEditView->Paint(rDevice.PixelToLogic(Rectangle(Point(nScreenX, nScreenY), Size(nScreenW, nScreenH))), &rDevice);
+                        rDevice.SetMapMode(MAP_PIXEL);
+                    }
+
+                 }
+            }
+
+            pViewShell = SfxViewShell::GetNext(*pViewShell);
+        }
+
+    }
+
+
+
+
+
     if (pViewData->HasEditView(eWhich))
     {
         // flush OverlayManager before changing the MapMode
diff --git a/sc/source/ui/view/tabview3.cxx b/sc/source/ui/view/tabview3.cxx
index 3057200..a8b2102 100644
--- a/sc/source/ui/view/tabview3.cxx
+++ b/sc/source/ui/view/tabview3.cxx
@@ -26,6 +26,7 @@
 #include <svx/fmshell.hxx>
 #include <svx/svdoole2.hxx>
 #include <sfx2/bindings.hxx>
+#include <sfx2/lokhelper.hxx>
 #include <sfx2/viewfrm.hxx>
 #include <vcl/cursor.hxx>
 
@@ -1862,6 +1863,175 @@ void ScTabView::SetTabNo( SCTAB nTab, bool bNew, bool bExtendSelection, bool bSa
                 pRefDlg->ViewShellChanged();
             }
         }
+
+        OnLibreOfficeKitTabChanged();
+    }
+}
+
+class ExtraEditViewManager
+{
+public:
+    ExtraEditViewManager(ScTabViewShell* pThisViewShell, VclPtr<ScGridWindow>* pGridWin)
+        : mpThisViewShell(pThisViewShell)
+        , mpGridWin(pGridWin)
+        , mpOtherEditView(nullptr)
+        , mpOtherEngine(nullptr)
+        , mpEditViews(nullptr)
+        , maSameEditViewChecker()
+    {}
+
+    void Add(SfxViewShell* pViewShell, ScSplitPos eWhich)
+    {
+        Apply(pViewShell, eWhich, &ExtraEditViewManager::Adder);
+    }
+
+    void Remove(SfxViewShell* pViewShell, ScSplitPos eWhich)
+    {
+        Apply(pViewShell, eWhich, &ExtraEditViewManager::Remover);
+    }
+
+private:
+    class SameEditViewChecker
+    {
+    public:
+        SameEditViewChecker()
+            : mpOtherEditView(nullptr)
+            , mpWindow(nullptr)
+        {}
+        void SetEditView(EditView* pOtherEditView) { mpOtherEditView = pOtherEditView; }
+        void SetWindow(ScGridWindow* pWindow) { mpWindow = pWindow; }
+        bool operator() (EditView* pView)
+        {
+            return ( pView != nullptr
+                  && pView->GetWindow() == mpWindow
+                  && pView->GetEditEngine() == mpOtherEditView->GetEditEngine()
+                  && pView->GetOutputArea() == mpOtherEditView->GetOutputArea()
+                  && pView->GetVisArea() == mpOtherEditView->GetVisArea() );
+        }
+
+    private:
+        EditView* mpOtherEditView;
+        ScGridWindow* mpWindow;
+    };
+
+private:
+    typedef void (ExtraEditViewManager::* FuncType)(ScGridWindow* );
+
+    void Apply(SfxViewShell* pViewShell, ScSplitPos eWhich, FuncType fHandler)
+    {
+        ScTabViewShell* pOtherViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
+        if (pOtherViewShell != nullptr && pOtherViewShell != mpThisViewShell)
+        {
+            mpOtherEditView = pOtherViewShell->GetViewData().GetEditView(eWhich);
+            if (mpOtherEditView != nullptr)
+            {
+                mpOtherEngine = mpOtherEditView->GetEditEngine();
+                if (mpOtherEngine != nullptr)
+                {
+                    mpEditViews = &(mpOtherEngine->GetEditViews());
+                    maSameEditViewChecker.SetEditView(mpOtherEditView);
+                    for (int i = 0; i < 4; ++i)
+                    {
+                        (this->*fHandler)(mpGridWin[i]);
+                    }
+                }
+            }
+        }
+    }
+
+    void Adder(ScGridWindow* pWin)
+    {
+        if (pWin != nullptr)
+        {
+            maSameEditViewChecker.SetWindow(pWin);
+            auto found = std::find_if(mpEditViews->begin(), mpEditViews->end(), maSameEditViewChecker);
+            if (found == mpEditViews->end())
+            {
+                EditView* pThisEditView = new EditView( mpOtherEngine, pWin );
+                if (pThisEditView != nullptr)
+                {
+                    pThisEditView->SetOutputArea(mpOtherEditView->GetOutputArea());
+                    pThisEditView->SetVisArea(mpOtherEditView->GetVisArea());
+                    mpOtherEngine->InsertView(pThisEditView);
+                }
+            }
+        }
+    }
+
+    void Remover(ScGridWindow* pWin)
+    {
+        if (pWin != nullptr)
+        {
+            maSameEditViewChecker.SetWindow(pWin);
+            auto found = std::find_if(mpEditViews->begin(), mpEditViews->end(), maSameEditViewChecker);
+            if (found != mpEditViews->end())
+            {
+                EditView* pView = *found;
+                if (pView)
+                {
+                    mpOtherEngine->RemoveView(pView);
+                    delete pView;
+                    pView = nullptr;
+                }
+            }
+        }
+    }
+
+private:
+    ScTabViewShell* mpThisViewShell;
+    VclPtr<ScGridWindow>* mpGridWin;
+    EditView* mpOtherEditView;
+    EditEngine* mpOtherEngine;
+    EditEngine::ViewsType* mpEditViews;
+    SameEditViewChecker maSameEditViewChecker;
+};
+
+void ScTabView::AddEditViewToOtherView(SfxViewShell* pViewShell, ScSplitPos eWhich)
+{
+    ExtraEditViewManager aExtraEditViewManager(aViewData.GetViewShell(), pGridWin);
+    aExtraEditViewManager.Add(pViewShell, eWhich);
+}
+
+void ScTabView::RemoveEditViewFromOtherView(SfxViewShell* pViewShell, ScSplitPos eWhich)
+{
+    ExtraEditViewManager aExtraEditViewManager(aViewData.GetViewShell(), pGridWin);
+    aExtraEditViewManager.Remove(pViewShell, eWhich);
+}
+
+void ScTabView::OnLibreOfficeKitTabChanged()
+{
+    if (comphelper::LibreOfficeKit::isActive())
+    {
+        ScTabViewShell* pThisViewShell = aViewData.GetViewShell();
+        SCTAB nThisTabNo = pThisViewShell->GetViewData().GetTabNo();
+        auto lTabSwitch =
+                [pThisViewShell, nThisTabNo] (ScTabViewShell* pOtherViewShell)
+                {
+                    ScViewData& rOtherViewData = pOtherViewShell->GetViewData();
+                    SCTAB nOtherTabNo = rOtherViewData.GetTabNo();
+                    if (nThisTabNo == nOtherTabNo)
+                    {
+                        for (int i = 0; i < 4; ++i)
+                        {
+                            if (rOtherViewData.HasEditView( (ScSplitPos)(i)))
+                            {
+                                pThisViewShell->AddEditViewToOtherView(pOtherViewShell, (ScSplitPos)(i));
+                            }
+                        }
+                    }
+                    else
+                    {
+                        for (int i = 0; i < 4; ++i)
+                        {
+                            if (rOtherViewData.HasEditView( (ScSplitPos)(i)))
+                            {
+                                pThisViewShell->RemoveEditViewFromOtherView(pOtherViewShell, (ScSplitPos)(i));
+                            }
+                        }
+                    }
+                };
+
+        SfxLokHelper::forEachOtherView(pThisViewShell, lTabSwitch);
     }
 }
 
diff --git a/sc/source/ui/view/tabview5.cxx b/sc/source/ui/view/tabview5.cxx
index d19ec5a..710b6a7 100644
--- a/sc/source/ui/view/tabview5.cxx
+++ b/sc/source/ui/view/tabview5.cxx
@@ -25,6 +25,7 @@
 #include <svx/svdoutl.hxx>
 #include <sfx2/bindings.hxx>
 #include <sfx2/dispatch.hxx>
+#include <sfx2/lokhelper.hxx>
 #include <sfx2/objsh.hxx>
 
 #include "tabview.hxx"
@@ -55,7 +56,6 @@
 #include <officecfg/Office/Calc.hxx>
 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
 
-
 using namespace com::sun::star;
 
 void ScTabView::Init()
@@ -160,6 +160,24 @@ ScTabView::~ScTabView()
     DELETEZ(pDrawOld);
     DELETEZ(pDrawActual);
 
+    if (comphelper::LibreOfficeKit::isActive())
+    {
+        ScTabViewShell* pThisViewShell = GetViewData().GetViewShell();
+
+        auto lRemoveEditView =
+                [pThisViewShell] (ScTabViewShell* pOtherViewShell)
+                {
+                    ScViewData& rOtherViewData = pOtherViewShell->GetViewData();
+                    for (int k = 0; k < 4; ++k)
+                    {
+                        if (rOtherViewData.HasEditView((ScSplitPos)(k)))
+                            pThisViewShell->RemoveEditViewFromOtherView(pOtherViewShell, (ScSplitPos)(k));
+                    }
+                };
+
+        SfxLokHelper::forEachOtherView(pThisViewShell, lRemoveEditView);
+    }
+
     aViewData.KillEditView();           // solange GridWin's noch existieren
 
     if (pDrawView)
diff --git a/sc/source/ui/view/viewdata.cxx b/sc/source/ui/view/viewdata.cxx
index a14e50e..058b992 100644
--- a/sc/source/ui/view/viewdata.cxx
+++ b/sc/source/ui/view/viewdata.cxx
@@ -20,6 +20,7 @@
 #include "scitems.hxx"
 #include <editeng/eeitem.hxx>
 
+#include <sfx2/lokhelper.hxx>
 #include <sfx2/viewfrm.hxx>
 #include <editeng/adjustitem.hxx>
 #include <svx/algitem.hxx>
@@ -77,6 +78,22 @@ using namespace com::sun::star;
 static bool bMoveArea = false;                  // Member?
 sal_uInt16 nEditAdjust = SVX_ADJUST_LEFT;       // Member!
 
+namespace {
+
+void lcl_LOKRemoveEditView(ScTabViewShell* pTabViewShell, ScSplitPos eWhich)
+{
+    if (comphelper::LibreOfficeKit::isActive())
+    {
+        auto lRemoveEditView =
+                [pTabViewShell, eWhich] (ScTabViewShell* pOtherViewShell)
+                { pOtherViewShell->RemoveEditViewFromOtherView(pTabViewShell, eWhich); };
+
+        SfxLokHelper::forEachOtherView(pTabViewShell, lRemoveEditView);
+    }
+}
+
+} // anonymous namespace
+
 ScViewDataTable::ScViewDataTable() :
                 eZoomType( SvxZoomType::PERCENT ),
                 aZoomX( 1,1 ),
@@ -932,12 +949,18 @@ void ScViewData::SetEditEngine( ScSplitPos eWhich,
     {
         //  if the view is already there don't call anything that changes the cursor position
         if (bEditActive[eWhich])
+        {
             bWasThere = true;
+        }
         else
+        {
+            lcl_LOKRemoveEditView(GetViewShell(), eWhich);
             pEditView[eWhich]->SetEditEngine(pNewEngine);
+        }
 
         if (pEditView[eWhich]->GetWindow() != pWin)
         {
+            lcl_LOKRemoveEditView(GetViewShell(), eWhich);
             pEditView[eWhich]->SetWindow(pWin);
             OSL_FAIL("EditView Window has changed");
         }
@@ -1107,6 +1130,23 @@ void ScViewData::SetEditEngine( ScSplitPos eWhich,
 
     pEditView[eWhich]->Invalidate();            //  needed?
     //  needed, wenn position changed
+
+    if (comphelper::LibreOfficeKit::isActive())
+    {
+        ScTabViewShell* pThisViewShell = GetViewShell();
+        SCTAB nThisTabNo = GetTabNo();
+        auto lAddEditView =
+                [pThisViewShell, nThisTabNo, eWhich] (ScTabViewShell* pOtherViewShell)
+                {
+                    ScViewData& rOtherViewData = pOtherViewShell->GetViewData();
+                    SCTAB nOtherTabNo = rOtherViewData.GetTabNo();
+                    if (nThisTabNo == nOtherTabNo)
+                        pOtherViewShell->AddEditViewToOtherView(pThisViewShell, eWhich);
+                };
+
+        SfxLokHelper::forEachOtherView(pThisViewShell, lAddEditView);
+    }
+
 }
 
 IMPL_LINK_TYPED( ScViewData, EditEngineHdl, EditStatus&, rStatus, void )
@@ -1396,6 +1436,7 @@ void ScViewData::ResetEditView()
         {
             if (bEditActive[i])
             {
+                lcl_LOKRemoveEditView(GetViewShell(), (ScSplitPos)(i));
                 pEngine = pEditView[i]->GetEditEngine();
                 pEngine->RemoveView(pEditView[i]);
                 pEditView[i]->SetOutputArea( Rectangle() );
commit 34f4926bdeaed961a845890029d840523cb9c588
Author: Marco Cecchetti <marco.cecchetti at collabora.com>
Date:   Mon Sep 19 17:21:39 2016 +0200

    Calc: edit engine could be accessed after being destroyed
    
    ScTabView <---------------- ScTabViewShell
    +ScViewData                 +ScInputHandler
       +EditView[4]                +EditEngine
                                    +ImpEditEngine
                                       +vector<pointer<EditView>>
    
    On tab view shell destruction:
    ~ScTabViewShell -> ~ScTabView -> ScViewData::KillEditView ->
    EditEngine::RemoveView
    
    but it occurs after the following:
    ~ScTabViewShell -> ~ScInputHandler -> ~EditEngine
    
    since data members are destroyed before ancestor classes.
    
    Change-Id: Ida56b8009c0d8a3cd23952259d78318e96ae5124

diff --git a/sc/source/ui/app/inputhdl.cxx b/sc/source/ui/app/inputhdl.cxx
index 2ea037f..9978071 100644
--- a/sc/source/ui/app/inputhdl.cxx
+++ b/sc/source/ui/app/inputhdl.cxx
@@ -563,14 +563,14 @@ ScInputHandler::~ScInputHandler()
     if ( pInputWin && pInputWin->GetInputHandler() == this )
         pInputWin->SetInputHandler( nullptr );
 
-    delete pRangeFindList;
-    delete pEditDefaults;
-    delete pEngine;
-    delete pLastState;
-    delete pDelayTimer;
-    delete pColumnData;
-    delete pFormulaData;
-    delete pFormulaDataPara;
+    delete pRangeFindList;     pRangeFindList = nullptr;
+    delete pEditDefaults;      pEditDefaults = nullptr;
+    delete pEngine;            pEngine = nullptr;
+    delete pLastState;         pLastState = nullptr;
+    delete pDelayTimer;        pDelayTimer = nullptr;
+    delete pColumnData;        pColumnData = nullptr;
+    delete pFormulaData;       pFormulaData = nullptr;
+    delete pFormulaDataPara;   pFormulaDataPara = nullptr;
 }
 
 void ScInputHandler::SetRefScale( const Fraction& rX, const Fraction& rY )
diff --git a/sc/source/ui/view/viewdata.cxx b/sc/source/ui/view/viewdata.cxx
index 167d125..a14e50e 100644
--- a/sc/source/ui/view/viewdata.cxx
+++ b/sc/source/ui/view/viewdata.cxx
@@ -1409,11 +1409,16 @@ void ScViewData::ResetEditView()
 
 void ScViewData::KillEditView()
 {
+    EditEngine* pEngine = nullptr;
     for (sal_uInt16 i=0; i<4; i++)
         if (pEditView[i])
         {
             if (bEditActive[i])
-                pEditView[i]->GetEditEngine()->RemoveView(pEditView[i]);
+            {
+                pEngine = pEditView[i]->GetEditEngine();
+                if (pEngine)
+                    pEngine->RemoveView(pEditView[i]);
+            }
             delete pEditView[i];
             pEditView[i] = nullptr;
         }
commit c90267d86e3bcccf178cb423d6b81fa9f34cca07
Author: Marco Cecchetti <marco.cecchetti at collabora.com>
Date:   Fri Sep 16 12:36:06 2016 +0200

    LOK - when a view is enabled, the existing edit views are killed
    
    A view is notified about killing its own edit view, if any, in 4
    cases:
    
    - before being deactivated
    - soon after being activated
    - when a 'cursor position changed' event occurs in any view
    - when a 'selection changed' event occurs in any view
    
    Now these notifications are skipped when LOK is active.
    
    Change-Id: I94020987a35b1450ec41e2fa5fcce8cfa7e92130

diff --git a/sc/inc/scmod.hxx b/sc/inc/scmod.hxx
index ec93563..d142bcd 100644
--- a/sc/inc/scmod.hxx
+++ b/sc/inc/scmod.hxx
@@ -215,7 +215,7 @@ public:
     ScInputHandler*     GetRefInputHdl() { return pRefInputHandler;}
 
     void                ViewShellGone(ScTabViewShell* pViewSh);
-    void                ViewShellChanged();
+    void                ViewShellChanged(bool bStopEditing = true);
     // communication with function-autopilot
     void                InputGetSelection( sal_Int32& rStart, sal_Int32& rEnd );
     void                InputSetSelection( sal_Int32 nStart, sal_Int32 nEnd );
diff --git a/sc/qa/unit/tiledrendering/tiledrendering.cxx b/sc/qa/unit/tiledrendering/tiledrendering.cxx
index 25af056..6f4fd48 100644
--- a/sc/qa/unit/tiledrendering/tiledrendering.cxx
+++ b/sc/qa/unit/tiledrendering/tiledrendering.cxx
@@ -62,6 +62,7 @@ public:
     void testColRowResize();
     void testUndoShells();
     void testCreateViewGraphicSelection();
+    void testTextEditViews();
     void testGraphicInvalidate();
 
     CPPUNIT_TEST_SUITE(ScTiledRenderingTest);
@@ -76,6 +77,7 @@ public:
     CPPUNIT_TEST(testColRowResize);
     CPPUNIT_TEST(testUndoShells);
     CPPUNIT_TEST(testCreateViewGraphicSelection);
+    CPPUNIT_TEST(testTextEditViews);
     CPPUNIT_TEST(testGraphicInvalidate);
     CPPUNIT_TEST_SUITE_END();
 
@@ -616,6 +618,57 @@ void ScTiledRenderingTest::testUndoShells()
     comphelper::LibreOfficeKit::setActive(false);
 }
 
+bool lcl_hasEditView(ScViewData& rViewData)
+{
+    bool bResult = false;
+    for (unsigned int i=0; i<4; i++)
+    {
+        bResult = rViewData.HasEditView( (ScSplitPos) i );
+        if (bResult) break;
+    }
+    return bResult;
+}
+
+void ScTiledRenderingTest::testTextEditViews()
+{
+    comphelper::LibreOfficeKit::setActive();
+
+    ScModelObj* pModelObj = createDoc("small.ods");
+    CPPUNIT_ASSERT(pModelObj);
+    ScViewData* pViewData = ScDocShell::GetViewData();
+    CPPUNIT_ASSERT(pViewData);
+
+    // view #1
+    ViewCallback aView1;
+    SfxViewShell::Current()->registerLibreOfficeKitViewCallback(&ViewCallback::callback, &aView1);
+    CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData));
+
+    // text edit a cell in view #1
+    pModelObj->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'x', 0);
+    pModelObj->postKeyEvent(LOK_KEYEVENT_KEYUP, 'x', 0);
+    Scheduler::ProcessEventsToIdle();
+    CPPUNIT_ASSERT(lcl_hasEditView(*pViewData));
+
+    // view #2
+    SfxLokHelper::createView();
+    ViewCallback aView2;
+    pModelObj->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
+    SfxViewShell::Current()->registerLibreOfficeKitViewCallback(&ViewCallback::callback, &aView2);
+
+    // move cell cursor i view #2
+    pModelObj->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::DOWN);
+    pModelObj->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::DOWN);
+    Scheduler::ProcessEventsToIdle();
+
+    // check that text edit view in view #1 has not be killed
+    CPPUNIT_ASSERT(lcl_hasEditView(*pViewData));
+
+    mxComponent->dispose();
+    mxComponent.clear();
+
+    comphelper::LibreOfficeKit::setActive(false);
+}
+
 void ScTiledRenderingTest::testCreateViewGraphicSelection()
 {
     // Load a document
diff --git a/sc/source/ui/app/scmod.cxx b/sc/source/ui/app/scmod.cxx
index 5fc5258..bc68854 100644
--- a/sc/source/ui/app/scmod.cxx
+++ b/sc/source/ui/app/scmod.cxx
@@ -20,6 +20,7 @@
 #include <config_features.h>
 
 #include <com/sun/star/ui/dialogs/XSLTFilterDialog.hpp>
+#include <comphelper/lok.hxx>
 #include <comphelper/processfactory.hxx>
 
 #include "scitems.hxx"
@@ -1386,12 +1387,12 @@ ScInputHandler* ScModule::GetInputHdl( ScTabViewShell* pViewSh, bool bUseRef )
     return pHdl;
 }
 
-void ScModule::ViewShellChanged()
+void ScModule::ViewShellChanged(bool bStopEditing /*=true*/)
 {
     ScInputHandler* pHdl   = GetInputHdl();
     ScTabViewShell* pShell = ScTabViewShell::GetActiveViewShell();
     if ( pShell && pHdl )
-        pShell->UpdateInputHandler();
+        pShell->UpdateInputHandler(false, bStopEditing);
 }
 
 void ScModule::SetInputMode( ScInputMode eMode, const OUString* pInitText )
diff --git a/sc/source/ui/inc/tabvwsh.hxx b/sc/source/ui/inc/tabvwsh.hxx
index cd0f3e0..7e3641f 100644
--- a/sc/source/ui/inc/tabvwsh.hxx
+++ b/sc/source/ui/inc/tabvwsh.hxx
@@ -155,6 +155,9 @@ private:
     bool                    bChartAreaValid; // if chart is drawn
     bool                    bForceFocusOnCurCell; // #i123629#
 
+    bool                    bInPrepareClose;
+    bool                    bInDispose;
+
     ScRangeListRef          aChartSource;
     Rectangle               aChartPos;
     SCTAB                   nChartDestTab;
diff --git a/sc/source/ui/view/tabvwsh4.cxx b/sc/source/ui/view/tabvwsh4.cxx
index e5b86c7..a57e952 100644
--- a/sc/source/ui/view/tabvwsh4.cxx
+++ b/sc/source/ui/view/tabvwsh4.cxx
@@ -99,11 +99,20 @@
 #include <com/sun/star/chart2/XChartType.hpp>
 #include <sfx2/lokhelper.hxx>
 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <comphelper/lok.hxx>
 
 extern SfxViewShell* pScActiveViewShell;            // global.cxx
 
 using namespace com::sun::star;
 
+struct BoolLock
+{
+    bool& mflag;
+    explicit BoolLock( bool& flag ) : mflag(flag)
+    { mflag = true; }
+    ~BoolLock() { mflag = false; }
+};
+
 void ScTabViewShell::Activate(bool bMDI)
 {
     SfxViewShell::Activate(bMDI);
@@ -114,7 +123,7 @@ void ScTabViewShell::Activate(bool bMDI)
     {
         // for input row (ClearCache)
         ScModule* pScMod = SC_MOD();
-        pScMod->ViewShellChanged();
+        pScMod->ViewShellChanged(/*bStopEditing=*/ !comphelper::LibreOfficeKit::isActive());
 
         ActivateView( true, bFirstActivate );
 
@@ -154,7 +163,7 @@ void ScTabViewShell::Activate(bool bMDI)
             }
         }
 
-        UpdateInputHandler( true );
+        UpdateInputHandler( /*bForce=*/ true, /*bStopEditing=*/ !comphelper::LibreOfficeKit::isActive() );
 
         if ( bFirstActivate )
         {
@@ -237,7 +246,7 @@ void ScTabViewShell::Deactivate(bool bMDI)
     bIsActive = false;
     ScInputHandler* pHdl = SC_MOD()->GetInputHdl(this);
 
-    if( bMDI )
+    if( bMDI && !comphelper::LibreOfficeKit::isActive())
     {
         //  during shell deactivation, shells must not be switched, or the loop
         //  through the shell stack (in SfxDispatcher::DoDeactivate_Impl) will not work
@@ -275,12 +284,15 @@ void ScTabViewShell::SetActive()
 
 bool ScTabViewShell::PrepareClose(bool bUI)
 {
+    BoolLock aBoolLock(bInPrepareClose);
     // Call EnterHandler even in formula mode here,
     // so a formula change in an embedded object isn't lost
     // (ScDocShell::PrepareClose isn't called then).
     ScInputHandler* pHdl = SC_MOD()->GetInputHdl( this );
     if ( pHdl && pHdl->IsInputMode() )
+    {
         pHdl->EnterHandler();
+    }
 
     // draw text edit mode must be closed
     FuPoor* pPoor = GetDrawFuncPtr();
@@ -1670,6 +1682,8 @@ ScTabViewShell::ScTabViewShell( SfxViewFrame* pViewFrame,
     bReadOnly(false),
     bChartAreaValid(false),
     bForceFocusOnCurCell(false),
+    bInPrepareClose(false),
+    bInDispose(false),
     nCurRefDlgId(0),
     pAccessibilityBroadcaster(nullptr),
     mbInSwitch(false)
@@ -1719,6 +1733,8 @@ ScTabViewShell::ScTabViewShell( SfxViewFrame* pViewFrame,
 
 ScTabViewShell::~ScTabViewShell()
 {
+    bInDispose = true;
+
     // Notify other LOK views that we are going away.
     SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_VIEW_CURSOR_VISIBLE, "visible", "false");
     SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", "");
diff --git a/sc/source/ui/view/tabvwsh5.cxx b/sc/source/ui/view/tabvwsh5.cxx
index 674dc65..943afe5 100644
--- a/sc/source/ui/view/tabvwsh5.cxx
+++ b/sc/source/ui/view/tabvwsh5.cxx
@@ -18,6 +18,7 @@
  */
 
 #include "scitems.hxx"
+#include <comphelper/lok.hxx>
 #include <svl/smplhint.hxx>
 #include <svl/zforlist.hxx>
 #include <svx/numfmtsh.hxx>
@@ -67,8 +68,14 @@ void ScTabViewShell::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
 
             case FID_KILLEDITVIEW:
             case FID_KILLEDITVIEW_NOPAINT:
-                StopEditShell();
-                KillEditView( nSlot == FID_KILLEDITVIEW_NOPAINT );
+                if (!comphelper::LibreOfficeKit::isActive()
+                    || this == SfxViewShell::Current()
+                    || bInPrepareClose
+                    || bInDispose)
+                {
+                    StopEditShell();
+                    KillEditView( nSlot == FID_KILLEDITVIEW_NOPAINT );
+                }
                 break;
 
             case SFX_HINT_DOCCHANGED:


More information about the Libreoffice-commits mailing list