xref: /trunk/main/svx/source/svdraw/sdrpagewindow.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svx.hxx"
30 #include <svx/sdrpagewindow.hxx>
31 #include <com/sun/star/awt/XWindow.hpp>
32 #include <com/sun/star/beans/XPropertySet.hpp>
33 #include <com/sun/star/awt/PosSize.hpp>
34 #include <com/sun/star/util/XModeChangeBroadcaster.hpp>
35 #include <comphelper/processfactory.hxx>
36 #include <vcl/svapp.hxx>
37 #include <toolkit/helper/vclunohelper.hxx>
38 #include <svx/svdouno.hxx>
39 #include <svx/svdpage.hxx>
40 #include <svx/svdview.hxx>
41 #include <svx/svdpagv.hxx>
42 #include <svx/sdrpaintwindow.hxx>
43 #include <svx/sdr/contact/objectcontactofpageview.hxx>
44 #include <svx/sdr/contact/displayinfo.hxx>
45 #include <vos/mutex.hxx>
46 #include <svx/fmview.hxx>
47 #include <basegfx/matrix/b2dhommatrix.hxx>
48 
49 ////////////////////////////////////////////////////////////////////////////////////////////////////
50 
51 using namespace ::rtl;
52 using namespace ::com::sun::star;
53 
54 ////////////////////////////////////////////////////////////////////////////////////////////////////
55 
56 ::com::sun::star::uno::Reference< ::com::sun::star::awt::XControlContainer > SdrPageWindow::GetControlContainer( bool _bCreateIfNecessary ) const
57 {
58     if ( !mxControlContainer.is() && _bCreateIfNecessary )
59     {
60         SdrView& rView = GetPageView().GetView();
61 
62         const SdrPaintWindow& rPaintWindow( GetOriginalPaintWindow() ? *GetOriginalPaintWindow() : GetPaintWindow() );
63         if ( rPaintWindow.OutputToWindow() && !rView.IsPrintPreview() )
64         {
65             Window& rWindow = dynamic_cast< Window& >( rPaintWindow.GetOutputDevice() );
66             const_cast< SdrPageWindow* >( this )->mxControlContainer = VCLUnoHelper::CreateControlContainer( &rWindow );
67 
68             // #100394# xC->setVisible triggers window->Show() and this has
69             // problems when the view is not completely constructed which may
70             // happen when loading. This leads to accessibility broadcasts which
71             // throw asserts due to the not finished view. All this chan be avoided
72             // since xC->setVisible is here called only for the side effect in
73             // UnoControlContainer::setVisible(...) which calls createPeer(...).
74             // This will now be called directly from here.
75 
76             // UnoContainerModel erzeugen
77             // uno::Reference< awt::XWindow > xC(mxControlContainer, uno::UNO_QUERY);
78             // CreateControlContainer() is only used from
79             // , thus it seems not necessary to make
80             // it visible her at all.
81             // #58917# Das Show darf nicht am VCL-Fenster landen, weil dann Assertion vom SFX
82             // sal_Bool bVis = pWindow->IsVisible();
83             // xC->setVisible(sal_True);
84             // if ( !bVis )
85             //  pWindow->Hide();
86             //  if( !mxContext.is() && bVisible )
87             //      // Es ist ein TopWindow, also automatisch anzeigen
88             //      createPeer( ::com::sun::star::uno::Reference< ::com::sun::star::awt::XToolkit > (), ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindowPeer > () );
89 
90             uno::Reference< awt::XControl > xControl(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( ::com::sun::star::uno::Reference< ::com::sun::star::awt::XToolkit > (),
97                         ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindowPeer > () );
98                 }
99             }
100         }
101         else
102         {
103             // Printer und VirtualDevice, bzw. kein OutDev
104             uno::Reference< lang::XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory() );
105             if( xFactory.is() )
106             {
107                 const_cast< SdrPageWindow* >( this )->mxControlContainer = uno::Reference< awt::XControlContainer >(xFactory->createInstance(rtl::OUString::createFromAscii("com.sun.star.awt.UnoControlContainer")), uno::UNO_QUERY);
108                 uno::Reference< awt::XControlModel > xModel(xFactory->createInstance(rtl::OUString::createFromAscii("com.sun.star.awt.UnoControlContainerModel")), uno::UNO_QUERY);
109                 uno::Reference< awt::XControl > xControl(mxControlContainer, uno::UNO_QUERY);
110                 if (xControl.is())
111                     xControl->setModel(xModel);
112 
113                 OutputDevice& rOutDev = rPaintWindow.GetOutputDevice();
114                 Point aPosPix = rOutDev.GetMapMode().GetOrigin();
115                 Size aSizePix = rOutDev.GetOutputSizePixel();
116 
117                 uno::Reference< awt::XWindow > xContComp(mxControlContainer, uno::UNO_QUERY);
118                 if( xContComp.is() )
119                     xContComp->setPosSize(aPosPix.X(), aPosPix.Y(), aSizePix.Width(), aSizePix.Height(), awt::PosSize::POSSIZE);
120             }
121         }
122 
123         FmFormView* pViewAsFormView = dynamic_cast< FmFormView* >( &rView );
124         if ( pViewAsFormView )
125             pViewAsFormView->InsertControlContainer(mxControlContainer);
126     }
127     return mxControlContainer;
128 }
129 
130 SdrPageWindow::SdrPageWindow(SdrPageView& rPageView, SdrPaintWindow& rPaintWindow)
131 :   mpObjectContact(0L),
132     mrPageView(rPageView),
133     mpPaintWindow(&rPaintWindow),
134     mpOriginalPaintWindow(NULL)
135 {
136 }
137 
138 SdrPageWindow::~SdrPageWindow()
139 {
140     // #110094#, #i26631#
141     ResetObjectContact();
142 
143     if (mxControlContainer.is())
144     {
145         SdrView& rView = GetPageView().GetView();
146 
147         // notify derived views
148         FmFormView* pViewAsFormView = dynamic_cast< FmFormView* >( &rView );
149         if ( pViewAsFormView )
150             pViewAsFormView->RemoveControlContainer(mxControlContainer);
151 
152         // dispose the control container
153         uno::Reference< lang::XComponent > xComponent(mxControlContainer, uno::UNO_QUERY);
154         xComponent->dispose();
155     }
156 }
157 
158 // #110094# ObjectContact section
159 sdr::contact::ObjectContact* SdrPageWindow::CreateViewSpecificObjectContact()
160 {
161     return new sdr::contact::ObjectContactOfPageView(*this);
162 }
163 
164 // OVERLAYMANAGER
165 ::sdr::overlay::OverlayManager* SdrPageWindow::GetOverlayManager() const
166 {
167     return GetPaintWindow().GetOverlayManager();
168 }
169 
170 void SdrPageWindow::patchPaintWindow(SdrPaintWindow& rPaintWindow)
171 {
172     mpOriginalPaintWindow = mpPaintWindow;
173     mpPaintWindow = &rPaintWindow;
174 }
175 
176 void SdrPageWindow::unpatchPaintWindow()
177 {
178     DBG_ASSERT(mpOriginalPaintWindow, "SdrPageWindow::unpatchPaintWindow: paint window not patched!" );
179     if ( mpOriginalPaintWindow )
180     {
181         mpPaintWindow = mpOriginalPaintWindow;
182         mpOriginalPaintWindow = NULL;
183     }
184 }
185 
186 void SdrPageWindow::PrePaint()
187 {
188     // give OC the chance to do ProcessDisplay preparations
189     if(HasObjectContact())
190     {
191         GetObjectContact().PrepareProcessDisplay();
192     }
193 }
194 
195 void SdrPageWindow::PostPaint()
196 {
197 }
198 
199 void SdrPageWindow::PrepareRedraw(const Region& rReg)
200 {
201     // evtl. give OC the chance to do ProcessDisplay preparations
202     if(HasObjectContact())
203     {
204         GetObjectContact().PrepareProcessDisplay();
205     }
206 
207     // remember eventually changed RedrawArea at PaintWindow for usage with
208     // overlay and PreRenderDevice stuff
209     GetPaintWindow().SetRedrawRegion(rReg);
210 }
211 
212 //////////////////////////////////////////////////////////////////////////////
213 // clip test
214 #ifdef CLIPPER_TEST
215 #include <svx/svdopath.hxx>
216 #include <basegfx/polygon/b2dpolygon.hxx>
217 #include <vcl/salbtype.hxx>     // FRound
218 #include <basegfx/polygon/b2dpolygoncutandtouch.hxx>
219 #include <basegfx/polygon/b2dpolypolygontools.hxx>
220 #include <basegfx/polygon/b2dpolygontools.hxx>
221 #include <basegfx/polygon/b2dpolygonclipper.hxx>
222 
223 // for ::std::sort
224 #include <algorithm>
225 
226 namespace
227 {
228     void impPaintStrokePolygon(const basegfx::B2DPolygon& rCandidate, OutputDevice& rOutDev, Color aColor)
229     {
230         basegfx::B2DPolygon aCandidate(rCandidate);
231 
232         if(aCandidate.areControlPointsUsed())
233         {
234             aCandidate = basegfx::tools::adaptiveSubdivideByAngle(rCandidate);
235         }
236 
237         if(aCandidate.count())
238         {
239             const sal_uInt32 nLoopCount(aCandidate.isClosed() ? aCandidate.count() : aCandidate.count() - 1L);
240             rOutDev.SetFillColor();
241             rOutDev.SetLineColor(aColor);
242 
243             for(sal_uInt32 a(0L); a < nLoopCount; a++)
244             {
245                 const basegfx::B2DPoint aBStart(aCandidate.getB2DPoint(a));
246                 const basegfx::B2DPoint aBEnd(aCandidate.getB2DPoint((a + 1) % aCandidate.count()));
247                 const Point aStart(FRound(aBStart.getX()), FRound(aBStart.getY()));
248                 const Point aEnd(FRound(aBEnd.getX()), FRound(aBEnd.getY()));
249                 rOutDev.DrawLine(aStart, aEnd);
250             }
251         }
252     }
253 
254     void impTryTest(const SdrPageView& rPageView, OutputDevice& rOutDev)
255     {
256         if(rPageView.GetPage() && rPageView.GetPage()->GetObjCount() >= 2L)
257         {
258             SdrPage* pPage = rPageView.GetPage();
259             SdrObject* pObjA = pPage->GetObj(0L);
260 
261             if(pObjA && pObjA->ISA(SdrPathObj))
262             {
263                 basegfx::B2DPolyPolygon aPolyA(((SdrPathObj*)pObjA)->GetPathPoly());
264                 aPolyA = basegfx::tools::correctOrientations(aPolyA);
265 
266                 basegfx::B2DPolyPolygon aPolyB;
267 
268                 for(sal_uInt32 a(1L); a < rPageView.GetPage()->GetObjCount(); a++)
269                 {
270                     SdrObject* pObjB = pPage->GetObj(a);
271 
272                     if(pObjB && pObjB->ISA(SdrPathObj))
273                     {
274                         basegfx::B2DPolyPolygon aCandidate(((SdrPathObj*)pObjB)->GetPathPoly());
275                         aCandidate = basegfx::tools::correctOrientations(aCandidate);
276                         aPolyB.append(aCandidate);
277                     }
278                 }
279 
280                 if(aPolyA.count() && aPolyA.isClosed() && aPolyB.count())
281                 {
282                     // poly A is the clipregion, clip poly b against it. Algo depends on
283                     // poly b being closed.
284                     basegfx::B2DPolyPolygon aResult(basegfx::tools::clipPolyPolygonOnPolyPolygon(aPolyB, aPolyA));
285 
286                     for(sal_uInt32 a(0L); a < aResult.count(); a++)
287                     {
288                         Color aColor(rand()%255, rand()%255, rand()%255);
289                         impPaintStrokePolygon(aResult.getB2DPolygon(a), rOutDev, aColor);
290                     }
291 
292                     bool bBla = true;
293                 }
294             }
295         }
296     }
297 } // end of anonymous namespace
298 #endif // CLIPPER_TEST
299 
300 //////////////////////////////////////////////////////////////////////////////
301 
302 void SdrPageWindow::RedrawAll(sdr::contact::ViewObjectContactRedirector* pRedirector) const
303 {
304     // set Redirector
305     GetObjectContact().SetViewObjectContactRedirector(pRedirector);
306 
307     // set PaintingPageView
308     const SdrView& rView = mrPageView.GetView();
309     SdrModel& rModel = *((SdrModel*)rView.GetModel());
310 
311     // get to be processed layers
312     const sal_Bool bPrinter(GetPaintWindow().OutputToPrinter());
313     SetOfByte aProcessLayers = bPrinter ? mrPageView.GetPrintableLayers() : mrPageView.GetVisibleLayers();
314 
315     // create PaintInfoRec, #114359# use Rectangle only temporarily
316     const Region& rRegion = GetPaintWindow().GetRedrawRegion();
317 
318     // create processing data
319     sdr::contact::DisplayInfo aDisplayInfo;
320 
321     // Draw all layers. do NOT draw form layer from CompleteRedraw, this is done separate
322     // as a single layer paint
323     const SdrLayerAdmin& rLayerAdmin = rModel.GetLayerAdmin();
324     const SdrLayerID nControlLayerId = rLayerAdmin.GetLayerID(rLayerAdmin.GetControlLayerName(), sal_False);
325     aProcessLayers.Clear(nControlLayerId);
326 
327     // still something to paint?
328     if(!aProcessLayers.IsEmpty())
329     {
330         aDisplayInfo.SetProcessLayers(aProcessLayers);
331 
332         // Set region as redraw area
333         aDisplayInfo.SetRedrawArea(rRegion);
334 
335         // Draw/Impress
336         aDisplayInfo.SetPageProcessingActive(rView.IsPagePaintingAllowed()); // #i72889#
337 
338         // paint page
339         GetObjectContact().ProcessDisplay(aDisplayInfo);
340     }
341 
342     // reset redirector
343     GetObjectContact().SetViewObjectContactRedirector(0L);
344 
345     // LineClip test
346 #ifdef CLIPPER_TEST
347     if(true)
348     {
349         impTryTest(GetPageView(), GetPaintWindow().GetOutputDevice());
350     }
351 #endif // CLIPPER_TEST
352 }
353 
354 void SdrPageWindow::RedrawLayer(const SdrLayerID* pId, sdr::contact::ViewObjectContactRedirector* pRedirector) const
355 {
356     // set redirector
357     GetObjectContact().SetViewObjectContactRedirector(pRedirector);
358 
359     // set PaintingPageView
360     const SdrView& rView = mrPageView.GetView();
361     SdrModel& rModel = *((SdrModel*)rView.GetModel());
362 
363     // get the layers to process
364     const sal_Bool bPrinter(GetPaintWindow().OutputToPrinter());
365     SetOfByte aProcessLayers = bPrinter ? mrPageView.GetPrintableLayers() : 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(), sal_False);
373         const sal_Bool bControlLayerProcessingActive(pId && nControlLayerId == *pId);
374 
375         // create PaintInfoRec, use Rectangle only temporarily
376         const 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         // paint page
398         GetObjectContact().ProcessDisplay(aDisplayInfo);
399     }
400 
401     // reset redirector
402     GetObjectContact().SetViewObjectContactRedirector(0L);
403 }
404 
405 // Invalidate call, used from ObjectContact(OfPageView) in InvalidatePartOfView(...)
406 void SdrPageWindow::InvalidatePageWindow(const basegfx::B2DRange& rRange)
407 {
408     if(GetPageView().IsVisible() && GetPaintWindow().OutputToWindow())
409     {
410         const SvtOptionsDrawinglayer aDrawinglayerOpt;
411         Window& rWindow(static_cast< Window& >(GetPaintWindow().GetOutputDevice()));
412         basegfx::B2DRange aDiscreteRange(rRange);
413         aDiscreteRange.transform(rWindow.GetViewTransformation());
414 
415         if(aDrawinglayerOpt.IsAntiAliasing())
416         {
417             // invalidate one discrete unit more under the assumption that AA
418             // needs one pixel more
419             aDiscreteRange.grow(1.0);
420         }
421 
422         const Rectangle aVCLDiscreteRectangle(
423                 (sal_Int32)floor(aDiscreteRange.getMinX()), (sal_Int32)floor(aDiscreteRange.getMinY()),
424                 (sal_Int32)ceil(aDiscreteRange.getMaxX()), (sal_Int32)ceil(aDiscreteRange.getMaxY()));
425         const bool bWasMapModeEnabled(rWindow.IsMapModeEnabled());
426 
427         rWindow.EnableMapMode(false);
428         rWindow.Invalidate(aVCLDiscreteRectangle, INVALIDATE_NOERASE);
429         rWindow.EnableMapMode(bWasMapModeEnabled);
430     }
431 }
432 
433 // #110094# ObjectContact section
434 sdr::contact::ObjectContact& SdrPageWindow::GetObjectContact() const
435 {
436     if(!mpObjectContact)
437     {
438         ((SdrPageWindow*)this)->mpObjectContact = ((SdrPageWindow*)this)->CreateViewSpecificObjectContact();
439     }
440 
441     return *mpObjectContact;
442 }
443 
444 bool SdrPageWindow::HasObjectContact() const
445 {
446     return ( mpObjectContact != NULL );
447 }
448 
449 // #i26631#
450 void SdrPageWindow::ResetObjectContact()
451 {
452     if(mpObjectContact)
453     {
454         delete mpObjectContact;
455         mpObjectContact = 0L;
456     }
457 }
458 
459 void SdrPageWindow::SetDesignMode( bool _bDesignMode ) const
460 {
461     const ::sdr::contact::ObjectContactOfPageView* pOC = dynamic_cast< const ::sdr::contact::ObjectContactOfPageView* >( &GetObjectContact() );
462     DBG_ASSERT( pOC, "SdrPageWindow::SetDesignMode: invalid object contact!" );
463     if ( pOC )
464         pOC->SetUNOControlsDesignMode( _bDesignMode );
465 }
466 
467 ////////////////////////////////////////////////////////////////////////////////////////////////////
468 // eof
469