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>
23 #include <drawingml/table/tableproperties.hxx>
25 #include <com/sun/star/awt/Rectangle.hpp>
26 #include <com/sun/star/container/XNamed.hpp>
27 #include <com/sun/star/beans/XMultiPropertySet.hpp>
28 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
29 #include <com/sun/star/drawing/HomogenMatrix3.hpp>
30 #include <com/sun/star/drawing/XShapes.hpp>
31 #include <com/sun/star/text/XText.hpp>
32 #include <basegfx/matrix/b2dhommatrix.hxx>
33 #include <sal/log.hxx>
34 #include <oox/ppt/slidepersist.hxx>
35 #include <oox/token/tokens.hxx>
36 #include <unotools/fltrcfg.hxx>
38 using namespace ::oox::core
;
39 using namespace ::oox::drawingml
;
40 using namespace ::com::sun::star
;
41 using namespace ::com::sun::star::awt
;
42 using namespace ::com::sun::star::uno
;
43 using namespace ::com::sun::star::beans
;
44 using namespace ::com::sun::star::text
;
45 using namespace ::com::sun::star::drawing
;
47 namespace oox
{ namespace ppt
{
49 PPTShape::PPTShape( const oox::ppt::ShapeLocation eShapeLocation
, const sal_Char
* pServiceName
)
50 : Shape( pServiceName
)
51 , meShapeLocation( eShapeLocation
)
52 , mbReferenced( false )
60 static const char* lclDebugSubType( sal_Int32 nType
)
85 return "unknown - please extend lclDebugSubType";
88 oox::drawingml::TextListStylePtr
PPTShape::getSubTypeTextListStyle( const SlidePersist
& rSlidePersist
, sal_Int32 nSubType
)
90 oox::drawingml::TextListStylePtr pTextListStyle
;
92 SAL_INFO("oox.ppt", "subtype style: " << lclDebugSubType( nSubType
) );
98 pTextListStyle
= rSlidePersist
.getMasterPersist().get() ? rSlidePersist
.getMasterPersist()->getTitleTextStyle() : rSlidePersist
.getTitleTextStyle();
103 if ( rSlidePersist
.isNotesPage() )
104 pTextListStyle
= rSlidePersist
.getMasterPersist().get() ? rSlidePersist
.getMasterPersist()->getNotesTextStyle() : rSlidePersist
.getNotesTextStyle();
106 pTextListStyle
= rSlidePersist
.getMasterPersist().get() ? rSlidePersist
.getMasterPersist()->getBodyTextStyle() : rSlidePersist
.getBodyTextStyle();
110 return pTextListStyle
;
113 void PPTShape::addShape(
114 oox::core::XmlFilterBase
& rFilterBase
,
115 const SlidePersist
& rSlidePersist
,
116 const oox::drawingml::Theme
* pTheme
,
117 const Reference
< XShapes
>& rxShapes
,
118 basegfx::B2DHomMatrix
& aTransformation
,
119 ::oox::drawingml::ShapeIdMap
* pShapeMap
)
121 SAL_INFO("oox.ppt","add shape id: " << msId
<< " location: " << ((meShapeLocation
== Master
) ? "master" : ((meShapeLocation
== Slide
) ? "slide" : ((meShapeLocation
== Layout
) ? "layout" : "other"))) << " subtype: " << mnSubType
<< " service: " << msServiceName
);
122 // only placeholder from layout are being inserted
123 if ( mnSubType
&& ( meShapeLocation
== Master
) )
126 OUString
sServiceName( msServiceName
);
127 if (sServiceName
.isEmpty())
131 oox::drawingml::TextListStylePtr aMasterTextListStyle
;
132 Reference
<lang::XMultiServiceFactory
> xServiceFact(rFilterBase
.getModel(), UNO_QUERY_THROW
);
133 bool bClearText
= false;
135 if (sServiceName
!= "com.sun.star.drawing.GraphicObjectShape" &&
136 sServiceName
!= "com.sun.star.drawing.OLE2Shape")
138 const OUString
sOutlinerShapeService("com.sun.star.presentation.OutlinerShape");
139 SAL_INFO("oox.ppt","has master: " << std::hex
<< rSlidePersist
.getMasterPersist().get());
145 sServiceName
= "com.sun.star.presentation.TitleTextShape";
146 aMasterTextListStyle
= rSlidePersist
.getMasterPersist().get() ? rSlidePersist
.getMasterPersist()->getTitleTextStyle() : rSlidePersist
.getTitleTextStyle();
151 if ((meShapeLocation
== Master
) || (meShapeLocation
== Layout
))
152 sServiceName
= OUString();
154 sServiceName
= "com.sun.star.presentation.SubtitleShape";
155 aMasterTextListStyle
= rSlidePersist
.getMasterPersist().get() ? rSlidePersist
.getMasterPersist()->getBodyTextStyle() : rSlidePersist
.getBodyTextStyle();
161 sServiceName
= sOutlinerShapeService
;
162 aMasterTextListStyle
= rSlidePersist
.getMasterPersist().get() ? rSlidePersist
.getMasterPersist()->getBodyTextStyle() : rSlidePersist
.getBodyTextStyle();
167 if (rSlidePersist
.isNotesPage())
169 sServiceName
= "com.sun.star.presentation.NotesShape";
170 aMasterTextListStyle
= rSlidePersist
.getMasterPersist().get() ? rSlidePersist
.getMasterPersist()->getNotesTextStyle() : rSlidePersist
.getNotesTextStyle();
174 sServiceName
= sOutlinerShapeService
;
175 aMasterTextListStyle
= rSlidePersist
.getMasterPersist().get() ? rSlidePersist
.getMasterPersist()->getBodyTextStyle() : rSlidePersist
.getBodyTextStyle();
180 sServiceName
= "com.sun.star.presentation.DateTimeShape";
184 sServiceName
= "com.sun.star.presentation.HeaderShape";
188 sServiceName
= "com.sun.star.presentation.FooterShape";
192 sServiceName
= "com.sun.star.presentation.SlideNumberShape";
196 sServiceName
= "com.sun.star.presentation.PageShape";
199 if (meShapeLocation
== Layout
)
200 sServiceName
= sOutlinerShapeService
;
202 sServiceName
= "com.sun.star.presentation.ChartShape";
205 if (meShapeLocation
== Layout
)
206 sServiceName
= sOutlinerShapeService
;
208 sServiceName
= "com.sun.star.presentation.TableShape";
211 if (meShapeLocation
== Layout
)
212 sServiceName
= sOutlinerShapeService
;
214 sServiceName
= "com.sun.star.presentation.GraphicObjectShape";
217 if (meShapeLocation
== Layout
)
218 sServiceName
= sOutlinerShapeService
;
220 sServiceName
= "com.sun.star.presentation.MediaShape";
223 if (mnSubType
&& meShapeLocation
== Layout
)
224 sServiceName
= sOutlinerShapeService
;
229 if (sServiceName
!= "com.sun.star.drawing.TableShape")
231 if (TextBodyPtr pTextBody
= getTextBody())
233 sal_Int32 nNumCol
= pTextBody
->getTextProperties().mnNumCol
;
236 // This shape is not a table, but has multiple columns,
237 // represent that as a table.
238 sServiceName
= "com.sun.star.drawing.TableShape";
239 oox::drawingml::table::TablePropertiesPtr pTableProperties
= getTableProperties();
240 pTableProperties
->pullFromTextBody(pTextBody
, maSize
.Width
);
241 setTextBody(nullptr);
246 SAL_INFO("oox.ppt","shape service: " << sServiceName
);
248 if (mnSubType
&& getSubTypeIndex().has() && meShapeLocation
== Layout
)
250 oox::drawingml::ShapePtr pPlaceholder
= PPTShape::findPlaceholderByIndex( getSubTypeIndex().get(), rSlidePersist
.getShapes()->getChildren(), true );
251 if (!pPlaceholder
.get())
252 pPlaceholder
= PPTShape::findPlaceholder( mnSubType
, 0, getSubTypeIndex(), rSlidePersist
.getShapes()->getChildren(), true );
254 if (pPlaceholder
.get()) {
255 if (maSize
.Width
== 0 || maSize
.Height
== 0) {
256 awt::Size aSize
= maSize
;
257 if (maSize
.Width
== 0)
258 aSize
.Width
= pPlaceholder
->getSize().Width
;
259 if (maSize
.Height
== 0)
260 aSize
.Height
= pPlaceholder
->getSize().Height
;
262 if (maPosition
.X
== 0 || maPosition
.Y
== 0) {
263 awt::Point aPosition
= maPosition
;
264 if (maPosition
.X
== 0)
265 aPosition
.X
= pPlaceholder
->getPosition().X
;
266 if (maPosition
.Y
== 0)
267 aPosition
.Y
= pPlaceholder
->getPosition().Y
;
268 setPosition( aPosition
);
274 // use placeholder index if possible
275 if (mnSubType
&& getSubTypeIndex().has() && rSlidePersist
.getMasterPersist().get())
277 oox::drawingml::ShapePtr pPlaceholder
= PPTShape::findPlaceholderByIndex(getSubTypeIndex().get(), rSlidePersist
.getMasterPersist()->getShapes()->getChildren());
278 // TODO: Check if this is required for non-notes slides as well...
279 if (rSlidePersist
.isNotesPage() && pPlaceholder
.get() && pPlaceholder
->getSubType() != getSubType())
280 pPlaceholder
.reset();
282 if (pPlaceholder
.get()) {
283 SAL_INFO("oox.ppt","found placeholder with index: " << getSubTypeIndex().get() << " and type: " << lclDebugSubType( mnSubType
));
285 if (pPlaceholder
.get()) {
286 PPTShape
* pPPTPlaceholder
= dynamic_cast< PPTShape
* >( pPlaceholder
.get() );
287 TextListStylePtr
pNewTextListStyle ( new TextListStyle() );
289 if (pPlaceholder
->getTextBody()) {
291 pNewTextListStyle
->apply( pPlaceholder
->getTextBody()->getTextListStyle() );
292 if (pPlaceholder
->getMasterTextListStyle().get())
293 pNewTextListStyle
->apply( *pPlaceholder
->getMasterTextListStyle() );
295 // SAL_INFO("oox.ppt","placeholder body style");
296 // pPlaceholder->getTextBody()->getTextListStyle().dump();
297 // SAL_INFO("oox.ppt","master text list style");
298 // pPlaceholder->getMasterTextListStyle()->dump();
300 aMasterTextListStyle
= pNewTextListStyle
;
301 // SAL_INFO("oox.ppt","combined master text list style");
302 // aMasterTextListStyle->dump();
304 if (pPPTPlaceholder
&& pPPTPlaceholder
->mpPlaceholder
.get()) {
305 SAL_INFO("oox.ppt","placeholder has parent placeholder: " << pPPTPlaceholder
->mpPlaceholder
->getId() << " type: " << lclDebugSubType( pPPTPlaceholder
->mpPlaceholder
->getSubType() ) << " index: " << pPPTPlaceholder
->mpPlaceholder
->getSubTypeIndex().get() );
306 SAL_INFO("oox.ppt","has textbody " << (pPPTPlaceholder
->mpPlaceholder
->getTextBody() != nullptr) );
307 TextListStylePtr pPlaceholderStyle
= getSubTypeTextListStyle( rSlidePersist
, pPPTPlaceholder
->mpPlaceholder
->getSubType() );
308 if (pPPTPlaceholder
->mpPlaceholder
->getTextBody())
309 pNewTextListStyle
->apply( pPPTPlaceholder
->mpPlaceholder
->getTextBody()->getTextListStyle() );
310 if (pPlaceholderStyle
.get()) {
311 pNewTextListStyle
->apply( *pPlaceholderStyle
);
312 //pPlaceholderStyle->dump();
315 } else if (!mpPlaceholder
.get()) {
316 aMasterTextListStyle
.reset();
318 SAL_INFO("oox.ppt","placeholder id: " << (pPlaceholder
.get() ? pPlaceholder
->getId() : "not found"));
321 if (!sServiceName
.isEmpty())
323 if (!aMasterTextListStyle
.get())
325 bool isOther
= !getTextBody().get() && sServiceName
!= "com.sun.star.drawing.GroupShape";
326 TextListStylePtr aSlideStyle
= isOther
? rSlidePersist
.getOtherTextStyle() : rSlidePersist
.getDefaultTextStyle();
327 // Combine from MasterSlide details as well.
328 if (rSlidePersist
.getMasterPersist().get())
330 aMasterTextListStyle
= isOther
? rSlidePersist
.getMasterPersist()->getOtherTextStyle() : rSlidePersist
.getMasterPersist()->getDefaultTextStyle();
331 if (aSlideStyle
.get())
332 aMasterTextListStyle
->apply( *aSlideStyle
);
336 aMasterTextListStyle
= aSlideStyle
;
340 if( aMasterTextListStyle
.get() && getTextBody().get() ) {
341 TextListStylePtr
aCombinedTextListStyle (new TextListStyle());
343 aCombinedTextListStyle
->apply( *aMasterTextListStyle
);
345 if( mpPlaceholder
.get() && mpPlaceholder
->getTextBody().get() )
346 aCombinedTextListStyle
->apply( mpPlaceholder
->getTextBody()->getTextListStyle() );
347 aCombinedTextListStyle
->apply( getTextBody()->getTextListStyle() );
349 setMasterTextListStyle( aCombinedTextListStyle
);
351 setMasterTextListStyle( aMasterTextListStyle
);
353 Reference
< XShape
> xShape( createAndInsert( rFilterBase
, sServiceName
, pTheme
, rxShapes
, bClearText
, mpPlaceholder
.get() != nullptr, aTransformation
, getFillProperties() ) );
354 if (!rSlidePersist
.isMasterPage() && rSlidePersist
.getPage().is() && mnSubType
== XML_title
)
359 Reference
<XTextRange
> xText(xShape
, UNO_QUERY_THROW
);
360 aTitleText
= xText
->getString();
361 if (!aTitleText
.isEmpty() && (aTitleText
.getLength() < 64)) // just a magic value, but we don't want to set slide names which are too long
363 Reference
<container::XNamed
> xName(rSlidePersist
.getPage(), UNO_QUERY_THROW
);
364 xName
->setName(aTitleText
);
367 catch (uno::Exception
&)
373 // Apply text properties on placeholder text inside this placeholder shape
374 if (meShapeLocation
== Slide
&& mpPlaceholder
.get() != nullptr && getTextBody() && getTextBody()->isEmpty())
376 Reference
< XText
> xText(mxShape
, UNO_QUERY
);
379 TextCharacterProperties aCharStyleProperties
;
380 getTextBody()->ApplyStyleEmpty(rFilterBase
, xText
, aCharStyleProperties
, mpMasterTextListStyle
);
385 // bnc#705982 - if optional model id reference is
386 // there, use that to obtain target shape
387 if (!msModelId
.isEmpty())
389 (*pShapeMap
)[ msModelId
] = shared_from_this();
391 else if (!msId
.isEmpty())
393 (*pShapeMap
)[ msId
] = shared_from_this();
397 // if this is a group shape, we have to add also each child shape
398 Reference
<XShapes
> xShapes(xShape
, UNO_QUERY
);
400 addChildren( rFilterBase
, *this, pTheme
, xShapes
, pShapeMap
, aTransformation
);
402 if (meFrameType
== FRAMETYPE_DIAGRAM
)
403 keepDiagramCompatibilityInfo();
406 catch (const Exception
&)
413 bool ShapeLocationIsMaster(oox::drawingml::Shape
*pInShape
)
415 PPTShape
* pShape
= dynamic_cast<PPTShape
*>(pInShape
);
416 return pShape
&& pShape
->getShapeLocation() == Master
;
420 // Function to find placeholder (ph) for a shape. No idea how MSO implements this, but
421 // this order seems to work quite well (probably it's unnecessary complicated / wrong):
422 // 1. ph with nFirstSubType and the same oSubTypeIndex
423 // 2. ph with nFirstSubType
424 // 3. ph with nSecondSubType and the same oSubTypeIndex
425 // 4. ph with nSecondSubType
426 // 5. ph with the same oSubTypeIndex
427 oox::drawingml::ShapePtr
PPTShape::findPlaceholder( sal_Int32 nFirstSubType
, sal_Int32 nSecondSubType
,
428 const OptValue
< sal_Int32
>& oSubTypeIndex
, std::vector
< oox::drawingml::ShapePtr
>& rShapes
, bool bMasterOnly
)
430 oox::drawingml::ShapePtr aShapePtr
;
431 oox::drawingml::ShapePtr aChoiceShapePtr1
;
432 oox::drawingml::ShapePtr aChoiceShapePtr2
;
433 oox::drawingml::ShapePtr aChoiceShapePtr3
;
434 oox::drawingml::ShapePtr aChoiceShapePtr4
;
435 std::vector
< oox::drawingml::ShapePtr
>::reverse_iterator
aRevIter( rShapes
.rbegin() );
436 while (aRevIter
!= rShapes
.rend())
438 if (!bMasterOnly
|| ShapeLocationIsMaster((*aRevIter
).get()))
440 if ((*aRevIter
)->getSubTypeIndex() == oSubTypeIndex
)
442 if ((*aRevIter
)->getSubType() == nFirstSubType
)
444 aShapePtr
= *aRevIter
;
447 else if ((*aRevIter
)->getSubType() == nSecondSubType
&& !aChoiceShapePtr2
.get())
448 aChoiceShapePtr2
= *aRevIter
;
449 else if (!aChoiceShapePtr4
.get())
450 aChoiceShapePtr4
= *aRevIter
;
452 else if ((*aRevIter
)->getSubType() == nFirstSubType
&& !aChoiceShapePtr1
.get())
453 aChoiceShapePtr1
= *aRevIter
;
454 else if ((*aRevIter
)->getSubType() == nSecondSubType
&& !aChoiceShapePtr3
.get())
455 aChoiceShapePtr3
= *aRevIter
;
457 std::vector
< oox::drawingml::ShapePtr
>& rChildren
= (*aRevIter
)->getChildren();
458 aChoiceShapePtr4
= findPlaceholder( nFirstSubType
, nSecondSubType
, oSubTypeIndex
, rChildren
, bMasterOnly
);
459 if (aChoiceShapePtr4
.get())
461 if (aChoiceShapePtr4
->getSubType() == nFirstSubType
)
463 if (aChoiceShapePtr4
->getSubTypeIndex() == oSubTypeIndex
)
464 aShapePtr
= aChoiceShapePtr4
;
466 aChoiceShapePtr1
= aChoiceShapePtr4
;
468 else if (aChoiceShapePtr4
->getSubType() == nSecondSubType
)
470 if (aChoiceShapePtr4
->getSubTypeIndex() == oSubTypeIndex
)
471 aChoiceShapePtr2
= aChoiceShapePtr4
;
473 aChoiceShapePtr3
= aChoiceShapePtr4
;
482 if (aChoiceShapePtr1
.get())
483 return aChoiceShapePtr1
;
484 if (aChoiceShapePtr2
.get())
485 return aChoiceShapePtr2
;
486 if (aChoiceShapePtr3
.get())
487 return aChoiceShapePtr3
;
488 return aChoiceShapePtr4
;
491 oox::drawingml::ShapePtr
PPTShape::findPlaceholderByIndex( const sal_Int32 nIdx
, std::vector
< oox::drawingml::ShapePtr
>& rShapes
, bool bMasterOnly
)
493 oox::drawingml::ShapePtr aShapePtr
;
495 std::vector
< oox::drawingml::ShapePtr
>::reverse_iterator
aRevIter( rShapes
.rbegin() );
496 while( aRevIter
!= rShapes
.rend() )
498 if ( (*aRevIter
)->getSubTypeIndex().has() && (*aRevIter
)->getSubTypeIndex().get() == nIdx
&&
499 ( !bMasterOnly
|| ShapeLocationIsMaster((*aRevIter
).get()) ) )
501 aShapePtr
= *aRevIter
;
504 std::vector
< oox::drawingml::ShapePtr
>& rChildren
= (*aRevIter
)->getChildren();
505 aShapePtr
= findPlaceholderByIndex( nIdx
, rChildren
, bMasterOnly
);
506 if ( aShapePtr
.get() )
515 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */