LibreOffice Module xmloff (master) 1
shapeimport.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <tools/debug.hxx>
22#include <sal/log.hxx>
24
25#include <com/sun/star/beans/XPropertySet.hpp>
26#include <com/sun/star/text/PositionLayoutDir.hpp>
27#include <com/sun/star/drawing/XShapes3.hpp>
28
29#include <utility>
31
33#include <xmloff/xmlstyle.hxx>
34#include <xmloff/xmltkmap.hxx>
36#include <xmloff/xmltoken.hxx>
38#include <xmloff/attrlist.hxx>
39#include "eventimp.hxx"
40#include "ximpshap.hxx"
41#include "sdpropls.hxx"
42#include <xmloff/xmlprmap.hxx>
43#include "ximp3dscene.hxx"
44#include "ximp3dobject.hxx"
45#include "ximpgrp.hxx"
46#include "ximplink.hxx"
47
48#include <unordered_map>
49#include <string_view>
50#include <vector>
51
52namespace {
53
54class ShapeGroupContext;
55
56}
57
58using namespace ::std;
59using namespace ::com::sun::star;
60using namespace ::xmloff::token;
61
62namespace {
63
64struct ConnectionHint
65{
66 css::uno::Reference< css::drawing::XShape > mxConnector;
67 OUString aDestShapeId;
68 sal_Int32 nDestGlueId;
69 bool bStart;
70};
71
72}
73
76typedef std::map<sal_Int32,sal_Int32> GluePointIdMap;
77typedef std::unordered_map< css::uno::Reference < css::drawing::XShape >, GluePointIdMap > ShapeGluePointsMap;
78
83{
85
86 uno::Reference < drawing::XShapes > mxShapes;
87
88 std::shared_ptr<XMLShapeImportPageContextImpl> mpNext;
89};
90
93{
94 // context for sorting shapes
95 std::shared_ptr<ShapeGroupContext> mpGroupContext;
96
97 std::vector<ConnectionHint> maConnections;
98
99 // #88546# possibility to switch progress bar handling on/off
101
102 // stores the capability of the current model to create presentation shapes
104};
105
106constexpr OUStringLiteral gsStartShape(u"StartShape");
107constexpr OUStringLiteral gsEndShape(u"EndShape");
108constexpr OUStringLiteral gsStartGluePointIndex(u"StartGluePointIndex");
109constexpr OUStringLiteral gsEndGluePointIndex(u"EndGluePointIndex");
110
112 SvXMLImport& rImporter,
113 const uno::Reference< frame::XModel>& rModel,
114 SvXMLImportPropertyMapper *pExtMapper )
115: mpImpl( new XMLShapeImportHelperImpl ),
116 mrImporter( rImporter )
117{
118 mpImpl->mpGroupContext = nullptr;
119
120 // #88546# init to sal_False
121 mpImpl->mbHandleProgressBar = false;
122
123 mpSdPropHdlFactory = new XMLSdPropHdlFactory( rModel, rImporter );
124
125 // construct PropertySetMapper
127 mpPropertySetMapper = new SvXMLImportPropertyMapper( xMapper, rImporter );
128
129 if( pExtMapper )
130 {
131 rtl::Reference < SvXMLImportPropertyMapper > xExtMapper( pExtMapper );
132 mpPropertySetMapper->ChainImportMapper( xExtMapper );
133 }
134
135 // chain text attributes
138
139 // construct PresPagePropsMapper
141 mpPresPagePropsMapper = new SvXMLImportPropertyMapper( xMapper, rImporter );
142
143 uno::Reference< lang::XServiceInfo > xInfo( rImporter.GetModel(), uno::UNO_QUERY );
144 mpImpl->mbIsPresentationShapesSupported = xInfo.is() && xInfo->supportsService( "com.sun.star.presentation.PresentationDocument" );
145}
146
148{
149 SAL_WARN_IF( !mpImpl->maConnections.empty(), "xmloff", "XMLShapeImportHelper::restoreConnections() was not called!" );
150
151 // cleanup factory, decrease refcount. Should lead to destruction.
152 mpSdPropHdlFactory.clear();
153
154 // cleanup mapper, decrease refcount. Should lead to destruction.
155 mpPropertySetMapper.clear();
156
157 // cleanup presPage mapper, decrease refcount. Should lead to destruction.
158 mpPresPagePropsMapper.clear();
159
160 // Styles or AutoStyles context?
161 if(mxStylesContext.is())
162 mxStylesContext->dispose();
163
164 if(mxAutoStylesContext.is())
165 mxAutoStylesContext->dispose();
166}
167
168
170 SvXMLImport& rImport,
171 sal_Int32 nElement,
172 const uno::Reference< xml::sax::XFastAttributeList>& xAttrList,
173 uno::Reference< drawing::XShapes > const & rShapes)
174{
175 SdXMLShapeContext *pContext = nullptr;
176
177 if(rShapes.is())
178 {
179 switch(nElement)
180 {
181 case XML_ELEMENT(DR3D, XML_SCENE):
182 {
183 // dr3d:3dscene inside dr3d:3dscene context
184 pContext = new SdXML3DSceneShapeContext( rImport, xAttrList, rShapes, false);
185 break;
186 }
187 case XML_ELEMENT(DR3D, XML_CUBE):
188 {
189 // dr3d:3dcube inside dr3d:3dscene context
190 pContext = new SdXML3DCubeObjectShapeContext( rImport, xAttrList, rShapes);
191 break;
192 }
193 case XML_ELEMENT(DR3D, XML_SPHERE):
194 {
195 // dr3d:3dsphere inside dr3d:3dscene context
196 pContext = new SdXML3DSphereObjectShapeContext( rImport, xAttrList, rShapes);
197 break;
198 }
199 case XML_ELEMENT(DR3D, XML_ROTATE):
200 {
201 // dr3d:3dlathe inside dr3d:3dscene context
202 pContext = new SdXML3DLatheObjectShapeContext( rImport, xAttrList, rShapes);
203 break;
204 }
205 case XML_ELEMENT(DR3D, XML_EXTRUDE):
206 {
207 // dr3d:3dextrude inside dr3d:3dscene context
208 pContext = new SdXML3DExtrudeObjectShapeContext( rImport, xAttrList, rShapes);
209 break;
210 }
211 default:
212 XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
213 }
214 }
215
216 if (!pContext)
217 return nullptr;
218
219 // now parse the attribute list and call the child context for each unknown attribute
220 for(auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList))
221 {
222 if (!pContext->processAttribute( aIter ))
223 XMLOFF_WARN_UNKNOWN("xmloff", aIter);
224
225 }
226
227 return pContext;
228}
229
231{
232 mxStylesContext.set(pNew);
233}
234
236{
237 mxAutoStylesContext.set(pNew);
238}
239
241 SvXMLImport& rImport,
242 sal_Int32 nElement,
243 const uno::Reference< xml::sax::XFastAttributeList>& xAttrList,
244 uno::Reference< drawing::XShapes > const & rShapes,
245 bool bTemporaryShape)
246{
247 SdXMLShapeContext *pContext = nullptr;
248 switch (nElement)
249 {
250 case XML_ELEMENT(DRAW, XML_G):
251 // draw:g inside group context (RECURSIVE)
252 pContext = new SdXMLGroupShapeContext( rImport, xAttrList, rShapes, bTemporaryShape);
253 break;
254 case XML_ELEMENT(DR3D, XML_SCENE):
255 {
256 // dr3d:3dscene inside group context
257 pContext = new SdXML3DSceneShapeContext( rImport, xAttrList, rShapes, bTemporaryShape);
258 break;
259 }
261 {
262 // draw:rect inside group context
263 pContext = new SdXMLRectShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
264 break;
265 }
267 {
268 // draw:line inside group context
269 pContext = new SdXMLLineShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
270 break;
271 }
274 {
275 // draw:circle or draw:ellipse inside group context
276 pContext = new SdXMLEllipseShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
277 break;
278 }
281 {
282 // draw:polygon or draw:polyline inside group context
283 pContext = new SdXMLPolygonShapeContext( rImport, xAttrList, rShapes,
284 nElement == XML_ELEMENT(DRAW, XML_POLYGON), bTemporaryShape );
285 break;
286 }
288 {
289 // draw:path inside group context
290 pContext = new SdXMLPathShapeContext( rImport, xAttrList, rShapes, bTemporaryShape);
291 break;
292 }
294 {
295 // text:text-box inside group context
296 pContext = new SdXMLFrameShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
297 break;
298 }
300 {
301 // draw:control inside group context
302 pContext = new SdXMLControlShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
303 break;
304 }
306 {
307 // draw:connector inside group context
308 pContext = new SdXMLConnectorShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
309 break;
310 }
312 {
313 // draw:measure inside group context
314 pContext = new SdXMLMeasureShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
315 break;
316 }
318 {
319 // draw:page inside group context
320 pContext = new SdXMLPageShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
321 break;
322 }
325 {
326 // draw:caption inside group context
327 pContext = new SdXMLCaptionShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
328 break;
329 }
331 {
332 // chart:chart inside group context
333 pContext = new SdXMLChartShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
334 break;
335 }
337 {
338 // draw:customshape
339 pContext = new SdXMLCustomShapeContext( rImport, xAttrList, rShapes );
340 break;
341 }
342 case XML_ELEMENT(DRAW, XML_A):
343 return new SdXMLShapeLinkContext( rImport, xAttrList, rShapes );
344 // add other shapes here...
345 default:
346 XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
347 return new SvXMLShapeContext( rImport, bTemporaryShape );
348 }
349
350 // now parse the attribute list and call the child context for each unknown attribute
351 for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ))
352 {
353 if (!pContext->processAttribute( aIter ))
354 XMLOFF_WARN_UNKNOWN("xmloff", aIter);
355 }
356 return pContext;
357}
358
359// This method is called from SdXMLFrameShapeContext to create children of draw:frame
361 SvXMLImport& rImport,
362 sal_Int32 nElement,
363 const uno::Reference< xml::sax::XFastAttributeList>& rAttrList,
364 uno::Reference< drawing::XShapes > const & rShapes,
365 const uno::Reference< xml::sax::XFastAttributeList>& rFrameAttrList)
366{
367 SdXMLShapeContext *pContext = nullptr;
368
370 if( rFrameAttrList.is() )
371 xCombinedAttrList->add(rFrameAttrList);
372
373 switch(nElement)
374 {
375 case XML_ELEMENT(DRAW, XML_TEXT_BOX):
376 {
377 // text:text-box inside group context
378 pContext = new SdXMLTextBoxShapeContext( rImport, xCombinedAttrList, rShapes );
379 break;
380 }
381 case XML_ELEMENT(DRAW, XML_IMAGE):
382 {
383 // office:image inside group context
384 pContext = new SdXMLGraphicObjectShapeContext( rImport, xCombinedAttrList, rShapes );
385 break;
386 }
387 case XML_ELEMENT(DRAW, XML_OBJECT):
389 {
390 // draw:object or draw:object_ole
391 pContext = new SdXMLObjectShapeContext( rImport, xCombinedAttrList, rShapes );
392 break;
393 }
394 case XML_ELEMENT(TABLE, XML_TABLE):
395 {
396 // draw:object or draw:object_ole
397 if( rImport.IsTableShapeSupported() )
398 pContext = new SdXMLTableShapeContext( rImport, xCombinedAttrList, rShapes );
399 break;
400
401 }
402 case XML_ELEMENT(DRAW, XML_PLUGIN):
403 {
404 // draw:plugin
405 pContext = new SdXMLPluginShapeContext( rImport, xCombinedAttrList, rShapes );
406 break;
407 }
409 {
410 // draw:floating-frame
411 pContext = new SdXMLFloatingFrameShapeContext( rImport, xCombinedAttrList, rShapes );
412 break;
413 }
414 case XML_ELEMENT(DRAW, XML_APPLET):
415 {
416 // draw:applet
417 pContext = new SdXMLAppletShapeContext( rImport, xCombinedAttrList, rShapes );
418 break;
419 }
420 // add other shapes here...
421 default:
422 SAL_INFO("xmloff", "unknown element " << SvXMLImport::getPrefixAndNameFromToken(nElement));
423 break;
424 }
425
426 if( pContext )
427 {
428 // now parse the attribute list and call the child context for each unknown attribute
429 for(auto& aIter : *xCombinedAttrList)
430 {
431 if (!pContext->processAttribute( aIter ))
432 SAL_INFO("xmloff", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << " value=" << aIter.toString());
433 }
434 }
435
436 return pContext;
437}
438
439css::uno::Reference< css::xml::sax::XFastContextHandler > XMLShapeImportHelper::CreateFrameChildContext(
440 SvXMLImportContext *pThisContext,
441 sal_Int32 nElement,
442 const uno::Reference< xml::sax::XFastAttributeList>& xAttrList )
443{
444 css::uno::Reference< css::xml::sax::XFastContextHandler > xContext;
445 SdXMLFrameShapeContext *pFrameContext = dynamic_cast<SdXMLFrameShapeContext*>( pThisContext );
446 if (pFrameContext)
447 xContext = pFrameContext->createFastChildContext( nElement, xAttrList );
448
449 if (!xContext)
450 XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
451 return xContext;
452}
453
457void XMLShapeImportHelper::addShape( uno::Reference< drawing::XShape >& rShape,
458 const uno::Reference< xml::sax::XFastAttributeList >&,
459 uno::Reference< drawing::XShapes >& rShapes)
460{
461 if( rShape.is() && rShapes.is() )
462 {
463 // add new shape to parent
464 rShapes->add( rShape );
465
466 uno::Reference<beans::XPropertySet> xPropertySet(rShape, uno::UNO_QUERY);
467 if (xPropertySet.is())
468 {
469 static constexpr OUStringLiteral sHandlePathObjScale = u"HandlePathObjScale";
470 xPropertySet->setPropertyValue(sHandlePathObjScale, uno::Any(true));
471 }
472 }
473}
474
480 css::uno::Reference< css::drawing::XShape >& rShape,
481 const css::uno::Reference< css::xml::sax::XFastAttributeList >&,
482 css::uno::Reference< css::drawing::XShapes >&)
483{
484 /* Set property <PositionLayoutDir>
485 to <PositionInHoriL2R>, if it exists and the import states that
486 the shape positioning attributes are in horizontal left-to-right
487 layout. This is the case for the OpenOffice.org file format.
488 This setting is done for Writer documents, because the property
489 only exists at service css::text::Shape - the Writer
490 UNO service for shapes.
491 The value indicates that the positioning attributes are given
492 in horizontal left-to-right layout. The property is evaluated
493 during the first positioning of the shape in order to convert
494 the shape position given in the OpenOffice.org file format to
495 the one for the OASIS Open Office file format. (#i28749#, #i36248#)
496 */
497 uno::Reference< beans::XPropertySet > xPropSet(rShape, uno::UNO_QUERY);
498 if ( xPropSet.is() )
499 {
501 xPropSet->getPropertySetInfo()->hasPropertyByName(
502 "PositionLayoutDir") )
503 {
504 uno::Any aPosLayoutDir;
505 aPosLayoutDir <<= text::PositionLayoutDir::PositionInHoriL2R;
506 xPropSet->setPropertyValue( "PositionLayoutDir", aPosLayoutDir );
507 }
508 }
509}
510
511namespace {
512
513// helper functions for z-order sorting
514struct ZOrderHint
515{
516 sal_Int32 nIs;
517 sal_Int32 nShould;
520 drawing::XShape* pShape;
521
522 bool operator<(const ZOrderHint& rComp) const { return nShould < rComp.nShould; }
523};
524
525// a) handle z-order of group contents after it has been imported
526// b) apply group events over group contents after it has been imported
527class ShapeGroupContext
528{
529public:
530 uno::Reference< drawing::XShapes > mxShapes;
531 std::vector<SdXMLEventContextData> maEventData;
532 vector<ZOrderHint> maZOrderList;
533 vector<ZOrderHint> maUnsortedList;
534
535 sal_Int32 mnCurrentZ;
536 std::shared_ptr<ShapeGroupContext> mpParentContext;
537
538 ShapeGroupContext( uno::Reference< drawing::XShapes > xShapes, std::shared_ptr<ShapeGroupContext> pParentContext );
539
540 void popGroupAndPostProcess();
541private:
542 void moveShape( sal_Int32 nSourcePos, sal_Int32 nDestPos );
543};
544
545}
546
547ShapeGroupContext::ShapeGroupContext( uno::Reference< drawing::XShapes > xShapes, std::shared_ptr<ShapeGroupContext> pParentContext )
548: mxShapes(std::move( xShapes )), mnCurrentZ( 0 ), mpParentContext( std::move(pParentContext) )
549{
550}
551
552void ShapeGroupContext::moveShape( sal_Int32 nSourcePos, sal_Int32 nDestPos )
553{
554 uno::Any aAny( mxShapes->getByIndex( nSourcePos ) );
555 uno::Reference< beans::XPropertySet > xPropSet;
556 aAny >>= xPropSet;
557
558 if( !(xPropSet.is() && xPropSet->getPropertySetInfo()->hasPropertyByName( "ZOrder" )) )
559 return;
560
561 xPropSet->setPropertyValue( "ZOrder", uno::Any(nDestPos) );
562
563 for( ZOrderHint& rHint : maZOrderList )
564 {
565 if( rHint.nIs < nSourcePos )
566 {
567 DBG_ASSERT(rHint.nIs >= nDestPos, "Shape sorting failed" );
568 rHint.nIs++;
569 }
570 }
571
572 for( ZOrderHint& rHint : maUnsortedList )
573 {
574 if( rHint.nIs < nSourcePos )
575 {
576 SAL_WARN_IF( rHint.nIs < nDestPos, "xmloff", "shape sorting failed" );
577 rHint.nIs++;
578 }
579 }
580}
581
582// sort shapes
583void ShapeGroupContext::popGroupAndPostProcess()
584{
585 if (!maEventData.empty())
586 {
587 // tdf#127791 wait until a group is popped to set its event data
588 for (auto& event : maEventData)
589 event.ApplyProperties();
590 maEventData.clear();
591 }
592
593 // only do something if we have shapes to sort
594 if( maZOrderList.empty() )
595 return;
596
597 // check if there are more shapes than inserted with ::shapeWithZIndexAdded()
598 // This can happen if there where already shapes on the page before import
599 // Since the writer may delete some of this shapes during import, we need
600 // to do this here and not in our c'tor anymore
601
602 // check if we have more shapes than we know of
603 sal_Int32 nCount = mxShapes->getCount();
604
605 nCount -= maZOrderList.size();
606 nCount -= maUnsortedList.size();
607
608 if( nCount > 0 )
609 {
610 // first update offsets of added shapes
611 for (ZOrderHint& rHint : maZOrderList)
612 rHint.nIs += nCount;
613 for (ZOrderHint& rHint : maUnsortedList)
614 rHint.nIs += nCount;
615
616 // second add the already existing shapes in the unsorted list
617 ZOrderHint aNewHint;
618 aNewHint.pShape = nullptr;
619 do
620 {
621 nCount--;
622
623 aNewHint.nIs = nCount;
624 aNewHint.nShould = -1;
625
626 maUnsortedList.insert(maUnsortedList.begin(), aNewHint);
627 }
628 while( nCount );
629 }
630
631 bool bSorted = std::is_sorted(maZOrderList.begin(), maZOrderList.end(),
632 [](const ZOrderHint& rLeft, const ZOrderHint& rRight)
633 { return rLeft.nShould < rRight.nShould; } );
634
635 if (bSorted)
636 return; // nothin' to do
637
638 // sort z-ordered shapes by nShould field
639 std::sort(maZOrderList.begin(), maZOrderList.end());
640
641 uno::Reference<drawing::XShapes3> xShapes3(mxShapes, uno::UNO_QUERY);
642 if( xShapes3.is())
643 {
644 uno::Sequence<sal_Int32> aNewOrder(maZOrderList.size() + maUnsortedList.size());
645 auto pNewOrder = aNewOrder.getArray();
646 sal_Int32 nIndex = 0;
647
648 for (const ZOrderHint& rHint : maZOrderList)
649 {
650 // fill in the gaps from unordered list
651 for (vector<ZOrderHint>::iterator aIt = maUnsortedList.begin(); aIt != maUnsortedList.end() && nIndex < rHint.nShould; )
652 {
653 pNewOrder[nIndex++] = (*aIt).nIs;
654 aIt = maUnsortedList.erase(aIt);
655 }
656
657 pNewOrder[nIndex] = rHint.nIs;
658 nIndex++;
659 }
660
661 try
662 {
663 xShapes3->sort(aNewOrder);
664 maZOrderList.clear();
665 return;
666 }
667 catch (const css::lang::IllegalArgumentException& /*e*/)
668 {}
669 }
670
671 // this is the current index, all shapes before that
672 // index are finished
673 sal_Int32 nIndex = 0;
674 for (const ZOrderHint& rHint : maZOrderList)
675 {
676 for (vector<ZOrderHint>::iterator aIt = maUnsortedList.begin(); aIt != maUnsortedList.end() && nIndex < rHint.nShould; )
677 {
678 moveShape( (*aIt).nIs, nIndex++ );
679 aIt = maUnsortedList.erase(aIt);
680
681 }
682
683 if(rHint.nIs != nIndex )
684 moveShape( rHint.nIs, nIndex );
685
686 nIndex++;
687 }
688 maZOrderList.clear();
689}
690
691void XMLShapeImportHelper::pushGroupForPostProcessing( uno::Reference< drawing::XShapes >& rShapes )
692{
693 mpImpl->mpGroupContext = std::make_shared<ShapeGroupContext>( rShapes, mpImpl->mpGroupContext );
694}
695
697{
698 if (mpImpl->mpGroupContext && mpImpl->mpGroupContext->mxShapes == rData.mxShape)
699 {
700 // tdf#127791 wait until a group is popped to set its event data so
701 // that the events are applied to all its children, which are not available
702 // at the start of the group tag
703 mpImpl->mpGroupContext->maEventData.push_back(rData);
704 }
705 else
706 rData.ApplyProperties();
707}
708
710{
711 SAL_WARN_IF( !mpImpl->mpGroupContext, "xmloff", "No context to sort!" );
712 if( !mpImpl->mpGroupContext )
713 return;
714
715 try
716 {
717 mpImpl->mpGroupContext->popGroupAndPostProcess();
718 }
719 catch( const uno::Exception& )
720 {
721 DBG_UNHANDLED_EXCEPTION("xmloff", "exception while sorting shapes, sorting failed");
722 }
723
724 // put parent on top and drop current context, we are done
725 mpImpl->mpGroupContext = mpImpl->mpGroupContext->mpParentContext;
726}
727
728void XMLShapeImportHelper::shapeWithZIndexAdded( css::uno::Reference< css::drawing::XShape > const & xShape, sal_Int32 nZIndex )
729{
730 if( !mpImpl->mpGroupContext)
731 return;
732
733 ZOrderHint aNewHint;
734 aNewHint.nIs = mpImpl->mpGroupContext->mnCurrentZ++;
735 aNewHint.nShould = nZIndex;
736 aNewHint.pShape = xShape.get();
737
738 if( nZIndex == -1 )
739 {
740 // don't care, so add to unsorted list
741 mpImpl->mpGroupContext->maUnsortedList.push_back(aNewHint);
742 }
743 else
744 {
745 // insert into sort list
746 mpImpl->mpGroupContext->maZOrderList.push_back(aNewHint);
747 }
748}
749
750void XMLShapeImportHelper::shapeRemoved(const uno::Reference<drawing::XShape>& xShape)
751{
752 auto it = std::find_if(mpImpl->mpGroupContext->maZOrderList.begin(), mpImpl->mpGroupContext->maZOrderList.end(), [&xShape](const ZOrderHint& rHint)
753 {
754 return rHint.pShape == xShape.get();
755 });
756 if (it == mpImpl->mpGroupContext->maZOrderList.end())
757 // Part of the unsorted list, nothing to do.
758 return;
759
760 sal_Int32 nZIndex = it->nIs;
761
762 for (it = mpImpl->mpGroupContext->maZOrderList.begin(); it != mpImpl->mpGroupContext->maZOrderList.end();)
763 {
764 if (it->nIs == nZIndex)
765 {
766 // This is xShape: remove it and adjust the max of indexes
767 // accordingly.
768 it = mpImpl->mpGroupContext->maZOrderList.erase(it);
769 mpImpl->mpGroupContext->mnCurrentZ--;
770 continue;
771 }
772 else if (it->nIs > nZIndex)
773 // On top of xShape: adjust actual index to reflect removal.
774 it->nIs--;
775
776 // On top of or below xShape.
777 ++it;
778 }
779}
780
781void XMLShapeImportHelper::addShapeConnection( css::uno::Reference< css::drawing::XShape > const & rConnectorShape,
782 bool bStart,
783 const OUString& rDestShapeId,
784 sal_Int32 nDestGlueId )
785{
786 ConnectionHint aHint;
787 aHint.mxConnector = rConnectorShape;
788 aHint.bStart = bStart;
789 aHint.aDestShapeId = rDestShapeId;
790 aHint.nDestGlueId = nDestGlueId;
791
792 mpImpl->maConnections.push_back( aHint );
793}
794
796{
797 const vector<ConnectionHint>::size_type nCount = mpImpl->maConnections.size();
798 for( vector<ConnectionHint>::size_type i = 0; i < nCount; i++ )
799 {
800 ConnectionHint& rHint = mpImpl->maConnections[i];
801 uno::Reference< beans::XPropertySet > xConnector( rHint.mxConnector, uno::UNO_QUERY );
802 if( xConnector.is() )
803 {
804 // #86637# remember line deltas
805 uno::Any aLine1Delta;
806 uno::Any aLine2Delta;
807 uno::Any aLine3Delta;
808 OUString aStr1("EdgeLine1Delta");
809 OUString aStr2("EdgeLine2Delta");
810 OUString aStr3("EdgeLine3Delta");
811 aLine1Delta = xConnector->getPropertyValue(aStr1);
812 aLine2Delta = xConnector->getPropertyValue(aStr2);
813 aLine3Delta = xConnector->getPropertyValue(aStr3);
814
815 // #86637# simply setting these values WILL force the connector to do
816 // a new layout promptly. So the line delta values have to be rescued
817 // and restored around connector changes.
818 uno::Reference< drawing::XShape > xShape(
819 mrImporter.getInterfaceToIdentifierMapper().getReference( rHint.aDestShapeId ), uno::UNO_QUERY );
820 if( xShape.is() )
821 {
822 if (rHint.bStart)
823 xConnector->setPropertyValue( gsStartShape, uno::Any(xShape) );
824 else
825 xConnector->setPropertyValue( gsEndShape, uno::Any(xShape) );
826
827 sal_Int32 nGlueId = rHint.nDestGlueId < 4 ? rHint.nDestGlueId : getGluePointId( xShape, rHint.nDestGlueId );
828 if(rHint.bStart)
829 xConnector->setPropertyValue( gsStartGluePointIndex, uno::Any(nGlueId) );
830 else
831 xConnector->setPropertyValue( gsEndGluePointIndex, uno::Any(nGlueId) );
832 }
833
834 // #86637# restore line deltas
835 xConnector->setPropertyValue(aStr1, aLine1Delta );
836 xConnector->setPropertyValue(aStr2, aLine2Delta );
837 xConnector->setPropertyValue(aStr3, aLine3Delta );
838 }
839 }
840 mpImpl->maConnections.clear();
841}
842
843SvXMLImportPropertyMapper* XMLShapeImportHelper::CreateShapePropMapper( const uno::Reference< frame::XModel>& rModel, SvXMLImport& rImport )
844{
847 SvXMLImportPropertyMapper* pResult = new SvXMLImportPropertyMapper( xMapper, rImport );
848
849 // chain text attributes
851 return pResult;
852}
853
856void XMLShapeImportHelper::addGluePointMapping( css::uno::Reference< css::drawing::XShape > const & xShape,
857 sal_Int32 nSourceId, sal_Int32 nDestinnationId )
858{
859 if( mpPageContext )
860 mpPageContext->maShapeGluePointsMap[xShape][nSourceId] = nDestinnationId;
861}
862
864void XMLShapeImportHelper::moveGluePointMapping( const css::uno::Reference< css::drawing::XShape >& xShape, const sal_Int32 n )
865{
866 if( mpPageContext )
867 {
868 ShapeGluePointsMap::iterator aShapeIter( mpPageContext->maShapeGluePointsMap.find( xShape ) );
869 if( aShapeIter != mpPageContext->maShapeGluePointsMap.end() )
870 {
871 for ( auto& rShapeId : (*aShapeIter).second )
872 {
873 if ( rShapeId.second != -1 )
874 rShapeId.second += n;
875 }
876 }
877 }
878}
879
882sal_Int32 XMLShapeImportHelper::getGluePointId( const css::uno::Reference< css::drawing::XShape >& xShape, sal_Int32 nSourceId )
883{
884 if( mpPageContext )
885 {
886 ShapeGluePointsMap::iterator aShapeIter( mpPageContext->maShapeGluePointsMap.find( xShape ) );
887 if( aShapeIter != mpPageContext->maShapeGluePointsMap.end() )
888 {
889 GluePointIdMap::iterator aIdIter = (*aShapeIter).second.find(nSourceId);
890 if( aIdIter != (*aShapeIter).second.end() )
891 return (*aIdIter).second;
892 }
893 }
894
895 return -1;
896}
897
899void XMLShapeImportHelper::startPage( css::uno::Reference< css::drawing::XShapes > const & rShapes )
900{
901 const std::shared_ptr<XMLShapeImportPageContextImpl> pOldContext = mpPageContext;
902 mpPageContext = std::make_shared<XMLShapeImportPageContextImpl>();
903 mpPageContext->mpNext = pOldContext;
904 mpPageContext->mxShapes = rShapes;
905}
906
908void XMLShapeImportHelper::endPage( css::uno::Reference< css::drawing::XShapes > const & rShapes )
909{
910 SAL_WARN_IF( !mpPageContext || (mpPageContext->mxShapes != rShapes), "xmloff", "wrong call to endPage(), no startPage called or wrong page" );
911 if( nullptr == mpPageContext )
912 return;
913
915
917}
918
921{
922 mpImpl->mbHandleProgressBar = true;
923}
924
926{
927 return mpImpl->mbHandleProgressBar;
928}
929
932{
933 return mpImpl->mbIsPresentationShapesSupported;
934}
935
937{
938 if( !mxShapeTableImport.is() )
939 {
942 mxShapeTableImport = new XMLTableImport( mrImporter, xPropertySetMapper, xFactory );
943 }
944
945 return mxShapeTableImport;
946}
947
948void SvXMLShapeContext::setHyperlink( const OUString& rHyperlink )
949{
950 msHyperlink = rHyperlink;
951}
952
953/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &AttrList) override
Definition: ximpshap.cxx:3308
virtual bool processAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter &)
Definition: ximpshap.cxx:795
This class deliberately does not support XWeak, to improve performance when loading large documents.
Definition: xmlictxt.hxx:48
void ChainImportMapper(const rtl::Reference< SvXMLImportPropertyMapper > &rMapper)
Definition: xmlimppr.cxx:76
bool IsShapePositionInHoriL2R() const
Definition: xmlimp.cxx:1812
::comphelper::UnoInterfaceToUniqueIdentifierMapper & getInterfaceToIdentifierMapper()
Definition: xmlimp.cxx:1790
static OUString getPrefixAndNameFromToken(sal_Int32 nToken)
Definition: xmlimp.cxx:1957
const css::uno::Reference< css::frame::XModel > & GetModel() const
Definition: xmlimp.hxx:405
bool IsTableShapeSupported() const
Definition: xmlimp.hxx:464
void setHyperlink(const OUString &rHyperlink)
rtl::Reference< SvXMLImportPropertyMapper > mpPresPagePropsMapper
void addGluePointMapping(css::uno::Reference< css::drawing::XShape > const &xShape, sal_Int32 nSourceId, sal_Int32 nDestinnationId)
adds a mapping for a gluepoint identifier from an xml file to the identifier created after inserting ...
void shapeRemoved(const css::uno::Reference< css::drawing::XShape > &rShape)
Updates the z-order of other shapes to be consistent again, needed due to the removal of rShape.
static SvXMLShapeContext * CreateGroupChildContext(SvXMLImport &rImport, sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList, css::uno::Reference< css::drawing::XShapes > const &rShapes, bool bTemporaryShape=false)
void addShapeConnection(css::uno::Reference< css::drawing::XShape > const &rConnectorShape, bool bStart, const OUString &rDestShapeId, sal_Int32 nDestGlueId)
virtual ~XMLShapeImportHelper() override
virtual void addShape(css::uno::Reference< css::drawing::XShape > &rShape, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList, css::uno::Reference< css::drawing::XShapes > &rShapes)
this function is called whenever the implementation classes like to add this new shape to the given X...
SvXMLImport & mrImporter
virtual void finishShape(css::uno::Reference< css::drawing::XShape > &rShape, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList, css::uno::Reference< css::drawing::XShapes > &rShapes)
this function is called whenever the implementation classes have finished importing a shape to the gi...
rtl::Reference< SvXMLImportPropertyMapper > mpPropertySetMapper
void pushGroupForPostProcessing(css::uno::Reference< css::drawing::XShapes > &rShapes)
rtl::Reference< SvXMLStylesContext > mxAutoStylesContext
rtl::Reference< XMLTableImport > mxShapeTableImport
rtl::Reference< XMLSdPropHdlFactory > mpSdPropHdlFactory
static SvXMLShapeContext * CreateFrameChildContext(SvXMLImport &rImport, sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList, css::uno::Reference< css::drawing::XShapes > const &rShapes, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xFrameAttrList)
void shapeWithZIndexAdded(css::uno::Reference< css::drawing::XShape > const &rShape, sal_Int32 nZIndex)
XMLShapeImportHelper(SvXMLImport &rImporter, const css::uno::Reference< css::frame::XModel > &rModel, SvXMLImportPropertyMapper *pExtMapper=nullptr)
bool IsHandleProgressBarEnabled() const
void moveGluePointMapping(const css::uno::Reference< css::drawing::XShape > &xShape, const sal_Int32 n)
moves all current DestinationId's for rXShape by n
sal_Int32 getGluePointId(const css::uno::Reference< css::drawing::XShape > &xShape, sal_Int32 nSourceId)
retrieves a mapping for a gluepoint identifier from the current xml file to the identifier created af...
void SetAutoStylesContext(SvXMLStylesContext *pNew)
void addShapeEvents(SdXMLEventContextData &rData)
void endPage(css::uno::Reference< css::drawing::XShapes > const &rShapes)
this method must be calling after the last shape is imported for the given page Calls to this method ...
void enableHandleProgressBar()
defines if the import should increment the progress bar or not
std::shared_ptr< XMLShapeImportPageContextImpl > mpPageContext
static SvXMLShapeContext * Create3DSceneChildContext(SvXMLImport &rImport, sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList, css::uno::Reference< css::drawing::XShapes > const &rShapes)
void startPage(css::uno::Reference< css::drawing::XShapes > const &rShapes)
this method must be calling before the first shape is imported for the given page.
std::unique_ptr< XMLShapeImportHelperImpl > mpImpl
bool IsPresentationShapesSupported() const
queries the capability of the current model to create presentation shapes
rtl::Reference< SvXMLStylesContext > mxStylesContext
static SvXMLImportPropertyMapper * CreateShapePropMapper(const css::uno::Reference< css::frame::XModel > &rModel, SvXMLImport &rImport)
creates a property mapper for external chaining
void SetStylesContext(SvXMLStylesContext *pNew)
const rtl::Reference< XMLTableImport > & GetShapeTableImport()
static SvXMLImportPropertyMapper * CreateParaExtPropMapper(SvXMLImport &)
Definition: txtimp.cxx:560
static SvXMLImportPropertyMapper * CreateParaDefaultExtPropMapper(SvXMLImport &)
Definition: txtimp.cxx:567
const css::uno::Reference< css::uno::XInterface > & getReference(const OUString &rIdentifier) const
int nCount
#define DBG_ASSERT(sCon, aError)
#define DBG_UNHANDLED_EXCEPTION(...)
float u
Reference< XSingleServiceFactory > xFactory
DRAW
sal_Int32 nIndex
sal_Int64 n
#define SAL_WARN_IF(condition, area, stream)
#define SAL_INFO(area, stream)
int i
FastAttributeList & castToFastAttributeList(const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList)
Handling of tokens in XML:
const XMLPropertyMapEntry aXMLSDPresPageProps[]
Definition: sdpropls.cxx:329
constexpr OUStringLiteral gsEndGluePointIndex(u"EndGluePointIndex")
constexpr OUStringLiteral gsStartShape(u"StartShape")
constexpr OUStringLiteral gsEndShape(u"EndShape")
std::map< sal_Int32, sal_Int32 > GluePointIdMap
this map store all gluepoint id mappings for shapes that had user defined gluepoints.
Definition: shapeimport.cxx:76
constexpr OUStringLiteral gsStartGluePointIndex(u"StartGluePointIndex")
std::unordered_map< css::uno::Reference< css::drawing::XShape >, GluePointIdMap > ShapeGluePointsMap
Definition: shapeimport.cxx:77
css::uno::Reference< css::drawing::XShape > mxShape
Definition: eventimp.hxx:51
this class is to enable adding members to the XMLShapeImportHelper without getting incompatible
Definition: shapeimport.cxx:93
std::shared_ptr< ShapeGroupContext > mpGroupContext
Definition: shapeimport.cxx:95
std::vector< ConnectionHint > maConnections
Definition: shapeimport.cxx:97
this struct is created for each startPage() call and stores information that is needed during import ...
Definition: shapeimport.cxx:83
std::shared_ptr< XMLShapeImportPageContextImpl > mpNext
Definition: shapeimport.cxx:88
ShapeGluePointsMap maShapeGluePointsMap
Definition: shapeimport.cxx:84
uno::Reference< drawing::XShapes > mxShapes
Definition: shapeimport.cxx:86
bool operator<(const tSchXMLIndexWithPart &rFirst, const tSchXMLIndexWithPart &rSecond)
#define XMLOFF_WARN_UNKNOWN_ELEMENT(area, token)
Definition: xmlictxt.hxx:120
#define XMLOFF_WARN_UNKNOWN(area, rIter)
Definition: xmlictxt.hxx:114
#define XML_ELEMENT(prefix, name)
Definition: xmlimp.hxx:98