Bump version to 24.04.3.4
[LibreOffice.git] / oox / source / ppt / pptshape.cxx
blob733aa2a73aed5e84b2952bf02c0511493a736c94
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/customshapeproperties.hxx>
23 #include <drawingml/textbody.hxx>
24 #include <drawingml/textparagraph.hxx>
25 #include <drawingml/textfield.hxx>
26 #include <editeng/flditem.hxx>
28 #include <com/sun/star/text/XTextField.hpp>
29 #include <com/sun/star/container/XNamed.hpp>
30 #include <com/sun/star/frame/XModel.hpp>
31 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
32 #include <com/sun/star/drawing/XDrawPage.hpp>
33 #include <com/sun/star/drawing/XDrawPages.hpp>
34 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
35 #include <com/sun/star/drawing/XShapes.hpp>
36 #include <com/sun/star/text/XText.hpp>
37 #include <com/sun/star/document/XEventsSupplier.hpp>
38 #include <com/sun/star/container/XNameReplace.hpp>
39 #include <com/sun/star/presentation/ClickAction.hpp>
40 #include <basegfx/matrix/b2dhommatrix.hxx>
41 #include <sal/log.hxx>
42 #include <oox/ppt/slidepersist.hxx>
43 #include <oox/token/tokens.hxx>
44 #include <oox/token/properties.hxx>
45 #include <o3tl/string_view.hxx>
47 using namespace ::oox::core;
48 using namespace ::oox::drawingml;
49 using namespace ::com::sun::star;
50 using namespace ::com::sun::star::awt;
51 using namespace ::com::sun::star::uno;
52 using namespace ::com::sun::star::beans;
53 using namespace ::com::sun::star::text;
54 using namespace ::com::sun::star::drawing;
55 using namespace ::com::sun::star::document;
56 using namespace ::com::sun::star::container;
57 using namespace ::com::sun::star::presentation;
59 namespace oox::ppt {
61 PPTShape::PPTShape( const oox::ppt::ShapeLocation eShapeLocation, const char* pServiceName )
62 : Shape( pServiceName )
63 , meShapeLocation( eShapeLocation )
64 , mbReferenced( false )
65 , mbHasNoninheritedShapeProperties( false )
69 PPTShape::~PPTShape()
73 static const char* lclDebugSubType( sal_Int32 nType )
75 switch (nType) {
76 case XML_ctrTitle :
77 return "ctrTitle";
78 case XML_title :
79 return "title";
80 case XML_subTitle :
81 return "subTitle";
82 case XML_obj :
83 return "obj";
84 case XML_body :
85 return "body";
86 case XML_dt :
87 return "dt";
88 case XML_hdr :
89 return "hdr";
90 case XML_ftr :
91 return "frt";
92 case XML_sldNum :
93 return "sldNum";
94 case XML_sldImg :
95 return "sldImg";
98 return "unknown - please extend lclDebugSubType";
101 namespace
103 bool ShapeHasNoVisualPropertiesOnImport(const oox::ppt::PPTShape& rPPTShape)
105 return !rPPTShape.hasNonInheritedShapeProperties()
106 && !rPPTShape.hasShapeStyleRefs()
107 && !rPPTShape.getTextBody()->hasVisualRunProperties()
108 && !rPPTShape.getTextBody()->hasNoninheritedBodyProperties()
109 && !rPPTShape.getTextBody()->hasListStyleOnImport()
110 && !rPPTShape.getTextBody()->hasParagraphProperties();
114 oox::drawingml::TextListStylePtr PPTShape::getSubTypeTextListStyle( const SlidePersist& rSlidePersist, sal_Int32 nSubType )
116 oox::drawingml::TextListStylePtr pTextListStyle;
118 SAL_INFO("oox.ppt", "subtype style: " << lclDebugSubType( nSubType ) );
120 switch( nSubType )
122 case XML_ctrTitle :
123 case XML_title :
124 pTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getTitleTextStyle() : rSlidePersist.getTitleTextStyle();
125 break;
126 case XML_subTitle :
127 case XML_obj :
128 case XML_body :
129 if ( rSlidePersist.isNotesPage() )
130 pTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getNotesTextStyle() : rSlidePersist.getNotesTextStyle();
131 else
132 pTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getBodyTextStyle() : rSlidePersist.getBodyTextStyle();
133 break;
136 return pTextListStyle;
139 bool PPTShape::IsPlaceHolderCandidate(const SlidePersist& rSlidePersist) const
141 if (meShapeLocation != Slide)
142 return false;
143 if (rSlidePersist.isNotesPage())
144 return false;
145 auto pTextBody = getTextBody();
146 if (!pTextBody)
147 return false;
148 auto rParagraphs = pTextBody->getParagraphs();
149 if (rParagraphs.size() != 1)
150 return false;
151 if (rParagraphs.front()->getRuns().size() != 1)
152 return false;
153 // If the placeholder has a shape other than rectangle,
154 // we have to place it in the slide as a CustomShape.
155 if (!mpCustomShapePropertiesPtr->representsDefaultShape())
156 return false;
157 return ShapeHasNoVisualPropertiesOnImport(*this);
160 void PPTShape::addShape(
161 oox::core::XmlFilterBase& rFilterBase,
162 const SlidePersist& rSlidePersist,
163 const oox::drawingml::Theme* pTheme,
164 const Reference< XShapes >& rxShapes,
165 basegfx::B2DHomMatrix& aTransformation,
166 ::oox::drawingml::ShapeIdMap* pShapeMap )
168 SAL_INFO("oox.ppt","add shape id: " << msId << " location: " << ((meShapeLocation == Master) ? "master" : ((meShapeLocation == Slide) ? "slide" : ((meShapeLocation == Layout) ? "layout" : "other"))) << " subtype: " << mnSubType << " service: " << msServiceName);
169 // only placeholder from layout are being inserted
170 if ( mnSubType && ( meShapeLocation == Master ) )
171 return;
173 OUString sServiceName( msServiceName );
174 if (sServiceName.isEmpty())
175 return;
178 oox::drawingml::TextListStylePtr aMasterTextListStyle;
179 Reference<lang::XMultiServiceFactory> xServiceFact(rFilterBase.getModel(), UNO_QUERY_THROW);
180 bool bClearText = false;
182 if (sServiceName != "com.sun.star.drawing.GraphicObjectShape" &&
183 sServiceName != "com.sun.star.drawing.OLE2Shape")
185 static constexpr OUString sOutlinerShapeService(u"com.sun.star.presentation.OutlinerShape"_ustr);
186 SAL_INFO("oox.ppt","has master: " << std::hex << rSlidePersist.getMasterPersist().get());
187 switch (mnSubType)
189 case XML_ctrTitle :
190 case XML_title :
192 sServiceName = "com.sun.star.presentation.TitleTextShape";
193 aMasterTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getTitleTextStyle() : rSlidePersist.getTitleTextStyle();
195 break;
196 case XML_subTitle :
198 if ((meShapeLocation == Master) || (meShapeLocation == Layout))
199 sServiceName = OUString();
200 else {
201 sServiceName = "com.sun.star.presentation.SubtitleShape";
202 aMasterTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getBodyTextStyle() : rSlidePersist.getBodyTextStyle();
205 break;
206 case XML_obj :
208 sServiceName = sOutlinerShapeService;
209 if (getSubTypeIndex().has_value())
210 aMasterTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getBodyTextStyle() : rSlidePersist.getBodyTextStyle();
212 break;
213 case XML_body :
215 if (rSlidePersist.isNotesPage())
217 sServiceName = "com.sun.star.presentation.NotesShape";
218 aMasterTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getNotesTextStyle() : rSlidePersist.getNotesTextStyle();
220 else
222 sServiceName = sOutlinerShapeService;
223 aMasterTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getBodyTextStyle() : rSlidePersist.getBodyTextStyle();
226 break;
227 case XML_dt :
228 if (IsPlaceHolderCandidate(rSlidePersist))
230 TextRunPtr& pTextRun = getTextBody()->getParagraphs().front()->getRuns().front();
231 oox::drawingml::TextField* pTextField = dynamic_cast<oox::drawingml::TextField*>(pTextRun.get());
232 if (pTextField)
234 OUString aType = pTextField->getType();
235 if ( aType.startsWith("datetime") )
237 SvxDateFormat eDateFormat = drawingml::TextField::getLODateFormat(aType);
238 SvxTimeFormat eTimeFormat = drawingml::TextField::getLOTimeFormat(aType);
239 Reference< XPropertySet > xPropertySet( rSlidePersist.getPage(), UNO_QUERY );
241 if( eDateFormat != SvxDateFormat::AppDefault
242 || eTimeFormat != SvxTimeFormat::AppDefault )
244 // DateTimeFormat property looks for the date in 4 LSBs
245 // and looks for time format in the 4 bits after that
246 sal_Int32 nDateTimeFormat = static_cast<sal_Int32>(eDateFormat) |
247 static_cast<sal_Int32>(eTimeFormat) << 4;
248 xPropertySet->setPropertyValue( "IsDateTimeVisible", Any(true) );
249 xPropertySet->setPropertyValue( "IsDateTimeFixed", Any(false) );
250 xPropertySet->setPropertyValue( "DateTimeFormat", Any(nDateTimeFormat) );
251 return;
256 sServiceName = "com.sun.star.presentation.DateTimeShape";
257 bClearText = true;
258 break;
259 case XML_hdr :
260 sServiceName = "com.sun.star.presentation.HeaderShape";
261 bClearText = true;
262 break;
263 case XML_ftr :
264 if (IsPlaceHolderCandidate(rSlidePersist))
266 const OUString& rFooterText = getTextBody()->toString();
268 if( !rFooterText.isEmpty() )
270 // if it is possible to get the footer as a property the LO way,
271 // get it and discard the shape
272 Reference< XPropertySet > xPropertySet( rSlidePersist.getPage(), UNO_QUERY );
273 xPropertySet->setPropertyValue( "IsFooterVisible", Any( true ) );
274 xPropertySet->setPropertyValue( "FooterText", Any(rFooterText) );
275 return;
278 sServiceName = "com.sun.star.presentation.FooterShape";
279 bClearText = true;
280 break;
281 case XML_sldNum :
282 if (IsPlaceHolderCandidate(rSlidePersist))
284 TextRunPtr& pTextRun
285 = getTextBody()->getParagraphs().front()->getRuns().front();
286 oox::drawingml::TextField* pTextField
287 = dynamic_cast<oox::drawingml::TextField*>(pTextRun.get());
288 if (pTextField && pTextField->getType() == "slidenum")
290 // if it is possible to get the slidenum placeholder as a property
291 // do that and discard the shape
292 Reference<XPropertySet> xPropertySet(rSlidePersist.getPage(),
293 UNO_QUERY);
294 xPropertySet->setPropertyValue("IsPageNumberVisible", Any(true));
295 return;
298 sServiceName = "com.sun.star.presentation.SlideNumberShape";
299 bClearText = true;
300 break;
301 case XML_sldImg :
302 sServiceName = "com.sun.star.presentation.PageShape";
303 break;
304 case XML_chart :
305 if (meShapeLocation == Layout)
306 sServiceName = sOutlinerShapeService;
307 else
308 sServiceName = "com.sun.star.presentation.ChartShape";
309 break;
310 case XML_tbl :
311 if (meShapeLocation == Layout)
312 sServiceName = sOutlinerShapeService;
313 else
314 sServiceName = "com.sun.star.presentation.TableShape";
315 break;
316 case XML_pic :
317 if (meShapeLocation == Layout)
318 sServiceName = sOutlinerShapeService;
319 else
320 sServiceName = "com.sun.star.presentation.GraphicObjectShape";
321 break;
322 case XML_media :
323 if (meShapeLocation == Layout)
324 sServiceName = sOutlinerShapeService;
325 else
326 sServiceName = "com.sun.star.presentation.MediaShape";
327 break;
328 default:
329 if (mnSubType && meShapeLocation == Layout)
330 sServiceName = sOutlinerShapeService;
331 break;
335 // Since it is not possible to represent custom shaped placeholders in Impress
336 // Need to use service name css.drawing.CustomShape if they have a non default shape.
337 // This workaround has the drawback of them not really being processed as placeholders
338 // so it is only done for slide footers...
339 bool convertInSlideMode = meShapeLocation == Slide &&
340 (mnSubType == XML_sldNum || mnSubType == XML_dt || mnSubType == XML_ftr || mnSubType == XML_body);
341 bool convertInLayoutMode = meShapeLocation == Layout && (mnSubType == XML_body);
342 if ((convertInSlideMode || convertInLayoutMode) && !mpCustomShapePropertiesPtr->representsDefaultShape())
344 sServiceName = "com.sun.star.drawing.CustomShape";
347 SAL_INFO("oox.ppt","shape service: " << sServiceName);
349 if (mnSubType && getSubTypeIndex().has_value() && meShapeLocation == Layout)
351 oox::drawingml::ShapePtr pPlaceholder = PPTShape::findPlaceholderByIndex( getSubTypeIndex().value(), rSlidePersist.getShapes()->getChildren(), true );
352 if (!pPlaceholder)
353 pPlaceholder = PPTShape::findPlaceholder( mnSubType, 0, getSubTypeIndex(), rSlidePersist.getShapes()->getChildren(), true );
355 if (pPlaceholder) {
356 if (maSize.Width == 0 || maSize.Height == 0) {
357 awt::Size aSize = maSize;
358 if (maSize.Width == 0)
359 aSize.Width = pPlaceholder->getSize().Width;
360 if (maSize.Height == 0)
361 aSize.Height = pPlaceholder->getSize().Height;
362 setSize( aSize );
363 if (maPosition.X == 0 || maPosition.Y == 0) {
364 awt::Point aPosition = maPosition;
365 if (maPosition.X == 0)
366 aPosition.X = pPlaceholder->getPosition().X;
367 if (maPosition.Y == 0)
368 aPosition.Y = pPlaceholder->getPosition().Y;
369 setPosition( aPosition );
375 // use placeholder index if possible
376 if (mnSubType && getSubTypeIndex().has_value() && rSlidePersist.getMasterPersist())
378 oox::drawingml::ShapePtr pPlaceholder = PPTShape::findPlaceholderByIndex(getSubTypeIndex().value(), rSlidePersist.getMasterPersist()->getShapes()->getChildren());
379 // TODO: Check if this is required for non-notes slides as well...
380 if (rSlidePersist.isNotesPage() && pPlaceholder && pPlaceholder->getSubType() != getSubType())
381 pPlaceholder.reset();
383 if (pPlaceholder) {
384 SAL_INFO("oox.ppt","found placeholder with index: " << getSubTypeIndex().value() << " and type: " << lclDebugSubType( mnSubType ));
385 PPTShape* pPPTPlaceholder = dynamic_cast< PPTShape* >( pPlaceholder.get() );
386 TextListStylePtr pNewTextListStyle = std::make_shared<TextListStyle>();
388 if (pPlaceholder->getTextBody()) {
390 pNewTextListStyle->apply( pPlaceholder->getTextBody()->getTextListStyle() );
391 if (pPlaceholder->getMasterTextListStyle())
392 pNewTextListStyle->apply( *pPlaceholder->getMasterTextListStyle() );
394 // SAL_INFO("oox.ppt","placeholder body style");
395 // pPlaceholder->getTextBody()->getTextListStyle().dump();
396 // SAL_INFO("oox.ppt","master text list style");
397 // pPlaceholder->getMasterTextListStyle()->dump();
399 aMasterTextListStyle = pNewTextListStyle;
400 // SAL_INFO("oox.ppt","combined master text list style");
401 // aMasterTextListStyle->dump();
403 if (pPPTPlaceholder && pPPTPlaceholder->mpPlaceholder) {
404 SAL_INFO("oox.ppt","placeholder has parent placeholder: " << pPPTPlaceholder->mpPlaceholder->getId() << " type: " << lclDebugSubType( pPPTPlaceholder->mpPlaceholder->getSubType() ) << " index: " << pPPTPlaceholder->mpPlaceholder->getSubTypeIndex().value() );
405 SAL_INFO("oox.ppt","has textbody " << (pPPTPlaceholder->mpPlaceholder->getTextBody() != nullptr) );
406 TextListStylePtr pPlaceholderStyle = getSubTypeTextListStyle( rSlidePersist, pPPTPlaceholder->mpPlaceholder->getSubType() );
407 if (pPPTPlaceholder->mpPlaceholder->getTextBody())
408 pNewTextListStyle->apply( pPPTPlaceholder->mpPlaceholder->getTextBody()->getTextListStyle() );
409 if (pPlaceholderStyle) {
410 pNewTextListStyle->apply( *pPlaceholderStyle );
411 //pPlaceholderStyle->dump();
414 } else if (!mpPlaceholder) {
415 aMasterTextListStyle.reset();
417 SAL_INFO("oox.ppt","placeholder id: " << (pPlaceholder ? pPlaceholder->getId() : "not found"));
420 if (!sServiceName.isEmpty())
422 if (!aMasterTextListStyle)
424 bool isOther = !getTextBody() && sServiceName != "com.sun.star.drawing.GroupShape";
425 TextListStylePtr aSlideStyle = isOther ? rSlidePersist.getOtherTextStyle() : rSlidePersist.getDefaultTextStyle();
426 // Combine from MasterSlide details as well.
427 if (rSlidePersist.getMasterPersist())
429 aMasterTextListStyle = isOther ? rSlidePersist.getMasterPersist()->getOtherTextStyle() : rSlidePersist.getMasterPersist()->getDefaultTextStyle();
430 if (aSlideStyle)
431 aMasterTextListStyle->apply( *aSlideStyle );
433 else
435 aMasterTextListStyle = aSlideStyle;
439 if( aMasterTextListStyle && getTextBody() ) {
440 TextListStylePtr aCombinedTextListStyle = std::make_shared<TextListStyle>();
442 aCombinedTextListStyle->apply( *aMasterTextListStyle );
444 if( mpPlaceholder && mpPlaceholder->getTextBody() )
445 aCombinedTextListStyle->apply( mpPlaceholder->getTextBody()->getTextListStyle() );
446 aCombinedTextListStyle->apply( getTextBody()->getTextListStyle() );
448 setMasterTextListStyle( aCombinedTextListStyle );
449 } else
450 setMasterTextListStyle( aMasterTextListStyle );
452 Reference< XShape > xShape( createAndInsert( rFilterBase, sServiceName, pTheme, rxShapes, bClearText, bool(mpPlaceholder), aTransformation, getFillProperties() ) );
454 // Apply text properties on placeholder text inside this placeholder shape
455 if (meShapeLocation == Slide && mpPlaceholder && getTextBody() && getTextBody()->isEmpty())
457 Reference < XText > xText(mxShape, UNO_QUERY);
458 if (xText.is())
460 TextCharacterProperties aCharStyleProperties;
461 getTextBody()->ApplyStyleEmpty(rFilterBase, xText, aCharStyleProperties, mpMasterTextListStyle);
464 if (pShapeMap)
466 // bnc#705982 - if optional model id reference is
467 // there, use that to obtain target shape
468 if (!msModelId.isEmpty())
470 (*pShapeMap)[ msModelId ] = shared_from_this();
472 else if (!msId.isEmpty())
474 (*pShapeMap)[ msId ] = shared_from_this();
478 // we will be losing whatever information there is in the footer placeholder on master/layout slides
479 // since they should have the "<footer>" textfield in them in order to make LibreOffice process them as expected
480 // likewise DateTime placeholder data on master/layout slides will be lost and replaced
481 if( (mnSubType == XML_ftr || mnSubType == XML_dt) && meShapeLocation != Slide )
483 OUString aFieldType;
484 if( mnSubType == XML_ftr )
485 aFieldType = "com.sun.star.presentation.TextField.Footer";
486 else
487 aFieldType = "com.sun.star.presentation.TextField.DateTime";
488 Reference < XTextField > xField( xServiceFact->createInstance( aFieldType ), UNO_QUERY );
489 Reference < XText > xText(mxShape, UNO_QUERY);
490 if(xText.is())
492 xText->setString("");
493 Reference < XTextCursor > xTextCursor = xText->createTextCursor();
494 xText->insertTextContent( xTextCursor, xField, false);
498 OUString sURL;
499 std::vector<std::pair<OUString, Reference<XShape>>> aURLShapes;
500 // if this is a group shape, we have to add also each child shape
501 Reference<XShapes> xShapes(xShape, UNO_QUERY);
502 if (xShapes.is())
504 // temporarily remember setting
505 NamedShapePairs* pDiagramFontHeights(rFilterBase.getDiagramFontHeights());
507 // for shapes unequal to FRAMETYPE_DIAGRAM do
508 // disable DiagramFontHeights recording
509 if (meFrameType != FRAMETYPE_DIAGRAM)
510 rFilterBase.setDiagramFontHeights(nullptr);
512 addChildren( rFilterBase, *this, pTheme, xShapes, pShapeMap, aTransformation );
514 // restore remembered setting
515 rFilterBase.setDiagramFontHeights(pDiagramFontHeights);
517 for (size_t i = 0; i < this->getChildren().size(); i++)
519 this->getChildren()[i]->getShapeProperties().getProperty(PROP_URL) >>= sURL;
520 if (!sURL.isEmpty())
522 Reference<XShape> xChild = this->getChildren()[i]->getXShape();
523 aURLShapes.push_back({ sURL, xChild });
528 if (meFrameType == FRAMETYPE_DIAGRAM)
530 keepDiagramCompatibilityInfo();
533 // Support advanced DiagramHelper
534 if (FRAMETYPE_DIAGRAM == meFrameType)
536 propagateDiagramHelper();
539 getShapeProperties().getProperty(PROP_URL) >>= sURL;
540 if (!sURL.isEmpty() && !xShapes.is())
541 aURLShapes.push_back({ sURL, xShape });
543 if (!aURLShapes.empty())
545 for (auto const& URLShape : aURLShapes)
547 Reference<XEventsSupplier> xEventsSupplier(URLShape.second, UNO_QUERY);
548 if (!xEventsSupplier.is())
549 return;
551 Reference<XNameReplace> xEvents(xEventsSupplier->getEvents());
552 if (!xEvents.is())
553 return;
555 OUString sAPIEventName;
556 sal_Int32 nPropertyCount = 2;
557 css::presentation::ClickAction meClickAction;
558 uno::Sequence<beans::PropertyValue> aProperties;
560 std::map<OUString, css::presentation::ClickAction> ActionMap = {
561 { "#action?jump=nextslide", ClickAction_NEXTPAGE },
562 { "#action?jump=previousslide", ClickAction_PREVPAGE },
563 { "#action?jump=firstslide", ClickAction_FIRSTPAGE },
564 { "#action?jump=lastslide", ClickAction_LASTPAGE },
565 { "#action?jump=endshow", ClickAction_STOPPRESENTATION },
568 sURL = URLShape.first;
569 std::map<OUString, css::presentation::ClickAction>::const_iterator aIt
570 = ActionMap.find(sURL);
571 aIt != ActionMap.end() ? meClickAction = aIt->second
572 : meClickAction = ClickAction_BOOKMARK;
574 // ClickAction_BOOKMARK and ClickAction_DOCUMENT share the same event
575 // so check here if it's a bookmark or a document
576 if (meClickAction == ClickAction_BOOKMARK)
578 if (!sURL.startsWith("#"))
579 meClickAction = ClickAction_DOCUMENT;
580 else
582 sURL = OUString::Concat("page")
583 + sURL.subView(sURL.lastIndexOf(' ') + 1);
585 nPropertyCount += 1;
588 aProperties.realloc(nPropertyCount);
589 beans::PropertyValue* pProperties = aProperties.getArray();
591 pProperties->Name = "EventType";
592 pProperties->Handle = -1;
593 pProperties->Value <<= OUString("Presentation");
594 pProperties->State = beans::PropertyState_DIRECT_VALUE;
595 pProperties++;
597 pProperties->Name = "ClickAction";
598 pProperties->Handle = -1;
599 pProperties->Value <<= meClickAction;
600 pProperties->State = beans::PropertyState_DIRECT_VALUE;
601 pProperties++;
603 switch (meClickAction)
605 case ClickAction_BOOKMARK:
606 case ClickAction_DOCUMENT:
607 pProperties->Name = "Bookmark";
608 pProperties->Handle = -1;
609 pProperties->Value <<= sURL;
610 pProperties->State = beans::PropertyState_DIRECT_VALUE;
611 break;
612 default:
613 break;
616 sAPIEventName = "OnClick";
617 xEvents->replaceByName(sAPIEventName, uno::Any(aProperties));
622 catch (const Exception&)
627 namespace
629 bool ShapeLocationIsMaster(oox::drawingml::Shape *pInShape)
631 PPTShape* pShape = dynamic_cast<PPTShape*>(pInShape);
632 return pShape && pShape->getShapeLocation() == Master;
636 // Function to find placeholder (ph) for a shape. No idea how MSO implements this, but
637 // this order seems to work quite well
638 // (probably it's unnecessary complicated / wrong. i.e. tdf#104202):
639 // 1. ph with nFirstSubType and the same oSubTypeIndex
640 // 2. ph with nFirstSubType
641 // 3. ph with nSecondSubType and the same oSubTypeIndex
642 // 4. ph with nSecondSubType
643 // 5. ph with the same oSubTypeIndex
645 oox::drawingml::ShapePtr PPTShape::findPlaceholder( sal_Int32 nFirstSubType, sal_Int32 nSecondSubType,
646 const std::optional< sal_Int32 >& oSubTypeIndex, std::vector< oox::drawingml::ShapePtr >& rShapes, bool bMasterOnly )
648 class Placeholders
650 public:
651 Placeholders()
652 : aChoice(5) // resize to 5
656 void add(const oox::drawingml::ShapePtr& aShape, sal_Int32 nFirstSubType, sal_Int32 nSecondSubType, const std::optional< sal_Int32 >& oSubTypeIndex)
658 if (!aShape)
659 return;
661 // get flags
662 const bool bSameFirstSubType = aShape->getSubType() == nFirstSubType;
663 const bool bSameSecondSubType = aShape->getSubType() == nSecondSubType;
664 const bool bSameIndex = aShape->getSubTypeIndex() == oSubTypeIndex;
666 // get prio
667 int aPrioIndex = -1;
668 if (bSameIndex && bSameFirstSubType)
669 aPrioIndex = 0;
670 else if (!bSameIndex && bSameFirstSubType)
671 aPrioIndex = 1;
672 else if (bSameIndex && bSameSecondSubType)
673 aPrioIndex = 2;
674 else if (!bSameIndex && bSameSecondSubType)
675 aPrioIndex = 3;
676 else if (bSameIndex)
677 aPrioIndex = 4;
679 // add
680 if (aPrioIndex != -1)
682 if (!aChoice.at(aPrioIndex))
684 aChoice.at(aPrioIndex) = aShape;
689 // return according to prio
690 oox::drawingml::ShapePtr getByPrio() const
692 for (const oox::drawingml::ShapePtr& aShape : aChoice)
694 if (aShape)
696 return aShape;
700 return oox::drawingml::ShapePtr();
703 bool hasByPrio(size_t aIndex) const
705 return bool(aChoice.at(aIndex));
708 private:
709 std::vector< oox::drawingml::ShapePtr > aChoice;
711 } aPlaceholders;
713 // check all shapes
714 std::vector< oox::drawingml::ShapePtr >::reverse_iterator aRevIter( rShapes.rbegin() );
715 for (; aRevIter != rShapes.rend(); ++aRevIter)
717 // check shape
718 if (!bMasterOnly || ShapeLocationIsMaster((*aRevIter).get()))
720 const oox::drawingml::ShapePtr& aShape = *aRevIter;
721 aPlaceholders.add(aShape, nFirstSubType, nSecondSubType, oSubTypeIndex);
724 // check children
725 std::vector< oox::drawingml::ShapePtr >& rChildren = (*aRevIter)->getChildren();
726 if (!rChildren.empty())
728 const oox::drawingml::ShapePtr aShape = findPlaceholder( nFirstSubType, nSecondSubType, oSubTypeIndex, rChildren, bMasterOnly );
729 if (aShape)
731 aPlaceholders.add(aShape, nFirstSubType, nSecondSubType, oSubTypeIndex);
735 if (aPlaceholders.hasByPrio(0))
737 break;
741 // return something according to prio
742 return aPlaceholders.getByPrio();
745 oox::drawingml::ShapePtr PPTShape::findPlaceholderByIndex( const sal_Int32 nIdx, std::vector< oox::drawingml::ShapePtr >& rShapes, bool bMasterOnly )
747 oox::drawingml::ShapePtr aShapePtr;
749 std::vector< oox::drawingml::ShapePtr >::reverse_iterator aRevIter( rShapes.rbegin() );
750 while( aRevIter != rShapes.rend() )
752 if ( (*aRevIter)->getSubTypeIndex().has_value() && (*aRevIter)->getSubTypeIndex().value() == nIdx &&
753 ( !bMasterOnly || ShapeLocationIsMaster((*aRevIter).get()) ) )
755 aShapePtr = *aRevIter;
756 break;
758 std::vector< oox::drawingml::ShapePtr >& rChildren = (*aRevIter)->getChildren();
759 aShapePtr = findPlaceholderByIndex( nIdx, rChildren, bMasterOnly );
760 if ( aShapePtr )
761 break;
762 ++aRevIter;
764 return aShapePtr;
769 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */