nss: upgrade to release 3.73
[LibreOffice.git] / xmloff / source / draw / shapeimport.cxx
blob2a2d5e137eb4b3699757efdf12bf1ab29d296244
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 <tools/debug.hxx>
21 #include <tools/diagnose_ex.h>
22 #include <sal/log.hxx>
24 #include <com/sun/star/beans/XPropertySet.hpp>
25 #include <com/sun/star/text/PositionLayoutDir.hpp>
26 #include <com/sun/star/drawing/XShapes3.hpp>
28 #include <utility>
29 #include <xmloff/unointerfacetouniqueidentifiermapper.hxx>
31 #include <xmloff/shapeimport.hxx>
32 #include <xmloff/xmlstyle.hxx>
33 #include <xmloff/xmltkmap.hxx>
34 #include <xmloff/xmlnamespace.hxx>
35 #include <xmloff/xmltoken.hxx>
36 #include <xmloff/table/XMLTableImport.hxx>
37 #include <xmloff/attrlist.hxx>
38 #include "eventimp.hxx"
39 #include "ximpshap.hxx"
40 #include "sdpropls.hxx"
41 #include <xmloff/xmlprmap.hxx>
42 #include "ximp3dscene.hxx"
43 #include "ximp3dobject.hxx"
44 #include "ximpgrp.hxx"
45 #include "ximplink.hxx"
47 #include <map>
48 #include <string_view>
49 #include <vector>
51 namespace {
53 class ShapeGroupContext;
57 using namespace ::std;
58 using namespace ::com::sun::star;
59 using namespace ::xmloff::token;
61 namespace {
63 struct ConnectionHint
65 css::uno::Reference< css::drawing::XShape > mxConnector;
66 bool bStart;
67 OUString aDestShapeId;
68 sal_Int32 nDestGlueId;
71 struct XShapeCompareHelper
73 bool operator()(const css::uno::Reference < css::drawing::XShape >& x1,
74 const css::uno::Reference < css::drawing::XShape >& x2 ) const
76 return x1.get() < x2.get();
82 /** this map store all glue point id mappings for shapes that had user defined glue points. This
83 is needed because on insertion the glue points will get a new and unique id */
84 typedef std::map<sal_Int32,sal_Int32> GluePointIdMap;
85 typedef std::map< css::uno::Reference < css::drawing::XShape >, GluePointIdMap, XShapeCompareHelper > ShapeGluePointsMap;
87 /** this struct is created for each startPage() call and stores information that is needed during
88 import of shapes for one page. Since pages could be nested ( notes pages inside impress ) there
89 is a pointer so one can build up a stack of this structs */
90 struct XMLShapeImportPageContextImpl
92 ShapeGluePointsMap maShapeGluePointsMap;
94 uno::Reference < drawing::XShapes > mxShapes;
96 std::shared_ptr<XMLShapeImportPageContextImpl> mpNext;
99 /** this class is to enable adding members to the XMLShapeImportHelper without getting incompatible */
100 struct XMLShapeImportHelperImpl
102 // context for sorting shapes
103 std::shared_ptr<ShapeGroupContext> mpGroupContext;
105 std::vector<ConnectionHint> maConnections;
107 // #88546# possibility to switch progress bar handling on/off
108 bool mbHandleProgressBar;
110 // stores the capability of the current model to create presentation shapes
111 bool mbIsPresentationShapesSupported;
114 const std::u16string_view gsStartShape(u"StartShape");
115 const std::u16string_view gsEndShape(u"EndShape");
116 const std::u16string_view gsStartGluePointIndex(u"StartGluePointIndex");
117 const std::u16string_view gsEndGluePointIndex(u"EndGluePointIndex");
119 XMLShapeImportHelper::XMLShapeImportHelper(
120 SvXMLImport& rImporter,
121 const uno::Reference< frame::XModel>& rModel,
122 SvXMLImportPropertyMapper *pExtMapper )
123 : mpImpl( new XMLShapeImportHelperImpl ),
124 mrImporter( rImporter )
126 mpImpl->mpGroupContext = nullptr;
128 // #88546# init to sal_False
129 mpImpl->mbHandleProgressBar = false;
131 mpSdPropHdlFactory = new XMLSdPropHdlFactory( rModel, rImporter );
133 // construct PropertySetMapper
134 rtl::Reference < XMLPropertySetMapper > xMapper = new XMLShapePropertySetMapper(mpSdPropHdlFactory.get(), false);
135 mpPropertySetMapper = new SvXMLImportPropertyMapper( xMapper, rImporter );
137 if( pExtMapper )
139 rtl::Reference < SvXMLImportPropertyMapper > xExtMapper( pExtMapper );
140 mpPropertySetMapper->ChainImportMapper( xExtMapper );
143 // chain text attributes
144 mpPropertySetMapper->ChainImportMapper(XMLTextImportHelper::CreateParaExtPropMapper(rImporter));
145 mpPropertySetMapper->ChainImportMapper(XMLTextImportHelper::CreateParaDefaultExtPropMapper(rImporter));
147 // construct PresPagePropsMapper
148 xMapper = new XMLPropertySetMapper(aXMLSDPresPageProps, mpSdPropHdlFactory.get(), false);
149 mpPresPagePropsMapper = new SvXMLImportPropertyMapper( xMapper, rImporter );
151 uno::Reference< lang::XServiceInfo > xInfo( rImporter.GetModel(), uno::UNO_QUERY );
152 mpImpl->mbIsPresentationShapesSupported = xInfo.is() && xInfo->supportsService( "com.sun.star.presentation.PresentationDocument" );
155 XMLShapeImportHelper::~XMLShapeImportHelper()
157 SAL_WARN_IF( !mpImpl->maConnections.empty(), "xmloff", "XMLShapeImportHelper::restoreConnections() was not called!" );
159 // cleanup factory, decrease refcount. Should lead to destruction.
160 mpSdPropHdlFactory.clear();
162 // cleanup mapper, decrease refcount. Should lead to destruction.
163 mpPropertySetMapper.clear();
165 // cleanup presPage mapper, decrease refcount. Should lead to destruction.
166 mpPresPagePropsMapper.clear();
168 // Styles or AutoStyles context?
169 if(mxStylesContext.is())
170 mxStylesContext->dispose();
172 if(mxAutoStylesContext.is())
173 mxAutoStylesContext->dispose();
176 const SvXMLTokenMap& XMLShapeImportHelper::GetGroupShapeElemTokenMap()
178 if(!mpGroupShapeElemTokenMap)
180 static const SvXMLTokenMapEntry aGroupShapeElemTokenMap[] =
182 { XML_NAMESPACE_DRAW, XML_G, XML_TOK_GROUP_GROUP },
183 { XML_NAMESPACE_DRAW, XML_RECT, XML_TOK_GROUP_RECT },
184 { XML_NAMESPACE_DRAW, XML_LINE, XML_TOK_GROUP_LINE },
185 { XML_NAMESPACE_DRAW, XML_CIRCLE, XML_TOK_GROUP_CIRCLE },
186 { XML_NAMESPACE_DRAW, XML_ELLIPSE, XML_TOK_GROUP_ELLIPSE },
187 { XML_NAMESPACE_DRAW, XML_POLYGON, XML_TOK_GROUP_POLYGON },
188 { XML_NAMESPACE_DRAW, XML_POLYLINE, XML_TOK_GROUP_POLYLINE },
189 { XML_NAMESPACE_DRAW, XML_PATH, XML_TOK_GROUP_PATH },
191 { XML_NAMESPACE_DRAW, XML_CONTROL, XML_TOK_GROUP_CONTROL },
192 { XML_NAMESPACE_DRAW, XML_CONNECTOR, XML_TOK_GROUP_CONNECTOR },
193 { XML_NAMESPACE_DRAW, XML_MEASURE, XML_TOK_GROUP_MEASURE },
194 { XML_NAMESPACE_DRAW, XML_PAGE_THUMBNAIL, XML_TOK_GROUP_PAGE },
195 { XML_NAMESPACE_DRAW, XML_CAPTION, XML_TOK_GROUP_CAPTION },
197 { XML_NAMESPACE_CHART, XML_CHART, XML_TOK_GROUP_CHART },
198 { XML_NAMESPACE_DR3D, XML_SCENE, XML_TOK_GROUP_3DSCENE },
200 { XML_NAMESPACE_DRAW, XML_FRAME, XML_TOK_GROUP_FRAME },
202 { XML_NAMESPACE_DRAW, XML_CUSTOM_SHAPE, XML_TOK_GROUP_CUSTOM_SHAPE },
203 { XML_NAMESPACE_OFFICE, XML_ANNOTATION, XML_TOK_GROUP_ANNOTATION },
204 { XML_NAMESPACE_DRAW, XML_A, XML_TOK_GROUP_A },
206 XML_TOKEN_MAP_END
209 mpGroupShapeElemTokenMap = std::make_unique<SvXMLTokenMap>(aGroupShapeElemTokenMap);
212 return *mpGroupShapeElemTokenMap;
215 const SvXMLTokenMap& XMLShapeImportHelper::GetFrameShapeElemTokenMap()
217 if(!mpFrameShapeElemTokenMap)
219 static const SvXMLTokenMapEntry aFrameShapeElemTokenMap[] =
221 { XML_NAMESPACE_DRAW, XML_TEXT_BOX, XML_TOK_FRAME_TEXT_BOX },
222 { XML_NAMESPACE_DRAW, XML_IMAGE, XML_TOK_FRAME_IMAGE },
223 { XML_NAMESPACE_DRAW, XML_OBJECT, XML_TOK_FRAME_OBJECT },
224 { XML_NAMESPACE_DRAW, XML_OBJECT_OLE, XML_TOK_FRAME_OBJECT_OLE },
225 { XML_NAMESPACE_DRAW, XML_PLUGIN, XML_TOK_FRAME_PLUGIN },
226 { XML_NAMESPACE_DRAW, XML_FLOATING_FRAME, XML_TOK_FRAME_FLOATING_FRAME},
227 { XML_NAMESPACE_DRAW, XML_APPLET, XML_TOK_FRAME_APPLET },
228 { XML_NAMESPACE_TABLE, XML_TABLE, XML_TOK_FRAME_TABLE },
229 XML_TOKEN_MAP_END
232 mpFrameShapeElemTokenMap = std::make_unique<SvXMLTokenMap>(aFrameShapeElemTokenMap);
235 return *mpFrameShapeElemTokenMap;
238 const SvXMLTokenMap& XMLShapeImportHelper::Get3DSceneShapeElemTokenMap()
240 if(!mp3DSceneShapeElemTokenMap)
242 static const SvXMLTokenMapEntry a3DSceneShapeElemTokenMap[] =
244 { XML_NAMESPACE_DR3D, XML_SCENE, XML_TOK_3DSCENE_3DSCENE },
245 { XML_NAMESPACE_DR3D, XML_CUBE, XML_TOK_3DSCENE_3DCUBE },
246 { XML_NAMESPACE_DR3D, XML_SPHERE, XML_TOK_3DSCENE_3DSPHERE },
247 { XML_NAMESPACE_DR3D, XML_ROTATE, XML_TOK_3DSCENE_3DLATHE },
248 { XML_NAMESPACE_DR3D, XML_EXTRUDE, XML_TOK_3DSCENE_3DEXTRUDE },
249 XML_TOKEN_MAP_END
252 mp3DSceneShapeElemTokenMap = std::make_unique<SvXMLTokenMap>(a3DSceneShapeElemTokenMap);
255 return *mp3DSceneShapeElemTokenMap;
258 const SvXMLTokenMap& XMLShapeImportHelper::Get3DObjectAttrTokenMap()
260 if(!mp3DObjectAttrTokenMap)
262 static const SvXMLTokenMapEntry a3DObjectAttrTokenMap[] =
264 { XML_NAMESPACE_DRAW, XML_STYLE_NAME, XML_TOK_3DOBJECT_DRAWSTYLE_NAME },
265 { XML_NAMESPACE_DR3D, XML_TRANSFORM, XML_TOK_3DOBJECT_TRANSFORM },
266 XML_TOKEN_MAP_END
269 mp3DObjectAttrTokenMap = std::make_unique<SvXMLTokenMap>(a3DObjectAttrTokenMap);
272 return *mp3DObjectAttrTokenMap;
275 const SvXMLTokenMap& XMLShapeImportHelper::Get3DPolygonBasedAttrTokenMap()
277 if(!mp3DPolygonBasedAttrTokenMap)
279 static const SvXMLTokenMapEntry a3DPolygonBasedAttrTokenMap[] =
281 { XML_NAMESPACE_SVG, XML_VIEWBOX, XML_TOK_3DPOLYGONBASED_VIEWBOX },
282 { XML_NAMESPACE_SVG, XML_D, XML_TOK_3DPOLYGONBASED_D },
283 XML_TOKEN_MAP_END
286 mp3DPolygonBasedAttrTokenMap = std::make_unique<SvXMLTokenMap>(a3DPolygonBasedAttrTokenMap);
289 return *mp3DPolygonBasedAttrTokenMap;
292 const SvXMLTokenMap& XMLShapeImportHelper::Get3DCubeObjectAttrTokenMap()
294 if(!mp3DCubeObjectAttrTokenMap)
296 static const SvXMLTokenMapEntry a3DCubeObjectAttrTokenMap[] =
298 { XML_NAMESPACE_DR3D, XML_MIN_EDGE, XML_TOK_3DCUBEOBJ_MINEDGE },
299 { XML_NAMESPACE_DR3D, XML_MAX_EDGE, XML_TOK_3DCUBEOBJ_MAXEDGE },
300 XML_TOKEN_MAP_END
303 mp3DCubeObjectAttrTokenMap = std::make_unique<SvXMLTokenMap>(a3DCubeObjectAttrTokenMap);
306 return *mp3DCubeObjectAttrTokenMap;
309 const SvXMLTokenMap& XMLShapeImportHelper::Get3DSphereObjectAttrTokenMap()
311 if(!mp3DSphereObjectAttrTokenMap)
313 static const SvXMLTokenMapEntry a3DSphereObjectAttrTokenMap[] =
315 { XML_NAMESPACE_DR3D, XML_CENTER, XML_TOK_3DSPHEREOBJ_CENTER },
316 { XML_NAMESPACE_DR3D, XML_SIZE, XML_TOK_3DSPHEREOBJ_SIZE },
317 XML_TOKEN_MAP_END
320 mp3DSphereObjectAttrTokenMap = std::make_unique<SvXMLTokenMap>(a3DSphereObjectAttrTokenMap);
323 return *mp3DSphereObjectAttrTokenMap;
326 const SvXMLTokenMap& XMLShapeImportHelper::Get3DLightAttrTokenMap()
328 if(!mp3DLightAttrTokenMap)
330 static const SvXMLTokenMapEntry a3DLightAttrTokenMap[] =
332 { XML_NAMESPACE_DR3D, XML_DIFFUSE_COLOR, XML_TOK_3DLIGHT_DIFFUSE_COLOR },
333 { XML_NAMESPACE_DR3D, XML_DIRECTION, XML_TOK_3DLIGHT_DIRECTION },
334 { XML_NAMESPACE_DR3D, XML_ENABLED, XML_TOK_3DLIGHT_ENABLED },
335 { XML_NAMESPACE_DR3D, XML_SPECULAR, XML_TOK_3DLIGHT_SPECULAR },
336 XML_TOKEN_MAP_END
339 mp3DLightAttrTokenMap = std::make_unique<SvXMLTokenMap>(a3DLightAttrTokenMap);
342 return *mp3DLightAttrTokenMap;
345 SvXMLShapeContext* XMLShapeImportHelper::Create3DSceneChildContext(
346 SvXMLImport& rImport,
347 sal_uInt16 p_nPrefix,
348 const OUString& rLocalName,
349 const uno::Reference< xml::sax::XAttributeList>& xAttrList,
350 uno::Reference< drawing::XShapes > const & rShapes)
352 SdXMLShapeContext *pContext = nullptr;
354 if(rShapes.is())
356 const SvXMLTokenMap& rTokenMap = Get3DSceneShapeElemTokenMap();
357 switch(rTokenMap.Get(p_nPrefix, rLocalName))
359 case XML_TOK_3DSCENE_3DSCENE:
361 // dr3d:3dscene inside dr3d:3dscene context
362 pContext = new SdXML3DSceneShapeContext( rImport, xAttrList, rShapes, false);
363 break;
365 case XML_TOK_3DSCENE_3DCUBE:
367 // dr3d:3dcube inside dr3d:3dscene context
368 pContext = new SdXML3DCubeObjectShapeContext( rImport, xAttrList, rShapes);
369 break;
371 case XML_TOK_3DSCENE_3DSPHERE:
373 // dr3d:3dsphere inside dr3d:3dscene context
374 pContext = new SdXML3DSphereObjectShapeContext( rImport, xAttrList, rShapes);
375 break;
377 case XML_TOK_3DSCENE_3DLATHE:
379 // dr3d:3dlathe inside dr3d:3dscene context
380 pContext = new SdXML3DLatheObjectShapeContext( rImport, xAttrList, rShapes);
381 break;
383 case XML_TOK_3DSCENE_3DEXTRUDE:
385 // dr3d:3dextrude inside dr3d:3dscene context
386 pContext = new SdXML3DExtrudeObjectShapeContext( rImport, xAttrList, rShapes);
387 break;
392 if (!pContext)
393 return nullptr;
395 // now parse the attribute list and call the child context for each unknown attribute
396 sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
397 for(sal_Int16 a(0); a < nAttrCount; a++)
399 const OUString& rAttrName = xAttrList->getNameByIndex(a);
400 OUString aLocalName;
401 sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName(rAttrName, &aLocalName);
402 const OUString aValue( xAttrList->getValueByIndex(a) );
404 pContext->processAttribute( nPrefix, aLocalName, aValue );
407 return pContext;
410 void XMLShapeImportHelper::SetStylesContext(SvXMLStylesContext* pNew)
412 mxStylesContext.set(pNew);
415 void XMLShapeImportHelper::SetAutoStylesContext(SvXMLStylesContext* pNew)
417 mxAutoStylesContext.set(pNew);
420 SvXMLShapeContext* XMLShapeImportHelper::CreateGroupChildContext(
421 SvXMLImport& rImport,
422 sal_uInt16 p_nPrefix,
423 const OUString& rLocalName,
424 const uno::Reference< xml::sax::XAttributeList>& xAttrList,
425 uno::Reference< drawing::XShapes > const & rShapes,
426 bool bTemporaryShape)
428 SdXMLShapeContext *pContext = nullptr;
430 const SvXMLTokenMap& rTokenMap = GetGroupShapeElemTokenMap();
431 sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
433 switch(rTokenMap.Get(p_nPrefix, rLocalName))
435 case XML_TOK_GROUP_GROUP:
437 // draw:g inside group context (RECURSIVE)
438 pContext = new SdXMLGroupShapeContext( rImport, xAttrList, rShapes, bTemporaryShape);
439 break;
441 case XML_TOK_GROUP_3DSCENE:
443 // dr3d:3dscene inside group context
444 pContext = new SdXML3DSceneShapeContext( rImport, xAttrList, rShapes, bTemporaryShape);
445 break;
447 case XML_TOK_GROUP_RECT:
449 // draw:rect inside group context
450 pContext = new SdXMLRectShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
451 break;
453 case XML_TOK_GROUP_LINE:
455 // draw:line inside group context
456 pContext = new SdXMLLineShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
457 break;
459 case XML_TOK_GROUP_CIRCLE:
460 case XML_TOK_GROUP_ELLIPSE:
462 // draw:circle or draw:ellipse inside group context
463 pContext = new SdXMLEllipseShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
464 break;
466 case XML_TOK_GROUP_POLYGON:
467 case XML_TOK_GROUP_POLYLINE:
469 // draw:polygon or draw:polyline inside group context
470 pContext = new SdXMLPolygonShapeContext( rImport, xAttrList, rShapes,
471 rTokenMap.Get(p_nPrefix, rLocalName) == XML_TOK_GROUP_POLYGON, bTemporaryShape );
472 break;
474 case XML_TOK_GROUP_PATH:
476 // draw:path inside group context
477 pContext = new SdXMLPathShapeContext( rImport, xAttrList, rShapes, bTemporaryShape);
478 break;
480 case XML_TOK_GROUP_FRAME:
482 // text:text-box inside group context
483 pContext = new SdXMLFrameShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
484 break;
486 case XML_TOK_GROUP_CONTROL:
488 // draw:control inside group context
489 pContext = new SdXMLControlShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
490 break;
492 case XML_TOK_GROUP_CONNECTOR:
494 // draw:connector inside group context
495 pContext = new SdXMLConnectorShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
496 break;
498 case XML_TOK_GROUP_MEASURE:
500 // draw:measure inside group context
501 pContext = new SdXMLMeasureShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
502 break;
504 case XML_TOK_GROUP_PAGE:
506 // draw:page inside group context
507 pContext = new SdXMLPageShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
508 break;
510 case XML_TOK_GROUP_CAPTION:
511 case XML_TOK_GROUP_ANNOTATION:
513 // draw:caption inside group context
514 pContext = new SdXMLCaptionShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
515 break;
517 case XML_TOK_GROUP_CHART:
519 // chart:chart inside group context
520 pContext = new SdXMLChartShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
521 break;
523 case XML_TOK_GROUP_CUSTOM_SHAPE:
525 // draw:customshape
526 pContext = new SdXMLCustomShapeContext( rImport, xAttrList, rShapes );
527 break;
529 case XML_TOK_GROUP_A:
531 return new SdXMLShapeLinkContext( rImport, xAttrList, rShapes );
533 // add other shapes here...
534 default:
535 return new SvXMLShapeContext( rImport, bTemporaryShape );
538 // now parse the attribute list and call the child context for each unknown attribute
539 for(sal_Int16 a(0); a < nAttrCount; a++)
541 const OUString& rAttrName = xAttrList->getNameByIndex(a);
542 OUString aLocalName;
543 sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName(rAttrName, &aLocalName);
544 const OUString aValue( xAttrList->getValueByIndex(a) );
546 pContext->processAttribute( nPrefix, aLocalName, aValue );
549 return pContext;
552 // This method is called from SdXMLFrameShapeContext to create children of draw:frame
553 SvXMLShapeContext* XMLShapeImportHelper::CreateFrameChildContext(
554 SvXMLImport& rImport,
555 sal_uInt16 p_nPrefix,
556 const OUString& rLocalName,
557 const uno::Reference< xml::sax::XAttributeList>& rAttrList,
558 uno::Reference< drawing::XShapes > const & rShapes,
559 const uno::Reference< xml::sax::XAttributeList>& rFrameAttrList)
561 SdXMLShapeContext *pContext = nullptr;
563 const SvXMLTokenMap& rTokenMap = GetFrameShapeElemTokenMap();
565 SvXMLAttributeList *pAttrList = new SvXMLAttributeList( rAttrList );
566 if( rFrameAttrList.is() )
567 pAttrList->AppendAttributeList( rFrameAttrList );
568 uno::Reference < xml::sax::XAttributeList > xAttrList = pAttrList;
570 switch(rTokenMap.Get(p_nPrefix, rLocalName))
572 case XML_TOK_FRAME_TEXT_BOX:
574 // text:text-box inside group context
575 pContext = new SdXMLTextBoxShapeContext( rImport, xAttrList, rShapes );
576 break;
578 case XML_TOK_FRAME_IMAGE:
580 // office:image inside group context
581 pContext = new SdXMLGraphicObjectShapeContext( rImport, xAttrList, rShapes );
582 break;
584 case XML_TOK_FRAME_OBJECT:
585 case XML_TOK_FRAME_OBJECT_OLE:
587 // draw:object or draw:object_ole
588 pContext = new SdXMLObjectShapeContext( rImport, xAttrList, rShapes );
589 break;
591 case XML_TOK_FRAME_TABLE:
593 // draw:object or draw:object_ole
594 if( rImport.IsTableShapeSupported() )
595 pContext = new SdXMLTableShapeContext( rImport, xAttrList, rShapes );
596 break;
599 case XML_TOK_FRAME_PLUGIN:
601 // draw:plugin
602 pContext = new SdXMLPluginShapeContext( rImport, xAttrList, rShapes );
603 break;
605 case XML_TOK_FRAME_FLOATING_FRAME:
607 // draw:floating-frame
608 pContext = new SdXMLFloatingFrameShapeContext( rImport, xAttrList, rShapes );
609 break;
611 case XML_TOK_FRAME_APPLET:
613 // draw:applet
614 pContext = new SdXMLAppletShapeContext( rImport, xAttrList, rShapes );
615 break;
617 // add other shapes here...
618 default:
619 break;
622 if( pContext )
624 // now parse the attribute list and call the child context for each unknown attribute
625 sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
626 for(sal_Int16 a(0); a < nAttrCount; a++)
628 const OUString& rAttrName = xAttrList->getNameByIndex(a);
629 OUString aLocalName;
630 sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName(rAttrName, &aLocalName);
631 const OUString aValue( xAttrList->getValueByIndex(a) );
633 pContext->processAttribute( nPrefix, aLocalName, aValue );
637 return pContext;
640 SvXMLImportContextRef XMLShapeImportHelper::CreateFrameChildContext(
641 SvXMLImportContext *pThisContext,
642 sal_uInt16 nPrefix,
643 const OUString& rLocalName,
644 const uno::Reference< xml::sax::XAttributeList>& xAttrList )
646 SvXMLImportContextRef xContext;
648 SdXMLFrameShapeContext *pFrameContext = dynamic_cast<SdXMLFrameShapeContext*>( pThisContext );
649 if (pFrameContext)
650 xContext = pFrameContext->CreateChildContext( nPrefix, rLocalName, xAttrList );
652 return xContext;
655 /** this function is called whenever the implementation classes like to add this new
656 shape to the given XShapes.
658 void XMLShapeImportHelper::addShape( uno::Reference< drawing::XShape >& rShape,
659 const uno::Reference< xml::sax::XAttributeList >&,
660 uno::Reference< drawing::XShapes >& rShapes)
662 if( rShape.is() && rShapes.is() )
664 // add new shape to parent
665 rShapes->add( rShape );
669 /** this function is called whenever the implementation classes have finished importing
670 a shape to the given XShapes. The shape is already inserted into its XShapes and
671 all properties and styles are set.
673 void XMLShapeImportHelper::finishShape(
674 css::uno::Reference< css::drawing::XShape >& rShape,
675 const css::uno::Reference< css::xml::sax::XAttributeList >&,
676 css::uno::Reference< css::drawing::XShapes >&)
678 /* Set property <PositionLayoutDir>
679 to <PositionInHoriL2R>, if it exists and the import states that
680 the shape positioning attributes are in horizontal left-to-right
681 layout. This is the case for the OpenOffice.org file format.
682 This setting is done for Writer documents, because the property
683 only exists at service css::text::Shape - the Writer
684 UNO service for shapes.
685 The value indicates that the positioning attributes are given
686 in horizontal left-to-right layout. The property is evaluated
687 during the first positioning of the shape in order to convert
688 the shape position given in the OpenOffice.org file format to
689 the one for the OASIS Open Office file format. (#i28749#, #i36248#)
691 uno::Reference< beans::XPropertySet > xPropSet(rShape, uno::UNO_QUERY);
692 if ( xPropSet.is() )
694 if ( mrImporter.IsShapePositionInHoriL2R() &&
695 xPropSet->getPropertySetInfo()->hasPropertyByName(
696 "PositionLayoutDir") )
698 uno::Any aPosLayoutDir;
699 aPosLayoutDir <<= text::PositionLayoutDir::PositionInHoriL2R;
700 xPropSet->setPropertyValue( "PositionLayoutDir", aPosLayoutDir );
705 namespace {
707 // helper functions for z-order sorting
708 struct ZOrderHint
710 sal_Int32 nIs;
711 sal_Int32 nShould;
712 /// The hint is for this shape.
713 uno::Reference<drawing::XShape> xShape;
715 bool operator<(const ZOrderHint& rComp) const { return nShould < rComp.nShould; }
718 // a) handle z-order of group contents after it has been imported
719 // b) apply group events over group contents after it has been imported
720 class ShapeGroupContext
722 public:
723 uno::Reference< drawing::XShapes > mxShapes;
724 std::vector<SdXMLEventContextData> maEventData;
725 vector<ZOrderHint> maZOrderList;
726 vector<ZOrderHint> maUnsortedList;
728 sal_Int32 mnCurrentZ;
729 std::shared_ptr<ShapeGroupContext> mpParentContext;
731 ShapeGroupContext( uno::Reference< drawing::XShapes > const & rShapes, std::shared_ptr<ShapeGroupContext> pParentContext );
733 void popGroupAndPostProcess();
734 private:
735 void moveShape( sal_Int32 nSourcePos, sal_Int32 nDestPos );
740 ShapeGroupContext::ShapeGroupContext( uno::Reference< drawing::XShapes > const & rShapes, std::shared_ptr<ShapeGroupContext> pParentContext )
741 : mxShapes( rShapes ), mnCurrentZ( 0 ), mpParentContext( std::move(pParentContext) )
745 void ShapeGroupContext::moveShape( sal_Int32 nSourcePos, sal_Int32 nDestPos )
747 uno::Any aAny( mxShapes->getByIndex( nSourcePos ) );
748 uno::Reference< beans::XPropertySet > xPropSet;
749 aAny >>= xPropSet;
751 if( !(xPropSet.is() && xPropSet->getPropertySetInfo()->hasPropertyByName( "ZOrder" )) )
752 return;
754 xPropSet->setPropertyValue( "ZOrder", uno::Any(nDestPos) );
756 for( ZOrderHint& rHint : maZOrderList )
758 if( rHint.nIs < nSourcePos )
760 DBG_ASSERT(rHint.nIs >= nDestPos, "Shape sorting failed" );
761 rHint.nIs++;
765 for( ZOrderHint& rHint : maUnsortedList )
767 if( rHint.nIs < nSourcePos )
769 SAL_WARN_IF( rHint.nIs < nDestPos, "xmloff", "shape sorting failed" );
770 rHint.nIs++;
775 // sort shapes
776 void ShapeGroupContext::popGroupAndPostProcess()
778 if (!maEventData.empty())
780 // tdf#127791 wait until a group is popped to set its event data
781 for (auto& event : maEventData)
782 event.ApplyProperties();
783 maEventData.clear();
786 // only do something if we have shapes to sort
787 if( maZOrderList.empty() )
788 return;
790 // check if there are more shapes than inserted with ::shapeWithZIndexAdded()
791 // This can happen if there where already shapes on the page before import
792 // Since the writer may delete some of this shapes during import, we need
793 // to do this here and not in our c'tor anymore
795 // check if we have more shapes than we know of
796 sal_Int32 nCount = mxShapes->getCount();
798 nCount -= maZOrderList.size();
799 nCount -= maUnsortedList.size();
801 if( nCount > 0 )
803 // first update offsets of added shapes
804 for (ZOrderHint& rHint : maZOrderList)
805 rHint.nIs += nCount;
806 for (ZOrderHint& rHint : maUnsortedList)
807 rHint.nIs += nCount;
809 // second add the already existing shapes in the unsorted list
810 ZOrderHint aNewHint;
813 nCount--;
815 aNewHint.nIs = nCount;
816 aNewHint.nShould = -1;
818 maUnsortedList.insert(maUnsortedList.begin(), aNewHint);
820 while( nCount );
823 bool bSorted = std::is_sorted(maZOrderList.begin(), maZOrderList.end(),
824 [&](const ZOrderHint& rLeft, const ZOrderHint& rRight)
825 { return rLeft.nShould < rRight.nShould; } );
827 if (bSorted)
828 return; // nothin' to do
830 // sort z-ordered shapes by nShould field
831 std::sort(maZOrderList.begin(), maZOrderList.end());
833 uno::Reference<drawing::XShapes3> xShapes3(mxShapes, uno::UNO_QUERY);
834 if( xShapes3.is())
836 uno::Sequence<sal_Int32> aNewOrder(maZOrderList.size() + maUnsortedList.size());
837 sal_Int32 nIndex = 0;
839 for (ZOrderHint& rHint : maZOrderList)
841 // fill in the gaps from unordered list
842 for (vector<ZOrderHint>::iterator aIt = maUnsortedList.begin(); aIt != maUnsortedList.end() && nIndex < rHint.nShould; )
844 aNewOrder[nIndex++] = (*aIt).nIs;
845 aIt = maUnsortedList.erase(aIt);
848 aNewOrder[nIndex] = rHint.nIs;
849 nIndex++;
854 xShapes3->sort(aNewOrder);
855 maZOrderList.clear();
856 return;
858 catch (const css::lang::IllegalArgumentException& /*e*/)
862 // this is the current index, all shapes before that
863 // index are finished
864 sal_Int32 nIndex = 0;
865 for (const ZOrderHint& rHint : maZOrderList)
867 for (vector<ZOrderHint>::iterator aIt = maUnsortedList.begin(); aIt != maUnsortedList.end() && nIndex < rHint.nShould; )
869 moveShape( (*aIt).nIs, nIndex++ );
870 aIt = maUnsortedList.erase(aIt);
874 if(rHint.nIs != nIndex )
875 moveShape( rHint.nIs, nIndex );
877 nIndex++;
879 maZOrderList.clear();
882 void XMLShapeImportHelper::pushGroupForPostProcessing( uno::Reference< drawing::XShapes >& rShapes )
884 mpImpl->mpGroupContext = std::make_shared<ShapeGroupContext>( rShapes, mpImpl->mpGroupContext );
887 void XMLShapeImportHelper::addShapeEvents(SdXMLEventContextData& rData)
889 if (mpImpl->mpGroupContext && mpImpl->mpGroupContext->mxShapes == rData.mxShape)
891 // tdf#127791 wait until a group is popped to set its event data so
892 // that the events are applied to all its children, which are not available
893 // at the start of the group tag
894 mpImpl->mpGroupContext->maEventData.push_back(rData);
896 else
897 rData.ApplyProperties();
900 void XMLShapeImportHelper::popGroupAndPostProcess()
902 SAL_WARN_IF( !mpImpl->mpGroupContext, "xmloff", "No context to sort!" );
903 if( !mpImpl->mpGroupContext )
904 return;
908 mpImpl->mpGroupContext->popGroupAndPostProcess();
910 catch( const uno::Exception& )
912 DBG_UNHANDLED_EXCEPTION("xmloff", "exception while sorting shapes, sorting failed");
915 // put parent on top and drop current context, we are done
916 mpImpl->mpGroupContext = mpImpl->mpGroupContext->mpParentContext;
919 void XMLShapeImportHelper::shapeWithZIndexAdded( css::uno::Reference< css::drawing::XShape > const & xShape, sal_Int32 nZIndex )
921 if( !mpImpl->mpGroupContext)
922 return;
924 ZOrderHint aNewHint;
925 aNewHint.nIs = mpImpl->mpGroupContext->mnCurrentZ++;
926 aNewHint.nShould = nZIndex;
927 aNewHint.xShape = xShape;
929 if( nZIndex == -1 )
931 // don't care, so add to unsorted list
932 mpImpl->mpGroupContext->maUnsortedList.push_back(aNewHint);
934 else
936 // insert into sort list
937 mpImpl->mpGroupContext->maZOrderList.push_back(aNewHint);
941 void XMLShapeImportHelper::shapeRemoved(const uno::Reference<drawing::XShape>& xShape)
943 auto it = std::find_if(mpImpl->mpGroupContext->maZOrderList.begin(), mpImpl->mpGroupContext->maZOrderList.end(), [&xShape](const ZOrderHint& rHint)
945 return rHint.xShape == xShape;
947 if (it == mpImpl->mpGroupContext->maZOrderList.end())
948 // Part of the unsorted list, nothing to do.
949 return;
951 sal_Int32 nZIndex = it->nIs;
953 for (it = mpImpl->mpGroupContext->maZOrderList.begin(); it != mpImpl->mpGroupContext->maZOrderList.end();)
955 if (it->nIs == nZIndex)
957 // This is xShape: remove it and adjust the max of indexes
958 // accordingly.
959 it = mpImpl->mpGroupContext->maZOrderList.erase(it);
960 mpImpl->mpGroupContext->mnCurrentZ--;
961 continue;
963 else if (it->nIs > nZIndex)
964 // On top of xShape: adjust actual index to reflect removal.
965 it->nIs--;
967 // On top of or below xShape.
968 ++it;
972 void XMLShapeImportHelper::addShapeConnection( css::uno::Reference< css::drawing::XShape > const & rConnectorShape,
973 bool bStart,
974 const OUString& rDestShapeId,
975 sal_Int32 nDestGlueId )
977 ConnectionHint aHint;
978 aHint.mxConnector = rConnectorShape;
979 aHint.bStart = bStart;
980 aHint.aDestShapeId = rDestShapeId;
981 aHint.nDestGlueId = nDestGlueId;
983 mpImpl->maConnections.push_back( aHint );
986 void XMLShapeImportHelper::restoreConnections()
988 const vector<ConnectionHint>::size_type nCount = mpImpl->maConnections.size();
989 for( vector<ConnectionHint>::size_type i = 0; i < nCount; i++ )
991 ConnectionHint& rHint = mpImpl->maConnections[i];
992 uno::Reference< beans::XPropertySet > xConnector( rHint.mxConnector, uno::UNO_QUERY );
993 if( xConnector.is() )
995 // #86637# remember line deltas
996 uno::Any aLine1Delta;
997 uno::Any aLine2Delta;
998 uno::Any aLine3Delta;
999 OUString aStr1("EdgeLine1Delta");
1000 OUString aStr2("EdgeLine2Delta");
1001 OUString aStr3("EdgeLine3Delta");
1002 aLine1Delta = xConnector->getPropertyValue(aStr1);
1003 aLine2Delta = xConnector->getPropertyValue(aStr2);
1004 aLine3Delta = xConnector->getPropertyValue(aStr3);
1006 // #86637# simply setting these values WILL force the connector to do
1007 // a new layout promptly. So the line delta values have to be rescued
1008 // and restored around connector changes.
1009 uno::Reference< drawing::XShape > xShape(
1010 mrImporter.getInterfaceToIdentifierMapper().getReference( rHint.aDestShapeId ), uno::UNO_QUERY );
1011 if( xShape.is() )
1013 xConnector->setPropertyValue( rHint.bStart ? gsStartShape : gsEndShape, uno::Any(xShape) );
1015 sal_Int32 nGlueId = rHint.nDestGlueId < 4 ? rHint.nDestGlueId : getGluePointId( xShape, rHint.nDestGlueId );
1016 xConnector->setPropertyValue( rHint.bStart ? gsStartGluePointIndex : gsEndGluePointIndex, uno::Any(nGlueId) );
1019 // #86637# restore line deltas
1020 xConnector->setPropertyValue(aStr1, aLine1Delta );
1021 xConnector->setPropertyValue(aStr2, aLine2Delta );
1022 xConnector->setPropertyValue(aStr3, aLine3Delta );
1025 mpImpl->maConnections.clear();
1028 SvXMLImportPropertyMapper* XMLShapeImportHelper::CreateShapePropMapper( const uno::Reference< frame::XModel>& rModel, SvXMLImport& rImport )
1030 rtl::Reference< XMLPropertyHandlerFactory > xFactory = new XMLSdPropHdlFactory( rModel, rImport );
1031 rtl::Reference < XMLPropertySetMapper > xMapper = new XMLShapePropertySetMapper( xFactory, false );
1032 SvXMLImportPropertyMapper* pResult = new SvXMLImportPropertyMapper( xMapper, rImport );
1034 // chain text attributes
1035 pResult->ChainImportMapper( XMLTextImportHelper::CreateParaExtPropMapper( rImport ) );
1036 return pResult;
1039 /** adds a mapping for a glue point identifier from an xml file to the identifier created after inserting
1040 the new glue point into the core. The saved mappings can be retrieved by getGluePointId() */
1041 void XMLShapeImportHelper::addGluePointMapping( css::uno::Reference< css::drawing::XShape > const & xShape,
1042 sal_Int32 nSourceId, sal_Int32 nDestinnationId )
1044 if( mpPageContext )
1045 mpPageContext->maShapeGluePointsMap[xShape][nSourceId] = nDestinnationId;
1048 /** moves all current DestinationId's by n */
1049 void XMLShapeImportHelper::moveGluePointMapping( const css::uno::Reference< css::drawing::XShape >& xShape, const sal_Int32 n )
1051 if( mpPageContext )
1053 ShapeGluePointsMap::iterator aShapeIter( mpPageContext->maShapeGluePointsMap.find( xShape ) );
1054 if( aShapeIter != mpPageContext->maShapeGluePointsMap.end() )
1056 for ( auto& rShapeId : (*aShapeIter).second )
1058 if ( rShapeId.second != -1 )
1059 rShapeId.second += n;
1065 /** retrieves a mapping for a glue point identifier from the current xml file to the identifier created after
1066 inserting the new glue point into the core. The mapping must be initialized first with addGluePointMapping() */
1067 sal_Int32 XMLShapeImportHelper::getGluePointId( const css::uno::Reference< css::drawing::XShape >& xShape, sal_Int32 nSourceId )
1069 if( mpPageContext )
1071 ShapeGluePointsMap::iterator aShapeIter( mpPageContext->maShapeGluePointsMap.find( xShape ) );
1072 if( aShapeIter != mpPageContext->maShapeGluePointsMap.end() )
1074 GluePointIdMap::iterator aIdIter = (*aShapeIter).second.find(nSourceId);
1075 if( aIdIter != (*aShapeIter).second.end() )
1076 return (*aIdIter).second;
1080 return -1;
1083 /** this method must be calling before the first shape is imported for the given page */
1084 void XMLShapeImportHelper::startPage( css::uno::Reference< css::drawing::XShapes > const & rShapes )
1086 const std::shared_ptr<XMLShapeImportPageContextImpl> pOldContext = mpPageContext;
1087 mpPageContext = std::make_shared<XMLShapeImportPageContextImpl>();
1088 mpPageContext->mpNext = pOldContext;
1089 mpPageContext->mxShapes = rShapes;
1092 /** this method must be calling after the last shape is imported for the given page */
1093 void XMLShapeImportHelper::endPage( css::uno::Reference< css::drawing::XShapes > const & rShapes )
1095 SAL_WARN_IF( !mpPageContext || (mpPageContext->mxShapes != rShapes), "xmloff", "wrong call to endPage(), no startPage called or wrong page" );
1096 if( nullptr == mpPageContext )
1097 return;
1099 restoreConnections();
1101 mpPageContext = mpPageContext->mpNext;
1104 /** defines if the import should increment the progress bar or not */
1105 void XMLShapeImportHelper::enableHandleProgressBar()
1107 mpImpl->mbHandleProgressBar = true;
1110 bool XMLShapeImportHelper::IsHandleProgressBarEnabled() const
1112 return mpImpl->mbHandleProgressBar;
1115 /** queries the capability of the current model to create presentation shapes */
1116 bool XMLShapeImportHelper::IsPresentationShapesSupported() const
1118 return mpImpl->mbIsPresentationShapesSupported;
1121 const rtl::Reference< XMLTableImport >& XMLShapeImportHelper::GetShapeTableImport()
1123 if( !mxShapeTableImport.is() )
1125 rtl::Reference< XMLPropertyHandlerFactory > xFactory( new XMLSdPropHdlFactory( mrImporter.GetModel(), mrImporter ) );
1126 rtl::Reference< XMLPropertySetMapper > xPropertySetMapper( new XMLShapePropertySetMapper( xFactory.get(), false ) );
1127 mxShapeTableImport = new XMLTableImport( mrImporter, xPropertySetMapper, xFactory );
1130 return mxShapeTableImport;
1133 void SvXMLShapeContext::setHyperlink( const OUString& rHyperlink )
1135 msHyperlink = rHyperlink;
1138 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */