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
= std::move(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
= std::move(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
> 0)
91 vcl::Window
* pChildWin
= pParent
->GetChild(nTotChildren
);
92 if (pChildWin
&& pChildWin
->IsChart())
103 return mpWindow
.get();
106 tools::Rectangle
LokChartHelper::GetChartBoundingBox()
108 tools::Rectangle aBBox
;
111 SfxInPlaceClient
* pIPClient
= mpViewShell
->GetIPClient();
114 vcl::Window
* pRootWin
= pIPClient
->GetEditWin();
117 vcl::Window
* pWindow
= GetWindow();
120 // In all cases, the following code fragment
121 // returns the chart bounding box in twips.
122 const MapMode
& aCWMapMode
= pWindow
->GetMapMode();
123 constexpr auto p
= o3tl::getConversionMulDiv(o3tl::Length::px
, o3tl::Length::twip
);
124 const auto& scaleX
= aCWMapMode
.GetScaleX();
125 const auto& scaleY
= aCWMapMode
.GetScaleY();
126 const auto nXNum
= p
.first
* scaleX
.GetDenominator();
127 const auto nXDen
= p
.second
* scaleX
.GetNumerator();
128 const auto nYNum
= p
.first
* scaleY
.GetDenominator();
129 const auto nYDen
= p
.second
* scaleY
.GetNumerator();
131 Point aOffset
= pWindow
->GetOffsetPixelFrom(*pRootWin
);
132 if (mbNegativeX
&& AllSettings::GetLayoutRTL())
134 // If global RTL flag is set, vcl-window X offset of chart window is
135 // mirrored w.r.t parent window rectangle. This needs to be reverted.
136 aOffset
.setX(pRootWin
->GetOutOffXPixel() + pRootWin
->GetSizePixel().Width()
137 - pWindow
->GetOutOffXPixel() - pWindow
->GetSizePixel().Width());
141 aOffset
= aOffset
.scale(nXNum
, nXDen
, nYNum
, nYDen
);
142 Size aSize
= pWindow
->GetSizePixel().scale(nXNum
, nXDen
, nYNum
, nYDen
);
143 aBBox
= tools::Rectangle(aOffset
, aSize
);
151 void LokChartHelper::Invalidate()
154 mxDispatcher
.clear();
155 mxController
.clear();
158 bool LokChartHelper::Hit(const Point
& aPos
)
162 vcl::Window
* pChartWindow
= GetWindow();
165 tools::Rectangle rChartBBox
= GetChartBoundingBox();
166 return rChartBBox
.Contains(aPos
);
172 bool LokChartHelper::HitAny(const Point
& aPos
, bool bNegativeX
)
174 SfxViewShell
* pCurView
= SfxViewShell::Current();
175 int nPartForCurView
= pCurView
? pCurView
->getPart() : -1;
176 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
179 if (pCurView
&& pViewShell
->GetDocId() == pCurView
->GetDocId() && pViewShell
->getPart() == nPartForCurView
)
181 LokChartHelper
aChartHelper(pViewShell
, bNegativeX
);
182 if (aChartHelper
.Hit(aPos
))
185 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
190 void LokChartHelper::PaintTile(VirtualDevice
& rRenderContext
, const tools::Rectangle
& rTileRect
)
195 vcl::Window
* pChartWindow
= GetWindow();
199 tools::Rectangle aChartRect
= GetChartBoundingBox();
200 tools::Rectangle aTestRect
= rTileRect
;
201 aTestRect
.Intersection( aChartRect
);
202 if (aTestRect
.IsEmpty())
205 Point
aOffset( aChartRect
.Left() - rTileRect
.Left(), aChartRect
.Top() - rTileRect
.Top() );
206 Point aOffsetFromTile
= convertTwipToMm100(aOffset
);
207 Size aSize
= convertTwipToMm100(aChartRect
.GetSize());
208 tools::Rectangle
aRectangle(Point(0,0), aSize
);
210 bool bEnableMapMode
= !pChartWindow
->IsMapModeEnabled();
211 pChartWindow
->EnableMapMode();
212 bool bRenderContextEnableMapMode
= !rRenderContext
.IsMapModeEnabled();
213 rRenderContext
.EnableMapMode();
215 rRenderContext
.Push(vcl::PushFlags::MAPMODE
);
217 MapMode aCWMapMode
= pChartWindow
->GetMapMode();
218 aCWMapMode
.SetScaleX(rRenderContext
.GetMapMode().GetScaleX());
219 aCWMapMode
.SetScaleY(rRenderContext
.GetMapMode().GetScaleY());
221 aCWMapMode
.SetOrigin(aOffsetFromTile
);
222 rRenderContext
.SetMapMode(aCWMapMode
);
224 pChartWindow
->Paint(rRenderContext
, aRectangle
);
226 rRenderContext
.Pop();
228 if (bRenderContextEnableMapMode
)
229 rRenderContext
.EnableMapMode(false);
231 pChartWindow
->EnableMapMode(false);
234 void LokChartHelper::PaintAllChartsOnTile(VirtualDevice
& rDevice
,
235 int nOutputWidth
, int nOutputHeight
,
236 int nTilePosX
, int nTilePosY
,
237 tools::Long nTileWidth
, tools::Long nTileHeight
,
240 if (comphelper::LibreOfficeKit::isTiledAnnotations())
243 // Resizes the virtual device so to contain the entries context
244 rDevice
.SetOutputSizePixel(Size(nOutputWidth
, nOutputHeight
));
246 rDevice
.Push(vcl::PushFlags::MAPMODE
);
247 MapMode
aMapMode(rDevice
.GetMapMode());
249 // Scaling. Must convert from pixels to twips. We know
250 // that VirtualDevices use a DPI of 96.
251 const Fraction scale
= conversionFract(o3tl::Length::px
, o3tl::Length::twip
);
252 Fraction scaleX
= Fraction(nOutputWidth
, nTileWidth
) * scale
;
253 Fraction scaleY
= Fraction(nOutputHeight
, nTileHeight
) * scale
;
254 aMapMode
.SetScaleX(scaleX
);
255 aMapMode
.SetScaleY(scaleY
);
256 rDevice
.SetMapMode(aMapMode
);
258 SfxViewShell
* pCurView
= SfxViewShell::Current();
259 int nPartForCurView
= pCurView
? pCurView
->getPart() : -1;
260 tools::Long nTileRectLeft
= bNegativeX
? -nTilePosX
- nTileWidth
: nTilePosX
;
261 tools::Rectangle
aTileRect(Point(nTileRectLeft
, nTilePosY
), Size(nTileWidth
, nTileHeight
));
262 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
265 if (pCurView
&& pViewShell
->GetDocId() == pCurView
->GetDocId() && pViewShell
->getPart() == nPartForCurView
)
267 LokChartHelper
aChartHelper(pViewShell
, bNegativeX
);
268 aChartHelper
.PaintTile(rDevice
, aTileRect
);
270 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
275 bool LokChartHelper::postMouseEvent(int nType
, int nX
, int nY
,
276 int nCount
, int nButtons
, int nModifier
,
277 double fScaleX
, double fScaleY
)
279 Point
aMousePos(nX
, nY
);
280 vcl::Window
* pChartWindow
= GetWindow();
283 tools::Rectangle rChartBBox
= GetChartBoundingBox();
284 if (rChartBBox
.Contains(aMousePos
))
286 int nChartWinX
= nX
- rChartBBox
.Left();
287 int nChartWinY
= nY
- rChartBBox
.Top();
289 // chart window expects pixels, but the conversion factor
290 // can depend on the client zoom
291 Point
aPos(nChartWinX
* fScaleX
, nChartWinY
* fScaleY
);
293 LokMouseEventData
aMouseEventData(nType
, aPos
, nCount
, MouseEventModifiers::SIMPLECLICK
,
294 nButtons
, nModifier
);
295 SfxLokHelper::postMouseEventAsync(pChartWindow
, aMouseEventData
);
303 bool LokChartHelper::setTextSelection(int nType
, int nX
, int nY
)
305 tools::Rectangle rChartBBox
= GetChartBoundingBox();
306 if (rChartBBox
.Contains(Point(nX
, nY
)))
308 css::uno::Reference
<css::frame::XDispatch
> xDispatcher
= GetXDispatcher();
309 if (xDispatcher
.is())
311 int nChartWinX
= nX
- rChartBBox
.Left();
312 int nChartWinY
= nY
- rChartBBox
.Top();
314 // no scale here the chart controller expects twips
315 // that are converted to hmm
317 aURL
.Path
= "LOKSetTextSelection";
318 uno::Sequence
< beans::PropertyValue
> aArgs
{
319 comphelper::makePropertyValue({}, static_cast<sal_Int32
>(nType
)), // Why no name?
320 comphelper::makePropertyValue({}, static_cast<sal_Int32
>(nChartWinX
)),
321 comphelper::makePropertyValue({}, static_cast<sal_Int32
>(nChartWinY
))
323 xDispatcher
->dispatch(aURL
, aArgs
);
330 bool LokChartHelper::setGraphicSelection(int nType
, int nX
, int nY
,
331 double fScaleX
, double fScaleY
)
333 tools::Rectangle rChartBBox
= GetChartBoundingBox();
334 if (rChartBBox
.Contains(Point(nX
, nY
)))
336 int nChartWinX
= nX
- rChartBBox
.Left();
337 int nChartWinY
= nY
- rChartBBox
.Top();
339 vcl::Window
* pChartWindow
= GetWindow();
341 Point
aPos(nChartWinX
* fScaleX
, nChartWinY
* fScaleY
);
344 case LOK_SETGRAPHICSELECTION_START
:
346 MouseEvent
aClickEvent(aPos
, 1, MouseEventModifiers::SIMPLECLICK
, MOUSE_LEFT
);
347 pChartWindow
->MouseButtonDown(aClickEvent
);
348 MouseEvent
aMoveEvent(aPos
, 0, MouseEventModifiers::SIMPLEMOVE
, MOUSE_LEFT
);
349 pChartWindow
->MouseMove(aMoveEvent
);
352 case LOK_SETGRAPHICSELECTION_END
:
354 MouseEvent
aMoveEvent(aPos
, 0, MouseEventModifiers::SIMPLEMOVE
, MOUSE_LEFT
);
355 pChartWindow
->MouseMove(aMoveEvent
);
356 MouseEvent
aClickEvent(aPos
, 1, MouseEventModifiers::SIMPLECLICK
, MOUSE_LEFT
);
357 pChartWindow
->MouseButtonUp(aClickEvent
);
370 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */