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>
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/xmlnamespace.hxx>
34 #include <xmloff/xmltoken.hxx>
35 #include <xmloff/table/XMLTableImport.hxx>
36 #include "eventimp.hxx"
37 #include "ximpshap.hxx"
38 #include "sdpropls.hxx"
39 #include <xmloff/xmlprmap.hxx>
40 #include "ximp3dscene.hxx"
41 #include "ximp3dobject.hxx"
42 #include "ximpgrp.hxx"
43 #include "ximplink.hxx"
45 #include <unordered_map>
50 class ShapeGroupContext
;
54 using namespace ::com::sun::star
;
55 using namespace ::xmloff::token
;
61 css::uno::Reference
< css::drawing::XShape
> mxConnector
;
62 OUString aDestShapeId
;
63 sal_Int32 nDestGlueId
;
69 /** this map store all gluepoint id mappings for shapes that had user defined gluepoints. This
70 is needed because on insertion the gluepoints will get a new and unique id */
71 typedef std::map
<sal_Int32
,sal_Int32
> GluePointIdMap
;
72 typedef std::unordered_map
< css::uno::Reference
< css::drawing::XShape
>, GluePointIdMap
> ShapeGluePointsMap
;
74 /** this struct is created for each startPage() call and stores information that is needed during
75 import of shapes for one page. Since pages could be nested ( notes pages inside impress ) there
76 is a pointer so one can build up a stack of this structs */
77 struct XMLShapeImportPageContextImpl
79 ShapeGluePointsMap maShapeGluePointsMap
;
81 uno::Reference
< drawing::XShapes
> mxShapes
;
83 std::shared_ptr
<XMLShapeImportPageContextImpl
> mpNext
;
86 /** this class is to enable adding members to the XMLShapeImportHelper without getting incompatible */
87 struct XMLShapeImportHelperImpl
89 // context for sorting shapes
90 std::shared_ptr
<ShapeGroupContext
> mpGroupContext
;
92 std::vector
<ConnectionHint
> maConnections
;
94 // #88546# possibility to switch progress bar handling on/off
95 bool mbHandleProgressBar
;
97 // stores the capability of the current model to create presentation shapes
98 bool mbIsPresentationShapesSupported
;
101 XMLShapeImportHelper::XMLShapeImportHelper(
102 SvXMLImport
& rImporter
,
103 const uno::Reference
< frame::XModel
>& rModel
,
104 SvXMLImportPropertyMapper
*pExtMapper
)
105 : mpImpl( new XMLShapeImportHelperImpl
),
106 mrImporter( rImporter
)
108 mpImpl
->mpGroupContext
= nullptr;
110 // #88546# init to sal_False
111 mpImpl
->mbHandleProgressBar
= false;
113 mpSdPropHdlFactory
= new XMLSdPropHdlFactory( rModel
, rImporter
);
115 // construct PropertySetMapper
116 rtl::Reference
< XMLPropertySetMapper
> xMapper
= new XMLShapePropertySetMapper(mpSdPropHdlFactory
, false);
117 mpPropertySetMapper
= new SvXMLImportPropertyMapper( xMapper
, rImporter
);
121 rtl::Reference
< SvXMLImportPropertyMapper
> xExtMapper( pExtMapper
);
122 mpPropertySetMapper
->ChainImportMapper( xExtMapper
);
125 // chain text attributes
126 mpPropertySetMapper
->ChainImportMapper(XMLTextImportHelper::CreateParaExtPropMapper(rImporter
));
127 mpPropertySetMapper
->ChainImportMapper(XMLTextImportHelper::CreateParaDefaultExtPropMapper(rImporter
));
129 // construct PresPagePropsMapper
130 xMapper
= new XMLPropertySetMapper(aXMLSDPresPageProps
, mpSdPropHdlFactory
, false);
131 mpPresPagePropsMapper
= new SvXMLImportPropertyMapper( xMapper
, rImporter
);
133 uno::Reference
< lang::XServiceInfo
> xInfo( rImporter
.GetModel(), uno::UNO_QUERY
);
134 mpImpl
->mbIsPresentationShapesSupported
= xInfo
.is() && xInfo
->supportsService( u
"com.sun.star.presentation.PresentationDocument"_ustr
);
137 XMLShapeImportHelper::~XMLShapeImportHelper()
139 SAL_WARN_IF( !mpImpl
->maConnections
.empty(), "xmloff", "XMLShapeImportHelper::restoreConnections() was not called!" );
141 // cleanup factory, decrease refcount. Should lead to destruction.
142 mpSdPropHdlFactory
.clear();
144 // cleanup mapper, decrease refcount. Should lead to destruction.
145 mpPropertySetMapper
.clear();
147 // cleanup presPage mapper, decrease refcount. Should lead to destruction.
148 mpPresPagePropsMapper
.clear();
150 // Styles or AutoStyles context?
151 if(mxStylesContext
.is())
152 mxStylesContext
->dispose();
154 if(mxAutoStylesContext
.is())
155 mxAutoStylesContext
->dispose();
159 SvXMLShapeContext
* XMLShapeImportHelper::Create3DSceneChildContext(
160 SvXMLImport
& rImport
,
162 const uno::Reference
< xml::sax::XFastAttributeList
>& xAttrList
,
163 uno::Reference
< drawing::XShapes
> const & rShapes
)
165 SdXMLShapeContext
*pContext
= nullptr;
171 case XML_ELEMENT(DR3D
, XML_SCENE
):
173 // dr3d:3dscene inside dr3d:3dscene context
174 pContext
= new SdXML3DSceneShapeContext( rImport
, xAttrList
, rShapes
, false);
177 case XML_ELEMENT(DR3D
, XML_CUBE
):
179 // dr3d:3dcube inside dr3d:3dscene context
180 pContext
= new SdXML3DCubeObjectShapeContext( rImport
, xAttrList
, rShapes
);
183 case XML_ELEMENT(DR3D
, XML_SPHERE
):
185 // dr3d:3dsphere inside dr3d:3dscene context
186 pContext
= new SdXML3DSphereObjectShapeContext( rImport
, xAttrList
, rShapes
);
189 case XML_ELEMENT(DR3D
, XML_ROTATE
):
191 // dr3d:3dlathe inside dr3d:3dscene context
192 pContext
= new SdXML3DLatheObjectShapeContext( rImport
, xAttrList
, rShapes
);
195 case XML_ELEMENT(DR3D
, XML_EXTRUDE
):
197 // dr3d:3dextrude inside dr3d:3dscene context
198 pContext
= new SdXML3DExtrudeObjectShapeContext( rImport
, xAttrList
, rShapes
);
202 XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement
);
209 // now parse the attribute list and call the child context for each unknown attribute
210 for(auto& aIter
: sax_fastparser::castToFastAttributeList(xAttrList
))
212 if (!pContext
->processAttribute( aIter
))
213 XMLOFF_WARN_UNKNOWN("xmloff", aIter
);
220 void XMLShapeImportHelper::SetStylesContext(SvXMLStylesContext
* pNew
)
222 mxStylesContext
.set(pNew
);
225 void XMLShapeImportHelper::SetAutoStylesContext(SvXMLStylesContext
* pNew
)
227 mxAutoStylesContext
.set(pNew
);
230 SvXMLShapeContext
* XMLShapeImportHelper::CreateGroupChildContext(
231 SvXMLImport
& rImport
,
233 const uno::Reference
< xml::sax::XFastAttributeList
>& xAttrList
,
234 uno::Reference
< drawing::XShapes
> const & rShapes
,
235 bool bTemporaryShape
)
237 SdXMLShapeContext
*pContext
= nullptr;
240 case XML_ELEMENT(DRAW
, XML_G
):
241 // draw:g inside group context (RECURSIVE)
242 pContext
= new SdXMLGroupShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
244 case XML_ELEMENT(DR3D
, XML_SCENE
):
246 // dr3d:3dscene inside group context
247 pContext
= new SdXML3DSceneShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
250 case XML_ELEMENT(DRAW
, XML_RECT
):
252 // draw:rect inside group context
253 pContext
= new SdXMLRectShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
256 case XML_ELEMENT(DRAW
, XML_LINE
):
258 // draw:line inside group context
259 pContext
= new SdXMLLineShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
262 case XML_ELEMENT(DRAW
, XML_CIRCLE
):
263 case XML_ELEMENT(DRAW
, XML_ELLIPSE
):
265 // draw:circle or draw:ellipse inside group context
266 pContext
= new SdXMLEllipseShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
269 case XML_ELEMENT(DRAW
, XML_POLYGON
):
270 case XML_ELEMENT(DRAW
, XML_POLYLINE
):
272 // draw:polygon or draw:polyline inside group context
273 pContext
= new SdXMLPolygonShapeContext( rImport
, xAttrList
, rShapes
,
274 nElement
== XML_ELEMENT(DRAW
, XML_POLYGON
), bTemporaryShape
);
277 case XML_ELEMENT(DRAW
, XML_PATH
):
279 // draw:path inside group context
280 pContext
= new SdXMLPathShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
283 case XML_ELEMENT(DRAW
, XML_FRAME
):
285 // text:text-box inside group context
286 pContext
= new SdXMLFrameShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
289 case XML_ELEMENT(DRAW
, XML_CONTROL
):
291 // draw:control inside group context
292 pContext
= new SdXMLControlShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
295 case XML_ELEMENT(DRAW
, XML_CONNECTOR
):
297 // draw:connector inside group context
298 pContext
= new SdXMLConnectorShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
301 case XML_ELEMENT(DRAW
, XML_MEASURE
):
303 // draw:measure inside group context
304 pContext
= new SdXMLMeasureShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
307 case XML_ELEMENT(DRAW
, XML_PAGE_THUMBNAIL
):
309 // draw:page inside group context
310 pContext
= new SdXMLPageShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
313 case XML_ELEMENT(DRAW
, XML_CAPTION
):
314 case XML_ELEMENT(OFFICE
, XML_ANNOTATION
):
316 // draw:caption inside group context
317 pContext
= new SdXMLCaptionShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
320 case XML_ELEMENT(CHART
, XML_CHART
):
322 // chart:chart inside group context
323 pContext
= new SdXMLChartShapeContext( rImport
, xAttrList
, rShapes
, bTemporaryShape
);
326 case XML_ELEMENT(DRAW
, XML_CUSTOM_SHAPE
):
329 pContext
= new SdXMLCustomShapeContext( rImport
, xAttrList
, rShapes
);
332 case XML_ELEMENT(DRAW
, XML_A
):
333 return new SdXMLShapeLinkContext( rImport
, xAttrList
, rShapes
);
334 // add other shapes here...
336 XMLOFF_INFO_UNKNOWN_ELEMENT("xmloff", nElement
);
337 return new SvXMLShapeContext( rImport
, bTemporaryShape
);
340 // now parse the attribute list and call the child context for each unknown attribute
341 for (auto &aIter
: sax_fastparser::castToFastAttributeList( xAttrList
))
343 if (!pContext
->processAttribute( aIter
))
344 XMLOFF_INFO_UNKNOWN("xmloff", aIter
);
349 // This method is called from SdXMLFrameShapeContext to create children of draw:frame
350 SvXMLShapeContext
* XMLShapeImportHelper::CreateFrameChildContext(
351 SvXMLImport
& rImport
,
353 const uno::Reference
< xml::sax::XFastAttributeList
>& rAttrList
,
354 uno::Reference
< drawing::XShapes
> const & rShapes
,
355 const uno::Reference
< xml::sax::XFastAttributeList
>& rFrameAttrList
)
357 SdXMLShapeContext
*pContext
= nullptr;
359 rtl::Reference
<sax_fastparser::FastAttributeList
> xCombinedAttrList
= new sax_fastparser::FastAttributeList(rAttrList
);
360 if( rFrameAttrList
.is() )
361 xCombinedAttrList
->add(rFrameAttrList
);
365 case XML_ELEMENT(DRAW
, XML_TEXT_BOX
):
367 // text:text-box inside group context
368 pContext
= new SdXMLTextBoxShapeContext( rImport
, xCombinedAttrList
, rShapes
);
371 case XML_ELEMENT(DRAW
, XML_IMAGE
):
373 // office:image inside group context
374 pContext
= new SdXMLGraphicObjectShapeContext( rImport
, xCombinedAttrList
, rShapes
);
377 case XML_ELEMENT(DRAW
, XML_OBJECT
):
378 case XML_ELEMENT(DRAW
, XML_OBJECT_OLE
):
380 // draw:object or draw:object_ole
381 pContext
= new SdXMLObjectShapeContext( rImport
, xCombinedAttrList
, rShapes
);
384 case XML_ELEMENT(TABLE
, XML_TABLE
):
386 // draw:object or draw:object_ole
387 if( rImport
.IsTableShapeSupported() )
388 pContext
= new SdXMLTableShapeContext( rImport
, xCombinedAttrList
, rShapes
);
392 case XML_ELEMENT(DRAW
, XML_PLUGIN
):
395 pContext
= new SdXMLPluginShapeContext( rImport
, xCombinedAttrList
, rShapes
);
398 case XML_ELEMENT(DRAW
, XML_FLOATING_FRAME
):
400 // draw:floating-frame
401 pContext
= new SdXMLFloatingFrameShapeContext( rImport
, xCombinedAttrList
, rShapes
);
404 case XML_ELEMENT(DRAW
, XML_APPLET
):
407 pContext
= new SdXMLAppletShapeContext( rImport
, xCombinedAttrList
, rShapes
);
410 // add other shapes here...
412 SAL_INFO("xmloff", "unknown element " << SvXMLImport::getPrefixAndNameFromToken(nElement
));
418 // now parse the attribute list and call the child context for each unknown attribute
419 for(auto& aIter
: *xCombinedAttrList
)
421 if (!pContext
->processAttribute( aIter
))
422 SAL_INFO("xmloff", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter
.getToken()) << " value=" << aIter
.toString());
429 css::uno::Reference
< css::xml::sax::XFastContextHandler
> XMLShapeImportHelper::CreateFrameChildContext(
430 SvXMLImportContext
*pThisContext
,
432 const uno::Reference
< xml::sax::XFastAttributeList
>& xAttrList
)
434 css::uno::Reference
< css::xml::sax::XFastContextHandler
> xContext
;
435 SdXMLFrameShapeContext
*pFrameContext
= dynamic_cast<SdXMLFrameShapeContext
*>( pThisContext
);
437 xContext
= pFrameContext
->createFastChildContext( nElement
, xAttrList
);
440 XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement
);
444 /** this function is called whenever the implementation classes like to add this new
445 shape to the given XShapes.
447 void XMLShapeImportHelper::addShape( uno::Reference
< drawing::XShape
>& rShape
,
448 const uno::Reference
< xml::sax::XFastAttributeList
>&,
449 uno::Reference
< drawing::XShapes
>& rShapes
)
451 if( rShape
.is() && rShapes
.is() )
453 // add new shape to parent
454 rShapes
->add( rShape
);
456 uno::Reference
<beans::XPropertySet
> xPropertySet(rShape
, uno::UNO_QUERY
);
457 if (xPropertySet
.is())
459 xPropertySet
->setPropertyValue(u
"HandlePathObjScale"_ustr
, uno::Any(true));
464 /** this function is called whenever the implementation classes have finished importing
465 a shape to the given XShapes. The shape is already inserted into its XShapes and
466 all properties and styles are set.
468 void XMLShapeImportHelper::finishShape(
469 css::uno::Reference
< css::drawing::XShape
>& rShape
,
470 const css::uno::Reference
< css::xml::sax::XFastAttributeList
>&,
471 css::uno::Reference
< css::drawing::XShapes
>&)
473 /* Set property <PositionLayoutDir>
474 to <PositionInHoriL2R>, if it exists and the import states that
475 the shape positioning attributes are in horizontal left-to-right
476 layout. This is the case for the OpenOffice.org file format.
477 This setting is done for Writer documents, because the property
478 only exists at service css::text::Shape - the Writer
479 UNO service for shapes.
480 The value indicates that the positioning attributes are given
481 in horizontal left-to-right layout. The property is evaluated
482 during the first positioning of the shape in order to convert
483 the shape position given in the OpenOffice.org file format to
484 the one for the OASIS Open Office file format. (#i28749#, #i36248#)
486 uno::Reference
< beans::XPropertySet
> xPropSet(rShape
, uno::UNO_QUERY
);
489 if ( mrImporter
.IsShapePositionInHoriL2R() &&
490 xPropSet
->getPropertySetInfo()->hasPropertyByName(
491 u
"PositionLayoutDir"_ustr
) )
493 uno::Any aPosLayoutDir
;
494 aPosLayoutDir
<<= text::PositionLayoutDir::PositionInHoriL2R
;
495 xPropSet
->setPropertyValue( u
"PositionLayoutDir"_ustr
, aPosLayoutDir
);
502 // helper functions for z-order sorting
507 /// The hint is for this shape. We don't use uno::Reference here to speed up
508 /// some operations, and because this shape is always held by mxShapes
509 drawing::XShape
* pShape
;
511 bool operator<(const ZOrderHint
& rComp
) const { return nShould
< rComp
.nShould
; }
514 // a) handle z-order of group contents after it has been imported
515 // b) apply group events over group contents after it has been imported
516 class ShapeGroupContext
519 uno::Reference
< drawing::XShapes
> mxShapes
;
520 std::vector
<SdXMLEventContextData
> maEventData
;
521 std::vector
<ZOrderHint
> maZOrderList
;
522 std::vector
<ZOrderHint
> maUnsortedList
;
524 sal_Int32 mnCurrentZ
;
525 std::shared_ptr
<ShapeGroupContext
> mpParentContext
;
527 ShapeGroupContext( uno::Reference
< drawing::XShapes
> xShapes
, std::shared_ptr
<ShapeGroupContext
> pParentContext
);
529 void popGroupAndPostProcess();
531 void moveShape( sal_Int32 nSourcePos
, sal_Int32 nDestPos
);
536 ShapeGroupContext::ShapeGroupContext( uno::Reference
< drawing::XShapes
> xShapes
, std::shared_ptr
<ShapeGroupContext
> pParentContext
)
537 : mxShapes(std::move( xShapes
)), mnCurrentZ( 0 ), mpParentContext( std::move(pParentContext
) )
541 void ShapeGroupContext::moveShape( sal_Int32 nSourcePos
, sal_Int32 nDestPos
)
543 uno::Any
aAny( mxShapes
->getByIndex( nSourcePos
) );
544 uno::Reference
< beans::XPropertySet
> xPropSet
;
547 if( !(xPropSet
.is() && xPropSet
->getPropertySetInfo()->hasPropertyByName( u
"ZOrder"_ustr
)) )
550 xPropSet
->setPropertyValue( u
"ZOrder"_ustr
, uno::Any(nDestPos
) );
552 for( ZOrderHint
& rHint
: maZOrderList
)
554 if( rHint
.nIs
< nSourcePos
)
556 DBG_ASSERT(rHint
.nIs
>= nDestPos
, "Shape sorting failed" );
561 for( ZOrderHint
& rHint
: maUnsortedList
)
563 if( rHint
.nIs
< nSourcePos
)
565 SAL_WARN_IF( rHint
.nIs
< nDestPos
, "xmloff", "shape sorting failed" );
572 void ShapeGroupContext::popGroupAndPostProcess()
574 if (!maEventData
.empty())
576 // tdf#127791 wait until a group is popped to set its event data
577 for (auto& event
: maEventData
)
578 event
.ApplyProperties();
582 // only do something if we have shapes to sort
583 if( maZOrderList
.empty() )
586 // check if there are more shapes than inserted with ::shapeWithZIndexAdded()
587 // This can happen if there where already shapes on the page before import
588 // Since the writer may delete some of this shapes during import, we need
589 // to do this here and not in our c'tor anymore
591 // check if we have more shapes than we know of
592 sal_Int32 nCount
= mxShapes
->getCount();
594 nCount
-= maZOrderList
.size();
595 nCount
-= maUnsortedList
.size();
599 // first update offsets of added shapes
600 for (ZOrderHint
& rHint
: maZOrderList
)
602 for (ZOrderHint
& rHint
: maUnsortedList
)
605 // second add the already existing shapes in the unsorted list
607 aNewHint
.pShape
= nullptr;
612 aNewHint
.nIs
= nCount
;
613 aNewHint
.nShould
= -1;
615 maUnsortedList
.insert(maUnsortedList
.begin(), aNewHint
);
620 bool bSorted
= std::is_sorted(maZOrderList
.begin(), maZOrderList
.end(),
621 [](const ZOrderHint
& rLeft
, const ZOrderHint
& rRight
)
622 { return rLeft
.nShould
< rRight
.nShould
; } );
625 return; // nothin' to do
627 // sort z-ordered shapes by nShould field
628 std::sort(maZOrderList
.begin(), maZOrderList
.end());
630 uno::Reference
<drawing::XShapes3
> xShapes3(mxShapes
, uno::UNO_QUERY
);
633 uno::Sequence
<sal_Int32
> aNewOrder(maZOrderList
.size() + maUnsortedList
.size());
634 auto pNewOrder
= aNewOrder
.getArray();
635 sal_Int32 nIndex
= 0;
637 for (const ZOrderHint
& rHint
: maZOrderList
)
639 // fill in the gaps from unordered list
640 for (std::vector
<ZOrderHint
>::iterator aIt
= maUnsortedList
.begin(); aIt
!= maUnsortedList
.end() && nIndex
< rHint
.nShould
; )
642 pNewOrder
[nIndex
++] = (*aIt
).nIs
;
643 aIt
= maUnsortedList
.erase(aIt
);
646 pNewOrder
[nIndex
] = rHint
.nIs
;
652 xShapes3
->sort(aNewOrder
);
653 maZOrderList
.clear();
656 catch (const css::lang::IllegalArgumentException
& /*e*/)
660 // this is the current index, all shapes before that
661 // index are finished
662 sal_Int32 nIndex
= 0;
663 for (const ZOrderHint
& rHint
: maZOrderList
)
665 for (std::vector
<ZOrderHint
>::iterator aIt
= maUnsortedList
.begin(); aIt
!= maUnsortedList
.end() && nIndex
< rHint
.nShould
; )
667 moveShape( (*aIt
).nIs
, nIndex
++ );
668 aIt
= maUnsortedList
.erase(aIt
);
672 if(rHint
.nIs
!= nIndex
)
673 moveShape( rHint
.nIs
, nIndex
);
677 maZOrderList
.clear();
680 void XMLShapeImportHelper::pushGroupForPostProcessing( uno::Reference
< drawing::XShapes
>& rShapes
)
682 mpImpl
->mpGroupContext
= std::make_shared
<ShapeGroupContext
>( rShapes
, mpImpl
->mpGroupContext
);
685 void XMLShapeImportHelper::addShapeEvents(SdXMLEventContextData
& rData
)
687 if (mpImpl
->mpGroupContext
&& mpImpl
->mpGroupContext
->mxShapes
== rData
.mxShape
)
689 // tdf#127791 wait until a group is popped to set its event data so
690 // that the events are applied to all its children, which are not available
691 // at the start of the group tag
692 mpImpl
->mpGroupContext
->maEventData
.push_back(rData
);
695 rData
.ApplyProperties();
698 void XMLShapeImportHelper::popGroupAndPostProcess()
700 SAL_WARN_IF( !mpImpl
->mpGroupContext
, "xmloff", "No context to sort!" );
701 if( !mpImpl
->mpGroupContext
)
706 mpImpl
->mpGroupContext
->popGroupAndPostProcess();
708 catch( const uno::Exception
& )
710 DBG_UNHANDLED_EXCEPTION("xmloff", "exception while sorting shapes, sorting failed");
713 // put parent on top and drop current context, we are done
714 mpImpl
->mpGroupContext
= mpImpl
->mpGroupContext
->mpParentContext
;
717 void XMLShapeImportHelper::shapeWithZIndexAdded( css::uno::Reference
< css::drawing::XShape
> const & xShape
, sal_Int32 nZIndex
)
719 if( !mpImpl
->mpGroupContext
)
723 aNewHint
.nIs
= mpImpl
->mpGroupContext
->mnCurrentZ
++;
724 aNewHint
.nShould
= nZIndex
;
725 aNewHint
.pShape
= xShape
.get();
729 // don't care, so add to unsorted list
730 mpImpl
->mpGroupContext
->maUnsortedList
.push_back(aNewHint
);
734 // insert into sort list
735 mpImpl
->mpGroupContext
->maZOrderList
.push_back(aNewHint
);
739 void XMLShapeImportHelper::shapeRemoved(const uno::Reference
<drawing::XShape
>& xShape
)
741 auto it
= std::find_if(mpImpl
->mpGroupContext
->maZOrderList
.begin(), mpImpl
->mpGroupContext
->maZOrderList
.end(), [&xShape
](const ZOrderHint
& rHint
)
743 return rHint
.pShape
== xShape
.get();
745 if (it
== mpImpl
->mpGroupContext
->maZOrderList
.end())
746 // Part of the unsorted list, nothing to do.
749 sal_Int32 nZIndex
= it
->nIs
;
751 for (it
= mpImpl
->mpGroupContext
->maZOrderList
.begin(); it
!= mpImpl
->mpGroupContext
->maZOrderList
.end();)
753 if (it
->nIs
== nZIndex
)
755 // This is xShape: remove it and adjust the max of indexes
757 it
= mpImpl
->mpGroupContext
->maZOrderList
.erase(it
);
758 mpImpl
->mpGroupContext
->mnCurrentZ
--;
761 else if (it
->nIs
> nZIndex
)
762 // On top of xShape: adjust actual index to reflect removal.
765 // On top of or below xShape.
770 void XMLShapeImportHelper::addShapeConnection( css::uno::Reference
< css::drawing::XShape
> const & rConnectorShape
,
772 const OUString
& rDestShapeId
,
773 sal_Int32 nDestGlueId
)
775 ConnectionHint aHint
;
776 aHint
.mxConnector
= rConnectorShape
;
777 aHint
.bStart
= bStart
;
778 aHint
.aDestShapeId
= rDestShapeId
;
779 aHint
.nDestGlueId
= nDestGlueId
;
781 mpImpl
->maConnections
.push_back( aHint
);
784 void XMLShapeImportHelper::restoreConnections()
786 const std::vector
<ConnectionHint
>::size_type nCount
= mpImpl
->maConnections
.size();
787 for( std::vector
<ConnectionHint
>::size_type i
= 0; i
< nCount
; i
++ )
789 ConnectionHint
& rHint
= mpImpl
->maConnections
[i
];
790 uno::Reference
< beans::XPropertySet
> xConnector( rHint
.mxConnector
, uno::UNO_QUERY
);
791 if( xConnector
.is() )
793 // #86637# remember line deltas
794 uno::Any aLine1Delta
;
795 uno::Any aLine2Delta
;
796 uno::Any aLine3Delta
;
797 OUString
aStr1(u
"EdgeLine1Delta"_ustr
);
798 OUString
aStr2(u
"EdgeLine2Delta"_ustr
);
799 OUString
aStr3(u
"EdgeLine3Delta"_ustr
);
800 aLine1Delta
= xConnector
->getPropertyValue(aStr1
);
801 aLine2Delta
= xConnector
->getPropertyValue(aStr2
);
802 aLine3Delta
= xConnector
->getPropertyValue(aStr3
);
804 // #86637# simply setting these values WILL force the connector to do
805 // a new layout promptly. So the line delta values have to be rescued
806 // and restored around connector changes.
807 uno::Reference
< drawing::XShape
> xShape(
808 mrImporter
.getInterfaceToIdentifierMapper().getReference( rHint
.aDestShapeId
), uno::UNO_QUERY
);
812 xConnector
->setPropertyValue( u
"StartShape"_ustr
, uno::Any(xShape
) );
814 xConnector
->setPropertyValue( u
"EndShape"_ustr
, uno::Any(xShape
) );
816 sal_Int32 nGlueId
= rHint
.nDestGlueId
< 4 ? rHint
.nDestGlueId
: getGluePointId( xShape
, rHint
.nDestGlueId
);
818 xConnector
->setPropertyValue( u
"StartGluePointIndex"_ustr
, uno::Any(nGlueId
) );
820 xConnector
->setPropertyValue( u
"EndGluePointIndex"_ustr
, uno::Any(nGlueId
) );
823 // #86637# restore line deltas
824 xConnector
->setPropertyValue(aStr1
, aLine1Delta
);
825 xConnector
->setPropertyValue(aStr2
, aLine2Delta
);
826 xConnector
->setPropertyValue(aStr3
, aLine3Delta
);
829 mpImpl
->maConnections
.clear();
832 SvXMLImportPropertyMapper
* XMLShapeImportHelper::CreateShapePropMapper( const uno::Reference
< frame::XModel
>& rModel
, SvXMLImport
& rImport
)
834 rtl::Reference
< XMLPropertyHandlerFactory
> xFactory
= new XMLSdPropHdlFactory( rModel
, rImport
);
835 rtl::Reference
< XMLPropertySetMapper
> xMapper
= new XMLShapePropertySetMapper( xFactory
, false );
836 SvXMLImportPropertyMapper
* pResult
= new SvXMLImportPropertyMapper( xMapper
, rImport
);
838 // chain text attributes
839 pResult
->ChainImportMapper( XMLTextImportHelper::CreateParaExtPropMapper( rImport
) );
843 /** adds a mapping for a gluepoint identifier from an xml file to the identifier created after inserting
844 the new gluepoint into the core. The saved mappings can be retrieved by getGluePointId() */
845 void XMLShapeImportHelper::addGluePointMapping( css::uno::Reference
< css::drawing::XShape
> const & xShape
,
846 sal_Int32 nSourceId
, sal_Int32 nDestinnationId
)
849 mpPageContext
->maShapeGluePointsMap
[xShape
][nSourceId
] = nDestinnationId
;
852 /** moves all current DestinationId's by n */
853 void XMLShapeImportHelper::moveGluePointMapping( const css::uno::Reference
< css::drawing::XShape
>& xShape
, const sal_Int32 n
)
857 ShapeGluePointsMap::iterator
aShapeIter( mpPageContext
->maShapeGluePointsMap
.find( xShape
) );
858 if( aShapeIter
!= mpPageContext
->maShapeGluePointsMap
.end() )
860 for ( auto& rShapeId
: (*aShapeIter
).second
)
862 if ( rShapeId
.second
!= -1 )
863 rShapeId
.second
+= n
;
869 /** retrieves a mapping for a gluepoint identifier from the current xml file to the identifier created after
870 inserting the new gluepoint into the core. The mapping must be initialized first with addGluePointMapping() */
871 sal_Int32
XMLShapeImportHelper::getGluePointId( const css::uno::Reference
< css::drawing::XShape
>& xShape
, sal_Int32 nSourceId
)
875 ShapeGluePointsMap::iterator
aShapeIter( mpPageContext
->maShapeGluePointsMap
.find( xShape
) );
876 if( aShapeIter
!= mpPageContext
->maShapeGluePointsMap
.end() )
878 GluePointIdMap::iterator aIdIter
= (*aShapeIter
).second
.find(nSourceId
);
879 if( aIdIter
!= (*aShapeIter
).second
.end() )
880 return (*aIdIter
).second
;
887 /** this method must be calling before the first shape is imported for the given page */
888 void XMLShapeImportHelper::startPage( css::uno::Reference
< css::drawing::XShapes
> const & rShapes
)
890 const std::shared_ptr
<XMLShapeImportPageContextImpl
> pOldContext
= mpPageContext
;
891 mpPageContext
= std::make_shared
<XMLShapeImportPageContextImpl
>();
892 mpPageContext
->mpNext
= pOldContext
;
893 mpPageContext
->mxShapes
= rShapes
;
896 /** this method must be calling after the last shape is imported for the given page */
897 void XMLShapeImportHelper::endPage( css::uno::Reference
< css::drawing::XShapes
> const & rShapes
)
899 SAL_WARN_IF( !mpPageContext
|| (mpPageContext
->mxShapes
!= rShapes
), "xmloff", "wrong call to endPage(), no startPage called or wrong page" );
900 if( nullptr == mpPageContext
)
903 restoreConnections();
905 mpPageContext
= mpPageContext
->mpNext
;
908 /** defines if the import should increment the progress bar or not */
909 void XMLShapeImportHelper::enableHandleProgressBar()
911 mpImpl
->mbHandleProgressBar
= true;
914 bool XMLShapeImportHelper::IsHandleProgressBarEnabled() const
916 return mpImpl
->mbHandleProgressBar
;
919 /** queries the capability of the current model to create presentation shapes */
920 bool XMLShapeImportHelper::IsPresentationShapesSupported() const
922 return mpImpl
->mbIsPresentationShapesSupported
;
925 const rtl::Reference
< XMLTableImport
>& XMLShapeImportHelper::GetShapeTableImport()
927 if( !mxShapeTableImport
.is() )
929 rtl::Reference
< XMLPropertyHandlerFactory
> xFactory( new XMLSdPropHdlFactory( mrImporter
.GetModel(), mrImporter
) );
930 rtl::Reference
< XMLPropertySetMapper
> xPropertySetMapper( new XMLShapePropertySetMapper( xFactory
, false ) );
931 mxShapeTableImport
= new XMLTableImport( mrImporter
, xPropertySetMapper
, xFactory
);
934 return mxShapeTableImport
;
937 void SvXMLShapeContext::setHyperlink( const OUString
& rHyperlink
)
939 msHyperlink
= rHyperlink
;
942 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */