[Libreoffice-commits] core.git: chart2/source editeng/source include/editeng include/sfx2 include/vcl sc/source sd/source sfx2/Library_sfx.mk sfx2/source svx/source sw/inc sw/source vcl/source

Marco Cecchetti marco.cecchetti at collabora.com
Thu Aug 3 08:59:49 UTC 2017


 chart2/source/controller/inc/ChartController.hxx         |    2 
 chart2/source/controller/inc/ChartWindow.hxx             |    9 
 chart2/source/controller/main/ChartController.cxx        |   15 
 chart2/source/controller/main/ChartController_Tools.cxx  |   35 +
 chart2/source/controller/main/ChartController_Window.cxx |    5 
 chart2/source/controller/main/ChartWindow.cxx            |  110 ++++
 editeng/source/editeng/impedit.cxx                       |   26 -
 include/editeng/outliner.hxx                             |    1 
 include/sfx2/lokcharthelper.hxx                          |   60 ++
 include/sfx2/viewsh.hxx                                  |    3 
 include/vcl/window.hxx                                   |    4 
 sc/source/ui/unoobj/docuno.cxx                           |   55 +-
 sd/source/ui/unoidl/unomodel.cxx                         |   60 ++
 sfx2/Library_sfx.mk                                      |    1 
 sfx2/source/view/ipclient.cxx                            |   56 ++
 sfx2/source/view/lokcharthelper.cxx                      |  373 +++++++++++++++
 sfx2/source/view/viewsh.cxx                              |   15 
 svx/source/svdraw/svdmrkv.cxx                            |   37 +
 svx/source/svdraw/svdpntv.cxx                            |    9 
 sw/inc/unotxdoc.hxx                                      |    2 
 sw/source/core/view/viewsh.cxx                           |   29 +
 sw/source/uibase/uno/unotxdoc.cxx                        |   89 +++
 vcl/source/window/stacking.cxx                           |    5 
 vcl/source/window/window2.cxx                            |    5 
 24 files changed, 977 insertions(+), 29 deletions(-)

New commits:
commit eba883c8a2ce045fc7bd3848d796ca10b7f4ba51
Author: Marco Cecchetti <marco.cecchetti at collabora.com>
Date:   Tue Jun 27 23:35:08 2017 +0200

    lok - add support for in place chart editing
    
    This commit add a minimal support for editing chart embedded in a
    spreadsheet or a text document or a presentation.
    Graphic objects can be moved and resized, text objects can be edited.
    
    Change-Id: I8e637dabf328a94bd6bb0e309a245302cff421d8
    Reviewed-on: https://gerrit.libreoffice.org/39342
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Marco Cecchetti <mrcekets at gmail.com>

diff --git a/chart2/source/controller/inc/ChartController.hxx b/chart2/source/controller/inc/ChartController.hxx
index 29f74ad358e2..145939f1b947 100644
--- a/chart2/source/controller/inc/ChartController.hxx
+++ b/chart2/source/controller/inc/ChartController.hxx
@@ -488,6 +488,8 @@ private:
     void executeDispatch_ToggleGridHorizontal();
     void executeDispatch_ToggleGridVertical();
 
+    void executeDispatch_LOKSetTextSelection(int nType, int nX, int nY);
+
     void sendPopupRequest(OUString const & rCID, tools::Rectangle aRectangle);
 
     void impl_ShapeControllerDispatch( const css::util::URL& rURL,
diff --git a/chart2/source/controller/inc/ChartWindow.hxx b/chart2/source/controller/inc/ChartWindow.hxx
index 95a029698e9c..db9044970247 100644
--- a/chart2/source/controller/inc/ChartWindow.hxx
+++ b/chart2/source/controller/inc/ChartWindow.hxx
@@ -58,6 +58,7 @@ public:
     virtual void Invalidate( InvalidateFlags nFlags = InvalidateFlags::NONE ) override;
     virtual void Invalidate( const tools::Rectangle& rRect, InvalidateFlags nFlags = InvalidateFlags::NONE ) override;
     virtual void Invalidate( const vcl::Region& rRegion, InvalidateFlags nFlags = InvalidateFlags::NONE ) override;
+    virtual void LogicInvalidate( const tools::Rectangle* pRectangle ) override;
 
     virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessible() override;
 
@@ -65,9 +66,17 @@ public:
 
     ChartController* GetController();
 
+    virtual bool IsChart() const override { return true; }
+    vcl::Window* GetParentEditWin();
+
+private:
+    // returns the chart bounding box in twips
+    tools::Rectangle GetBoundingBox();
+
 private:
     ChartController* m_pWindowController;
     bool m_bInPaint;
+    VclPtr<vcl::Window> m_pViewShellWindow;
     VclPtr<vcl::Window> m_pOpenGLWindow;
 
     void adjustHighContrastMode();
diff --git a/chart2/source/controller/main/ChartController.cxx b/chart2/source/controller/main/ChartController.cxx
index 2e822ceea120..e660dfb24be7 100644
--- a/chart2/source/controller/main/ChartController.cxx
+++ b/chart2/source/controller/main/ChartController.cxx
@@ -1091,7 +1091,20 @@ void SAL_CALL ChartController::dispatch(
 {
     OUString aCommand = rURL.Path;
 
-    if(aCommand == "Paste")
+    if(aCommand == "LOKSetTextSelection")
+    {
+        if (rArgs.getLength() == 3)
+        {
+            sal_Int32 nType = -1;
+            rArgs[0].Value >>= nType;
+            sal_Int32 nX = 0;
+            rArgs[1].Value >>= nX;
+            sal_Int32 nY = 0;
+            rArgs[2].Value >>= nY;
+            executeDispatch_LOKSetTextSelection(nType, nX, nY);
+        }
+    }
+    else if(aCommand == "Paste")
         this->executeDispatch_Paste();
     else if(aCommand == "Copy" )
         this->executeDispatch_Copy();
diff --git a/chart2/source/controller/main/ChartController_Tools.cxx b/chart2/source/controller/main/ChartController_Tools.cxx
index 36c6a569985e..61144839e995 100644
--- a/chart2/source/controller/main/ChartController_Tools.cxx
+++ b/chart2/source/controller/main/ChartController_Tools.cxx
@@ -52,6 +52,8 @@
 #include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
 #include <com/sun/star/chart/ErrorBarStyle.hpp>
 
+#include <editeng/editview.hxx>
+#include <editeng/outliner.hxx>
 #include <svx/ActionDescriptionProvider.hxx>
 #include <svtools/transfer.hxx>
 #include <sot/storage.hxx>
@@ -70,6 +72,8 @@
 #include <svx/unoapi.hxx>
 #include <svx/unopage.hxx>
 
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+
 #include <memory>
 
 using namespace ::com::sun::star;
@@ -923,6 +927,37 @@ void ChartController::executeDispatch_ToggleGridVertical()
     }
 }
 
+void ChartController::executeDispatch_LOKSetTextSelection(int nType, int nX, int nY)
+{
+    if (m_pDrawViewWrapper)
+    {
+        if (m_pDrawViewWrapper->IsTextEdit())
+        {
+            OutlinerView* pOutlinerView = m_pDrawViewWrapper->GetTextEditOutlinerView();
+            if (pOutlinerView)
+            {
+                EditView& rEditView = pOutlinerView->GetEditView();
+                Point aPoint(convertTwipToMm100(nX), convertTwipToMm100(nY));
+                switch (nType)
+                {
+                    case LOK_SETTEXTSELECTION_START:
+                        rEditView.SetCursorLogicPosition(aPoint, /*bPoint=*/false, /*bClearMark=*/false);
+                        break;
+                    case LOK_SETTEXTSELECTION_END:
+                        rEditView.SetCursorLogicPosition(aPoint, /*bPoint=*/true, /*bClearMark=*/false);
+                        break;
+                    case LOK_SETTEXTSELECTION_RESET:
+                        rEditView.SetCursorLogicPosition(aPoint, /*bPoint=*/true, /*bClearMark=*/true);
+                        break;
+                    default:
+                        assert(false);
+                        break;
+                }
+            }
+        }
+    }
+}
+
 void ChartController::impl_ShapeControllerDispatch( const util::URL& rURL, const Sequence< beans::PropertyValue >& rArgs )
 {
     Reference< frame::XDispatch > xDispatch( m_aDispatchContainer.getShapeController() );
diff --git a/chart2/source/controller/main/ChartController_Window.cxx b/chart2/source/controller/main/ChartController_Window.cxx
index c05c56af059d..f5d31525cc24 100644
--- a/chart2/source/controller/main/ChartController_Window.cxx
+++ b/chart2/source/controller/main/ChartController_Window.cxx
@@ -888,7 +888,10 @@ void ChartController::execute_MouseButtonUp( const MouseEvent& rMEvt )
             else
                 m_aSelection.resetPossibleSelectionAfterSingleClickWasEnsured();
         }
-        else if( isDoubleClick(rMEvt) && !bMouseUpWithoutMouseDown /*#i106966#*/ )
+        // In tiled rendering drag mode could be not yet over on the call
+        // that should handle the double-click, so better to perform this check
+        // always.
+        if( isDoubleClick(rMEvt) && !bMouseUpWithoutMouseDown /*#i106966#*/ )
         {
             Point aMousePixel = rMEvt.GetPosPixel();
             execute_DoubleClick( &aMousePixel );
diff --git a/chart2/source/controller/main/ChartWindow.cxx b/chart2/source/controller/main/ChartWindow.cxx
index b03f10164b17..717704fcda27 100644
--- a/chart2/source/controller/main/ChartWindow.cxx
+++ b/chart2/source/controller/main/ChartWindow.cxx
@@ -28,6 +28,13 @@
 #include <config_features.h>
 #include <com/sun/star/chart2/X3DChartWindowProvider.hpp>
 
+#include <sfx2/ipclient.hxx>
+#include <sfx2/viewsh.hxx>
+#include <sfx2/lokhelper.hxx>
+#include <comphelper/lok.hxx>
+
+#define TWIPS_PER_PIXEL 15
+
 using namespace ::com::sun::star;
 
 namespace
@@ -50,6 +57,7 @@ ChartWindow::ChartWindow( ChartController* pController, vcl::Window* pParent, Wi
         : Window(pParent, nStyle)
         , m_pWindowController( pController )
         , m_bInPaint(false)
+        , m_pViewShellWindow( nullptr )
 #if HAVE_FEATURE_OPENGL
         , m_pOpenGLWindow(VclPtr<OpenGLWindow>::Create(this, false))
 #else
@@ -94,6 +102,7 @@ void ChartWindow::dispose()
         xUpdatable->update();
     }
     m_pOpenGLWindow.disposeAndClear();
+    m_pViewShellWindow.clear();
     vcl::Window::dispose();
 }
 
@@ -108,6 +117,10 @@ void ChartWindow::PrePaint(vcl::RenderContext& )
 
 void ChartWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
 {
+    if (comphelper::LibreOfficeKit::isActive()
+        && rRenderContext.GetOutDevType() != OutDevType::OUTDEV_VIRDEV)
+        return;
+
     m_bInPaint = true;
     if (m_pOpenGLWindow && m_pOpenGLWindow->IsVisible())
     {
@@ -301,6 +314,56 @@ void ChartWindow::Invalidate( const vcl::Region& rRegion, InvalidateFlags nFlags
     }
 }
 
+void ChartWindow::LogicInvalidate(const tools::Rectangle* pRectangle)
+{
+    OString sRectangle;
+    if (!pRectangle)
+    {
+        // we have to invalidate the whole chart area not the whole document
+        sRectangle = GetBoundingBox().toString();
+    }
+    else
+    {
+        tools::Rectangle aRectangle(*pRectangle);
+        // When dragging shapes the map mode is disabled.
+        if (IsMapModeEnabled())
+        {
+            if (GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
+                aRectangle = OutputDevice::LogicToLogic(aRectangle, MapUnit::Map100thMM, MapUnit::MapTwip);
+        }
+        else
+        {
+            aRectangle = PixelToLogic(aRectangle, MapMode(MapUnit::MapTwip));
+        }
+
+        vcl::Window* pEditWin = GetParentEditWin();
+        if (pEditWin)
+        {
+            MapMode aCWMapMode = GetMapMode();
+            double fXScale = aCWMapMode.GetScaleX();
+            double fYScale = aCWMapMode.GetScaleY();
+
+            if (!IsMapModeEnabled())
+            {
+                aRectangle.Left() /= fXScale;
+                aRectangle.Right() /= fXScale;
+                aRectangle.Top() /= fYScale;
+                aRectangle.Bottom() /= fYScale;
+            }
+
+            Point aOffset = this->GetOffsetPixelFrom(*pEditWin);
+            aOffset.X() *= (TWIPS_PER_PIXEL / fXScale);
+            aOffset.Y() *= (TWIPS_PER_PIXEL / fYScale);
+
+            aRectangle = tools::Rectangle(aRectangle.TopLeft() + aOffset, aRectangle.GetSize());
+        }
+
+        sRectangle = aRectangle.toString();
+    }
+    SfxViewShell* pCurrentShell = SfxViewShell::Current();
+    SfxLokHelper::notifyInvalidation(pCurrentShell, sRectangle);
+}
+
 FactoryFunction ChartWindow::GetUITestFactory() const
 {
     return ChartWindowUIObject::create;
@@ -311,6 +374,53 @@ ChartController* ChartWindow::GetController()
     return m_pWindowController;
 }
 
+vcl::Window* ChartWindow::GetParentEditWin()
+{
+    if (m_pViewShellWindow)
+        return m_pViewShellWindow.get();
+
+    // So, you are thinking, why do not invoke pCurrentShell->GetWindow() ?
+    // Because in Impress the parent edit win is not view shell window.
+    SfxViewShell* pCurrentShell = SfxViewShell::Current();
+    if( pCurrentShell )
+    {
+        SfxInPlaceClient* pIPClient = pCurrentShell->GetIPClient();
+        if (pIPClient)
+        {
+            vcl::Window* pRootWin = pIPClient->GetEditWin();
+            if(pRootWin && pRootWin->IsAncestorOf(*this))
+            {
+                m_pViewShellWindow = pRootWin;
+                return m_pViewShellWindow.get();
+            }
+        }
+    }
+    return nullptr;
+}
+
+tools::Rectangle ChartWindow::GetBoundingBox()
+{
+    tools::Rectangle aBBox;
+
+    vcl::Window* pRootWin = GetParentEditWin();
+    if (pRootWin)
+    {
+        // In all cases, the following code fragment
+        // returns the chart bounding box in twips.
+        MapMode aCWMapMode = GetMapMode();
+        double fXScale = aCWMapMode.GetScaleX();
+        double fYScale = aCWMapMode.GetScaleY();
+        Point aOffset = GetOffsetPixelFrom(*pRootWin);
+        aOffset.X() *= (TWIPS_PER_PIXEL / fXScale);
+        aOffset.Y() *= (TWIPS_PER_PIXEL / fYScale);
+        Size aSize = GetSizePixel();
+        aSize.Width() *= (TWIPS_PER_PIXEL / fXScale);
+        aSize.Height() *= (TWIPS_PER_PIXEL / fYScale);
+        aBBox = tools::Rectangle(aOffset, aSize);
+    }
+    return aBBox;
+}
+
 } //namespace chart
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/editeng/source/editeng/impedit.cxx b/editeng/source/editeng/impedit.cxx
index 4f35f97227ce..22efd056dbee 100644
--- a/editeng/source/editeng/impedit.cxx
+++ b/editeng/source/editeng/impedit.cxx
@@ -376,6 +376,17 @@ void ImpEditView::DrawSelection( EditSelection aTmpSel, vcl::Region* pRegion, Ou
             {
                 std::vector<tools::Rectangle> aRectangles;
                 pRegion->GetRegionRectangles(aRectangles);
+                if (pOutWin->IsChart())
+                {
+                    const vcl::Window* pViewShellWindow = mpViewShell->GetEditWindowForActiveOLEObj();
+                    if (pViewShellWindow && pViewShellWindow->IsAncestorOf(*pOutWin))
+                    {
+                        Point aOffsetPx = pOutWin->GetOffsetPixelFrom(*pViewShellWindow);
+                        Point aLogicOffset = pOutWin->PixelToLogic(aOffsetPx);
+                        for (tools::Rectangle& rRect : aRectangles)
+                            rRect.Move(aLogicOffset.getX(), aLogicOffset.getY());
+                    }
+                }
 
                 if (!aRectangles.empty())
                 {
@@ -1017,8 +1028,19 @@ void ImpEditView::ShowCursor( bool bGotoCursor, bool bForceVisCursor )
 
         if (comphelper::LibreOfficeKit::isActive() && mpViewShell)
         {
-            const Point& rPos = GetCursor()->GetPos();
-            tools::Rectangle aRect(rPos.getX(), rPos.getY(), rPos.getX() + GetCursor()->GetWidth(), rPos.getY() + GetCursor()->GetHeight());
+            Point aPos = GetCursor()->GetPos();
+            if (pOutWin->IsChart())
+            {
+                const vcl::Window* pViewShellWindow = mpViewShell->GetEditWindowForActiveOLEObj();
+                if (pViewShellWindow && pViewShellWindow->IsAncestorOf(*pOutWin))
+                {
+                    Point aOffsetPx = pOutWin->GetOffsetPixelFrom(*pViewShellWindow);
+                    Point aLogicOffset = pOutWin->PixelToLogic(aOffsetPx);
+                    aPos.Move(aLogicOffset.getX(), aLogicOffset.getY());
+                }
+            }
+
+            tools::Rectangle aRect(aPos.getX(), aPos.getY(), aPos.getX() + GetCursor()->GetWidth(), aPos.getY() + GetCursor()->GetHeight());
 
             // LOK output is always in twips, convert from mm100 if necessary.
             if (pOutWin->GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
diff --git a/include/editeng/outliner.hxx b/include/editeng/outliner.hxx
index 3e7e889064d1..1cc38d50263e 100644
--- a/include/editeng/outliner.hxx
+++ b/include/editeng/outliner.hxx
@@ -384,6 +384,7 @@ public:
     virtual void NotifyOtherViews(int nType, const OString& rKey, const OString& rPayload) = 0;
     /// Wrapper around SfxLokHelper::notifyOtherView().
     virtual void NotifyOtherView(OutlinerViewShell* pOtherShell, int nType, const OString& rKey, const OString& rPayload) = 0;
+    virtual vcl::Window* GetEditWindowForActiveOLEObj() const = 0;
 
 protected:
     ~OutlinerViewShell() throw () {}
diff --git a/include/sfx2/lokcharthelper.hxx b/include/sfx2/lokcharthelper.hxx
new file mode 100644
index 000000000000..deb2c43f0556
--- /dev/null
+++ b/include/sfx2/lokcharthelper.hxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ */
+
+#ifndef INCLUDED_SFX2_LOKCHARTHELPER_HXX
+#define INCLUDED_SFX2_LOKCHARTHELPER_HXX
+
+#include <sfx2/dllapi.h>
+#include <tools/gen.hxx>
+#include <vcl/window.hxx>
+
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/frame/XDispatch.hpp>
+
+class SfxViewShell;
+class VirtualDevice;
+
+class SFX2_DLLPUBLIC LokChartHelper
+{
+private:
+    SfxViewShell* mpViewShell;
+    css::uno::Reference<css::frame::XController> mxController;
+    css::uno::Reference<css::frame::XDispatch> mxDispatcher;
+    VclPtr<vcl::Window> mpWindow;
+
+public:
+    LokChartHelper(SfxViewShell* pViewShell)
+        : mpViewShell(pViewShell)
+        , mpWindow(nullptr)
+    {}
+
+    css::uno::Reference<css::frame::XController>& GetXController();
+    css::uno::Reference<css::frame::XDispatch>& GetXDispatcher();
+    vcl::Window* GetWindow();
+    tools::Rectangle GetChartBoundingBox();
+    void Invalidate();
+
+    bool Hit(const Point& aPos);
+    static bool HitAny(const Point& aPos);
+    void PaintTile(VirtualDevice& rRenderContext, const tools::Rectangle& rTileRect);
+    static void PaintAllChartsOnTile(VirtualDevice& rDevice,
+                                     int nOutputWidth, int nOutputHeight,
+                                     int nTilePosX, int nTilePosY,
+                                     long nTileWidth, long nTileHeight);
+    bool postMouseEvent(int nType, int nX, int nY,
+                        int nCount, int nButtons, int nModifier,
+                        double fScaleX = 1.0, double fScaleY = 1.0);
+    bool setTextSelection(int nType, int nX, int nY);
+    bool setGraphicSelection(int nType, int nX, int nY,
+                             double fScaleX = 1.0, double fScaleY = 1.0);
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/sfx2/viewsh.hxx b/include/sfx2/viewsh.hxx
index 89bb429aa41b..f186f8d4135a 100644
--- a/include/sfx2/viewsh.hxx
+++ b/include/sfx2/viewsh.hxx
@@ -336,6 +336,9 @@ public:
     virtual void NotifyCursor(SfxViewShell* /*pViewShell*/) const;
     /// Where a new view can perform some update/initialization soon after the callback has been registered.
     virtual void afterCallbackRegistered();
+    /// See OutlinerViewShell::GetEditWindowForActiveOLEObj().
+    virtual vcl::Window* GetEditWindowForActiveOLEObj() const override;
+
 };
 
 
diff --git a/include/vcl/window.hxx b/include/vcl/window.hxx
index 7c2aa534fa69..3b8a42ac5d0b 100644
--- a/include/vcl/window.hxx
+++ b/include/vcl/window.hxx
@@ -931,6 +931,7 @@ public:
     vcl::Window*                        GetParent() const;
     // return the dialog we are contained in or NULL if un-contained
     Dialog*                             GetParentDialog() const;
+    bool                                IsAncestorOf( const vcl::Window& rWindow ) const;
 
     void                                Show( bool bVisible = true, ShowFlags nFlags = ShowFlags::NONE );
     void                                Hide() { Show( false ); }
@@ -1030,6 +1031,7 @@ public:
     virtual void                        SetOutputSizePixel( const Size& rNewSize );
     bool                                IsDefaultPos() const;
     bool                                IsDefaultSize() const;
+    Point                               GetOffsetPixelFrom(const vcl::Window& rWindow) const;
 
     // those conversion routines might deliver different results during UI mirroring
     Point                               OutputToScreenPixel( const Point& rPos ) const;
@@ -1540,6 +1542,8 @@ public:
     virtual Selection GetSurroundingTextSelection() const;
 
     virtual FactoryFunction GetUITestFactory() const;
+
+    virtual bool IsChart() const { return false; }
 };
 
 }
diff --git a/sc/source/ui/unoobj/docuno.cxx b/sc/source/ui/unoobj/docuno.cxx
index b6eeca6fc39a..8b70fa9f44e9 100644
--- a/sc/source/ui/unoobj/docuno.cxx
+++ b/sc/source/ui/unoobj/docuno.cxx
@@ -48,6 +48,7 @@
 #include <unotools/charclass.hxx>
 #include <tools/multisel.hxx>
 #include <toolkit/awt/vclxdevice.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
 #include <unotools/saveopt.hxx>
 
 #include <float.h>
@@ -75,6 +76,7 @@
 #include <opencl/platforminfo.hxx>
 #endif
 #include <sfx2/lokhelper.hxx>
+#include <sfx2/lokcharthelper.hxx>
 
 #include "cellsuno.hxx"
 #include <columnspanset.hxx>
@@ -503,6 +505,9 @@ void ScModelObj::paintTile( VirtualDevice& rDevice,
 
     pGridWindow->PaintTile( rDevice, nOutputWidth, nOutputHeight,
                             nTilePosX, nTilePosY, nTileWidth, nTileHeight );
+
+    LokChartHelper::PaintAllChartsOnTile(rDevice, nOutputWidth, nOutputHeight,
+                                         nTilePosX, nTilePosY, nTileWidth, nTileHeight);
 }
 
 void ScModelObj::setPart( int nPart )
@@ -570,20 +575,28 @@ void ScModelObj::postKeyEvent(int nType, int nCharCode, int nKeyCode)
     // There seems to be no clear way of getting the grid window for this
     // particular document, hence we need to hope we get the right window.
     ScViewData* pViewData = ScDocShell::GetViewData();
-    ScGridWindow* pGridWindow = pViewData->GetActiveWin();
+    vcl::Window* pWindow = pViewData->GetActiveWin();
 
-    if (!pGridWindow)
+    if (!pWindow)
         return;
 
     KeyEvent aEvent(nCharCode, nKeyCode, 0);
 
+    ScTabViewShell * pTabViewShell = pViewData->GetViewShell();
+    LokChartHelper aChartHelper(pTabViewShell);
+    vcl::Window* pChartWindow = aChartHelper.GetWindow();
+    if (pChartWindow)
+    {
+        pWindow = pChartWindow;
+    }
+
     switch (nType)
     {
     case LOK_KEYEVENT_KEYINPUT:
-        pGridWindow->KeyInput(aEvent);
+        pWindow->KeyInput(aEvent);
         break;
     case LOK_KEYEVENT_KEYUP:
-        pGridWindow->KeyUp(aEvent);
+        pWindow->KeyUp(aEvent);
         break;
     default:
         assert(false);
@@ -607,6 +620,23 @@ void ScModelObj::postMouseEvent(int nType, int nX, int nY, int nCount, int nButt
     pViewData->SetZoom(Fraction(mnTilePixelWidth * TWIPS_PER_PIXEL, mnTileTwipWidth),
                        Fraction(mnTilePixelHeight * TWIPS_PER_PIXEL, mnTileTwipHeight), true);
 
+    // check if user hit a chart which is being edited by him
+    ScTabViewShell * pTabViewShell = pViewData->GetViewShell();
+    LokChartHelper aChartHelper(pTabViewShell);
+    if (aChartHelper.postMouseEvent(nType, nX, nY,
+                                    nCount, nButtons, nModifier,
+                                    pViewData->GetPPTX(), pViewData->GetPPTY()))
+        return;
+
+    // check if the user hit a chart which is being edited by someone else
+    // and, if so, skip current mouse event
+    if (nType != LOK_MOUSEEVENT_MOUSEMOVE)
+    {
+        if (LokChartHelper::HitAny(Point(nX, nY)))
+            return;
+    }
+
+
     // Calc operates in pixels...
     Point aPos(nX * pViewData->GetPPTX(), nY * pViewData->GetPPTY());
     MouseEvent aEvent(aPos, nCount,
@@ -645,9 +675,13 @@ void ScModelObj::postMouseEvent(int nType, int nX, int nY, int nCount, int nButt
 void ScModelObj::setTextSelection(int nType, int nX, int nY)
 {
     SolarMutexGuard aGuard;
-
     ScViewData* pViewData = ScDocShell::GetViewData();
     ScTabViewShell* pViewShell = pViewData->GetViewShell();
+
+    LokChartHelper aChartHelper(pViewShell);
+    if (aChartHelper.setTextSelection(nType, nX, nY))
+        return;
+
     ScInputHandler* pInputHandler = SC_MOD()->GetInputHdl(pViewShell);
     ScDrawView* pDrawView = pViewData->GetScDrawView();
 
@@ -822,9 +856,16 @@ void ScModelObj::setGraphicSelection(int nType, int nX, int nY)
     // update the aLogicMode in ScViewData to something predictable
     pViewData->SetZoom(Fraction(mnTilePixelWidth * TWIPS_PER_PIXEL, mnTileTwipWidth),
                        Fraction(mnTilePixelHeight * TWIPS_PER_PIXEL, mnTileTwipHeight), true);
+    double fPPTX = pViewData->GetPPTX();
+    double fPPTY = pViewData->GetPPTY();
+
+    ScTabViewShell* pViewShell = pViewData->GetViewShell();
+    LokChartHelper aChartHelper(pViewShell);
+    if (aChartHelper.setGraphicSelection(nType, nX, nY, fPPTX, fPPTY))
+        return;
 
-    int nPixelX = nX * pViewData->GetPPTX();
-    int nPixelY = nY * pViewData->GetPPTY();
+    int nPixelX = nX * fPPTX;
+    int nPixelY = nY * fPPTY;
 
     switch (nType)
     {
diff --git a/sd/source/ui/unoidl/unomodel.cxx b/sd/source/ui/unoidl/unomodel.cxx
index 352994d067da..a7c4d0663734 100644
--- a/sd/source/ui/unoidl/unomodel.cxx
+++ b/sd/source/ui/unoidl/unomodel.cxx
@@ -119,6 +119,10 @@
 
 #include <drawinglayer/primitive2d/structuretagprimitive2d.hxx>
 
+#include <sfx2/lokcharthelper.hxx>
+
+#define TWIPS_PER_PIXEL 15
+
 using namespace ::cppu;
 using namespace ::com::sun::star;
 using namespace ::sd;
@@ -2250,15 +2254,15 @@ void SdXImpressDocument::paintTile( VirtualDevice& rDevice,
     // 100th mm rather than TWIP. It makes most sense just to
     // convert here and in getDocumentSize, and leave the tiled
     // rendering API working in TWIPs.
-    nTileWidth = convertTwipToMm100( nTileWidth );
-    nTileHeight = convertTwipToMm100( nTileHeight );
-    nTilePosX = convertTwipToMm100( nTilePosX );
-    nTilePosY = convertTwipToMm100( nTilePosY );
+    long nTileWidthHMM = convertTwipToMm100( nTileWidth );
+    long nTileHeightHMM = convertTwipToMm100( nTileHeight );
+    int nTilePosXHMM = convertTwipToMm100( nTilePosX );
+    int nTilePosYHMM = convertTwipToMm100( nTilePosY );
 
     MapMode aMapMode = rDevice.GetMapMode();
     aMapMode.SetMapUnit( MapUnit::Map100thMM );
-    aMapMode.SetOrigin( Point( -nTilePosX,
-                               -nTilePosY) );
+    aMapMode.SetOrigin( Point( -nTilePosXHMM,
+                               -nTilePosYHMM) );
     aMapMode.SetScaleX( scaleX );
     aMapMode.SetScaleY( scaleY );
 
@@ -2266,11 +2270,14 @@ void SdXImpressDocument::paintTile( VirtualDevice& rDevice,
 
     rDevice.SetOutputSizePixel( Size(nOutputWidth, nOutputHeight) );
 
-    Point aPoint(nTilePosX, nTilePosY);
-    Size aSize(nTileWidth, nTileHeight);
+    Point aPoint(nTilePosXHMM, nTilePosYHMM);
+    Size aSize(nTileWidthHMM, nTileHeightHMM);
     ::tools::Rectangle aRect(aPoint, aSize);
 
     pViewSh->GetView()->CompleteRedraw(&rDevice, vcl::Region(aRect));
+
+    LokChartHelper::PaintAllChartsOnTile(rDevice, nOutputWidth, nOutputHeight,
+                                         nTilePosX, nTilePosY, nTileWidth, nTileHeight);
 }
 
 void SdXImpressDocument::setPart( int nPart )
@@ -2449,10 +2456,17 @@ void SdXImpressDocument::postKeyEvent(int nType, int nCharCode, int nKeyCode)
     if (!pViewShell)
         return;
 
-    sd::Window* pWindow = pViewShell->GetActiveWindow();
+    vcl::Window* pWindow = pViewShell->GetActiveWindow();
     if (!pWindow)
         return;
 
+    LokChartHelper aChartHelper(pViewShell->GetViewShell());
+    vcl::Window* pChartWindow = aChartHelper.GetWindow();
+    if (pChartWindow)
+    {
+        pWindow = pChartWindow;
+    }
+
     KeyEvent aEvent(nCharCode, nKeyCode, 0);
 
     switch (nType)
@@ -2476,6 +2490,24 @@ void SdXImpressDocument::postMouseEvent(int nType, int nX, int nY, int nCount, i
     DrawViewShell* pViewShell = GetViewShell();
     if (!pViewShell)
         return;
+
+    double fScale = 1.0/TWIPS_PER_PIXEL;
+
+    // check if user hit a chart which is being edited by him
+    LokChartHelper aChartHelper(pViewShell->GetViewShell());
+    if (aChartHelper.postMouseEvent(nType, nX, nY,
+                                    nCount, nButtons, nModifier,
+                                    fScale, fScale))
+        return;
+
+    // check if the user hit a chart which is being edited by someone else
+    // and, if so, skip current mouse event
+    if (nType != LOK_MOUSEEVENT_MOUSEMOVE)
+    {
+        if (LokChartHelper::HitAny(Point(nX, nY)))
+            return;
+    }
+
     Window* pWindow = pViewShell->GetActiveWindow();
 
     Point aPos(Point(convertTwipToMm100(nX), convertTwipToMm100(nY)));
@@ -2513,6 +2545,10 @@ void SdXImpressDocument::setTextSelection(int nType, int nX, int nY)
     if (!pViewShell)
         return;
 
+    LokChartHelper aChartHelper(pViewShell->GetViewShell());
+    if (aChartHelper.setTextSelection(nType, nX, nY))
+        return;
+
     Point aPoint(convertTwipToMm100(nX), convertTwipToMm100(nY));
     switch (nType)
     {
@@ -2550,6 +2586,12 @@ void SdXImpressDocument::setGraphicSelection(int nType, int nX, int nY)
     if (!pViewShell)
         return;
 
+    double fScale = 1.0/TWIPS_PER_PIXEL;
+
+    LokChartHelper aChartHelper(pViewShell->GetViewShell());
+    if (aChartHelper.setGraphicSelection(nType, nX, nY, fScale, fScale))
+        return;
+
     Point aPoint(convertTwipToMm100(nX), convertTwipToMm100(nY));
     switch (nType)
     {
diff --git a/sfx2/Library_sfx.mk b/sfx2/Library_sfx.mk
index 201a106d0738..c0913939f31e 100644
--- a/sfx2/Library_sfx.mk
+++ b/sfx2/Library_sfx.mk
@@ -300,6 +300,7 @@ $(eval $(call gb_Library_add_exception_objects,sfx,\
     sfx2/source/view/frame2 \
     sfx2/source/view/frmload \
     sfx2/source/view/ipclient \
+    sfx2/source/view/lokcharthelper \
     sfx2/source/view/lokhelper \
     sfx2/source/view/printer \
     sfx2/source/view/sfxbasecontroller \
diff --git a/sfx2/source/view/ipclient.cxx b/sfx2/source/view/ipclient.cxx
index a70bb145cd2a..21f5de28970e 100644
--- a/sfx2/source/view/ipclient.cxx
+++ b/sfx2/source/view/ipclient.cxx
@@ -64,6 +64,8 @@
 #include <svtools/soerr.hxx>
 #include <comphelper/processfactory.hxx>
 
+#include <sfx2/lokhelper.hxx>
+
 #define SFX_CLIENTACTIVATE_TIMEOUT 100
 
 using namespace com::sun::star;
@@ -394,7 +396,27 @@ awt::Rectangle SAL_CALL SfxInPlaceClient_Impl::getPlacement()
     aRealObjArea.SetSize( Size( Fraction( aRealObjArea.GetWidth() ) * m_aScaleWidth,
                                 Fraction( aRealObjArea.GetHeight() ) * m_aScaleHeight ) );
 
-    aRealObjArea = m_pClient->GetEditWin()->LogicToPixel( aRealObjArea );
+    // In Writer and Impress the map mode is disabled. So when a chart is
+    // activated (for in place editing) we get the chart win size in 100th mm
+    // and any method that should return pixels returns 100th mm and the chart
+    // window map mode has a ~26.485 scale factor.
+    // All that does not fit with current implementation for handling chart
+    // editing in LOK.
+    if (comphelper::LibreOfficeKit::isActive())
+    {
+        vcl::Window* pEditWin = m_pClient->GetEditWin();
+        bool bMapModeEnabled = pEditWin->IsMapModeEnabled();
+        if (!bMapModeEnabled)
+            pEditWin->EnableMapMode();
+        aRealObjArea = m_pClient->GetEditWin()->LogicToPixel( aRealObjArea );
+        if (!bMapModeEnabled && pEditWin->IsMapModeEnabled())
+            pEditWin->EnableMapMode(false);
+    }
+    else
+    {
+        aRealObjArea = m_pClient->GetEditWin()->LogicToPixel( aRealObjArea );
+    }
+
     return AWTRectangle( aRealObjArea );
 }
 
@@ -409,7 +431,22 @@ awt::Rectangle SAL_CALL SfxInPlaceClient_Impl::getClipRectangle()
     aRealObjArea.SetSize( Size( Fraction( aRealObjArea.GetWidth() ) * m_aScaleWidth,
                                 Fraction( aRealObjArea.GetHeight() ) * m_aScaleHeight ) );
 
-    aRealObjArea = m_pClient->GetEditWin()->LogicToPixel( aRealObjArea );
+    // See comment for SfxInPlaceClient_Impl::getPlacement.
+    if (comphelper::LibreOfficeKit::isActive())
+    {
+        vcl::Window* pEditWin = m_pClient->GetEditWin();
+        bool bMapModeEnabled = pEditWin->IsMapModeEnabled();
+        if (!bMapModeEnabled)
+            pEditWin->EnableMapMode();
+        aRealObjArea = m_pClient->GetEditWin()->LogicToPixel( aRealObjArea );
+        if (!bMapModeEnabled && pEditWin->IsMapModeEnabled())
+            pEditWin->EnableMapMode(false);
+    }
+    else
+    {
+        aRealObjArea = m_pClient->GetEditWin()->LogicToPixel( aRealObjArea );
+    }
+
     return AWTRectangle( aRealObjArea );
 }
 
@@ -878,7 +915,13 @@ ErrCode SfxInPlaceClient::DoVerb( long nVerb )
 
             if ( !nError )
             {
-
+                // See comment for SfxInPlaceClient_Impl::getPlacement.
+                vcl::Window* pEditWin = GetEditWin();
+                bool bMapModeEnabled = pEditWin->IsMapModeEnabled();
+                if (comphelper::LibreOfficeKit::isActive() && !bMapModeEnabled)
+                {
+                    pEditWin->EnableMapMode();
+                }
                 m_pViewSh->GetViewFrame()->GetFrame().LockResize_Impl(true);
                 try
                 {
@@ -929,8 +972,13 @@ ErrCode SfxInPlaceClient::DoVerb( long nVerb )
                             " exception caught: " << e.Message);
                     nError = ERRCODE_SO_GENERALERROR;
                     //TODO/LATER: better error handling
-                }
 
+                }
+                if (comphelper::LibreOfficeKit::isActive() && !bMapModeEnabled
+                        && pEditWin->IsMapModeEnabled())
+                {
+                    pEditWin->EnableMapMode(false);
+                }
                 SfxViewFrame* pFrame = m_pViewSh->GetViewFrame();
                 pFrame->GetFrame().LockResize_Impl(false);
                 pFrame->GetFrame().Resize();
diff --git a/sfx2/source/view/lokcharthelper.cxx b/sfx2/source/view/lokcharthelper.cxx
new file mode 100644
index 000000000000..fffbc3efa58e
--- /dev/null
+++ b/sfx2/source/view/lokcharthelper.cxx
@@ -0,0 +1,373 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ */
+
+#include <sfx2/lokcharthelper.hxx>
+
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <sfx2/ipclient.hxx>
+#include <sfx2/lokhelper.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/fract.hxx>
+#include <tools/mapunit.hxx>
+#include <vcl/virdev.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/chart2/XChartDocument.hpp>
+
+
+#define TWIPS_PER_PIXEL 15
+
+using namespace com::sun::star;
+
+namespace {
+
+inline Point lcl_TwipsToHMM( const Point& rPoint )
+{
+    return Point(convertTwipToMm100(rPoint.getX()), convertTwipToMm100(rPoint.getY()));
+}
+
+inline Size lcl_TwipsToHMM( const Size& rSize )
+{
+    return Size(convertTwipToMm100(rSize.getWidth()), convertTwipToMm100(rSize.getHeight()));
+}
+
+} // end anonymous ns
+
+css::uno::Reference<css::frame::XController>& LokChartHelper::GetXController()
+{
+    if(!mxController.is() )
+    {
+        if (mpViewShell)
+        {
+            SfxInPlaceClient* pIPClient = mpViewShell->GetIPClient();
+            if (pIPClient)
+            {
+                css::uno::Reference< ::css::embed::XEmbeddedObject > xEmbObj = pIPClient->GetObject();
+                if( xEmbObj.is() )
+                {
+                    ::css::uno::Reference< ::css::chart2::XChartDocument > xChart( xEmbObj->getComponent(), uno::UNO_QUERY );
+                    if( xChart.is() )
+                    {
+                        ::css::uno::Reference< ::css::frame::XController > xChartController = xChart->getCurrentController();
+                        if( xChartController.is() )
+                        {
+                            mxController = xChartController;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    return mxController;
+}
+
+css::uno::Reference<css::frame::XDispatch>& LokChartHelper::GetXDispatcher()
+{
+    if( !mxDispatcher.is() )
+    {
+        ::css::uno::Reference< ::css::frame::XController >& xChartController = GetXController();
+        if( xChartController.is() )
+        {
+            ::css::uno::Reference< ::css::frame::XDispatch > xDispatcher( xChartController, uno::UNO_QUERY );
+            if( xDispatcher.is() )
+            {
+                mxDispatcher = xDispatcher;
+            }
+        }
+    }
+
+    return mxDispatcher;
+}
+
+vcl::Window* LokChartHelper::GetWindow()
+{
+    if (!mpWindow)
+    {
+        ::css::uno::Reference< ::css::frame::XController >& xChartController = GetXController();
+        if( xChartController.is() )
+        {
+            ::css::uno::Reference< ::css::frame::XFrame > xFrame = xChartController->getFrame();
+            if (xFrame.is())
+            {
+                ::css::uno::Reference< ::css::awt::XWindow > xDockerWin = xFrame->getContainerWindow();
+                vcl::Window* pParent = VCLUnoHelper::GetWindow( xDockerWin ).get();
+                if (pParent)
+                {
+                    sal_uInt16 nTotChildren = pParent->GetChildCount();
+                    while (nTotChildren--)
+                    {
+                        vcl::Window* pChildWin = pParent->GetChild(nTotChildren);
+                        if (pChildWin && pChildWin->IsChart())
+                        {
+                            mpWindow = pChildWin;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    return mpWindow.get();
+}
+
+tools::Rectangle LokChartHelper::GetChartBoundingBox()
+{
+    tools::Rectangle aBBox;
+    if (mpViewShell)
+    {
+        SfxInPlaceClient* pIPClient = mpViewShell->GetIPClient();
+        if (pIPClient)
+        {
+            vcl::Window* pRootWin = pIPClient->GetEditWin();
+            if (pRootWin)
+            {
+                vcl::Window* pWindow = GetWindow();
+                if (pWindow)
+                {
+                    // In all cases, the following code fragment
+                    // returns the chart bounding box in twips.
+                    MapMode aCWMapMode = pWindow->GetMapMode();
+                    double fXScale = aCWMapMode.GetScaleX();
+                    double fYScale = aCWMapMode.GetScaleY();
+                    Point aOffset = pWindow->GetOffsetPixelFrom(*pRootWin);
+                    aOffset.X() *= (TWIPS_PER_PIXEL / fXScale);
+                    aOffset.Y() *= (TWIPS_PER_PIXEL / fYScale);
+                    Size aSize = pWindow->GetSizePixel();
+                    aSize.Width() *= (TWIPS_PER_PIXEL / fXScale);
+                    aSize.Height() *= (TWIPS_PER_PIXEL / fYScale);
+                    aBBox = tools::Rectangle(aOffset, aSize);
+                }
+            }
+        }
+    }
+    return aBBox;
+}
+
+void LokChartHelper::Invalidate()
+{
+    mpWindow = nullptr;
+    mxDispatcher.clear();
+    mxController.clear();
+}
+
+bool LokChartHelper::Hit(const Point& aPos)
+{
+    if (mpViewShell)
+    {
+        vcl::Window* pChartWindow = GetWindow();
+        if (pChartWindow)
+        {
+            tools::Rectangle rChartBBox = GetChartBoundingBox();
+            return rChartBBox.IsInside(aPos);
+        }
+    }
+    return false;
+}
+
+bool LokChartHelper::HitAny(const Point& aPos)
+{
+    SfxViewShell* pViewShell = SfxViewShell::GetFirst();
+    while (pViewShell)
+    {
+        LokChartHelper aChartHelper(pViewShell);
+        if (aChartHelper.Hit(aPos))
+            return true;
+        pViewShell = SfxViewShell::GetNext(*pViewShell);
+    }
+    return false;
+}
+
+void LokChartHelper::PaintTile(VirtualDevice& rRenderContext, const tools::Rectangle& rTileRect)
+{
+    if (mpViewShell)
+    {
+        vcl::Window* pChartWindow = GetWindow();
+        if (pChartWindow)
+        {
+            tools::Rectangle aChartRect = GetChartBoundingBox();
+            tools::Rectangle aTestRect = rTileRect;
+            aTestRect.Intersection( aChartRect );
+            if (!aTestRect.IsEmpty())
+            {
+                Point aOffset( aChartRect.Left() - rTileRect.Left(), aChartRect.Top() - rTileRect.Top() );
+                Point aOffsetFromTile = lcl_TwipsToHMM(aOffset);
+                Size aSize = lcl_TwipsToHMM(aChartRect.GetSize());
+                tools::Rectangle aRectangle(Point(0,0), aSize);
+
+                bool bEnableMapMode = !pChartWindow->IsMapModeEnabled();
+                pChartWindow->EnableMapMode();
+                bool bRenderContextEnableMapMode = !rRenderContext.IsMapModeEnabled();
+                rRenderContext.EnableMapMode();
+
+                rRenderContext.Push(PushFlags::MAPMODE);
+
+                MapMode aCWMapMode = pChartWindow->GetMapMode();
+                aCWMapMode.SetScaleX(rRenderContext.GetMapMode().GetScaleX());
+                aCWMapMode.SetScaleY(rRenderContext.GetMapMode().GetScaleY());
+
+                aCWMapMode.SetOrigin(aOffsetFromTile);
+                rRenderContext.SetMapMode(aCWMapMode);
+
+                pChartWindow->Paint(rRenderContext, aRectangle);
+
+                rRenderContext.Pop();
+
+                if (bRenderContextEnableMapMode)
+                    rRenderContext.EnableMapMode(false);
+                if (bEnableMapMode)
+                    pChartWindow->EnableMapMode(false);
+            }
+        }
+    }
+}
+
+void LokChartHelper::PaintAllChartsOnTile(VirtualDevice& rDevice,
+                                          int nOutputWidth, int nOutputHeight,
+                                          int nTilePosX, int nTilePosY,
+                                          long nTileWidth, long nTileHeight)
+{
+    // Resizes the virtual device so to contain the entries context
+    rDevice.SetOutputSizePixel(Size(nOutputWidth, nOutputHeight));
+
+    rDevice.Push(PushFlags::MAPMODE);
+    MapMode aMapMode(rDevice.GetMapMode());
+
+    // Scaling. Must convert from pixels to twips. We know
+    // that VirtualDevices use a DPI of 96.
+    Fraction scaleX = Fraction(nOutputWidth, 96) * Fraction(1440L) / Fraction(nTileWidth);
+    Fraction scaleY = Fraction(nOutputHeight, 96) * Fraction(1440L) / Fraction(nTileHeight);
+    aMapMode.SetScaleX(scaleX);
+    aMapMode.SetScaleY(scaleY);
+    rDevice.SetMapMode(aMapMode);
+
+    tools::Rectangle aTileRect(Point(nTilePosX, nTilePosY), Size(nTileWidth, nTileHeight));
+    SfxViewShell* pViewShell = SfxViewShell::GetFirst();
+    while (pViewShell)
+    {
+        LokChartHelper aChartHelper(pViewShell);
+        aChartHelper.PaintTile(rDevice, aTileRect);
+        pViewShell = SfxViewShell::GetNext(*pViewShell);
+    }
+    rDevice.Pop();
+}
+
+bool LokChartHelper::postMouseEvent(int nType, int nX, int nY,
+                                    int nCount, int nButtons, int nModifier,
+                                    double fScaleX, double fScaleY)
+{
+    Point aMousePos(nX, nY);
+    vcl::Window* pChartWindow = GetWindow();
+    if (pChartWindow)
+    {
+        tools::Rectangle rChartBBox = GetChartBoundingBox();
+        if (rChartBBox.IsInside(aMousePos))
+        {
+            int nChartWinX = nX - rChartBBox.Left();
+            int nChartWinY = nY - rChartBBox.Top();
+
+            // chart window expects pixels, but the conversion factor
+            // can depend on the client zoom
+            Point aPos(nChartWinX * fScaleX, nChartWinY * fScaleY);
+            MouseEvent aEvent(aPos, nCount,
+                    MouseEventModifiers::SIMPLECLICK, nButtons, nModifier);
+
+            switch (nType)
+            {
+            case LOK_MOUSEEVENT_MOUSEBUTTONDOWN:
+                pChartWindow->MouseButtonDown(aEvent);
+                break;
+            case LOK_MOUSEEVENT_MOUSEBUTTONUP:
+                pChartWindow->MouseButtonUp(aEvent);
+                if (pChartWindow->IsTracking())
+                    pChartWindow->EndTracking(TrackingEventFlags::DontCallHdl);
+                break;
+            case LOK_MOUSEEVENT_MOUSEMOVE:
+                pChartWindow->MouseMove(aEvent);
+                break;
+            default:
+                assert(false);
+                break;
+            }
+            return true;
+        }
+    }
+    return false;
+}
+
+bool LokChartHelper::setTextSelection(int nType, int nX, int nY)
+{
+    tools::Rectangle rChartBBox = GetChartBoundingBox();
+    if (rChartBBox.IsInside(Point(nX, nY)))
+    {
+        css::uno::Reference<css::frame::XDispatch> xDispatcher = GetXDispatcher();
+        if (xDispatcher.is())
+        {
+            int nChartWinX = nX - rChartBBox.Left();
+            int nChartWinY = nY - rChartBBox.Top();
+
+            // no scale here the chart controller expects twips
+            // that are converted to hmm
+            util::URL aURL;
+            aURL.Path = "LOKSetTextSelection";
+            uno::Sequence< beans::PropertyValue > aArgs(3);
+            aArgs[0].Value <<= static_cast<sal_Int32>(nType);
+            aArgs[1].Value <<= static_cast<sal_Int32>(nChartWinX);
+            aArgs[2].Value <<= static_cast<sal_Int32>(nChartWinY);
+            xDispatcher->dispatch(aURL, aArgs);
+        }
+        return true;
+    }
+    return false;
+}
+
+bool LokChartHelper::setGraphicSelection(int nType, int nX, int nY,
+                                         double fScaleX, double fScaleY)
+{
+    tools::Rectangle rChartBBox = GetChartBoundingBox();
+    if (rChartBBox.IsInside(Point(nX, nY)))
+    {
+        int nChartWinX = nX - rChartBBox.Left();
+        int nChartWinY = nY - rChartBBox.Top();
+
+        vcl::Window* pChartWindow = GetWindow();
+
+        Point aPos(nChartWinX * fScaleX, nChartWinY * fScaleY);
+        switch (nType)
+        {
+        case LOK_SETGRAPHICSELECTION_START:
+            {
+                MouseEvent aClickEvent(aPos, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
+                pChartWindow->MouseButtonDown(aClickEvent);
+                MouseEvent aMoveEvent(aPos, 0, MouseEventModifiers::SIMPLEMOVE, MOUSE_LEFT);
+                pChartWindow->MouseMove(aMoveEvent);
+            }
+            break;
+        case LOK_SETGRAPHICSELECTION_END:
+            {
+                MouseEvent aMoveEvent(aPos, 0, MouseEventModifiers::SIMPLEMOVE, MOUSE_LEFT);
+                pChartWindow->MouseMove(aMoveEvent);
+                MouseEvent aClickEvent(aPos, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
+                pChartWindow->MouseButtonUp(aClickEvent);
+            }
+            break;
+        default:
+            assert(false);
+            break;
+        }
+        return true;
+    }
+    return false;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/view/viewsh.cxx b/sfx2/source/view/viewsh.cxx
index bfb0552d2d7d..80c91ef25b7c 100644
--- a/sfx2/source/view/viewsh.cxx
+++ b/sfx2/source/view/viewsh.cxx
@@ -832,9 +832,11 @@ SfxInPlaceClient* SfxViewShell::GetUIActiveClient() const
     if ( !pClients )
         return nullptr;
 
+    bool bIsTiledRendering = comphelper::LibreOfficeKit::isActive();
+
     for (SfxInPlaceClient* pIPClient : *pClients)
     {
-        if ( pIPClient->IsObjectUIActive() )
+        if ( pIPClient->IsObjectUIActive() || ( bIsTiledRendering && pIPClient->IsObjectInPlaceActive() ) )
             return pIPClient;
     }
 
@@ -1464,6 +1466,17 @@ void SfxViewShell::afterCallbackRegistered()
 {
 }
 
+vcl::Window* SfxViewShell::GetEditWindowForActiveOLEObj() const
+{
+    vcl::Window* pEditWin = nullptr;
+    SfxInPlaceClient* pIPClient = GetIPClient();
+    if (pIPClient)
+    {
+        pEditWin = pIPClient->GetEditWin();
+    }
+    return pEditWin;
+}
+
 void SfxViewShell::NotifyCursor(SfxViewShell* /*pViewShell*/) const
 {
 }
diff --git a/svx/source/svdraw/svdmrkv.cxx b/svx/source/svdraw/svdmrkv.cxx
index ce62affb411c..938ce9e60370 100644
--- a/svx/source/svdraw/svdmrkv.cxx
+++ b/svx/source/svdraw/svdmrkv.cxx
@@ -207,6 +207,22 @@ void SdrMarkView::ModelHasChanged()
             sSelection = "EMPTY";
         else
         {
+            sal_uInt32 nTotalPaintWindows = this->PaintWindowCount();
+            if (nTotalPaintWindows == 1)
+            {
+                const vcl::Window* pWin = dynamic_cast<const vcl::Window*>(this->GetFirstOutputDevice());
+                if (pWin && pWin->IsChart())
+                {
+                    const vcl::Window* pViewShellWindow = GetSfxViewShell()->GetEditWindowForActiveOLEObj();
+                    if (pViewShellWindow && pViewShellWindow->IsAncestorOf(*pWin))
+                    {
+                        Point aOffsetPx = pWin->GetOffsetPixelFrom(*pViewShellWindow);
+                        Point aLogicOffset = pWin->PixelToLogic(aOffsetPx);
+                        aSelection.Move(aLogicOffset.getX(), aLogicOffset.getY());
+                    }
+                }
+            }
+
             // In case the map mode is in 100th MM, then need to convert the coordinates over to twips for LOK.
             if (mpMarkedPV)
             {
@@ -732,10 +748,29 @@ void SdrMarkView::SetMarkHandles(SfxViewShell* pOtherShell)
         }
 
         tools::Rectangle aRect(GetMarkedObjRect());
+        tools::Rectangle aSelection(aRect);
+
+        if (bTiledRendering && !aRect.IsEmpty())
+        {
+            sal_uInt32 nTotalPaintWindows = this->PaintWindowCount();
+            if (nTotalPaintWindows == 1)
+            {
+                const vcl::Window* pWin = dynamic_cast<const vcl::Window*>(this->GetFirstOutputDevice());
+                if (pWin && pWin->IsChart())
+                {
+                    const vcl::Window* pViewShellWindow = GetSfxViewShell()->GetEditWindowForActiveOLEObj();
+                    if (pViewShellWindow && pViewShellWindow->IsAncestorOf(*pWin))
+                    {
+                        Point aOffsetPx = pWin->GetOffsetPixelFrom(*pViewShellWindow);
+                        Point aLogicOffset = pWin->PixelToLogic(aOffsetPx);
+                        aSelection.Move(aLogicOffset.getX(), aLogicOffset.getY());
+                    }
+                }
+            }
+        }
 
         if (bTiledRendering)
         {
-            tools::Rectangle aSelection(aRect);
             OString sSelection;
             if (aSelection.IsEmpty())
                 sSelection = "EMPTY";
diff --git a/svx/source/svdraw/svdpntv.cxx b/svx/source/svdraw/svdpntv.cxx
index 7642a1ce2e7b..4ac29efb0e08 100644
--- a/svx/source/svdraw/svdpntv.cxx
+++ b/svx/source/svdraw/svdpntv.cxx
@@ -59,6 +59,8 @@
 #include <comphelper/lok.hxx>
 #include <svx/svdviter.hxx>
 
+#include <sfx2/lokhelper.hxx>
+
 using namespace ::com::sun::star;
 
 // interface to SdrPaintWindow
@@ -1115,6 +1117,13 @@ void SdrPaintView::ShowItemBrowser(bool bShow)
 
 void SdrPaintView::MakeVisible(const tools::Rectangle& rRect, vcl::Window& rWin)
 {
+    // TODO: handle when the text cursor goes out of the chart area
+    // However this hack avoids that the cursor gets misplaced wrt the text.
+    if (comphelper::LibreOfficeKit::isActive() && rWin.IsChart())
+    {
+        return;
+    }
+
     MapMode aMap(rWin.GetMapMode());
     Size aActualSize(rWin.GetOutputSize());
 
diff --git a/sw/inc/unotxdoc.hxx b/sw/inc/unotxdoc.hxx
index ccbfb62589cd..9316b919137e 100644
--- a/sw/inc/unotxdoc.hxx
+++ b/sw/inc/unotxdoc.hxx
@@ -415,6 +415,8 @@ public:
     virtual bool isMimeTypeSupported() override;
     /// @see vcl::ITiledRenderable::setClientVisibleArea().
     virtual void setClientVisibleArea(const tools::Rectangle& rRectangle) override;
+    /// @see vcl::ITiledRenderable::setClientZoom.
+    virtual void setClientZoom(int nTilePixelWidth_, int nTilePixelHeight_, int nTileTwipWidth_, int nTileTwipHeight_) override;
     /// @see vcl::ITiledRenderable::getPointer().
     virtual Pointer getPointer() override;
     /// @see vcl::ITiledRenderable::getTrackedChanges().
diff --git a/sw/source/core/view/viewsh.cxx b/sw/source/core/view/viewsh.cxx
index 8a79a0896b60..2a2d46c95c39 100644
--- a/sw/source/core/view/viewsh.cxx
+++ b/sw/source/core/view/viewsh.cxx
@@ -25,6 +25,7 @@
 #include <svx/srchdlg.hxx>
 #include <svx/svdobj.hxx>
 #include <sfx2/viewsh.hxx>
+#include <sfx2/ipclient.hxx>
 #include <drawdoc.hxx>
 #include <swwait.hxx>
 #include <swmodule.hxx>
@@ -1885,10 +1886,12 @@ void SwViewShell::PaintTile(VirtualDevice &rDevice, int contextWidth, int contex
     rDevice.SetMapMode(aMapMode);
 
     // Update scaling of SwEditWin and its sub-widgets, needed for comments.
+    sal_uInt16 nOldZoomValue = 0;
     if (GetWin() && GetWin()->GetMapMode().GetScaleX() != scaleX)
     {
         double fScale = scaleX;
         SwViewOption aOption(*GetViewOptions());
+        nOldZoomValue = aOption.GetZoom();
         aOption.SetZoom(fScale * 100);
         ApplyViewOptions(aOption);
         // Make sure the map mode (disabled in SwXTextDocument::initializeForTiledRendering()) is still disabled.
@@ -1918,6 +1921,32 @@ void SwViewShell::PaintTile(VirtualDevice &rDevice, int contextWidth, int contex
         pPostItMgr->PaintTile(rDevice);
 
     // SwViewShell's output device tear down
+
+    // A view shell can get a PaintTile call for a tile at a zoom level
+    // different from the one, the related client really is.
+    // In such a case it is better to reset the current scale value to
+    // the original one, since such a value should be in synchronous with
+    // the zoom level in the client (see setClientZoom).
+    // At present the zoom value returned by GetViewOptions()->GetZoom() is
+    // used in SwXTextDocument methods (postMouseEvent and setGraphicSelection)
+    // for passing the correct mouse position to an edited chart (if any).
+    if (nOldZoomValue !=0)
+    {
+        SwViewOption aOption(*GetViewOptions());
+        aOption.SetZoom(nOldZoomValue);
+        ApplyViewOptions(aOption);
+
+        // Changing the zoom value doesn't always trigger the updating of
+        // the client ole object area, so we call it directly.
+        SfxInPlaceClient* pIPClient = GetSfxViewShell()->GetIPClient();
+        if (pIPClient)
+        {
+            pIPClient->VisAreaChanged();
+        }
+        // Make sure the map mode (disabled in SwXTextDocument::initializeForTiledRendering()) is still disabled.
+        GetWin()->EnableMapMode(false);
+    }
+
     mpOut = pSaveOut;
     comphelper::LibreOfficeKit::setTiledPainting(false);
 }
diff --git a/sw/source/uibase/uno/unotxdoc.cxx b/sw/source/uibase/uno/unotxdoc.cxx
index aca79a13c678..1e2473fdc6f8 100644
--- a/sw/source/uibase/uno/unotxdoc.cxx
+++ b/sw/source/uibase/uno/unotxdoc.cxx
@@ -37,6 +37,8 @@
 #include <toolkit/helper/vclunohelper.hxx>
 #include <toolkit/awt/vclxdevice.hxx>
 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <sfx2/lokcharthelper.hxx>
+#include <sfx2/ipclient.hxx>
 #include <editeng/svxacorr.hxx>
 #include <editeng/acorrcfg.hxx>
 #include <cmdid.h>
@@ -166,6 +168,8 @@
 #include <comphelper/servicehelper.hxx>
 #include <memory>
 
+#define TWIPS_PER_PIXEL 15
+
 using namespace ::com::sun::star;
 using namespace ::com::sun::star::text;
 using namespace ::com::sun::star::i18n;
@@ -3078,6 +3082,9 @@ void SwXTextDocument::paintTile( VirtualDevice &rDevice,
     SwViewShell* pViewShell = pDocShell->GetWrtShell();
     pViewShell->PaintTile(rDevice, nOutputWidth, nOutputHeight,
                           nTilePosX, nTilePosY, nTileWidth, nTileHeight);
+
+    LokChartHelper::PaintAllChartsOnTile(rDevice, nOutputWidth, nOutputHeight,
+                                         nTilePosX, nTilePosY, nTileWidth, nTileHeight);
 }
 
 Size SwXTextDocument::getDocumentSize()
@@ -3158,6 +3165,34 @@ void SwXTextDocument::setClientVisibleArea(const tools::Rectangle& rRectangle)
     pView->ForcePageUpDownOffset(2 * rRectangle.GetHeight() / 3);
 }
 
+void SwXTextDocument::setClientZoom(int nTilePixelWidth_, int /*nTilePixelHeight_*/,
+                                    int nTileTwipWidth_, int /*nTileTwipHeight_*/)
+{
+    // Here we set the zoom value as it has been set by the user in the client.
+    // This value is used in postMouseEvent and setGraphicSelection methods
+    // for in place chart editing. We assume that x and y scale is rougly
+    // the same.
+    // Indeed we could set mnTilePixelWidth, mnTilePixelHeight, mnTileTwipWidth,
+    // mnTileTwipHeight data members of this class but they are not very useful
+    // since we need to be able to retrieve the zoom value for each view shell.
+    SfxInPlaceClient* pIPClient = pDocShell->GetView()->GetIPClient();
+    if (pIPClient)
+    {
+        SwViewShell* pWrtViewShell = pDocShell->GetWrtShell();
+        double fScale = nTilePixelWidth_ * TWIPS_PER_PIXEL / (nTileTwipWidth_ * 1.0);
+        SwViewOption aOption(*(pWrtViewShell->GetViewOptions()));
+        if (aOption.GetZoom() != fScale * 100)
+        {
+            aOption.SetZoom(fScale * 100);
+            pWrtViewShell->ApplyViewOptions(aOption);
+
+            // Changing the zoom value doesn't always trigger the updating of
+            // the client ole object area, so we call it directly.
+            pIPClient->VisAreaChanged();
+        }
+    }
+}
+
 Pointer SwXTextDocument::getPointer()
 {
     SolarMutexGuard aGuard;
@@ -3322,6 +3357,11 @@ void SwXTextDocument::initializeForTiledRendering(const css::uno::Sequence<css::
         }
     }
 
+    // Set the initial zoom value to 1; usually it is set in setClientZoom and
+    // SwViewShell::PaintTile; zoom value is used for chart in place
+    // editing, see postMouseEvent and setGraphicSelection methods.
+    aViewOption.SetZoom(1 * 100);
+
     aViewOption.SetPostIts(comphelper::LibreOfficeKit::isTiledAnnotations());
     pViewShell->ApplyViewOptions(aViewOption);
 
@@ -3354,16 +3394,25 @@ void SwXTextDocument::postKeyEvent(int nType, int nCharCode, int nKeyCode)
 {
     SolarMutexGuard aGuard;
 
-    SwEditWin& rEditWin = pDocShell->GetView()->GetEditWin();
+    vcl::Window* pWindow = &(pDocShell->GetView()->GetEditWin());
+
+    SfxViewShell* pViewShell = pDocShell->GetView();
+    LokChartHelper aChartHelper(pViewShell);
+    vcl::Window* pChartWindow = aChartHelper.GetWindow();
+    if (pChartWindow)
+    {
+        pWindow = pChartWindow;
+    }
+
     KeyEvent aEvent(nCharCode, nKeyCode, 0);
 
     switch (nType)
     {
     case LOK_KEYEVENT_KEYINPUT:
-        rEditWin.KeyInput(aEvent);
+        pWindow->KeyInput(aEvent);
         break;
     case LOK_KEYEVENT_KEYUP:
-        rEditWin.KeyUp(aEvent);
+        pWindow->KeyUp(aEvent);
         break;
     default:
         assert(false);
@@ -3375,6 +3424,26 @@ void SwXTextDocument::postMouseEvent(int nType, int nX, int nY, int nCount, int
 {
     SolarMutexGuard aGuard;
 
+    SwViewShell* pWrtViewShell = pDocShell->GetWrtShell();
+    SwViewOption aOption(*(pWrtViewShell->GetViewOptions()));
+    double fScale = aOption.GetZoom() / (TWIPS_PER_PIXEL * 100.0);
+
+    // check if user hit a chart which is being edited by him
+    SfxViewShell* pViewShell = pDocShell->GetView();
+    LokChartHelper aChartHelper(pViewShell);
+    if (aChartHelper.postMouseEvent(nType, nX, nY,
+                                    nCount, nButtons, nModifier,
+                                    fScale, fScale))
+        return;
+
+    // check if the user hit a chart which is being edited by someone else
+    // and, if so, skip current mouse event
+    if (nType != LOK_MOUSEEVENT_MOUSEMOVE)
+    {
+        if (LokChartHelper::HitAny(Point(nX, nY)))
+            return;
+    }
+
     SwEditWin& rEditWin = pDocShell->GetView()->GetEditWin();
     Point aPos(nX , nY);
     MouseEvent aEvent(aPos, nCount, MouseEventModifiers::SIMPLECLICK, nButtons, nModifier);
@@ -3406,6 +3475,11 @@ void SwXTextDocument::setTextSelection(int nType, int nX, int nY)
 {
     SolarMutexGuard aGuard;
 
+    SfxViewShell* pViewShell = pDocShell->GetView();
+    LokChartHelper aChartHelper(pViewShell);
+    if (aChartHelper.setTextSelection(nType, nX, nY))
+        return;
+
     SwEditWin& rEditWin = pDocShell->GetView()->GetEditWin();
     switch (nType)
     {
@@ -3504,6 +3578,15 @@ void SwXTextDocument::setGraphicSelection(int nType, int nX, int nY)
 {
     SolarMutexGuard aGuard;
 
+    SwViewShell* pWrtViewShell = pDocShell->GetWrtShell();
+    SwViewOption aOption(*(pWrtViewShell->GetViewOptions()));
+    double fScale = aOption.GetZoom() / (TWIPS_PER_PIXEL * 100.0);
+
+    SfxViewShell* pViewShell = pDocShell->GetView();
+    LokChartHelper aChartHelper(pViewShell);
+    if (aChartHelper.setGraphicSelection(nType, nX, nY, fScale, fScale))
+        return;
+
     SwEditWin& rEditWin = pDocShell->GetView()->GetEditWin();
     switch (nType)
     {
diff --git a/vcl/source/window/stacking.cxx b/vcl/source/window/stacking.cxx
index 1aa805e0fdee..cb7c6ebf2b51 100644
--- a/vcl/source/window/stacking.cxx
+++ b/vcl/source/window/stacking.cxx
@@ -1005,6 +1005,11 @@ void Window::SetParent( vcl::Window* pNewParent )
         Show( true, ShowFlags::NoFocusChange | ShowFlags::NoActivate );
 }
 
+bool Window::IsAncestorOf( const vcl::Window& rWindow ) const
+{
+    return ImplIsRealParentPath(&rWindow);
+}
+
 sal_uInt16 Window::GetChildCount() const
 {
     if (!mpWindowImpl)
diff --git a/vcl/source/window/window2.cxx b/vcl/source/window/window2.cxx
index 6f1282736c5f..de44129ab447 100644
--- a/vcl/source/window/window2.cxx
+++ b/vcl/source/window/window2.cxx
@@ -1207,6 +1207,11 @@ bool Window::IsDefaultSize() const
     return mpWindowImpl->mbDefSize;
 }
 
+Point Window::GetOffsetPixelFrom(const vcl::Window& rWindow) const
+{
+    return Point(GetOutOffXPixel() - rWindow.GetOutOffXPixel(), GetOutOffYPixel() - rWindow.GetOutOffYPixel());
+}
+
 void Window::EnablePaint( bool bEnable )
 {
     mpWindowImpl->mbPaintDisabled = !bEnable;


More information about the Libreoffice-commits mailing list