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 #include "precompiled_svx.hxx"
29 #include <svx/sdr/primitive2d/sdrtextprimitive2d.hxx>
30 #include <svx/svdotext.hxx>
31 #include <basegfx/color/bcolor.hxx>
32 #include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
33 #include <drawinglayer/primitive2d/texthierarchyprimitive2d.hxx>
34 #include <editeng/outlobj.hxx>
35 #include <editeng/editobj.hxx>
36 #include <editeng/flditem.hxx>
37 #include <drawinglayer/geometry/viewinformation2d.hxx>
38 #include <svx/unoapi.hxx>
39 #include <svx/svdpage.hxx>
40 #include <svx/svdmodel.hxx>
41 #include <svx/svdoutl.hxx>
42 #include <com/sun/star/beans/XPropertySet.hpp>
43 
44 //////////////////////////////////////////////////////////////////////////////
45 
46 using namespace com::sun::star;
47 
48 //////////////////////////////////////////////////////////////////////////////
49 
50 namespace
51 {
52     sal_Int16 getPageNumber(const uno::Reference< drawing::XDrawPage >& rxDrawPage)
53     {
54         sal_Int16 nRetval(0);
55         uno::Reference< beans::XPropertySet > xSet(rxDrawPage, uno::UNO_QUERY);
56 
57         if (xSet.is())
58         {
59             try
60             {
61                 const uno::Any aNumber(xSet->getPropertyValue(::rtl::OUString::createFromAscii("Number")));
62                 aNumber >>= nRetval;
63             }
64             catch(const uno::Exception&)
65             {
66                 OSL_ASSERT(false);
67             }
68         }
69 
70         return nRetval;
71     }
72 
73     sal_Int16 getPageCount(const uno::Reference< drawing::XDrawPage >& rxDrawPage)
74     {
75         sal_Int16 nRetval(0);
76         SdrPage* pPage = GetSdrPageFromXDrawPage(rxDrawPage);
77 
78         if(pPage && pPage->GetModel())
79         {
80 			if( (pPage->GetPageNum() == 0) && !pPage->IsMasterPage() )
81 			{
82 				// handout page!
83 				return pPage->GetModel()->getHandoutPageCount();
84 			}
85 			else
86 			{
87 				const sal_uInt16 nPageCount(pPage->GetModel()->GetPageCount());
88 				nRetval = ((sal_Int16)nPageCount - 1) / 2;
89 			}
90         }
91 
92         return nRetval;
93     }
94 } // end of anonymous namespace
95 
96 //////////////////////////////////////////////////////////////////////////////
97 
98 namespace drawinglayer
99 {
100 	namespace primitive2d
101 	{
102 		// support for XTEXT_PAINTSHAPE_BEGIN/XTEXT_PAINTSHAPE_END Metafile comments
103         // for slideshow. This uses TextHierarchyBlockPrimitive2D to mark a text block.
104         // ATM there is only one text block per SdrObject, this may get more in the future
105         Primitive2DSequence SdrTextPrimitive2D::encapsulateWithTextHierarchyBlockPrimitive2D(const Primitive2DSequence& rCandidate) const
106         {
107             Primitive2DReference xReference(new TextHierarchyBlockPrimitive2D(rCandidate));
108             Primitive2DSequence xRetval(&xReference, 1);
109 
110             return xRetval;
111         }
112 
113         SdrTextPrimitive2D::SdrTextPrimitive2D(
114             const SdrText* pSdrText,
115             const OutlinerParaObject& rOutlinerParaObject)
116 		:	BufferedDecompositionPrimitive2D(),
117 			mrSdrText(const_cast< SdrText* >(pSdrText)),
118             maOutlinerParaObject(rOutlinerParaObject),
119             mxLastVisualizingPage(),
120             mnLastPageNumber(0),
121             mnLastPageCount(0),
122             maLastTextBackgroundColor(),
123 			mbContainsPageField(false),
124 			mbContainsPageCountField(false),
125             mbContainsOtherFields(false)
126 		{
127 			const EditTextObject& rETO = maOutlinerParaObject.GetTextObject();
128 
129             mbContainsPageField = rETO.HasField(SvxPageField::StaticType());
130             mbContainsPageCountField = rETO.HasField(SvxPagesField::StaticType());
131 			mbContainsOtherFields = rETO.HasField(SvxHeaderField::StaticType())
132 				|| rETO.HasField(SvxFooterField::StaticType())
133 				|| rETO.HasField(SvxDateTimeField::StaticType())
134 				|| rETO.HasField(SvxAuthorField::StaticType());
135 		}
136 
137 		bool SdrTextPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
138 		{
139 			if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
140 			{
141 				const SdrTextPrimitive2D& rCompare = (SdrTextPrimitive2D&)rPrimitive;
142 
143                 return (
144 
145                     // compare OPO and content, but not WrongList
146                     getOutlinerParaObject() == rCompare.getOutlinerParaObject()
147 
148                     // also compare WrongList (not-persistent data, but visualized)
149                     && getOutlinerParaObject().isWrongListEqual(rCompare.getOutlinerParaObject()));
150 			}
151 
152 			return false;
153 		}
154 
155 		Primitive2DSequence SdrTextPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
156         {
157             uno::Reference< drawing::XDrawPage > xCurrentlyVisualizingPage;
158 			bool bCurrentlyVisualizingPageIsSet(false);
159 			Color aNewTextBackgroundColor;
160 			bool bNewTextBackgroundColorIsSet(false);
161             sal_Int16 nCurrentlyValidPageNumber(0);
162             sal_Int16 nCurrentlyValidPageCount(0);
163 
164 			if(getBuffered2DDecomposition().hasElements())
165             {
166                 bool bDoDelete(false);
167 
168                 // check visualized page
169                 if(mbContainsPageField || mbContainsPageCountField || mbContainsOtherFields)
170                 {
171                     // get visualized page and remember
172                     xCurrentlyVisualizingPage = rViewInformation.getVisualizedPage();
173 					bCurrentlyVisualizingPageIsSet = true;
174 
175                     if(xCurrentlyVisualizingPage != mxLastVisualizingPage)
176                     {
177                         bDoDelete = true;
178                     }
179 
180                     // #i98870# check visualized PageNumber
181                     if(!bDoDelete && mbContainsPageField)
182                     {
183                         nCurrentlyValidPageNumber = getPageNumber(xCurrentlyVisualizingPage);
184 
185                         if(nCurrentlyValidPageNumber != mnLastPageNumber)
186                         {
187                             bDoDelete = true;
188                         }
189                     }
190 
191                     // #i98870# check visualized PageCount, too
192                     if(!bDoDelete && mbContainsPageCountField)
193                     {
194                         nCurrentlyValidPageCount = getPageCount(xCurrentlyVisualizingPage);
195 
196                         if(nCurrentlyValidPageCount != mnLastPageCount)
197                         {
198                             bDoDelete = true;
199                         }
200                     }
201                 }
202 
203                 // #i101443#  check change of TextBackgroundolor
204                 if(!bDoDelete && getSdrText() && getSdrText()->GetModel())
205 				{
206 					SdrOutliner& rDrawOutliner = getSdrText()->GetModel()->GetDrawOutliner(0);
207 					aNewTextBackgroundColor = rDrawOutliner.GetBackgroundColor();
208 					bNewTextBackgroundColorIsSet = true;
209 
210 					if(aNewTextBackgroundColor != maLastTextBackgroundColor)
211 					{
212 						bDoDelete = true;
213 					}
214 				}
215 
216 				if(bDoDelete)
217                 {
218     			    const_cast< SdrTextPrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DSequence());
219                 }
220             }
221 
222 			if(!getBuffered2DDecomposition().hasElements())
223             {
224 				if(!bCurrentlyVisualizingPageIsSet && mbContainsPageField)
225 				{
226                     xCurrentlyVisualizingPage = rViewInformation.getVisualizedPage();
227 				}
228 
229                 if(!nCurrentlyValidPageNumber && mbContainsPageField)
230                 {
231                     nCurrentlyValidPageNumber = getPageNumber(xCurrentlyVisualizingPage);
232                 }
233 
234                 if(!nCurrentlyValidPageCount && mbContainsPageCountField)
235                 {
236                     nCurrentlyValidPageCount = getPageCount(xCurrentlyVisualizingPage);
237                 }
238 
239                 if(!bNewTextBackgroundColorIsSet && getSdrText() && getSdrText()->GetModel())
240 				{
241 					SdrOutliner& rDrawOutliner = getSdrText()->GetModel()->GetDrawOutliner(0);
242 					aNewTextBackgroundColor = rDrawOutliner.GetBackgroundColor();
243 				}
244 
245 	    		const_cast< SdrTextPrimitive2D* >(this)->mxLastVisualizingPage = xCurrentlyVisualizingPage;
246 	    		const_cast< SdrTextPrimitive2D* >(this)->mnLastPageNumber = nCurrentlyValidPageNumber;
247 	    		const_cast< SdrTextPrimitive2D* >(this)->mnLastPageCount = nCurrentlyValidPageCount;
248 	    		const_cast< SdrTextPrimitive2D* >(this)->maLastTextBackgroundColor = aNewTextBackgroundColor;
249             }
250 
251             // call parent
252             return BufferedDecompositionPrimitive2D::get2DDecomposition(rViewInformation);
253         }
254 	} // end of namespace primitive2d
255 } // end of namespace drawinglayer
256 
257 //////////////////////////////////////////////////////////////////////////////
258 
259 namespace drawinglayer
260 {
261 	namespace primitive2d
262 	{
263 		Primitive2DSequence SdrContourTextPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& aViewInformation) const
264 		{
265             Primitive2DSequence aRetval;
266             getSdrText()->GetObject().impDecomposeContourTextPrimitive(aRetval, *this, aViewInformation);
267 
268 			return encapsulateWithTextHierarchyBlockPrimitive2D(aRetval);
269 		}
270 
271 		SdrContourTextPrimitive2D::SdrContourTextPrimitive2D(
272 			const SdrText* pSdrText,
273             const OutlinerParaObject& rOutlinerParaObject,
274 			const basegfx::B2DPolyPolygon& rUnitPolyPolygon,
275 			const basegfx::B2DHomMatrix& rObjectTransform)
276 		:	SdrTextPrimitive2D(pSdrText, rOutlinerParaObject),
277 			maUnitPolyPolygon(rUnitPolyPolygon),
278 			maObjectTransform(rObjectTransform)
279 		{
280 		}
281 
282 		bool SdrContourTextPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
283 		{
284 			if(SdrTextPrimitive2D::operator==(rPrimitive))
285 			{
286 				const SdrContourTextPrimitive2D& rCompare = (SdrContourTextPrimitive2D&)rPrimitive;
287 
288 				return (getUnitPolyPolygon() == rCompare.getUnitPolyPolygon()
289 					&& getObjectTransform() == rCompare.getObjectTransform());
290 			}
291 
292 			return false;
293 		}
294 
295 		SdrTextPrimitive2D* SdrContourTextPrimitive2D::createTransformedClone(const basegfx::B2DHomMatrix& rTransform) const
296 		{
297 			return new SdrContourTextPrimitive2D(
298                 getSdrText(),
299                 getOutlinerParaObject(),
300                 getUnitPolyPolygon(),
301                 rTransform * getObjectTransform());
302 		}
303 
304 		// provide unique ID
305 		ImplPrimitrive2DIDBlock(SdrContourTextPrimitive2D, PRIMITIVE2D_ID_SDRCONTOURTEXTPRIMITIVE2D)
306 
307 	} // end of namespace primitive2d
308 } // end of namespace drawinglayer
309 
310 //////////////////////////////////////////////////////////////////////////////
311 
312 namespace drawinglayer
313 {
314 	namespace primitive2d
315 	{
316 		Primitive2DSequence SdrPathTextPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& aViewInformation) const
317 		{
318             Primitive2DSequence aRetval;
319             getSdrText()->GetObject().impDecomposePathTextPrimitive(aRetval, *this, aViewInformation);
320 
321             return encapsulateWithTextHierarchyBlockPrimitive2D(aRetval);
322 		}
323 
324 		SdrPathTextPrimitive2D::SdrPathTextPrimitive2D(
325 			const SdrText* pSdrText,
326             const OutlinerParaObject& rOutlinerParaObject,
327 			const basegfx::B2DPolyPolygon& rPathPolyPolygon,
328             const attribute::SdrFormTextAttribute& rSdrFormTextAttribute)
329 		:	SdrTextPrimitive2D(pSdrText, rOutlinerParaObject),
330 			maPathPolyPolygon(rPathPolyPolygon),
331             maSdrFormTextAttribute(rSdrFormTextAttribute)
332 		{
333 		}
334 
335 		bool SdrPathTextPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
336 		{
337 			if(SdrTextPrimitive2D::operator==(rPrimitive))
338 			{
339 				const SdrPathTextPrimitive2D& rCompare = (SdrPathTextPrimitive2D&)rPrimitive;
340 
341 				return (getPathPolyPolygon() == rCompare.getPathPolyPolygon()
342                     && getSdrFormTextAttribute() == rCompare.getSdrFormTextAttribute());
343 			}
344 
345 			return false;
346 		}
347 
348 		SdrTextPrimitive2D* SdrPathTextPrimitive2D::createTransformedClone(const basegfx::B2DHomMatrix& rTransform) const
349 		{
350 			basegfx::B2DPolyPolygon aNewPolyPolygon(getPathPolyPolygon());
351 			aNewPolyPolygon.transform(rTransform);
352 
353             return new SdrPathTextPrimitive2D(
354                 getSdrText(),
355                 getOutlinerParaObject(),
356                 aNewPolyPolygon,
357                 getSdrFormTextAttribute());
358 		}
359 
360 		// provide unique ID
361 		ImplPrimitrive2DIDBlock(SdrPathTextPrimitive2D, PRIMITIVE2D_ID_SDRPATHTEXTPRIMITIVE2D)
362 
363 	} // end of namespace primitive2d
364 } // end of namespace drawinglayer
365 
366 //////////////////////////////////////////////////////////////////////////////
367 
368 namespace drawinglayer
369 {
370 	namespace primitive2d
371 	{
372 		Primitive2DSequence SdrBlockTextPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& aViewInformation) const
373 		{
374             Primitive2DSequence aRetval;
375             getSdrText()->GetObject().impDecomposeBlockTextPrimitive(aRetval, *this, aViewInformation);
376 
377             return encapsulateWithTextHierarchyBlockPrimitive2D(aRetval);
378 		}
379 
380 		SdrBlockTextPrimitive2D::SdrBlockTextPrimitive2D(
381 			const SdrText* pSdrText,
382             const OutlinerParaObject& rOutlinerParaObject,
383 			const basegfx::B2DHomMatrix& rTextRangeTransform,
384             SdrTextHorzAdjust aSdrTextHorzAdjust,
385             SdrTextVertAdjust aSdrTextVertAdjust,
386             bool bFixedCellHeight,
387 			bool bUnlimitedPage,
388 			bool bCellText,
389             bool bWordWrap,
390 			bool bClipOnBounds)
391 		:	SdrTextPrimitive2D(pSdrText, rOutlinerParaObject),
392 			maTextRangeTransform(rTextRangeTransform),
393             maSdrTextHorzAdjust(aSdrTextHorzAdjust),
394             maSdrTextVertAdjust(aSdrTextVertAdjust),
395             mbFixedCellHeight(bFixedCellHeight),
396             mbUnlimitedPage(bUnlimitedPage),
397 			mbCellText(bCellText),
398             mbWordWrap(bWordWrap),
399 			mbClipOnBounds(bClipOnBounds)
400 		{
401 		}
402 
403 		bool SdrBlockTextPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
404 		{
405 			if(SdrTextPrimitive2D::operator==(rPrimitive))
406 			{
407 				const SdrBlockTextPrimitive2D& rCompare = (SdrBlockTextPrimitive2D&)rPrimitive;
408 
409 				return (getTextRangeTransform() == rCompare.getTextRangeTransform()
410                     && getSdrTextHorzAdjust() == rCompare.getSdrTextHorzAdjust()
411                     && getSdrTextVertAdjust() == rCompare.getSdrTextVertAdjust()
412                     && isFixedCellHeight() == rCompare.isFixedCellHeight()
413 					&& getUnlimitedPage() == rCompare.getUnlimitedPage()
414 					&& getCellText() == rCompare.getCellText()
415                     && getWordWrap() == rCompare.getWordWrap()
416 					&& getClipOnBounds() == rCompare.getClipOnBounds());
417 			}
418 
419 			return false;
420 		}
421 
422 		SdrTextPrimitive2D* SdrBlockTextPrimitive2D::createTransformedClone(const basegfx::B2DHomMatrix& rTransform) const
423 		{
424 			return new SdrBlockTextPrimitive2D(
425                 getSdrText(),
426                 getOutlinerParaObject(),
427                 rTransform * getTextRangeTransform(),
428                 getSdrTextHorzAdjust(),
429                 getSdrTextVertAdjust(),
430                 isFixedCellHeight(),
431                 getUnlimitedPage(),
432                 getCellText(),
433                 getWordWrap(),
434 				getClipOnBounds());
435 		}
436 
437 		// provide unique ID
438 		ImplPrimitrive2DIDBlock(SdrBlockTextPrimitive2D, PRIMITIVE2D_ID_SDRBLOCKTEXTPRIMITIVE2D)
439 
440 	} // end of namespace primitive2d
441 } // end of namespace drawinglayer
442 
443 //////////////////////////////////////////////////////////////////////////////
444 
445 namespace drawinglayer
446 {
447 	namespace primitive2d
448 	{
449 		Primitive2DSequence SdrStretchTextPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& aViewInformation) const
450 		{
451             Primitive2DSequence aRetval;
452             getSdrText()->GetObject().impDecomposeStretchTextPrimitive(aRetval, *this, aViewInformation);
453 
454             return encapsulateWithTextHierarchyBlockPrimitive2D(aRetval);
455 		}
456 
457 		SdrStretchTextPrimitive2D::SdrStretchTextPrimitive2D(
458 			const SdrText* pSdrText,
459             const OutlinerParaObject& rOutlinerParaObject,
460 			const basegfx::B2DHomMatrix& rTextRangeTransform,
461             bool bFixedCellHeight)
462 		:	SdrTextPrimitive2D(pSdrText, rOutlinerParaObject),
463 			maTextRangeTransform(rTextRangeTransform),
464             mbFixedCellHeight(bFixedCellHeight)
465 		{
466 		}
467 
468 		bool SdrStretchTextPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
469 		{
470 			if(SdrTextPrimitive2D::operator==(rPrimitive))
471 			{
472 				const SdrStretchTextPrimitive2D& rCompare = (SdrStretchTextPrimitive2D&)rPrimitive;
473 
474 				return (getTextRangeTransform() == rCompare.getTextRangeTransform()
475                     && isFixedCellHeight() == rCompare.isFixedCellHeight());
476 			}
477 
478 			return false;
479 		}
480 
481 		SdrTextPrimitive2D* SdrStretchTextPrimitive2D::createTransformedClone(const basegfx::B2DHomMatrix& rTransform) const
482 		{
483 			return new SdrStretchTextPrimitive2D(
484                 getSdrText(),
485                 getOutlinerParaObject(),
486                 rTransform * getTextRangeTransform(),
487                 isFixedCellHeight());
488 		}
489 
490 		// provide unique ID
491 		ImplPrimitrive2DIDBlock(SdrStretchTextPrimitive2D, PRIMITIVE2D_ID_SDRSTRETCHTEXTPRIMITIVE2D)
492 
493 	} // end of namespace primitive2d
494 } // end of namespace drawinglayer
495 
496 //////////////////////////////////////////////////////////////////////////////
497 // eof
498