Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / oox / source / ppt / pptshape.cxx
blob0088c1e51673b5f935f8be0128457b118bdf2df1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 )
56 PPTShape::~PPTShape()
60 static const char* lclDebugSubType( sal_Int32 nType )
62 switch (nType) {
63 case XML_ctrTitle :
64 return "ctrTitle";
65 case XML_title :
66 return "title";
67 case XML_subTitle :
68 return "subTitle";
69 case XML_obj :
70 return "obj";
71 case XML_body :
72 return "body";
73 case XML_dt :
74 return "dt";
75 case XML_hdr :
76 return "hdr";
77 case XML_ftr :
78 return "frt";
79 case XML_sldNum :
80 return "sldNum";
81 case XML_sldImg :
82 return "sldImg";
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 ) );
94 switch( nSubType )
96 case XML_ctrTitle :
97 case XML_title :
98 pTextListStyle = rSlidePersist.getMasterPersist().get() ? rSlidePersist.getMasterPersist()->getTitleTextStyle() : rSlidePersist.getTitleTextStyle();
99 break;
100 case XML_subTitle :
101 case XML_obj :
102 case XML_body :
103 if ( rSlidePersist.isNotesPage() )
104 pTextListStyle = rSlidePersist.getMasterPersist().get() ? rSlidePersist.getMasterPersist()->getNotesTextStyle() : rSlidePersist.getNotesTextStyle();
105 else
106 pTextListStyle = rSlidePersist.getMasterPersist().get() ? rSlidePersist.getMasterPersist()->getBodyTextStyle() : rSlidePersist.getBodyTextStyle();
107 break;
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 ) )
124 return;
126 OUString sServiceName( msServiceName );
127 if (sServiceName.isEmpty())
128 return;
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());
140 switch (mnSubType)
142 case XML_ctrTitle :
143 case XML_title :
145 sServiceName = "com.sun.star.presentation.TitleTextShape";
146 aMasterTextListStyle = rSlidePersist.getMasterPersist().get() ? rSlidePersist.getMasterPersist()->getTitleTextStyle() : rSlidePersist.getTitleTextStyle();
148 break;
149 case XML_subTitle :
151 if ((meShapeLocation == Master) || (meShapeLocation == Layout))
152 sServiceName = OUString();
153 else {
154 sServiceName = "com.sun.star.presentation.SubtitleShape";
155 aMasterTextListStyle = rSlidePersist.getMasterPersist().get() ? rSlidePersist.getMasterPersist()->getBodyTextStyle() : rSlidePersist.getBodyTextStyle();
158 break;
159 case XML_obj :
161 sServiceName = sOutlinerShapeService;
162 aMasterTextListStyle = rSlidePersist.getMasterPersist().get() ? rSlidePersist.getMasterPersist()->getBodyTextStyle() : rSlidePersist.getBodyTextStyle();
164 break;
165 case XML_body :
167 if (rSlidePersist.isNotesPage())
169 sServiceName = "com.sun.star.presentation.NotesShape";
170 aMasterTextListStyle = rSlidePersist.getMasterPersist().get() ? rSlidePersist.getMasterPersist()->getNotesTextStyle() : rSlidePersist.getNotesTextStyle();
172 else
174 sServiceName = sOutlinerShapeService;
175 aMasterTextListStyle = rSlidePersist.getMasterPersist().get() ? rSlidePersist.getMasterPersist()->getBodyTextStyle() : rSlidePersist.getBodyTextStyle();
178 break;
179 case XML_dt :
180 sServiceName = "com.sun.star.presentation.DateTimeShape";
181 bClearText = true;
182 break;
183 case XML_hdr :
184 sServiceName = "com.sun.star.presentation.HeaderShape";
185 bClearText = true;
186 break;
187 case XML_ftr :
188 sServiceName = "com.sun.star.presentation.FooterShape";
189 bClearText = true;
190 break;
191 case XML_sldNum :
192 sServiceName = "com.sun.star.presentation.SlideNumberShape";
193 bClearText = true;
194 break;
195 case XML_sldImg :
196 sServiceName = "com.sun.star.presentation.PageShape";
197 break;
198 case XML_chart :
199 if (meShapeLocation == Layout)
200 sServiceName = sOutlinerShapeService;
201 else
202 sServiceName = "com.sun.star.presentation.ChartShape";
203 break;
204 case XML_tbl :
205 if (meShapeLocation == Layout)
206 sServiceName = sOutlinerShapeService;
207 else
208 sServiceName = "com.sun.star.presentation.TableShape";
209 break;
210 case XML_pic :
211 if (meShapeLocation == Layout)
212 sServiceName = sOutlinerShapeService;
213 else
214 sServiceName = "com.sun.star.presentation.GraphicObjectShape";
215 break;
216 case XML_media :
217 if (meShapeLocation == Layout)
218 sServiceName = sOutlinerShapeService;
219 else
220 sServiceName = "com.sun.star.presentation.MediaShape";
221 break;
222 default:
223 if (mnSubType && meShapeLocation == Layout)
224 sServiceName = sOutlinerShapeService;
225 break;
229 if (sServiceName != "com.sun.star.drawing.TableShape")
231 if (TextBodyPtr pTextBody = getTextBody())
233 sal_Int32 nNumCol = pTextBody->getTextProperties().mnNumCol;
234 if (nNumCol > 1)
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;
261 setSize( aSize );
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 );
334 else
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 );
350 } else
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)
358 OUString aTitleText;
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);
377 if (xText.is())
379 TextCharacterProperties aCharStyleProperties;
380 getTextBody()->ApplyStyleEmpty(rFilterBase, xText, aCharStyleProperties, mpMasterTextListStyle);
383 if (pShapeMap)
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);
399 if (xShapes.is())
400 addChildren( rFilterBase, *this, pTheme, xShapes, pShapeMap, aTransformation );
402 if (meFrameType == FRAMETYPE_DIAGRAM)
403 keepDiagramCompatibilityInfo();
406 catch (const Exception&)
411 namespace
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;
445 break;
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;
465 else
466 aChoiceShapePtr1 = aChoiceShapePtr4;
468 else if (aChoiceShapePtr4->getSubType() == nSecondSubType)
470 if (aChoiceShapePtr4->getSubTypeIndex() == oSubTypeIndex)
471 aChoiceShapePtr2 = aChoiceShapePtr4;
472 else
473 aChoiceShapePtr3 = aChoiceShapePtr4;
476 if (aShapePtr.get())
477 break;
478 ++aRevIter;
480 if (aShapePtr.get())
481 return aShapePtr;
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;
502 break;
504 std::vector< oox::drawingml::ShapePtr >& rChildren = (*aRevIter)->getChildren();
505 aShapePtr = findPlaceholderByIndex( nIdx, rChildren, bMasterOnly );
506 if ( aShapePtr.get() )
507 break;
508 ++aRevIter;
510 return aShapePtr;
515 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */