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