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 <comphelper/diagnose_ex.hxx>
22 #include <sal/log.hxx>
23 #include <comphelper/attributelist.hxx>
25 #include <com/sun/star/beans/XPropertySet.hpp>
26 #include <com/sun/star/text/PositionLayoutDir.hpp>
27 #include <com/sun/star/drawing/XShapes3.hpp>
30 #include <xmloff/unointerfacetouniqueidentifiermapper.hxx>
32 #include <xmloff/shapeimport.hxx>
33 #include <xmloff/xmlstyle.hxx>
34 #include <xmloff/xmltkmap.hxx>
35 #include <xmloff/xmlnamespace.hxx>
36 #include <xmloff/xmltoken.hxx>
37 #include <xmloff/table/XMLTableImport.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 <unordered_map>
48 #include <string_view>
53 class ShapeGroupContext
;
57 using namespace ::com::sun::star
;
58 using namespace ::xmloff::token
;
64 css::uno::Reference
< css::drawing::XShape
> mxConnector
;
65 OUString aDestShapeId
;
66 sal_Int32 nDestGlueId
;
72 /** this map store all gluepoint id mappings for shapes that had user defined gluepoints. This
73 is needed because on insertion the gluepoints will get a new and unique id */
74 typedef std::map
<sal_Int32
,sal_Int32
> GluePointIdMap
;
75 typedef std::unordered_map
< css::uno::Reference
< css::drawing::XShape
>, GluePointIdMap
> ShapeGluePointsMap
;
77 /** this struct is created for each startPage() call and stores information that is needed during
78 import of shapes for one page. Since pages could be nested ( notes pages inside impress ) there
79 is a pointer so one can build up a stack of this structs */
80 struct XMLShapeImportPageContextImpl
82 ShapeGluePointsMap maShapeGluePointsMap
;
84 uno::Reference
< drawing::XShapes
> mxShapes
;
86 std::shared_ptr
<XMLShapeImportPageContextImpl
> mpNext
;
89 /** this class is to enable adding members to the XMLShapeImportHelper without getting incompatible */
90 struct XMLShapeImportHelperImpl
92 // context for sorting shapes
93 std::shared_ptr
<ShapeGroupContext
> mpGroupContext
;
95 std::vector
<ConnectionHint
> maConnections
;
97 // #88546# possibility to switch progress bar handling on/off
98 bool mbHandleProgressBar
;
100 // stores the capability of the current model to create presentation shapes
101 bool mbIsPresentationShapesSupported
;
104 constexpr OUStringLiteral
gsStartShape(u
"StartShape");
105 constexpr OUStringLiteral
gsEndShape(u
"EndShape");
106 constexpr OUStringLiteral
gsStartGluePointIndex(u
"StartGluePointIndex");
107 constexpr OUStringLiteral
gsEndGluePointIndex(u
"EndGluePointIndex");
109 XMLShapeImportHelper::XMLShapeImportHelper(
110 SvXMLImport
& rImporter
,
111 const uno::Reference
< frame::XModel
>& rModel
,
112 SvXMLImportPropertyMapper
*pExtMapper
)
113 : mpImpl( new XMLShapeImportHelperImpl
),
114 mrImporter( rImporter
)
116 mpImpl
->mpGroupContext
= 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
, false);
125 mpPropertySetMapper
= new SvXMLImportPropertyMapper( xMapper
, rImporter
);
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
, false);
139 mpPresPagePropsMapper
= new SvXMLImportPropertyMapper( xMapper
, rImporter
);
141 uno::Reference
< lang::XServiceInfo
> xInfo( rImporter
.GetModel(), uno::UNO_QUERY
);
142 mpImpl
->mbIsPresentationShapesSupported
= xInfo
.is() && xInfo
->supportsService( "com.sun.star.presentation.PresentationDocument" );
145 XMLShapeImportHelper::~XMLShapeImportHelper()
147 SAL_WARN_IF( !mpImpl
->maConnections
.empty(), "xmloff", "XMLShapeImportHelper::restoreConnections() was not called!" );
149 // cleanup factory, decrease refcount. Should lead to destruction.
150 mpSdPropHdlFactory
.clear();
152 // cleanup mapper, decrease refcount. Should lead to destruction.
153 mpPropertySetMapper
.clear();
155 // cleanup presPage mapper, decrease refcount. Should lead to destruction.
156 mpPresPagePropsMapper
.clear();
158 // Styles or AutoStyles context?
159 if(mxStylesContext
.is())
160 mxStylesContext
->dispose();
162 if(mxAutoStylesContext
.is())
163 mxAutoStylesContext
->dispose();
167 SvXMLShapeContext
* XMLShapeImportHelper::Create3DSceneChildContext(
168 SvXMLImport
& rImport
,
170 const uno::Reference
< xml::sax::XFastAttributeList
>& xAttrList
,
171 uno::Reference
< drawing::XShapes
> const & rShapes
)
173 SdXMLShapeContext
*pContext
= nullptr;
179 case XML_ELEMENT(DR3D
, XML_SCENE
):
181 // dr3d:3dscene inside dr3d:3dscene context
182 pContext
= new SdXML3DSceneShapeContext( rImport
, xAttrList
, rShapes
, false);
185 case XML_ELEMENT(DR3D
, XML_CUBE
):
187 // dr3d:3dcube inside dr3d:3dscene context
188 pContext
= new SdXML3DCubeObjectShapeContext( rImport
, xAttrList
, rShapes
);
191 case XML_ELEMENT(DR3D
, XML_SPHERE
):
193 // dr3d:3dsphere inside dr3d:3dscene context
194 pContext
= new SdXML3DSphereObjectShapeContext( rImport
, xAttrList
, rShapes
);
197 case XML_ELEMENT(DR3D
, XML_ROTATE
):
199 // dr3d:3dlathe inside dr3d:3dscene context
200 pContext
= new SdXML3DLatheObjectShapeContext( rImport
, xAttrList
, rShapes
);
203 case XML_ELEMENT(DR3D
, XML_EXTRUDE
):
205 // dr3d:3dextrude inside dr3d:3dscene context
206 pContext
= new SdXML3DExtrudeObjectShapeContext( rImport
, xAttrList
, rShapes
);
210 XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement
);
217 // now parse the attribute list and call the child context for each unknown attribute
218 for(auto& aIter
: sax_fastparser::castToFastAttributeList(xAttrList
))
220 if (!pContext
->processAttribute( aIter
))
221 XMLOFF_WARN_UNKNOWN("xmloff", aIter
);
228 void XMLShapeImportHelper::SetStylesContext(SvXMLStylesContext
* pNew
)
230 mxStylesContext
.set(pNew
);
233 void XMLShapeImportHelper::SetAutoStylesContext(SvXMLStylesContext
* pNew
)
235 mxAutoStylesContext
.set(pNew
);
238 SvXMLShapeContext
* XMLShapeImportHelper::CreateGroupChildContext(
239 SvXMLImport
& rImport
,
241 const uno::Reference
< xml::sax::XFastAttributeList
>& xAttrList
,
242 uno::Reference
< drawing::XShapes
> const & rShapes
,
243 bool bTemporaryShape
)
245 SdXMLShapeContext
*pContext
= nullptr;
248 case XML_ELEMENT(DRAW
, XML_G
):
249 // draw:g inside group context (RECURSIVE)
250 pContext
= new SdXMLGroupShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
252 case XML_ELEMENT(DR3D
, XML_SCENE
):
254 // dr3d:3dscene inside group context
255 pContext
= new SdXML3DSceneShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
258 case XML_ELEMENT(DRAW
, XML_RECT
):
260 // draw:rect inside group context
261 pContext
= new SdXMLRectShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
264 case XML_ELEMENT(DRAW
, XML_LINE
):
266 // draw:line inside group context
267 pContext
= new SdXMLLineShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
270 case XML_ELEMENT(DRAW
, XML_CIRCLE
):
271 case XML_ELEMENT(DRAW
, XML_ELLIPSE
):
273 // draw:circle or draw:ellipse inside group context
274 pContext
= new SdXMLEllipseShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
277 case XML_ELEMENT(DRAW
, XML_POLYGON
):
278 case XML_ELEMENT(DRAW
, XML_POLYLINE
):
280 // draw:polygon or draw:polyline inside group context
281 pContext
= new SdXMLPolygonShapeContext( rImport
, xAttrList
, rShapes
,
282 nElement
== XML_ELEMENT(DRAW
, XML_POLYGON
), bTemporaryShape
);
285 case XML_ELEMENT(DRAW
, XML_PATH
):
287 // draw:path inside group context
288 pContext
= new SdXMLPathShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
291 case XML_ELEMENT(DRAW
, XML_FRAME
):
293 // text:text-box inside group context
294 pContext
= new SdXMLFrameShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
297 case XML_ELEMENT(DRAW
, XML_CONTROL
):
299 // draw:control inside group context
300 pContext
= new SdXMLControlShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
303 case XML_ELEMENT(DRAW
, XML_CONNECTOR
):
305 // draw:connector inside group context
306 pContext
= new SdXMLConnectorShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
309 case XML_ELEMENT(DRAW
, XML_MEASURE
):
311 // draw:measure inside group context
312 pContext
= new SdXMLMeasureShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
315 case XML_ELEMENT(DRAW
, XML_PAGE_THUMBNAIL
):
317 // draw:page inside group context
318 pContext
= new SdXMLPageShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
321 case XML_ELEMENT(DRAW
, XML_CAPTION
):
322 case XML_ELEMENT(OFFICE
, XML_ANNOTATION
):
324 // draw:caption inside group context
325 pContext
= new SdXMLCaptionShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
328 case XML_ELEMENT(CHART
, XML_CHART
):
330 // chart:chart inside group context
331 pContext
= new SdXMLChartShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
334 case XML_ELEMENT(DRAW
, XML_CUSTOM_SHAPE
):
337 pContext
= new SdXMLCustomShapeContext( rImport
, xAttrList
, rShapes
);
340 case XML_ELEMENT(DRAW
, XML_A
):
341 return new SdXMLShapeLinkContext( rImport
, xAttrList
, rShapes
);
342 // add other shapes here...
344 XMLOFF_INFO_UNKNOWN_ELEMENT("xmloff", nElement
);
345 return new SvXMLShapeContext( rImport
, bTemporaryShape
);
348 // now parse the attribute list and call the child context for each unknown attribute
349 for (auto &aIter
: sax_fastparser::castToFastAttributeList( xAttrList
))
351 if (!pContext
->processAttribute( aIter
))
352 XMLOFF_INFO_UNKNOWN("xmloff", aIter
);
357 // This method is called from SdXMLFrameShapeContext to create children of draw:frame
358 SvXMLShapeContext
* XMLShapeImportHelper::CreateFrameChildContext(
359 SvXMLImport
& rImport
,
361 const uno::Reference
< xml::sax::XFastAttributeList
>& rAttrList
,
362 uno::Reference
< drawing::XShapes
> const & rShapes
,
363 const uno::Reference
< xml::sax::XFastAttributeList
>& rFrameAttrList
)
365 SdXMLShapeContext
*pContext
= nullptr;
367 rtl::Reference
<sax_fastparser::FastAttributeList
> xCombinedAttrList
= new sax_fastparser::FastAttributeList(rAttrList
);
368 if( rFrameAttrList
.is() )
369 xCombinedAttrList
->add(rFrameAttrList
);
373 case XML_ELEMENT(DRAW
, XML_TEXT_BOX
):
375 // text:text-box inside group context
376 pContext
= new SdXMLTextBoxShapeContext( rImport
, xCombinedAttrList
, rShapes
);
379 case XML_ELEMENT(DRAW
, XML_IMAGE
):
381 // office:image inside group context
382 pContext
= new SdXMLGraphicObjectShapeContext( rImport
, xCombinedAttrList
, rShapes
);
385 case XML_ELEMENT(DRAW
, XML_OBJECT
):
386 case XML_ELEMENT(DRAW
, XML_OBJECT_OLE
):
388 // draw:object or draw:object_ole
389 pContext
= new SdXMLObjectShapeContext( rImport
, xCombinedAttrList
, rShapes
);
392 case XML_ELEMENT(TABLE
, XML_TABLE
):
394 // draw:object or draw:object_ole
395 if( rImport
.IsTableShapeSupported() )
396 pContext
= new SdXMLTableShapeContext( rImport
, xCombinedAttrList
, rShapes
);
400 case XML_ELEMENT(DRAW
, XML_PLUGIN
):
403 pContext
= new SdXMLPluginShapeContext( rImport
, xCombinedAttrList
, rShapes
);
406 case XML_ELEMENT(DRAW
, XML_FLOATING_FRAME
):
408 // draw:floating-frame
409 pContext
= new SdXMLFloatingFrameShapeContext( rImport
, xCombinedAttrList
, rShapes
);
412 case XML_ELEMENT(DRAW
, XML_APPLET
):
415 pContext
= new SdXMLAppletShapeContext( rImport
, xCombinedAttrList
, rShapes
);
418 // add other shapes here...
420 SAL_INFO("xmloff", "unknown element " << SvXMLImport::getPrefixAndNameFromToken(nElement
));
426 // now parse the attribute list and call the child context for each unknown attribute
427 for(auto& aIter
: *xCombinedAttrList
)
429 if (!pContext
->processAttribute( aIter
))
430 SAL_INFO("xmloff", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter
.getToken()) << " value=" << aIter
.toString());
437 css::uno::Reference
< css::xml::sax::XFastContextHandler
> XMLShapeImportHelper::CreateFrameChildContext(
438 SvXMLImportContext
*pThisContext
,
440 const uno::Reference
< xml::sax::XFastAttributeList
>& xAttrList
)
442 css::uno::Reference
< css::xml::sax::XFastContextHandler
> xContext
;
443 SdXMLFrameShapeContext
*pFrameContext
= dynamic_cast<SdXMLFrameShapeContext
*>( pThisContext
);
445 xContext
= pFrameContext
->createFastChildContext( nElement
, xAttrList
);
448 XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement
);
452 /** this function is called whenever the implementation classes like to add this new
453 shape to the given XShapes.
455 void XMLShapeImportHelper::addShape( uno::Reference
< drawing::XShape
>& rShape
,
456 const uno::Reference
< xml::sax::XFastAttributeList
>&,
457 uno::Reference
< drawing::XShapes
>& rShapes
)
459 if( rShape
.is() && rShapes
.is() )
461 // add new shape to parent
462 rShapes
->add( rShape
);
464 uno::Reference
<beans::XPropertySet
> xPropertySet(rShape
, uno::UNO_QUERY
);
465 if (xPropertySet
.is())
467 static constexpr OUStringLiteral sHandlePathObjScale
= u
"HandlePathObjScale";
468 xPropertySet
->setPropertyValue(sHandlePathObjScale
, uno::Any(true));
473 /** this function is called whenever the implementation classes have finished importing
474 a shape to the given XShapes. The shape is already inserted into its XShapes and
475 all properties and styles are set.
477 void XMLShapeImportHelper::finishShape(
478 css::uno::Reference
< css::drawing::XShape
>& rShape
,
479 const css::uno::Reference
< css::xml::sax::XFastAttributeList
>&,
480 css::uno::Reference
< css::drawing::XShapes
>&)
482 /* Set property <PositionLayoutDir>
483 to <PositionInHoriL2R>, if it exists and the import states that
484 the shape positioning attributes are in horizontal left-to-right
485 layout. This is the case for the OpenOffice.org file format.
486 This setting is done for Writer documents, because the property
487 only exists at service css::text::Shape - the Writer
488 UNO service for shapes.
489 The value indicates that the positioning attributes are given
490 in horizontal left-to-right layout. The property is evaluated
491 during the first positioning of the shape in order to convert
492 the shape position given in the OpenOffice.org file format to
493 the one for the OASIS Open Office file format. (#i28749#, #i36248#)
495 uno::Reference
< beans::XPropertySet
> xPropSet(rShape
, uno::UNO_QUERY
);
498 if ( mrImporter
.IsShapePositionInHoriL2R() &&
499 xPropSet
->getPropertySetInfo()->hasPropertyByName(
500 "PositionLayoutDir") )
502 uno::Any aPosLayoutDir
;
503 aPosLayoutDir
<<= text::PositionLayoutDir::PositionInHoriL2R
;
504 xPropSet
->setPropertyValue( "PositionLayoutDir", aPosLayoutDir
);
511 // helper functions for z-order sorting
516 /// The hint is for this shape. We don't use uno::Reference here to speed up
517 /// some operations, and because this shape is always held by mxShapes
518 drawing::XShape
* pShape
;
520 bool operator<(const ZOrderHint
& rComp
) const { return nShould
< rComp
.nShould
; }
523 // a) handle z-order of group contents after it has been imported
524 // b) apply group events over group contents after it has been imported
525 class ShapeGroupContext
528 uno::Reference
< drawing::XShapes
> mxShapes
;
529 std::vector
<SdXMLEventContextData
> maEventData
;
530 std::vector
<ZOrderHint
> maZOrderList
;
531 std::vector
<ZOrderHint
> maUnsortedList
;
533 sal_Int32 mnCurrentZ
;
534 std::shared_ptr
<ShapeGroupContext
> mpParentContext
;
536 ShapeGroupContext( uno::Reference
< drawing::XShapes
> xShapes
, std::shared_ptr
<ShapeGroupContext
> pParentContext
);
538 void popGroupAndPostProcess();
540 void moveShape( sal_Int32 nSourcePos
, sal_Int32 nDestPos
);
545 ShapeGroupContext::ShapeGroupContext( uno::Reference
< drawing::XShapes
> xShapes
, std::shared_ptr
<ShapeGroupContext
> pParentContext
)
546 : mxShapes(std::move( xShapes
)), mnCurrentZ( 0 ), mpParentContext( std::move(pParentContext
) )
550 void ShapeGroupContext::moveShape( sal_Int32 nSourcePos
, sal_Int32 nDestPos
)
552 uno::Any
aAny( mxShapes
->getByIndex( nSourcePos
) );
553 uno::Reference
< beans::XPropertySet
> xPropSet
;
556 if( !(xPropSet
.is() && xPropSet
->getPropertySetInfo()->hasPropertyByName( "ZOrder" )) )
559 xPropSet
->setPropertyValue( "ZOrder", uno::Any(nDestPos
) );
561 for( ZOrderHint
& rHint
: maZOrderList
)
563 if( rHint
.nIs
< nSourcePos
)
565 DBG_ASSERT(rHint
.nIs
>= nDestPos
, "Shape sorting failed" );
570 for( ZOrderHint
& rHint
: maUnsortedList
)
572 if( rHint
.nIs
< nSourcePos
)
574 SAL_WARN_IF( rHint
.nIs
< nDestPos
, "xmloff", "shape sorting failed" );
581 void ShapeGroupContext::popGroupAndPostProcess()
583 if (!maEventData
.empty())
585 // tdf#127791 wait until a group is popped to set its event data
586 for (auto& event
: maEventData
)
587 event
.ApplyProperties();
591 // only do something if we have shapes to sort
592 if( maZOrderList
.empty() )
595 // check if there are more shapes than inserted with ::shapeWithZIndexAdded()
596 // This can happen if there where already shapes on the page before import
597 // Since the writer may delete some of this shapes during import, we need
598 // to do this here and not in our c'tor anymore
600 // check if we have more shapes than we know of
601 sal_Int32 nCount
= mxShapes
->getCount();
603 nCount
-= maZOrderList
.size();
604 nCount
-= maUnsortedList
.size();
608 // first update offsets of added shapes
609 for (ZOrderHint
& rHint
: maZOrderList
)
611 for (ZOrderHint
& rHint
: maUnsortedList
)
614 // second add the already existing shapes in the unsorted list
616 aNewHint
.pShape
= nullptr;
621 aNewHint
.nIs
= nCount
;
622 aNewHint
.nShould
= -1;
624 maUnsortedList
.insert(maUnsortedList
.begin(), aNewHint
);
629 bool bSorted
= std::is_sorted(maZOrderList
.begin(), maZOrderList
.end(),
630 [](const ZOrderHint
& rLeft
, const ZOrderHint
& rRight
)
631 { return rLeft
.nShould
< rRight
.nShould
; } );
634 return; // nothin' to do
636 // sort z-ordered shapes by nShould field
637 std::sort(maZOrderList
.begin(), maZOrderList
.end());
639 uno::Reference
<drawing::XShapes3
> xShapes3(mxShapes
, uno::UNO_QUERY
);
642 uno::Sequence
<sal_Int32
> aNewOrder(maZOrderList
.size() + maUnsortedList
.size());
643 auto pNewOrder
= aNewOrder
.getArray();
644 sal_Int32 nIndex
= 0;
646 for (const ZOrderHint
& rHint
: maZOrderList
)
648 // fill in the gaps from unordered list
649 for (std::vector
<ZOrderHint
>::iterator aIt
= maUnsortedList
.begin(); aIt
!= maUnsortedList
.end() && nIndex
< rHint
.nShould
; )
651 pNewOrder
[nIndex
++] = (*aIt
).nIs
;
652 aIt
= maUnsortedList
.erase(aIt
);
655 pNewOrder
[nIndex
] = rHint
.nIs
;
661 xShapes3
->sort(aNewOrder
);
662 maZOrderList
.clear();
665 catch (const css::lang::IllegalArgumentException
& /*e*/)
669 // this is the current index, all shapes before that
670 // index are finished
671 sal_Int32 nIndex
= 0;
672 for (const ZOrderHint
& rHint
: maZOrderList
)
674 for (std::vector
<ZOrderHint
>::iterator aIt
= maUnsortedList
.begin(); aIt
!= maUnsortedList
.end() && nIndex
< rHint
.nShould
; )
676 moveShape( (*aIt
).nIs
, nIndex
++ );
677 aIt
= maUnsortedList
.erase(aIt
);
681 if(rHint
.nIs
!= nIndex
)
682 moveShape( rHint
.nIs
, nIndex
);
686 maZOrderList
.clear();
689 void XMLShapeImportHelper::pushGroupForPostProcessing( uno::Reference
< drawing::XShapes
>& rShapes
)
691 mpImpl
->mpGroupContext
= std::make_shared
<ShapeGroupContext
>( rShapes
, mpImpl
->mpGroupContext
);
694 void XMLShapeImportHelper::addShapeEvents(SdXMLEventContextData
& rData
)
696 if (mpImpl
->mpGroupContext
&& mpImpl
->mpGroupContext
->mxShapes
== rData
.mxShape
)
698 // tdf#127791 wait until a group is popped to set its event data so
699 // that the events are applied to all its children, which are not available
700 // at the start of the group tag
701 mpImpl
->mpGroupContext
->maEventData
.push_back(rData
);
704 rData
.ApplyProperties();
707 void XMLShapeImportHelper::popGroupAndPostProcess()
709 SAL_WARN_IF( !mpImpl
->mpGroupContext
, "xmloff", "No context to sort!" );
710 if( !mpImpl
->mpGroupContext
)
715 mpImpl
->mpGroupContext
->popGroupAndPostProcess();
717 catch( const uno::Exception
& )
719 DBG_UNHANDLED_EXCEPTION("xmloff", "exception while sorting shapes, sorting failed");
722 // put parent on top and drop current context, we are done
723 mpImpl
->mpGroupContext
= mpImpl
->mpGroupContext
->mpParentContext
;
726 void XMLShapeImportHelper::shapeWithZIndexAdded( css::uno::Reference
< css::drawing::XShape
> const & xShape
, sal_Int32 nZIndex
)
728 if( !mpImpl
->mpGroupContext
)
732 aNewHint
.nIs
= mpImpl
->mpGroupContext
->mnCurrentZ
++;
733 aNewHint
.nShould
= nZIndex
;
734 aNewHint
.pShape
= xShape
.get();
738 // don't care, so add to unsorted list
739 mpImpl
->mpGroupContext
->maUnsortedList
.push_back(aNewHint
);
743 // insert into sort list
744 mpImpl
->mpGroupContext
->maZOrderList
.push_back(aNewHint
);
748 void XMLShapeImportHelper::shapeRemoved(const uno::Reference
<drawing::XShape
>& xShape
)
750 auto it
= std::find_if(mpImpl
->mpGroupContext
->maZOrderList
.begin(), mpImpl
->mpGroupContext
->maZOrderList
.end(), [&xShape
](const ZOrderHint
& rHint
)
752 return rHint
.pShape
== xShape
.get();
754 if (it
== mpImpl
->mpGroupContext
->maZOrderList
.end())
755 // Part of the unsorted list, nothing to do.
758 sal_Int32 nZIndex
= it
->nIs
;
760 for (it
= mpImpl
->mpGroupContext
->maZOrderList
.begin(); it
!= mpImpl
->mpGroupContext
->maZOrderList
.end();)
762 if (it
->nIs
== nZIndex
)
764 // This is xShape: remove it and adjust the max of indexes
766 it
= mpImpl
->mpGroupContext
->maZOrderList
.erase(it
);
767 mpImpl
->mpGroupContext
->mnCurrentZ
--;
770 else if (it
->nIs
> nZIndex
)
771 // On top of xShape: adjust actual index to reflect removal.
774 // On top of or below xShape.
779 void XMLShapeImportHelper::addShapeConnection( css::uno::Reference
< css::drawing::XShape
> const & rConnectorShape
,
781 const OUString
& rDestShapeId
,
782 sal_Int32 nDestGlueId
)
784 ConnectionHint aHint
;
785 aHint
.mxConnector
= rConnectorShape
;
786 aHint
.bStart
= bStart
;
787 aHint
.aDestShapeId
= rDestShapeId
;
788 aHint
.nDestGlueId
= nDestGlueId
;
790 mpImpl
->maConnections
.push_back( aHint
);
793 void XMLShapeImportHelper::restoreConnections()
795 const std::vector
<ConnectionHint
>::size_type nCount
= mpImpl
->maConnections
.size();
796 for( std::vector
<ConnectionHint
>::size_type i
= 0; i
< nCount
; i
++ )
798 ConnectionHint
& rHint
= mpImpl
->maConnections
[i
];
799 uno::Reference
< beans::XPropertySet
> xConnector( rHint
.mxConnector
, uno::UNO_QUERY
);
800 if( xConnector
.is() )
802 // #86637# remember line deltas
803 uno::Any aLine1Delta
;
804 uno::Any aLine2Delta
;
805 uno::Any aLine3Delta
;
806 OUString
aStr1("EdgeLine1Delta");
807 OUString
aStr2("EdgeLine2Delta");
808 OUString
aStr3("EdgeLine3Delta");
809 aLine1Delta
= xConnector
->getPropertyValue(aStr1
);
810 aLine2Delta
= xConnector
->getPropertyValue(aStr2
);
811 aLine3Delta
= xConnector
->getPropertyValue(aStr3
);
813 // #86637# simply setting these values WILL force the connector to do
814 // a new layout promptly. So the line delta values have to be rescued
815 // and restored around connector changes.
816 uno::Reference
< drawing::XShape
> xShape(
817 mrImporter
.getInterfaceToIdentifierMapper().getReference( rHint
.aDestShapeId
), uno::UNO_QUERY
);
821 xConnector
->setPropertyValue( gsStartShape
, uno::Any(xShape
) );
823 xConnector
->setPropertyValue( gsEndShape
, uno::Any(xShape
) );
825 sal_Int32 nGlueId
= rHint
.nDestGlueId
< 4 ? rHint
.nDestGlueId
: getGluePointId( xShape
, rHint
.nDestGlueId
);
827 xConnector
->setPropertyValue( gsStartGluePointIndex
, uno::Any(nGlueId
) );
829 xConnector
->setPropertyValue( gsEndGluePointIndex
, uno::Any(nGlueId
) );
832 // #86637# restore line deltas
833 xConnector
->setPropertyValue(aStr1
, aLine1Delta
);
834 xConnector
->setPropertyValue(aStr2
, aLine2Delta
);
835 xConnector
->setPropertyValue(aStr3
, aLine3Delta
);
838 mpImpl
->maConnections
.clear();
841 SvXMLImportPropertyMapper
* XMLShapeImportHelper::CreateShapePropMapper( const uno::Reference
< frame::XModel
>& rModel
, SvXMLImport
& rImport
)
843 rtl::Reference
< XMLPropertyHandlerFactory
> xFactory
= new XMLSdPropHdlFactory( rModel
, rImport
);
844 rtl::Reference
< XMLPropertySetMapper
> xMapper
= new XMLShapePropertySetMapper( xFactory
, false );
845 SvXMLImportPropertyMapper
* pResult
= new SvXMLImportPropertyMapper( xMapper
, rImport
);
847 // chain text attributes
848 pResult
->ChainImportMapper( XMLTextImportHelper::CreateParaExtPropMapper( rImport
) );
852 /** adds a mapping for a gluepoint identifier from an xml file to the identifier created after inserting
853 the new gluepoint into the core. The saved mappings can be retrieved by getGluePointId() */
854 void XMLShapeImportHelper::addGluePointMapping( css::uno::Reference
< css::drawing::XShape
> const & xShape
,
855 sal_Int32 nSourceId
, sal_Int32 nDestinnationId
)
858 mpPageContext
->maShapeGluePointsMap
[xShape
][nSourceId
] = nDestinnationId
;
861 /** moves all current DestinationId's by n */
862 void XMLShapeImportHelper::moveGluePointMapping( const css::uno::Reference
< css::drawing::XShape
>& xShape
, const sal_Int32 n
)
866 ShapeGluePointsMap::iterator
aShapeIter( mpPageContext
->maShapeGluePointsMap
.find( xShape
) );
867 if( aShapeIter
!= mpPageContext
->maShapeGluePointsMap
.end() )
869 for ( auto& rShapeId
: (*aShapeIter
).second
)
871 if ( rShapeId
.second
!= -1 )
872 rShapeId
.second
+= n
;
878 /** retrieves a mapping for a gluepoint identifier from the current xml file to the identifier created after
879 inserting the new gluepoint into the core. The mapping must be initialized first with addGluePointMapping() */
880 sal_Int32
XMLShapeImportHelper::getGluePointId( const css::uno::Reference
< css::drawing::XShape
>& xShape
, sal_Int32 nSourceId
)
884 ShapeGluePointsMap::iterator
aShapeIter( mpPageContext
->maShapeGluePointsMap
.find( xShape
) );
885 if( aShapeIter
!= mpPageContext
->maShapeGluePointsMap
.end() )
887 GluePointIdMap::iterator aIdIter
= (*aShapeIter
).second
.find(nSourceId
);
888 if( aIdIter
!= (*aShapeIter
).second
.end() )
889 return (*aIdIter
).second
;
896 /** this method must be calling before the first shape is imported for the given page */
897 void XMLShapeImportHelper::startPage( css::uno::Reference
< css::drawing::XShapes
> const & rShapes
)
899 const std::shared_ptr
<XMLShapeImportPageContextImpl
> pOldContext
= mpPageContext
;
900 mpPageContext
= std::make_shared
<XMLShapeImportPageContextImpl
>();
901 mpPageContext
->mpNext
= pOldContext
;
902 mpPageContext
->mxShapes
= rShapes
;
905 /** this method must be calling after the last shape is imported for the given page */
906 void XMLShapeImportHelper::endPage( css::uno::Reference
< css::drawing::XShapes
> const & rShapes
)
908 SAL_WARN_IF( !mpPageContext
|| (mpPageContext
->mxShapes
!= rShapes
), "xmloff", "wrong call to endPage(), no startPage called or wrong page" );
909 if( nullptr == mpPageContext
)
912 restoreConnections();
914 mpPageContext
= mpPageContext
->mpNext
;
917 /** defines if the import should increment the progress bar or not */
918 void XMLShapeImportHelper::enableHandleProgressBar()
920 mpImpl
->mbHandleProgressBar
= true;
923 bool XMLShapeImportHelper::IsHandleProgressBarEnabled() const
925 return mpImpl
->mbHandleProgressBar
;
928 /** queries the capability of the current model to create presentation shapes */
929 bool XMLShapeImportHelper::IsPresentationShapesSupported() const
931 return mpImpl
->mbIsPresentationShapesSupported
;
934 const rtl::Reference
< XMLTableImport
>& XMLShapeImportHelper::GetShapeTableImport()
936 if( !mxShapeTableImport
.is() )
938 rtl::Reference
< XMLPropertyHandlerFactory
> xFactory( new XMLSdPropHdlFactory( mrImporter
.GetModel(), mrImporter
) );
939 rtl::Reference
< XMLPropertySetMapper
> xPropertySetMapper( new XMLShapePropertySetMapper( xFactory
, false ) );
940 mxShapeTableImport
= new XMLTableImport( mrImporter
, xPropertySetMapper
, xFactory
);
943 return mxShapeTableImport
;
946 void SvXMLShapeContext::setHyperlink( const OUString
& rHyperlink
)
948 msHyperlink
= rHyperlink
;
951 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */