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
145  mpPropertySetMapper->ChainImportMapper(XMLTextImportHelper::CreateParaExtPropMapper(rImporter));
146  mpPropertySetMapper->ChainImportMapper(XMLTextImportHelper::CreateParaDefaultExtPropMapper(rImporter));
147 
148  // construct PresPagePropsMapper
149  xMapper = new XMLPropertySetMapper(aXMLSDPresPageProps, mpSdPropHdlFactory.get(), false);
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  break;
354  // add other shapes here...
355  default:
356  XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
357  return new SvXMLShapeContext( rImport, bTemporaryShape );
358  }
359 
360  // now parse the attribute list and call the child context for each unknown attribute
361  for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ))
362  {
363  if (!pContext->processAttribute( aIter ))
364  XMLOFF_WARN_UNKNOWN("xmloff", aIter);
365  }
366  return pContext;
367 }
368 
369 // This method is called from SdXMLFrameShapeContext to create children of draw:frame
371  SvXMLImport& rImport,
372  sal_Int32 nElement,
373  const uno::Reference< xml::sax::XFastAttributeList>& rAttrList,
374  uno::Reference< drawing::XShapes > const & rShapes,
375  const uno::Reference< xml::sax::XFastAttributeList>& rFrameAttrList)
376 {
377  SdXMLShapeContext *pContext = nullptr;
378 
380  if( rFrameAttrList.is() )
381  xCombinedAttrList->add(rFrameAttrList);
382 
383  switch(nElement)
384  {
385  case XML_ELEMENT(DRAW, XML_TEXT_BOX):
386  {
387  // text:text-box inside group context
388  pContext = new SdXMLTextBoxShapeContext( rImport, xCombinedAttrList.get(), rShapes );
389  break;
390  }
391  case XML_ELEMENT(DRAW, XML_IMAGE):
392  {
393  // office:image inside group context
394  pContext = new SdXMLGraphicObjectShapeContext( rImport, xCombinedAttrList.get(), rShapes );
395  break;
396  }
397  case XML_ELEMENT(DRAW, XML_OBJECT):
399  {
400  // draw:object or draw:object_ole
401  pContext = new SdXMLObjectShapeContext( rImport, xCombinedAttrList.get(), rShapes );
402  break;
403  }
404  case XML_ELEMENT(TABLE, XML_TABLE):
405  {
406  // draw:object or draw:object_ole
407  if( rImport.IsTableShapeSupported() )
408  pContext = new SdXMLTableShapeContext( rImport, xCombinedAttrList.get(), rShapes );
409  break;
410 
411  }
412  case XML_ELEMENT(DRAW, XML_PLUGIN):
413  {
414  // draw:plugin
415  pContext = new SdXMLPluginShapeContext( rImport, xCombinedAttrList.get(), rShapes );
416  break;
417  }
418  case XML_ELEMENT(DRAW, XML_FLOATING_FRAME):
419  {
420  // draw:floating-frame
421  pContext = new SdXMLFloatingFrameShapeContext( rImport, xCombinedAttrList.get(), rShapes );
422  break;
423  }
424  case XML_ELEMENT(DRAW, XML_APPLET):
425  {
426  // draw:applet
427  pContext = new SdXMLAppletShapeContext( rImport, xCombinedAttrList.get(), rShapes );
428  break;
429  }
430  // add other shapes here...
431  default:
432  XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
433  break;
434  }
435 
436  if( pContext )
437  {
438  // now parse the attribute list and call the child context for each unknown attribute
439  for(auto& aIter : *xCombinedAttrList)
440  {
441  if (!pContext->processAttribute( aIter ))
442  XMLOFF_WARN_UNKNOWN("xmloff", aIter);
443  }
444  }
445 
446  return pContext;
447 }
448 
449 css::uno::Reference< css::xml::sax::XFastContextHandler > XMLShapeImportHelper::CreateFrameChildContext(
450  SvXMLImportContext *pThisContext,
451  sal_Int32 nElement,
452  const uno::Reference< xml::sax::XFastAttributeList>& xAttrList )
453 {
454  css::uno::Reference< css::xml::sax::XFastContextHandler > xContext;
455  SdXMLFrameShapeContext *pFrameContext = dynamic_cast<SdXMLFrameShapeContext*>( pThisContext );
456  if (pFrameContext)
457  xContext = pFrameContext->createFastChildContext( nElement, xAttrList );
458 
459  if (!xContext)
460  XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
461  return xContext;
462 }
463 
467 void XMLShapeImportHelper::addShape( uno::Reference< drawing::XShape >& rShape,
468  const uno::Reference< xml::sax::XFastAttributeList >&,
469  uno::Reference< drawing::XShapes >& rShapes)
470 {
471  if( rShape.is() && rShapes.is() )
472  {
473  // add new shape to parent
474  rShapes->add( rShape );
475  }
476 }
477 
483  css::uno::Reference< css::drawing::XShape >& rShape,
484  const css::uno::Reference< css::xml::sax::XFastAttributeList >&,
485  css::uno::Reference< css::drawing::XShapes >&)
486 {
487  /* Set property <PositionLayoutDir>
488  to <PositionInHoriL2R>, if it exists and the import states that
489  the shape positioning attributes are in horizontal left-to-right
490  layout. This is the case for the OpenOffice.org file format.
491  This setting is done for Writer documents, because the property
492  only exists at service css::text::Shape - the Writer
493  UNO service for shapes.
494  The value indicates that the positioning attributes are given
495  in horizontal left-to-right layout. The property is evaluated
496  during the first positioning of the shape in order to convert
497  the shape position given in the OpenOffice.org file format to
498  the one for the OASIS Open Office file format. (#i28749#, #i36248#)
499  */
500  uno::Reference< beans::XPropertySet > xPropSet(rShape, uno::UNO_QUERY);
501  if ( xPropSet.is() )
502  {
504  xPropSet->getPropertySetInfo()->hasPropertyByName(
505  "PositionLayoutDir") )
506  {
507  uno::Any aPosLayoutDir;
508  aPosLayoutDir <<= text::PositionLayoutDir::PositionInHoriL2R;
509  xPropSet->setPropertyValue( "PositionLayoutDir", aPosLayoutDir );
510  }
511  }
512 }
513 
514 namespace {
515 
516 // helper functions for z-order sorting
517 struct ZOrderHint
518 {
519  sal_Int32 nIs;
520  sal_Int32 nShould;
522  uno::Reference<drawing::XShape> xShape;
523 
524  bool operator<(const ZOrderHint& rComp) const { return nShould < rComp.nShould; }
525 };
526 
527 // a) handle z-order of group contents after it has been imported
528 // b) apply group events over group contents after it has been imported
529 class ShapeGroupContext
530 {
531 public:
532  uno::Reference< drawing::XShapes > mxShapes;
533  std::vector<SdXMLEventContextData> maEventData;
534  vector<ZOrderHint> maZOrderList;
535  vector<ZOrderHint> maUnsortedList;
536 
537  sal_Int32 mnCurrentZ;
538  std::shared_ptr<ShapeGroupContext> mpParentContext;
539 
540  ShapeGroupContext( uno::Reference< drawing::XShapes > const & rShapes, std::shared_ptr<ShapeGroupContext> pParentContext );
541 
542  void popGroupAndPostProcess();
543 private:
544  void moveShape( sal_Int32 nSourcePos, sal_Int32 nDestPos );
545 };
546 
547 }
548 
549 ShapeGroupContext::ShapeGroupContext( uno::Reference< drawing::XShapes > const & rShapes, std::shared_ptr<ShapeGroupContext> pParentContext )
550 : mxShapes( rShapes ), mnCurrentZ( 0 ), mpParentContext( std::move(pParentContext) )
551 {
552 }
553 
554 void ShapeGroupContext::moveShape( sal_Int32 nSourcePos, sal_Int32 nDestPos )
555 {
556  uno::Any aAny( mxShapes->getByIndex( nSourcePos ) );
557  uno::Reference< beans::XPropertySet > xPropSet;
558  aAny >>= xPropSet;
559 
560  if( !(xPropSet.is() && xPropSet->getPropertySetInfo()->hasPropertyByName( "ZOrder" )) )
561  return;
562 
563  xPropSet->setPropertyValue( "ZOrder", uno::Any(nDestPos) );
564 
565  for( ZOrderHint& rHint : maZOrderList )
566  {
567  if( rHint.nIs < nSourcePos )
568  {
569  DBG_ASSERT(rHint.nIs >= nDestPos, "Shape sorting failed" );
570  rHint.nIs++;
571  }
572  }
573 
574  for( ZOrderHint& rHint : maUnsortedList )
575  {
576  if( rHint.nIs < nSourcePos )
577  {
578  SAL_WARN_IF( rHint.nIs < nDestPos, "xmloff", "shape sorting failed" );
579  rHint.nIs++;
580  }
581  }
582 }
583 
584 // sort shapes
585 void ShapeGroupContext::popGroupAndPostProcess()
586 {
587  if (!maEventData.empty())
588  {
589  // tdf#127791 wait until a group is popped to set its event data
590  for (auto& event : maEventData)
591  event.ApplyProperties();
592  maEventData.clear();
593  }
594 
595  // only do something if we have shapes to sort
596  if( maZOrderList.empty() )
597  return;
598 
599  // check if there are more shapes than inserted with ::shapeWithZIndexAdded()
600  // This can happen if there where already shapes on the page before import
601  // Since the writer may delete some of this shapes during import, we need
602  // to do this here and not in our c'tor anymore
603 
604  // check if we have more shapes than we know of
605  sal_Int32 nCount = mxShapes->getCount();
606 
607  nCount -= maZOrderList.size();
608  nCount -= maUnsortedList.size();
609 
610  if( nCount > 0 )
611  {
612  // first update offsets of added shapes
613  for (ZOrderHint& rHint : maZOrderList)
614  rHint.nIs += nCount;
615  for (ZOrderHint& rHint : maUnsortedList)
616  rHint.nIs += nCount;
617 
618  // second add the already existing shapes in the unsorted list
619  ZOrderHint aNewHint;
620  do
621  {
622  nCount--;
623 
624  aNewHint.nIs = nCount;
625  aNewHint.nShould = -1;
626 
627  maUnsortedList.insert(maUnsortedList.begin(), aNewHint);
628  }
629  while( nCount );
630  }
631 
632  bool bSorted = std::is_sorted(maZOrderList.begin(), maZOrderList.end(),
633  [&](const ZOrderHint& rLeft, const ZOrderHint& rRight)
634  { return rLeft.nShould < rRight.nShould; } );
635 
636  if (bSorted)
637  return; // nothin' to do
638 
639  // sort z-ordered shapes by nShould field
640  std::sort(maZOrderList.begin(), maZOrderList.end());
641 
642  uno::Reference<drawing::XShapes3> xShapes3(mxShapes, uno::UNO_QUERY);
643  if( xShapes3.is())
644  {
645  uno::Sequence<sal_Int32> aNewOrder(maZOrderList.size() + maUnsortedList.size());
646  sal_Int32 nIndex = 0;
647 
648  for (ZOrderHint& rHint : maZOrderList)
649  {
650  // fill in the gaps from unordered list
651  for (vector<ZOrderHint>::iterator aIt = maUnsortedList.begin(); aIt != maUnsortedList.end() && nIndex < rHint.nShould; )
652  {
653  aNewOrder[nIndex++] = (*aIt).nIs;
654  aIt = maUnsortedList.erase(aIt);
655  }
656 
657  aNewOrder[nIndex] = rHint.nIs;
658  nIndex++;
659  }
660 
661  try
662  {
663  xShapes3->sort(aNewOrder);
664  maZOrderList.clear();
665  return;
666  }
667  catch (const css::lang::IllegalArgumentException& /*e*/)
668  {}
669  }
670 
671  // this is the current index, all shapes before that
672  // index are finished
673  sal_Int32 nIndex = 0;
674  for (const ZOrderHint& rHint : maZOrderList)
675  {
676  for (vector<ZOrderHint>::iterator aIt = maUnsortedList.begin(); aIt != maUnsortedList.end() && nIndex < rHint.nShould; )
677  {
678  moveShape( (*aIt).nIs, nIndex++ );
679  aIt = maUnsortedList.erase(aIt);
680 
681  }
682 
683  if(rHint.nIs != nIndex )
684  moveShape( rHint.nIs, nIndex );
685 
686  nIndex++;
687  }
688  maZOrderList.clear();
689 }
690 
691 void XMLShapeImportHelper::pushGroupForPostProcessing( uno::Reference< drawing::XShapes >& rShapes )
692 {
693  mpImpl->mpGroupContext = std::make_shared<ShapeGroupContext>( rShapes, mpImpl->mpGroupContext );
694 }
695 
697 {
698  if (mpImpl->mpGroupContext && mpImpl->mpGroupContext->mxShapes == rData.mxShape)
699  {
700  // tdf#127791 wait until a group is popped to set its event data so
701  // that the events are applied to all its children, which are not available
702  // at the start of the group tag
703  mpImpl->mpGroupContext->maEventData.push_back(rData);
704  }
705  else
706  rData.ApplyProperties();
707 }
708 
710 {
711  SAL_WARN_IF( !mpImpl->mpGroupContext, "xmloff", "No context to sort!" );
712  if( !mpImpl->mpGroupContext )
713  return;
714 
715  try
716  {
717  mpImpl->mpGroupContext->popGroupAndPostProcess();
718  }
719  catch( const uno::Exception& )
720  {
721  DBG_UNHANDLED_EXCEPTION("xmloff", "exception while sorting shapes, sorting failed");
722  }
723 
724  // put parent on top and drop current context, we are done
725  mpImpl->mpGroupContext = mpImpl->mpGroupContext->mpParentContext;
726 }
727 
728 void XMLShapeImportHelper::shapeWithZIndexAdded( css::uno::Reference< css::drawing::XShape > const & xShape, sal_Int32 nZIndex )
729 {
730  if( !mpImpl->mpGroupContext)
731  return;
732 
733  ZOrderHint aNewHint;
734  aNewHint.nIs = mpImpl->mpGroupContext->mnCurrentZ++;
735  aNewHint.nShould = nZIndex;
736  aNewHint.xShape = xShape;
737 
738  if( nZIndex == -1 )
739  {
740  // don't care, so add to unsorted list
741  mpImpl->mpGroupContext->maUnsortedList.push_back(aNewHint);
742  }
743  else
744  {
745  // insert into sort list
746  mpImpl->mpGroupContext->maZOrderList.push_back(aNewHint);
747  }
748 }
749 
750 void XMLShapeImportHelper::shapeRemoved(const uno::Reference<drawing::XShape>& xShape)
751 {
752  auto it = std::find_if(mpImpl->mpGroupContext->maZOrderList.begin(), mpImpl->mpGroupContext->maZOrderList.end(), [&xShape](const ZOrderHint& rHint)
753  {
754  return rHint.xShape == xShape;
755  });
756  if (it == mpImpl->mpGroupContext->maZOrderList.end())
757  // Part of the unsorted list, nothing to do.
758  return;
759 
760  sal_Int32 nZIndex = it->nIs;
761 
762  for (it = mpImpl->mpGroupContext->maZOrderList.begin(); it != mpImpl->mpGroupContext->maZOrderList.end();)
763  {
764  if (it->nIs == nZIndex)
765  {
766  // This is xShape: remove it and adjust the max of indexes
767  // accordingly.
768  it = mpImpl->mpGroupContext->maZOrderList.erase(it);
769  mpImpl->mpGroupContext->mnCurrentZ--;
770  continue;
771  }
772  else if (it->nIs > nZIndex)
773  // On top of xShape: adjust actual index to reflect removal.
774  it->nIs--;
775 
776  // On top of or below xShape.
777  ++it;
778  }
779 }
780 
781 void XMLShapeImportHelper::addShapeConnection( css::uno::Reference< css::drawing::XShape > const & rConnectorShape,
782  bool bStart,
783  const OUString& rDestShapeId,
784  sal_Int32 nDestGlueId )
785 {
786  ConnectionHint aHint;
787  aHint.mxConnector = rConnectorShape;
788  aHint.bStart = bStart;
789  aHint.aDestShapeId = rDestShapeId;
790  aHint.nDestGlueId = nDestGlueId;
791 
792  mpImpl->maConnections.push_back( aHint );
793 }
794 
796 {
797  const vector<ConnectionHint>::size_type nCount = mpImpl->maConnections.size();
798  for( vector<ConnectionHint>::size_type i = 0; i < nCount; i++ )
799  {
800  ConnectionHint& rHint = mpImpl->maConnections[i];
801  uno::Reference< beans::XPropertySet > xConnector( rHint.mxConnector, uno::UNO_QUERY );
802  if( xConnector.is() )
803  {
804  // #86637# remember line deltas
805  uno::Any aLine1Delta;
806  uno::Any aLine2Delta;
807  uno::Any aLine3Delta;
808  OUString aStr1("EdgeLine1Delta");
809  OUString aStr2("EdgeLine2Delta");
810  OUString aStr3("EdgeLine3Delta");
811  aLine1Delta = xConnector->getPropertyValue(aStr1);
812  aLine2Delta = xConnector->getPropertyValue(aStr2);
813  aLine3Delta = xConnector->getPropertyValue(aStr3);
814 
815  // #86637# simply setting these values WILL force the connector to do
816  // a new layout promptly. So the line delta values have to be rescued
817  // and restored around connector changes.
818  uno::Reference< drawing::XShape > xShape(
819  mrImporter.getInterfaceToIdentifierMapper().getReference( rHint.aDestShapeId ), uno::UNO_QUERY );
820  if( xShape.is() )
821  {
822  if (rHint.bStart)
823  xConnector->setPropertyValue( gsStartShape, uno::Any(xShape) );
824  else
825  xConnector->setPropertyValue( gsEndShape, uno::Any(xShape) );
826 
827  sal_Int32 nGlueId = rHint.nDestGlueId < 4 ? rHint.nDestGlueId : getGluePointId( xShape, rHint.nDestGlueId );
828  if(rHint.bStart)
829  xConnector->setPropertyValue( gsStartGluePointIndex, uno::Any(nGlueId) );
830  else
831  xConnector->setPropertyValue( gsEndGluePointIndex, uno::Any(nGlueId) );
832  }
833 
834  // #86637# restore line deltas
835  xConnector->setPropertyValue(aStr1, aLine1Delta );
836  xConnector->setPropertyValue(aStr2, aLine2Delta );
837  xConnector->setPropertyValue(aStr3, aLine3Delta );
838  }
839  }
840  mpImpl->maConnections.clear();
841 }
842 
843 SvXMLImportPropertyMapper* XMLShapeImportHelper::CreateShapePropMapper( const uno::Reference< frame::XModel>& rModel, SvXMLImport& rImport )
844 {
847  SvXMLImportPropertyMapper* pResult = new SvXMLImportPropertyMapper( xMapper, rImport );
848 
849  // chain text attributes
851  return pResult;
852 }
853 
856 void XMLShapeImportHelper::addGluePointMapping( css::uno::Reference< css::drawing::XShape > const & xShape,
857  sal_Int32 nSourceId, sal_Int32 nDestinnationId )
858 {
859  if( mpPageContext )
860  mpPageContext->maShapeGluePointsMap[xShape][nSourceId] = nDestinnationId;
861 }
862 
864 void XMLShapeImportHelper::moveGluePointMapping( const css::uno::Reference< css::drawing::XShape >& xShape, const sal_Int32 n )
865 {
866  if( mpPageContext )
867  {
868  ShapeGluePointsMap::iterator aShapeIter( mpPageContext->maShapeGluePointsMap.find( xShape ) );
869  if( aShapeIter != mpPageContext->maShapeGluePointsMap.end() )
870  {
871  for ( auto& rShapeId : (*aShapeIter).second )
872  {
873  if ( rShapeId.second != -1 )
874  rShapeId.second += n;
875  }
876  }
877  }
878 }
879 
882 sal_Int32 XMLShapeImportHelper::getGluePointId( const css::uno::Reference< css::drawing::XShape >& xShape, sal_Int32 nSourceId )
883 {
884  if( mpPageContext )
885  {
886  ShapeGluePointsMap::iterator aShapeIter( mpPageContext->maShapeGluePointsMap.find( xShape ) );
887  if( aShapeIter != mpPageContext->maShapeGluePointsMap.end() )
888  {
889  GluePointIdMap::iterator aIdIter = (*aShapeIter).second.find(nSourceId);
890  if( aIdIter != (*aShapeIter).second.end() )
891  return (*aIdIter).second;
892  }
893  }
894 
895  return -1;
896 }
897 
899 void XMLShapeImportHelper::startPage( css::uno::Reference< css::drawing::XShapes > const & rShapes )
900 {
901  const std::shared_ptr<XMLShapeImportPageContextImpl> pOldContext = mpPageContext;
902  mpPageContext = std::make_shared<XMLShapeImportPageContextImpl>();
903  mpPageContext->mpNext = pOldContext;
904  mpPageContext->mxShapes = rShapes;
905 }
906 
908 void XMLShapeImportHelper::endPage( css::uno::Reference< css::drawing::XShapes > const & rShapes )
909 {
910  SAL_WARN_IF( !mpPageContext || (mpPageContext->mxShapes != rShapes), "xmloff", "wrong call to endPage(), no startPage called or wrong page" );
911  if( nullptr == mpPageContext )
912  return;
913 
915 
916  mpPageContext = mpPageContext->mpNext;
917 }
918 
921 {
922  mpImpl->mbHandleProgressBar = true;
923 }
924 
926 {
927  return mpImpl->mbHandleProgressBar;
928 }
929 
932 {
933  return mpImpl->mbIsPresentationShapesSupported;
934 }
935 
937 {
938  if( !mxShapeTableImport.is() )
939  {
941  rtl::Reference< XMLPropertySetMapper > xPropertySetMapper( new XMLShapePropertySetMapper( xFactory.get(), false ) );
942  mxShapeTableImport = new XMLTableImport( mrImporter, xPropertySetMapper, xFactory );
943  }
944 
945  return mxShapeTableImport;
946 }
947 
948 void SvXMLShapeContext::setHyperlink( const OUString& rHyperlink )
949 {
950  msHyperlink = rHyperlink;
951 }
952 
953 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_Int32 nIndex
css::uno::Reference< css::drawing::XShape > mxShape
Definition: eventimp.hxx:52
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:1786
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:110
::comphelper::UnoInterfaceToUniqueIdentifierMapper & getInterfaceToIdentifierMapper()
Definition: xmlimp.cxx:1764
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:565
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 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:399
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:116
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:558
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:458