summaryrefslogtreecommitdiff
path: root/sfx2
diff options
context:
space:
mode:
authorMarco Cecchetti <marco.cecchetti@collabora.com>2017-06-27 23:35:08 +0200
committerMiklos Vajna <vmiklos@collabora.co.uk>2017-08-03 12:32:51 +0200
commit0d3a367b5623639e7fdc9ce1ccc277e2597694a0 (patch)
treebd69a33834b9d85fd738c550015461453da5f16f /sfx2
parent9a5c39ea56bbac48f30a1a4966caa68697d8b318 (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>
Diffstat (limited to 'sfx2')
-rw-r--r--sfx2/Library_sfx.mk1
-rw-r--r--sfx2/source/view/ipclient.cxx56
-rw-r--r--sfx2/source/view/lokcharthelper.cxx373
-rw-r--r--sfx2/source/view/viewsh.cxx15
4 files changed, 440 insertions, 5 deletions
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
{
}