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 1788 : PPTShape::PPTShape( const oox::ppt::ShapeLocation eShapeLocation, const sal_Char* pServiceName )
45 : : Shape( pServiceName )
46 : , meShapeLocation( eShapeLocation )
47 1788 : , mbReferenced( false )
48 : {
49 1788 : }
50 :
51 3576 : PPTShape::~PPTShape()
52 : {
53 3576 : }
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 16 : oox::drawingml::TextListStylePtr PPTShape::getSubTypeTextListStyle( const SlidePersist& rSlidePersist, sal_Int32 nSubType )
84 : {
85 16 : oox::drawingml::TextListStylePtr pTextListStyle;
86 :
87 : SAL_INFO("oox.ppt", "subtype style: " << lclDebugSubType( nSubType ) );
88 :
89 16 : 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 16 : if ( rSlidePersist.isNotesPage() )
99 0 : pTextListStyle = rSlidePersist.getMasterPersist().get() ? rSlidePersist.getMasterPersist()->getNotesTextStyle() : rSlidePersist.getNotesTextStyle();
100 : else
101 16 : pTextListStyle = rSlidePersist.getMasterPersist().get() ? rSlidePersist.getMasterPersist()->getBodyTextStyle() : rSlidePersist.getBodyTextStyle();
102 16 : break;
103 : }
104 :
105 16 : return pTextListStyle;
106 : }
107 :
108 1095 : 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 1095 : if ( mnSubType && ( meShapeLocation == Master ) )
120 1477 : return;
121 : try
122 : {
123 713 : OUString sServiceName( msServiceName );
124 713 : if( !sServiceName.isEmpty() )
125 : {
126 713 : oox::drawingml::TextListStylePtr aMasterTextListStyle;
127 1426 : Reference< lang::XMultiServiceFactory > xServiceFact( rFilterBase.getModel(), UNO_QUERY_THROW );
128 713 : bool bClearText = false;
129 :
130 1416 : if ( sServiceName != "com.sun.star.drawing.GraphicObjectShape" &&
131 703 : sServiceName != "com.sun.star.drawing.OLE2Shape" )
132 : {
133 690 : const OUString sOutlinerShapeService( "com.sun.star.presentation.OutlinerShape" );
134 : SAL_INFO("oox.ppt","has master: " << std::hex << rSlidePersist.getMasterPersist().get());
135 690 : switch( mnSubType )
136 : {
137 : case XML_ctrTitle :
138 : case XML_title :
139 : {
140 88 : sServiceName = "com.sun.star.presentation.TitleTextShape";
141 88 : aMasterTextListStyle = rSlidePersist.getMasterPersist().get() ? rSlidePersist.getMasterPersist()->getTitleTextStyle() : rSlidePersist.getTitleTextStyle();
142 88 : bClearText = true;
143 : }
144 88 : break;
145 : case XML_subTitle :
146 : {
147 65 : sServiceName = "com.sun.star.presentation.SubtitleShape";
148 65 : aMasterTextListStyle = rSlidePersist.getMasterPersist().get() ? rSlidePersist.getMasterPersist()->getBodyTextStyle() : rSlidePersist.getBodyTextStyle();
149 65 : bClearText = true;
150 : }
151 65 : break;
152 : case XML_obj :
153 : {
154 14 : sServiceName = sOutlinerShapeService;
155 14 : aMasterTextListStyle = rSlidePersist.getMasterPersist().get() ? rSlidePersist.getMasterPersist()->getBodyTextStyle() : rSlidePersist.getBodyTextStyle();
156 : }
157 14 : break;
158 : case XML_body :
159 : {
160 31 : if ( rSlidePersist.isNotesPage() )
161 : {
162 9 : sServiceName = "com.sun.star.presentation.NotesShape";
163 9 : aMasterTextListStyle = rSlidePersist.getMasterPersist().get() ? rSlidePersist.getMasterPersist()->getNotesTextStyle() : rSlidePersist.getNotesTextStyle();
164 : }
165 : else
166 : {
167 22 : sServiceName = sOutlinerShapeService;
168 22 : aMasterTextListStyle = rSlidePersist.getMasterPersist().get() ? rSlidePersist.getMasterPersist()->getBodyTextStyle() : rSlidePersist.getBodyTextStyle();
169 : }
170 : }
171 31 : break;
172 : case XML_dt :
173 42 : sServiceName = "com.sun.star.presentation.DateTimeShape";
174 42 : bClearText = true;
175 42 : 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 43 : sServiceName = "com.sun.star.presentation.FooterShape";
182 43 : bClearText = true;
183 43 : break;
184 : case XML_sldNum :
185 51 : sServiceName = "com.sun.star.presentation.SlideNumberShape";
186 51 : bClearText = true;
187 51 : break;
188 : case XML_sldImg :
189 8 : sServiceName = "com.sun.star.presentation.PageShape";
190 8 : 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 348 : if ( mnSubType && meShapeLocation == Layout )
217 0 : sServiceName = sOutlinerShapeService;
218 348 : break;
219 690 : }
220 : }
221 :
222 : SAL_INFO("oox.ppt","shape service: " << sServiceName);
223 :
224 713 : if( mnSubType && getSubTypeIndex().has() && meShapeLocation == Layout ) {
225 176 : oox::drawingml::ShapePtr pPlaceholder = PPTShape::findPlaceholderByIndex( getSubTypeIndex().get(), rSlidePersist.getShapes()->getChildren(), true );
226 176 : if (!pPlaceholder.get())
227 137 : pPlaceholder = PPTShape::findPlaceholder( mnSubType, 0, getSubTypeIndex(), rSlidePersist.getShapes()->getChildren(), true );
228 :
229 176 : if (pPlaceholder.get()) {
230 176 : 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 176 : }
247 : }
248 :
249 : // use placeholder index if possible
250 713 : if( mnSubType && getSubTypeIndex().has() && rSlidePersist.getMasterPersist().get() ) {
251 34 : 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 34 : if( rSlidePersist.isNotesPage() && pPlaceholder.get() && pPlaceholder->getSubType() != getSubType() )
254 5 : pPlaceholder.reset();
255 :
256 34 : if( pPlaceholder.get()) {
257 : SAL_INFO("oox.ppt","found placeholder with index: " << getSubTypeIndex().get() << " and type: " << lclDebugSubType( mnSubType ));
258 : }
259 34 : if( pPlaceholder.get() ) {
260 18 : PPTShape* pPPTPlaceholder = dynamic_cast< PPTShape* >( pPlaceholder.get() );
261 18 : TextListStylePtr pNewTextListStyle ( new TextListStyle() );
262 :
263 18 : if( pPlaceholder->getTextBody() ) {
264 :
265 18 : pNewTextListStyle->apply( pPlaceholder->getTextBody()->getTextListStyle() );
266 18 : if( pPlaceholder->getMasterTextListStyle().get() )
267 18 : 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 18 : aMasterTextListStyle = pNewTextListStyle;
275 : // SAL_INFO("oox.ppt","combined master text list style");
276 : // aMasterTextListStyle->dump();
277 : }
278 18 : 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 16 : TextListStylePtr pPlaceholderStyle = getSubTypeTextListStyle( rSlidePersist, pPPTPlaceholder->mpPlaceholder->getSubType() );
282 16 : if( pPPTPlaceholder->mpPlaceholder->getTextBody() )
283 16 : pNewTextListStyle->apply( pPPTPlaceholder->mpPlaceholder->getTextBody()->getTextListStyle() );
284 16 : if( pPlaceholderStyle.get() ) {
285 16 : pNewTextListStyle->apply( *pPlaceholderStyle );
286 : //pPlaceholderStyle->dump();
287 16 : }
288 18 : }
289 16 : } else if( !mpPlaceholder.get() ) {
290 0 : aMasterTextListStyle.reset();
291 : }
292 34 : SAL_INFO("oox.ppt","placeholder id: " << (pPlaceholder.get() ? pPlaceholder->getId() : "not found"));
293 : }
294 :
295 713 : if ( !sServiceName.isEmpty() )
296 : {
297 713 : if ( !aMasterTextListStyle.get() )
298 : {
299 513 : bool isOther = !getTextBody().get() && sServiceName != "com.sun.star.drawing.GroupShape";
300 513 : TextListStylePtr aSlideStyle = isOther ? rSlidePersist.getOtherTextStyle() : rSlidePersist.getDefaultTextStyle();
301 : // Combine from MasterSlide details as well.
302 513 : if( rSlidePersist.getMasterPersist().get() )
303 : {
304 378 : aMasterTextListStyle = isOther ? rSlidePersist.getMasterPersist()->getOtherTextStyle() : rSlidePersist.getMasterPersist()->getDefaultTextStyle();
305 378 : if( aSlideStyle.get() )
306 378 : aMasterTextListStyle->apply( *aSlideStyle.get() );
307 : }
308 : else
309 : {
310 135 : aMasterTextListStyle = aSlideStyle;
311 513 : }
312 : }
313 :
314 713 : if( aMasterTextListStyle.get() && getTextBody().get() ) {
315 449 : TextListStylePtr aCombinedTextListStyle (new TextListStyle());
316 :
317 449 : aCombinedTextListStyle->apply( *aMasterTextListStyle.get() );
318 :
319 449 : if( mpPlaceholder.get() && mpPlaceholder->getTextBody().get() )
320 329 : aCombinedTextListStyle->apply( mpPlaceholder->getTextBody()->getTextListStyle() );
321 449 : aCombinedTextListStyle->apply( getTextBody()->getTextListStyle() );
322 :
323 449 : setMasterTextListStyle( aCombinedTextListStyle );
324 : } else
325 264 : setMasterTextListStyle( aMasterTextListStyle );
326 :
327 713 : Reference< XShape > xShape( createAndInsert( rFilterBase, sServiceName, pTheme, rxShapes, pShapeRect, bClearText, mpPlaceholder.get() != NULL, aTransformation, getFillProperties() ) );
328 713 : 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 713 : if( pShapeMap )
347 : {
348 : // bnc#705982 - if optional model id reference is
349 : // there, use that to obtain target shape
350 713 : if( !msModelId.isEmpty() )
351 : {
352 0 : (*pShapeMap)[ msModelId ] = shared_from_this();
353 : }
354 713 : else if( !msId.isEmpty() )
355 : {
356 713 : (*pShapeMap)[ msId ] = shared_from_this();
357 : }
358 : }
359 :
360 : // if this is a group shape, we have to add also each child shape
361 1426 : Reference< XShapes > xShapes( xShape, UNO_QUERY );
362 713 : if ( xShapes.is() )
363 733 : addChildren( rFilterBase, *this, pTheme, xShapes, pShapeRect ? *pShapeRect : awt::Rectangle( maPosition.X, maPosition.Y, maSize.Width, maSize.Height ), pShapeMap, aTransformation );
364 713 : }
365 713 : }
366 : }
367 0 : catch( const Exception& )
368 : {
369 : }
370 : }
371 :
372 339 : void PPTShape::applyShapeReference( const oox::drawingml::Shape& rReferencedShape, bool bUseText )
373 : {
374 339 : Shape::applyShapeReference( rReferencedShape, bUseText );
375 339 : }
376 :
377 : namespace
378 : {
379 3417 : bool ShapeLocationIsMaster(oox::drawingml::Shape *pInShape)
380 : {
381 3417 : PPTShape* pShape = dynamic_cast<PPTShape*>(pInShape);
382 3417 : 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 3938 : 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 3938 : oox::drawingml::ShapePtr aShapePtr;
397 7876 : oox::drawingml::ShapePtr aChoiceShapePtr1;
398 7876 : oox::drawingml::ShapePtr aChoiceShapePtr2;
399 7876 : oox::drawingml::ShapePtr aChoiceShapePtr3;
400 7876 : oox::drawingml::ShapePtr aChoiceShapePtr4;
401 3938 : std::vector< oox::drawingml::ShapePtr >::reverse_iterator aRevIter( rShapes.rbegin() );
402 11240 : while (aRevIter != rShapes.rend())
403 : {
404 3550 : if (!bMasterOnly || ShapeLocationIsMaster((*aRevIter).get()))
405 : {
406 2765 : if ((*aRevIter)->getSubTypeIndex() == oSubTypeIndex)
407 : {
408 550 : if ((*aRevIter)->getSubType() == nFirstSubType)
409 : {
410 93 : aShapePtr = *aRevIter;
411 93 : break;
412 : }
413 457 : else if ((*aRevIter)->getSubType() == nSecondSubType && !aChoiceShapePtr2.get())
414 155 : aChoiceShapePtr2 = *aRevIter;
415 302 : else if (!aChoiceShapePtr4.get())
416 299 : aChoiceShapePtr4 = *aRevIter;
417 : }
418 2215 : else if ((*aRevIter)->getSubType() == nFirstSubType && !aChoiceShapePtr1.get())
419 292 : aChoiceShapePtr1 = *aRevIter;
420 1923 : else if ((*aRevIter)->getSubType() == nSecondSubType && !aChoiceShapePtr3.get())
421 316 : aChoiceShapePtr3 = *aRevIter;
422 : }
423 3457 : std::vector< oox::drawingml::ShapePtr >& rChildren = (*aRevIter)->getChildren();
424 3457 : aChoiceShapePtr4 = findPlaceholder( nFirstSubType, nSecondSubType, oSubTypeIndex, rChildren, bMasterOnly );
425 3457 : if (aChoiceShapePtr4.get())
426 : {
427 477 : if (aChoiceShapePtr4->getSubType() == nFirstSubType)
428 : {
429 382 : if (aChoiceShapePtr4->getSubTypeIndex() == oSubTypeIndex)
430 93 : aShapePtr = aChoiceShapePtr4;
431 : else
432 289 : aChoiceShapePtr1 = aChoiceShapePtr4;
433 : }
434 95 : else if (aChoiceShapePtr4->getSubType() == nSecondSubType)
435 : {
436 95 : if (aChoiceShapePtr4->getSubTypeIndex() == oSubTypeIndex)
437 81 : aChoiceShapePtr2 = aChoiceShapePtr4;
438 : else
439 14 : aChoiceShapePtr3 = aChoiceShapePtr4;
440 : }
441 : }
442 3457 : if (aShapePtr.get())
443 93 : break;
444 3364 : ++aRevIter;
445 : }
446 3938 : if (aShapePtr.get())
447 186 : return aShapePtr;
448 3752 : if (aChoiceShapePtr1.get())
449 577 : return aChoiceShapePtr1;
450 3175 : if (aChoiceShapePtr2.get())
451 162 : return aChoiceShapePtr2;
452 3013 : if (aChoiceShapePtr3.get())
453 28 : return aChoiceShapePtr3;
454 6923 : return aChoiceShapePtr4;
455 : }
456 :
457 2343 : oox::drawingml::ShapePtr PPTShape::findPlaceholderByIndex( const sal_Int32 nIdx, std::vector< oox::drawingml::ShapePtr >& rShapes, bool bMasterOnly )
458 : {
459 2343 : oox::drawingml::ShapePtr aShapePtr;
460 :
461 2343 : std::vector< oox::drawingml::ShapePtr >::reverse_iterator aRevIter( rShapes.rbegin() );
462 6757 : while( aRevIter != rShapes.rend() )
463 : {
464 2495 : if ( (*aRevIter)->getSubTypeIndex().has() && (*aRevIter)->getSubTypeIndex().get() == nIdx &&
465 453 : ( !bMasterOnly || ShapeLocationIsMaster((*aRevIter).get()) ) )
466 : {
467 62 : aShapePtr = *aRevIter;
468 62 : break;
469 : }
470 2133 : std::vector< oox::drawingml::ShapePtr >& rChildren = (*aRevIter)->getChildren();
471 2133 : aShapePtr = findPlaceholderByIndex( nIdx, rChildren, bMasterOnly );
472 2133 : if ( aShapePtr.get() )
473 62 : break;
474 2071 : ++aRevIter;
475 : }
476 2343 : return aShapePtr;
477 : }
478 :
479 246 : } }
480 :
481 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|