LibreOffice Module svx (master)  1
sdrpagewindow.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  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <svx/sdrpagewindow.hxx>
21 #include <com/sun/star/awt/XWindow.hpp>
22 #include <com/sun/star/beans/XPropertySet.hpp>
23 #include <com/sun/star/awt/PosSize.hpp>
24 #include <com/sun/star/util/XModeChangeBroadcaster.hpp>
25 #include <comphelper/lok.hxx>
27 #include <comphelper/random.hxx>
28 #include <vcl/svapp.hxx>
30 #include <svx/svdouno.hxx>
31 #include <svx/svdpage.hxx>
32 #include <svx/svdview.hxx>
33 #include <svx/svdpagv.hxx>
34 #include <svx/sdrpaintwindow.hxx>
37 #include <svx/fmview.hxx>
39 #include <sfx2/lokhelper.hxx>
40 #include <tools/debug.hxx>
41 
42 using namespace ::com::sun::star;
43 
45 {
46  // #110094# ObjectContact section
48 
49  // the SdrPageView this window belongs to
51 
52  // the PaintWindow to paint on. Here is access to OutDev etc.
53  // #i72752# change to pointer to allow patcing it in DrawLayer() if necessary
56 
57  // UNO stuff for xControls
58  uno::Reference<awt::XControlContainer> mxControlContainer;
59 
60  Impl( SdrPageView& rPageView, SdrPaintWindow& rPaintWindow ) :
61  mpObjectContact(nullptr),
62  mrPageView(rPageView),
63  mpPaintWindow(&rPaintWindow),
64  mpOriginalPaintWindow(nullptr)
65  {
66  }
67 };
68 
69 
70 uno::Reference<awt::XControlContainer> const & SdrPageWindow::GetControlContainer( bool _bCreateIfNecessary ) const
71 {
72  if (!mpImpl->mxControlContainer.is() && _bCreateIfNecessary)
73  {
74  SdrView& rView = GetPageView().GetView();
75 
77  if ( rPaintWindow.OutputToWindow() && !rView.IsPrintPreview() )
78  {
79  vcl::Window& rWindow = dynamic_cast< vcl::Window& >( rPaintWindow.GetOutputDevice() );
80  const_cast< SdrPageWindow* >( this )->mpImpl->mxControlContainer = VCLUnoHelper::CreateControlContainer( &rWindow );
81 
82  // #100394# xC->setVisible triggers window->Show() and this has
83  // problems when the view is not completely constructed which may
84  // happen when loading. This leads to accessibility broadcasts which
85  // throw asserts due to the not finished view. All this chain can be avoided
86  // since xC->setVisible is here called only for the side effect in
87  // UnoControlContainer::setVisible(...) which calls createPeer(...).
88  // This will now be called directly from here.
89 
90  uno::Reference< awt::XControl > xControl(mpImpl->mxControlContainer, uno::UNO_QUERY);
91  if(xControl.is())
92  {
93  uno::Reference< uno::XInterface > xContext = xControl->getContext();
94  if(!xContext.is())
95  {
96  xControl->createPeer( uno::Reference<awt::XToolkit>(), uno::Reference<awt::XWindowPeer>() );
97  }
98  }
99  }
100  else
101  {
102  // Printer and VirtualDevice, or rather: no OutDev
103  uno::Reference< lang::XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory() );
104  const_cast< SdrPageWindow* >( this )->mpImpl->mxControlContainer.set(xFactory->createInstance("com.sun.star.awt.UnoControlContainer"), uno::UNO_QUERY);
105  uno::Reference< awt::XControlModel > xModel(xFactory->createInstance("com.sun.star.awt.UnoControlContainerModel"), uno::UNO_QUERY);
106  uno::Reference< awt::XControl > xControl(mpImpl->mxControlContainer, uno::UNO_QUERY);
107  if (xControl.is())
108  xControl->setModel(xModel);
109 
110  OutputDevice& rOutDev = rPaintWindow.GetOutputDevice();
111  Point aPosPix = rOutDev.GetMapMode().GetOrigin();
112  Size aSizePix = rOutDev.GetOutputSizePixel();
113 
114  uno::Reference< awt::XWindow > xContComp(mpImpl->mxControlContainer, uno::UNO_QUERY);
115  if( xContComp.is() )
116  xContComp->setPosSize(aPosPix.X(), aPosPix.Y(), aSizePix.Width(), aSizePix.Height(), awt::PosSize::POSSIZE);
117  }
118 
119  FmFormView* pViewAsFormView = dynamic_cast< FmFormView* >( &rView );
120  if ( pViewAsFormView )
121  pViewAsFormView->InsertControlContainer(mpImpl->mxControlContainer);
122  }
123  return mpImpl->mxControlContainer;
124 }
125 
127  mpImpl(new Impl(rPageView, rPaintWindow))
128 {
129 }
130 
132 {
133  // #i26631#
135 
136  if (mpImpl->mxControlContainer.is())
137  {
138  auto & rView = static_cast<SdrPaintView &>(GetPageView().GetView());
139 
140  // notify derived views
141  FmFormView* pViewAsFormView = dynamic_cast< FmFormView* >( &rView );
142  if ( pViewAsFormView )
143  pViewAsFormView->RemoveControlContainer(mpImpl->mxControlContainer);
144 
145  // dispose the control container
146  uno::Reference< lang::XComponent > xComponent(mpImpl->mxControlContainer, uno::UNO_QUERY);
147  xComponent->dispose();
148  }
149 }
150 
152 {
153  return mpImpl->mrPageView;
154 }
155 
157 {
158  return *mpImpl->mpPaintWindow;
159 }
160 
162 {
163  return mpImpl->mpOriginalPaintWindow;
164 }
165 
166 // OVERLAY MANAGER
168 {
170 }
171 
173 {
174  mpImpl->mpOriginalPaintWindow = mpImpl->mpPaintWindow;
175  mpImpl->mpPaintWindow = &rPaintWindow;
176 }
177 
179 {
180  DBG_ASSERT(mpImpl->mpOriginalPaintWindow, "SdrPageWindow::unpatchPaintWindow: paint window not patched!" );
181  if (mpImpl->mpOriginalPaintWindow)
182  {
183  mpImpl->mpPaintWindow = mpImpl->mpOriginalPaintWindow;
184  mpImpl->mpOriginalPaintWindow = nullptr;
185  }
186 }
187 
189 {
190  // give OC the chance to do ProcessDisplay preparations
191  if(HasObjectContact())
192  {
194  }
195 }
196 
198 {
199  // give OC the chance to do ProcessDisplay preparations
200  if(HasObjectContact())
201  {
203  }
204 
205  // if necessary, remember changed RedrawArea at PaintWindow for usage with
206  // overlay and PreRenderDevice stuff
208 }
209 
210 
211 // clip test
212 #ifdef CLIPPER_TEST
213 #include <svx/svdopath.hxx>
215 #include <tools/helpers.hxx>
220 
221 // for ::std::sort
222 #include <algorithm>
223 
224 namespace
225 {
226  void impPaintStrokePolygon(const basegfx::B2DPolygon& rCandidate, OutputDevice& rOutDev, Color aColor)
227  {
228  basegfx::B2DPolygon aCandidate(rCandidate);
229 
230  if(aCandidate.areControlPointsUsed())
231  {
232  aCandidate = basegfx::utils::adaptiveSubdivideByAngle(rCandidate);
233  }
234 
235  if(aCandidate.count())
236  {
237  const sal_uInt32 nLoopCount(aCandidate.isClosed() ? aCandidate.count() : aCandidate.count() - 1);
238  rOutDev.SetFillColor();
239  rOutDev.SetLineColor(aColor);
240 
241  for(sal_uInt32 a(0); a < nLoopCount; a++)
242  {
243  const basegfx::B2DPoint aBStart(aCandidate.getB2DPoint(a));
244  const basegfx::B2DPoint aBEnd(aCandidate.getB2DPoint((a + 1) % aCandidate.count()));
245  const Point aStart(FRound(aBStart.getX()), FRound(aBStart.getY()));
246  const Point aEnd(FRound(aBEnd.getX()), FRound(aBEnd.getY()));
247  rOutDev.DrawLine(aStart, aEnd);
248  }
249  }
250  }
251 
252  void impTryTest(const SdrPageView& rPageView, OutputDevice& rOutDev)
253  {
254  if(rPageView.GetPage() && rPageView.GetPage()->GetObjCount() >= 2)
255  {
256  SdrPage* pPage = rPageView.GetPage();
257  SdrObject* pObjA = pPage->GetObj(0);
258 
259  if(dynamic_cast<const SdrPathObj*>( pObjA))
260  {
261  basegfx::B2DPolyPolygon aPolyA(pObjA->GetPathPoly());
262  aPolyA = basegfx::utils::correctOrientations(aPolyA);
263 
265 
266  for(sal_uInt32 a(1); a < rPageView.GetPage()->GetObjCount(); a++)
267  {
268  SdrObject* pObjB = pPage->GetObj(a);
269 
270  if(dynamic_cast<const SdrPathObj*>( pObjB))
271  {
272  basegfx::B2DPolyPolygon aCandidate(pObjB->GetPathPoly());
273  aCandidate = basegfx::utils::correctOrientations(aCandidate);
274  aPolyB.append(aCandidate);
275  }
276  }
277 
278  if(aPolyA.count() && aPolyA.isClosed() && aPolyB.count())
279  {
280  // poly A is the clipregion, clip poly b against it. Algo depends on
281  // poly b being closed.
283 
284  for(auto const& rPolygon : aResult)
285  {
289  Color aColor(nR, nG, nB);
290  impPaintStrokePolygon(rPolygon, rOutDev, aColor);
291  }
292  }
293  }
294  }
295  }
296 } // end of anonymous namespace
297 #endif // CLIPPER_TEST
298 
299 
301 {
302  // set Redirector
304 
305  // set PaintingPageView
306  const SdrView& rView = mpImpl->mrPageView.GetView();
307  SdrModel& rModel = *(rView.GetModel());
308 
309  // get to be processed layers
310  const bool bPrinter(GetPaintWindow().OutputToPrinter());
311  SdrLayerIDSet aProcessLayers = bPrinter ? mpImpl->mrPageView.GetPrintableLayers() : mpImpl->mrPageView.GetVisibleLayers();
312 
313  // create PaintInfoRec; use Rectangle only temporarily
314  const vcl::Region& rRegion = GetPaintWindow().GetRedrawRegion();
315 
316  // create processing data
317  sdr::contact::DisplayInfo aDisplayInfo;
318 
319  // Draw all layers. do NOT draw form layer from CompleteRedraw, this is done separately
320  // as a single layer paint
321  const SdrLayerAdmin& rLayerAdmin = rModel.GetLayerAdmin();
322  const SdrLayerID nControlLayerId = rLayerAdmin.GetLayerID(rLayerAdmin.GetControlLayerName());
323  aProcessLayers.Clear(nControlLayerId);
324 
325  // still something to paint?
326  if(!aProcessLayers.IsEmpty())
327  {
328  aDisplayInfo.SetProcessLayers(aProcessLayers);
329 
330  // Set region as redraw area
331  aDisplayInfo.SetRedrawArea(rRegion);
332 
333  // Draw/Impress
334  aDisplayInfo.SetPageProcessingActive(rView.IsPagePaintingAllowed()); // #i72889#
335 
336  // paint page
337  GetObjectContact().ProcessDisplay(aDisplayInfo);
338  }
339 
340  // reset redirector
342 
343  // LineClip test
344 #ifdef CLIPPER_TEST
345  if(true)
346  {
347  impTryTest(GetPageView(), GetPaintWindow().GetOutputDevice());
348  }
349 #endif // CLIPPER_TEST
350 }
351 
354  basegfx::B2IRectangle const*const pPageFrame)
355 {
356  // set redirector
358 
359  // set PaintingPageView
360  const SdrView& rView = mpImpl->mrPageView.GetView();
361  SdrModel& rModel = *(rView.GetModel());
362 
363  // get the layers to process
364  const bool bPrinter(GetPaintWindow().OutputToPrinter());
365  SdrLayerIDSet aProcessLayers = bPrinter ? mpImpl->mrPageView.GetPrintableLayers() : mpImpl->mrPageView.GetVisibleLayers();
366 
367  // is the given layer visible at all?
368  if(aProcessLayers.IsSet(*pId))
369  {
370  // find out if we are painting the ControlLayer
371  const SdrLayerAdmin& rLayerAdmin = rModel.GetLayerAdmin();
372  const SdrLayerID nControlLayerId = rLayerAdmin.GetLayerID(rLayerAdmin.GetControlLayerName());
373  const bool bControlLayerProcessingActive(nControlLayerId == *pId);
374 
375  // create PaintInfoRec, use Rectangle only temporarily
376  const vcl::Region& rRegion = GetPaintWindow().GetRedrawRegion();
377 
378  // create processing data
379  sdr::contact::DisplayInfo aDisplayInfo;
380 
381  // is it the control layer? If Yes, set flag
382  aDisplayInfo.SetControlLayerProcessingActive(bControlLayerProcessingActive);
383 
384  // Draw just the one given layer
385  aProcessLayers.ClearAll();
386  aProcessLayers.Set(*pId);
387 
388  aDisplayInfo.SetProcessLayers(aProcessLayers);
389 
390  // Set region as redraw area
391  aDisplayInfo.SetRedrawArea(rRegion);
392 
393  // Writer or calc, coming from original RedrawOneLayer.
394  // #i72889# no page painting for layer painting
395  aDisplayInfo.SetPageProcessingActive(false);
396 
397  if (pPageFrame) // Writer page frame for anchor based clipping
398  {
399  aDisplayInfo.SetWriterPageFrame(*pPageFrame);
400  }
401 
402  // paint page
403  GetObjectContact().ProcessDisplay(aDisplayInfo);
404  }
405 
406  // reset redirector
408 }
409 
410 // Invalidate call, used from ObjectContact(OfPageView) in InvalidatePartOfView(...)
412 {
413  if (GetPageView().IsVisible() && GetPaintWindow().OutputToWindow())
414  {
415  const SvtOptionsDrawinglayer aDrawinglayerOpt;
416  OutputDevice& rWindow(GetPaintWindow().GetOutputDevice());
417  basegfx::B2DRange aDiscreteRange(rRange);
418  aDiscreteRange.transform(rWindow.GetViewTransformation());
419 
420  if (aDrawinglayerOpt.IsAntiAliasing())
421  {
422  // invalidate one discrete unit more under the assumption that AA
423  // needs one pixel more
424  aDiscreteRange.grow(1.0);
425  }
426 
427  const tools::Rectangle aVCLDiscreteRectangle(
428  static_cast<long>(floor(aDiscreteRange.getMinX())),
429  static_cast<long>(floor(aDiscreteRange.getMinY())),
430  static_cast<long>(ceil(aDiscreteRange.getMaxX())),
431  static_cast<long>(ceil(aDiscreteRange.getMaxY())));
432 
433  const bool bWasMapModeEnabled(rWindow.IsMapModeEnabled());
434  rWindow.EnableMapMode(false);
435  GetPageView().GetView().InvalidateOneWin(rWindow, aVCLDiscreteRectangle);
436  rWindow.EnableMapMode(bWasMapModeEnabled);
437  }
439  {
440  // we don't really have to have a paint window with LOK; OTOH we know
441  // that the drawinglayer units are 100ths of mm, so they are easy to
442  // convert to twips
443  const tools::Rectangle aRect100thMM(
444  static_cast<long>(floor(rRange.getMinX())),
445  static_cast<long>(floor(rRange.getMinY())),
446  static_cast<long>(ceil(rRange.getMaxX())),
447  static_cast<long>(ceil(rRange.getMaxY())));
448 
449  const tools::Rectangle aRectTwips = OutputDevice::LogicToLogic(aRect100thMM, MapMode(MapUnit::Map100thMM), MapMode(MapUnit::MapTwip));
450 
451  if (SfxViewShell* pViewShell = SfxViewShell::Current())
452  SfxLokHelper::notifyInvalidation(pViewShell, aRectTwips.toString());
453  }
454 }
455 
456 // ObjectContact section
458 {
459  if (!mpImpl->mpObjectContact)
460  {
462  const_cast<SdrPageWindow&>(*this),
463  "svx::svdraw::SdrPageWindow mpObjectContact");
464  }
465 
466  return *mpImpl->mpObjectContact;
467 }
468 
470 {
471  if (!mpImpl->mpObjectContact)
472  {
474  *this,
475  "svx::svdraw::SdrPageWindow mpObjectContact" );
476  }
477 
478  return *mpImpl->mpObjectContact;
479 }
480 
482 {
483  return mpImpl->mpObjectContact != nullptr;
484 }
485 
486 // #i26631#
488 {
489  if (mpImpl->mpObjectContact)
490  {
491  delete mpImpl->mpObjectContact;
492  mpImpl->mpObjectContact = nullptr;
493  }
494 }
495 
496 void SdrPageWindow::SetDesignMode( bool _bDesignMode ) const
497 {
499  DBG_ASSERT( pOC, "SdrPageWindow::SetDesignMode: invalid object contact!" );
500  if ( pOC )
501  pOC->SetUNOControlsDesignMode( _bDesignMode );
502 }
503 
504 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
long Width() const
rtl::Reference< sdr::overlay::OverlayManager > const & GetOverlayManager() const
SdrPaintWindow * mpOriginalPaintWindow
void SetWriterPageFrame(basegfx::B2IRectangle const &rPageFrame)
Definition: displayinfo.cxx:49
void Set(SdrLayerID a)
Definition: svdsob.hxx:48
const SdrPaintWindow * GetOriginalPaintWindow() const
virtual void PrepareProcessDisplay()
uno::Reference< awt::XControlContainer > mxControlContainer
long FRound(double fVal)
rtl::Reference< sdr::overlay::OverlayManager > const & GetOverlayManager() const
Point LogicToLogic(const Point &rPtSource, const MapMode *pMapModeSource, const MapMode *pMapModeDest) const
long Height() const
SdrView & GetView()
Definition: svdpagv.hxx:137
void unpatchPaintWindow()
bool IsMapModeEnabled() const
SdrObject * GetObj(size_t nNum) const
Definition: svdpage.cxx:773
css::uno::Reference< css::awt::XControlContainer > const & GetControlContainer(bool _bCreateIfNecessary=true) const
size_t GetObjCount() const
Definition: svdpage.cxx:767
sdr::contact::ObjectContact * mpObjectContact
bool IsEmpty() const
Definition: svdlayer.cxx:27
const MapMode & GetMapMode() const
void SetControlLayerProcessingActive(bool bDoPaint)
Definition: displayinfo.cxx:54
static css::uno::Reference< css::awt::XControlContainer > CreateControlContainer(vcl::Window *pWindow)
void EnableMapMode(bool bEnable=true)
double getMaxX() const
B2DPolyPolygon clipPolyPolygonOnPolyPolygon(const B2DPolyPolygon &rCandidate, const B2DPolyPolygon &rClip, bool bInside, bool bStroke)
void SetRedrawRegion(const vcl::Region &rNew)
void RedrawLayer(const SdrLayerID *pId, sdr::contact::ViewObjectContactRedirector *pRedirector, basegfx::B2IRectangle const *)
void SetProcessLayers(const SdrLayerIDSet &rSet)
Definition: displayinfo.cxx:38
static void notifyInvalidation(SfxViewShell const *pThisView, const OString &rPayload)
void RemoveControlContainer(const css::uno::Reference< css::awt::XControlContainer > &xCC)
Definition: fmview.cxx:445
void SetPageProcessingActive(bool bDoPaint)
Definition: displayinfo.cxx:62
BASEGFX_DLLPUBLIC void transform(const B2DHomMatrix &rMatrix)
bool OutputToWindow() const
bool IsPagePaintingAllowed() const
Definition: svdpntv.hxx:213
static SfxViewShell * Current()
void InsertControlContainer(const css::uno::Reference< css::awt::XControlContainer > &xCC)
Definition: fmview.cxx:423
double getMaxY() const
void SetUNOControlsDesignMode(bool _bDesignMode) const
sets all UNO controls which are associated with this ObjectContact to design or alive mode...
void DrawLine(const Point &rStartPt, const Point &rEndPt)
css::uno::Reference< css::lang::XComponent > xComponent
void ResetObjectContact()
void grow(double fValue)
void SetLineColor()
SdrPageView & mrPageView
const OUString & GetControlLayerName() const
Definition: svdlayer.hxx:151
#define DBG_ASSERT(sCon, aError)
uno_Any a
Impl(SdrPageView &rPageView, SdrPaintWindow &rPaintWindow)
void SetFillColor()
void SetRedrawArea(const vcl::Region &rRegion)
Definition: displayinfo.cxx:44
const vcl::Region & GetRedrawRegion() const
void SetViewObjectContactRedirector(ViewObjectContactRedirector *pNew)
Size GetOutputSizePixel() const
const sdr::contact::ObjectContact & GetObjectContact() const
Abstract DrawObject.
Definition: svdobj.hxx:312
virtual sdr::contact::ObjectContact * createViewSpecificObjectContact(SdrPageWindow &rPageWindow, const sal_Char *pDebugName) const
Definition: svdview.cxx:1459
void RedrawAll(sdr::contact::ViewObjectContactRedirector *pRedirector)
long X() const
void PrepareRedraw(const vcl::Region &rReg)
void patchPaintWindow(SdrPaintWindow &rPaintWindow)
void append(const B2DPolygon &rPolygon, sal_uInt32 nCount=1)
bool IsSet(SdrLayerID a) const
Definition: svdsob.hxx:66
Reference< XMultiServiceFactory > getProcessServiceFactory()
double getMinY() const
sal_uInt32 count() const
SdrPageWindow(const SdrPageWindow &)=delete
B2DPolygon adaptiveSubdivideByAngle(const B2DPolygon &rCandidate, double fAngleBound)
SdrPage * GetPage() const
Definition: svdpagv.hxx:173
bool HasObjectContact() const
determines whether there already exists an ObjectContact
int uniform_int_distribution(int a, int b)
SdrPaintWindow * mpPaintWindow
SdrPaintWindow & GetPaintWindow() const
void InvalidatePageWindow(const basegfx::B2DRange &rRange)
std::unique_ptr< Impl > mpImpl
virtual void ProcessDisplay(DisplayInfo &rDisplayInfo)
bool IsPrintPreview() const
Definition: svdpntv.hxx:497
const Point & GetOrigin() const
bool IsAntiAliasing() const
Reference< XSingleServiceFactory > xFactory
Reference< XModel > xModel
double getMinX() const
void ClearAll()
Definition: svdsob.hxx:76
A SdrPage contains exactly one SdrObjList and a description of the physical page dimensions (size / m...
Definition: svdpage.hxx:366
B2DPolyPolygon correctOrientations(const B2DPolyPolygon &rCandidate)
const SdrLayerAdmin & GetLayerAdmin() const
Definition: svdmodel.hxx:311
virtual void InvalidateOneWin(OutputDevice &rWin)
If the View should not call Invalidate() on the windows, override the following 2 methods and do some...
Definition: svdpntv.cxx:868
void Clear(SdrLayerID a)
Definition: svdsob.hxx:53
SdrLayerID GetLayerID(const OUString &rName) const
Definition: svdlayer.cxx:230
basegfx::B2DHomMatrix GetViewTransformation() const
SdrModel * GetModel() const
Definition: svdpntv.hxx:271
OutputDevice & GetOutputDevice() const
long Y() const
void SetDesignMode(bool _bDesignMode) const
sets all elements in the view which support a design and an alive mode into the given mode ...
SdrPageView & GetPageView() const