/src/libreoffice/oox/source/ppt/pptshape.cxx
Line | Count | Source |
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> |
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> |
27 | | |
28 | | #include <com/sun/star/text/XTextField.hpp> |
29 | | #include <com/sun/star/style/XStyle.hpp> |
30 | | #include <com/sun/star/style/XStyleFamiliesSupplier.hpp> |
31 | | #include <com/sun/star/container/XNamed.hpp> |
32 | | #include <com/sun/star/frame/XModel.hpp> |
33 | | #include <com/sun/star/lang/XMultiServiceFactory.hpp> |
34 | | #include <com/sun/star/drawing/XDrawPage.hpp> |
35 | | #include <com/sun/star/drawing/XDrawPages.hpp> |
36 | | #include <com/sun/star/drawing/XDrawPagesSupplier.hpp> |
37 | | #include <com/sun/star/drawing/XShapes.hpp> |
38 | | #include <com/sun/star/text/XText.hpp> |
39 | | #include <com/sun/star/document/XEventsSupplier.hpp> |
40 | | #include <com/sun/star/container/XNameReplace.hpp> |
41 | | #include <com/sun/star/presentation/ClickAction.hpp> |
42 | | #include <basegfx/matrix/b2dhommatrix.hxx> |
43 | | #include <sal/log.hxx> |
44 | | #include <oox/ppt/slidepersist.hxx> |
45 | | #include <oox/token/tokens.hxx> |
46 | | #include <oox/token/properties.hxx> |
47 | | #include <o3tl/string_view.hxx> |
48 | | |
49 | | using namespace ::oox::core; |
50 | | using namespace ::oox::drawingml; |
51 | | using namespace ::com::sun::star; |
52 | | using namespace ::com::sun::star::awt; |
53 | | using namespace ::com::sun::star::uno; |
54 | | using namespace ::com::sun::star::beans; |
55 | | using namespace ::com::sun::star::text; |
56 | | using namespace ::com::sun::star::drawing; |
57 | | using namespace ::com::sun::star::document; |
58 | | using namespace ::com::sun::star::container; |
59 | | using namespace ::com::sun::star::presentation; |
60 | | |
61 | | namespace oox::ppt { |
62 | | |
63 | | PPTShape::PPTShape( const oox::ppt::ShapeLocation eShapeLocation, const OUString& rServiceName ) |
64 | 130k | : Shape( rServiceName ) |
65 | 130k | , meShapeLocation( eShapeLocation ) |
66 | 130k | , mbReferenced( false ) |
67 | 130k | , mbHasNoninheritedShapeProperties( false ) |
68 | 130k | { |
69 | 130k | } |
70 | | |
71 | | PPTShape::~PPTShape() |
72 | 130k | { |
73 | 130k | } |
74 | | |
75 | | static const char* lclDebugSubType( sal_Int32 nType ) |
76 | 0 | { |
77 | 0 | switch (nType) { |
78 | 0 | case XML_ctrTitle : |
79 | 0 | return "ctrTitle"; |
80 | 0 | case XML_title : |
81 | 0 | return "title"; |
82 | 0 | case XML_subTitle : |
83 | 0 | return "subTitle"; |
84 | 0 | case XML_obj : |
85 | 0 | return "obj"; |
86 | 0 | case XML_body : |
87 | 0 | return "body"; |
88 | 0 | case XML_dt : |
89 | 0 | return "dt"; |
90 | 0 | case XML_hdr : |
91 | 0 | return "hdr"; |
92 | 0 | case XML_ftr : |
93 | 0 | return "frt"; |
94 | 0 | case XML_sldNum : |
95 | 0 | return "sldNum"; |
96 | 0 | case XML_sldImg : |
97 | 0 | return "sldImg"; |
98 | 0 | } |
99 | | |
100 | 0 | return "unknown - please extend lclDebugSubType"; |
101 | 0 | } |
102 | | |
103 | | namespace |
104 | | { |
105 | | bool ShapeHasNoVisualPropertiesOnImport(const oox::ppt::PPTShape& rPPTShape) |
106 | 24 | { |
107 | 24 | return !rPPTShape.hasNonInheritedShapeProperties() |
108 | 19 | && !rPPTShape.hasShapeStyleRefs() |
109 | 19 | && !rPPTShape.getTextBody()->hasVisualRunProperties() |
110 | 0 | && !rPPTShape.getTextBody()->hasNoninheritedBodyProperties() |
111 | 0 | && !rPPTShape.getTextBody()->hasListStyleOnImport() |
112 | 0 | && !rPPTShape.getTextBody()->hasParagraphProperties(); |
113 | 24 | } |
114 | | } |
115 | | |
116 | | oox::drawingml::TextListStylePtr PPTShape::getSubTypeTextListStyle( const SlidePersist& rSlidePersist, sal_Int32 nSubType ) |
117 | 90 | { |
118 | 90 | oox::drawingml::TextListStylePtr pTextListStyle; |
119 | | |
120 | 90 | SAL_INFO("oox.ppt", "subtype style: " << lclDebugSubType( nSubType ) ); |
121 | | |
122 | 90 | switch( nSubType ) |
123 | 90 | { |
124 | 0 | case XML_ctrTitle : |
125 | 0 | case XML_title : |
126 | 0 | pTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getTitleTextStyle() : rSlidePersist.getTitleTextStyle(); |
127 | 0 | break; |
128 | 0 | case XML_subTitle : |
129 | 0 | case XML_obj : |
130 | 87 | case XML_body : |
131 | 87 | if ( rSlidePersist.isNotesPage() ) |
132 | 0 | pTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getNotesTextStyle() : rSlidePersist.getNotesTextStyle(); |
133 | 87 | else |
134 | 87 | pTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getBodyTextStyle() : rSlidePersist.getBodyTextStyle(); |
135 | 87 | break; |
136 | 90 | } |
137 | | |
138 | 90 | return pTextListStyle; |
139 | 90 | } |
140 | | |
141 | | bool PPTShape::IsPlaceHolderCandidate(const SlidePersist& rSlidePersist) const |
142 | 31.3k | { |
143 | 31.3k | if (meShapeLocation != Slide) |
144 | 31.2k | return false; |
145 | 34 | if (rSlidePersist.isNotesPage()) |
146 | 5 | return false; |
147 | 29 | auto pTextBody = getTextBody(); |
148 | 29 | if (!pTextBody) |
149 | 0 | return false; |
150 | 29 | auto rParagraphs = pTextBody->getParagraphs(); |
151 | 29 | if (rParagraphs.size() != 1) |
152 | 5 | return false; |
153 | 24 | if (rParagraphs.front()->getRuns().size() != 1) |
154 | 0 | return false; |
155 | | // If the placeholder has a shape other than rectangle, |
156 | | // we have to place it in the slide as a CustomShape. |
157 | 24 | if (!mpCustomShapePropertiesPtr->representsDefaultShape()) |
158 | 0 | return false; |
159 | 24 | return ShapeHasNoVisualPropertiesOnImport(*this); |
160 | 24 | } |
161 | | |
162 | | void PPTShape::setTextMasterStyles( const SlidePersist& rSlidePersist, const oox::core::XmlFilterBase& rFilterBase, const std::u16string_view& sType ) |
163 | 48.4k | { |
164 | 48.4k | if (!rSlidePersist.isMasterPage()) |
165 | 0 | return; |
166 | | |
167 | 48.4k | try |
168 | 48.4k | { |
169 | 48.4k | Reference< style::XStyleFamiliesSupplier > aXStyleFamiliesSupplier(rFilterBase.getModel(), UNO_QUERY_THROW); |
170 | 48.4k | Reference< container::XNameAccess > aXNameAccess(aXStyleFamiliesSupplier->getStyleFamilies()); |
171 | | |
172 | 48.4k | if (!aXNameAccess.is()) |
173 | 0 | return; |
174 | | |
175 | 48.4k | Reference< container::XNamed > aXNamed(rSlidePersist.getPage(), UNO_QUERY_THROW); |
176 | 48.4k | OUString aFamily = aXNamed->getName(); |
177 | | |
178 | 48.4k | if (!aXNameAccess->hasByName(aFamily)) |
179 | 0 | return; |
180 | | |
181 | 48.4k | Reference< container::XNameAccess > xFamilies; |
182 | 48.4k | if (aXNameAccess->getByName(aFamily) >>= xFamilies) |
183 | 48.4k | { |
184 | 48.4k | OUString aStyle; |
185 | 48.4k | if (sType == u"com.sun.star.presentation.TitleTextShape") // title style |
186 | 12.2k | aStyle = u"title"_ustr; |
187 | 36.1k | else if (sType == u"com.sun.star.presentation.SubtitleShape") // subtitle |
188 | 379 | aStyle = u"subtitle"_ustr; |
189 | 35.7k | else if (sType == u"com.sun.star.presentation.OutlinerShape") // body style |
190 | 13.2k | aStyle = u"outline1"_ustr; |
191 | 22.5k | else if (sType == u"com.sun.star.presentation.NotesShape") // notes style |
192 | 0 | aStyle = u"title"_ustr; |
193 | | |
194 | 48.4k | if (!xFamilies->hasByName(aStyle)) |
195 | 22.5k | return; |
196 | | |
197 | 25.8k | Reference< style::XStyle > aXStyle; |
198 | 25.8k | if (xFamilies->getByName(aStyle) >>= aXStyle) |
199 | 25.8k | { |
200 | 25.8k | TextCharacterProperties aCharStyleProperties; |
201 | 25.8k | getTextBody()->ApplyMasterTextStyle(rFilterBase, aXStyle, aCharStyleProperties, |
202 | 25.8k | mpMasterTextListStyle, size_t(0)); |
203 | 25.8k | if (aStyle.equals(u"outline1"_ustr)/* BodyStyle */) |
204 | 13.2k | { |
205 | 118k | for (size_t nLevel = 2; nLevel < 10; nLevel++) // outline2 ... outline9 |
206 | 105k | { |
207 | 105k | char pOutline[9] = "outline1"; |
208 | 105k | pOutline[7] = static_cast<char>('0' + nLevel); |
209 | 105k | OUString sOutlineStyle(OUString::createFromAscii(pOutline)); |
210 | 105k | if (xFamilies->hasByName(sOutlineStyle)) |
211 | 105k | { |
212 | 105k | if (aXStyle.is()) |
213 | 105k | aXStyle.clear(); |
214 | | |
215 | 105k | xFamilies->getByName(sOutlineStyle) >>= aXStyle; |
216 | 105k | if (aXStyle.is()) |
217 | 105k | { |
218 | 105k | TextCharacterProperties aCharStyleLvlProps; |
219 | 105k | getTextBody()->ApplyMasterTextStyle(rFilterBase, aXStyle, aCharStyleLvlProps, mpMasterTextListStyle, nLevel - 1); |
220 | 105k | } |
221 | 105k | } |
222 | 105k | } |
223 | 13.2k | } |
224 | 25.8k | } |
225 | 25.8k | } |
226 | 48.4k | } |
227 | 48.4k | catch (const Exception&) |
228 | 48.4k | { |
229 | 0 | } |
230 | 48.4k | } |
231 | | |
232 | | void PPTShape::addShape( |
233 | | oox::core::XmlFilterBase& rFilterBase, |
234 | | const SlidePersist& rSlidePersist, |
235 | | const oox::drawingml::Theme* pTheme, |
236 | | const Reference< XShapes >& rxShapes, |
237 | | basegfx::B2DHomMatrix& aTransformation, |
238 | | ::oox::drawingml::ShapeIdMap* pShapeMap ) |
239 | 88.6k | { |
240 | 88.6k | SAL_INFO("oox.ppt","add shape id: " << msId << " location: " << ((meShapeLocation == Master) ? "master" : ((meShapeLocation == Slide) ? "slide" : ((meShapeLocation == Layout) ? "layout" : "other"))) << " subtype: " << mnSubType << " service: " << msServiceName); |
241 | | |
242 | 88.6k | OUString sServiceName( msServiceName ); |
243 | 88.6k | if (sServiceName.isEmpty()) |
244 | 0 | return; |
245 | 88.6k | try |
246 | 88.6k | { |
247 | 88.6k | oox::drawingml::TextListStylePtr aMasterTextListStyle; |
248 | 88.6k | Reference<lang::XMultiServiceFactory> xServiceFact(rFilterBase.getModel(), UNO_QUERY_THROW); |
249 | 88.6k | bool bClearText = false; |
250 | | |
251 | 88.6k | if (sServiceName != "com.sun.star.drawing.GraphicObjectShape" && |
252 | 87.3k | sServiceName != "com.sun.star.drawing.OLE2Shape") |
253 | 87.2k | { |
254 | 87.2k | static constexpr OUString sOutlinerShapeService(u"com.sun.star.presentation.OutlinerShape"_ustr); |
255 | 87.2k | SAL_INFO("oox.ppt","has master: " << std::hex << rSlidePersist.getMasterPersist().get()); |
256 | 87.2k | switch (mnSubType) |
257 | 87.2k | { |
258 | 609 | case XML_ctrTitle : |
259 | 16.9k | case XML_title : |
260 | 16.9k | { |
261 | 16.9k | sServiceName = "com.sun.star.presentation.TitleTextShape"; |
262 | 16.9k | aMasterTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getTitleTextStyle() : rSlidePersist.getTitleTextStyle(); |
263 | 16.9k | } |
264 | 16.9k | break; |
265 | 1.37k | case XML_subTitle : |
266 | 1.37k | { |
267 | 1.37k | sServiceName = "com.sun.star.presentation.SubtitleShape"; |
268 | 1.37k | aMasterTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getBodyTextStyle() : rSlidePersist.getBodyTextStyle(); |
269 | 1.37k | } |
270 | 1.37k | break; |
271 | 2.41k | case XML_obj : |
272 | 2.41k | { |
273 | 2.41k | sServiceName = sOutlinerShapeService; |
274 | 2.41k | if (getSubTypeIndex().has_value()) |
275 | 2.41k | aMasterTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getBodyTextStyle() : rSlidePersist.getBodyTextStyle(); |
276 | 2.41k | } |
277 | 2.41k | break; |
278 | 20.4k | case XML_body : |
279 | 20.4k | { |
280 | 20.4k | if (rSlidePersist.isNotesPage()) |
281 | 95 | { |
282 | 95 | sServiceName = "com.sun.star.presentation.NotesShape"; |
283 | 95 | aMasterTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getNotesTextStyle() : rSlidePersist.getNotesTextStyle(); |
284 | 95 | } |
285 | 20.3k | else |
286 | 20.3k | { |
287 | 20.3k | sServiceName = sOutlinerShapeService; |
288 | 20.3k | aMasterTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getBodyTextStyle() : rSlidePersist.getBodyTextStyle(); |
289 | 20.3k | } |
290 | 20.4k | } |
291 | 20.4k | break; |
292 | 10.5k | case XML_dt : |
293 | 10.5k | if (IsPlaceHolderCandidate(rSlidePersist)) |
294 | 0 | { |
295 | 0 | TextRunPtr& pTextRun = getTextBody()->getParagraphs().front()->getRuns().front(); |
296 | 0 | oox::drawingml::TextField* pTextField = dynamic_cast<oox::drawingml::TextField*>(pTextRun.get()); |
297 | 0 | if (pTextField) |
298 | 0 | { |
299 | 0 | OUString aType = pTextField->getType(); |
300 | 0 | if ( aType.startsWith("datetime") ) |
301 | 0 | { |
302 | 0 | SvxDateFormat eDateFormat = drawingml::TextField::getLODateFormat(aType); |
303 | 0 | SvxTimeFormat eTimeFormat = drawingml::TextField::getLOTimeFormat(aType); |
304 | 0 | Reference< XPropertySet > xPropertySet( rSlidePersist.getPage(), UNO_QUERY ); |
305 | |
|
306 | 0 | if( eDateFormat != SvxDateFormat::AppDefault |
307 | 0 | || eTimeFormat != SvxTimeFormat::AppDefault ) |
308 | 0 | { |
309 | | // DateTimeFormat property looks for the date in 4 LSBs |
310 | | // and looks for time format in the 4 bits after that |
311 | 0 | sal_Int32 nDateTimeFormat = static_cast<sal_Int32>(eDateFormat) | |
312 | 0 | static_cast<sal_Int32>(eTimeFormat) << 4; |
313 | 0 | xPropertySet->setPropertyValue( u"IsDateTimeVisible"_ustr, Any(true) ); |
314 | 0 | xPropertySet->setPropertyValue( u"IsDateTimeFixed"_ustr, Any(false) ); |
315 | 0 | xPropertySet->setPropertyValue( u"DateTimeFormat"_ustr, Any(nDateTimeFormat) ); |
316 | 0 | return; |
317 | 0 | } |
318 | 0 | } |
319 | 0 | } |
320 | 0 | } |
321 | 10.5k | sServiceName = "com.sun.star.presentation.DateTimeShape"; |
322 | 10.5k | bClearText = true; |
323 | 10.5k | break; |
324 | 0 | case XML_hdr : |
325 | 0 | sServiceName = "com.sun.star.presentation.HeaderShape"; |
326 | 0 | bClearText = true; |
327 | 0 | break; |
328 | 10.3k | case XML_ftr : |
329 | 10.3k | if (IsPlaceHolderCandidate(rSlidePersist)) |
330 | 0 | { |
331 | 0 | const OUString aFooterText = getTextBody()->toString(); |
332 | |
|
333 | 0 | if( !aFooterText.isEmpty() ) |
334 | 0 | { |
335 | | // if it is possible to get the footer as a property the LO way, |
336 | | // get it and discard the shape |
337 | 0 | Reference< XPropertySet > xPropertySet( rSlidePersist.getPage(), UNO_QUERY ); |
338 | 0 | xPropertySet->setPropertyValue( u"IsFooterVisible"_ustr, Any( true ) ); |
339 | 0 | xPropertySet->setPropertyValue( u"FooterText"_ustr, Any(aFooterText) ); |
340 | 0 | return; |
341 | 0 | } |
342 | 0 | } |
343 | 10.3k | sServiceName = "com.sun.star.presentation.FooterShape"; |
344 | 10.3k | bClearText = true; |
345 | 10.3k | break; |
346 | 10.5k | case XML_sldNum : |
347 | 10.5k | if (IsPlaceHolderCandidate(rSlidePersist)) |
348 | 0 | { |
349 | 0 | TextRunPtr& pTextRun |
350 | 0 | = getTextBody()->getParagraphs().front()->getRuns().front(); |
351 | 0 | oox::drawingml::TextField* pTextField |
352 | 0 | = dynamic_cast<oox::drawingml::TextField*>(pTextRun.get()); |
353 | 0 | if (pTextField && pTextField->getType() == "slidenum") |
354 | 0 | { |
355 | | // if it is possible to get the slidenum placeholder as a property |
356 | | // do that and discard the shape |
357 | 0 | Reference<XPropertySet> xPropertySet(rSlidePersist.getPage(), |
358 | 0 | UNO_QUERY); |
359 | 0 | xPropertySet->setPropertyValue(u"IsPageNumberVisible"_ustr, Any(true)); |
360 | 0 | return; |
361 | 0 | } |
362 | 0 | } |
363 | 10.5k | sServiceName = "com.sun.star.presentation.SlideNumberShape"; |
364 | 10.5k | bClearText = true; |
365 | 10.5k | break; |
366 | 31 | case XML_sldImg : |
367 | 31 | sServiceName = "com.sun.star.presentation.PageShape"; |
368 | 31 | break; |
369 | 12 | case XML_chart : |
370 | 12 | if (meShapeLocation == Layout) |
371 | 12 | sServiceName = sOutlinerShapeService; |
372 | 0 | else |
373 | 0 | sServiceName = "com.sun.star.presentation.ChartShape"; |
374 | 12 | break; |
375 | 0 | case XML_tbl : |
376 | 0 | if (meShapeLocation == Layout) |
377 | 0 | sServiceName = sOutlinerShapeService; |
378 | 0 | else |
379 | 0 | sServiceName = "com.sun.star.presentation.TableShape"; |
380 | 0 | break; |
381 | 373 | case XML_pic : |
382 | | // <p:ph type="pic"/> is a real picture placeholder on both |
383 | | // slides and layouts, so the layout's type survives PPTX |
384 | | // round-trip and slide-side inheritance can resolve it. |
385 | 373 | sServiceName = "com.sun.star.presentation.GraphicObjectShape"; |
386 | 373 | break; |
387 | 0 | case XML_media : |
388 | 0 | if (meShapeLocation == Layout) |
389 | 0 | sServiceName = sOutlinerShapeService; |
390 | 0 | else |
391 | 0 | sServiceName = "com.sun.star.presentation.MediaShape"; |
392 | 0 | break; |
393 | 14.4k | default: |
394 | 14.4k | if (mnSubType && meShapeLocation == Layout) |
395 | 0 | sServiceName = sOutlinerShapeService; |
396 | 14.4k | break; |
397 | 87.2k | } |
398 | 87.2k | } |
399 | | |
400 | | // Since it is not possible to represent custom shaped placeholders in Impress |
401 | | // Need to use service name css.drawing.CustomShape if they have a non default shape. |
402 | | // This workaround has the drawback of them not really being processed as placeholders |
403 | | // so it is done for slide footers and obj placeholder |
404 | 88.6k | bool convertInSlideMode |
405 | 88.6k | = meShapeLocation == Slide |
406 | 5.40k | && (mnSubType == XML_sldNum || mnSubType == XML_dt || mnSubType == XML_ftr |
407 | 5.36k | || mnSubType == XML_body |
408 | 5.25k | || (mnSubType == XML_obj |
409 | 77 | && sServiceName != "com.sun.star.drawing.GraphicObjectShape")); |
410 | | |
411 | 88.6k | bool convertInLayoutMode = meShapeLocation == Layout && (mnSubType == XML_body); |
412 | 88.6k | if ((convertInSlideMode || convertInLayoutMode) && !mpCustomShapePropertiesPtr->representsDefaultShape()) |
413 | 0 | { |
414 | 0 | sServiceName = "com.sun.star.drawing.CustomShape"; |
415 | 0 | } |
416 | | |
417 | 88.6k | SAL_INFO("oox.ppt","shape service: " << sServiceName); |
418 | | |
419 | 88.6k | if (mnSubType && getSubTypeIndex().has_value() && meShapeLocation == Layout) |
420 | 18.7k | { |
421 | 18.7k | oox::drawingml::ShapePtr pPlaceholder = PPTShape::findPlaceholderByIndex( getSubTypeIndex().value(), rSlidePersist.getShapes()->getChildren(), true ); |
422 | 18.7k | if (!pPlaceholder) |
423 | 15.1k | pPlaceholder = PPTShape::findPlaceholder( mnSubType, 0, getSubTypeIndex(), rSlidePersist.getShapes()->getChildren(), true ); |
424 | | |
425 | 18.7k | if (pPlaceholder) { |
426 | 11.7k | if (maSize.Width == 0 || maSize.Height == 0) { |
427 | 0 | awt::Size aSize = maSize; |
428 | 0 | if (maSize.Width == 0) |
429 | 0 | aSize.Width = pPlaceholder->getSize().Width; |
430 | 0 | if (maSize.Height == 0) |
431 | 0 | aSize.Height = pPlaceholder->getSize().Height; |
432 | 0 | setSize( aSize ); |
433 | 0 | if (maPosition.X == 0 || maPosition.Y == 0) { |
434 | 0 | awt::Point aPosition = maPosition; |
435 | 0 | if (maPosition.X == 0) |
436 | 0 | aPosition.X = pPlaceholder->getPosition().X; |
437 | 0 | if (maPosition.Y == 0) |
438 | 0 | aPosition.Y = pPlaceholder->getPosition().Y; |
439 | 0 | setPosition( aPosition ); |
440 | 0 | } |
441 | 0 | } |
442 | 11.7k | } |
443 | 18.7k | } |
444 | | |
445 | | // use placeholder index if possible |
446 | 88.6k | if (mnSubType && getSubTypeIndex().has_value() && rSlidePersist.getMasterPersist()) |
447 | 256 | { |
448 | 256 | oox::drawingml::ShapePtr pPlaceholder = PPTShape::findPlaceholderByIndex(getSubTypeIndex().value(), rSlidePersist.getMasterPersist()->getShapes()->getChildren()); |
449 | | // TODO: Check if this is required for non-notes slides as well... |
450 | 256 | if (rSlidePersist.isNotesPage() && pPlaceholder && pPlaceholder->getSubType() != getSubType()) |
451 | 16 | pPlaceholder.reset(); |
452 | | |
453 | 256 | if (pPlaceholder) { |
454 | 178 | SAL_INFO("oox.ppt","found placeholder with index: " << getSubTypeIndex().value() << " and type: " << lclDebugSubType( mnSubType )); |
455 | 178 | PPTShape* pPPTPlaceholder = dynamic_cast< PPTShape* >( pPlaceholder.get() ); |
456 | 178 | TextListStylePtr pNewTextListStyle = std::make_shared<TextListStyle>(); |
457 | | |
458 | 178 | if (pPlaceholder->getTextBody()) { |
459 | | |
460 | 178 | pNewTextListStyle->apply( pPlaceholder->getTextBody()->getTextListStyle() ); |
461 | 178 | if (pPlaceholder->getMasterTextListStyle()) |
462 | 178 | pNewTextListStyle->apply( *pPlaceholder->getMasterTextListStyle() ); |
463 | | |
464 | | // SAL_INFO("oox.ppt","placeholder body style"); |
465 | | // pPlaceholder->getTextBody()->getTextListStyle().dump(); |
466 | | // SAL_INFO("oox.ppt","master text list style"); |
467 | | // pPlaceholder->getMasterTextListStyle()->dump(); |
468 | | |
469 | 178 | aMasterTextListStyle = pNewTextListStyle; |
470 | | // SAL_INFO("oox.ppt","combined master text list style"); |
471 | | // aMasterTextListStyle->dump(); |
472 | 178 | } |
473 | 178 | if (pPPTPlaceholder && pPPTPlaceholder->mpPlaceholder) { |
474 | 90 | SAL_INFO("oox.ppt","placeholder has parent placeholder: " << pPPTPlaceholder->mpPlaceholder->getId() << " type: " << lclDebugSubType( pPPTPlaceholder->mpPlaceholder->getSubType() ) << " index: " << pPPTPlaceholder->mpPlaceholder->getSubTypeIndex().value() ); |
475 | 90 | SAL_INFO("oox.ppt","has textbody " << (pPPTPlaceholder->mpPlaceholder->getTextBody() != nullptr) ); |
476 | 90 | TextListStylePtr pPlaceholderStyle = getSubTypeTextListStyle( rSlidePersist, pPPTPlaceholder->mpPlaceholder->getSubType() ); |
477 | 90 | if (pPPTPlaceholder->mpPlaceholder->getTextBody()) |
478 | 90 | pNewTextListStyle->apply( pPPTPlaceholder->mpPlaceholder->getTextBody()->getTextListStyle() ); |
479 | 90 | if (pPlaceholderStyle) { |
480 | 87 | pNewTextListStyle->apply( *pPlaceholderStyle ); |
481 | | //pPlaceholderStyle->dump(); |
482 | 87 | } |
483 | 90 | } |
484 | 178 | } else if (!mpPlaceholder) { |
485 | 58 | aMasterTextListStyle.reset(); |
486 | 58 | } |
487 | 256 | SAL_INFO("oox.ppt","placeholder id: " << (pPlaceholder ? pPlaceholder->getId() : u"not found"_ustr)); |
488 | 256 | } |
489 | | |
490 | 88.6k | if (!sServiceName.isEmpty()) |
491 | 88.6k | { |
492 | 88.6k | if (!aMasterTextListStyle) |
493 | 47.5k | { |
494 | 47.5k | bool isOther = !getTextBody() && sServiceName != "com.sun.star.drawing.GroupShape"; |
495 | 47.5k | TextListStylePtr aSlideStyle = isOther ? rSlidePersist.getOtherTextStyle() : rSlidePersist.getDefaultTextStyle(); |
496 | | // Combine from MasterSlide details as well. |
497 | 47.5k | if (rSlidePersist.getMasterPersist()) |
498 | 2.87k | { |
499 | 2.87k | aMasterTextListStyle = isOther ? rSlidePersist.getMasterPersist()->getOtherTextStyle() : rSlidePersist.getMasterPersist()->getDefaultTextStyle(); |
500 | 2.87k | if (aSlideStyle) |
501 | 2.87k | aMasterTextListStyle->apply( *aSlideStyle ); |
502 | 2.87k | } |
503 | 44.6k | else |
504 | 44.6k | { |
505 | 44.6k | aMasterTextListStyle = std::move(aSlideStyle); |
506 | 44.6k | } |
507 | 47.5k | } |
508 | | |
509 | 88.6k | if( aMasterTextListStyle && getTextBody() ) { |
510 | 80.5k | TextListStylePtr aCombinedTextListStyle = std::make_shared<TextListStyle>(); |
511 | | |
512 | 80.5k | aCombinedTextListStyle->apply( *aMasterTextListStyle ); |
513 | | |
514 | 80.5k | if( mpPlaceholder && mpPlaceholder->getTextBody() ) |
515 | 21.3k | aCombinedTextListStyle->apply( mpPlaceholder->getTextBody()->getTextListStyle() ); |
516 | 80.5k | aCombinedTextListStyle->apply( getTextBody()->getTextListStyle() ); |
517 | | |
518 | 80.5k | setMasterTextListStyle( aCombinedTextListStyle ); |
519 | 80.5k | } else |
520 | 8.14k | setMasterTextListStyle( aMasterTextListStyle ); |
521 | | |
522 | 88.6k | if (mnSubType && meShapeLocation == Master) |
523 | 34.7k | { |
524 | 34.7k | if (getTextBody() && !getTextBody()->isEmpty()) |
525 | 30.5k | setTextMasterStyles(rSlidePersist, rFilterBase, sServiceName); |
526 | 34.7k | return; |
527 | 34.7k | } |
528 | | |
529 | 53.8k | Reference< XShape > xShape( createAndInsert( rFilterBase, sServiceName, pTheme, rxShapes, bClearText, mpPlaceholder, aTransformation, getFillProperties() ) ); |
530 | | |
531 | | // Apply text properties on placeholder text inside this placeholder shape |
532 | 53.8k | if (meShapeLocation == Slide && mpPlaceholder && getTextBody() && getTextBody()->isEmpty()) |
533 | 252 | { |
534 | 252 | Reference < XText > xText(mxShape, UNO_QUERY); |
535 | 252 | if (xText.is()) |
536 | 236 | { |
537 | 236 | TextCharacterProperties aCharStyleProperties; |
538 | 236 | getTextBody()->ApplyStyleEmpty(rFilterBase, xText, aCharStyleProperties, mpMasterTextListStyle); |
539 | 236 | } |
540 | 252 | } |
541 | | // Apply text properties on master placeholder styles |
542 | 53.8k | if (meShapeLocation == Layout && getTextBody() && !getTextBody()->isEmpty()) |
543 | 17.8k | { |
544 | 17.8k | setTextMasterStyles(rSlidePersist, rFilterBase, sServiceName); |
545 | 17.8k | } |
546 | 53.8k | if (pShapeMap) |
547 | 53.8k | { |
548 | | // bnc#705982 - if optional model id reference is |
549 | | // there, use that to obtain target shape |
550 | 53.8k | if (!msModelId.isEmpty()) |
551 | 0 | { |
552 | 0 | (*pShapeMap)[ msModelId ] = shared_from_this(); |
553 | 0 | } |
554 | 53.8k | else if (!msId.isEmpty()) |
555 | 53.8k | { |
556 | 53.8k | (*pShapeMap)[ msId ] = shared_from_this(); |
557 | 53.8k | } |
558 | 53.8k | } |
559 | | |
560 | | // we will be losing whatever information there is in the footer placeholder on master/layout slides |
561 | | // since they should have the "<footer>" textfield in them in order to make LibreOffice process them as expected |
562 | | // likewise DateTime placeholder data on master/layout slides will be lost and replaced |
563 | 53.8k | if( (mnSubType == XML_ftr || mnSubType == XML_dt) && meShapeLocation != Slide ) |
564 | 8.63k | { |
565 | 8.63k | OUString aFieldType; |
566 | 8.63k | if( mnSubType == XML_ftr ) |
567 | 4.31k | aFieldType = "com.sun.star.presentation.TextField.Footer"; |
568 | 4.31k | else |
569 | 4.31k | aFieldType = "com.sun.star.presentation.TextField.DateTime"; |
570 | 8.63k | Reference < XTextField > xField( xServiceFact->createInstance( aFieldType ), UNO_QUERY ); |
571 | 8.63k | Reference < XText > xText(mxShape, UNO_QUERY); |
572 | 8.63k | if(xText.is()) |
573 | 8.63k | { |
574 | 8.63k | xText->setString(u""_ustr); |
575 | 8.63k | Reference < XTextCursor > xTextCursor = xText->createTextCursor(); |
576 | 8.63k | xText->insertTextContent( xTextCursor, xField, false); |
577 | 8.63k | } |
578 | 8.63k | } |
579 | | |
580 | 53.8k | OUString sURL; |
581 | 53.8k | std::vector<std::pair<OUString, Reference<XShape>>> aURLShapes; |
582 | | // if this is a group shape, we have to add also each child shape |
583 | 53.8k | Reference<XShapes> xShapes(xShape, UNO_QUERY); |
584 | 53.8k | if (xShapes.is()) |
585 | 8 | { |
586 | | // temporarily remember setting |
587 | 8 | NamedShapePairs* pDiagramFontHeights(rFilterBase.getDiagramFontHeights()); |
588 | | |
589 | | // for shapes unequal to FRAMETYPE_DIAGRAM do |
590 | | // disable DiagramFontHeights recording |
591 | 8 | if (meFrameType != FRAMETYPE_DIAGRAM) |
592 | 8 | rFilterBase.setDiagramFontHeights(nullptr); |
593 | | |
594 | 8 | addChildren( rFilterBase, *this, pTheme, xShapes, pShapeMap, aTransformation ); |
595 | | |
596 | | // restore remembered setting |
597 | 8 | rFilterBase.setDiagramFontHeights(pDiagramFontHeights); |
598 | | |
599 | 24 | for (size_t i = 0; i < this->getChildren().size(); i++) |
600 | 16 | { |
601 | 16 | this->getChildren()[i]->getShapeProperties().getProperty(PROP_URL) >>= sURL; |
602 | 16 | if (!sURL.isEmpty()) |
603 | 0 | { |
604 | 0 | Reference<XShape> xChild = this->getChildren()[i]->getXShape(); |
605 | 0 | aURLShapes.push_back({ sURL, xChild }); |
606 | 0 | } |
607 | 16 | } |
608 | 8 | } |
609 | | |
610 | | // Support advanced DiagramHelper |
611 | 53.8k | if (FRAMETYPE_DIAGRAM == meFrameType) |
612 | 0 | { |
613 | 0 | propagateDiagramHelper(); |
614 | 0 | } |
615 | | |
616 | 53.8k | getShapeProperties().getProperty(PROP_URL) >>= sURL; |
617 | 53.8k | if (!sURL.isEmpty() && !xShapes.is()) |
618 | 0 | aURLShapes.push_back({ sURL, xShape }); |
619 | | |
620 | 53.8k | if (!aURLShapes.empty()) |
621 | 0 | { |
622 | 0 | for (auto const& URLShape : aURLShapes) |
623 | 0 | { |
624 | 0 | Reference<XEventsSupplier> xEventsSupplier(URLShape.second, UNO_QUERY); |
625 | 0 | if (!xEventsSupplier.is()) |
626 | 0 | return; |
627 | | |
628 | 0 | Reference<XNameReplace> xEvents(xEventsSupplier->getEvents()); |
629 | 0 | if (!xEvents.is()) |
630 | 0 | return; |
631 | | |
632 | 0 | OUString sAPIEventName; |
633 | 0 | sal_Int32 nPropertyCount = 2; |
634 | 0 | css::presentation::ClickAction meClickAction; |
635 | 0 | uno::Sequence<beans::PropertyValue> aProperties; |
636 | |
|
637 | 0 | std::map<OUString, css::presentation::ClickAction> ActionMap = { |
638 | 0 | { "#action?jump=nextslide", ClickAction_NEXTPAGE }, |
639 | 0 | { "#action?jump=previousslide", ClickAction_PREVPAGE }, |
640 | 0 | { "#action?jump=firstslide", ClickAction_FIRSTPAGE }, |
641 | 0 | { "#action?jump=lastslide", ClickAction_LASTPAGE }, |
642 | 0 | { "#action?jump=endshow", ClickAction_STOPPRESENTATION }, |
643 | 0 | }; |
644 | |
|
645 | 0 | sURL = URLShape.first; |
646 | 0 | std::map<OUString, css::presentation::ClickAction>::const_iterator aIt |
647 | 0 | = ActionMap.find(sURL); |
648 | 0 | aIt != ActionMap.end() ? meClickAction = aIt->second |
649 | 0 | : meClickAction = ClickAction_BOOKMARK; |
650 | | |
651 | | // ClickAction_BOOKMARK and ClickAction_DOCUMENT share the same event |
652 | | // so check here if it's a bookmark or a document |
653 | 0 | if (meClickAction == ClickAction_BOOKMARK) |
654 | 0 | { |
655 | 0 | if (!sURL.startsWith("#")) |
656 | 0 | meClickAction = ClickAction_DOCUMENT; |
657 | 0 | else |
658 | 0 | { |
659 | 0 | sURL = OUString::Concat("page") |
660 | 0 | + sURL.subView(sURL.lastIndexOf(' ') + 1); |
661 | 0 | } |
662 | 0 | nPropertyCount += 1; |
663 | 0 | } |
664 | |
|
665 | 0 | aProperties.realloc(nPropertyCount); |
666 | 0 | beans::PropertyValue* pProperties = aProperties.getArray(); |
667 | |
|
668 | 0 | pProperties->Name = "EventType"; |
669 | 0 | pProperties->Handle = -1; |
670 | 0 | pProperties->Value <<= u"Presentation"_ustr; |
671 | 0 | pProperties->State = beans::PropertyState_DIRECT_VALUE; |
672 | 0 | pProperties++; |
673 | |
|
674 | 0 | pProperties->Name = "ClickAction"; |
675 | 0 | pProperties->Handle = -1; |
676 | 0 | pProperties->Value <<= meClickAction; |
677 | 0 | pProperties->State = beans::PropertyState_DIRECT_VALUE; |
678 | 0 | pProperties++; |
679 | |
|
680 | 0 | switch (meClickAction) |
681 | 0 | { |
682 | 0 | case ClickAction_BOOKMARK: |
683 | 0 | case ClickAction_DOCUMENT: |
684 | 0 | pProperties->Name = "Bookmark"; |
685 | 0 | pProperties->Handle = -1; |
686 | 0 | pProperties->Value <<= sURL; |
687 | 0 | pProperties->State = beans::PropertyState_DIRECT_VALUE; |
688 | 0 | break; |
689 | 0 | default: |
690 | 0 | break; |
691 | 0 | } |
692 | | |
693 | 0 | sAPIEventName = "OnClick"; |
694 | 0 | xEvents->replaceByName(sAPIEventName, uno::Any(aProperties)); |
695 | 0 | } |
696 | 0 | } |
697 | 53.8k | } |
698 | 88.6k | } |
699 | 88.6k | catch (const Exception&) |
700 | 88.6k | { |
701 | 0 | } |
702 | 88.6k | } |
703 | | |
704 | | namespace |
705 | | { |
706 | | bool ShapeLocationIsMaster(oox::drawingml::Shape *pInShape) |
707 | 427k | { |
708 | 427k | PPTShape* pShape = dynamic_cast<PPTShape*>(pInShape); |
709 | 427k | return pShape && pShape->getShapeLocation() == Master; |
710 | 427k | } |
711 | | } |
712 | | |
713 | | // Function to find placeholder (ph) for a shape. No idea how MSO implements this, but |
714 | | // this order seems to work quite well |
715 | | // (probably it's unnecessary complicated / wrong. i.e. tdf#104202): |
716 | | // 1. ph with nFirstSubType and the same oSubTypeIndex |
717 | | // 2. ph with nFirstSubType |
718 | | // 3. ph with nSecondSubType and the same oSubTypeIndex |
719 | | // 4. ph with nSecondSubType |
720 | | // 5. ph with the same oSubTypeIndex |
721 | | |
722 | | oox::drawingml::ShapePtr PPTShape::findPlaceholder( sal_Int32 nFirstSubType, sal_Int32 nSecondSubType, |
723 | | const std::optional< sal_Int32 >& oSubTypeIndex, std::vector< oox::drawingml::ShapePtr >& rShapes, bool bMasterOnly ) |
724 | 135k | { |
725 | 135k | class Placeholders |
726 | 135k | { |
727 | 135k | public: |
728 | 135k | Placeholders() |
729 | 135k | : aChoice(5) // resize to 5 |
730 | 135k | { |
731 | 135k | } |
732 | | |
733 | 135k | void add(const oox::drawingml::ShapePtr& aShape, sal_Int32 nFirstSubType, sal_Int32 nSecondSubType, const std::optional< sal_Int32 >& oSubTypeIndex) |
734 | 195k | { |
735 | 195k | if (!aShape) |
736 | 0 | return; |
737 | | |
738 | | // get flags |
739 | 195k | const bool bSameFirstSubType = aShape->getSubType() == nFirstSubType; |
740 | 195k | const bool bSameSecondSubType = aShape->getSubType() == nSecondSubType; |
741 | 195k | const bool bSameIndex = aShape->getSubTypeIndex() == oSubTypeIndex; |
742 | | |
743 | | // get prio |
744 | 195k | int aPrioIndex = -1; |
745 | 195k | if (bSameIndex && bSameFirstSubType) |
746 | 20.1k | aPrioIndex = 0; |
747 | 174k | else if (!bSameIndex && bSameFirstSubType) |
748 | 33.8k | aPrioIndex = 1; |
749 | 141k | else if (bSameIndex && bSameSecondSubType) |
750 | 12.4k | aPrioIndex = 2; |
751 | 128k | else if (!bSameIndex && bSameSecondSubType) |
752 | 19.8k | aPrioIndex = 3; |
753 | 108k | else if (bSameIndex) |
754 | 18.8k | aPrioIndex = 4; |
755 | | |
756 | | // add |
757 | 195k | if (aPrioIndex != -1) |
758 | 105k | { |
759 | 105k | if (!aChoice.at(aPrioIndex)) |
760 | 94.2k | { |
761 | 94.2k | aChoice.at(aPrioIndex) = aShape; |
762 | 94.2k | } |
763 | 105k | } |
764 | 195k | } |
765 | | |
766 | | // return according to prio |
767 | 135k | oox::drawingml::ShapePtr getByPrio() const |
768 | 135k | { |
769 | 135k | for (const oox::drawingml::ShapePtr& aShape : aChoice) |
770 | 486k | { |
771 | 486k | if (aShape) |
772 | 59.7k | { |
773 | 59.7k | return aShape; |
774 | 59.7k | } |
775 | 486k | } |
776 | | |
777 | 75.7k | return oox::drawingml::ShapePtr(); |
778 | 135k | } |
779 | | |
780 | 135k | bool hasByPrio(size_t aIndex) const |
781 | 407k | { |
782 | 407k | return bool(aChoice.at(aIndex)); |
783 | 407k | } |
784 | | |
785 | 135k | private: |
786 | 135k | std::vector< oox::drawingml::ShapePtr > aChoice; |
787 | | |
788 | 135k | } aPlaceholders; |
789 | | |
790 | | // check all shapes |
791 | 135k | std::vector< oox::drawingml::ShapePtr >::reverse_iterator aRevIter( rShapes.rbegin() ); |
792 | 522k | for (; aRevIter != rShapes.rend(); ++aRevIter) |
793 | 407k | { |
794 | | // check shape |
795 | 407k | if (!bMasterOnly || ShapeLocationIsMaster((*aRevIter).get())) |
796 | 165k | { |
797 | 165k | const oox::drawingml::ShapePtr& aShape = *aRevIter; |
798 | 165k | aPlaceholders.add(aShape, nFirstSubType, nSecondSubType, oSubTypeIndex); |
799 | 165k | } |
800 | | |
801 | | // check children |
802 | 407k | std::vector< oox::drawingml::ShapePtr >& rChildren = (*aRevIter)->getChildren(); |
803 | 407k | if (!rChildren.empty()) |
804 | 82.4k | { |
805 | 82.4k | const oox::drawingml::ShapePtr aShape = findPlaceholder( nFirstSubType, nSecondSubType, oSubTypeIndex, rChildren, bMasterOnly ); |
806 | 82.4k | if (aShape) |
807 | 29.8k | { |
808 | 29.8k | aPlaceholders.add(aShape, nFirstSubType, nSecondSubType, oSubTypeIndex); |
809 | 29.8k | } |
810 | 82.4k | } |
811 | | |
812 | 407k | if (aPlaceholders.hasByPrio(0)) |
813 | 20.1k | { |
814 | 20.1k | break; |
815 | 20.1k | } |
816 | 407k | } |
817 | | |
818 | | // return something according to prio |
819 | 135k | return aPlaceholders.getByPrio(); |
820 | 135k | } |
821 | | |
822 | | oox::drawingml::ShapePtr PPTShape::findPlaceholderByIndex( const sal_Int32 nIdx, std::vector< oox::drawingml::ShapePtr >& rShapes, bool bMasterOnly ) |
823 | 203k | { |
824 | 203k | oox::drawingml::ShapePtr aShapePtr; |
825 | | |
826 | 203k | std::vector< oox::drawingml::ShapePtr >::reverse_iterator aRevIter( rShapes.rbegin() ); |
827 | 383k | while( aRevIter != rShapes.rend() ) |
828 | 187k | { |
829 | 187k | if ( (*aRevIter)->getSubTypeIndex().has_value() && (*aRevIter)->getSubTypeIndex().value() == nIdx && |
830 | 22.6k | ( !bMasterOnly || ShapeLocationIsMaster((*aRevIter).get()) ) ) |
831 | 3.86k | { |
832 | 3.86k | aShapePtr = *aRevIter; |
833 | 3.86k | break; |
834 | 3.86k | } |
835 | 184k | std::vector< oox::drawingml::ShapePtr >& rChildren = (*aRevIter)->getChildren(); |
836 | 184k | aShapePtr = findPlaceholderByIndex( nIdx, rChildren, bMasterOnly ); |
837 | 184k | if ( aShapePtr ) |
838 | 3.86k | break; |
839 | 180k | ++aRevIter; |
840 | 180k | } |
841 | 203k | return aShapePtr; |
842 | 203k | } |
843 | | |
844 | | } |
845 | | |
846 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |