1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "oox/ppt/pptshape.hxx"
21 #include "oox/core/xmlfilterbase.hxx"
22 #include "drawingml/textbody.hxx"
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"
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
;
42 namespace oox
{ namespace ppt
{
44 PPTShape::PPTShape( const oox::ppt::ShapeLocation eShapeLocation
, const sal_Char
* pServiceName
)
45 : Shape( pServiceName
)
46 , meShapeLocation( eShapeLocation
)
47 , mbReferenced( false )
55 static const char* lclDebugSubType( sal_Int32 nType
)
80 return "unknown - please extend lclDebugSubType";
83 oox::drawingml::TextListStylePtr
PPTShape::getSubTypeTextListStyle( const SlidePersist
& rSlidePersist
, sal_Int32 nSubType
)
85 oox::drawingml::TextListStylePtr pTextListStyle
;
87 SAL_INFO("oox.ppt", "subtype style: " << lclDebugSubType( nSubType
) );
93 pTextListStyle
= rSlidePersist
.getMasterPersist().get() ? rSlidePersist
.getMasterPersist()->getTitleTextStyle() : rSlidePersist
.getTitleTextStyle();
98 if ( rSlidePersist
.isNotesPage() )
99 pTextListStyle
= rSlidePersist
.getMasterPersist().get() ? rSlidePersist
.getMasterPersist()->getNotesTextStyle() : rSlidePersist
.getNotesTextStyle();
101 pTextListStyle
= rSlidePersist
.getMasterPersist().get() ? rSlidePersist
.getMasterPersist()->getBodyTextStyle() : rSlidePersist
.getBodyTextStyle();
105 return pTextListStyle
;
108 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
)
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 if ( mnSubType
&& ( meShapeLocation
== Master
) )
123 OUString
sServiceName( msServiceName
);
124 if( !sServiceName
.isEmpty() )
126 oox::drawingml::TextListStylePtr aMasterTextListStyle
;
127 Reference
< lang::XMultiServiceFactory
> xServiceFact( rFilterBase
.getModel(), UNO_QUERY_THROW
);
128 bool bClearText
= false;
130 if ( sServiceName
!= "com.sun.star.drawing.GraphicObjectShape" &&
131 sServiceName
!= "com.sun.star.drawing.OLE2Shape" )
133 const OUString
sOutlinerShapeService( "com.sun.star.presentation.OutlinerShape" );
134 SAL_INFO("oox.ppt","has master: " << std::hex
<< rSlidePersist
.getMasterPersist().get());
140 sServiceName
= "com.sun.star.presentation.TitleTextShape";
141 aMasterTextListStyle
= rSlidePersist
.getMasterPersist().get() ? rSlidePersist
.getMasterPersist()->getTitleTextStyle() : rSlidePersist
.getTitleTextStyle();
147 sServiceName
= "com.sun.star.presentation.SubtitleShape";
148 aMasterTextListStyle
= rSlidePersist
.getMasterPersist().get() ? rSlidePersist
.getMasterPersist()->getBodyTextStyle() : rSlidePersist
.getBodyTextStyle();
154 sServiceName
= sOutlinerShapeService
;
155 aMasterTextListStyle
= rSlidePersist
.getMasterPersist().get() ? rSlidePersist
.getMasterPersist()->getBodyTextStyle() : rSlidePersist
.getBodyTextStyle();
160 if ( rSlidePersist
.isNotesPage() )
162 sServiceName
= "com.sun.star.presentation.NotesShape";
163 aMasterTextListStyle
= rSlidePersist
.getMasterPersist().get() ? rSlidePersist
.getMasterPersist()->getNotesTextStyle() : rSlidePersist
.getNotesTextStyle();
167 sServiceName
= sOutlinerShapeService
;
168 aMasterTextListStyle
= rSlidePersist
.getMasterPersist().get() ? rSlidePersist
.getMasterPersist()->getBodyTextStyle() : rSlidePersist
.getBodyTextStyle();
173 sServiceName
= "com.sun.star.presentation.DateTimeShape";
177 sServiceName
= "com.sun.star.presentation.HeaderShape";
181 sServiceName
= "com.sun.star.presentation.FooterShape";
185 sServiceName
= "com.sun.star.presentation.SlideNumberShape";
189 sServiceName
= "com.sun.star.presentation.PageShape";
192 if ( meShapeLocation
== Layout
)
193 sServiceName
= sOutlinerShapeService
;
195 sServiceName
= "com.sun.star.presentation.ChartShape";
198 if ( meShapeLocation
== Layout
)
199 sServiceName
= sOutlinerShapeService
;
201 sServiceName
= "com.sun.star.presentation.TableShape";
204 if ( meShapeLocation
== Layout
)
205 sServiceName
= sOutlinerShapeService
;
207 sServiceName
= "com.sun.star.presentation.GraphicObjectShape";
210 if ( meShapeLocation
== Layout
)
211 sServiceName
= sOutlinerShapeService
;
213 sServiceName
= "com.sun.star.presentation.MediaShape";
216 if ( mnSubType
&& meShapeLocation
== Layout
)
217 sServiceName
= sOutlinerShapeService
;
222 SAL_INFO("oox.ppt","shape service: " << sServiceName
);
224 if( mnSubType
&& getSubTypeIndex().has() && meShapeLocation
== Layout
) {
225 oox::drawingml::ShapePtr pPlaceholder
= PPTShape::findPlaceholderByIndex( getSubTypeIndex().get(), rSlidePersist
.getShapes()->getChildren(), true );
226 if (!pPlaceholder
.get())
227 pPlaceholder
= PPTShape::findPlaceholder( mnSubType
, 0, getSubTypeIndex(), rSlidePersist
.getShapes()->getChildren(), true );
229 if (pPlaceholder
.get()) {
230 if( maSize
.Width
== 0 || maSize
.Height
== 0 ) {
231 awt::Size aSize
= maSize
;
232 if( maSize
.Width
== 0 )
233 aSize
.Width
= pPlaceholder
->getSize().Width
;
234 if( maSize
.Height
== 0 )
235 aSize
.Height
= pPlaceholder
->getSize().Height
;
237 if ( maPosition
.X
== 0 || maPosition
.Y
== 0 ) {
238 awt::Point aPosition
= maPosition
;
239 if( maPosition
.X
== 0 )
240 aPosition
.X
= pPlaceholder
->getPosition().X
;
241 if( maPosition
.Y
== 0 )
242 aPosition
.Y
= pPlaceholder
->getPosition().Y
;
243 setPosition( aPosition
);
249 // use placeholder index if possible
250 if( mnSubType
&& getSubTypeIndex().has() && rSlidePersist
.getMasterPersist().get() ) {
251 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 if( rSlidePersist
.isNotesPage() && pPlaceholder
.get() && pPlaceholder
->getSubType() != getSubType() )
254 pPlaceholder
.reset();
256 if( pPlaceholder
.get()) {
257 SAL_INFO("oox.ppt","found placeholder with index: " << getSubTypeIndex().get() << " and type: " << lclDebugSubType( mnSubType
));
259 if( pPlaceholder
.get() ) {
260 PPTShape
* pPPTPlaceholder
= dynamic_cast< PPTShape
* >( pPlaceholder
.get() );
261 TextListStylePtr
pNewTextListStyle ( new TextListStyle() );
263 if( pPlaceholder
->getTextBody() ) {
265 pNewTextListStyle
->apply( pPlaceholder
->getTextBody()->getTextListStyle() );
266 if( pPlaceholder
->getMasterTextListStyle().get() )
267 pNewTextListStyle
->apply( *pPlaceholder
->getMasterTextListStyle() );
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();
274 aMasterTextListStyle
= pNewTextListStyle
;
275 // SAL_INFO("oox.ppt","combined master text list style");
276 // aMasterTextListStyle->dump();
278 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 TextListStylePtr pPlaceholderStyle
= getSubTypeTextListStyle( rSlidePersist
, pPPTPlaceholder
->mpPlaceholder
->getSubType() );
282 if( pPPTPlaceholder
->mpPlaceholder
->getTextBody() )
283 pNewTextListStyle
->apply( pPPTPlaceholder
->mpPlaceholder
->getTextBody()->getTextListStyle() );
284 if( pPlaceholderStyle
.get() ) {
285 pNewTextListStyle
->apply( *pPlaceholderStyle
);
286 //pPlaceholderStyle->dump();
289 } else if( !mpPlaceholder
.get() ) {
290 aMasterTextListStyle
.reset();
292 SAL_INFO("oox.ppt","placeholder id: " << (pPlaceholder
.get() ? pPlaceholder
->getId() : "not found"));
295 if ( !sServiceName
.isEmpty() )
297 if ( !aMasterTextListStyle
.get() )
299 bool isOther
= !getTextBody().get() && sServiceName
!= "com.sun.star.drawing.GroupShape";
300 TextListStylePtr aSlideStyle
= isOther
? rSlidePersist
.getOtherTextStyle() : rSlidePersist
.getDefaultTextStyle();
301 // Combine from MasterSlide details as well.
302 if( rSlidePersist
.getMasterPersist().get() )
304 aMasterTextListStyle
= isOther
? rSlidePersist
.getMasterPersist()->getOtherTextStyle() : rSlidePersist
.getMasterPersist()->getDefaultTextStyle();
305 if( aSlideStyle
.get() )
306 aMasterTextListStyle
->apply( *aSlideStyle
.get() );
310 aMasterTextListStyle
= aSlideStyle
;
314 if( aMasterTextListStyle
.get() && getTextBody().get() ) {
315 TextListStylePtr
aCombinedTextListStyle (new TextListStyle());
317 aCombinedTextListStyle
->apply( *aMasterTextListStyle
.get() );
319 if( mpPlaceholder
.get() && mpPlaceholder
->getTextBody().get() )
320 aCombinedTextListStyle
->apply( mpPlaceholder
->getTextBody()->getTextListStyle() );
321 aCombinedTextListStyle
->apply( getTextBody()->getTextListStyle() );
323 setMasterTextListStyle( aCombinedTextListStyle
);
325 setMasterTextListStyle( aMasterTextListStyle
);
327 Reference
< XShape
> xShape( createAndInsert( rFilterBase
, sServiceName
, pTheme
, rxShapes
, pShapeRect
, bClearText
, mpPlaceholder
.get() != NULL
, aTransformation
, getFillProperties() ) );
328 if ( !rSlidePersist
.isMasterPage() && rSlidePersist
.getPage().is() && ( (sal_Int32
)mnSubType
== XML_title
) )
333 Reference
< XTextRange
> xText( xShape
, UNO_QUERY_THROW
);
334 aTitleText
= xText
->getString();
335 if ( !aTitleText
.isEmpty() && ( aTitleText
.getLength() < 64 ) ) // just a magic value, but we don't want to set slide names which are too long
337 Reference
< container::XNamed
> xName( rSlidePersist
.getPage(), UNO_QUERY_THROW
);
338 xName
->setName( aTitleText
);
341 catch( uno::Exception
& )
348 // bnc#705982 - if optional model id reference is
349 // there, use that to obtain target shape
350 if( !msModelId
.isEmpty() )
352 (*pShapeMap
)[ msModelId
] = shared_from_this();
354 else if( !msId
.isEmpty() )
356 (*pShapeMap
)[ msId
] = shared_from_this();
360 // if this is a group shape, we have to add also each child shape
361 Reference
< XShapes
> xShapes( xShape
, UNO_QUERY
);
363 addChildren( rFilterBase
, *this, pTheme
, xShapes
, pShapeRect
? *pShapeRect
: awt::Rectangle( maPosition
.X
, maPosition
.Y
, maSize
.Width
, maSize
.Height
), pShapeMap
, aTransformation
);
367 catch( const Exception
& )
372 void PPTShape::applyShapeReference( const oox::drawingml::Shape
& rReferencedShape
, bool bUseText
)
374 Shape::applyShapeReference( rReferencedShape
, bUseText
);
379 bool ShapeLocationIsMaster(oox::drawingml::Shape
*pInShape
)
381 PPTShape
* pShape
= dynamic_cast<PPTShape
*>(pInShape
);
382 return pShape
&& pShape
->getShapeLocation() == Master
;
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 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
)
396 oox::drawingml::ShapePtr aShapePtr
;
397 oox::drawingml::ShapePtr aChoiceShapePtr1
;
398 oox::drawingml::ShapePtr aChoiceShapePtr2
;
399 oox::drawingml::ShapePtr aChoiceShapePtr3
;
400 oox::drawingml::ShapePtr aChoiceShapePtr4
;
401 std::vector
< oox::drawingml::ShapePtr
>::reverse_iterator
aRevIter( rShapes
.rbegin() );
402 while (aRevIter
!= rShapes
.rend())
404 if (!bMasterOnly
|| ShapeLocationIsMaster((*aRevIter
).get()))
406 if ((*aRevIter
)->getSubTypeIndex() == oSubTypeIndex
)
408 if ((*aRevIter
)->getSubType() == nFirstSubType
)
410 aShapePtr
= *aRevIter
;
413 else if ((*aRevIter
)->getSubType() == nSecondSubType
&& !aChoiceShapePtr2
.get())
414 aChoiceShapePtr2
= *aRevIter
;
415 else if (!aChoiceShapePtr4
.get())
416 aChoiceShapePtr4
= *aRevIter
;
418 else if ((*aRevIter
)->getSubType() == nFirstSubType
&& !aChoiceShapePtr1
.get())
419 aChoiceShapePtr1
= *aRevIter
;
420 else if ((*aRevIter
)->getSubType() == nSecondSubType
&& !aChoiceShapePtr3
.get())
421 aChoiceShapePtr3
= *aRevIter
;
423 std::vector
< oox::drawingml::ShapePtr
>& rChildren
= (*aRevIter
)->getChildren();
424 aChoiceShapePtr4
= findPlaceholder( nFirstSubType
, nSecondSubType
, oSubTypeIndex
, rChildren
, bMasterOnly
);
425 if (aChoiceShapePtr4
.get())
427 if (aChoiceShapePtr4
->getSubType() == nFirstSubType
)
429 if (aChoiceShapePtr4
->getSubTypeIndex() == oSubTypeIndex
)
430 aShapePtr
= aChoiceShapePtr4
;
432 aChoiceShapePtr1
= aChoiceShapePtr4
;
434 else if (aChoiceShapePtr4
->getSubType() == nSecondSubType
)
436 if (aChoiceShapePtr4
->getSubTypeIndex() == oSubTypeIndex
)
437 aChoiceShapePtr2
= aChoiceShapePtr4
;
439 aChoiceShapePtr3
= aChoiceShapePtr4
;
448 if (aChoiceShapePtr1
.get())
449 return aChoiceShapePtr1
;
450 if (aChoiceShapePtr2
.get())
451 return aChoiceShapePtr2
;
452 if (aChoiceShapePtr3
.get())
453 return aChoiceShapePtr3
;
454 return aChoiceShapePtr4
;
457 oox::drawingml::ShapePtr
PPTShape::findPlaceholderByIndex( const sal_Int32 nIdx
, std::vector
< oox::drawingml::ShapePtr
>& rShapes
, bool bMasterOnly
)
459 oox::drawingml::ShapePtr aShapePtr
;
461 std::vector
< oox::drawingml::ShapePtr
>::reverse_iterator
aRevIter( rShapes
.rbegin() );
462 while( aRevIter
!= rShapes
.rend() )
464 if ( (*aRevIter
)->getSubTypeIndex().has() && (*aRevIter
)->getSubTypeIndex().get() == nIdx
&&
465 ( !bMasterOnly
|| ShapeLocationIsMaster((*aRevIter
).get()) ) )
467 aShapePtr
= *aRevIter
;
470 std::vector
< oox::drawingml::ShapePtr
>& rChildren
= (*aRevIter
)->getChildren();
471 aShapePtr
= findPlaceholderByIndex( nIdx
, rChildren
, bMasterOnly
);
472 if ( aShapePtr
.get() )
481 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */