1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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"
48 #include <string_view>
53 class ShapeGroupContext
;
57 using namespace ::std
;
58 using namespace ::com::sun::star
;
59 using namespace ::xmloff::token
;
65 css::uno::Reference
< css::drawing::XShape
> mxConnector
;
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
);
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
},
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
},
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
},
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
},
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
},
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
},
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
},
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
},
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;
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);
365 case XML_TOK_3DSCENE_3DCUBE
:
367 // dr3d:3dcube inside dr3d:3dscene context
368 pContext
= new SdXML3DCubeObjectShapeContext( rImport
, xAttrList
, rShapes
);
371 case XML_TOK_3DSCENE_3DSPHERE
:
373 // dr3d:3dsphere inside dr3d:3dscene context
374 pContext
= new SdXML3DSphereObjectShapeContext( rImport
, xAttrList
, rShapes
);
377 case XML_TOK_3DSCENE_3DLATHE
:
379 // dr3d:3dlathe inside dr3d:3dscene context
380 pContext
= new SdXML3DLatheObjectShapeContext( rImport
, xAttrList
, rShapes
);
383 case XML_TOK_3DSCENE_3DEXTRUDE
:
385 // dr3d:3dextrude inside dr3d:3dscene context
386 pContext
= new SdXML3DExtrudeObjectShapeContext( rImport
, xAttrList
, rShapes
);
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
);
401 sal_uInt16 nPrefix
= rImport
.GetNamespaceMap().GetKeyByAttrName(rAttrName
, &aLocalName
);
402 const OUString
aValue( xAttrList
->getValueByIndex(a
) );
404 pContext
->processAttribute( nPrefix
, aLocalName
, aValue
);
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
);
441 case XML_TOK_GROUP_3DSCENE
:
443 // dr3d:3dscene inside group context
444 pContext
= new SdXML3DSceneShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
447 case XML_TOK_GROUP_RECT
:
449 // draw:rect inside group context
450 pContext
= new SdXMLRectShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
453 case XML_TOK_GROUP_LINE
:
455 // draw:line inside group context
456 pContext
= new SdXMLLineShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
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
);
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
);
474 case XML_TOK_GROUP_PATH
:
476 // draw:path inside group context
477 pContext
= new SdXMLPathShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
480 case XML_TOK_GROUP_FRAME
:
482 // text:text-box inside group context
483 pContext
= new SdXMLFrameShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
486 case XML_TOK_GROUP_CONTROL
:
488 // draw:control inside group context
489 pContext
= new SdXMLControlShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
492 case XML_TOK_GROUP_CONNECTOR
:
494 // draw:connector inside group context
495 pContext
= new SdXMLConnectorShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
498 case XML_TOK_GROUP_MEASURE
:
500 // draw:measure inside group context
501 pContext
= new SdXMLMeasureShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
504 case XML_TOK_GROUP_PAGE
:
506 // draw:page inside group context
507 pContext
= new SdXMLPageShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
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
);
517 case XML_TOK_GROUP_CHART
:
519 // chart:chart inside group context
520 pContext
= new SdXMLChartShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
523 case XML_TOK_GROUP_CUSTOM_SHAPE
:
526 pContext
= new SdXMLCustomShapeContext( rImport
, xAttrList
, rShapes
);
529 case XML_TOK_GROUP_A
:
531 return new SdXMLShapeLinkContext( rImport
, xAttrList
, rShapes
);
533 // add other shapes here...
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
);
543 sal_uInt16 nPrefix
= rImport
.GetNamespaceMap().GetKeyByAttrName(rAttrName
, &aLocalName
);
544 const OUString
aValue( xAttrList
->getValueByIndex(a
) );
546 pContext
->processAttribute( nPrefix
, aLocalName
, aValue
);
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
);
578 case XML_TOK_FRAME_IMAGE
:
580 // office:image inside group context
581 pContext
= new SdXMLGraphicObjectShapeContext( rImport
, xAttrList
, rShapes
);
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
);
591 case XML_TOK_FRAME_TABLE
:
593 // draw:object or draw:object_ole
594 if( rImport
.IsTableShapeSupported() )
595 pContext
= new SdXMLTableShapeContext( rImport
, xAttrList
, rShapes
);
599 case XML_TOK_FRAME_PLUGIN
:
602 pContext
= new SdXMLPluginShapeContext( rImport
, xAttrList
, rShapes
);
605 case XML_TOK_FRAME_FLOATING_FRAME
:
607 // draw:floating-frame
608 pContext
= new SdXMLFloatingFrameShapeContext( rImport
, xAttrList
, rShapes
);
611 case XML_TOK_FRAME_APPLET
:
614 pContext
= new SdXMLAppletShapeContext( rImport
, xAttrList
, rShapes
);
617 // add other shapes here...
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
);
630 sal_uInt16 nPrefix
= rImport
.GetNamespaceMap().GetKeyByAttrName(rAttrName
, &aLocalName
);
631 const OUString
aValue( xAttrList
->getValueByIndex(a
) );
633 pContext
->processAttribute( nPrefix
, aLocalName
, aValue
);
640 SvXMLImportContextRef
XMLShapeImportHelper::CreateFrameChildContext(
641 SvXMLImportContext
*pThisContext
,
643 const OUString
& rLocalName
,
644 const uno::Reference
< xml::sax::XAttributeList
>& xAttrList
)
646 SvXMLImportContextRef xContext
;
648 SdXMLFrameShapeContext
*pFrameContext
= dynamic_cast<SdXMLFrameShapeContext
*>( pThisContext
);
650 xContext
= pFrameContext
->CreateChildContext( nPrefix
, rLocalName
, xAttrList
);
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
);
694 if ( mrImporter
.IsShapePositionInHoriL2R() &&
695 xPropSet
->getPropertySetInfo()->hasPropertyByName(
696 "PositionLayoutDir") )
698 uno::Any aPosLayoutDir
;
699 aPosLayoutDir
<<= text::PositionLayoutDir::PositionInHoriL2R
;
700 xPropSet
->setPropertyValue( "PositionLayoutDir", aPosLayoutDir
);
707 // helper functions for z-order sorting
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
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();
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
;
751 if( !(xPropSet
.is() && xPropSet
->getPropertySetInfo()->hasPropertyByName( "ZOrder" )) )
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" );
765 for( ZOrderHint
& rHint
: maUnsortedList
)
767 if( rHint
.nIs
< nSourcePos
)
769 SAL_WARN_IF( rHint
.nIs
< nDestPos
, "xmloff", "shape sorting failed" );
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();
786 // only do something if we have shapes to sort
787 if( maZOrderList
.empty() )
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();
803 // first update offsets of added shapes
804 for (ZOrderHint
& rHint
: maZOrderList
)
806 for (ZOrderHint
& rHint
: maUnsortedList
)
809 // second add the already existing shapes in the unsorted list
815 aNewHint
.nIs
= nCount
;
816 aNewHint
.nShould
= -1;
818 maUnsortedList
.insert(maUnsortedList
.begin(), aNewHint
);
823 bool bSorted
= std::is_sorted(maZOrderList
.begin(), maZOrderList
.end(),
824 [&](const ZOrderHint
& rLeft
, const ZOrderHint
& rRight
)
825 { return rLeft
.nShould
< rRight
.nShould
; } );
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
);
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
;
854 xShapes3
->sort(aNewOrder
);
855 maZOrderList
.clear();
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
);
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
);
897 rData
.ApplyProperties();
900 void XMLShapeImportHelper::popGroupAndPostProcess()
902 SAL_WARN_IF( !mpImpl
->mpGroupContext
, "xmloff", "No context to sort!" );
903 if( !mpImpl
->mpGroupContext
)
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
)
925 aNewHint
.nIs
= mpImpl
->mpGroupContext
->mnCurrentZ
++;
926 aNewHint
.nShould
= nZIndex
;
927 aNewHint
.xShape
= xShape
;
931 // don't care, so add to unsorted list
932 mpImpl
->mpGroupContext
->maUnsortedList
.push_back(aNewHint
);
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.
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
959 it
= mpImpl
->mpGroupContext
->maZOrderList
.erase(it
);
960 mpImpl
->mpGroupContext
->mnCurrentZ
--;
963 else if (it
->nIs
> nZIndex
)
964 // On top of xShape: adjust actual index to reflect removal.
967 // On top of or below xShape.
972 void XMLShapeImportHelper::addShapeConnection( css::uno::Reference
< css::drawing::XShape
> const & rConnectorShape
,
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
);
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
) );
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
)
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
)
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
)
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
;
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
)
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: */