LibreOffice Module oox (master) 1
pptshape.cxx
Go to the documentation of this file.
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>
26#include <editeng/flditem.hxx>
27
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>
41#include <sal/log.hxx>
43#include <oox/token/tokens.hxx>
44#include <oox/token/properties.hxx>
45#include <o3tl/string_view.hxx>
46
47using namespace ::oox::core;
48using namespace ::oox::drawingml;
49using namespace ::com::sun::star;
50using namespace ::com::sun::star::awt;
51using namespace ::com::sun::star::uno;
52using namespace ::com::sun::star::beans;
53using namespace ::com::sun::star::text;
54using namespace ::com::sun::star::drawing;
55using namespace ::com::sun::star::document;
56using namespace ::com::sun::star::container;
57using namespace ::com::sun::star::presentation;
58
59namespace oox::ppt {
60
61PPTShape::PPTShape( const oox::ppt::ShapeLocation eShapeLocation, const char* pServiceName )
62: Shape( pServiceName )
63, meShapeLocation( eShapeLocation )
64, mbReferenced( false )
65, mbHasNoninheritedShapeProperties( false )
66{
67}
68
70{
71}
72
73static const char* lclDebugSubType( sal_Int32 nType )
74{
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";
96 }
97
98 return "unknown - please extend lclDebugSubType";
99}
100
101namespace
102{
103bool ShapeHasNoVisualPropertiesOnImport(const oox::ppt::PPTShape& rPPTShape)
104{
105 return !rPPTShape.hasNonInheritedShapeProperties()
106 && !rPPTShape.hasShapeStyleRefs()
107 && !rPPTShape.getTextBody()->hasVisualRunProperties()
108 && !rPPTShape.getTextBody()->hasNoninheritedBodyProperties()
109 && !rPPTShape.getTextBody()->hasListStyleOnImport()
110 && !rPPTShape.getTextBody()->hasParagraphProperties();
111}
112}
113
115{
117
118 SAL_INFO("oox.ppt", "subtype style: " << lclDebugSubType( nSubType ) );
119
120 switch( nSubType )
121 {
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;
134 }
135
136 return pTextListStyle;
137}
138
139bool PPTShape::IsPlaceHolderCandidate(const SlidePersist& rSlidePersist) const
140{
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);
158}
159
161 oox::core::XmlFilterBase& rFilterBase,
162 const SlidePersist& rSlidePersist,
163 const oox::drawingml::Theme* pTheme,
164 const Reference< XShapes >& rxShapes,
165 basegfx::B2DHomMatrix& aTransformation,
167{
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;
172
173 OUString sServiceName( msServiceName );
174 if (sServiceName.isEmpty())
175 return;
176 try
177 {
178 oox::drawingml::TextListStylePtr aMasterTextListStyle;
179 Reference<lang::XMultiServiceFactory> xServiceFact(rFilterBase.getModel(), UNO_QUERY_THROW);
180 bool bClearText = false;
181
182 if (sServiceName != "com.sun.star.drawing.GraphicObjectShape" &&
183 sServiceName != "com.sun.star.drawing.OLE2Shape")
184 {
185 static const OUStringLiteral sOutlinerShapeService(u"com.sun.star.presentation.OutlinerShape");
186 SAL_INFO("oox.ppt","has master: " << std::hex << rSlidePersist.getMasterPersist().get());
187 switch (mnSubType)
188 {
189 case XML_ctrTitle :
190 case XML_title :
191 {
192 sServiceName = "com.sun.star.presentation.TitleTextShape";
193 aMasterTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getTitleTextStyle() : rSlidePersist.getTitleTextStyle();
194 }
195 break;
196 case XML_subTitle :
197 {
199 sServiceName = OUString();
200 else {
201 sServiceName = "com.sun.star.presentation.SubtitleShape";
202 aMasterTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getBodyTextStyle() : rSlidePersist.getBodyTextStyle();
203 }
204 }
205 break;
206 case XML_obj :
207 {
208 sServiceName = sOutlinerShapeService;
209 aMasterTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getBodyTextStyle() : rSlidePersist.getBodyTextStyle();
210 }
211 break;
212 case XML_body :
213 {
214 if (rSlidePersist.isNotesPage())
215 {
216 sServiceName = "com.sun.star.presentation.NotesShape";
217 aMasterTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getNotesTextStyle() : rSlidePersist.getNotesTextStyle();
218 }
219 else
220 {
221 sServiceName = sOutlinerShapeService;
222 aMasterTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getBodyTextStyle() : rSlidePersist.getBodyTextStyle();
223 }
224 }
225 break;
226 case XML_dt :
227 if (IsPlaceHolderCandidate(rSlidePersist))
228 {
229 TextRunPtr& pTextRun = getTextBody()->getParagraphs().front()->getRuns().front();
230 oox::drawingml::TextField* pTextField = dynamic_cast<oox::drawingml::TextField*>(pTextRun.get());
231 if (pTextField)
232 {
233 OUString aType = pTextField->getType();
234 if ( aType.startsWith("datetime") )
235 {
238 Reference< XPropertySet > xPropertySet( rSlidePersist.getPage(), UNO_QUERY );
239
240 if( eDateFormat != SvxDateFormat::AppDefault
241 || eTimeFormat != SvxTimeFormat::AppDefault )
242 {
243 // DateTimeFormat property looks for the date in 4 LSBs
244 // and looks for time format in the 4 bits after that
245 sal_Int32 nDateTimeFormat = static_cast<sal_Int32>(eDateFormat) |
246 static_cast<sal_Int32>(eTimeFormat) << 4;
247 xPropertySet->setPropertyValue( "IsDateTimeVisible", Any(true) );
248 xPropertySet->setPropertyValue( "IsDateTimeFixed", Any(false) );
249 xPropertySet->setPropertyValue( "DateTimeFormat", Any(nDateTimeFormat) );
250 return;
251 }
252 }
253 }
254 }
255 sServiceName = "com.sun.star.presentation.DateTimeShape";
256 bClearText = true;
257 break;
258 case XML_hdr :
259 sServiceName = "com.sun.star.presentation.HeaderShape";
260 bClearText = true;
261 break;
262 case XML_ftr :
263 if (IsPlaceHolderCandidate(rSlidePersist))
264 {
265 const OUString& rFooterText = getTextBody()->toString();
266
267 if( !rFooterText.isEmpty() )
268 {
269 // if it is possible to get the footer as a property the LO way,
270 // get it and discard the shape
271 Reference< XPropertySet > xPropertySet( rSlidePersist.getPage(), UNO_QUERY );
272 xPropertySet->setPropertyValue( "IsFooterVisible", Any( true ) );
273 xPropertySet->setPropertyValue( "FooterText", Any(rFooterText) );
274 return;
275 }
276 }
277 sServiceName = "com.sun.star.presentation.FooterShape";
278 bClearText = true;
279 break;
280 case XML_sldNum :
281 if (IsPlaceHolderCandidate(rSlidePersist))
282 {
283 TextRunPtr& pTextRun
284 = getTextBody()->getParagraphs().front()->getRuns().front();
285 oox::drawingml::TextField* pTextField
286 = dynamic_cast<oox::drawingml::TextField*>(pTextRun.get());
287 if (pTextField && pTextField->getType() == "slidenum")
288 {
289 // if it is possible to get the slidenum placeholder as a property
290 // do that and discard the shape
291 Reference<XPropertySet> xPropertySet(rSlidePersist.getPage(),
292 UNO_QUERY);
293 xPropertySet->setPropertyValue("IsPageNumberVisible", Any(true));
294 return;
295 }
296 }
297 sServiceName = "com.sun.star.presentation.SlideNumberShape";
298 bClearText = true;
299 break;
300 case XML_sldImg :
301 sServiceName = "com.sun.star.presentation.PageShape";
302 break;
303 case XML_chart :
304 if (meShapeLocation == Layout)
305 sServiceName = sOutlinerShapeService;
306 else
307 sServiceName = "com.sun.star.presentation.ChartShape";
308 break;
309 case XML_tbl :
310 if (meShapeLocation == Layout)
311 sServiceName = sOutlinerShapeService;
312 else
313 sServiceName = "com.sun.star.presentation.TableShape";
314 break;
315 case XML_pic :
316 if (meShapeLocation == Layout)
317 sServiceName = sOutlinerShapeService;
318 else
319 sServiceName = "com.sun.star.presentation.GraphicObjectShape";
320 break;
321 case XML_media :
322 if (meShapeLocation == Layout)
323 sServiceName = sOutlinerShapeService;
324 else
325 sServiceName = "com.sun.star.presentation.MediaShape";
326 break;
327 default:
329 sServiceName = sOutlinerShapeService;
330 break;
331 }
332 }
333
334 // Since it is not possible to represent custom shaped placeholders in Impress
335 // Need to use service name css.drawing.CustomShape if they have a non default shape.
336 // This workaround has the drawback of them not really being processed as placeholders
337 // so it is only done for slide footers...
338 if ((mnSubType == XML_sldNum || mnSubType == XML_dt || mnSubType == XML_ftr)
339 && meShapeLocation == Slide && !mpCustomShapePropertiesPtr->representsDefaultShape())
340 {
341 sServiceName = "com.sun.star.drawing.CustomShape";
342 }
343
344 SAL_INFO("oox.ppt","shape service: " << sServiceName);
345
346 if (mnSubType && getSubTypeIndex().has_value() && meShapeLocation == Layout)
347 {
348 oox::drawingml::ShapePtr pPlaceholder = PPTShape::findPlaceholderByIndex( getSubTypeIndex().value(), rSlidePersist.getShapes()->getChildren(), true );
349 if (!pPlaceholder)
350 pPlaceholder = PPTShape::findPlaceholder( mnSubType, 0, getSubTypeIndex(), rSlidePersist.getShapes()->getChildren(), true );
351
352 if (pPlaceholder) {
353 if (maSize.Width == 0 || maSize.Height == 0) {
354 awt::Size aSize = maSize;
355 if (maSize.Width == 0)
356 aSize.Width = pPlaceholder->getSize().Width;
357 if (maSize.Height == 0)
358 aSize.Height = pPlaceholder->getSize().Height;
359 setSize( aSize );
360 if (maPosition.X == 0 || maPosition.Y == 0) {
361 awt::Point aPosition = maPosition;
362 if (maPosition.X == 0)
363 aPosition.X = pPlaceholder->getPosition().X;
364 if (maPosition.Y == 0)
365 aPosition.Y = pPlaceholder->getPosition().Y;
366 setPosition( aPosition );
367 }
368 }
369 }
370 }
371
372 // use placeholder index if possible
373 if (mnSubType && getSubTypeIndex().has_value() && rSlidePersist.getMasterPersist())
374 {
375 oox::drawingml::ShapePtr pPlaceholder = PPTShape::findPlaceholderByIndex(getSubTypeIndex().value(), rSlidePersist.getMasterPersist()->getShapes()->getChildren());
376 // TODO: Check if this is required for non-notes slides as well...
377 if (rSlidePersist.isNotesPage() && pPlaceholder && pPlaceholder->getSubType() != getSubType())
378 pPlaceholder.reset();
379
380 if (pPlaceholder) {
381 SAL_INFO("oox.ppt","found placeholder with index: " << getSubTypeIndex().value() << " and type: " << lclDebugSubType( mnSubType ));
382 PPTShape* pPPTPlaceholder = dynamic_cast< PPTShape* >( pPlaceholder.get() );
383 TextListStylePtr pNewTextListStyle = std::make_shared<TextListStyle>();
384
385 if (pPlaceholder->getTextBody()) {
386
387 pNewTextListStyle->apply( pPlaceholder->getTextBody()->getTextListStyle() );
388 if (pPlaceholder->getMasterTextListStyle())
389 pNewTextListStyle->apply( *pPlaceholder->getMasterTextListStyle() );
390
391 // SAL_INFO("oox.ppt","placeholder body style");
392 // pPlaceholder->getTextBody()->getTextListStyle().dump();
393 // SAL_INFO("oox.ppt","master text list style");
394 // pPlaceholder->getMasterTextListStyle()->dump();
395
396 aMasterTextListStyle = pNewTextListStyle;
397 // SAL_INFO("oox.ppt","combined master text list style");
398 // aMasterTextListStyle->dump();
399 }
400 if (pPPTPlaceholder && pPPTPlaceholder->mpPlaceholder) {
401 SAL_INFO("oox.ppt","placeholder has parent placeholder: " << pPPTPlaceholder->mpPlaceholder->getId() << " type: " << lclDebugSubType( pPPTPlaceholder->mpPlaceholder->getSubType() ) << " index: " << pPPTPlaceholder->mpPlaceholder->getSubTypeIndex().value() );
402 SAL_INFO("oox.ppt","has textbody " << (pPPTPlaceholder->mpPlaceholder->getTextBody() != nullptr) );
403 TextListStylePtr pPlaceholderStyle = getSubTypeTextListStyle( rSlidePersist, pPPTPlaceholder->mpPlaceholder->getSubType() );
404 if (pPPTPlaceholder->mpPlaceholder->getTextBody())
405 pNewTextListStyle->apply( pPPTPlaceholder->mpPlaceholder->getTextBody()->getTextListStyle() );
406 if (pPlaceholderStyle) {
407 pNewTextListStyle->apply( *pPlaceholderStyle );
408 //pPlaceholderStyle->dump();
409 }
410 }
411 } else if (!mpPlaceholder) {
412 aMasterTextListStyle.reset();
413 }
414 SAL_INFO("oox.ppt","placeholder id: " << (pPlaceholder ? pPlaceholder->getId() : "not found"));
415 }
416
417 if (!sServiceName.isEmpty())
418 {
419 if (!aMasterTextListStyle)
420 {
421 bool isOther = !getTextBody() && sServiceName != "com.sun.star.drawing.GroupShape";
422 TextListStylePtr aSlideStyle = isOther ? rSlidePersist.getOtherTextStyle() : rSlidePersist.getDefaultTextStyle();
423 // Combine from MasterSlide details as well.
424 if (rSlidePersist.getMasterPersist())
425 {
426 aMasterTextListStyle = isOther ? rSlidePersist.getMasterPersist()->getOtherTextStyle() : rSlidePersist.getMasterPersist()->getDefaultTextStyle();
427 if (aSlideStyle)
428 aMasterTextListStyle->apply( *aSlideStyle );
429 }
430 else
431 {
432 aMasterTextListStyle = aSlideStyle;
433 }
434 }
435
436 if( aMasterTextListStyle && getTextBody() ) {
437 TextListStylePtr aCombinedTextListStyle = std::make_shared<TextListStyle>();
438
439 aCombinedTextListStyle->apply( *aMasterTextListStyle );
440
441 if( mpPlaceholder && mpPlaceholder->getTextBody() )
442 aCombinedTextListStyle->apply( mpPlaceholder->getTextBody()->getTextListStyle() );
443 aCombinedTextListStyle->apply( getTextBody()->getTextListStyle() );
444
445 setMasterTextListStyle( aCombinedTextListStyle );
446 } else
447 setMasterTextListStyle( aMasterTextListStyle );
448
449 Reference< XShape > xShape( createAndInsert( rFilterBase, sServiceName, pTheme, rxShapes, bClearText, bool(mpPlaceholder), aTransformation, getFillProperties() ) );
450 // if exists and not duplicated, try to use the title text as slide name to help its re-use on UI
451 if (!rSlidePersist.isMasterPage() && rSlidePersist.getPage().is() && (mnSubType == XML_title || mnSubType == XML_ctrTitle))
452 {
453 try
454 {
455 sal_Int32 nCount = 1;
456 OUString aTitleText;
457 Reference<XTextRange> xText(xShape, UNO_QUERY_THROW);
458 aTitleText = xText->getString();
459 Reference<drawing::XDrawPagesSupplier> xDPS(rFilterBase.getModel(), uno::UNO_QUERY_THROW);
460 Reference<drawing::XDrawPages> xDrawPages(xDPS->getDrawPages(), uno::UNO_SET_THROW);
461 sal_uInt32 nMaxPages = xDrawPages->getCount();
462 // just a magic value but we don't want to drop out slide names which are too long
463 if (aTitleText.getLength() > 63)
464 aTitleText = aTitleText.copy(0, 63);
465 bool bUseTitleAsSlideName = !aTitleText.isEmpty();
466 // check duplicated title name
467 if (bUseTitleAsSlideName)
468 {
469 for (sal_uInt32 nPage = 0; nPage < nMaxPages; ++nPage)
470 {
471 Reference<XDrawPage> xDrawPage(xDrawPages->getByIndex(nPage), uno::UNO_QUERY);
472 Reference<container::XNamed> xNamed(xDrawPage, UNO_QUERY_THROW);
473 OUString sRest;
474 if (xNamed->getName().startsWith(aTitleText, &sRest)
475 && (sRest.isEmpty()
476 || (sRest.startsWith(" (") && sRest.endsWith(")")
477 && o3tl::toInt32(sRest.subView(2, sRest.getLength() - 3)) > 0)))
478 nCount++;
479 }
480 Reference<container::XNamed> xName(rSlidePersist.getPage(), UNO_QUERY_THROW);
481 xName->setName(
482 aTitleText
483 + (nCount == 1 ? OUString("") : " (" + OUString::number(nCount) + ")"));
484 }
485 }
486 catch (uno::Exception&)
487 {
488
489 }
490 }
491
492 // Apply text properties on placeholder text inside this placeholder shape
493 if (meShapeLocation == Slide && mpPlaceholder && getTextBody() && getTextBody()->isEmpty())
494 {
495 Reference < XText > xText(mxShape, UNO_QUERY);
496 if (xText.is())
497 {
498 TextCharacterProperties aCharStyleProperties;
499 getTextBody()->ApplyStyleEmpty(rFilterBase, xText, aCharStyleProperties, mpMasterTextListStyle);
500 }
501 }
502 if (pShapeMap)
503 {
504 // bnc#705982 - if optional model id reference is
505 // there, use that to obtain target shape
506 if (!msModelId.isEmpty())
507 {
508 (*pShapeMap)[ msModelId ] = shared_from_this();
509 }
510 else if (!msId.isEmpty())
511 {
512 (*pShapeMap)[ msId ] = shared_from_this();
513 }
514 }
515
516 // we will be losing whatever information there is in the footer placeholder on master/layout slides
517 // since they should have the "<footer>" textfield in them in order to make LibreOffice process them as expected
518 // likewise DateTime placeholder data on master/layout slides will be lost and replaced
519 if( (mnSubType == XML_ftr || mnSubType == XML_dt) && meShapeLocation != Slide )
520 {
521 OUString aFieldType;
522 if( mnSubType == XML_ftr )
523 aFieldType = "com.sun.star.presentation.TextField.Footer";
524 else
525 aFieldType = "com.sun.star.presentation.TextField.DateTime";
526 Reference < XTextField > xField( xServiceFact->createInstance( aFieldType ), UNO_QUERY );
527 Reference < XText > xText(mxShape, UNO_QUERY);
528 if(xText.is())
529 {
530 xText->setString("");
531 Reference < XTextCursor > xTextCursor = xText->createTextCursor();
532 xText->insertTextContent( xTextCursor, xField, false);
533 }
534 }
535
536 OUString sURL;
537 std::vector<std::pair<OUString, Reference<XShape>>> aURLShapes;
538 // if this is a group shape, we have to add also each child shape
539 Reference<XShapes> xShapes(xShape, UNO_QUERY);
540 if (xShapes.is())
541 {
542 // temporarily remember setting
543 NamedShapePairs* pDiagramFontHeights(rFilterBase.getDiagramFontHeights());
544
545 // for shapes unequal to FRAMETYPE_DIAGRAM do
546 // disable DiagramFontHeights recording
548 rFilterBase.setDiagramFontHeights(nullptr);
549
550 addChildren( rFilterBase, *this, pTheme, xShapes, pShapeMap, aTransformation );
551
552 // restore remembered setting
553 rFilterBase.setDiagramFontHeights(pDiagramFontHeights);
554
555 for (size_t i = 0; i < this->getChildren().size(); i++)
556 {
557 this->getChildren()[i]->getShapeProperties().getProperty(PROP_URL) >>= sURL;
558 if (!sURL.isEmpty())
559 {
560 Reference<XShape> xChild = this->getChildren()[i]->getXShape();
561 aURLShapes.push_back({ sURL, xChild });
562 }
563 }
564 }
565
567 {
569 }
570
571 // Support advanced DiagramHelper
573 {
575 }
576
577 getShapeProperties().getProperty(PROP_URL) >>= sURL;
578 if (!sURL.isEmpty() && !xShapes.is())
579 aURLShapes.push_back({ sURL, xShape });
580
581 if (!aURLShapes.empty())
582 {
583 for (auto const& URLShape : aURLShapes)
584 {
585 Reference<XEventsSupplier> xEventsSupplier(URLShape.second, UNO_QUERY);
586 if (!xEventsSupplier.is())
587 return;
588
589 Reference<XNameReplace> xEvents(xEventsSupplier->getEvents());
590 if (!xEvents.is())
591 return;
592
593 OUString sAPIEventName;
594 sal_Int32 nPropertyCount = 2;
595 css::presentation::ClickAction meClickAction;
596 uno::Sequence<beans::PropertyValue> aProperties;
597
598 std::map<OUString, css::presentation::ClickAction> ActionMap = {
599 { "#action?jump=nextslide", ClickAction_NEXTPAGE },
600 { "#action?jump=previousslide", ClickAction_PREVPAGE },
601 { "#action?jump=firstslide", ClickAction_FIRSTPAGE },
602 { "#action?jump=lastslide", ClickAction_LASTPAGE },
603 { "#action?jump=endshow", ClickAction_STOPPRESENTATION },
604 };
605
606 sURL = URLShape.first;
607 std::map<OUString, css::presentation::ClickAction>::const_iterator aIt
608 = ActionMap.find(sURL);
609 aIt != ActionMap.end() ? meClickAction = aIt->second
610 : meClickAction = ClickAction_BOOKMARK;
611
612 // ClickAction_BOOKMARK and ClickAction_DOCUMENT share the same event
613 // so check here if it's a bookmark or a document
614 if (meClickAction == ClickAction_BOOKMARK)
615 {
616 sal_Int32 nSplitPos;
617 if (!sURL.startsWith("#"))
618 meClickAction = ClickAction_DOCUMENT;
619 else if (-1 != (nSplitPos = sURL.indexOf( ' ' )))
620 {
621 setBookmark(true);
622 // reuse slide number from '#Slide [Num]' or "#Notes [Num]"
623 sURL = OUString::Concat("#page") + sURL.subView(nSplitPos);
624 }
625 nPropertyCount += 1;
626 }
627
628 aProperties.realloc(nPropertyCount);
629 beans::PropertyValue* pProperties = aProperties.getArray();
630
631 pProperties->Name = "EventType";
632 pProperties->Handle = -1;
633 pProperties->Value <<= OUString("Presentation");
634 pProperties->State = beans::PropertyState_DIRECT_VALUE;
635 pProperties++;
636
637 pProperties->Name = "ClickAction";
638 pProperties->Handle = -1;
639 pProperties->Value <<= meClickAction;
640 pProperties->State = beans::PropertyState_DIRECT_VALUE;
641 pProperties++;
642
643 switch (meClickAction)
644 {
645 case ClickAction_BOOKMARK:
646 case ClickAction_DOCUMENT:
647 pProperties->Name = "Bookmark";
648 pProperties->Handle = -1;
649 pProperties->Value <<= sURL;
650 pProperties->State = beans::PropertyState_DIRECT_VALUE;
651 break;
652 default:
653 break;
654 }
655
656 sAPIEventName = "OnClick";
657 xEvents->replaceByName(sAPIEventName, uno::Any(aProperties));
658 }
659 }
660 }
661 }
662 catch (const Exception&)
663 {
664 }
665}
666
667namespace
668{
669 bool ShapeLocationIsMaster(oox::drawingml::Shape *pInShape)
670 {
671 PPTShape* pShape = dynamic_cast<PPTShape*>(pInShape);
672 return pShape && pShape->getShapeLocation() == Master;
673 }
674}
675
676// Function to find placeholder (ph) for a shape. No idea how MSO implements this, but
677// this order seems to work quite well
678// (probably it's unnecessary complicated / wrong. i.e. tdf#104202):
679// 1. ph with nFirstSubType and the same oSubTypeIndex
680// 2. ph with nFirstSubType
681// 3. ph with nSecondSubType and the same oSubTypeIndex
682// 4. ph with nSecondSubType
683// 5. ph with the same oSubTypeIndex
684
685oox::drawingml::ShapePtr PPTShape::findPlaceholder( sal_Int32 nFirstSubType, sal_Int32 nSecondSubType,
686 const std::optional< sal_Int32 >& oSubTypeIndex, std::vector< oox::drawingml::ShapePtr >& rShapes, bool bMasterOnly )
687{
688 class Placeholders
689 {
690 public:
691 Placeholders()
692 : aChoice(5) // resize to 5
693 {
694 }
695
696 void add(const oox::drawingml::ShapePtr& aShape, sal_Int32 nFirstSubType, sal_Int32 nSecondSubType, const std::optional< sal_Int32 >& oSubTypeIndex)
697 {
698 if (!aShape)
699 return;
700
701 // get flags
702 const bool bSameFirstSubType = aShape->getSubType() == nFirstSubType;
703 const bool bSameSecondSubType = aShape->getSubType() == nSecondSubType;
704 const bool bSameIndex = aShape->getSubTypeIndex() == oSubTypeIndex;
705
706 // get prio
707 int aPrioIndex = -1;
708 if (bSameIndex && bSameFirstSubType)
709 aPrioIndex = 0;
710 else if (!bSameIndex && bSameFirstSubType)
711 aPrioIndex = 1;
712 else if (bSameIndex && bSameSecondSubType)
713 aPrioIndex = 2;
714 else if (!bSameIndex && bSameSecondSubType)
715 aPrioIndex = 3;
716 else if (bSameIndex)
717 aPrioIndex = 4;
718
719 // add
720 if (aPrioIndex != -1)
721 {
722 if (!aChoice.at(aPrioIndex))
723 {
724 aChoice.at(aPrioIndex) = aShape;
725 }
726 }
727 }
728
729 // return according to prio
730 oox::drawingml::ShapePtr getByPrio() const
731 {
732 for (const oox::drawingml::ShapePtr& aShape : aChoice)
733 {
734 if (aShape)
735 {
736 return aShape;
737 }
738 }
739
741 }
742
743 bool hasByPrio(size_t aIndex) const
744 {
745 return bool(aChoice.at(aIndex));
746 }
747
748 private:
749 std::vector< oox::drawingml::ShapePtr > aChoice;
750
751 } aPlaceholders;
752
753 // check all shapes
754 std::vector< oox::drawingml::ShapePtr >::reverse_iterator aRevIter( rShapes.rbegin() );
755 for (; aRevIter != rShapes.rend(); ++aRevIter)
756 {
757 // check shape
758 if (!bMasterOnly || ShapeLocationIsMaster((*aRevIter).get()))
759 {
760 const oox::drawingml::ShapePtr& aShape = *aRevIter;
761 aPlaceholders.add(aShape, nFirstSubType, nSecondSubType, oSubTypeIndex);
762 }
763
764 // check children
765 std::vector< oox::drawingml::ShapePtr >& rChildren = (*aRevIter)->getChildren();
766 if (!rChildren.empty())
767 {
768 const oox::drawingml::ShapePtr aShape = findPlaceholder( nFirstSubType, nSecondSubType, oSubTypeIndex, rChildren, bMasterOnly );
769 if (aShape)
770 {
771 aPlaceholders.add(aShape, nFirstSubType, nSecondSubType, oSubTypeIndex);
772 }
773 }
774
775 if (aPlaceholders.hasByPrio(0))
776 {
777 break;
778 }
779 }
780
781 // return something according to prio
782 return aPlaceholders.getByPrio();
783}
784
785oox::drawingml::ShapePtr PPTShape::findPlaceholderByIndex( const sal_Int32 nIdx, std::vector< oox::drawingml::ShapePtr >& rShapes, bool bMasterOnly )
786{
787 oox::drawingml::ShapePtr aShapePtr;
788
789 std::vector< oox::drawingml::ShapePtr >::reverse_iterator aRevIter( rShapes.rbegin() );
790 while( aRevIter != rShapes.rend() )
791 {
792 if ( (*aRevIter)->getSubTypeIndex().has_value() && (*aRevIter)->getSubTypeIndex().value() == nIdx &&
793 ( !bMasterOnly || ShapeLocationIsMaster((*aRevIter).get()) ) )
794 {
795 aShapePtr = *aRevIter;
796 break;
797 }
798 std::vector< oox::drawingml::ShapePtr >& rChildren = (*aRevIter)->getChildren();
799 aShapePtr = findPlaceholderByIndex( nIdx, rChildren, bMasterOnly );
800 if ( aShapePtr )
801 break;
802 ++aRevIter;
803 }
804 return aShapePtr;
805}
806
807}
808
809/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
PropertiesInfo aProperties
constexpr OUStringLiteral sServiceName
css::uno::Any getProperty(sal_Int32 nPropId)
const css::uno::Reference< css::frame::XModel > & getModel() const
Returns the document model (always existing).
Definition: filterbase.cxx:220
void setDiagramFontHeights(NamedShapePairs *pDiagramFontHeights)
NamedShapePairs * getDiagramFontHeights()
FrameType meFrameType
Type for graphic frame shapes.
Definition: shape.hxx:365
PropertyMap & getShapeProperties()
Definition: shape.hxx:126
void setSize(css::awt::Size aSize)
Definition: shape.hxx:159
std::vector< ShapePtr > & getChildren()
Definition: shape.hxx:167
void propagateDiagramHelper()
Definition: shape.cxx:219
void setBookmark(bool bBookmark)
Definition: shape.hxx:143
const std::optional< sal_Int32 > & getSubTypeIndex() const
Definition: shape.hxx:182
void setMasterTextListStyle(const TextListStylePtr &pMasterTextListStyle)
Definition: shape.cxx:1982
@ FRAMETYPE_DIAGRAM
Complex diagram drawing shape.
Definition: shape.hxx:278
void addChildren(::oox::core::XmlFilterBase &rFilterBase, Shape &rMaster, const Theme *pTheme, const css::uno::Reference< css::drawing::XShapes > &rxShapes, ShapeIdMap *pShapeMap, const basegfx::B2DHomMatrix &aTransformation)
Definition: shape.cxx:510
sal_Int32 getSubType() const
Definition: shape.hxx:180
css::awt::Point maPosition
Definition: shape.hxx:361
TextListStylePtr mpMasterTextListStyle
Definition: shape.hxx:346
void keepDiagramCompatibilityInfo()
Definition: shape.cxx:1857
CustomShapePropertiesPtr mpCustomShapePropertiesPtr
Definition: shape.hxx:339
FillProperties & getFillProperties()
Definition: shape.hxx:131
css::awt::Size maSize
Definition: shape.hxx:360
void setPosition(css::awt::Point nPosition)
Definition: shape.hxx:156
sal_Int32 mnSubType
Definition: shape.hxx:355
const TextBodyPtr & getTextBody() const
Definition: shape.hxx:193
css::uno::Reference< css::drawing::XShape > const & createAndInsert(::oox::core::XmlFilterBase &rFilterBase, const OUString &rServiceName, const Theme *pTheme, const css::uno::Reference< css::drawing::XShapes > &rxShapes, bool bClearText, bool bDoNotInsertEmptyTextBody, basegfx::B2DHomMatrix &aTransformation, const FillProperties &rShapeOrParentShapeFillProps, oox::drawingml::ShapePtr pParentGroupShape=nullptr)
Definition: shape.cxx:793
css::uno::Reference< css::drawing::XShape > mxShape
Definition: shape.hxx:347
bool hasShapeStyleRefs() const
Definition: shape.hxx:200
OUString msServiceName
Definition: shape.hxx:350
static SvxDateFormat getLODateFormat(std::u16string_view rDateTimeType)
Gets the corresponding LO Date format for given OOXML datetime field type.
Definition: textfield.cxx:211
const OUString & getType() const
Definition: textfield.hxx:43
static SvxTimeFormat getLOTimeFormat(std::u16string_view rDateTimeType)
Gets the corresponding LO Time format for given OOXML datetime field type.
Definition: textfield.cxx:244
static oox::drawingml::ShapePtr findPlaceholder(const sal_Int32 nFirstSubType, const sal_Int32 nSecondSubType, const std::optional< sal_Int32 > &oSubTypeIndex, std::vector< oox::drawingml::ShapePtr > &rShapes, bool bMasterOnly=false)
Definition: pptshape.cxx:685
bool hasNonInheritedShapeProperties() const
Returns whether or not the shape had a non-empty spPr tag.
Definition: pptshape.hxx:82
void addShape(oox::core::XmlFilterBase &rFilterBase, const SlidePersist &rPersist, const oox::drawingml::Theme *pTheme, const css::uno::Reference< css::drawing::XShapes > &rxShapes, basegfx::B2DHomMatrix &aTransformation, ::oox::drawingml::ShapeIdMap *pShapeMap)
Definition: pptshape.cxx:160
OUString msModelId
Definition: pptshape.hxx:48
PPTShape(const oox::ppt::ShapeLocation eShapeLocation, const char *pServiceType)
Definition: pptshape.cxx:61
ShapeLocation getShapeLocation() const
Definition: pptshape.hxx:74
static oox::drawingml::TextListStylePtr getSubTypeTextListStyle(const SlidePersist &rSlidePersist, sal_Int32 nSubType)
Definition: pptshape.cxx:114
virtual ~PPTShape() override
Definition: pptshape.cxx:69
static oox::drawingml::ShapePtr findPlaceholderByIndex(const sal_Int32 nIdx, std::vector< oox::drawingml::ShapePtr > &rShapes, bool bMasterOnly=false)
Definition: pptshape.cxx:785
bool IsPlaceHolderCandidate(const SlidePersist &rSlidePersist) const
Definition: pptshape.cxx:139
ShapeLocation meShapeLocation
Definition: pptshape.hxx:49
oox::drawingml::ShapePtr mpPlaceholder
Definition: pptshape.hxx:52
const oox::drawingml::TextListStylePtr & getOtherTextStyle() const
const oox::drawingml::TextListStylePtr & getBodyTextStyle() const
const css::uno::Reference< css::drawing::XDrawPage > & getPage() const
const oox::drawingml::TextListStylePtr & getTitleTextStyle() const
const oox::drawingml::TextListStylePtr & getNotesTextStyle() const
const oox::drawingml::TextListStylePtr & getDefaultTextStyle() const
const SlidePersistPtr & getMasterPersist() const
bool isNotesPage() const
const oox::drawingml::ShapePtr & getShapes() const
bool isMasterPage() const
Any value
int nCount
float u
std::deque< AttacherIndex_Impl > aIndex
SvxTimeFormat
SvxDateFormat
#define SAL_INFO(area, stream)
@ Exception
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
std::map< OUString, ShapePairs > NamedShapePairs
std::shared_ptr< Shape > ShapePtr
std::shared_ptr< TextRun > TextRunPtr
Definition: textrun.hxx:65
::std::map< OUString, ShapePtr > ShapeIdMap
Definition: shape.hxx:77
std::shared_ptr< TextListStyle > TextListStylePtr
static const char * lclDebugSubType(sal_Int32 nType)
Definition: pptshape.cxx:73
QPRO_FUNC_TYPE nType
Shape