xref: /trunk/main/svx/source/sdr/contact/viewobjectcontactofpageobj.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 
31 #include <svx/sdr/contact/viewobjectcontactofpageobj.hxx>
32 #include <svx/sdr/contact/viewcontactofpageobj.hxx>
33 #include <svx/svdopage.hxx>
34 #include <svx/sdr/contact/displayinfo.hxx>
35 #include <basegfx/polygon/b2dpolygontools.hxx>
36 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
37 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
38 #include <svx/sdr/contact/objectcontactofobjlistpainter.hxx>
39 #include <basegfx/matrix/b2dhommatrix.hxx>
40 #include <svx/svdpage.hxx>
41 #include <svx/unoapi.hxx>
42 #include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx>
43 #include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
44 
45 //////////////////////////////////////////////////////////////////////////////
46 
47 using namespace com::sun::star;
48 
49 //////////////////////////////////////////////////////////////////////////////
50 
51 namespace sdr
52 {
53     namespace contact
54     {
55         class PagePrimitiveExtractor : public ObjectContactOfPagePainter, public Timer
56         {
57         private:
58             // the ViewObjectContactOfPageObj using this painter
59             ViewObjectContactOfPageObj&         mrViewObjectContactOfPageObj;
60 
61         public:
62             // basic constructor/destructor
63             PagePrimitiveExtractor(ViewObjectContactOfPageObj& rVOC);
64             virtual ~PagePrimitiveExtractor();
65 
66             // LazyInvalidate request. Supported here to not automatically
67             // invalidate the second interaction state all the time at the
68             // original OC
69             virtual void setLazyInvalidate(ViewObjectContact& rVOC);
70 
71             // From baseclass Timer, the timeout call triggered by te LazyInvalidate mechanism
72             virtual void Timeout();
73 
74             // get primitive visualization
75             drawinglayer::primitive2d::Primitive2DSequence createPrimitive2DSequenceForPage(const DisplayInfo& rDisplayInfo);
76 
77             // Own reaction on changes which will be forwarded to the OC of the owner-VOC
78             virtual void InvalidatePartOfView(const basegfx::B2DRange& rRange) const;
79 
80             // forward access to SdrPageView of ViewObjectContactOfPageObj
81             virtual bool isOutputToPrinter() const;
82             virtual bool isOutputToWindow() const;
83             virtual bool isOutputToVirtualDevice() const;
84             virtual bool isOutputToRecordingMetaFile() const;
85             virtual bool isOutputToPDFFile() const;
86             virtual bool isDrawModeGray() const;
87             virtual bool isDrawModeBlackWhite() const;
88             virtual bool isDrawModeHighContrast() const;
89             virtual SdrPageView* TryToGetSdrPageView() const;
90             virtual OutputDevice* TryToGetOutputDevice() const;
91         };
92 
93         PagePrimitiveExtractor::PagePrimitiveExtractor(
94             ViewObjectContactOfPageObj& rVOC)
95         :   ObjectContactOfPagePainter(0, rVOC.GetObjectContact()),
96             mrViewObjectContactOfPageObj(rVOC)
97         {
98             // make this renderer a preview renderer
99             setPreviewRenderer(true);
100 
101             // init timer
102             SetTimeout(1);
103             Stop();
104         }
105 
106         PagePrimitiveExtractor::~PagePrimitiveExtractor()
107         {
108             // execute missing LazyInvalidates and stop timer
109             Timeout();
110         }
111 
112         void PagePrimitiveExtractor::setLazyInvalidate(ViewObjectContact& /*rVOC*/)
113         {
114             // do NOT call parent, but remember that something is to do by
115             // starting the LazyInvalidateTimer
116             Start();
117         }
118 
119         // From baseclass Timer, the timeout call triggered by te LazyInvalidate mechanism
120         void PagePrimitiveExtractor::Timeout()
121         {
122             // stop the timer
123             Stop();
124 
125             // invalidate all LazyInvalidate VOCs new situations
126             const sal_uInt32 nVOCCount(getViewObjectContactCount());
127 
128             for(sal_uInt32 a(0); a < nVOCCount; a++)
129             {
130                 ViewObjectContact* pCandidate = getViewObjectContact(a);
131                 pCandidate->triggerLazyInvalidate();
132             }
133         }
134 
135         drawinglayer::primitive2d::Primitive2DSequence PagePrimitiveExtractor::createPrimitive2DSequenceForPage(const DisplayInfo& /*rDisplayInfo*/)
136         {
137             drawinglayer::primitive2d::Primitive2DSequence xRetval;
138             const SdrPage* pStartPage = GetStartPage();
139 
140             if(pStartPage)
141             {
142                 // update own ViewInformation2D for visualized page
143                 const drawinglayer::geometry::ViewInformation2D& rOriginalViewInformation = mrViewObjectContactOfPageObj.GetObjectContact().getViewInformation2D();
144                 const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D(
145                     rOriginalViewInformation.getObjectTransformation(),
146                     rOriginalViewInformation.getViewTransformation(),
147 
148                     // #i101075# use empty range for page content here to force
149                     // the content not to be physically clipped in any way. This
150                     // would be possible, but would require the internal transformation
151                     // which maps between the page visualisation object and the page
152                     // content, including the aspect ratios (for details see in
153                     // PagePreviewPrimitive2D::create2DDecomposition)
154                     basegfx::B2DRange(),
155 
156                     GetXDrawPageForSdrPage(const_cast< SdrPage* >(pStartPage)),
157                     0.0, // no time; page previews are not animated
158                     rOriginalViewInformation.getExtendedInformationSequence());
159                 updateViewInformation2D(aNewViewInformation2D);
160 
161                 // create copy of DisplayInfo to set PagePainting
162                 DisplayInfo aDisplayInfo;
163 
164                 // get page's VOC
165                 ViewObjectContact& rDrawPageVOContact = pStartPage->GetViewContact().GetViewObjectContact(*this);
166 
167                 // get whole Primitive2DSequence
168                 xRetval = rDrawPageVOContact.getPrimitive2DSequenceHierarchy(aDisplayInfo);
169             }
170 
171             return xRetval;
172         }
173 
174         void PagePrimitiveExtractor::InvalidatePartOfView(const basegfx::B2DRange& rRange) const
175         {
176             // an invalidate is called at this view, this needs to be translated to an invalidate
177             // for the using VOC. Coordinates are in page coordinate system.
178             const SdrPage* pStartPage = GetStartPage();
179 
180             if(pStartPage && !rRange.isEmpty())
181             {
182                 const basegfx::B2DRange aPageRange(0.0, 0.0, (double)pStartPage->GetWdt(), (double)pStartPage->GetHgt());
183 
184                 if(rRange.overlaps(aPageRange))
185                 {
186                     // if object on the page is inside or overlapping with page, create ActionChanged() for
187                     // involved VOC
188                     mrViewObjectContactOfPageObj.ActionChanged();
189                 }
190             }
191         }
192 
193         // forward access to SdrPageView to VOCOfPageObj
194         bool PagePrimitiveExtractor::isOutputToPrinter() const { return mrViewObjectContactOfPageObj.GetObjectContact().isOutputToPrinter(); }
195         bool PagePrimitiveExtractor::isOutputToWindow() const { return mrViewObjectContactOfPageObj.GetObjectContact().isOutputToWindow(); }
196         bool PagePrimitiveExtractor::isOutputToVirtualDevice() const { return mrViewObjectContactOfPageObj.GetObjectContact().isOutputToVirtualDevice(); }
197         bool PagePrimitiveExtractor::isOutputToRecordingMetaFile() const { return mrViewObjectContactOfPageObj.GetObjectContact().isOutputToRecordingMetaFile(); }
198         bool PagePrimitiveExtractor::isOutputToPDFFile() const { return mrViewObjectContactOfPageObj.GetObjectContact().isOutputToPDFFile(); }
199         bool PagePrimitiveExtractor::isDrawModeGray() const { return mrViewObjectContactOfPageObj.GetObjectContact().isDrawModeGray(); }
200         bool PagePrimitiveExtractor::isDrawModeBlackWhite() const { return mrViewObjectContactOfPageObj.GetObjectContact().isDrawModeBlackWhite(); }
201         bool PagePrimitiveExtractor::isDrawModeHighContrast() const { return mrViewObjectContactOfPageObj.GetObjectContact().isDrawModeHighContrast(); }
202         SdrPageView* PagePrimitiveExtractor::TryToGetSdrPageView() const { return mrViewObjectContactOfPageObj.GetObjectContact().TryToGetSdrPageView(); }
203         OutputDevice* PagePrimitiveExtractor::TryToGetOutputDevice() const { return mrViewObjectContactOfPageObj.GetObjectContact().TryToGetOutputDevice(); }
204     } // end of namespace contact
205 } // end of namespace sdr
206 
207 //////////////////////////////////////////////////////////////////////////////
208 
209 namespace sdr
210 {
211     namespace contact
212     {
213         drawinglayer::primitive2d::Primitive2DSequence ViewObjectContactOfPageObj::createPrimitive2DSequence(const DisplayInfo& rDisplayInfo) const
214         {
215             drawinglayer::primitive2d::Primitive2DSequence xRetval;
216             const SdrPageObj& rPageObject((static_cast< ViewContactOfPageObj& >(GetViewContact())).GetPageObj());
217             const SdrPage* pPage = rPageObject.GetReferencedPage();
218             const svtools::ColorConfig aColorConfig;
219 
220             // get PageObject's geometry
221             basegfx::B2DHomMatrix aPageObjectTransform;
222             {
223                 const Rectangle aPageObjectModelData(rPageObject.GetLastBoundRect());
224                 const basegfx::B2DRange aPageObjectBound(
225                     aPageObjectModelData.Left(), aPageObjectModelData.Top(),
226                     aPageObjectModelData.Right(), aPageObjectModelData.Bottom());
227 
228                 aPageObjectTransform.set(0, 0, aPageObjectBound.getWidth());
229                 aPageObjectTransform.set(1, 1, aPageObjectBound.getHeight());
230                 aPageObjectTransform.set(0, 2, aPageObjectBound.getMinX());
231                 aPageObjectTransform.set(1, 2, aPageObjectBound.getMinY());
232             }
233 
234             // #i102637# add gray frame also when printing and page exists (handout pages)
235             const bool bCreateGrayFrame(!GetObjectContact().isOutputToPrinter() || pPage);
236 
237             // get displayed page's content. This is the uscaled page content
238             if(mpExtractor && pPage)
239             {
240                 // get displayed page's geometry
241                 drawinglayer::primitive2d::Primitive2DSequence xPageContent;
242                 const Size aPageSize(pPage->GetSize());
243                 const double fPageWidth(aPageSize.getWidth());
244                 const double fPageHeight(aPageSize.getHeight());
245 
246                 // The case that a PageObject contains another PageObject which visualizes the
247                 // same page again would lead to a recursion. Limit that recursion depth to one
248                 // by using a local static bool
249                 static bool bInCreatePrimitive2D(false);
250 
251                 if(bInCreatePrimitive2D)
252                 {
253                     // Recursion is possible. Create a replacement primitive
254                     xPageContent.realloc(2);
255                     const Color aDocColor(aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor);
256                     const Color aBorderColor(aColorConfig.GetColorValue(svtools::DOCBOUNDARIES).nColor);
257                     const basegfx::B2DRange aPageBound(0.0, 0.0, fPageWidth, fPageHeight);
258                     const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(aPageBound));
259 
260                     // add replacement fill
261                     xPageContent[0L] = drawinglayer::primitive2d::Primitive2DReference(
262                         new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aOutline), aDocColor.getBColor()));
263 
264                     // add replacement border
265                     xPageContent[1L] = drawinglayer::primitive2d::Primitive2DReference(
266                         new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aOutline, aBorderColor.getBColor()));
267                 }
268                 else
269                 {
270                     // set recursion flag
271                     bInCreatePrimitive2D = true;
272 
273                     // init extractor, guarantee existance, set page there
274                     mpExtractor->SetStartPage(pPage);
275 
276                     // #i105548# also need to copy the VOCRedirector for sub-content creation
277                     mpExtractor->SetViewObjectContactRedirector(GetObjectContact().GetViewObjectContactRedirector());
278 
279                     // create page content
280                     xPageContent = mpExtractor->createPrimitive2DSequenceForPage(rDisplayInfo);
281 
282                     // #i105548# reset VOCRedirector to not accidentially have a pointer to a
283                     // temporary class, so calls to it are avoided safely
284                     mpExtractor->SetViewObjectContactRedirector(0);
285 
286                     // reset recursion flag
287                     bInCreatePrimitive2D = false;
288                 }
289 
290                 // prepare retval
291                 if(xPageContent.hasElements())
292                 {
293                     const uno::Reference< drawing::XDrawPage > xDrawPage(GetXDrawPageForSdrPage(const_cast< SdrPage*>(pPage)));
294                     const drawinglayer::primitive2d::Primitive2DReference xPagePreview(new drawinglayer::primitive2d::PagePreviewPrimitive2D(
295                         xDrawPage, aPageObjectTransform, fPageWidth, fPageHeight, xPageContent, true));
296                     xRetval = drawinglayer::primitive2d::Primitive2DSequence(&xPagePreview, 1);
297                 }
298             }
299             else if(bCreateGrayFrame)
300             {
301                 // #i105146# no content, but frame display. To make hitting the page preview objects
302                 // on the handout page more simple, add hidden fill geometry
303                 const drawinglayer::primitive2d::Primitive2DReference xFrameHit(
304                     drawinglayer::primitive2d::createHiddenGeometryPrimitives2D(
305                         false,
306                         aPageObjectTransform));
307                 xRetval = drawinglayer::primitive2d::Primitive2DSequence(&xFrameHit, 1);
308             }
309 
310             // add a gray outline frame, except not when printing
311             if(bCreateGrayFrame)
312             {
313                 const Color aFrameColor(aColorConfig.GetColorValue(svtools::OBJECTBOUNDARIES).nColor);
314                 basegfx::B2DPolygon aOwnOutline(basegfx::tools::createUnitPolygon());
315                 aOwnOutline.transform(aPageObjectTransform);
316 
317                 const drawinglayer::primitive2d::Primitive2DReference xGrayFrame(
318                     new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aOwnOutline, aFrameColor.getBColor()));
319 
320                 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(xRetval, xGrayFrame);
321             }
322 
323             return xRetval;
324         }
325 
326         ViewObjectContactOfPageObj::ViewObjectContactOfPageObj(ObjectContact& rObjectContact, ViewContact& rViewContact)
327         :   ViewObjectContactOfSdrObj(rObjectContact, rViewContact),
328             mpExtractor(new PagePrimitiveExtractor(*this))
329         {
330         }
331 
332         ViewObjectContactOfPageObj::~ViewObjectContactOfPageObj()
333         {
334             // delete the helper OC
335             if(mpExtractor)
336             {
337                 // remember candidate and reset own pointer to avoid action when createPrimitive2DSequence()
338                 // would be called for any reason
339                 PagePrimitiveExtractor* pCandidate = mpExtractor;
340                 mpExtractor = 0;
341 
342                 // also reset the StartPage to avoid ActionChanged() forwardings in the
343                 // PagePrimitiveExtractor::InvalidatePartOfView() implementation
344                 pCandidate->SetStartPage(0);
345                 delete pCandidate;
346             }
347         }
348     } // end of namespace contact
349 } // end of namespace sdr
350 
351 //////////////////////////////////////////////////////////////////////////////
352 // eof
353