LibreOffice Module sfx2 (master) 1
lokcharthelper.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
9
11
12#include <comphelper/lok.hxx>
14#include <LibreOfficeKit/LibreOfficeKitEnums.h>
15#include <sfx2/ipclient.hxx>
16#include <sfx2/lokhelper.hxx>
18#include <tools/fract.hxx>
20#include <vcl/virdev.hxx>
21#include <vcl/window.hxx>
22
23#include <com/sun/star/embed/XEmbeddedObject.hpp>
24#include <com/sun/star/frame/XDispatch.hpp>
25#include <com/sun/star/chart2/XChartDocument.hpp>
26
27using namespace com::sun::star;
28
29css::uno::Reference<css::frame::XController>& LokChartHelper::GetXController()
30{
31 if(!mxController.is() && mpViewShell)
32 {
34 if (pIPClient)
35 {
36 const css::uno::Reference< ::css::embed::XEmbeddedObject >& xEmbObj = pIPClient->GetObject();
37 if( xEmbObj.is() )
38 {
39 ::css::uno::Reference< ::css::chart2::XChartDocument > xChart( xEmbObj->getComponent(), uno::UNO_QUERY );
40 if( xChart.is() )
41 {
42 ::css::uno::Reference< ::css::frame::XController > xChartController = xChart->getCurrentController();
43 if( xChartController.is() )
44 {
45 mxController = xChartController;
46 }
47 }
48 }
49 }
50 }
51
52 return mxController;
53}
54
55css::uno::Reference<css::frame::XDispatch>& LokChartHelper::GetXDispatcher()
56{
57 if( !mxDispatcher.is() )
58 {
59 ::css::uno::Reference< ::css::frame::XController >& xChartController = GetXController();
60 if( xChartController.is() )
61 {
62 ::css::uno::Reference< ::css::frame::XDispatch > xDispatcher( xChartController, uno::UNO_QUERY );
63 if( xDispatcher.is() )
64 {
65 mxDispatcher = xDispatcher;
66 }
67 }
68 }
69
70 return mxDispatcher;
71}
72
74{
75 if (!mpWindow)
76 {
77 ::css::uno::Reference< ::css::frame::XController >& xChartController = GetXController();
78 if( xChartController.is() )
79 {
80 ::css::uno::Reference< ::css::frame::XFrame > xFrame = xChartController->getFrame();
81 if (xFrame.is())
82 {
83 ::css::uno::Reference< ::css::awt::XWindow > xDockerWin = xFrame->getContainerWindow();
84 vcl::Window* pParent = VCLUnoHelper::GetWindow( xDockerWin );
85 if (pParent)
86 {
87 sal_uInt16 nTotChildren = pParent->GetChildCount();
88 while (nTotChildren--)
89 {
90 vcl::Window* pChildWin = pParent->GetChild(nTotChildren);
91 if (pChildWin && pChildWin->IsChart())
92 {
93 mpWindow = pChildWin;
94 break;
95 }
96 }
97 }
98 }
99 }
100 }
101
102 return mpWindow.get();
103}
104
106{
107 tools::Rectangle aBBox;
108 if (mpViewShell)
109 {
111 if (pIPClient)
112 {
113 vcl::Window* pRootWin = pIPClient->GetEditWin();
114 if (pRootWin)
115 {
116 vcl::Window* pWindow = GetWindow();
117 if (pWindow)
118 {
119 // In all cases, the following code fragment
120 // returns the chart bounding box in twips.
121 const MapMode& aCWMapMode = pWindow->GetMapMode();
122 constexpr auto p = o3tl::getConversionMulDiv(o3tl::Length::px, o3tl::Length::twip);
123 const auto& scaleX = aCWMapMode.GetScaleX();
124 const auto& scaleY = aCWMapMode.GetScaleY();
125 const auto nXNum = p.first * scaleX.GetDenominator();
126 const auto nXDen = p.second * scaleX.GetNumerator();
127 const auto nYNum = p.first * scaleY.GetDenominator();
128 const auto nYDen = p.second * scaleY.GetNumerator();
129
130 Point aOffset = pWindow->GetOffsetPixelFrom(*pRootWin);
132 {
133 // If global RTL flag is set, vcl-window X offset of chart window is
134 // mirrored w.r.t parent window rectangle. This needs to be reverted.
135 aOffset.setX(pRootWin->GetOutOffXPixel() + pRootWin->GetSizePixel().Width()
136 - pWindow->GetOutOffXPixel() - pWindow->GetSizePixel().Width());
137
138 }
139
140 aOffset = aOffset.scale(nXNum, nXDen, nYNum, nYDen);
141 Size aSize = pWindow->GetSizePixel().scale(nXNum, nXDen, nYNum, nYDen);
142 aBBox = tools::Rectangle(aOffset, aSize);
143 }
144 }
145 }
146 }
147 return aBBox;
148}
149
151{
152 mpWindow = nullptr;
153 mxDispatcher.clear();
154 mxController.clear();
155}
156
157bool LokChartHelper::Hit(const Point& aPos)
158{
159 if (mpViewShell)
160 {
161 vcl::Window* pChartWindow = GetWindow();
162 if (pChartWindow)
163 {
165 return rChartBBox.Contains(aPos);
166 }
167 }
168 return false;
169}
170
171bool LokChartHelper::HitAny(const Point& aPos, bool bNegativeX)
172{
174 int nPartForCurView = pCurView ? pCurView->getPart() : -1;
175 SfxViewShell* pViewShell = SfxViewShell::GetFirst();
176 while (pViewShell)
177 {
178 if (pViewShell->GetDocId() == pCurView->GetDocId() && pViewShell->getPart() == nPartForCurView)
179 {
180 LokChartHelper aChartHelper(pViewShell, bNegativeX);
181 if (aChartHelper.Hit(aPos))
182 return true;
183 }
184 pViewShell = SfxViewShell::GetNext(*pViewShell);
185 }
186 return false;
187}
188
189void LokChartHelper::PaintTile(VirtualDevice& rRenderContext, const tools::Rectangle& rTileRect)
190{
191 if (!mpViewShell)
192 return;
193
194 vcl::Window* pChartWindow = GetWindow();
195 if (!pChartWindow)
196 return;
197
199 tools::Rectangle aTestRect = rTileRect;
200 aTestRect.Intersection( aChartRect );
201 if (aTestRect.IsEmpty())
202 return;
203
204 Point aOffset( aChartRect.Left() - rTileRect.Left(), aChartRect.Top() - rTileRect.Top() );
205 Point aOffsetFromTile = convertTwipToMm100(aOffset);
206 Size aSize = convertTwipToMm100(aChartRect.GetSize());
207 tools::Rectangle aRectangle(Point(0,0), aSize);
208
209 bool bEnableMapMode = !pChartWindow->IsMapModeEnabled();
210 pChartWindow->EnableMapMode();
211 bool bRenderContextEnableMapMode = !rRenderContext.IsMapModeEnabled();
212 rRenderContext.EnableMapMode();
213
214 rRenderContext.Push(vcl::PushFlags::MAPMODE);
215
216 MapMode aCWMapMode = pChartWindow->GetMapMode();
217 aCWMapMode.SetScaleX(rRenderContext.GetMapMode().GetScaleX());
218 aCWMapMode.SetScaleY(rRenderContext.GetMapMode().GetScaleY());
219
220 aCWMapMode.SetOrigin(aOffsetFromTile);
221 rRenderContext.SetMapMode(aCWMapMode);
222
223 pChartWindow->Paint(rRenderContext, aRectangle);
224
225 rRenderContext.Pop();
226
227 if (bRenderContextEnableMapMode)
228 rRenderContext.EnableMapMode(false);
229 if (bEnableMapMode)
230 pChartWindow->EnableMapMode(false);
231}
232
234 int nOutputWidth, int nOutputHeight,
235 int nTilePosX, int nTilePosY,
236 tools::Long nTileWidth, tools::Long nTileHeight,
237 bool bNegativeX)
238{
240 return;
241
242 // Resizes the virtual device so to contain the entries context
243 rDevice.SetOutputSizePixel(Size(nOutputWidth, nOutputHeight));
244
246 MapMode aMapMode(rDevice.GetMapMode());
247
248 // Scaling. Must convert from pixels to twips. We know
249 // that VirtualDevices use a DPI of 96.
251 Fraction scaleX = Fraction(nOutputWidth, nTileWidth) * scale;
252 Fraction scaleY = Fraction(nOutputHeight, nTileHeight) * scale;
253 aMapMode.SetScaleX(scaleX);
254 aMapMode.SetScaleY(scaleY);
255 rDevice.SetMapMode(aMapMode);
256
258 int nPartForCurView = pCurView ? pCurView->getPart() : -1;
259 tools::Long nTileRectLeft = bNegativeX ? -nTilePosX - nTileWidth : nTilePosX;
260 tools::Rectangle aTileRect(Point(nTileRectLeft, nTilePosY), Size(nTileWidth, nTileHeight));
261 SfxViewShell* pViewShell = SfxViewShell::GetFirst();
262 while (pViewShell)
263 {
264 if (pCurView && pViewShell->GetDocId() == pCurView->GetDocId() && pViewShell->getPart() == nPartForCurView)
265 {
266 LokChartHelper aChartHelper(pViewShell, bNegativeX);
267 aChartHelper.PaintTile(rDevice, aTileRect);
268 }
269 pViewShell = SfxViewShell::GetNext(*pViewShell);
270 }
271 rDevice.Pop();
272}
273
274bool LokChartHelper::postMouseEvent(int nType, int nX, int nY,
275 int nCount, int nButtons, int nModifier,
276 double fScaleX, double fScaleY)
277{
278 Point aMousePos(nX, nY);
279 vcl::Window* pChartWindow = GetWindow();
280 if (pChartWindow)
281 {
283 if (rChartBBox.Contains(aMousePos))
284 {
285 int nChartWinX = nX - rChartBBox.Left();
286 int nChartWinY = nY - rChartBBox.Top();
287
288 // chart window expects pixels, but the conversion factor
289 // can depend on the client zoom
290 Point aPos(nChartWinX * fScaleX, nChartWinY * fScaleY);
291
292 LokMouseEventData aMouseEventData(nType, aPos, nCount, MouseEventModifiers::SIMPLECLICK,
293 nButtons, nModifier);
294 SfxLokHelper::postMouseEventAsync(pChartWindow, aMouseEventData);
295
296 return true;
297 }
298 }
299 return false;
300}
301
302bool LokChartHelper::setTextSelection(int nType, int nX, int nY)
303{
305 if (rChartBBox.Contains(Point(nX, nY)))
306 {
307 css::uno::Reference<css::frame::XDispatch> xDispatcher = GetXDispatcher();
308 if (xDispatcher.is())
309 {
310 int nChartWinX = nX - rChartBBox.Left();
311 int nChartWinY = nY - rChartBBox.Top();
312
313 // no scale here the chart controller expects twips
314 // that are converted to hmm
315 util::URL aURL;
316 aURL.Path = "LOKSetTextSelection";
317 uno::Sequence< beans::PropertyValue > aArgs{
318 comphelper::makePropertyValue({}, static_cast<sal_Int32>(nType)), // Why no name?
319 comphelper::makePropertyValue({}, static_cast<sal_Int32>(nChartWinX)),
320 comphelper::makePropertyValue({}, static_cast<sal_Int32>(nChartWinY))
321 };
322 xDispatcher->dispatch(aURL, aArgs);
323 }
324 return true;
325 }
326 return false;
327}
328
329bool LokChartHelper::setGraphicSelection(int nType, int nX, int nY,
330 double fScaleX, double fScaleY)
331{
333 if (rChartBBox.Contains(Point(nX, nY)))
334 {
335 int nChartWinX = nX - rChartBBox.Left();
336 int nChartWinY = nY - rChartBBox.Top();
337
338 vcl::Window* pChartWindow = GetWindow();
339
340 Point aPos(nChartWinX * fScaleX, nChartWinY * fScaleY);
341 switch (nType)
342 {
343 case LOK_SETGRAPHICSELECTION_START:
344 {
345 MouseEvent aClickEvent(aPos, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
346 pChartWindow->MouseButtonDown(aClickEvent);
347 MouseEvent aMoveEvent(aPos, 0, MouseEventModifiers::SIMPLEMOVE, MOUSE_LEFT);
348 pChartWindow->MouseMove(aMoveEvent);
349 }
350 break;
351 case LOK_SETGRAPHICSELECTION_END:
352 {
353 MouseEvent aMoveEvent(aPos, 0, MouseEventModifiers::SIMPLEMOVE, MOUSE_LEFT);
354 pChartWindow->MouseMove(aMoveEvent);
355 MouseEvent aClickEvent(aPos, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
356 pChartWindow->MouseButtonUp(aClickEvent);
357 }
358 break;
359 default:
360 assert(false);
361 break;
362 }
363 return true;
364 }
365 return false;
366}
367
368
369/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Fraction conversionFract(o3tl::Length from, o3tl::Length to)
constexpr auto convertTwipToMm100(N n)
static bool GetLayoutRTL()
A class for chart editing support via LibreOfficeKit.
bool setGraphicSelection(int nType, int nX, int nY, double fScaleX=1.0, double fScaleY=1.0)
tools::Rectangle GetChartBoundingBox()
static bool HitAny(const Point &aPos, bool bNegativeX=false)
bool Hit(const Point &aPos)
bool setTextSelection(int nType, int nX, int nY)
css::uno::Reference< css::frame::XController > mxController
static void PaintAllChartsOnTile(VirtualDevice &rDevice, int nOutputWidth, int nOutputHeight, int nTilePosX, int nTilePosY, tools::Long nTileWidth, tools::Long nTileHeight, bool bNegativeX=false)
void PaintTile(VirtualDevice &rRenderContext, const tools::Rectangle &rTileRect)
SfxViewShell * mpViewShell
bool postMouseEvent(int nType, int nX, int nY, int nCount, int nButtons, int nModifier, double fScaleX=1.0, double fScaleY=1.0)
css::uno::Reference< css::frame::XDispatch > mxDispatcher
css::uno::Reference< css::frame::XController > & GetXController()
vcl::Window * GetWindow()
VclPtr< vcl::Window > mpWindow
css::uno::Reference< css::frame::XDispatch > & GetXDispatcher()
void SetOrigin(const Point &rOrigin)
void SetScaleY(const Fraction &rScaleY)
const Fraction & GetScaleX() const
const Fraction & GetScaleY() const
void SetScaleX(const Fraction &rScaleX)
void EnableMapMode(bool bEnable=true)
void SetMapMode()
const MapMode & GetMapMode() const
void Push(vcl::PushFlags nFlags=vcl::PushFlags::ALL)
bool IsMapModeEnabled() const
void setX(tools::Long nX)
constexpr Point scale(sal_Int64 nMulX, sal_Int64 nDivX, sal_Int64 nMulY, sal_Int64 nDivY) const
const css::uno::Reference< css::embed::XEmbeddedObject > & GetObject() const
Definition: ipclient.cxx:700
vcl::Window * GetEditWin() const
Definition: ipclient.hxx:67
static void postMouseEventAsync(const VclPtr< vcl::Window > &xWindow, LokMouseEventData const &rLokMouseEventData)
Helper for posting async mouse event.
Definition: lokhelper.cxx:929
One SfxViewShell more or less represents one edit window for a document, there can be multiple ones f...
Definition: viewsh.hxx:165
ViewShellDocId GetDocId() const override
Get the DocId used by Mobile LOKit to load multiple documents.
Definition: viewsh.cxx:2436
static SAL_WARN_UNUSED_RESULT SfxViewShell * GetNext(const SfxViewShell &rPrev, bool bOnlyVisible=true, const std::function< bool(const SfxViewShell *)> &isViewShell=nullptr)
Definition: viewsh.cxx:2046
static SAL_WARN_UNUSED_RESULT SfxViewShell * GetFirst(bool bOnlyVisible=true, const std::function< bool(const SfxViewShell *)> &isViewShell=nullptr)
Definition: viewsh.cxx:2017
static SAL_WARN_UNUSED_RESULT SfxViewShell * Current()
Definition: viewsh.cxx:1848
SfxInPlaceClient * GetIPClient() const
Definition: viewsh.cxx:1494
virtual int getPart() const
See lok::Document::getPart().
Definition: viewsh.cxx:2416
constexpr Size scale(sal_Int64 nMulX, sal_Int64 nDivX, sal_Int64 nMulY, sal_Int64 nDivY) const
constexpr tools::Long Width() const
static vcl::Window * GetWindow(const css::uno::Reference< css::awt::XWindow > &rxWindow)
reference_type * get() const
bool SetOutputSizePixel(const Size &rNewSize, bool bErase=true, bool bAlphaMaskTransparent=false)
bool Contains(const Point &rPOINT) const
constexpr tools::Long Top() const
constexpr Size GetSize() const
tools::Rectangle & Intersection(const tools::Rectangle &rRect)
constexpr tools::Long Left() const
constexpr bool IsEmpty() const
tools::Long GetOutOffXPixel() const
Point GetOffsetPixelFrom(const vcl::Window &rWindow) const
sal_uInt16 GetChildCount() const
virtual void MouseButtonDown(const MouseEvent &rMEvt)
virtual bool IsChart() const
bool IsMapModeEnabled() const
virtual void MouseButtonUp(const MouseEvent &rMEvt)
virtual void Paint(vcl::RenderContext &rRenderContext, const tools::Rectangle &rRect)
const MapMode & GetMapMode() const
virtual void MouseMove(const MouseEvent &rMEvt)
virtual Size GetSizePixel() const
void EnableMapMode(bool bEnable=true)
vcl::Window * GetChild(sal_uInt16 nChild) const
int nCount
URL aURL
#define MOUSE_LEFT
void * p
css::beans::PropertyValue makePropertyValue(const OUString &rName, T &&rValue)
long Long
sal_Int32 scale
QPRO_FUNC_TYPE nType
Reference< XFrame > xFrame