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  XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", 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  XMLOFF_WARN_UNKNOWN("xmloff", aIter);
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::makeAny(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  sal_Int32 nIndex = 0;
643 
644  for (const ZOrderHint& rHint : maZOrderList)
645  {
646  // fill in the gaps from unordered list
647  for (vector<ZOrderHint>::iterator aIt = maUnsortedList.begin(); aIt != maUnsortedList.end() && nIndex < rHint.nShould; )
648  {
649  aNewOrder[nIndex++] = (*aIt).nIs;
650  aIt = maUnsortedList.erase(aIt);
651  }
652 
653  aNewOrder[nIndex] = rHint.nIs;
654  nIndex++;
655  }
656 
657  try
658  {
659  xShapes3->sort(aNewOrder);
660  maZOrderList.clear();
661  return;
662  }
663  catch (const css::lang::IllegalArgumentException& /*e*/)
664  {}
665  }
666 
667  // this is the current index, all shapes before that
668  // index are finished
669  sal_Int32 nIndex = 0;
670  for (const ZOrderHint& rHint : maZOrderList)
671  {
672  for (vector<ZOrderHint>::iterator aIt = maUnsortedList.begin(); aIt != maUnsortedList.end() && nIndex < rHint.nShould; )
673  {
674  moveShape( (*aIt).nIs, nIndex++ );
675  aIt = maUnsortedList.erase(aIt);
676 
677  }
678 
679  if(rHint.nIs != nIndex )
680  moveShape( rHint.nIs, nIndex );
681 
682  nIndex++;
683  }
684  maZOrderList.clear();
685 }
686 
687 void XMLShapeImportHelper::pushGroupForPostProcessing( uno::Reference< drawing::XShapes >& rShapes )
688 {
689  mpImpl->mpGroupContext = std::make_shared<ShapeGroupContext>( rShapes, mpImpl->mpGroupContext );
690 }
691 
693 {
694  if (mpImpl->mpGroupContext && mpImpl->mpGroupContext->mxShapes == rData.mxShape)
695  {
696  // tdf#127791 wait until a group is popped to set its event data so
697  // that the events are applied to all its children, which are not available
698  // at the start of the group tag
699  mpImpl->mpGroupContext->maEventData.push_back(rData);
700  }
701  else
702  rData.ApplyProperties();
703 }
704 
706 {
707  SAL_WARN_IF( !mpImpl->mpGroupContext, "xmloff", "No context to sort!" );
708  if( !mpImpl->mpGroupContext )
709  return;
710 
711  try
712  {
713  mpImpl->mpGroupContext->popGroupAndPostProcess();
714  }
715  catch( const uno::Exception& )
716  {
717  DBG_UNHANDLED_EXCEPTION("xmloff", "exception while sorting shapes, sorting failed");
718  }
719 
720  // put parent on top and drop current context, we are done
721  mpImpl->mpGroupContext = mpImpl->mpGroupContext->mpParentContext;
722 }
723 
724 void XMLShapeImportHelper::shapeWithZIndexAdded( css::uno::Reference< css::drawing::XShape > const & xShape, sal_Int32 nZIndex )
725 {
726  if( !mpImpl->mpGroupContext)
727  return;
728 
729  ZOrderHint aNewHint;
730  aNewHint.nIs = mpImpl->mpGroupContext->mnCurrentZ++;
731  aNewHint.nShould = nZIndex;
732  aNewHint.xShape = xShape;
733 
734  if( nZIndex == -1 )
735  {
736  // don't care, so add to unsorted list
737  mpImpl->mpGroupContext->maUnsortedList.push_back(aNewHint);
738  }
739  else
740  {
741  // insert into sort list
742  mpImpl->mpGroupContext->maZOrderList.push_back(aNewHint);
743  }
744 }
745 
746 void XMLShapeImportHelper::shapeRemoved(const uno::Reference<drawing::XShape>& xShape)
747 {
748  auto it = std::find_if(mpImpl->mpGroupContext->maZOrderList.begin(), mpImpl->mpGroupContext->maZOrderList.end(), [&xShape](const ZOrderHint& rHint)
749  {
750  return rHint.xShape == xShape;
751  });
752  if (it == mpImpl->mpGroupContext->maZOrderList.end())
753  // Part of the unsorted list, nothing to do.
754  return;
755 
756  sal_Int32 nZIndex = it->nIs;
757 
758  for (it = mpImpl->mpGroupContext->maZOrderList.begin(); it != mpImpl->mpGroupContext->maZOrderList.end();)
759  {
760  if (it->nIs == nZIndex)
761  {
762  // This is xShape: remove it and adjust the max of indexes
763  // accordingly.
764  it = mpImpl->mpGroupContext->maZOrderList.erase(it);
765  mpImpl->mpGroupContext->mnCurrentZ--;
766  continue;
767  }
768  else if (it->nIs > nZIndex)
769  // On top of xShape: adjust actual index to reflect removal.
770  it->nIs--;
771 
772  // On top of or below xShape.
773  ++it;
774  }
775 }
776 
777 void XMLShapeImportHelper::addShapeConnection( css::uno::Reference< css::drawing::XShape > const & rConnectorShape,
778  bool bStart,
779  const OUString& rDestShapeId,
780  sal_Int32 nDestGlueId )
781 {
782  ConnectionHint aHint;
783  aHint.mxConnector = rConnectorShape;
784  aHint.bStart = bStart;
785  aHint.aDestShapeId = rDestShapeId;
786  aHint.nDestGlueId = nDestGlueId;
787 
788  mpImpl->maConnections.push_back( aHint );
789 }
790 
792 {
793  const vector<ConnectionHint>::size_type nCount = mpImpl->maConnections.size();
794  for( vector<ConnectionHint>::size_type i = 0; i < nCount; i++ )
795  {
796  ConnectionHint& rHint = mpImpl->maConnections[i];
797  uno::Reference< beans::XPropertySet > xConnector( rHint.mxConnector, uno::UNO_QUERY );
798  if( xConnector.is() )
799  {
800  // #86637# remember line deltas
801  uno::Any aLine1Delta;
802  uno::Any aLine2Delta;
803  uno::Any aLine3Delta;
804  OUString aStr1("EdgeLine1Delta");
805  OUString aStr2("EdgeLine2Delta");
806  OUString aStr3("EdgeLine3Delta");
807  aLine1Delta = xConnector->getPropertyValue(aStr1);
808  aLine2Delta = xConnector->getPropertyValue(aStr2);
809  aLine3Delta = xConnector->getPropertyValue(aStr3);
810 
811  // #86637# simply setting these values WILL force the connector to do
812  // a new layout promptly. So the line delta values have to be rescued
813  // and restored around connector changes.
814  uno::Reference< drawing::XShape > xShape(
815  mrImporter.getInterfaceToIdentifierMapper().getReference( rHint.aDestShapeId ), uno::UNO_QUERY );
816  if( xShape.is() )
817  {
818  if (rHint.bStart)
819  xConnector->setPropertyValue( gsStartShape, uno::Any(xShape) );
820  else
821  xConnector->setPropertyValue( gsEndShape, uno::Any(xShape) );
822 
823  sal_Int32 nGlueId = rHint.nDestGlueId < 4 ? rHint.nDestGlueId : getGluePointId( xShape, rHint.nDestGlueId );
824  if(rHint.bStart)
825  xConnector->setPropertyValue( gsStartGluePointIndex, uno::Any(nGlueId) );
826  else
827  xConnector->setPropertyValue( gsEndGluePointIndex, uno::Any(nGlueId) );
828  }
829 
830  // #86637# restore line deltas
831  xConnector->setPropertyValue(aStr1, aLine1Delta );
832  xConnector->setPropertyValue(aStr2, aLine2Delta );
833  xConnector->setPropertyValue(aStr3, aLine3Delta );
834  }
835  }
836  mpImpl->maConnections.clear();
837 }
838 
839 SvXMLImportPropertyMapper* XMLShapeImportHelper::CreateShapePropMapper( const uno::Reference< frame::XModel>& rModel, SvXMLImport& rImport )
840 {
843  SvXMLImportPropertyMapper* pResult = new SvXMLImportPropertyMapper( xMapper, rImport );
844 
845  // chain text attributes
847  return pResult;
848 }
849 
852 void XMLShapeImportHelper::addGluePointMapping( css::uno::Reference< css::drawing::XShape > const & xShape,
853  sal_Int32 nSourceId, sal_Int32 nDestinnationId )
854 {
855  if( mpPageContext )
856  mpPageContext->maShapeGluePointsMap[xShape][nSourceId] = nDestinnationId;
857 }
858 
860 void XMLShapeImportHelper::moveGluePointMapping( const css::uno::Reference< css::drawing::XShape >& xShape, const sal_Int32 n )
861 {
862  if( mpPageContext )
863  {
864  ShapeGluePointsMap::iterator aShapeIter( mpPageContext->maShapeGluePointsMap.find( xShape ) );
865  if( aShapeIter != mpPageContext->maShapeGluePointsMap.end() )
866  {
867  for ( auto& rShapeId : (*aShapeIter).second )
868  {
869  if ( rShapeId.second != -1 )
870  rShapeId.second += n;
871  }
872  }
873  }
874 }
875 
878 sal_Int32 XMLShapeImportHelper::getGluePointId( const css::uno::Reference< css::drawing::XShape >& xShape, sal_Int32 nSourceId )
879 {
880  if( mpPageContext )
881  {
882  ShapeGluePointsMap::iterator aShapeIter( mpPageContext->maShapeGluePointsMap.find( xShape ) );
883  if( aShapeIter != mpPageContext->maShapeGluePointsMap.end() )
884  {
885  GluePointIdMap::iterator aIdIter = (*aShapeIter).second.find(nSourceId);
886  if( aIdIter != (*aShapeIter).second.end() )
887  return (*aIdIter).second;
888  }
889  }
890 
891  return -1;
892 }
893 
895 void XMLShapeImportHelper::startPage( css::uno::Reference< css::drawing::XShapes > const & rShapes )
896 {
897  const std::shared_ptr<XMLShapeImportPageContextImpl> pOldContext = mpPageContext;
898  mpPageContext = std::make_shared<XMLShapeImportPageContextImpl>();
899  mpPageContext->mpNext = pOldContext;
900  mpPageContext->mxShapes = rShapes;
901 }
902 
904 void XMLShapeImportHelper::endPage( css::uno::Reference< css::drawing::XShapes > const & rShapes )
905 {
906  SAL_WARN_IF( !mpPageContext || (mpPageContext->mxShapes != rShapes), "xmloff", "wrong call to endPage(), no startPage called or wrong page" );
907  if( nullptr == mpPageContext )
908  return;
909 
911 
912  mpPageContext = mpPageContext->mpNext;
913 }
914 
917 {
918  mpImpl->mbHandleProgressBar = true;
919 }
920 
922 {
923  return mpImpl->mbHandleProgressBar;
924 }
925 
928 {
929  return mpImpl->mbIsPresentationShapesSupported;
930 }
931 
933 {
934  if( !mxShapeTableImport.is() )
935  {
937  rtl::Reference< XMLPropertySetMapper > xPropertySetMapper( new XMLShapePropertySetMapper( xFactory, false ) );
938  mxShapeTableImport = new XMLTableImport( mrImporter, xPropertySetMapper, xFactory );
939  }
940 
941  return mxShapeTableImport;
942 }
943 
944 void SvXMLShapeContext::setHyperlink( const OUString& rHyperlink )
945 {
946  msHyperlink = rHyperlink;
947 }
948 
949 /* 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:1799
const XMLPropertyMapEntry aXMLSDPresPageProps[]
Definition: sdpropls.cxx:321
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:113
::comphelper::UnoInterfaceToUniqueIdentifierMapper & getInterfaceToIdentifierMapper()
Definition: xmlimp.cxx:1777
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:3255
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: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 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:
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:782
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: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: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