1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
10 #include <sfx2/lokcomponenthelpers.hxx>
12 #include <comphelper/lok.hxx>
13 #include <comphelper/propertyvalue.hxx>
14 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
15 #include <sfx2/ipclient.hxx>
16 #include <sfx2/lokhelper.hxx>
17 #include <toolkit/helper/vclunohelper.hxx>
18 #include <tools/fract.hxx>
19 #include <tools/UnitConversion.hxx>
20 #include <vcl/virdev.hxx>
21 #include <vcl/window.hxx>
23 #include <com/sun/star/embed/XEmbeddedObject.hpp>
24 #include <com/sun/star/frame/XDispatch.hpp>
25 #include <com/sun/star/chart2/XChartDocument.hpp>
27 using namespace com::sun::star
;
29 css::uno::Reference
<css::frame::XController
>& LokChartHelper::GetXController()
31 if(!mxController
.is() && mpViewShell
)
33 SfxInPlaceClient
* pIPClient
= mpViewShell
->GetIPClient();
36 const css::uno::Reference
< ::css::embed::XEmbeddedObject
>& xEmbObj
= pIPClient
->GetObject();
39 ::css::uno::Reference
< ::css::chart2::XChartDocument
> xChart( xEmbObj
->getComponent(), uno::UNO_QUERY
);
42 ::css::uno::Reference
< ::css::frame::XController
> xChartController
= xChart
->getCurrentController();
43 if( xChartController
.is() )
45 mxController
= xChartController
;
55 css::uno::Reference
<css::frame::XDispatch
>& LokChartHelper::GetXDispatcher()
57 if( !mxDispatcher
.is() )
59 ::css::uno::Reference
< ::css::frame::XController
>& xChartController
= GetXController();
60 if( xChartController
.is() )
62 ::css::uno::Reference
< ::css::frame::XDispatch
> xDispatcher( xChartController
, uno::UNO_QUERY
);
63 if( xDispatcher
.is() )
65 mxDispatcher
= xDispatcher
;
73 vcl::Window
* LokChartHelper::GetWindow()
77 ::css::uno::Reference
< ::css::frame::XController
>& xChartController
= GetXController();
78 if( xChartController
.is() )
80 ::css::uno::Reference
< ::css::frame::XFrame
> xFrame
= xChartController
->getFrame();
83 ::css::uno::Reference
< ::css::awt::XWindow
> xDockerWin
= xFrame
->getContainerWindow();
84 vcl::Window
* pParent
= VCLUnoHelper::GetWindow( xDockerWin
);
87 sal_uInt16 nTotChildren
= pParent
->GetChildCount();
88 while (nTotChildren
--)
90 vcl::Window
* pChildWin
= pParent
->GetChild(nTotChildren
);
91 if (pChildWin
&& pChildWin
->IsChart())
102 return mpWindow
.get();
105 tools::Rectangle
LokChartHelper::GetChartBoundingBox()
107 tools::Rectangle aBBox
;
110 SfxInPlaceClient
* pIPClient
= mpViewShell
->GetIPClient();
113 vcl::Window
* pRootWin
= pIPClient
->GetEditWin();
116 vcl::Window
* pWindow
= GetWindow();
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();
130 Point aOffset
= pWindow
->GetOffsetPixelFrom(*pRootWin
);
131 if (mbNegativeX
&& AllSettings::GetLayoutRTL())
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());
140 aOffset
= aOffset
.scale(nXNum
, nXDen
, nYNum
, nYDen
);
141 Size aSize
= pWindow
->GetSizePixel().scale(nXNum
, nXDen
, nYNum
, nYDen
);
142 aBBox
= tools::Rectangle(aOffset
, aSize
);
150 void LokChartHelper::Invalidate()
153 mxDispatcher
.clear();
154 mxController
.clear();
157 bool LokChartHelper::Hit(const Point
& aPos
)
161 vcl::Window
* pChartWindow
= GetWindow();
164 tools::Rectangle rChartBBox
= GetChartBoundingBox();
165 return rChartBBox
.Contains(aPos
);
171 bool LokChartHelper::HitAny(const Point
& aPos
, bool bNegativeX
)
173 SfxViewShell
* pCurView
= SfxViewShell::Current();
174 int nPartForCurView
= pCurView
? pCurView
->getPart() : -1;
175 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
178 if (pViewShell
->GetDocId() == pCurView
->GetDocId() && pViewShell
->getPart() == nPartForCurView
)
180 LokChartHelper
aChartHelper(pViewShell
, bNegativeX
);
181 if (aChartHelper
.Hit(aPos
))
184 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
189 void LokChartHelper::PaintTile(VirtualDevice
& rRenderContext
, const tools::Rectangle
& rTileRect
)
194 vcl::Window
* pChartWindow
= GetWindow();
198 tools::Rectangle aChartRect
= GetChartBoundingBox();
199 tools::Rectangle aTestRect
= rTileRect
;
200 aTestRect
.Intersection( aChartRect
);
201 if (aTestRect
.IsEmpty())
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
);
209 bool bEnableMapMode
= !pChartWindow
->IsMapModeEnabled();
210 pChartWindow
->EnableMapMode();
211 bool bRenderContextEnableMapMode
= !rRenderContext
.IsMapModeEnabled();
212 rRenderContext
.EnableMapMode();
214 rRenderContext
.Push(vcl::PushFlags::MAPMODE
);
216 MapMode aCWMapMode
= pChartWindow
->GetMapMode();
217 aCWMapMode
.SetScaleX(rRenderContext
.GetMapMode().GetScaleX());
218 aCWMapMode
.SetScaleY(rRenderContext
.GetMapMode().GetScaleY());
220 aCWMapMode
.SetOrigin(aOffsetFromTile
);
221 rRenderContext
.SetMapMode(aCWMapMode
);
223 pChartWindow
->Paint(rRenderContext
, aRectangle
);
225 rRenderContext
.Pop();
227 if (bRenderContextEnableMapMode
)
228 rRenderContext
.EnableMapMode(false);
230 pChartWindow
->EnableMapMode(false);
233 void LokChartHelper::PaintAllChartsOnTile(VirtualDevice
& rDevice
,
234 int nOutputWidth
, int nOutputHeight
,
235 int nTilePosX
, int nTilePosY
,
236 tools::Long nTileWidth
, tools::Long nTileHeight
,
239 if (comphelper::LibreOfficeKit::isTiledAnnotations())
242 // Resizes the virtual device so to contain the entries context
243 rDevice
.SetOutputSizePixel(Size(nOutputWidth
, nOutputHeight
));
245 rDevice
.Push(vcl::PushFlags::MAPMODE
);
246 MapMode
aMapMode(rDevice
.GetMapMode());
248 // Scaling. Must convert from pixels to twips. We know
249 // that VirtualDevices use a DPI of 96.
250 const Fraction scale
= conversionFract(o3tl::Length::px
, o3tl::Length::twip
);
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
);
257 SfxViewShell
* pCurView
= SfxViewShell::Current();
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();
264 if (pCurView
&& pViewShell
->GetDocId() == pCurView
->GetDocId() && pViewShell
->getPart() == nPartForCurView
)
266 LokChartHelper
aChartHelper(pViewShell
, bNegativeX
);
267 aChartHelper
.PaintTile(rDevice
, aTileRect
);
269 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
274 bool LokChartHelper::postMouseEvent(int nType
, int nX
, int nY
,
275 int nCount
, int nButtons
, int nModifier
,
276 double fScaleX
, double fScaleY
)
278 Point
aMousePos(nX
, nY
);
279 vcl::Window
* pChartWindow
= GetWindow();
282 tools::Rectangle rChartBBox
= GetChartBoundingBox();
283 if (rChartBBox
.Contains(aMousePos
))
285 int nChartWinX
= nX
- rChartBBox
.Left();
286 int nChartWinY
= nY
- rChartBBox
.Top();
288 // chart window expects pixels, but the conversion factor
289 // can depend on the client zoom
290 Point
aPos(nChartWinX
* fScaleX
, nChartWinY
* fScaleY
);
292 LokMouseEventData
aMouseEventData(nType
, aPos
, nCount
, MouseEventModifiers::SIMPLECLICK
,
293 nButtons
, nModifier
);
294 SfxLokHelper::postMouseEventAsync(pChartWindow
, aMouseEventData
);
302 bool LokChartHelper::setTextSelection(int nType
, int nX
, int nY
)
304 tools::Rectangle rChartBBox
= GetChartBoundingBox();
305 if (rChartBBox
.Contains(Point(nX
, nY
)))
307 css::uno::Reference
<css::frame::XDispatch
> xDispatcher
= GetXDispatcher();
308 if (xDispatcher
.is())
310 int nChartWinX
= nX
- rChartBBox
.Left();
311 int nChartWinY
= nY
- rChartBBox
.Top();
313 // no scale here the chart controller expects twips
314 // that are converted to hmm
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
))
322 xDispatcher
->dispatch(aURL
, aArgs
);
329 bool LokChartHelper::setGraphicSelection(int nType
, int nX
, int nY
,
330 double fScaleX
, double fScaleY
)
332 tools::Rectangle rChartBBox
= GetChartBoundingBox();
333 if (rChartBBox
.Contains(Point(nX
, nY
)))
335 int nChartWinX
= nX
- rChartBBox
.Left();
336 int nChartWinY
= nY
- rChartBBox
.Top();
338 vcl::Window
* pChartWindow
= GetWindow();
340 Point
aPos(nChartWinX
* fScaleX
, nChartWinY
* fScaleY
);
343 case LOK_SETGRAPHICSELECTION_START
:
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
);
351 case LOK_SETGRAPHICSELECTION_END
:
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
);
369 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */