diff options
author | Marco Cecchetti <marco.cecchetti@collabora.com> | 2017-06-27 23:35:08 +0200 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.co.uk> | 2017-08-03 12:32:51 +0200 |
commit | 0d3a367b5623639e7fdc9ce1ccc277e2597694a0 (patch) | |
tree | bd69a33834b9d85fd738c550015461453da5f16f | |
parent | 9a5c39ea56bbac48f30a1a4966caa68697d8b318 (diff) |
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 object can be moved and resized, text object can be edited.
Change-Id: I8e637dabf328a94bd6bb0e309a245302cff421d8
Reviewed-on: https://gerrit.libreoffice.org/40681
Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk>
Tested-by: Miklos Vajna <vmiklos@collabora.co.uk>
24 files changed, 977 insertions, 29 deletions
diff --git a/chart2/source/controller/inc/ChartController.hxx b/chart2/source/controller/inc/ChartController.hxx index 3b3449170eec..7b5b7882e99b 100644 --- a/chart2/source/controller/inc/ChartController.hxx +++ b/chart2/source/controller/inc/ChartController.hxx @@ -546,6 +546,8 @@ private: void executeDispatch_ToggleGridHorizontal(); void executeDispatch_ToggleGridVertical(); + void executeDispatch_LOKSetTextSelection(int nType, int nX, int nY); + void impl_ShapeControllerDispatch( const css::util::URL& rURL, const css::uno::Sequence< css::beans::PropertyValue >& rArgs ); diff --git a/chart2/source/controller/inc/ChartWindow.hxx b/chart2/source/controller/inc/ChartWindow.hxx index 6b0feaf440da..7883794a02bf 100644 --- a/chart2/source/controller/inc/ChartWindow.hxx +++ b/chart2/source/controller/inc/ChartWindow.hxx @@ -62,6 +62,7 @@ public: virtual void Invalidate( InvalidateFlags nFlags = InvalidateFlags::NONE ) override; virtual void Invalidate( const Rectangle& rRect, InvalidateFlags nFlags = InvalidateFlags::NONE ) override; virtual void Invalidate( const vcl::Region& rRegion, InvalidateFlags nFlags = InvalidateFlags::NONE ) override; + virtual void LogicInvalidate( const Rectangle* pRectangle ) override; virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessible() override; @@ -69,9 +70,17 @@ public: ChartController* GetController(); + virtual bool IsChart() const override { return true; } + vcl::Window* GetParentEditWin(); + +private: + // returns the chart bounding box in twips + Rectangle GetBoundingBox(); + private: ChartController* m_pWindowController; bool m_bInPaint; + VclPtr<vcl::Window> m_pViewShellWindow; VclPtr<OpenGLWindow> m_pOpenGLWindow; void adjustHighContrastMode(); diff --git a/chart2/source/controller/main/ChartController.cxx b/chart2/source/controller/main/ChartController.cxx index d40782f48920..ee622de47b69 100644 --- a/chart2/source/controller/main/ChartController.cxx +++ b/chart2/source/controller/main/ChartController.cxx @@ -1137,7 +1137,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 6ec875364fda..c06234ef7a0b 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; @@ -927,6 +931,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 4e7a7912165d..2989e32d4faa 100644 --- a/chart2/source/controller/main/ChartController_Window.cxx +++ b/chart2/source/controller/main/ChartController_Window.cxx @@ -866,7 +866,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 21cc0cefc2ab..d50a741cd001 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(); } @@ -114,6 +123,10 @@ void ChartWindow::PrePaint(vcl::RenderContext& rRenderContext) void ChartWindow::Paint(vcl::RenderContext& rRenderContext, const Rectangle& rRect) { + if (comphelper::LibreOfficeKit::isActive() + && rRenderContext.GetOutDevType() != OutDevType::OUTDEV_VIRDEV) + return; + m_bInPaint = true; if (m_pOpenGLWindow && m_pOpenGLWindow->IsVisible()) { @@ -307,6 +320,56 @@ void ChartWindow::Invalidate( const vcl::Region& rRegion, InvalidateFlags nFlags } } +void ChartWindow::LogicInvalidate(const Rectangle* pRectangle) +{ + OString sRectangle; + if (!pRectangle) + { + // we have to invalidate the whole chart area not the whole document + sRectangle = GetBoundingBox().toString(); + } + else + { + 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 = Rectangle(aRectangle.TopLeft() + aOffset, aRectangle.GetSize()); + } + + sRectangle = aRectangle.toString(); + } + SfxViewShell* pCurrentShell = SfxViewShell::Current(); + SfxLokHelper::notifyInvalidation(pCurrentShell, sRectangle); +} + FactoryFunction ChartWindow::GetUITestFactory() const { return ChartWindowUIObject::create; @@ -317,6 +380,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; +} + +Rectangle ChartWindow::GetBoundingBox() +{ + 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 = 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 e3a5291a5e0e..795447296b20 100644 --- a/editeng/source/editeng/impedit.cxx +++ b/editeng/source/editeng/impedit.cxx @@ -382,6 +382,17 @@ void ImpEditView::DrawSelection( EditSelection aTmpSel, vcl::Region* pRegion, Ou { std::vector<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 (Rectangle& rRect : aRectangles) + rRect.Move(aLogicOffset.getX(), aLogicOffset.getY()); + } + } if (!aRectangles.empty()) { @@ -1024,8 +1035,19 @@ void ImpEditView::ShowCursor( bool bGotoCursor, bool bForceVisCursor ) if (comphelper::LibreOfficeKit::isActive() && mpViewShell) { - const Point& rPos = GetCursor()->GetPos(); - 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()); + } + } + + 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 ae04cd0ccb40..7fe332587e43 100644 --- a/include/editeng/outliner.hxx +++ b/include/editeng/outliner.hxx @@ -385,6 +385,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..2d7e376c73e7 --- /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(); + Rectangle GetChartBoundingBox(); + void Invalidate(); + + bool Hit(const Point& aPos); + static bool HitAny(const Point& aPos); + void PaintTile(VirtualDevice& rRenderContext, const 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 2c93dd17bcd1..073b9c9259e2 100644 --- a/include/sfx2/viewsh.hxx +++ b/include/sfx2/viewsh.hxx @@ -341,6 +341,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 7d6f69ce9b28..496a0743562c 100644 --- a/include/vcl/window.hxx +++ b/include/vcl/window.hxx @@ -939,6 +939,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 ); } @@ -1038,6 +1039,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; @@ -1548,6 +1550,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 917d03e15155..473a8dcb17ac 100644 --- a/sc/source/ui/unoobj/docuno.cxx +++ b/sc/source/ui/unoobj/docuno.cxx @@ -48,6 +48,7 @@ #include <tools/multisel.hxx> #include <tools/resary.hxx> #include <toolkit/awt/vclxdevice.hxx> +#include <toolkit/helper/vclunohelper.hxx> #include <unotools/saveopt.hxx> #include <ctype.h> @@ -74,6 +75,7 @@ #include <opencl/platforminfo.hxx> #endif #include <sfx2/lokhelper.hxx> +#include <sfx2/lokcharthelper.hxx> #include "cellsuno.hxx" #include <columnspanset.hxx> @@ -502,6 +504,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 ) @@ -581,20 +586,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); @@ -618,6 +631,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, @@ -656,9 +686,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(); @@ -835,9 +869,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 7791e4180123..6b852e2cb5bb 100644 --- a/sd/source/ui/unoidl/unomodel.cxx +++ b/sd/source/ui/unoidl/unomodel.cxx @@ -117,6 +117,10 @@ #include <drawinglayer/primitive2d/structuretagprimitive2d.hxx> +#include <sfx2/lokcharthelper.hxx> + +#define TWIPS_PER_PIXEL 15 + using namespace ::osl; using namespace ::cppu; using namespace ::com::sun::star; @@ -2289,15 +2293,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 ); @@ -2305,11 +2309,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); 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 ) @@ -2488,10 +2495,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) @@ -2515,6 +2529,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))); @@ -2552,6 +2584,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) { @@ -2589,6 +2625,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 17fd09f772dc..d3a4f69ca1cf 100644 --- a/sfx2/Library_sfx.mk +++ b/sfx2/Library_sfx.mk @@ -303,6 +303,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 e894546b4346..1c9d9a062c9d 100644 --- a/sfx2/source/view/ipclient.cxx +++ b/sfx2/source/view/ipclient.cxx @@ -63,6 +63,8 @@ #include <svtools/soerr.hxx> #include <comphelper/processfactory.hxx> +#include <sfx2/lokhelper.hxx> + #define SFX_CLIENTACTIVATE_TIMEOUT 100 using namespace com::sun::star; @@ -426,7 +428,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 ); } @@ -443,7 +465,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 ); } @@ -928,7 +965,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 { @@ -979,8 +1022,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..f5b4ba37c663 --- /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(); +} + +Rectangle LokChartHelper::GetChartBoundingBox() +{ + 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 = 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) + { + 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 Rectangle& rTileRect) +{ + if (mpViewShell) + { + vcl::Window* pChartWindow = GetWindow(); + if (pChartWindow) + { + Rectangle aChartRect = GetChartBoundingBox(); + 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()); + 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); + + 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) + { + 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) +{ + 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) +{ + 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 dbc6bc3a8c4c..e763676167d6 100644 --- a/sfx2/source/view/viewsh.cxx +++ b/sfx2/source/view/viewsh.cxx @@ -856,9 +856,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; } @@ -1498,6 +1500,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 c379541d4dd8..729778bb9cf4 100644 --- a/svx/source/svdraw/svdmrkv.cxx +++ b/svx/source/svdraw/svdmrkv.cxx @@ -214,6 +214,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) { @@ -739,10 +755,29 @@ void SdrMarkView::SetMarkHandles(SfxViewShell* pOtherShell) } Rectangle aRect(GetMarkedObjRect()); + 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) { - 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 c374c756e599..24936e9e5fee 100644 --- a/svx/source/svdraw/svdpntv.cxx +++ b/svx/source/svdraw/svdpntv.cxx @@ -62,6 +62,8 @@ #include <comphelper/lok.hxx> #include <svx/svdviter.hxx> +#include <sfx2/lokhelper.hxx> + using namespace ::com::sun::star; // interface to SdrPaintWindow @@ -1118,6 +1120,13 @@ void SdrPaintView::ShowItemBrowser(bool bShow) void SdrPaintView::MakeVisible(const 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 0560b41a04c9..a0af69fbc5bc 100644 --- a/sw/inc/unotxdoc.hxx +++ b/sw/inc/unotxdoc.hxx @@ -436,6 +436,8 @@ public: virtual bool isMimeTypeSupported() override; /// @see vcl::ITiledRenderable::setClientVisibleArea(). virtual void setClientVisibleArea(const 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 923ed6205876..ca5768373ad1 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> @@ -1868,10 +1869,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. @@ -1901,6 +1904,32 @@ void SwViewShell::PaintTile(VirtualDevice &rDevice, int contextWidth, int contex pPostItMgr->PaintTile(rDevice, aOutRect); // 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 7ef82e34934d..4fae34bb4565 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; @@ -3142,6 +3146,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() @@ -3222,6 +3229,34 @@ void SwXTextDocument::setClientVisibleArea(const 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; @@ -3389,6 +3424,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); @@ -3421,16 +3461,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); @@ -3442,6 +3491,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); @@ -3473,6 +3542,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) { @@ -3571,6 +3645,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 019dc0545b24..06720a588896 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 68a1dd554efd..559492bf2d6e 100644 --- a/vcl/source/window/window2.cxx +++ b/vcl/source/window/window2.cxx @@ -1223,6 +1223,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; |