Line data Source code
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 "oox/ppt/pptshape.hxx"
21 : #include "oox/core/xmlfilterbase.hxx"
22 : #include "drawingml/textbody.hxx"
23 :
24 : #include <com/sun/star/container/XNamed.hpp>
25 : #include <com/sun/star/beans/XMultiPropertySet.hpp>
26 : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
27 : #include <com/sun/star/drawing/HomogenMatrix3.hpp>
28 : #include <com/sun/star/text/XText.hpp>
29 : #include <basegfx/matrix/b2dhommatrix.hxx>
30 : #include "oox/ppt/slidepersist.hxx"
31 :
32 : using namespace ::oox::core;
33 : using namespace ::oox::drawingml;
34 : using namespace ::com::sun::star;
35 : using namespace ::com::sun::star::awt;
36 : using namespace ::com::sun::star::uno;
37 : using namespace ::com::sun::star::beans;
38 : using namespace ::com::sun::star::frame;
39 : using namespace ::com::sun::star::text;
40 : using namespace ::com::sun::star::drawing;
41 :
42 : namespace oox { namespace ppt {
43 :
44 2486 : PPTShape::PPTShape( const oox::ppt::ShapeLocation eShapeLocation, const sal_Char* pServiceName )
45 : : Shape( pServiceName )
46 : , meShapeLocation( eShapeLocation )
47 2486 : , mbReferenced( false )
48 : {
49 2486 : }
50 :
51 4972 : PPTShape::~PPTShape()
52 : {
53 4972 : }
54 :
55 0 : static const char* lclDebugSubType( sal_Int32 nType )
56 : {
57 0 : switch (nType) {
58 : case XML_ctrTitle :
59 0 : return "ctrTitle";
60 : case XML_title :
61 0 : return "title";
62 : case XML_subTitle :
63 0 : return "subTitle";
64 : case XML_obj :
65 0 : return "obj";
66 : case XML_body :
67 0 : return "body";
68 : case XML_dt :
69 0 : return "dt";
70 : case XML_hdr :
71 0 : return "hdr";
72 : case XML_ftr :
73 0 : return "frt";
74 : case XML_sldNum :
75 0 : return "sldNum";
76 : case XML_sldImg :
77 0 : return "sldImg";
78 : }
79 :
80 0 : return "unknown - please extend lclDebugSubType";
81 : }
82 :
83 22 : oox::drawingml::TextListStylePtr PPTShape::getSubTypeTextListStyle( const SlidePersist& rSlidePersist, sal_Int32 nSubType )
84 : {
85 22 : oox::drawingml::TextListStylePtr pTextListStyle;
86 :
87 : SAL_INFO("oox.ppt", "subtype style: " << lclDebugSubType( nSubType ) );
88 :
89 22 : switch( nSubType )
90 : {
91 : case XML_ctrTitle :
92 : case XML_title :
93 0 : pTextListStyle = rSlidePersist.getMasterPersist().get() ? rSlidePersist.getMasterPersist()->getTitleTextStyle() : rSlidePersist.getTitleTextStyle();
94 0 : break;
95 : case XML_subTitle :
96 : case XML_obj :
97 : case XML_body :
98 22 : if ( rSlidePersist.isNotesPage() )
99 0 : pTextListStyle = rSlidePersist.getMasterPersist().get() ? rSlidePersist.getMasterPersist()->getNotesTextStyle() : rSlidePersist.getNotesTextStyle();
100 : else
101 22 : pTextListStyle = rSlidePersist.getMasterPersist().get() ? rSlidePersist.getMasterPersist()->getBodyTextStyle() : rSlidePersist.getBodyTextStyle();
102 22 : break;
103 : }
104 :
105 22 : return pTextListStyle;
106 : }
107 :
108 1546 : void PPTShape::addShape(
109 : oox::core::XmlFilterBase& rFilterBase,
110 : SlidePersist& rSlidePersist,
111 : const oox::drawingml::Theme* pTheme,
112 : const Reference< XShapes >& rxShapes,
113 : basegfx::B2DHomMatrix& aTransformation,
114 : const awt::Rectangle* pShapeRect,
115 : ::oox::drawingml::ShapeIdMap* pShapeMap )
116 : {
117 : SAL_INFO("oox.ppt","add shape id: " << msId << " location: " << ((meShapeLocation == Master) ? "master" : ((meShapeLocation == Slide) ? "slide" : ((meShapeLocation == Layout) ? "layout" : "other"))) << " subtype: " << mnSubType << " service: " << msServiceName);
118 : // only placeholder from layout are being inserted
119 1546 : if ( mnSubType && ( meShapeLocation == Master ) )
120 2000 : return;
121 : try
122 : {
123 1092 : OUString sServiceName( msServiceName );
124 1092 : if( !sServiceName.isEmpty() )
125 : {
126 1092 : oox::drawingml::TextListStylePtr aMasterTextListStyle;
127 2184 : Reference< lang::XMultiServiceFactory > xServiceFact( rFilterBase.getModel(), UNO_QUERY_THROW );
128 1092 : bool bClearText = false;
129 :
130 2172 : if ( sServiceName != "com.sun.star.drawing.GraphicObjectShape" &&
131 1080 : sServiceName != "com.sun.star.drawing.OLE2Shape" )
132 : {
133 1058 : const OUString sOutlinerShapeService( "com.sun.star.presentation.OutlinerShape" );
134 : SAL_INFO("oox.ppt","has master: " << std::hex << rSlidePersist.getMasterPersist().get());
135 1058 : switch( mnSubType )
136 : {
137 : case XML_ctrTitle :
138 : case XML_title :
139 : {
140 106 : sServiceName = "com.sun.star.presentation.TitleTextShape";
141 106 : aMasterTextListStyle = rSlidePersist.getMasterPersist().get() ? rSlidePersist.getMasterPersist()->getTitleTextStyle() : rSlidePersist.getTitleTextStyle();
142 106 : bClearText = true;
143 : }
144 106 : break;
145 : case XML_subTitle :
146 : {
147 76 : sServiceName = "com.sun.star.presentation.SubtitleShape";
148 76 : aMasterTextListStyle = rSlidePersist.getMasterPersist().get() ? rSlidePersist.getMasterPersist()->getBodyTextStyle() : rSlidePersist.getBodyTextStyle();
149 76 : bClearText = true;
150 : }
151 76 : break;
152 : case XML_obj :
153 : {
154 16 : sServiceName = sOutlinerShapeService;
155 16 : aMasterTextListStyle = rSlidePersist.getMasterPersist().get() ? rSlidePersist.getMasterPersist()->getBodyTextStyle() : rSlidePersist.getBodyTextStyle();
156 : }
157 16 : break;
158 : case XML_body :
159 : {
160 30 : if ( rSlidePersist.isNotesPage() )
161 : {
162 12 : sServiceName = "com.sun.star.presentation.NotesShape";
163 12 : aMasterTextListStyle = rSlidePersist.getMasterPersist().get() ? rSlidePersist.getMasterPersist()->getNotesTextStyle() : rSlidePersist.getNotesTextStyle();
164 : }
165 : else
166 : {
167 18 : sServiceName = sOutlinerShapeService;
168 18 : aMasterTextListStyle = rSlidePersist.getMasterPersist().get() ? rSlidePersist.getMasterPersist()->getBodyTextStyle() : rSlidePersist.getBodyTextStyle();
169 : }
170 : }
171 30 : break;
172 : case XML_dt :
173 62 : sServiceName = "com.sun.star.presentation.DateTimeShape";
174 62 : bClearText = true;
175 62 : break;
176 : case XML_hdr :
177 0 : sServiceName = "com.sun.star.presentation.HeaderShape";
178 0 : bClearText = true;
179 0 : break;
180 : case XML_ftr :
181 64 : sServiceName = "com.sun.star.presentation.FooterShape";
182 64 : bClearText = true;
183 64 : break;
184 : case XML_sldNum :
185 78 : sServiceName = "com.sun.star.presentation.SlideNumberShape";
186 78 : bClearText = true;
187 78 : break;
188 : case XML_sldImg :
189 10 : sServiceName = "com.sun.star.presentation.PageShape";
190 10 : break;
191 : case XML_chart :
192 0 : if ( meShapeLocation == Layout )
193 0 : sServiceName = sOutlinerShapeService;
194 : else
195 0 : sServiceName = "com.sun.star.presentation.ChartShape";
196 0 : break;
197 : case XML_tbl :
198 0 : if ( meShapeLocation == Layout )
199 0 : sServiceName = sOutlinerShapeService;
200 : else
201 0 : sServiceName = "com.sun.star.presentation.TableShape";
202 0 : break;
203 : case XML_pic :
204 0 : if ( meShapeLocation == Layout )
205 0 : sServiceName = sOutlinerShapeService;
206 : else
207 0 : sServiceName = "com.sun.star.presentation.GraphicObjectShape";
208 0 : break;
209 : case XML_media :
210 0 : if ( meShapeLocation == Layout )
211 0 : sServiceName = sOutlinerShapeService;
212 : else
213 0 : sServiceName = "com.sun.star.presentation.MediaShape";
214 0 : break;
215 : default:
216 616 : if ( mnSubType && meShapeLocation == Layout )
217 0 : sServiceName = sOutlinerShapeService;
218 616 : break;
219 1058 : }
220 : }
221 :
222 : SAL_INFO("oox.ppt","shape service: " << sServiceName);
223 :
224 1092 : if( mnSubType && getSubTypeIndex().has() && meShapeLocation == Layout ) {
225 246 : oox::drawingml::ShapePtr pPlaceholder = PPTShape::findPlaceholderByIndex( getSubTypeIndex().get(), rSlidePersist.getShapes()->getChildren(), true );
226 246 : if (!pPlaceholder.get())
227 196 : pPlaceholder = PPTShape::findPlaceholder( mnSubType, 0, getSubTypeIndex(), rSlidePersist.getShapes()->getChildren(), true );
228 :
229 246 : if (pPlaceholder.get()) {
230 246 : if( maSize.Width == 0 || maSize.Height == 0 ) {
231 0 : awt::Size aSize = maSize;
232 0 : if( maSize.Width == 0 )
233 0 : aSize.Width = pPlaceholder->getSize().Width;
234 0 : if( maSize.Height == 0 )
235 0 : aSize.Height = pPlaceholder->getSize().Height;
236 0 : setSize( aSize );
237 0 : if ( maPosition.X == 0 || maPosition.Y == 0 ) {
238 0 : awt::Point aPosition = maPosition;
239 0 : if( maPosition.X == 0 )
240 0 : aPosition.X = pPlaceholder->getPosition().X;
241 0 : if( maPosition.Y == 0 )
242 0 : aPosition.Y = pPlaceholder->getPosition().Y;
243 0 : setPosition( aPosition );
244 : }
245 : }
246 246 : }
247 : }
248 :
249 : // use placeholder index if possible
250 1092 : if( mnSubType && getSubTypeIndex().has() && rSlidePersist.getMasterPersist().get() ) {
251 48 : oox::drawingml::ShapePtr pPlaceholder = PPTShape::findPlaceholderByIndex( getSubTypeIndex().get(), rSlidePersist.getMasterPersist()->getShapes()->getChildren() );
252 : // TODO: Check if this is required for non-notes slides as well...
253 48 : if( rSlidePersist.isNotesPage() && pPlaceholder.get() && pPlaceholder->getSubType() != getSubType() )
254 8 : pPlaceholder.reset();
255 :
256 48 : if( pPlaceholder.get()) {
257 : SAL_INFO("oox.ppt","found placeholder with index: " << getSubTypeIndex().get() << " and type: " << lclDebugSubType( mnSubType ));
258 : }
259 48 : if( pPlaceholder.get() ) {
260 26 : PPTShape* pPPTPlaceholder = dynamic_cast< PPTShape* >( pPlaceholder.get() );
261 26 : TextListStylePtr pNewTextListStyle ( new TextListStyle() );
262 :
263 26 : if( pPlaceholder->getTextBody() ) {
264 :
265 26 : pNewTextListStyle->apply( pPlaceholder->getTextBody()->getTextListStyle() );
266 26 : if( pPlaceholder->getMasterTextListStyle().get() )
267 26 : pNewTextListStyle->apply( *pPlaceholder->getMasterTextListStyle() );
268 :
269 : // SAL_INFO("oox.ppt","placeholder body style");
270 : // pPlaceholder->getTextBody()->getTextListStyle().dump();
271 : // SAL_INFO("oox.ppt","master text list style");
272 : // pPlaceholder->getMasterTextListStyle()->dump();
273 :
274 26 : aMasterTextListStyle = pNewTextListStyle;
275 : // SAL_INFO("oox.ppt","combined master text list style");
276 : // aMasterTextListStyle->dump();
277 : }
278 26 : if( pPPTPlaceholder && pPPTPlaceholder->mpPlaceholder.get() ) {
279 : SAL_INFO("oox.ppt","placeholder has parent placeholder: " << pPPTPlaceholder->mpPlaceholder->getId() << " type: " << lclDebugSubType( pPPTPlaceholder->mpPlaceholder->getSubType() ) << " index: " << pPPTPlaceholder->mpPlaceholder->getSubTypeIndex().get() );
280 : SAL_INFO("oox.ppt","has textbody " << (pPPTPlaceholder->mpPlaceholder->getTextBody() != 0) );
281 22 : TextListStylePtr pPlaceholderStyle = getSubTypeTextListStyle( rSlidePersist, pPPTPlaceholder->mpPlaceholder->getSubType() );
282 22 : if( pPPTPlaceholder->mpPlaceholder->getTextBody() )
283 22 : pNewTextListStyle->apply( pPPTPlaceholder->mpPlaceholder->getTextBody()->getTextListStyle() );
284 22 : if( pPlaceholderStyle.get() ) {
285 22 : pNewTextListStyle->apply( *pPlaceholderStyle );
286 : //pPlaceholderStyle->dump();
287 22 : }
288 26 : }
289 22 : } else if( !mpPlaceholder.get() ) {
290 0 : aMasterTextListStyle.reset();
291 : }
292 48 : SAL_INFO("oox.ppt","placeholder id: " << (pPlaceholder.get() ? pPlaceholder->getId() : "not found"));
293 : }
294 :
295 1092 : if ( !sServiceName.isEmpty() )
296 : {
297 1092 : if ( !aMasterTextListStyle.get() )
298 : {
299 860 : bool isOther = !getTextBody().get() && !sServiceName.equalsAscii("com.sun.star.drawing.GroupShape");
300 860 : TextListStylePtr aSlideStyle = isOther ? rSlidePersist.getOtherTextStyle() : rSlidePersist.getDefaultTextStyle();
301 : // Combine from MasterSlide details as well.
302 860 : if( rSlidePersist.getMasterPersist().get() )
303 : {
304 660 : aMasterTextListStyle = isOther ? rSlidePersist.getMasterPersist()->getOtherTextStyle() : rSlidePersist.getMasterPersist()->getDefaultTextStyle();
305 660 : if( aSlideStyle.get() )
306 660 : aMasterTextListStyle->apply( *aSlideStyle.get() );
307 : }
308 : else
309 : {
310 200 : aMasterTextListStyle = aSlideStyle;
311 860 : }
312 : }
313 :
314 1092 : if( aMasterTextListStyle.get() && getTextBody().get() ) {
315 610 : TextListStylePtr aCombinedTextListStyle (new TextListStyle());
316 :
317 610 : aCombinedTextListStyle->apply( *aMasterTextListStyle.get() );
318 :
319 610 : if( mpPlaceholder.get() && mpPlaceholder->getTextBody().get() )
320 428 : aCombinedTextListStyle->apply( mpPlaceholder->getTextBody()->getTextListStyle() );
321 610 : aCombinedTextListStyle->apply( getTextBody()->getTextListStyle() );
322 :
323 610 : setMasterTextListStyle( aCombinedTextListStyle );
324 : } else
325 482 : setMasterTextListStyle( aMasterTextListStyle );
326 :
327 1092 : Reference< XShape > xShape( createAndInsert( rFilterBase, sServiceName, pTheme, rxShapes, pShapeRect, bClearText, mpPlaceholder.get() != NULL, aTransformation, getFillProperties() ) );
328 1092 : if ( !rSlidePersist.isMasterPage() && rSlidePersist.getPage().is() && ( (sal_Int32)mnSubType == XML_title ) )
329 : {
330 : try
331 : {
332 6 : OUString aTitleText;
333 12 : Reference< XTextRange > xText( xShape, UNO_QUERY_THROW );
334 6 : aTitleText = xText->getString();
335 6 : if ( !aTitleText.isEmpty() && ( aTitleText.getLength() < 64 ) ) // just a magic value, but we don't want to set slide names which are too long
336 : {
337 6 : Reference< container::XNamed > xName( rSlidePersist.getPage(), UNO_QUERY_THROW );
338 6 : xName->setName( aTitleText );
339 6 : }
340 : }
341 0 : catch( uno::Exception& )
342 : {
343 :
344 : }
345 : }
346 1092 : if( pShapeMap )
347 : {
348 : // bnc#705982 - if optional model id reference is
349 : // there, use that to obtain target shape
350 1092 : if( !msModelId.isEmpty() )
351 : {
352 0 : (*pShapeMap)[ msModelId ] = shared_from_this();
353 : }
354 1092 : else if( !msId.isEmpty() )
355 : {
356 1092 : (*pShapeMap)[ msId ] = shared_from_this();
357 : }
358 : }
359 :
360 : // if this is a group shape, we have to add also each child shape
361 2184 : Reference< XShapes > xShapes( xShape, UNO_QUERY );
362 1092 : if ( xShapes.is() )
363 1128 : addChildren( rFilterBase, *this, pTheme, xShapes, pShapeRect ? *pShapeRect : awt::Rectangle( maPosition.X, maPosition.Y, maSize.Width, maSize.Height ), pShapeMap, aTransformation );
364 1092 : }
365 1092 : }
366 : }
367 0 : catch( const Exception& )
368 : {
369 : }
370 : }
371 :
372 438 : void PPTShape::applyShapeReference( const oox::drawingml::Shape& rReferencedShape, bool bUseText )
373 : {
374 438 : Shape::applyShapeReference( rReferencedShape, bUseText );
375 438 : }
376 :
377 : namespace
378 : {
379 4642 : bool ShapeLocationIsMaster(oox::drawingml::Shape *pInShape)
380 : {
381 4642 : PPTShape* pShape = dynamic_cast<PPTShape*>(pInShape);
382 4642 : return pShape && pShape->getShapeLocation() == Master;
383 : }
384 : }
385 :
386 : // Function to find placeholder (ph) for a shape. No idea how MSO implements this, but
387 : // this order seems to work quite well (probably it's unnecessary complicated / wrong):
388 : // 1. ph with nFirstSubType and the same oSubTypeIndex
389 : // 2. ph with nFirstSubType
390 : // 3. ph with nSecondSubType and the same oSubTypeIndex
391 : // 4. ph with nSecondSubType
392 : // 5. ph with the same oSubTypeIndex
393 5358 : oox::drawingml::ShapePtr PPTShape::findPlaceholder( sal_Int32 nFirstSubType, sal_Int32 nSecondSubType,
394 : const OptValue< sal_Int32 >& oSubTypeIndex, std::vector< oox::drawingml::ShapePtr >& rShapes, bool bMasterOnly )
395 : {
396 5358 : oox::drawingml::ShapePtr aShapePtr;
397 10716 : oox::drawingml::ShapePtr aChoiceShapePtr1;
398 10716 : oox::drawingml::ShapePtr aChoiceShapePtr2;
399 10716 : oox::drawingml::ShapePtr aChoiceShapePtr3;
400 10716 : oox::drawingml::ShapePtr aChoiceShapePtr4;
401 5358 : std::vector< oox::drawingml::ShapePtr >::reverse_iterator aRevIter( rShapes.rbegin() );
402 15326 : while (aRevIter != rShapes.rend())
403 : {
404 4822 : if (!bMasterOnly || ShapeLocationIsMaster((*aRevIter).get()))
405 : {
406 3720 : if ((*aRevIter)->getSubTypeIndex() == oSubTypeIndex)
407 : {
408 568 : if ((*aRevIter)->getSubType() == nFirstSubType)
409 : {
410 106 : aShapePtr = *aRevIter;
411 106 : break;
412 : }
413 462 : else if ((*aRevIter)->getSubType() == nSecondSubType && !aChoiceShapePtr2.get())
414 178 : aChoiceShapePtr2 = *aRevIter;
415 284 : else if (!aChoiceShapePtr4.get())
416 282 : aChoiceShapePtr4 = *aRevIter;
417 : }
418 3152 : else if ((*aRevIter)->getSubType() == nFirstSubType && !aChoiceShapePtr1.get())
419 424 : aChoiceShapePtr1 = *aRevIter;
420 2728 : else if ((*aRevIter)->getSubType() == nSecondSubType && !aChoiceShapePtr3.get())
421 422 : aChoiceShapePtr3 = *aRevIter;
422 : }
423 4716 : std::vector< oox::drawingml::ShapePtr >& rChildren = (*aRevIter)->getChildren();
424 4716 : aChoiceShapePtr4 = findPlaceholder( nFirstSubType, nSecondSubType, oSubTypeIndex, rChildren, bMasterOnly );
425 4716 : if (aChoiceShapePtr4.get())
426 : {
427 634 : if (aChoiceShapePtr4->getSubType() == nFirstSubType)
428 : {
429 528 : if (aChoiceShapePtr4->getSubTypeIndex() == oSubTypeIndex)
430 106 : aShapePtr = aChoiceShapePtr4;
431 : else
432 422 : aChoiceShapePtr1 = aChoiceShapePtr4;
433 : }
434 106 : else if (aChoiceShapePtr4->getSubType() == nSecondSubType)
435 : {
436 106 : if (aChoiceShapePtr4->getSubTypeIndex() == oSubTypeIndex)
437 102 : aChoiceShapePtr2 = aChoiceShapePtr4;
438 : else
439 4 : aChoiceShapePtr3 = aChoiceShapePtr4;
440 : }
441 : }
442 4716 : if (aShapePtr.get())
443 106 : break;
444 4610 : ++aRevIter;
445 : }
446 5358 : if (aShapePtr.get())
447 212 : return aShapePtr;
448 5146 : if (aChoiceShapePtr1.get())
449 842 : return aChoiceShapePtr1;
450 4304 : if (aChoiceShapePtr2.get())
451 202 : return aChoiceShapePtr2;
452 4102 : if (aChoiceShapePtr3.get())
453 12 : return aChoiceShapePtr3;
454 9448 : return aChoiceShapePtr4;
455 : }
456 :
457 3272 : oox::drawingml::ShapePtr PPTShape::findPlaceholderByIndex( const sal_Int32 nIdx, std::vector< oox::drawingml::ShapePtr >& rShapes, bool bMasterOnly )
458 : {
459 3272 : oox::drawingml::ShapePtr aShapePtr;
460 :
461 3272 : std::vector< oox::drawingml::ShapePtr >::reverse_iterator aRevIter( rShapes.rbegin() );
462 9438 : while( aRevIter != rShapes.rend() )
463 : {
464 3476 : if ( (*aRevIter)->getSubTypeIndex().has() && (*aRevIter)->getSubTypeIndex().get() == nIdx &&
465 626 : ( !bMasterOnly || ShapeLocationIsMaster((*aRevIter).get()) ) )
466 : {
467 84 : aShapePtr = *aRevIter;
468 84 : break;
469 : }
470 2978 : std::vector< oox::drawingml::ShapePtr >& rChildren = (*aRevIter)->getChildren();
471 2978 : aShapePtr = findPlaceholderByIndex( nIdx, rChildren, bMasterOnly );
472 2978 : if ( aShapePtr.get() )
473 84 : break;
474 2894 : ++aRevIter;
475 : }
476 3272 : return aShapePtr;
477 : }
478 :
479 408 : } }
480 :
481 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|