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 <unordered_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  OUString aDestShapeId;
68  sal_Int32 nDestGlueId;
69  bool bStart;
70 };
71 
72 }
73 
76 typedef std::map<sal_Int32,sal_Int32> GluePointIdMap;
77 typedef std::unordered_map< css::uno::Reference < css::drawing::XShape >, GluePointIdMap > ShapeGluePointsMap;
78 
83 {
85 
86  uno::Reference < drawing::XShapes > mxShapes;
87 
88  std::shared_ptr<XMLShapeImportPageContextImpl> mpNext;
89 };
90 
93 {
94  // context for sorting shapes
95  std::shared_ptr<ShapeGroupContext> mpGroupContext;
96 
97  std::vector<ConnectionHint> maConnections;
98 
99  // #88546# possibility to switch progress bar handling on/off
101 
102  // stores the capability of the current model to create presentation shapes
104 };
105 
106 constexpr OUStringLiteral gsStartShape(u"StartShape");
107 constexpr OUStringLiteral gsEndShape(u"EndShape");
108 constexpr OUStringLiteral gsStartGluePointIndex(u"StartGluePointIndex");
109 constexpr OUStringLiteral gsEndGluePointIndex(u"EndGluePointIndex");
110 
112  SvXMLImport& rImporter,
113  const uno::Reference< frame::XModel>& rModel,
114  SvXMLImportPropertyMapper *pExtMapper )
115 : mpImpl( new XMLShapeImportHelperImpl ),
116  mrImporter( rImporter )
117 {
118  mpImpl->mpGroupContext = nullptr;
119 
120  // #88546# init to sal_False
121  mpImpl->mbHandleProgressBar = false;
122 
123  mpSdPropHdlFactory = new XMLSdPropHdlFactory( rModel, rImporter );
124 
125  // construct PropertySetMapper
127  mpPropertySetMapper = new SvXMLImportPropertyMapper( xMapper, rImporter );
128 
129  if( pExtMapper )
130  {
131  rtl::Reference < SvXMLImportPropertyMapper > xExtMapper( pExtMapper );
132  mpPropertySetMapper->ChainImportMapper( xExtMapper );
133  }
134 
135  // chain text attributes
138 
139  // construct PresPagePropsMapper
141  mpPresPagePropsMapper = new SvXMLImportPropertyMapper( xMapper, rImporter );
142 
143  uno::Reference< lang::XServiceInfo > xInfo( rImporter.GetModel(), uno::UNO_QUERY );
144  mpImpl->mbIsPresentationShapesSupported = xInfo.is() && xInfo->supportsService( "com.sun.star.presentation.PresentationDocument" );
145 }
146 
148 {
149  SAL_WARN_IF( !mpImpl->maConnections.empty(), "xmloff", "XMLShapeImportHelper::restoreConnections() was not called!" );
150 
151  // cleanup factory, decrease refcount. Should lead to destruction.
152  mpSdPropHdlFactory.clear();
153 
154  // cleanup mapper, decrease refcount. Should lead to destruction.
155  mpPropertySetMapper.clear();
156 
157  // cleanup presPage mapper, decrease refcount. Should lead to destruction.
158  mpPresPagePropsMapper.clear();
159 
160  // Styles or AutoStyles context?
161  if(mxStylesContext.is())
162  mxStylesContext->dispose();
163 
164  if(mxAutoStylesContext.is())
165  mxAutoStylesContext->dispose();
166 }
167 
168 
170  SvXMLImport& rImport,
171  sal_Int32 nElement,
172  const uno::Reference< xml::sax::XFastAttributeList>& xAttrList,
173  uno::Reference< drawing::XShapes > const & rShapes)
174 {
175  SdXMLShapeContext *pContext = nullptr;
176 
177  if(rShapes.is())
178  {
179  switch(nElement)
180  {
181  case XML_ELEMENT(DR3D, XML_SCENE):
182  {
183  // dr3d:3dscene inside dr3d:3dscene context
184  pContext = new SdXML3DSceneShapeContext( rImport, xAttrList, rShapes, false);
185  break;
186  }
187  case XML_ELEMENT(DR3D, XML_CUBE):
188  {
189  // dr3d:3dcube inside dr3d:3dscene context
190  pContext = new SdXML3DCubeObjectShapeContext( rImport, xAttrList, rShapes);
191  break;
192  }
193  case XML_ELEMENT(DR3D, XML_SPHERE):
194  {
195  // dr3d:3dsphere inside dr3d:3dscene context
196  pContext = new SdXML3DSphereObjectShapeContext( rImport, xAttrList, rShapes);
197  break;
198  }
199  case XML_ELEMENT(DR3D, XML_ROTATE):
200  {
201  // dr3d:3dlathe inside dr3d:3dscene context
202  pContext = new SdXML3DLatheObjectShapeContext( rImport, xAttrList, rShapes);
203  break;
204  }
205  case XML_ELEMENT(DR3D, XML_EXTRUDE):
206  {
207  // dr3d:3dextrude inside dr3d:3dscene context
208  pContext = new SdXML3DExtrudeObjectShapeContext( rImport, xAttrList, rShapes);
209  break;
210  }
211  default:
212  XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
213  }
214  }
215 
216  if (!pContext)
217  return nullptr;
218 
219  // now parse the attribute list and call the child context for each unknown attribute
220  for(auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList))
221  {
222  if (!pContext->processAttribute( aIter ))
223  XMLOFF_WARN_UNKNOWN("xmloff", aIter);
224 
225  }
226 
227  return pContext;
228 }
229 
231 {
232  mxStylesContext.set(pNew);
233 }
234 
236 {
237  mxAutoStylesContext.set(pNew);
238 }
239 
241  SvXMLImport& rImport,
242  sal_Int32 nElement,
243  const uno::Reference< xml::sax::XFastAttributeList>& xAttrList,
244  uno::Reference< drawing::XShapes > const & rShapes,
245  bool bTemporaryShape)
246 {
247  SdXMLShapeContext *pContext = nullptr;
248  switch (nElement)
249  {
250  case XML_ELEMENT(DRAW, XML_G):
251  // draw:g inside group context (RECURSIVE)
252  pContext = new SdXMLGroupShapeContext( rImport, xAttrList, rShapes, bTemporaryShape);
253  break;
254  case XML_ELEMENT(DR3D, XML_SCENE):
255  {
256  // dr3d:3dscene inside group context
257  pContext = new SdXML3DSceneShapeContext( rImport, xAttrList, rShapes, bTemporaryShape);
258  break;
259  }
260  case XML_ELEMENT(DRAW, XML_RECT):
261  {
262  // draw:rect inside group context
263  pContext = new SdXMLRectShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
264  break;
265  }
266  case XML_ELEMENT(DRAW, XML_LINE):
267  {
268  // draw:line inside group context
269  pContext = new SdXMLLineShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
270  break;
271  }
272  case XML_ELEMENT(DRAW, XML_CIRCLE):
274  {
275  // draw:circle or draw:ellipse inside group context
276  pContext = new SdXMLEllipseShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
277  break;
278  }
281  {
282  // draw:polygon or draw:polyline inside group context
283  pContext = new SdXMLPolygonShapeContext( rImport, xAttrList, rShapes,
284  nElement == XML_ELEMENT(DRAW, XML_POLYGON), bTemporaryShape );
285  break;
286  }
287  case XML_ELEMENT(DRAW, XML_PATH):
288  {
289  // draw:path inside group context
290  pContext = new SdXMLPathShapeContext( rImport, xAttrList, rShapes, bTemporaryShape);
291  break;
292  }
293  case XML_ELEMENT(DRAW, XML_FRAME):
294  {
295  // text:text-box inside group context
296  pContext = new SdXMLFrameShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
297  break;
298  }
300  {
301  // draw:control inside group context
302  pContext = new SdXMLControlShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
303  break;
304  }
306  {
307  // draw:connector inside group context
308  pContext = new SdXMLConnectorShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
309  break;
310  }
312  {
313  // draw:measure inside group context
314  pContext = new SdXMLMeasureShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
315  break;
316  }
318  {
319  // draw:page inside group context
320  pContext = new SdXMLPageShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
321  break;
322  }
325  {
326  // draw:caption inside group context
327  pContext = new SdXMLCaptionShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
328  break;
329  }
330  case XML_ELEMENT(CHART, XML_CHART):
331  {
332  // chart:chart inside group context
333  pContext = new SdXMLChartShapeContext( rImport, xAttrList, rShapes, bTemporaryShape );
334  break;
335  }
337  {
338  // draw:customshape
339  pContext = new SdXMLCustomShapeContext( rImport, xAttrList, rShapes );
340  break;
341  }
342  case XML_ELEMENT(DRAW, XML_A):
343  return new SdXMLShapeLinkContext( rImport, xAttrList, rShapes );
344  // add other shapes here...
345  default:
346  XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
347  return new SvXMLShapeContext( rImport, bTemporaryShape );
348  }
349 
350  // now parse the attribute list and call the child context for each unknown attribute
351  for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ))
352  {
353  if (!pContext->processAttribute( aIter ))
354  XMLOFF_WARN_UNKNOWN("xmloff", aIter);
355  }
356  return pContext;
357 }
358 
359 // This method is called from SdXMLFrameShapeContext to create children of draw:frame
361  SvXMLImport& rImport,
362  sal_Int32 nElement,
363  const uno::Reference< xml::sax::XFastAttributeList>& rAttrList,
364  uno::Reference< drawing::XShapes > const & rShapes,
365  const uno::Reference< xml::sax::XFastAttributeList>& rFrameAttrList)
366 {
367  SdXMLShapeContext *pContext = nullptr;
368 
370  if( rFrameAttrList.is() )
371  xCombinedAttrList->add(rFrameAttrList);
372 
373  switch(nElement)
374  {
375  case XML_ELEMENT(DRAW, XML_TEXT_BOX):
376  {
377  // text:text-box inside group context
378  pContext = new SdXMLTextBoxShapeContext( rImport, xCombinedAttrList, rShapes );
379  break;
380  }
381  case XML_ELEMENT(DRAW, XML_IMAGE):
382  {
383  // office:image inside group context
384  pContext = new SdXMLGraphicObjectShapeContext( rImport, xCombinedAttrList, rShapes );
385  break;
386  }
387  case XML_ELEMENT(DRAW, XML_OBJECT):
389  {
390  // draw:object or draw:object_ole
391  pContext = new SdXMLObjectShapeContext( rImport, xCombinedAttrList, rShapes );
392  break;
393  }
394  case XML_ELEMENT(TABLE, XML_TABLE):
395  {
396  // draw:object or draw:object_ole
397  if( rImport.IsTableShapeSupported() )
398  pContext = new SdXMLTableShapeContext( rImport, xCombinedAttrList, rShapes );
399  break;
400 
401  }
402  case XML_ELEMENT(DRAW, XML_PLUGIN):
403  {
404  // draw:plugin
405  pContext = new SdXMLPluginShapeContext( rImport, xCombinedAttrList, rShapes );
406  break;
407  }
408  case XML_ELEMENT(DRAW, XML_FLOATING_FRAME):
409  {
410  // draw:floating-frame
411  pContext = new SdXMLFloatingFrameShapeContext( rImport, xCombinedAttrList, rShapes );
412  break;
413  }
414  case XML_ELEMENT(DRAW, XML_APPLET):
415  {
416  // draw:applet
417  pContext = new SdXMLAppletShapeContext( rImport, xCombinedAttrList, rShapes );
418  break;
419  }
420  // add other shapes here...
421  default:
422  SAL_INFO("xmloff", "unknown element " << SvXMLImport::getPrefixAndNameFromToken(nElement));
423  break;
424  }
425 
426  if( pContext )
427  {
428  // now parse the attribute list and call the child context for each unknown attribute
429  for(auto& aIter : *xCombinedAttrList)
430  {
431  if (!pContext->processAttribute( aIter ))
432  SAL_INFO("xmloff", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << " value=" << aIter.toString());
433  }
434  }
435 
436  return pContext;
437 }
438 
439 css::uno::Reference< css::xml::sax::XFastContextHandler > XMLShapeImportHelper::CreateFrameChildContext(
440  SvXMLImportContext *pThisContext,
441  sal_Int32 nElement,
442  const uno::Reference< xml::sax::XFastAttributeList>& xAttrList )
443 {
444  css::uno::Reference< css::xml::sax::XFastContextHandler > xContext;
445  SdXMLFrameShapeContext *pFrameContext = dynamic_cast<SdXMLFrameShapeContext*>( pThisContext );
446  if (pFrameContext)
447  xContext = pFrameContext->createFastChildContext( nElement, xAttrList );
448 
449  if (!xContext)
450  XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
451  return xContext;
452 }
453 
457 void XMLShapeImportHelper::addShape( uno::Reference< drawing::XShape >& rShape,
458  const uno::Reference< xml::sax::XFastAttributeList >&,
459  uno::Reference< drawing::XShapes >& rShapes)
460 {
461  if( rShape.is() && rShapes.is() )
462  {
463  // add new shape to parent
464  rShapes->add( rShape );
465 
466  uno::Reference<beans::XPropertySet> xPropertySet(rShape, uno::UNO_QUERY);
467  if (xPropertySet.is())
468  {
469  xPropertySet->setPropertyValue("HandlePathObjScale", 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  {
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 
510 namespace {
511 
512 // helper functions for z-order sorting
513 struct ZOrderHint
514 {
515  sal_Int32 nIs;
516  sal_Int32 nShould;
518  uno::Reference<drawing::XShape> xShape;
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
525 class ShapeGroupContext
526 {
527 public:
528  uno::Reference< drawing::XShapes > mxShapes;
529  std::vector<SdXMLEventContextData> maEventData;
530  vector<ZOrderHint> maZOrderList;
531  vector<ZOrderHint> maUnsortedList;
532 
533  sal_Int32 mnCurrentZ;
534  std::shared_ptr<ShapeGroupContext> mpParentContext;
535 
536  ShapeGroupContext( uno::Reference< drawing::XShapes > const & rShapes, std::shared_ptr<ShapeGroupContext> pParentContext );
537 
538  void popGroupAndPostProcess();
539 private:
540  void moveShape( sal_Int32 nSourcePos, sal_Int32 nDestPos );
541 };
542 
543 }
544 
545 ShapeGroupContext::ShapeGroupContext( uno::Reference< drawing::XShapes > const & rShapes, std::shared_ptr<ShapeGroupContext> pParentContext )
546 : mxShapes( rShapes ), mnCurrentZ( 0 ), mpParentContext( std::move(pParentContext) )
547 {
548 }
549 
550 void 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
581 void 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  do
617  {
618  nCount--;
619 
620  aNewHint.nIs = nCount;
621  aNewHint.nShould = -1;
622 
623  maUnsortedList.insert(maUnsortedList.begin(), aNewHint);
624  }
625  while( nCount );
626  }
627 
628  bool bSorted = std::is_sorted(maZOrderList.begin(), maZOrderList.end(),
629  [](const ZOrderHint& rLeft, const ZOrderHint& rRight)
630  { return rLeft.nShould < rRight.nShould; } );
631 
632  if (bSorted)
633  return; // nothin' to do
634 
635  // sort z-ordered shapes by nShould field
636  std::sort(maZOrderList.begin(), maZOrderList.end());
637 
638  uno::Reference<drawing::XShapes3> xShapes3(mxShapes, uno::UNO_QUERY);
639  if( xShapes3.is())
640  {
641  uno::Sequence<sal_Int32> aNewOrder(maZOrderList.size() + maUnsortedList.size());
642  auto pNewOrder = aNewOrder.getArray();
643  sal_Int32 nIndex = 0;
644 
645  for (const ZOrderHint& rHint : maZOrderList)
646  {
647  // fill in the gaps from unordered list
648  for (vector<ZOrderHint>::iterator aIt = maUnsortedList.begin(); aIt != maUnsortedList.end() && nIndex < rHint.nShould; )
649  {
650  pNewOrder[nIndex++] = (*aIt).nIs;
651  aIt = maUnsortedList.erase(aIt);
652  }
653 
654  pNewOrder[nIndex] = rHint.nIs;
655  nIndex++;
656  }
657 
658  try
659  {
660  xShapes3->sort(aNewOrder);
661  maZOrderList.clear();
662  return;
663  }
664  catch (const css::lang::IllegalArgumentException& /*e*/)
665  {}
666  }
667 
668  // this is the current index, all shapes before that
669  // index are finished
670  sal_Int32 nIndex = 0;
671  for (const ZOrderHint& rHint : maZOrderList)
672  {
673  for (vector<ZOrderHint>::iterator aIt = maUnsortedList.begin(); aIt != maUnsortedList.end() && nIndex < rHint.nShould; )
674  {
675  moveShape( (*aIt).nIs, nIndex++ );
676  aIt = maUnsortedList.erase(aIt);
677 
678  }
679 
680  if(rHint.nIs != nIndex )
681  moveShape( rHint.nIs, nIndex );
682 
683  nIndex++;
684  }
685  maZOrderList.clear();
686 }
687 
688 void XMLShapeImportHelper::pushGroupForPostProcessing( uno::Reference< drawing::XShapes >& rShapes )
689 {
690  mpImpl->mpGroupContext = std::make_shared<ShapeGroupContext>( rShapes, mpImpl->mpGroupContext );
691 }
692 
694 {
695  if (mpImpl->mpGroupContext && mpImpl->mpGroupContext->mxShapes == rData.mxShape)
696  {
697  // tdf#127791 wait until a group is popped to set its event data so
698  // that the events are applied to all its children, which are not available
699  // at the start of the group tag
700  mpImpl->mpGroupContext->maEventData.push_back(rData);
701  }
702  else
703  rData.ApplyProperties();
704 }
705 
707 {
708  SAL_WARN_IF( !mpImpl->mpGroupContext, "xmloff", "No context to sort!" );
709  if( !mpImpl->mpGroupContext )
710  return;
711 
712  try
713  {
714  mpImpl->mpGroupContext->popGroupAndPostProcess();
715  }
716  catch( const uno::Exception& )
717  {
718  DBG_UNHANDLED_EXCEPTION("xmloff", "exception while sorting shapes, sorting failed");
719  }
720 
721  // put parent on top and drop current context, we are done
722  mpImpl->mpGroupContext = mpImpl->mpGroupContext->mpParentContext;
723 }
724 
725 void XMLShapeImportHelper::shapeWithZIndexAdded( css::uno::Reference< css::drawing::XShape > const & xShape, sal_Int32 nZIndex )
726 {
727  if( !mpImpl->mpGroupContext)
728  return;
729 
730  ZOrderHint aNewHint;
731  aNewHint.nIs = mpImpl->mpGroupContext->mnCurrentZ++;
732  aNewHint.nShould = nZIndex;
733  aNewHint.xShape = xShape;
734 
735  if( nZIndex == -1 )
736  {
737  // don't care, so add to unsorted list
738  mpImpl->mpGroupContext->maUnsortedList.push_back(aNewHint);
739  }
740  else
741  {
742  // insert into sort list
743  mpImpl->mpGroupContext->maZOrderList.push_back(aNewHint);
744  }
745 }
746 
747 void XMLShapeImportHelper::shapeRemoved(const uno::Reference<drawing::XShape>& xShape)
748 {
749  auto it = std::find_if(mpImpl->mpGroupContext->maZOrderList.begin(), mpImpl->mpGroupContext->maZOrderList.end(), [&xShape](const ZOrderHint& rHint)
750  {
751  return rHint.xShape == xShape;
752  });
753  if (it == mpImpl->mpGroupContext->maZOrderList.end())
754  // Part of the unsorted list, nothing to do.
755  return;
756 
757  sal_Int32 nZIndex = it->nIs;
758 
759  for (it = mpImpl->mpGroupContext->maZOrderList.begin(); it != mpImpl->mpGroupContext->maZOrderList.end();)
760  {
761  if (it->nIs == nZIndex)
762  {
763  // This is xShape: remove it and adjust the max of indexes
764  // accordingly.
765  it = mpImpl->mpGroupContext->maZOrderList.erase(it);
766  mpImpl->mpGroupContext->mnCurrentZ--;
767  continue;
768  }
769  else if (it->nIs > nZIndex)
770  // On top of xShape: adjust actual index to reflect removal.
771  it->nIs--;
772 
773  // On top of or below xShape.
774  ++it;
775  }
776 }
777 
778 void XMLShapeImportHelper::addShapeConnection( css::uno::Reference< css::drawing::XShape > const & rConnectorShape,
779  bool bStart,
780  const OUString& rDestShapeId,
781  sal_Int32 nDestGlueId )
782 {
783  ConnectionHint aHint;
784  aHint.mxConnector = rConnectorShape;
785  aHint.bStart = bStart;
786  aHint.aDestShapeId = rDestShapeId;
787  aHint.nDestGlueId = nDestGlueId;
788 
789  mpImpl->maConnections.push_back( aHint );
790 }
791 
793 {
794  const vector<ConnectionHint>::size_type nCount = mpImpl->maConnections.size();
795  for( vector<ConnectionHint>::size_type i = 0; i < nCount; i++ )
796  {
797  ConnectionHint& rHint = mpImpl->maConnections[i];
798  uno::Reference< beans::XPropertySet > xConnector( rHint.mxConnector, uno::UNO_QUERY );
799  if( xConnector.is() )
800  {
801  // #86637# remember line deltas
802  uno::Any aLine1Delta;
803  uno::Any aLine2Delta;
804  uno::Any aLine3Delta;
805  OUString aStr1("EdgeLine1Delta");
806  OUString aStr2("EdgeLine2Delta");
807  OUString aStr3("EdgeLine3Delta");
808  aLine1Delta = xConnector->getPropertyValue(aStr1);
809  aLine2Delta = xConnector->getPropertyValue(aStr2);
810  aLine3Delta = xConnector->getPropertyValue(aStr3);
811 
812  // #86637# simply setting these values WILL force the connector to do
813  // a new layout promptly. So the line delta values have to be rescued
814  // and restored around connector changes.
815  uno::Reference< drawing::XShape > xShape(
816  mrImporter.getInterfaceToIdentifierMapper().getReference( rHint.aDestShapeId ), uno::UNO_QUERY );
817  if( xShape.is() )
818  {
819  if (rHint.bStart)
820  xConnector->setPropertyValue( gsStartShape, uno::Any(xShape) );
821  else
822  xConnector->setPropertyValue( gsEndShape, uno::Any(xShape) );
823 
824  sal_Int32 nGlueId = rHint.nDestGlueId < 4 ? rHint.nDestGlueId : getGluePointId( xShape, rHint.nDestGlueId );
825  if(rHint.bStart)
826  xConnector->setPropertyValue( gsStartGluePointIndex, uno::Any(nGlueId) );
827  else
828  xConnector->setPropertyValue( gsEndGluePointIndex, uno::Any(nGlueId) );
829  }
830 
831  // #86637# restore line deltas
832  xConnector->setPropertyValue(aStr1, aLine1Delta );
833  xConnector->setPropertyValue(aStr2, aLine2Delta );
834  xConnector->setPropertyValue(aStr3, aLine3Delta );
835  }
836  }
837  mpImpl->maConnections.clear();
838 }
839 
840 SvXMLImportPropertyMapper* XMLShapeImportHelper::CreateShapePropMapper( const uno::Reference< frame::XModel>& rModel, SvXMLImport& rImport )
841 {
844  SvXMLImportPropertyMapper* pResult = new SvXMLImportPropertyMapper( xMapper, rImport );
845 
846  // chain text attributes
848  return pResult;
849 }
850 
853 void XMLShapeImportHelper::addGluePointMapping( css::uno::Reference< css::drawing::XShape > const & xShape,
854  sal_Int32 nSourceId, sal_Int32 nDestinnationId )
855 {
856  if( mpPageContext )
857  mpPageContext->maShapeGluePointsMap[xShape][nSourceId] = nDestinnationId;
858 }
859 
861 void XMLShapeImportHelper::moveGluePointMapping( const css::uno::Reference< css::drawing::XShape >& xShape, const sal_Int32 n )
862 {
863  if( mpPageContext )
864  {
865  ShapeGluePointsMap::iterator aShapeIter( mpPageContext->maShapeGluePointsMap.find( xShape ) );
866  if( aShapeIter != mpPageContext->maShapeGluePointsMap.end() )
867  {
868  for ( auto& rShapeId : (*aShapeIter).second )
869  {
870  if ( rShapeId.second != -1 )
871  rShapeId.second += n;
872  }
873  }
874  }
875 }
876 
879 sal_Int32 XMLShapeImportHelper::getGluePointId( const css::uno::Reference< css::drawing::XShape >& xShape, sal_Int32 nSourceId )
880 {
881  if( mpPageContext )
882  {
883  ShapeGluePointsMap::iterator aShapeIter( mpPageContext->maShapeGluePointsMap.find( xShape ) );
884  if( aShapeIter != mpPageContext->maShapeGluePointsMap.end() )
885  {
886  GluePointIdMap::iterator aIdIter = (*aShapeIter).second.find(nSourceId);
887  if( aIdIter != (*aShapeIter).second.end() )
888  return (*aIdIter).second;
889  }
890  }
891 
892  return -1;
893 }
894 
896 void XMLShapeImportHelper::startPage( css::uno::Reference< css::drawing::XShapes > const & rShapes )
897 {
898  const std::shared_ptr<XMLShapeImportPageContextImpl> pOldContext = mpPageContext;
899  mpPageContext = std::make_shared<XMLShapeImportPageContextImpl>();
900  mpPageContext->mpNext = pOldContext;
901  mpPageContext->mxShapes = rShapes;
902 }
903 
905 void XMLShapeImportHelper::endPage( css::uno::Reference< css::drawing::XShapes > const & rShapes )
906 {
907  SAL_WARN_IF( !mpPageContext || (mpPageContext->mxShapes != rShapes), "xmloff", "wrong call to endPage(), no startPage called or wrong page" );
908  if( nullptr == mpPageContext )
909  return;
910 
912 
913  mpPageContext = mpPageContext->mpNext;
914 }
915 
918 {
919  mpImpl->mbHandleProgressBar = true;
920 }
921 
923 {
924  return mpImpl->mbHandleProgressBar;
925 }
926 
929 {
930  return mpImpl->mbIsPresentationShapesSupported;
931 }
932 
934 {
935  if( !mxShapeTableImport.is() )
936  {
938  rtl::Reference< XMLPropertySetMapper > xPropertySetMapper( new XMLShapePropertySetMapper( xFactory, false ) );
939  mxShapeTableImport = new XMLTableImport( mrImporter, xPropertySetMapper, xFactory );
940  }
941 
942  return mxShapeTableImport;
943 }
944 
945 void SvXMLShapeContext::setHyperlink( const OUString& rHyperlink )
946 {
947  msHyperlink = rHyperlink;
948 }
949 
950 /* 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:1810
const XMLPropertyMapEntry aXMLSDPresPageProps[]
Definition: sdpropls.cxx:324
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
Definition: shapeimport.cxx:95
rtl::Reference< XMLTableImport > mxShapeTableImport
virtual ~XMLShapeImportHelper() override
DRAW
int nCount
#define XMLOFF_WARN_UNKNOWN(area, rIter)
Definition: xmlictxt.hxx:114
::comphelper::UnoInterfaceToUniqueIdentifierMapper & getInterfaceToIdentifierMapper()
Definition: xmlimp.cxx:1788
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:3296
static OUString getPrefixAndNameFromToken(sal_Int32 nToken)
Definition: xmlimp.cxx:1955
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
Definition: shapeimport.cxx:97
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 gluepoint 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 gluepoint identifier from the current xml file to the identifier created af...
rtl::Reference< SvXMLStylesContext > mxStylesContext
SvXMLImport & mrImporter
ShapeGluePointsMap maShapeGluePointsMap
Definition: shapeimport.cxx:84
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:567
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:45
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 gluepoint id mappings for shapes that had user defined gluepoints.
Definition: shapeimport.cxx:76
std::shared_ptr< XMLShapeImportPageContextImpl > mpNext
Definition: shapeimport.cxx:88
#define SAL_WARN_IF(condition, area, stream)
uno::Reference< drawing::XShapes > mxShapes
Definition: shapeimport.cxx:86
Handling of tokens in XML:
#define SAL_INFO(area, stream)
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:97
rtl::Reference< XMLSdPropHdlFactory > mpSdPropHdlFactory
virtual bool processAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter &)
Definition: ximpshap.cxx:792
const css::uno::Reference< css::frame::XModel > & GetModel() const
Definition: xmlimp.hxx:404
this struct is created for each startPage() call and stores information that is needed during import ...
Definition: shapeimport.cxx:82
std::unordered_map< css::uno::Reference< css::drawing::XShape >, GluePointIdMap > ShapeGluePointsMap
Definition: shapeimport.cxx:77
Reference< XSingleServiceFactory > xFactory
#define XMLOFF_WARN_UNKNOWN_ELEMENT(area, token)
Definition: xmlictxt.hxx:120
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:560
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 ...
Definition: shapeimport.cxx:92
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:463