tdf#107392 ODF import: fix z-order sorting of SVG images
[LibreOffice.git] / xmloff / source / draw / shapeimport.cxx
bloba3da37016a1ffaeddcba9881c8bdf72aaf19ac08
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 <o3tl/make_unique.hxx>
22 #include <tools/debug.hxx>
24 #include <com/sun/star/text/PositionLayoutDir.hpp>
25 #include <com/sun/star/chart/XChartDocument.hpp>
27 #include <xmloff/unointerfacetouniqueidentifiermapper.hxx>
28 #include <osl/diagnose.h>
30 #include <list>
32 #include <xmloff/shapeimport.hxx>
33 #include <xmloff/xmltkmap.hxx>
34 #include <xmloff/xmlnmspe.hxx>
35 #include <xmloff/xmltoken.hxx>
36 #include "ximpstyl.hxx"
37 #include "ximpshap.hxx"
38 #include "sdpropls.hxx"
39 #include <xmloff/xmlprmap.hxx>
40 #include "ximp3dscene.hxx"
41 #include "ximp3dobject.hxx"
42 #include "ximpgrp.hxx"
43 #include "ximplink.hxx"
45 #include <map>
46 #include <vector>
48 using namespace ::std;
49 using namespace ::com::sun::star;
50 using namespace ::xmloff::token;
52 struct ConnectionHint
54 css::uno::Reference< css::drawing::XShape > mxConnector;
55 bool bStart;
56 OUString aDestShapeId;
57 sal_Int32 nDestGlueId;
60 struct XShapeCompareHelper
62 bool operator()(const css::uno::Reference < css::drawing::XShape >& x1,
63 const css::uno::Reference < css::drawing::XShape >& x2 ) const
65 return x1.get() < x2.get();
69 /** this map store all glue point id mappings for shapes that had user defined glue points. This
70 is needed because on insertion the glue points will get a new and unique id */
71 typedef std::map<sal_Int32,sal_Int32> GluePointIdMap;
72 typedef std::map< css::uno::Reference < css::drawing::XShape >, GluePointIdMap, XShapeCompareHelper > ShapeGluePointsMap;
74 /** this struct is created for each startPage() call and stores information that is needed during
75 import of shapes for one page. Since pages could be nested ( notes pages inside impress ) there
76 is a pointer so one can build up a stack of this structs */
77 struct XMLShapeImportPageContextImpl
79 ShapeGluePointsMap maShapeGluePointsMap;
81 uno::Reference < drawing::XShapes > mxShapes;
83 std::shared_ptr<XMLShapeImportPageContextImpl> mpNext;
86 /** this class is to enable adding members to the XMLShapeImportHelper without getting incompatible */
87 struct XMLShapeImportHelperImpl
89 // context for sorting shapes
90 std::shared_ptr<ShapeSortContext> mpSortContext;
92 std::vector<ConnectionHint> maConnections;
94 // #88546# possibility to switch progress bar handling on/off
95 bool mbHandleProgressBar;
97 // stores the capability of the current model to create presentation shapes
98 bool mbIsPresentationShapesSupported;
101 XMLShapeImportHelper::XMLShapeImportHelper(
102 SvXMLImport& rImporter,
103 const uno::Reference< frame::XModel>& rModel,
104 SvXMLImportPropertyMapper *pExtMapper )
105 : mpImpl( new XMLShapeImportHelperImpl() ),
107 mpPropertySetMapper(nullptr),
108 mpPresPagePropsMapper(nullptr),
109 msStartShape("StartShape"),
110 msEndShape("EndShape"),
111 msStartGluePointIndex("StartGluePointIndex"),
112 msEndGluePointIndex("EndGluePointIndex"),
114 mrImporter( rImporter )
116 mpImpl->mpSortContext = nullptr;
118 // #88546# init to sal_False
119 mpImpl->mbHandleProgressBar = false;
121 mpSdPropHdlFactory = new XMLSdPropHdlFactory( rModel, rImporter );
123 // construct PropertySetMapper
124 rtl::Reference < XMLPropertySetMapper > xMapper = new XMLShapePropertySetMapper(mpSdPropHdlFactory.get(), false);
125 mpPropertySetMapper = new SvXMLImportPropertyMapper( xMapper, rImporter );
127 if( pExtMapper )
129 rtl::Reference < SvXMLImportPropertyMapper > xExtMapper( pExtMapper );
130 mpPropertySetMapper->ChainImportMapper( xExtMapper );
133 // chain text attributes
134 mpPropertySetMapper->ChainImportMapper(XMLTextImportHelper::CreateParaExtPropMapper(rImporter));
135 mpPropertySetMapper->ChainImportMapper(XMLTextImportHelper::CreateParaDefaultExtPropMapper(rImporter));
137 // construct PresPagePropsMapper
138 xMapper = new XMLPropertySetMapper(aXMLSDPresPageProps, mpSdPropHdlFactory.get(), false);
139 mpPresPagePropsMapper = new SvXMLImportPropertyMapper( xMapper, rImporter );
141 uno::Reference< lang::XServiceInfo > xInfo( rImporter.GetModel(), uno::UNO_QUERY );
142 const OUString aSName( "com.sun.star.presentation.PresentationDocument" );
143 mpImpl->mbIsPresentationShapesSupported = xInfo.is() && xInfo->supportsService( aSName );
146 XMLShapeImportHelper::~XMLShapeImportHelper()
148 SAL_WARN_IF( !mpImpl->maConnections.empty(), "xmloff", "XMLShapeImportHelper::restoreConnections() was not called!" );
150 // cleanup factory, decrease refcount. Should lead to destruction.
151 mpSdPropHdlFactory.clear();
153 // cleanup mapper, decrease refcount. Should lead to destruction.
154 mpPropertySetMapper.clear();
156 // cleanup presPage mapper, decrease refcount. Should lead to destruction.
157 mpPresPagePropsMapper.clear();
159 // Styles or AutoStyles context?
160 if(mxStylesContext.is())
161 mxStylesContext->Clear();
163 if(mxAutoStylesContext.is())
164 mxAutoStylesContext->Clear();
167 const SvXMLTokenMap& XMLShapeImportHelper::GetGroupShapeElemTokenMap()
169 if(!mpGroupShapeElemTokenMap)
171 static const SvXMLTokenMapEntry aGroupShapeElemTokenMap[] =
173 { XML_NAMESPACE_DRAW, XML_G, XML_TOK_GROUP_GROUP },
174 { XML_NAMESPACE_DRAW, XML_RECT, XML_TOK_GROUP_RECT },
175 { XML_NAMESPACE_DRAW, XML_LINE, XML_TOK_GROUP_LINE },
176 { XML_NAMESPACE_DRAW, XML_CIRCLE, XML_TOK_GROUP_CIRCLE },
177 { XML_NAMESPACE_DRAW, XML_ELLIPSE, XML_TOK_GROUP_ELLIPSE },
178 { XML_NAMESPACE_DRAW, XML_POLYGON, XML_TOK_GROUP_POLYGON },
179 { XML_NAMESPACE_DRAW, XML_POLYLINE, XML_TOK_GROUP_POLYLINE },
180 { XML_NAMESPACE_DRAW, XML_PATH, XML_TOK_GROUP_PATH },
182 { XML_NAMESPACE_DRAW, XML_CONTROL, XML_TOK_GROUP_CONTROL },
183 { XML_NAMESPACE_DRAW, XML_CONNECTOR, XML_TOK_GROUP_CONNECTOR },
184 { XML_NAMESPACE_DRAW, XML_MEASURE, XML_TOK_GROUP_MEASURE },
185 { XML_NAMESPACE_DRAW, XML_PAGE_THUMBNAIL, XML_TOK_GROUP_PAGE },
186 { XML_NAMESPACE_DRAW, XML_CAPTION, XML_TOK_GROUP_CAPTION },
188 { XML_NAMESPACE_CHART, XML_CHART, XML_TOK_GROUP_CHART },
189 { XML_NAMESPACE_DR3D, XML_SCENE, XML_TOK_GROUP_3DSCENE },
191 { XML_NAMESPACE_DRAW, XML_FRAME, XML_TOK_GROUP_FRAME },
192 { XML_NAMESPACE_DRAW, XML_CUSTOM_SHAPE, XML_TOK_GROUP_CUSTOM_SHAPE },
194 { XML_NAMESPACE_DRAW, XML_CUSTOM_SHAPE, XML_TOK_GROUP_CUSTOM_SHAPE },
195 { XML_NAMESPACE_OFFICE, XML_ANNOTATION, XML_TOK_GROUP_ANNOTATION },
196 { XML_NAMESPACE_DRAW, XML_A, XML_TOK_GROUP_A },
198 XML_TOKEN_MAP_END
201 mpGroupShapeElemTokenMap = o3tl::make_unique<SvXMLTokenMap>(aGroupShapeElemTokenMap);
204 return *mpGroupShapeElemTokenMap;
207 const SvXMLTokenMap& XMLShapeImportHelper::GetFrameShapeElemTokenMap()
209 if(!mpFrameShapeElemTokenMap)
211 static const SvXMLTokenMapEntry aFrameShapeElemTokenMap[] =
213 { XML_NAMESPACE_DRAW, XML_TEXT_BOX, XML_TOK_FRAME_TEXT_BOX },
214 { XML_NAMESPACE_DRAW, XML_IMAGE, XML_TOK_FRAME_IMAGE },
215 { XML_NAMESPACE_DRAW, XML_OBJECT, XML_TOK_FRAME_OBJECT },
216 { XML_NAMESPACE_DRAW, XML_OBJECT_OLE, XML_TOK_FRAME_OBJECT_OLE },
217 { XML_NAMESPACE_DRAW, XML_PLUGIN, XML_TOK_FRAME_PLUGIN },
218 { XML_NAMESPACE_DRAW, XML_FLOATING_FRAME, XML_TOK_FRAME_FLOATING_FRAME},
219 { XML_NAMESPACE_DRAW, XML_APPLET, XML_TOK_FRAME_APPLET },
220 { XML_NAMESPACE_TABLE, XML_TABLE, XML_TOK_FRAME_TABLE },
221 XML_TOKEN_MAP_END
224 mpFrameShapeElemTokenMap = o3tl::make_unique<SvXMLTokenMap>(aFrameShapeElemTokenMap);
227 return *mpFrameShapeElemTokenMap;
230 const SvXMLTokenMap& XMLShapeImportHelper::Get3DSceneShapeElemTokenMap()
232 if(!mp3DSceneShapeElemTokenMap)
234 static const SvXMLTokenMapEntry a3DSceneShapeElemTokenMap[] =
236 { XML_NAMESPACE_DR3D, XML_SCENE, XML_TOK_3DSCENE_3DSCENE },
237 { XML_NAMESPACE_DR3D, XML_CUBE, XML_TOK_3DSCENE_3DCUBE },
238 { XML_NAMESPACE_DR3D, XML_SPHERE, XML_TOK_3DSCENE_3DSPHERE },
239 { XML_NAMESPACE_DR3D, XML_ROTATE, XML_TOK_3DSCENE_3DLATHE },
240 { XML_NAMESPACE_DR3D, XML_EXTRUDE, XML_TOK_3DSCENE_3DEXTRUDE },
241 XML_TOKEN_MAP_END
244 mp3DSceneShapeElemTokenMap = o3tl::make_unique<SvXMLTokenMap>(a3DSceneShapeElemTokenMap);
247 return *mp3DSceneShapeElemTokenMap;
250 const SvXMLTokenMap& XMLShapeImportHelper::Get3DObjectAttrTokenMap()
252 if(!mp3DObjectAttrTokenMap)
254 static const SvXMLTokenMapEntry a3DObjectAttrTokenMap[] =
256 { XML_NAMESPACE_DRAW, XML_STYLE_NAME, XML_TOK_3DOBJECT_DRAWSTYLE_NAME },
257 { XML_NAMESPACE_DR3D, XML_TRANSFORM, XML_TOK_3DOBJECT_TRANSFORM },
258 XML_TOKEN_MAP_END
261 mp3DObjectAttrTokenMap = o3tl::make_unique<SvXMLTokenMap>(a3DObjectAttrTokenMap);
264 return *mp3DObjectAttrTokenMap;
267 const SvXMLTokenMap& XMLShapeImportHelper::Get3DPolygonBasedAttrTokenMap()
269 if(!mp3DPolygonBasedAttrTokenMap)
271 static const SvXMLTokenMapEntry a3DPolygonBasedAttrTokenMap[] =
273 { XML_NAMESPACE_SVG, XML_VIEWBOX, XML_TOK_3DPOLYGONBASED_VIEWBOX },
274 { XML_NAMESPACE_SVG, XML_D, XML_TOK_3DPOLYGONBASED_D },
275 XML_TOKEN_MAP_END
278 mp3DPolygonBasedAttrTokenMap = o3tl::make_unique<SvXMLTokenMap>(a3DPolygonBasedAttrTokenMap);
281 return *mp3DPolygonBasedAttrTokenMap;
284 const SvXMLTokenMap& XMLShapeImportHelper::Get3DCubeObjectAttrTokenMap()
286 if(!mp3DCubeObjectAttrTokenMap)
288 static const SvXMLTokenMapEntry a3DCubeObjectAttrTokenMap[] =
290 { XML_NAMESPACE_DR3D, XML_MIN_EDGE, XML_TOK_3DCUBEOBJ_MINEDGE },
291 { XML_NAMESPACE_DR3D, XML_MAX_EDGE, XML_TOK_3DCUBEOBJ_MAXEDGE },
292 XML_TOKEN_MAP_END
295 mp3DCubeObjectAttrTokenMap = o3tl::make_unique<SvXMLTokenMap>(a3DCubeObjectAttrTokenMap);
298 return *mp3DCubeObjectAttrTokenMap;
301 const SvXMLTokenMap& XMLShapeImportHelper::Get3DSphereObjectAttrTokenMap()
303 if(!mp3DSphereObjectAttrTokenMap)
305 static const SvXMLTokenMapEntry a3DSphereObjectAttrTokenMap[] =
307 { XML_NAMESPACE_DR3D, XML_CENTER, XML_TOK_3DSPHEREOBJ_CENTER },
308 { XML_NAMESPACE_DR3D, XML_SIZE, XML_TOK_3DSPHEREOBJ_SIZE },
309 XML_TOKEN_MAP_END
312 mp3DSphereObjectAttrTokenMap = o3tl::make_unique<SvXMLTokenMap>(a3DSphereObjectAttrTokenMap);
315 return *mp3DSphereObjectAttrTokenMap;
318 const SvXMLTokenMap& XMLShapeImportHelper::Get3DLightAttrTokenMap()
320 if(!mp3DLightAttrTokenMap)
322 static const SvXMLTokenMapEntry a3DLightAttrTokenMap[] =
324 { XML_NAMESPACE_DR3D, XML_DIFFUSE_COLOR, XML_TOK_3DLIGHT_DIFFUSE_COLOR },
325 { XML_NAMESPACE_DR3D, XML_DIRECTION, XML_TOK_3DLIGHT_DIRECTION },
326 { XML_NAMESPACE_DR3D, XML_ENABLED, XML_TOK_3DLIGHT_ENABLED },
327 { XML_NAMESPACE_DR3D, XML_SPECULAR, XML_TOK_3DLIGHT_SPECULAR },
328 XML_TOKEN_MAP_END
331 mp3DLightAttrTokenMap = o3tl::make_unique<SvXMLTokenMap>(a3DLightAttrTokenMap);
334 return *mp3DLightAttrTokenMap;
337 SvXMLShapeContext* XMLShapeImportHelper::Create3DSceneChildContext(
338 SvXMLImport& rImport,
339 sal_uInt16 p_nPrefix,
340 const OUString& rLocalName,
341 const uno::Reference< xml::sax::XAttributeList>& xAttrList,
342 uno::Reference< drawing::XShapes >& rShapes)
344 SdXMLShapeContext *pContext = nullptr;
346 if(rShapes.is())
348 const SvXMLTokenMap& rTokenMap = Get3DSceneShapeElemTokenMap();
349 switch(rTokenMap.Get(p_nPrefix, rLocalName))
351 case XML_TOK_3DSCENE_3DSCENE:
353 // dr3d:3dscene inside dr3d:3dscene context
354 pContext = new SdXML3DSceneShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, false);
355 break;
357 case XML_TOK_3DSCENE_3DCUBE:
359 // dr3d:3dcube inside dr3d:3dscene context
360 pContext = new SdXML3DCubeObjectShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes);
361 break;
363 case XML_TOK_3DSCENE_3DSPHERE:
365 // dr3d:3dsphere inside dr3d:3dscene context
366 pContext = new SdXML3DSphereObjectShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes);
367 break;
369 case XML_TOK_3DSCENE_3DLATHE:
371 // dr3d:3dlathe inside dr3d:3dscene context
372 pContext = new SdXML3DLatheObjectShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes);
373 break;
375 case XML_TOK_3DSCENE_3DEXTRUDE:
377 // dr3d:3dextrude inside dr3d:3dscene context
378 pContext = new SdXML3DExtrudeObjectShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes);
379 break;
384 if (!pContext)
385 return nullptr;
387 // now parse the attribute list and call the child context for each unknown attribute
388 sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
389 for(sal_Int16 a(0); a < nAttrCount; a++)
391 const OUString& rAttrName = xAttrList->getNameByIndex(a);
392 OUString aLocalName;
393 sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName(rAttrName, &aLocalName);
394 const OUString aValue( xAttrList->getValueByIndex(a) );
396 pContext->processAttribute( nPrefix, aLocalName, aValue );
399 return pContext;
402 void XMLShapeImportHelper::SetStylesContext(SvXMLStylesContext* pNew)
404 mxStylesContext.set(pNew);
407 void XMLShapeImportHelper::SetAutoStylesContext(SvXMLStylesContext* pNew)
409 mxAutoStylesContext.set(pNew);
412 SvXMLShapeContext* XMLShapeImportHelper::CreateGroupChildContext(
413 SvXMLImport& rImport,
414 sal_uInt16 p_nPrefix,
415 const OUString& rLocalName,
416 const uno::Reference< xml::sax::XAttributeList>& xAttrList,
417 uno::Reference< drawing::XShapes >& rShapes,
418 bool bTemporaryShape)
420 SdXMLShapeContext *pContext = nullptr;
422 const SvXMLTokenMap& rTokenMap = GetGroupShapeElemTokenMap();
423 sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
425 switch(rTokenMap.Get(p_nPrefix, rLocalName))
427 case XML_TOK_GROUP_GROUP:
429 // draw:g inside group context (RECURSIVE)
430 pContext = new SdXMLGroupShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape);
431 break;
433 case XML_TOK_GROUP_3DSCENE:
435 // dr3d:3dscene inside group context
436 pContext = new SdXML3DSceneShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape);
437 break;
439 case XML_TOK_GROUP_RECT:
441 // draw:rect inside group context
442 pContext = new SdXMLRectShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
443 break;
445 case XML_TOK_GROUP_LINE:
447 // draw:line inside group context
448 pContext = new SdXMLLineShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
449 break;
451 case XML_TOK_GROUP_CIRCLE:
452 case XML_TOK_GROUP_ELLIPSE:
454 // draw:circle or draw:ellipse inside group context
455 pContext = new SdXMLEllipseShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
456 break;
458 case XML_TOK_GROUP_POLYGON:
459 case XML_TOK_GROUP_POLYLINE:
461 // draw:polygon or draw:polyline inside group context
462 pContext = new SdXMLPolygonShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes,
463 rTokenMap.Get(p_nPrefix, rLocalName) == XML_TOK_GROUP_POLYGON, bTemporaryShape );
464 break;
466 case XML_TOK_GROUP_PATH:
468 // draw:path inside group context
469 pContext = new SdXMLPathShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape);
470 break;
472 case XML_TOK_GROUP_FRAME:
474 // text:text-box inside group context
475 pContext = new SdXMLFrameShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
476 break;
478 case XML_TOK_GROUP_CONTROL:
480 // draw:control inside group context
481 pContext = new SdXMLControlShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
482 break;
484 case XML_TOK_GROUP_CONNECTOR:
486 // draw:connector inside group context
487 pContext = new SdXMLConnectorShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
488 break;
490 case XML_TOK_GROUP_MEASURE:
492 // draw:measure inside group context
493 pContext = new SdXMLMeasureShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
494 break;
496 case XML_TOK_GROUP_PAGE:
498 // draw:page inside group context
499 pContext = new SdXMLPageShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
500 break;
502 case XML_TOK_GROUP_CAPTION:
503 case XML_TOK_GROUP_ANNOTATION:
505 // draw:caption inside group context
506 pContext = new SdXMLCaptionShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
507 break;
509 case XML_TOK_GROUP_CHART:
511 // chart:chart inside group context
512 pContext = new SdXMLChartShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
513 break;
515 case XML_TOK_GROUP_CUSTOM_SHAPE:
517 // draw:customshape
518 pContext = new SdXMLCustomShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes );
519 break;
521 case XML_TOK_GROUP_A:
523 return new SdXMLShapeLinkContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes );
525 // add other shapes here...
526 default:
527 return new SvXMLShapeContext( rImport, p_nPrefix, rLocalName, bTemporaryShape );
530 // now parse the attribute list and call the child context for each unknown attribute
531 for(sal_Int16 a(0); a < nAttrCount; a++)
533 const OUString& rAttrName = xAttrList->getNameByIndex(a);
534 OUString aLocalName;
535 sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName(rAttrName, &aLocalName);
536 const OUString aValue( xAttrList->getValueByIndex(a) );
538 pContext->processAttribute( nPrefix, aLocalName, aValue );
541 return pContext;
544 // This method is called from SdXMLFrameShapeContext to create children of draw:frame
545 SvXMLShapeContext* XMLShapeImportHelper::CreateFrameChildContext(
546 SvXMLImport& rImport,
547 sal_uInt16 p_nPrefix,
548 const OUString& rLocalName,
549 const uno::Reference< xml::sax::XAttributeList>& rAttrList,
550 uno::Reference< drawing::XShapes >& rShapes,
551 const uno::Reference< xml::sax::XAttributeList>& rFrameAttrList)
553 SdXMLShapeContext *pContext = nullptr;
555 const SvXMLTokenMap& rTokenMap = GetFrameShapeElemTokenMap();
557 SvXMLAttributeList *pAttrList = new SvXMLAttributeList( rAttrList );
558 if( rFrameAttrList.is() )
559 pAttrList->AppendAttributeList( rFrameAttrList );
560 uno::Reference < xml::sax::XAttributeList > xAttrList = pAttrList;
562 switch(rTokenMap.Get(p_nPrefix, rLocalName))
564 case XML_TOK_FRAME_TEXT_BOX:
566 // text:text-box inside group context
567 pContext = new SdXMLTextBoxShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes );
568 break;
570 case XML_TOK_FRAME_IMAGE:
572 // office:image inside group context
573 pContext = new SdXMLGraphicObjectShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes );
574 break;
576 case XML_TOK_FRAME_OBJECT:
577 case XML_TOK_FRAME_OBJECT_OLE:
579 // draw:object or draw:object_ole
580 pContext = new SdXMLObjectShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes );
581 break;
583 case XML_TOK_FRAME_TABLE:
585 // draw:object or draw:object_ole
586 if( rImport.IsTableShapeSupported() )
587 pContext = new SdXMLTableShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes );
588 break;
591 case XML_TOK_FRAME_PLUGIN:
593 // draw:plugin
594 pContext = new SdXMLPluginShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes );
595 break;
597 case XML_TOK_FRAME_FLOATING_FRAME:
599 // draw:floating-frame
600 pContext = new SdXMLFloatingFrameShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes );
601 break;
603 case XML_TOK_FRAME_APPLET:
605 // draw:applet
606 pContext = new SdXMLAppletShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes );
607 break;
609 // add other shapes here...
610 default:
611 break;
614 if( pContext )
616 // now parse the attribute list and call the child context for each unknown attribute
617 sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
618 for(sal_Int16 a(0); a < nAttrCount; a++)
620 const OUString& rAttrName = xAttrList->getNameByIndex(a);
621 OUString aLocalName;
622 sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName(rAttrName, &aLocalName);
623 const OUString aValue( xAttrList->getValueByIndex(a) );
625 pContext->processAttribute( nPrefix, aLocalName, aValue );
629 return pContext;
632 SvXMLImportContext *XMLShapeImportHelper::CreateFrameChildContext(
633 SvXMLImportContext *pThisContext,
634 sal_uInt16 nPrefix,
635 const OUString& rLocalName,
636 const uno::Reference< xml::sax::XAttributeList>& xAttrList )
638 SvXMLImportContext * pContext = nullptr;
640 SdXMLFrameShapeContext *pFrameContext = dynamic_cast<SdXMLFrameShapeContext*>( pThisContext );
641 if( pFrameContext )
642 pContext = pFrameContext->CreateChildContext( nPrefix, rLocalName, xAttrList );
644 return pContext;
647 /** this function is called whenever the implementation classes like to add this new
648 shape to the given XShapes.
650 void XMLShapeImportHelper::addShape( uno::Reference< drawing::XShape >& rShape,
651 const uno::Reference< xml::sax::XAttributeList >&,
652 uno::Reference< drawing::XShapes >& rShapes)
654 if( rShape.is() && rShapes.is() )
656 // add new shape to parent
657 rShapes->add( rShape );
661 /** this function is called whenever the implementation classes have finished importing
662 a shape to the given XShapes. The shape is already inserted into its XShapes and
663 all properties and styles are set.
665 void XMLShapeImportHelper::finishShape(
666 css::uno::Reference< css::drawing::XShape >& rShape,
667 const css::uno::Reference< css::xml::sax::XAttributeList >&,
668 css::uno::Reference< css::drawing::XShapes >&)
670 /* Set property <PositionLayoutDir>
671 to <PositionInHoriL2R>, if it exists and the import states that
672 the shape positioning attributes are in horizontal left-to-right
673 layout. This is the case for the OpenOffice.org file format.
674 This setting is done for Writer documents, because the property
675 only exists at service css::text::Shape - the Writer
676 UNO service for shapes.
677 The value indicates that the positioning attributes are given
678 in horizontal left-to-right layout. The property is evaluated
679 during the first positioning of the shape in order to convert
680 the shape position given in the OpenOffice.org file format to
681 the one for the OASIS Open Office file format. (#i28749#, #i36248#)
683 uno::Reference< beans::XPropertySet > xPropSet(rShape, uno::UNO_QUERY);
684 if ( xPropSet.is() )
686 if ( mrImporter.IsShapePositionInHoriL2R() &&
687 xPropSet->getPropertySetInfo()->hasPropertyByName(
688 "PositionLayoutDir") )
690 uno::Any aPosLayoutDir;
691 aPosLayoutDir <<= text::PositionLayoutDir::PositionInHoriL2R;
692 xPropSet->setPropertyValue( "PositionLayoutDir", aPosLayoutDir );
697 // helper functions for z-order sorting
698 struct ZOrderHint
700 sal_Int32 nIs;
701 sal_Int32 nShould;
702 /// The hint is for this shape.
703 uno::Reference<drawing::XShape> xShape;
705 bool operator<(const ZOrderHint& rComp) const { return nShould < rComp.nShould; }
708 class ShapeSortContext
710 public:
711 uno::Reference< drawing::XShapes > mxShapes;
712 vector<ZOrderHint> maZOrderList;
713 vector<ZOrderHint> maUnsortedList;
715 sal_Int32 mnCurrentZ;
716 std::shared_ptr<ShapeSortContext> mpParentContext;
718 ShapeSortContext( uno::Reference< drawing::XShapes >& rShapes, std::shared_ptr<ShapeSortContext> pParentContext );
720 void popGroupAndSort();
721 private:
722 void moveShape( sal_Int32 nSourcePos, sal_Int32 nDestPos );
725 ShapeSortContext::ShapeSortContext( uno::Reference< drawing::XShapes >& rShapes, std::shared_ptr<ShapeSortContext> pParentContext )
726 : mxShapes( rShapes ), mnCurrentZ( 0 ), mpParentContext( pParentContext )
730 void ShapeSortContext::moveShape( sal_Int32 nSourcePos, sal_Int32 nDestPos )
732 uno::Any aAny( mxShapes->getByIndex( nSourcePos ) );
733 uno::Reference< beans::XPropertySet > xPropSet;
734 aAny >>= xPropSet;
736 if( xPropSet.is() && xPropSet->getPropertySetInfo()->hasPropertyByName( "ZOrder" ) )
738 xPropSet->setPropertyValue( "ZOrder", uno::Any(nDestPos) );
740 for( ZOrderHint& rHint : maZOrderList )
742 if( rHint.nIs < nSourcePos )
744 DBG_ASSERT(rHint.nIs >= nDestPos, "Shape sorting failed" );
745 rHint.nIs++;
749 for( ZOrderHint& rHint : maUnsortedList )
751 if( rHint.nIs < nSourcePos )
753 SAL_WARN_IF( rHint.nIs < nDestPos, "xmloff", "shape sorting failed" );
754 rHint.nIs++;
760 // sort shapes
761 void ShapeSortContext::popGroupAndSort()
763 // only do something if we have shapes to sort
764 if( maZOrderList.empty() )
765 return;
767 // check if there are more shapes than inserted with ::shapeWithZIndexAdded()
768 // This can happen if there where already shapes on the page before import
769 // Since the writer may delete some of this shapes during import, we need
770 // to do this here and not in our c'tor anymore
772 // check if we have more shapes than we know of
773 sal_Int32 nCount = mxShapes->getCount();
775 nCount -= maZOrderList.size();
776 nCount -= maUnsortedList.size();
778 if( nCount > 0 )
780 // first update offsets of added shapes
781 for (ZOrderHint& rHint : maZOrderList)
782 rHint.nIs += nCount;
783 for (ZOrderHint& rHint : maUnsortedList)
784 rHint.nIs += nCount;
786 // second add the already existing shapes in the unsorted list
787 ZOrderHint aNewHint;
790 nCount--;
792 aNewHint.nIs = nCount;
793 aNewHint.nShould = -1;
795 maUnsortedList.insert(maUnsortedList.begin(), aNewHint);
797 while( nCount );
800 // sort z-ordered shapes by nShould field
801 std::sort(maZOrderList.begin(), maZOrderList.end());
803 // this is the current index, all shapes before that
804 // index are finished
805 sal_Int32 nIndex = 0;
806 for (ZOrderHint& rHint : maZOrderList)
808 for (vector<ZOrderHint>::iterator aIt = maUnsortedList.begin(); aIt != maUnsortedList.end() && nIndex < rHint.nShould; )
810 moveShape( (*aIt).nIs, nIndex++ );
811 aIt = maUnsortedList.erase(aIt);
815 if(rHint.nIs != nIndex )
816 moveShape( rHint.nIs, nIndex );
818 nIndex++;
820 maZOrderList.clear();
823 void XMLShapeImportHelper::pushGroupForSorting( uno::Reference< drawing::XShapes >& rShapes )
825 mpImpl->mpSortContext = std::make_shared<ShapeSortContext>( rShapes, mpImpl->mpSortContext );
828 void XMLShapeImportHelper::popGroupAndSort()
830 SAL_WARN_IF( !mpImpl->mpSortContext, "xmloff", "No context to sort!" );
831 if( !mpImpl->mpSortContext )
832 return;
836 mpImpl->mpSortContext->popGroupAndSort();
838 catch( const uno::Exception& rException )
840 SAL_WARN("xmloff", "exception while sorting shapes, sorting failed: " << rException.Message);
843 // put parent on top and drop current context, we are done
844 mpImpl->mpSortContext = mpImpl->mpSortContext->mpParentContext;
847 void XMLShapeImportHelper::shapeWithZIndexAdded( css::uno::Reference< css::drawing::XShape >& xShape, sal_Int32 nZIndex )
849 if( mpImpl->mpSortContext)
851 ZOrderHint aNewHint;
852 aNewHint.nIs = mpImpl->mpSortContext->mnCurrentZ++;
853 aNewHint.nShould = nZIndex;
854 aNewHint.xShape = xShape;
856 if( nZIndex == -1 )
858 // don't care, so add to unsorted list
859 mpImpl->mpSortContext->maUnsortedList.push_back(aNewHint);
861 else
863 // insert into sort list
864 mpImpl->mpSortContext->maZOrderList.push_back(aNewHint);
869 void XMLShapeImportHelper::shapeRemoved(const uno::Reference<drawing::XShape>& xShape)
871 auto it = std::find_if(mpImpl->mpSortContext->maZOrderList.begin(), mpImpl->mpSortContext->maZOrderList.end(), [&xShape](const ZOrderHint& rHint)
873 return rHint.xShape == xShape;
875 if (it == mpImpl->mpSortContext->maZOrderList.end())
876 // Part of the unsorted list, nothing to do.
877 return;
879 sal_Int32 nZIndex = it->nIs;
881 for (it = mpImpl->mpSortContext->maZOrderList.begin(); it != mpImpl->mpSortContext->maZOrderList.end();)
883 if (it->nIs == nZIndex)
885 // This is xShape: remove it and adjust the max of indexes
886 // accordingly.
887 it = mpImpl->mpSortContext->maZOrderList.erase(it);
888 mpImpl->mpSortContext->mnCurrentZ--;
889 continue;
891 else if (it->nIs > nZIndex)
892 // On top of xShape: adjust actual index to reflect removal.
893 it->nIs--;
895 // On top of or below xShape.
896 ++it;
900 void XMLShapeImportHelper::addShapeConnection( css::uno::Reference< css::drawing::XShape >& rConnectorShape,
901 bool bStart,
902 const OUString& rDestShapeId,
903 sal_Int32 nDestGlueId )
905 ConnectionHint aHint;
906 aHint.mxConnector = rConnectorShape;
907 aHint.bStart = bStart;
908 aHint.aDestShapeId = rDestShapeId;
909 aHint.nDestGlueId = nDestGlueId;
911 mpImpl->maConnections.push_back( aHint );
914 void XMLShapeImportHelper::restoreConnections()
916 if( !mpImpl->maConnections.empty() )
918 const vector<ConnectionHint>::size_type nCount = mpImpl->maConnections.size();
919 for( vector<ConnectionHint>::size_type i = 0; i < nCount; i++ )
921 ConnectionHint& rHint = mpImpl->maConnections[i];
922 uno::Reference< beans::XPropertySet > xConnector( rHint.mxConnector, uno::UNO_QUERY );
923 if( xConnector.is() )
925 // #86637# remember line deltas
926 uno::Any aLine1Delta;
927 uno::Any aLine2Delta;
928 uno::Any aLine3Delta;
929 OUString aStr1("EdgeLine1Delta");
930 OUString aStr2("EdgeLine2Delta");
931 OUString aStr3("EdgeLine3Delta");
932 aLine1Delta = xConnector->getPropertyValue(aStr1);
933 aLine2Delta = xConnector->getPropertyValue(aStr2);
934 aLine3Delta = xConnector->getPropertyValue(aStr3);
936 // #86637# simply setting these values WILL force the connector to do
937 // an new layout promptly. So the line delta values have to be rescued
938 // and restored around connector changes.
939 uno::Reference< drawing::XShape > xShape(
940 mrImporter.getInterfaceToIdentifierMapper().getReference( rHint.aDestShapeId ), uno::UNO_QUERY );
941 if( xShape.is() )
943 xConnector->setPropertyValue( rHint.bStart ? msStartShape : msEndShape, uno::Any(xShape) );
945 sal_Int32 nGlueId = rHint.nDestGlueId < 4 ? rHint.nDestGlueId : getGluePointId( xShape, rHint.nDestGlueId );
946 xConnector->setPropertyValue( rHint.bStart ? msStartGluePointIndex : msEndGluePointIndex, uno::Any(nGlueId) );
949 // #86637# restore line deltas
950 xConnector->setPropertyValue(aStr1, aLine1Delta );
951 xConnector->setPropertyValue(aStr2, aLine2Delta );
952 xConnector->setPropertyValue(aStr3, aLine3Delta );
955 mpImpl->maConnections.clear();
959 SvXMLImportPropertyMapper* XMLShapeImportHelper::CreateShapePropMapper( const uno::Reference< frame::XModel>& rModel, SvXMLImport& rImport )
961 rtl::Reference< XMLPropertyHandlerFactory > xFactory = new XMLSdPropHdlFactory( rModel, rImport );
962 rtl::Reference < XMLPropertySetMapper > xMapper = new XMLShapePropertySetMapper( xFactory, false );
963 SvXMLImportPropertyMapper* pResult = new SvXMLImportPropertyMapper( xMapper, rImport );
965 // chain text attributes
966 pResult->ChainImportMapper( XMLTextImportHelper::CreateParaExtPropMapper( rImport ) );
967 return pResult;
970 /** adds a mapping for a glue point identifier from an xml file to the identifier created after inserting
971 the new glue point into the core. The saved mappings can be retrieved by getGluePointId() */
972 void XMLShapeImportHelper::addGluePointMapping( css::uno::Reference< css::drawing::XShape >& xShape,
973 sal_Int32 nSourceId, sal_Int32 nDestinnationId )
975 if( mpPageContext )
976 mpPageContext->maShapeGluePointsMap[xShape][nSourceId] = nDestinnationId;
979 /** find mapping for given DestinationID. This allows to extract the original draw:id imported with a draw:glue-point */
980 sal_Int32 XMLShapeImportHelper::findGluePointMapping(
981 const css::uno::Reference< css::drawing::XShape >& xShape,
982 sal_Int32 nDestinnationId ) const
984 if( mpPageContext )
986 ShapeGluePointsMap::iterator aShapeIter( mpPageContext->maShapeGluePointsMap.find( xShape ) );
988 if( aShapeIter != mpPageContext->maShapeGluePointsMap.end() )
990 GluePointIdMap::iterator aShapeIdIter = (*aShapeIter).second.begin();
991 GluePointIdMap::iterator aShapeIdEnd = (*aShapeIter).second.end();
993 while ( aShapeIdIter != aShapeIdEnd )
995 if ( (*aShapeIdIter).second == nDestinnationId )
997 return (*aShapeIdIter).first;
1000 ++aShapeIdIter;
1005 return -1;
1008 /** moves all current DestinationId's by n */
1009 void XMLShapeImportHelper::moveGluePointMapping( const css::uno::Reference< css::drawing::XShape >& xShape, const sal_Int32 n )
1011 if( mpPageContext )
1013 ShapeGluePointsMap::iterator aShapeIter( mpPageContext->maShapeGluePointsMap.find( xShape ) );
1014 if( aShapeIter != mpPageContext->maShapeGluePointsMap.end() )
1016 GluePointIdMap::iterator aShapeIdIter = (*aShapeIter).second.begin();
1017 GluePointIdMap::iterator aShapeIdEnd = (*aShapeIter).second.end();
1018 while ( aShapeIdIter != aShapeIdEnd )
1020 if ( (*aShapeIdIter).second != -1 )
1021 (*aShapeIdIter).second += n;
1022 ++aShapeIdIter;
1028 /** retrieves a mapping for a glue point identifier from the current xml file to the identifier created after
1029 inserting the new glue point into the core. The mapping must be initialized first with addGluePointMapping() */
1030 sal_Int32 XMLShapeImportHelper::getGluePointId( const css::uno::Reference< css::drawing::XShape >& xShape, sal_Int32 nSourceId )
1032 if( mpPageContext )
1034 ShapeGluePointsMap::iterator aShapeIter( mpPageContext->maShapeGluePointsMap.find( xShape ) );
1035 if( aShapeIter != mpPageContext->maShapeGluePointsMap.end() )
1037 GluePointIdMap::iterator aIdIter = (*aShapeIter).second.find(nSourceId);
1038 if( aIdIter != (*aShapeIter).second.end() )
1039 return (*aIdIter).second;
1043 return -1;
1046 /** this method must be calling before the first shape is imported for the given page */
1047 void XMLShapeImportHelper::startPage( css::uno::Reference< css::drawing::XShapes >& rShapes )
1049 const std::shared_ptr<XMLShapeImportPageContextImpl> pOldContext = mpPageContext;
1050 mpPageContext = std::make_shared<XMLShapeImportPageContextImpl>();
1051 mpPageContext->mpNext = pOldContext;
1052 mpPageContext->mxShapes = rShapes;
1055 /** this method must be calling after the last shape is imported for the given page */
1056 void XMLShapeImportHelper::endPage( css::uno::Reference< css::drawing::XShapes >& rShapes )
1058 SAL_WARN_IF( !mpPageContext || (mpPageContext->mxShapes != rShapes), "xmloff", "wrong call to endPage(), no startPage called or wrong page" );
1059 if( nullptr == mpPageContext )
1060 return;
1062 restoreConnections();
1064 mpPageContext = mpPageContext->mpNext;
1067 /** defines if the import should increment the progress bar or not */
1068 void XMLShapeImportHelper::enableHandleProgressBar()
1070 mpImpl->mbHandleProgressBar = true;
1073 bool XMLShapeImportHelper::IsHandleProgressBarEnabled() const
1075 return mpImpl->mbHandleProgressBar;
1078 /** queries the capability of the current model to create presentation shapes */
1079 bool XMLShapeImportHelper::IsPresentationShapesSupported()
1081 return mpImpl->mbIsPresentationShapesSupported;
1084 const rtl::Reference< XMLTableImport >& XMLShapeImportHelper::GetShapeTableImport()
1086 if( !mxShapeTableImport.is() )
1088 rtl::Reference< XMLPropertyHandlerFactory > xFactory( new XMLSdPropHdlFactory( mrImporter.GetModel(), mrImporter ) );
1089 rtl::Reference< XMLPropertySetMapper > xPropertySetMapper( new XMLShapePropertySetMapper( xFactory.get(), false ) );
1090 mxShapeTableImport = new XMLTableImport( mrImporter, xPropertySetMapper, xFactory );
1093 return mxShapeTableImport;
1096 void SvXMLShapeContext::setHyperlink( const OUString& rHyperlink )
1098 msHyperlink = rHyperlink;
1101 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */