xref: /trunk/main/svx/source/svdraw/sdrpagewindow.cxx (revision cdf0e10c)
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