diff options
author | Marco Cecchetti <marco.cecchetti@collabora.com> | 2017-06-27 23:35:08 +0200 |
---|---|---|
committer | Marco Cecchetti <mrcekets@gmail.com> | 2017-08-03 10:58:59 +0200 |
commit | eba883c8a2ce045fc7bd3848d796ca10b7f4ba51 (patch) | |
tree | a6a5684a36725e67a24eab86fa984c38252cb2d9 /sfx2 | |
parent | 166f13ef65b4a0eb9927eff2ffe5bac319785ee7 (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 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@libreoffice.org>
Reviewed-by: Marco Cecchetti <mrcekets@gmail.com>
Diffstat (limited to 'sfx2')
-rw-r--r-- | sfx2/Library_sfx.mk | 1 | ||||
-rw-r--r-- | sfx2/source/view/ipclient.cxx | 56 | ||||
-rw-r--r-- | sfx2/source/view/lokcharthelper.cxx | 373 | ||||
-rw-r--r-- | sfx2/source/view/viewsh.cxx | 15 |
4 files changed, 440 insertions, 5 deletions
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 { } |