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