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
;
31 Point
lcl_TwipsToHMM( const Point
& rPoint
)
33 return Point(convertTwipToMm100(rPoint
.getX()), convertTwipToMm100(rPoint
.getY()));
36 Size
lcl_TwipsToHMM( const Size
& rSize
)
38 return Size(convertTwipToMm100(rSize
.getWidth()), convertTwipToMm100(rSize
.getHeight()));
43 css::uno::Reference
<css::frame::XController
>& LokChartHelper::GetXController()
45 if(!mxController
.is() && mpViewShell
)
47 SfxInPlaceClient
* pIPClient
= mpViewShell
->GetIPClient();
50 const css::uno::Reference
< ::css::embed::XEmbeddedObject
>& xEmbObj
= pIPClient
->GetObject();
53 ::css::uno::Reference
< ::css::chart2::XChartDocument
> xChart( xEmbObj
->getComponent(), uno::UNO_QUERY
);
56 ::css::uno::Reference
< ::css::frame::XController
> xChartController
= xChart
->getCurrentController();
57 if( xChartController
.is() )
59 mxController
= xChartController
;
69 css::uno::Reference
<css::frame::XDispatch
>& LokChartHelper::GetXDispatcher()
71 if( !mxDispatcher
.is() )
73 ::css::uno::Reference
< ::css::frame::XController
>& xChartController
= GetXController();
74 if( xChartController
.is() )
76 ::css::uno::Reference
< ::css::frame::XDispatch
> xDispatcher( xChartController
, uno::UNO_QUERY
);
77 if( xDispatcher
.is() )
79 mxDispatcher
= xDispatcher
;
87 vcl::Window
* LokChartHelper::GetWindow()
91 ::css::uno::Reference
< ::css::frame::XController
>& xChartController
= GetXController();
92 if( xChartController
.is() )
94 ::css::uno::Reference
< ::css::frame::XFrame
> xFrame
= xChartController
->getFrame();
97 ::css::uno::Reference
< ::css::awt::XWindow
> xDockerWin
= xFrame
->getContainerWindow();
98 vcl::Window
* pParent
= VCLUnoHelper::GetWindow( xDockerWin
);
101 sal_uInt16 nTotChildren
= pParent
->GetChildCount();
102 while (nTotChildren
--)
104 vcl::Window
* pChildWin
= pParent
->GetChild(nTotChildren
);
105 if (pChildWin
&& pChildWin
->IsChart())
107 mpWindow
= pChildWin
;
116 return mpWindow
.get();
119 tools::Rectangle
LokChartHelper::GetChartBoundingBox()
121 tools::Rectangle aBBox
;
124 SfxInPlaceClient
* pIPClient
= mpViewShell
->GetIPClient();
127 vcl::Window
* pRootWin
= pIPClient
->GetEditWin();
130 vcl::Window
* pWindow
= GetWindow();
133 // In all cases, the following code fragment
134 // returns the chart bounding box in twips.
135 const MapMode
& aCWMapMode
= pWindow
->GetMapMode();
136 constexpr auto p
= o3tl::getConversionMulDiv(o3tl::Length::px
, o3tl::Length::twip
);
137 const auto& scaleX
= aCWMapMode
.GetScaleX();
138 const auto& scaleY
= aCWMapMode
.GetScaleY();
139 const auto nXNum
= p
.first
* scaleX
.GetDenominator();
140 const auto nXDen
= p
.second
* scaleX
.GetNumerator();
141 const auto nYNum
= p
.first
* scaleY
.GetDenominator();
142 const auto nYDen
= p
.second
* scaleY
.GetNumerator();
144 Point aOffset
= pWindow
->GetOffsetPixelFrom(*pRootWin
);
145 if (mbNegativeX
&& AllSettings::GetLayoutRTL())
147 // If global RTL flag is set, vcl-window X offset of chart window is
148 // mirrored w.r.t parent window rectangle. This needs to be reverted.
149 aOffset
.setX(pRootWin
->GetOutOffXPixel() + pRootWin
->GetSizePixel().Width()
150 - pWindow
->GetOutOffXPixel() - pWindow
->GetSizePixel().Width());
154 aOffset
= aOffset
.scale(nXNum
, nXDen
, nYNum
, nYDen
);
155 Size aSize
= pWindow
->GetSizePixel().scale(nXNum
, nXDen
, nYNum
, nYDen
);
156 aBBox
= tools::Rectangle(aOffset
, aSize
);
164 void LokChartHelper::Invalidate()
167 mxDispatcher
.clear();
168 mxController
.clear();
171 bool LokChartHelper::Hit(const Point
& aPos
)
175 vcl::Window
* pChartWindow
= GetWindow();
178 tools::Rectangle rChartBBox
= GetChartBoundingBox();
179 return rChartBBox
.Contains(aPos
);
185 bool LokChartHelper::HitAny(const Point
& aPos
, bool bNegativeX
)
187 SfxViewShell
* pCurView
= SfxViewShell::Current();
188 int nPartForCurView
= pCurView
? pCurView
->getPart() : -1;
189 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
192 if (pViewShell
->GetDocId() == pCurView
->GetDocId() && pViewShell
->getPart() == nPartForCurView
)
194 LokChartHelper
aChartHelper(pViewShell
, bNegativeX
);
195 if (aChartHelper
.Hit(aPos
))
198 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
203 void LokChartHelper::PaintTile(VirtualDevice
& rRenderContext
, const tools::Rectangle
& rTileRect
)
208 vcl::Window
* pChartWindow
= GetWindow();
212 tools::Rectangle aChartRect
= GetChartBoundingBox();
213 tools::Rectangle aTestRect
= rTileRect
;
214 aTestRect
.Intersection( aChartRect
);
215 if (aTestRect
.IsEmpty())
218 Point
aOffset( aChartRect
.Left() - rTileRect
.Left(), aChartRect
.Top() - rTileRect
.Top() );
219 Point aOffsetFromTile
= lcl_TwipsToHMM(aOffset
);
220 Size aSize
= lcl_TwipsToHMM(aChartRect
.GetSize());
221 tools::Rectangle
aRectangle(Point(0,0), aSize
);
223 bool bEnableMapMode
= !pChartWindow
->IsMapModeEnabled();
224 pChartWindow
->EnableMapMode();
225 bool bRenderContextEnableMapMode
= !rRenderContext
.IsMapModeEnabled();
226 rRenderContext
.EnableMapMode();
228 rRenderContext
.Push(vcl::PushFlags::MAPMODE
);
230 MapMode aCWMapMode
= pChartWindow
->GetMapMode();
231 aCWMapMode
.SetScaleX(rRenderContext
.GetMapMode().GetScaleX());
232 aCWMapMode
.SetScaleY(rRenderContext
.GetMapMode().GetScaleY());
234 aCWMapMode
.SetOrigin(aOffsetFromTile
);
235 rRenderContext
.SetMapMode(aCWMapMode
);
237 pChartWindow
->Paint(rRenderContext
, aRectangle
);
239 rRenderContext
.Pop();
241 if (bRenderContextEnableMapMode
)
242 rRenderContext
.EnableMapMode(false);
244 pChartWindow
->EnableMapMode(false);
247 void LokChartHelper::PaintAllChartsOnTile(VirtualDevice
& rDevice
,
248 int nOutputWidth
, int nOutputHeight
,
249 int nTilePosX
, int nTilePosY
,
250 tools::Long nTileWidth
, tools::Long nTileHeight
,
253 if (comphelper::LibreOfficeKit::isTiledAnnotations())
256 // Resizes the virtual device so to contain the entries context
257 rDevice
.SetOutputSizePixel(Size(nOutputWidth
, nOutputHeight
));
259 rDevice
.Push(vcl::PushFlags::MAPMODE
);
260 MapMode
aMapMode(rDevice
.GetMapMode());
262 // Scaling. Must convert from pixels to twips. We know
263 // that VirtualDevices use a DPI of 96.
264 const Fraction scale
= conversionFract(o3tl::Length::px
, o3tl::Length::twip
);
265 Fraction scaleX
= Fraction(nOutputWidth
, nTileWidth
) * scale
;
266 Fraction scaleY
= Fraction(nOutputHeight
, nTileHeight
) * scale
;
267 aMapMode
.SetScaleX(scaleX
);
268 aMapMode
.SetScaleY(scaleY
);
269 rDevice
.SetMapMode(aMapMode
);
271 SfxViewShell
* pCurView
= SfxViewShell::Current();
272 int nPartForCurView
= pCurView
? pCurView
->getPart() : -1;
273 tools::Long nTileRectLeft
= bNegativeX
? -nTilePosX
- nTileWidth
: nTilePosX
;
274 tools::Rectangle
aTileRect(Point(nTileRectLeft
, nTilePosY
), Size(nTileWidth
, nTileHeight
));
275 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
278 if (pCurView
&& pViewShell
->GetDocId() == pCurView
->GetDocId() && pViewShell
->getPart() == nPartForCurView
)
280 LokChartHelper
aChartHelper(pViewShell
, bNegativeX
);
281 aChartHelper
.PaintTile(rDevice
, aTileRect
);
283 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
288 bool LokChartHelper::postMouseEvent(int nType
, int nX
, int nY
,
289 int nCount
, int nButtons
, int nModifier
,
290 double fScaleX
, double fScaleY
)
292 Point
aMousePos(nX
, nY
);
293 vcl::Window
* pChartWindow
= GetWindow();
296 tools::Rectangle rChartBBox
= GetChartBoundingBox();
297 if (rChartBBox
.Contains(aMousePos
))
299 int nChartWinX
= nX
- rChartBBox
.Left();
300 int nChartWinY
= nY
- rChartBBox
.Top();
302 // chart window expects pixels, but the conversion factor
303 // can depend on the client zoom
304 Point
aPos(nChartWinX
* fScaleX
, nChartWinY
* fScaleY
);
306 LokMouseEventData
aMouseEventData(nType
, aPos
, nCount
, MouseEventModifiers::SIMPLECLICK
,
307 nButtons
, nModifier
);
308 SfxLokHelper::postMouseEventAsync(pChartWindow
, aMouseEventData
);
316 bool LokChartHelper::setTextSelection(int nType
, int nX
, int nY
)
318 tools::Rectangle rChartBBox
= GetChartBoundingBox();
319 if (rChartBBox
.Contains(Point(nX
, nY
)))
321 css::uno::Reference
<css::frame::XDispatch
> xDispatcher
= GetXDispatcher();
322 if (xDispatcher
.is())
324 int nChartWinX
= nX
- rChartBBox
.Left();
325 int nChartWinY
= nY
- rChartBBox
.Top();
327 // no scale here the chart controller expects twips
328 // that are converted to hmm
330 aURL
.Path
= "LOKSetTextSelection";
331 uno::Sequence
< beans::PropertyValue
> aArgs
{
332 comphelper::makePropertyValue({}, static_cast<sal_Int32
>(nType
)), // Why no name?
333 comphelper::makePropertyValue({}, static_cast<sal_Int32
>(nChartWinX
)),
334 comphelper::makePropertyValue({}, static_cast<sal_Int32
>(nChartWinY
))
336 xDispatcher
->dispatch(aURL
, aArgs
);
343 bool LokChartHelper::setGraphicSelection(int nType
, int nX
, int nY
,
344 double fScaleX
, double fScaleY
)
346 tools::Rectangle rChartBBox
= GetChartBoundingBox();
347 if (rChartBBox
.Contains(Point(nX
, nY
)))
349 int nChartWinX
= nX
- rChartBBox
.Left();
350 int nChartWinY
= nY
- rChartBBox
.Top();
352 vcl::Window
* pChartWindow
= GetWindow();
354 Point
aPos(nChartWinX
* fScaleX
, nChartWinY
* fScaleY
);
357 case LOK_SETGRAPHICSELECTION_START
:
359 MouseEvent
aClickEvent(aPos
, 1, MouseEventModifiers::SIMPLECLICK
, MOUSE_LEFT
);
360 pChartWindow
->MouseButtonDown(aClickEvent
);
361 MouseEvent
aMoveEvent(aPos
, 0, MouseEventModifiers::SIMPLEMOVE
, MOUSE_LEFT
);
362 pChartWindow
->MouseMove(aMoveEvent
);
365 case LOK_SETGRAPHICSELECTION_END
:
367 MouseEvent
aMoveEvent(aPos
, 0, MouseEventModifiers::SIMPLEMOVE
, MOUSE_LEFT
);
368 pChartWindow
->MouseMove(aMoveEvent
);
369 MouseEvent
aClickEvent(aPos
, 1, MouseEventModifiers::SIMPLECLICK
, MOUSE_LEFT
);
370 pChartWindow
->MouseButtonUp(aClickEvent
);
383 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */