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 "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"
46
47#include <unordered_map>
48#include <string_view>
49#include <vector>
50
51namespace {
52
53class ShapeGroupContext;
54
55}
56
57using namespace ::com::sun::star;
58using namespace ::xmloff::token;
59
60namespace {
61
62struct ConnectionHint
63{
64 css::uno::Reference< css::drawing::XShape > mxConnector;
65 OUString aDestShapeId;
66 sal_Int32 nDestGlueId;
67 bool bStart;
68};
69
70}
71
74typedef std::map<sal_Int32,sal_Int32> GluePointIdMap;
75typedef std::unordered_map< css::uno::Reference < css::drawing::XShape >, GluePointIdMap > ShapeGluePointsMap;
76
81{
83
84 uno::Reference < drawing::XShapes > mxShapes;
85
86 std::shared_ptr<XMLShapeImportPageContextImpl> mpNext;
87};
88
91{
92 // context for sorting shapes
93 std::shared_ptr<ShapeGroupContext> mpGroupContext;
94
95 std::vector<ConnectionHint> maConnections;
96
97 // #88546# possibility to switch progress bar handling on/off
99
100 // stores the capability of the current model to create presentation shapes
102};
103
104constexpr OUStringLiteral gsStartShape(u"StartShape");
105constexpr OUStringLiteral gsEndShape(u"EndShape");
106constexpr OUStringLiteral gsStartGluePointIndex(u"StartGluePointIndex");
107constexpr OUStringLiteral gsEndGluePointIndex(u"EndGluePointIndex");
108
110 SvXMLImport& rImporter,
111 const uno::Reference< frame::XModel>& rModel,
112 SvXMLImportPropertyMapper *pExtMapper )
113: mpImpl( new XMLShapeImportHelperImpl ),
114 mrImporter( rImporter )
115{
116 mpImpl->mpGroupContext = nullptr;
117
118 // #88546# init to sal_False
119 mpImpl->mbHandleProgressBar = false;
120
121 mpSdPropHdlFactory = new XMLSdPropHdlFactory( rModel, rImporter );
122
123 // construct PropertySetMapper
125 mpPropertySetMapper = new SvXMLImportPropertyMapper( xMapper, rImporter );
126
127 if( pExtMapper )
128 {
129 rtl::Reference < SvXMLImportPropertyMapper > xExtMapper( pExtMapper );
130 mpPropertySetMapper->ChainImportMapper( xExtMapper );
131 }
132
133 // chain text attributes
136
137 // construct PresPagePropsMapper
139 mpPresPagePropsMapper = new SvXMLImportPropertyMapper( xMapper, rImporter );
140
141 uno::Reference< lang::XServiceInfo > xInfo( rImporter.GetModel(), uno::UNO_QUERY );
142 mpImpl->mbIsPresentationShapesSupported = xInfo.is() && xInfo->supportsService( "com.sun.star.presentation.PresentationDocument" );
143}
144
146{
147 SAL_WARN_IF( !mpImpl->maConnections.empty(), "xmloff", "XMLShapeImportHelper::restoreConnections() was not called!" );
148
149 // cleanup factory, decrease refcount. Should lead to destruction.
150 mpSdPropHdlFactory.clear();
151
152 // cleanup mapper, decrease refcount. Should lead to destruction.
153 mpPropertySetMapper.clear();
154
155 // cleanup presPage mapper, decrease refcount. Should lead to destruction.
156 mpPresPagePropsMapper.clear();
157
158 // Styles or AutoStyles context?
159 if(mxStylesContext.is())
160 mxStylesContext->dispose();
161
162 if(mxAutoStylesContext.is())
163 mxAutoStylesContext->dispose();
164}
165
166
168 SvXMLImport& rImport,
169 sal_Int32 nElement,
170 const uno::Reference< xml::sax::XFastAttributeList>& xAttrList,
171 uno::Reference< drawing::XShapes > const & rShapes)
172{
173 SdXMLShapeContext *pContext = nullptr;
174
175 if(rShapes.is())
176 {
177 switch(nElement)
178 {
179 case XML_ELEMENT(DR3D, XML_SCENE):
180 {
181 // dr3d:3dscene inside dr3d:3dscene context
182 pContext = new SdXML3DSceneShapeContext( rImport, xAttrList, rShapes, false);
183 break;
184 }
185 case XML_ELEMENT(DR3D, XML_CUBE):
186 {
187 // dr3d:3dcube inside dr3d:3dscene context
188 pContext = new SdXML3DCubeObjectShapeContext( rImport, xAttrList, rShapes);
189 break;
190 }
191 case XML_ELEMENT(DR3D, XML_SPHERE):
192 {
193 // dr3d:3dsphere inside dr3d:3dscene context
194 pContext = new SdXML3DSphereObjectShapeContext( rImport, xAttrList, rShapes);
195 break;
196 }
197 case XML_ELEMENT(DR3D, XML_ROTATE):
198 {
199 // dr3d:3dlathe inside dr3d:3dscene context
200 pContext = new SdXML3DLatheObjectShapeContext( rImport, xAttrList, rShapes);
201 break;
202 }
203 case XML_ELEMENT(DR3D, XML_EXTRUDE):
204 {
205 // dr3d:3dextrude inside dr3d:3dscene context
206 pContext = new SdXML3DExtrudeObjectShapeContext( rImport, xAttrList, rShapes);
207 break;
208 }
209 default:
210 XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
211 }
212 }
213
214 if (!pContext)
215 return nullptr;
216
217 // now parse the attribute list and call the child context for each unknown attribute
218 for(auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList))
219 {
220 if (!pContext->processAttribute( aIter ))
221 XMLOFF_WARN_UNKNOWN("xmloff", aIter);
222
223 }
224
225 return pContext;
226}
227
229{
230 mxStylesContext.set(pNew);
231}
232
234{
235 mxAutoStylesContext.set(pNew);
236}
237
239 SvXMLImport& rImport,
240 sal_Int32 nElement,
241 const uno::Reference< xml::sax::XFastAttributeList>& xAttrList,
242 uno::Reference< drawing::XShapes > const & rShapes,
243 bool bTemporaryShape)
244{
245 SdXMLShapeContext *pContext = nullptr;
246 switch (nElement)
247 {
248 case XML_ELEMENT(DRAW, XML_G):
249 // draw:g inside group context (RECURSIVE)
250 pContext = new SdXMLGroupShapeContext( rImport, xAttrList, rShapes, bTemporaryShape);
251 break;
252 case XML_ELEMENT(DR3D, XML_SCENE):
253 {
254 // dr3d:3dscene inside group context
255 pContext = new SdXML3DSceneShapeContext( rImport, xAttrList, rShapes, bTemporaryShape);
256 break;
257 }
259 {
260 // draw:rect inside group context
261 pContext = new SdXMLRectShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
262 break;
263 }
265 {
266 // draw:line inside group context
267 pContext = new SdXMLLineShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
268 break;
269 }
272 {
273 // draw:circle or draw:ellipse inside group context
274 pContext = new SdXMLEllipseShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
275 break;
276 }
279 {
280 // draw:polygon or draw:polyline inside group context
281 pContext = new SdXMLPolygonShapeContext( rImport, xAttrList, rShapes,
282 nElement == XML_ELEMENT(DRAW, XML_POLYGON), bTemporaryShape );
283 break;
284 }
286 {
287 // draw:path inside group context
288 pContext = new SdXMLPathShapeContext( rImport, xAttrList, rShapes, bTemporaryShape);
289 break;
290 }
292 {
293 // text:text-box inside group context
294 pContext = new SdXMLFrameShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
295 break;
296 }
298 {
299 // draw:control inside group context
300 pContext = new SdXMLControlShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
301 break;
302 }
304 {
305 // draw:connector inside group context
306 pContext = new SdXMLConnectorShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
307 break;
308 }
310 {
311 // draw:measure inside group context
312 pContext = new SdXMLMeasureShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
313 break;
314 }
316 {
317 // draw:page inside group context
318 pContext = new SdXMLPageShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
319 break;
320 }
323 {
324 // draw:caption inside group context
325 pContext = new SdXMLCaptionShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
326 break;
327 }
329 {
330 // chart:chart inside group context
331 pContext = new SdXMLChartShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
332 break;
333 }
335 {
336 // draw:customshape
337 pContext = new SdXMLCustomShapeContext( rImport, xAttrList, rShapes );
338 break;
339 }
340 case XML_ELEMENT(DRAW, XML_A):
341 return new SdXMLShapeLinkContext( rImport, xAttrList, rShapes );
342 // add other shapes here...
343 default:
344 XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
345 return new SvXMLShapeContext( rImport, bTemporaryShape );
346 }
347
348 // now parse the attribute list and call the child context for each unknown attribute
349 for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ))
350 {
351 if (!pContext->processAttribute( aIter ))
352 XMLOFF_WARN_UNKNOWN("xmloff", aIter);
353 }
354 return pContext;
355}
356
357// This method is called from SdXMLFrameShapeContext to create children of draw:frame
359 SvXMLImport& rImport,
360 sal_Int32 nElement,
361 const uno::Reference< xml::sax::XFastAttributeList>& rAttrList,
362 uno::Reference< drawing::XShapes > const & rShapes,
363 const uno::Reference< xml::sax::XFastAttributeList>& rFrameAttrList)
364{
365 SdXMLShapeContext *pContext = nullptr;
366
368 if( rFrameAttrList.is() )
369 xCombinedAttrList->add(rFrameAttrList);
370
371 switch(nElement)
372 {
373 case XML_ELEMENT(DRAW, XML_TEXT_BOX):
374 {
375 // text:text-box inside group context
376 pContext = new SdXMLTextBoxShapeContext( rImport, xCombinedAttrList, rShapes );
377 break;
378 }
379 case XML_ELEMENT(DRAW, XML_IMAGE):
380 {
381 // office:image inside group context
382 pContext = new SdXMLGraphicObjectShapeContext( rImport, xCombinedAttrList, rShapes );
383 break;
384 }
385 case XML_ELEMENT(DRAW, XML_OBJECT):
387 {
388 // draw:object or draw:object_ole
389 pContext = new SdXMLObjectShapeContext( rImport, xCombinedAttrList, rShapes );
390 break;
391 }
392 case XML_ELEMENT(TABLE, XML_TABLE):
393 {
394 // draw:object or draw:object_ole
395 if( rImport.IsTableShapeSupported() )
396 pContext = new SdXMLTableShapeContext( rImport, xCombinedAttrList, rShapes );
397 break;
398
399 }
400 case XML_ELEMENT(DRAW, XML_PLUGIN):
401 {
402 // draw:plugin
403 pContext = new SdXMLPluginShapeContext( rImport, xCombinedAttrList, rShapes );
404 break;
405 }
407 {
408 // draw:floating-frame
409 pContext = new SdXMLFloatingFrameShapeContext( rImport, xCombinedAttrList, rShapes );
410 break;
411 }
412 case XML_ELEMENT(DRAW, XML_APPLET):
413 {
414 // draw:applet
415 pContext = new SdXMLAppletShapeContext( rImport, xCombinedAttrList, rShapes );
416 break;
417 }
418 // add other shapes here...
419 default:
420 SAL_INFO("xmloff", "unknown element " << SvXMLImport::getPrefixAndNameFromToken(nElement));
421 break;
422 }
423
424 if( pContext )
425 {
426 // now parse the attribute list and call the child context for each unknown attribute
427 for(auto& aIter : *xCombinedAttrList)
428 {
429 if (!pContext->processAttribute( aIter ))
430 SAL_INFO("xmloff", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << " value=" << aIter.toString());
431 }
432 }
433
434 return pContext;
435}
436
437css::uno::Reference< css::xml::sax::XFastContextHandler > XMLShapeImportHelper::CreateFrameChildContext(
438 SvXMLImportContext *pThisContext,
439 sal_Int32 nElement,
440 const uno::Reference< xml::sax::XFastAttributeList>& xAttrList )
441{
442 css::uno::Reference< css::xml::sax::XFastContextHandler > xContext;
443 SdXMLFrameShapeContext *pFrameContext = dynamic_cast<SdXMLFrameShapeContext*>( pThisContext );
444 if (pFrameContext)
445 xContext = pFrameContext->createFastChildContext( nElement, xAttrList );
446
447 if (!xContext)
448 XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
449 return xContext;
450}
451
455void XMLShapeImportHelper::addShape( uno::Reference< drawing::XShape >& rShape,
456 const uno::Reference< xml::sax::XFastAttributeList >&,
457 uno::Reference< drawing::XShapes >& rShapes)
458{
459 if( rShape.is() && rShapes.is() )
460 {
461 // add new shape to parent
462 rShapes->add( rShape );
463
464 uno::Reference<beans::XPropertySet> xPropertySet(rShape, uno::UNO_QUERY);
465 if (xPropertySet.is())
466 {
467 static constexpr OUStringLiteral sHandlePathObjScale = u"HandlePathObjScale";
468 xPropertySet->setPropertyValue(sHandlePathObjScale, uno::Any(true));
469 }
470 }
471}
472
478 css::uno::Reference< css::drawing::XShape >& rShape,
479 const css::uno::Reference< css::xml::sax::XFastAttributeList >&,
480 css::uno::Reference< css::drawing::XShapes >&)
481{
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#)
494 */
495 uno::Reference< beans::XPropertySet > xPropSet(rShape, uno::UNO_QUERY);
496 if ( xPropSet.is() )
497 {
498 if ( mrImporter.IsShapePositionInHoriL2R() &&
499 xPropSet->getPropertySetInfo()->hasPropertyByName(
500 "PositionLayoutDir") )
501 {
502 uno::Any aPosLayoutDir;
503 aPosLayoutDir <<= text::PositionLayoutDir::PositionInHoriL2R;
504 xPropSet->setPropertyValue( "PositionLayoutDir", aPosLayoutDir );
505 }
506 }
507}
508
509namespace {
510
511// helper functions for z-order sorting
512struct ZOrderHint
513{
514 sal_Int32 nIs;
515 sal_Int32 nShould;
518 drawing::XShape* pShape;
519
520 bool operator<(const ZOrderHint& rComp) const { return nShould < rComp.nShould; }
521};
522
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
525class ShapeGroupContext
526{
527public:
528 uno::Reference< drawing::XShapes > mxShapes;
529 std::vector<SdXMLEventContextData> maEventData;
530 std::vector<ZOrderHint> maZOrderList;
531 std::vector<ZOrderHint> maUnsortedList;
532
533 sal_Int32 mnCurrentZ;
534 std::shared_ptr<ShapeGroupContext> mpParentContext;
535
536 ShapeGroupContext( uno::Reference< drawing::XShapes > xShapes, std::shared_ptr<ShapeGroupContext> pParentContext );
537
538 void popGroupAndPostProcess();
539private:
540 void moveShape( sal_Int32 nSourcePos, sal_Int32 nDestPos );
541};
542
543}
544
545ShapeGroupContext::ShapeGroupContext( uno::Reference< drawing::XShapes > xShapes, std::shared_ptr<ShapeGroupContext> pParentContext )
546: mxShapes(std::move( xShapes )), mnCurrentZ( 0 ), mpParentContext( std::move(pParentContext) )
547{
548}
549
550void ShapeGroupContext::moveShape( sal_Int32 nSourcePos, sal_Int32 nDestPos )
551{
552 uno::Any aAny( mxShapes->getByIndex( nSourcePos ) );
553 uno::Reference< beans::XPropertySet > xPropSet;
554 aAny >>= xPropSet;
555
556 if( !(xPropSet.is() && xPropSet->getPropertySetInfo()->hasPropertyByName( "ZOrder" )) )
557 return;
558
559 xPropSet->setPropertyValue( "ZOrder", uno::Any(nDestPos) );
560
561 for( ZOrderHint& rHint : maZOrderList )
562 {
563 if( rHint.nIs < nSourcePos )
564 {
565 DBG_ASSERT(rHint.nIs >= nDestPos, "Shape sorting failed" );
566 rHint.nIs++;
567 }
568 }
569
570 for( ZOrderHint& rHint : maUnsortedList )
571 {
572 if( rHint.nIs < nSourcePos )
573 {
574 SAL_WARN_IF( rHint.nIs < nDestPos, "xmloff", "shape sorting failed" );
575 rHint.nIs++;
576 }
577 }
578}
579
580// sort shapes
581void ShapeGroupContext::popGroupAndPostProcess()
582{
583 if (!maEventData.empty())
584 {
585 // tdf#127791 wait until a group is popped to set its event data
586 for (auto& event : maEventData)
587 event.ApplyProperties();
588 maEventData.clear();
589 }
590
591 // only do something if we have shapes to sort
592 if( maZOrderList.empty() )
593 return;
594
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
599
600 // check if we have more shapes than we know of
601 sal_Int32 nCount = mxShapes->getCount();
602
603 nCount -= maZOrderList.size();
604 nCount -= maUnsortedList.size();
605
606 if( nCount > 0 )
607 {
608 // first update offsets of added shapes
609 for (ZOrderHint& rHint : maZOrderList)
610 rHint.nIs += nCount;
611 for (ZOrderHint& rHint : maUnsortedList)
612 rHint.nIs += nCount;
613
614 // second add the already existing shapes in the unsorted list
615 ZOrderHint aNewHint;
616 aNewHint.pShape = nullptr;
617 do
618 {
619 nCount--;
620
621 aNewHint.nIs = nCount;
622 aNewHint.nShould = -1;
623
624 maUnsortedList.insert(maUnsortedList.begin(), aNewHint);
625 }
626 while( nCount );
627 }
628
629 bool bSorted = std::is_sorted(maZOrderList.begin(), maZOrderList.end(),
630 [](const ZOrderHint& rLeft, const ZOrderHint& rRight)
631 { return rLeft.nShould < rRight.nShould; } );
632
633 if (bSorted)
634 return; // nothin' to do
635
636 // sort z-ordered shapes by nShould field
637 std::sort(maZOrderList.begin(), maZOrderList.end());
638
639 uno::Reference<drawing::XShapes3> xShapes3(mxShapes, uno::UNO_QUERY);
640 if( xShapes3.is())
641 {
642 uno::Sequence<sal_Int32> aNewOrder(maZOrderList.size() + maUnsortedList.size());
643 auto pNewOrder = aNewOrder.getArray();
644 sal_Int32 nIndex = 0;
645
646 for (const ZOrderHint& rHint : maZOrderList)
647 {
648 // fill in the gaps from unordered list
649 for (std::vector<ZOrderHint>::iterator aIt = maUnsortedList.begin(); aIt != maUnsortedList.end() && nIndex < rHint.nShould; )
650 {
651 pNewOrder[nIndex++] = (*aIt).nIs;
652 aIt = maUnsortedList.erase(aIt);
653 }
654
655 pNewOrder[nIndex] = rHint.nIs;
656 nIndex++;
657 }
658
659 try
660 {
661 xShapes3->sort(aNewOrder);
662 maZOrderList.clear();
663 return;
664 }
665 catch (const css::lang::IllegalArgumentException& /*e*/)
666 {}
667 }
668
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)
673 {
674 for (std::vector<ZOrderHint>::iterator aIt = maUnsortedList.begin(); aIt != maUnsortedList.end() && nIndex < rHint.nShould; )
675 {
676 moveShape( (*aIt).nIs, nIndex++ );
677 aIt = maUnsortedList.erase(aIt);
678
679 }
680
681 if(rHint.nIs != nIndex )
682 moveShape( rHint.nIs, nIndex );
683
684 nIndex++;
685 }
686 maZOrderList.clear();
687}
688
689void XMLShapeImportHelper::pushGroupForPostProcessing( uno::Reference< drawing::XShapes >& rShapes )
690{
691 mpImpl->mpGroupContext = std::make_shared<ShapeGroupContext>( rShapes, mpImpl->mpGroupContext );
692}
693
695{
696 if (mpImpl->mpGroupContext && mpImpl->mpGroupContext->mxShapes == rData.mxShape)
697 {
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);
702 }
703 else
704 rData.ApplyProperties();
705}
706
708{
709 SAL_WARN_IF( !mpImpl->mpGroupContext, "xmloff", "No context to sort!" );
710 if( !mpImpl->mpGroupContext )
711 return;
712
713 try
714 {
715 mpImpl->mpGroupContext->popGroupAndPostProcess();
716 }
717 catch( const uno::Exception& )
718 {
719 DBG_UNHANDLED_EXCEPTION("xmloff", "exception while sorting shapes, sorting failed");
720 }
721
722 // put parent on top and drop current context, we are done
723 mpImpl->mpGroupContext = mpImpl->mpGroupContext->mpParentContext;
724}
725
726void XMLShapeImportHelper::shapeWithZIndexAdded( css::uno::Reference< css::drawing::XShape > const & xShape, sal_Int32 nZIndex )
727{
728 if( !mpImpl->mpGroupContext)
729 return;
730
731 ZOrderHint aNewHint;
732 aNewHint.nIs = mpImpl->mpGroupContext->mnCurrentZ++;
733 aNewHint.nShould = nZIndex;
734 aNewHint.pShape = xShape.get();
735
736 if( nZIndex == -1 )
737 {
738 // don't care, so add to unsorted list
739 mpImpl->mpGroupContext->maUnsortedList.push_back(aNewHint);
740 }
741 else
742 {
743 // insert into sort list
744 mpImpl->mpGroupContext->maZOrderList.push_back(aNewHint);
745 }
746}
747
748void XMLShapeImportHelper::shapeRemoved(const uno::Reference<drawing::XShape>& xShape)
749{
750 auto it = std::find_if(mpImpl->mpGroupContext->maZOrderList.begin(), mpImpl->mpGroupContext->maZOrderList.end(), [&xShape](const ZOrderHint& rHint)
751 {
752 return rHint.pShape == xShape.get();
753 });
754 if (it == mpImpl->mpGroupContext->maZOrderList.end())
755 // Part of the unsorted list, nothing to do.
756 return;
757
758 sal_Int32 nZIndex = it->nIs;
759
760 for (it = mpImpl->mpGroupContext->maZOrderList.begin(); it != mpImpl->mpGroupContext->maZOrderList.end();)
761 {
762 if (it->nIs == nZIndex)
763 {
764 // This is xShape: remove it and adjust the max of indexes
765 // accordingly.
766 it = mpImpl->mpGroupContext->maZOrderList.erase(it);
767 mpImpl->mpGroupContext->mnCurrentZ--;
768 continue;
769 }
770 else if (it->nIs > nZIndex)
771 // On top of xShape: adjust actual index to reflect removal.
772 it->nIs--;
773
774 // On top of or below xShape.
775 ++it;
776 }
777}
778
779void XMLShapeImportHelper::addShapeConnection( css::uno::Reference< css::drawing::XShape > const & rConnectorShape,
780 bool bStart,
781 const OUString& rDestShapeId,
782 sal_Int32 nDestGlueId )
783{
784 ConnectionHint aHint;
785 aHint.mxConnector = rConnectorShape;
786 aHint.bStart = bStart;
787 aHint.aDestShapeId = rDestShapeId;
788 aHint.nDestGlueId = nDestGlueId;
789
790 mpImpl->maConnections.push_back( aHint );
791}
792
794{
795 const std::vector<ConnectionHint>::size_type nCount = mpImpl->maConnections.size();
796 for( std::vector<ConnectionHint>::size_type i = 0; i < nCount; i++ )
797 {
798 ConnectionHint& rHint = mpImpl->maConnections[i];
799 uno::Reference< beans::XPropertySet > xConnector( rHint.mxConnector, uno::UNO_QUERY );
800 if( xConnector.is() )
801 {
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);
812
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 );
818 if( xShape.is() )
819 {
820 if (rHint.bStart)
821 xConnector->setPropertyValue( gsStartShape, uno::Any(xShape) );
822 else
823 xConnector->setPropertyValue( gsEndShape, uno::Any(xShape) );
824
825 sal_Int32 nGlueId = rHint.nDestGlueId < 4 ? rHint.nDestGlueId : getGluePointId( xShape, rHint.nDestGlueId );
826 if(rHint.bStart)
827 xConnector->setPropertyValue( gsStartGluePointIndex, uno::Any(nGlueId) );
828 else
829 xConnector->setPropertyValue( gsEndGluePointIndex, uno::Any(nGlueId) );
830 }
831
832 // #86637# restore line deltas
833 xConnector->setPropertyValue(aStr1, aLine1Delta );
834 xConnector->setPropertyValue(aStr2, aLine2Delta );
835 xConnector->setPropertyValue(aStr3, aLine3Delta );
836 }
837 }
838 mpImpl->maConnections.clear();
839}
840
841SvXMLImportPropertyMapper* XMLShapeImportHelper::CreateShapePropMapper( const uno::Reference< frame::XModel>& rModel, SvXMLImport& rImport )
842{
845 SvXMLImportPropertyMapper* pResult = new SvXMLImportPropertyMapper( xMapper, rImport );
846
847 // chain text attributes
849 return pResult;
850}
851
854void XMLShapeImportHelper::addGluePointMapping( css::uno::Reference< css::drawing::XShape > const & xShape,
855 sal_Int32 nSourceId, sal_Int32 nDestinnationId )
856{
857 if( mpPageContext )
858 mpPageContext->maShapeGluePointsMap[xShape][nSourceId] = nDestinnationId;
859}
860
862void XMLShapeImportHelper::moveGluePointMapping( const css::uno::Reference< css::drawing::XShape >& xShape, const sal_Int32 n )
863{
864 if( mpPageContext )
865 {
866 ShapeGluePointsMap::iterator aShapeIter( mpPageContext->maShapeGluePointsMap.find( xShape ) );
867 if( aShapeIter != mpPageContext->maShapeGluePointsMap.end() )
868 {
869 for ( auto& rShapeId : (*aShapeIter).second )
870 {
871 if ( rShapeId.second != -1 )
872 rShapeId.second += n;
873 }
874 }
875 }
876}
877
880sal_Int32 XMLShapeImportHelper::getGluePointId( const css::uno::Reference< css::drawing::XShape >& xShape, sal_Int32 nSourceId )
881{
882 if( mpPageContext )
883 {
884 ShapeGluePointsMap::iterator aShapeIter( mpPageContext->maShapeGluePointsMap.find( xShape ) );
885 if( aShapeIter != mpPageContext->maShapeGluePointsMap.end() )
886 {
887 GluePointIdMap::iterator aIdIter = (*aShapeIter).second.find(nSourceId);
888 if( aIdIter != (*aShapeIter).second.end() )
889 return (*aIdIter).second;
890 }
891 }
892
893 return -1;
894}
895
897void XMLShapeImportHelper::startPage( css::uno::Reference< css::drawing::XShapes > const & rShapes )
898{
899 const std::shared_ptr<XMLShapeImportPageContextImpl> pOldContext = mpPageContext;
900 mpPageContext = std::make_shared<XMLShapeImportPageContextImpl>();
901 mpPageContext->mpNext = pOldContext;
902 mpPageContext->mxShapes = rShapes;
903}
904
906void XMLShapeImportHelper::endPage( css::uno::Reference< css::drawing::XShapes > const & rShapes )
907{
908 SAL_WARN_IF( !mpPageContext || (mpPageContext->mxShapes != rShapes), "xmloff", "wrong call to endPage(), no startPage called or wrong page" );
909 if( nullptr == mpPageContext )
910 return;
911
913
915}
916
919{
920 mpImpl->mbHandleProgressBar = true;
921}
922
924{
925 return mpImpl->mbHandleProgressBar;
926}
927
930{
931 return mpImpl->mbIsPresentationShapesSupported;
932}
933
935{
936 if( !mxShapeTableImport.is() )
937 {
940 mxShapeTableImport = new XMLTableImport( mrImporter, xPropertySetMapper, xFactory );
941 }
942
943 return mxShapeTableImport;
944}
945
946void SvXMLShapeContext::setHyperlink( const OUString& rHyperlink )
947{
948 msHyperlink = rHyperlink;
949}
950
951/* 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:3337
virtual bool processAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter &)
Definition: ximpshap.cxx:799
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:75
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:559
static SvXMLImportPropertyMapper * CreateParaDefaultExtPropMapper(SvXMLImport &)
Definition: txtimp.cxx:566
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:330
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:74
constexpr OUStringLiteral gsStartGluePointIndex(u"StartGluePointIndex")
std::unordered_map< css::uno::Reference< css::drawing::XShape >, GluePointIdMap > ShapeGluePointsMap
Definition: shapeimport.cxx:75
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:91
std::shared_ptr< ShapeGroupContext > mpGroupContext
Definition: shapeimport.cxx:93
std::vector< ConnectionHint > maConnections
Definition: shapeimport.cxx:95
this struct is created for each startPage() call and stores information that is needed during import ...
Definition: shapeimport.cxx:81
std::shared_ptr< XMLShapeImportPageContextImpl > mpNext
Definition: shapeimport.cxx:86
ShapeGluePointsMap maShapeGluePointsMap
Definition: shapeimport.cxx:82
uno::Reference< drawing::XShapes > mxShapes
Definition: shapeimport.cxx:84
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:97