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>
23 
24 #include <com/sun/star/beans/XPropertySet.hpp>
25 #include <com/sun/star/text/PositionLayoutDir.hpp>
26 #include <com/sun/star/drawing/XShapes3.hpp>
27 
28 #include <utility>
30 
31 #include <xmloff/shapeimport.hxx>
32 #include <xmloff/xmlstyle.hxx>
33 #include <xmloff/xmltkmap.hxx>
34 #include <xmloff/xmlnamespace.hxx>
35 #include <xmloff/xmltoken.hxx>
37 #include <xmloff/attrlist.hxx>
38 #include "eventimp.hxx"
39 #include "ximpshap.hxx"
40 #include "sdpropls.hxx"
41 #include <xmloff/xmlprmap.hxx>
42 #include "ximp3dscene.hxx"
43 #include "ximp3dobject.hxx"
44 #include "ximpgrp.hxx"
45 #include "ximplink.hxx"
46 
47 #include <map>
48 #include <string_view>
49 #include <vector>
50 
51 namespace {
52 
53 class ShapeGroupContext;
54 
55 }
56 
57 using namespace ::std;
58 using namespace ::com::sun::star;
59 using namespace ::xmloff::token;
60 
61 namespace {
62 
63 struct ConnectionHint
64 {
65  css::uno::Reference< css::drawing::XShape > mxConnector;
66  bool bStart;
67  OUString aDestShapeId;
68  sal_Int32 nDestGlueId;
69 };
70 
71 struct XShapeCompareHelper
72 {
73  bool operator()(const css::uno::Reference < css::drawing::XShape >& x1,
74  const css::uno::Reference < css::drawing::XShape >& x2 ) const
75  {
76  return x1.get() < x2.get();
77  }
78 };
79 
80 }
81 
84 typedef std::map<sal_Int32,sal_Int32> GluePointIdMap;
85 typedef std::map< css::uno::Reference < css::drawing::XShape >, GluePointIdMap, XShapeCompareHelper > ShapeGluePointsMap;
86 
91 {
92  ShapeGluePointsMap maShapeGluePointsMap;
93 
94  uno::Reference < drawing::XShapes > mxShapes;
95 
96  std::shared_ptr<XMLShapeImportPageContextImpl> mpNext;
97 };
98 
101 {
102  // context for sorting shapes
103  std::shared_ptr<ShapeGroupContext> mpGroupContext;
104 
105  std::vector<ConnectionHint> maConnections;
106 
107  // #88546# possibility to switch progress bar handling on/off
109 
110  // stores the capability of the current model to create presentation shapes
112 };
113 
114 const std::u16string_view gsStartShape(u"StartShape");
115 const std::u16string_view gsEndShape(u"EndShape");
116 const std::u16string_view gsStartGluePointIndex(u"StartGluePointIndex");
117 const std::u16string_view gsEndGluePointIndex(u"EndGluePointIndex");
118 
120  SvXMLImport& rImporter,
121  const uno::Reference< frame::XModel>& rModel,
122  SvXMLImportPropertyMapper *pExtMapper )
123 : mpImpl( new XMLShapeImportHelperImpl ),
124  mrImporter( rImporter )
125 {
126  mpImpl->mpGroupContext = nullptr;
127 
128  // #88546# init to sal_False
129  mpImpl->mbHandleProgressBar = false;
130 
131  mpSdPropHdlFactory = new XMLSdPropHdlFactory( rModel, rImporter );
132 
133  // construct PropertySetMapper
135  mpPropertySetMapper = new SvXMLImportPropertyMapper( xMapper, rImporter );
136 
137  if( pExtMapper )
138  {
139  rtl::Reference < SvXMLImportPropertyMapper > xExtMapper( pExtMapper );
140  mpPropertySetMapper->ChainImportMapper( xExtMapper );
141  }
142 
143  // chain text attributes
144  mpPropertySetMapper->ChainImportMapper(XMLTextImportHelper::CreateParaExtPropMapper(rImporter));
145  mpPropertySetMapper->ChainImportMapper(XMLTextImportHelper::CreateParaDefaultExtPropMapper(rImporter));
146 
147  // construct PresPagePropsMapper
148  xMapper = new XMLPropertySetMapper(aXMLSDPresPageProps, mpSdPropHdlFactory.get(), false);
149  mpPresPagePropsMapper = new SvXMLImportPropertyMapper( xMapper, rImporter );
150 
151  uno::Reference< lang::XServiceInfo > xInfo( rImporter.GetModel(), uno::UNO_QUERY );
152  mpImpl->mbIsPresentationShapesSupported = xInfo.is() && xInfo->supportsService( "com.sun.star.presentation.PresentationDocument" );
153 }
154 
156 {
157  SAL_WARN_IF( !mpImpl->maConnections.empty(), "xmloff", "XMLShapeImportHelper::restoreConnections() was not called!" );
158 
159  // cleanup factory, decrease refcount. Should lead to destruction.
160  mpSdPropHdlFactory.clear();
161 
162  // cleanup mapper, decrease refcount. Should lead to destruction.
163  mpPropertySetMapper.clear();
164 
165  // cleanup presPage mapper, decrease refcount. Should lead to destruction.
166  mpPresPagePropsMapper.clear();
167 
168  // Styles or AutoStyles context?
169  if(mxStylesContext.is())
170  mxStylesContext->dispose();
171 
172  if(mxAutoStylesContext.is())
173  mxAutoStylesContext->dispose();
174 }
175 
177 {
179  {
180  static const SvXMLTokenMapEntry aGroupShapeElemTokenMap[] =
181  {
190 
196 
199 
201 
205 
207  };
208 
209  mpGroupShapeElemTokenMap = std::make_unique<SvXMLTokenMap>(aGroupShapeElemTokenMap);
210  }
211 
212  return *mpGroupShapeElemTokenMap;
213 }
214 
216 {
218  {
219  static const SvXMLTokenMapEntry aFrameShapeElemTokenMap[] =
220  {
230  };
231 
232  mpFrameShapeElemTokenMap = std::make_unique<SvXMLTokenMap>(aFrameShapeElemTokenMap);
233  }
234 
235  return *mpFrameShapeElemTokenMap;
236 }
237 
239 {
241  {
242  static const SvXMLTokenMapEntry a3DSceneShapeElemTokenMap[] =
243  {
250  };
251 
252  mp3DSceneShapeElemTokenMap = std::make_unique<SvXMLTokenMap>(a3DSceneShapeElemTokenMap);
253  }
254 
256 }
257 
259 {
261  {
262  static const SvXMLTokenMapEntry a3DObjectAttrTokenMap[] =
263  {
267  };
268 
269  mp3DObjectAttrTokenMap = std::make_unique<SvXMLTokenMap>(a3DObjectAttrTokenMap);
270  }
271 
272  return *mp3DObjectAttrTokenMap;
273 }
274 
276 {
278  {
279  static const SvXMLTokenMapEntry a3DPolygonBasedAttrTokenMap[] =
280  {
284  };
285 
286  mp3DPolygonBasedAttrTokenMap = std::make_unique<SvXMLTokenMap>(a3DPolygonBasedAttrTokenMap);
287  }
288 
290 }
291 
293 {
295  {
296  static const SvXMLTokenMapEntry a3DCubeObjectAttrTokenMap[] =
297  {
301  };
302 
303  mp3DCubeObjectAttrTokenMap = std::make_unique<SvXMLTokenMap>(a3DCubeObjectAttrTokenMap);
304  }
305 
307 }
308 
310 {
312  {
313  static const SvXMLTokenMapEntry a3DSphereObjectAttrTokenMap[] =
314  {
318  };
319 
320  mp3DSphereObjectAttrTokenMap = std::make_unique<SvXMLTokenMap>(a3DSphereObjectAttrTokenMap);
321  }
322 
324 }
325 
327 {
329  {
330  static const SvXMLTokenMapEntry a3DLightAttrTokenMap[] =
331  {
337  };
338 
339  mp3DLightAttrTokenMap = std::make_unique<SvXMLTokenMap>(a3DLightAttrTokenMap);
340  }
341 
342  return *mp3DLightAttrTokenMap;
343 }
344 
346  SvXMLImport& rImport,
347  sal_uInt16 p_nPrefix,
348  const OUString& rLocalName,
349  const uno::Reference< xml::sax::XAttributeList>& xAttrList,
350  uno::Reference< drawing::XShapes > const & rShapes)
351 {
352  SdXMLShapeContext *pContext = nullptr;
353 
354  if(rShapes.is())
355  {
356  const SvXMLTokenMap& rTokenMap = Get3DSceneShapeElemTokenMap();
357  switch(rTokenMap.Get(p_nPrefix, rLocalName))
358  {
360  {
361  // dr3d:3dscene inside dr3d:3dscene context
362  pContext = new SdXML3DSceneShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, false);
363  break;
364  }
366  {
367  // dr3d:3dcube inside dr3d:3dscene context
368  pContext = new SdXML3DCubeObjectShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes);
369  break;
370  }
372  {
373  // dr3d:3dsphere inside dr3d:3dscene context
374  pContext = new SdXML3DSphereObjectShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes);
375  break;
376  }
378  {
379  // dr3d:3dlathe inside dr3d:3dscene context
380  pContext = new SdXML3DLatheObjectShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes);
381  break;
382  }
384  {
385  // dr3d:3dextrude inside dr3d:3dscene context
386  pContext = new SdXML3DExtrudeObjectShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes);
387  break;
388  }
389  }
390  }
391 
392  if (!pContext)
393  return nullptr;
394 
395  // now parse the attribute list and call the child context for each unknown attribute
396  sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
397  for(sal_Int16 a(0); a < nAttrCount; a++)
398  {
399  const OUString& rAttrName = xAttrList->getNameByIndex(a);
400  OUString aLocalName;
401  sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName(rAttrName, &aLocalName);
402  const OUString aValue( xAttrList->getValueByIndex(a) );
403 
404  pContext->processAttribute( nPrefix, aLocalName, aValue );
405  }
406 
407  return pContext;
408 }
409 
411 {
412  mxStylesContext.set(pNew);
413 }
414 
416 {
417  mxAutoStylesContext.set(pNew);
418 }
419 
421  SvXMLImport& rImport,
422  sal_uInt16 p_nPrefix,
423  const OUString& rLocalName,
424  const uno::Reference< xml::sax::XAttributeList>& xAttrList,
425  uno::Reference< drawing::XShapes > const & rShapes,
426  bool bTemporaryShape)
427 {
428  SdXMLShapeContext *pContext = nullptr;
429 
430  const SvXMLTokenMap& rTokenMap = GetGroupShapeElemTokenMap();
431  sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
432 
433  switch(rTokenMap.Get(p_nPrefix, rLocalName))
434  {
435  case XML_TOK_GROUP_GROUP:
436  {
437  // draw:g inside group context (RECURSIVE)
438  pContext = new SdXMLGroupShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape);
439  break;
440  }
442  {
443  // dr3d:3dscene inside group context
444  pContext = new SdXML3DSceneShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape);
445  break;
446  }
447  case XML_TOK_GROUP_RECT:
448  {
449  // draw:rect inside group context
450  pContext = new SdXMLRectShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
451  break;
452  }
453  case XML_TOK_GROUP_LINE:
454  {
455  // draw:line inside group context
456  pContext = new SdXMLLineShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
457  break;
458  }
461  {
462  // draw:circle or draw:ellipse inside group context
463  pContext = new SdXMLEllipseShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
464  break;
465  }
468  {
469  // draw:polygon or draw:polyline inside group context
470  pContext = new SdXMLPolygonShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes,
471  rTokenMap.Get(p_nPrefix, rLocalName) == XML_TOK_GROUP_POLYGON, bTemporaryShape );
472  break;
473  }
474  case XML_TOK_GROUP_PATH:
475  {
476  // draw:path inside group context
477  pContext = new SdXMLPathShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape);
478  break;
479  }
480  case XML_TOK_GROUP_FRAME:
481  {
482  // text:text-box inside group context
483  pContext = new SdXMLFrameShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
484  break;
485  }
487  {
488  // draw:control inside group context
489  pContext = new SdXMLControlShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
490  break;
491  }
493  {
494  // draw:connector inside group context
495  pContext = new SdXMLConnectorShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
496  break;
497  }
499  {
500  // draw:measure inside group context
501  pContext = new SdXMLMeasureShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
502  break;
503  }
504  case XML_TOK_GROUP_PAGE:
505  {
506  // draw:page inside group context
507  pContext = new SdXMLPageShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
508  break;
509  }
512  {
513  // draw:caption inside group context
514  pContext = new SdXMLCaptionShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
515  break;
516  }
517  case XML_TOK_GROUP_CHART:
518  {
519  // chart:chart inside group context
520  pContext = new SdXMLChartShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
521  break;
522  }
524  {
525  // draw:customshape
526  pContext = new SdXMLCustomShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes );
527  break;
528  }
529  case XML_TOK_GROUP_A:
530  {
531  return new SdXMLShapeLinkContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes );
532  }
533  // add other shapes here...
534  default:
535  return new SvXMLShapeContext( rImport, p_nPrefix, rLocalName, bTemporaryShape );
536  }
537 
538  // now parse the attribute list and call the child context for each unknown attribute
539  for(sal_Int16 a(0); a < nAttrCount; a++)
540  {
541  const OUString& rAttrName = xAttrList->getNameByIndex(a);
542  OUString aLocalName;
543  sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName(rAttrName, &aLocalName);
544  const OUString aValue( xAttrList->getValueByIndex(a) );
545 
546  pContext->processAttribute( nPrefix, aLocalName, aValue );
547  }
548 
549  return pContext;
550 }
551 
552 // This method is called from SdXMLFrameShapeContext to create children of draw:frame
554  SvXMLImport& rImport,
555  sal_uInt16 p_nPrefix,
556  const OUString& rLocalName,
557  const uno::Reference< xml::sax::XAttributeList>& rAttrList,
558  uno::Reference< drawing::XShapes > const & rShapes,
559  const uno::Reference< xml::sax::XAttributeList>& rFrameAttrList)
560 {
561  SdXMLShapeContext *pContext = nullptr;
562 
563  const SvXMLTokenMap& rTokenMap = GetFrameShapeElemTokenMap();
564 
565  SvXMLAttributeList *pAttrList = new SvXMLAttributeList( rAttrList );
566  if( rFrameAttrList.is() )
567  pAttrList->AppendAttributeList( rFrameAttrList );
568  uno::Reference < xml::sax::XAttributeList > xAttrList = pAttrList;
569 
570  switch(rTokenMap.Get(p_nPrefix, rLocalName))
571  {
573  {
574  // text:text-box inside group context
575  pContext = new SdXMLTextBoxShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes );
576  break;
577  }
578  case XML_TOK_FRAME_IMAGE:
579  {
580  // office:image inside group context
581  pContext = new SdXMLGraphicObjectShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes );
582  break;
583  }
586  {
587  // draw:object or draw:object_ole
588  pContext = new SdXMLObjectShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes );
589  break;
590  }
591  case XML_TOK_FRAME_TABLE:
592  {
593  // draw:object or draw:object_ole
594  if( rImport.IsTableShapeSupported() )
595  pContext = new SdXMLTableShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes );
596  break;
597 
598  }
600  {
601  // draw:plugin
602  pContext = new SdXMLPluginShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes );
603  break;
604  }
606  {
607  // draw:floating-frame
608  pContext = new SdXMLFloatingFrameShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes );
609  break;
610  }
612  {
613  // draw:applet
614  pContext = new SdXMLAppletShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes );
615  break;
616  }
617  // add other shapes here...
618  default:
619  break;
620  }
621 
622  if( pContext )
623  {
624  // now parse the attribute list and call the child context for each unknown attribute
625  sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
626  for(sal_Int16 a(0); a < nAttrCount; a++)
627  {
628  const OUString& rAttrName = xAttrList->getNameByIndex(a);
629  OUString aLocalName;
630  sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName(rAttrName, &aLocalName);
631  const OUString aValue( xAttrList->getValueByIndex(a) );
632 
633  pContext->processAttribute( nPrefix, aLocalName, aValue );
634  }
635  }
636 
637  return pContext;
638 }
639 
641  SvXMLImportContext *pThisContext,
642  sal_uInt16 nPrefix,
643  const OUString& rLocalName,
644  const uno::Reference< xml::sax::XAttributeList>& xAttrList )
645 {
646  SvXMLImportContextRef xContext;
647 
648  SdXMLFrameShapeContext *pFrameContext = dynamic_cast<SdXMLFrameShapeContext*>( pThisContext );
649  if (pFrameContext)
650  xContext = pFrameContext->CreateChildContext( nPrefix, rLocalName, xAttrList );
651 
652  return xContext;
653 }
654 
658 void XMLShapeImportHelper::addShape( uno::Reference< drawing::XShape >& rShape,
659  const uno::Reference< xml::sax::XAttributeList >&,
660  uno::Reference< drawing::XShapes >& rShapes)
661 {
662  if( rShape.is() && rShapes.is() )
663  {
664  // add new shape to parent
665  rShapes->add( rShape );
666  }
667 }
668 
674  css::uno::Reference< css::drawing::XShape >& rShape,
675  const css::uno::Reference< css::xml::sax::XAttributeList >&,
676  css::uno::Reference< css::drawing::XShapes >&)
677 {
678  /* Set property <PositionLayoutDir>
679  to <PositionInHoriL2R>, if it exists and the import states that
680  the shape positioning attributes are in horizontal left-to-right
681  layout. This is the case for the OpenOffice.org file format.
682  This setting is done for Writer documents, because the property
683  only exists at service css::text::Shape - the Writer
684  UNO service for shapes.
685  The value indicates that the positioning attributes are given
686  in horizontal left-to-right layout. The property is evaluated
687  during the first positioning of the shape in order to convert
688  the shape position given in the OpenOffice.org file format to
689  the one for the OASIS Open Office file format. (#i28749#, #i36248#)
690  */
691  uno::Reference< beans::XPropertySet > xPropSet(rShape, uno::UNO_QUERY);
692  if ( xPropSet.is() )
693  {
695  xPropSet->getPropertySetInfo()->hasPropertyByName(
696  "PositionLayoutDir") )
697  {
698  uno::Any aPosLayoutDir;
699  aPosLayoutDir <<= text::PositionLayoutDir::PositionInHoriL2R;
700  xPropSet->setPropertyValue( "PositionLayoutDir", aPosLayoutDir );
701  }
702  }
703 }
704 
705 namespace {
706 
707 // helper functions for z-order sorting
708 struct ZOrderHint
709 {
710  sal_Int32 nIs;
711  sal_Int32 nShould;
713  uno::Reference<drawing::XShape> xShape;
714 
715  bool operator<(const ZOrderHint& rComp) const { return nShould < rComp.nShould; }
716 };
717 
718 // a) handle z-order of group contents after it has been imported
719 // b) apply group events over group contents after it has been imported
720 class ShapeGroupContext
721 {
722 public:
723  uno::Reference< drawing::XShapes > mxShapes;
724  std::vector<SdXMLEventContextData> maEventData;
725  vector<ZOrderHint> maZOrderList;
726  vector<ZOrderHint> maUnsortedList;
727 
728  sal_Int32 mnCurrentZ;
729  std::shared_ptr<ShapeGroupContext> mpParentContext;
730 
731  ShapeGroupContext( uno::Reference< drawing::XShapes > const & rShapes, std::shared_ptr<ShapeGroupContext> pParentContext );
732 
733  void popGroupAndPostProcess();
734 private:
735  void moveShape( sal_Int32 nSourcePos, sal_Int32 nDestPos );
736 };
737 
738 }
739 
740 ShapeGroupContext::ShapeGroupContext( uno::Reference< drawing::XShapes > const & rShapes, std::shared_ptr<ShapeGroupContext> pParentContext )
741 : mxShapes( rShapes ), mnCurrentZ( 0 ), mpParentContext( std::move(pParentContext) )
742 {
743 }
744 
745 void ShapeGroupContext::moveShape( sal_Int32 nSourcePos, sal_Int32 nDestPos )
746 {
747  uno::Any aAny( mxShapes->getByIndex( nSourcePos ) );
748  uno::Reference< beans::XPropertySet > xPropSet;
749  aAny >>= xPropSet;
750 
751  if( !(xPropSet.is() && xPropSet->getPropertySetInfo()->hasPropertyByName( "ZOrder" )) )
752  return;
753 
754  xPropSet->setPropertyValue( "ZOrder", uno::Any(nDestPos) );
755 
756  for( ZOrderHint& rHint : maZOrderList )
757  {
758  if( rHint.nIs < nSourcePos )
759  {
760  DBG_ASSERT(rHint.nIs >= nDestPos, "Shape sorting failed" );
761  rHint.nIs++;
762  }
763  }
764 
765  for( ZOrderHint& rHint : maUnsortedList )
766  {
767  if( rHint.nIs < nSourcePos )
768  {
769  SAL_WARN_IF( rHint.nIs < nDestPos, "xmloff", "shape sorting failed" );
770  rHint.nIs++;
771  }
772  }
773 }
774 
775 // sort shapes
776 void ShapeGroupContext::popGroupAndPostProcess()
777 {
778  if (!maEventData.empty())
779  {
780  // tdf#127791 wait until a group is popped to set its event data
781  for (auto& event : maEventData)
782  event.ApplyProperties();
783  maEventData.clear();
784  }
785 
786  // only do something if we have shapes to sort
787  if( maZOrderList.empty() )
788  return;
789 
790  // check if there are more shapes than inserted with ::shapeWithZIndexAdded()
791  // This can happen if there where already shapes on the page before import
792  // Since the writer may delete some of this shapes during import, we need
793  // to do this here and not in our c'tor anymore
794 
795  // check if we have more shapes than we know of
796  sal_Int32 nCount = mxShapes->getCount();
797 
798  nCount -= maZOrderList.size();
799  nCount -= maUnsortedList.size();
800 
801  if( nCount > 0 )
802  {
803  // first update offsets of added shapes
804  for (ZOrderHint& rHint : maZOrderList)
805  rHint.nIs += nCount;
806  for (ZOrderHint& rHint : maUnsortedList)
807  rHint.nIs += nCount;
808 
809  // second add the already existing shapes in the unsorted list
810  ZOrderHint aNewHint;
811  do
812  {
813  nCount--;
814 
815  aNewHint.nIs = nCount;
816  aNewHint.nShould = -1;
817 
818  maUnsortedList.insert(maUnsortedList.begin(), aNewHint);
819  }
820  while( nCount );
821  }
822 
823  bool bSorted = std::is_sorted(maZOrderList.begin(), maZOrderList.end(),
824  [&](const ZOrderHint& rLeft, const ZOrderHint& rRight)
825  { return rLeft.nShould < rRight.nShould; } );
826 
827  if (bSorted)
828  return; // nothin' to do
829 
830  // sort z-ordered shapes by nShould field
831  std::sort(maZOrderList.begin(), maZOrderList.end());
832 
833  uno::Reference<drawing::XShapes3> xShapes3(mxShapes, uno::UNO_QUERY);
834  if( xShapes3.is())
835  {
836  uno::Sequence<sal_Int32> aNewOrder(maZOrderList.size() + maUnsortedList.size());
837  sal_Int32 nIndex = 0;
838 
839  for (ZOrderHint& rHint : maZOrderList)
840  {
841  // fill in the gaps from unordered list
842  for (vector<ZOrderHint>::iterator aIt = maUnsortedList.begin(); aIt != maUnsortedList.end() && nIndex < rHint.nShould; )
843  {
844  aNewOrder[nIndex++] = (*aIt).nIs;
845  aIt = maUnsortedList.erase(aIt);
846  }
847 
848  aNewOrder[nIndex] = rHint.nIs;
849  nIndex++;
850  }
851 
852  try
853  {
854  xShapes3->sort(aNewOrder);
855  maZOrderList.clear();
856  return;
857  }
858  catch (const css::lang::IllegalArgumentException& /*e*/)
859  {}
860  }
861 
862  // this is the current index, all shapes before that
863  // index are finished
864  sal_Int32 nIndex = 0;
865  for (const ZOrderHint& rHint : maZOrderList)
866  {
867  for (vector<ZOrderHint>::iterator aIt = maUnsortedList.begin(); aIt != maUnsortedList.end() && nIndex < rHint.nShould; )
868  {
869  moveShape( (*aIt).nIs, nIndex++ );
870  aIt = maUnsortedList.erase(aIt);
871 
872  }
873 
874  if(rHint.nIs != nIndex )
875  moveShape( rHint.nIs, nIndex );
876 
877  nIndex++;
878  }
879  maZOrderList.clear();
880 }
881 
882 void XMLShapeImportHelper::pushGroupForPostProcessing( uno::Reference< drawing::XShapes >& rShapes )
883 {
884  mpImpl->mpGroupContext = std::make_shared<ShapeGroupContext>( rShapes, mpImpl->mpGroupContext );
885 }
886 
888 {
889  if (mpImpl->mpGroupContext && mpImpl->mpGroupContext->mxShapes == rData.mxShape)
890  {
891  // tdf#127791 wait until a group is popped to set its event data so
892  // that the events are applied to all its children, which are not available
893  // at the start of the group tag
894  mpImpl->mpGroupContext->maEventData.push_back(rData);
895  }
896  else
897  rData.ApplyProperties();
898 }
899 
901 {
902  SAL_WARN_IF( !mpImpl->mpGroupContext, "xmloff", "No context to sort!" );
903  if( !mpImpl->mpGroupContext )
904  return;
905 
906  try
907  {
908  mpImpl->mpGroupContext->popGroupAndPostProcess();
909  }
910  catch( const uno::Exception& )
911  {
912  DBG_UNHANDLED_EXCEPTION("xmloff", "exception while sorting shapes, sorting failed");
913  }
914 
915  // put parent on top and drop current context, we are done
916  mpImpl->mpGroupContext = mpImpl->mpGroupContext->mpParentContext;
917 }
918 
919 void XMLShapeImportHelper::shapeWithZIndexAdded( css::uno::Reference< css::drawing::XShape > const & xShape, sal_Int32 nZIndex )
920 {
921  if( !mpImpl->mpGroupContext)
922  return;
923 
924  ZOrderHint aNewHint;
925  aNewHint.nIs = mpImpl->mpGroupContext->mnCurrentZ++;
926  aNewHint.nShould = nZIndex;
927  aNewHint.xShape = xShape;
928 
929  if( nZIndex == -1 )
930  {
931  // don't care, so add to unsorted list
932  mpImpl->mpGroupContext->maUnsortedList.push_back(aNewHint);
933  }
934  else
935  {
936  // insert into sort list
937  mpImpl->mpGroupContext->maZOrderList.push_back(aNewHint);
938  }
939 }
940 
941 void XMLShapeImportHelper::shapeRemoved(const uno::Reference<drawing::XShape>& xShape)
942 {
943  auto it = std::find_if(mpImpl->mpGroupContext->maZOrderList.begin(), mpImpl->mpGroupContext->maZOrderList.end(), [&xShape](const ZOrderHint& rHint)
944  {
945  return rHint.xShape == xShape;
946  });
947  if (it == mpImpl->mpGroupContext->maZOrderList.end())
948  // Part of the unsorted list, nothing to do.
949  return;
950 
951  sal_Int32 nZIndex = it->nIs;
952 
953  for (it = mpImpl->mpGroupContext->maZOrderList.begin(); it != mpImpl->mpGroupContext->maZOrderList.end();)
954  {
955  if (it->nIs == nZIndex)
956  {
957  // This is xShape: remove it and adjust the max of indexes
958  // accordingly.
959  it = mpImpl->mpGroupContext->maZOrderList.erase(it);
960  mpImpl->mpGroupContext->mnCurrentZ--;
961  continue;
962  }
963  else if (it->nIs > nZIndex)
964  // On top of xShape: adjust actual index to reflect removal.
965  it->nIs--;
966 
967  // On top of or below xShape.
968  ++it;
969  }
970 }
971 
972 void XMLShapeImportHelper::addShapeConnection( css::uno::Reference< css::drawing::XShape > const & rConnectorShape,
973  bool bStart,
974  const OUString& rDestShapeId,
975  sal_Int32 nDestGlueId )
976 {
977  ConnectionHint aHint;
978  aHint.mxConnector = rConnectorShape;
979  aHint.bStart = bStart;
980  aHint.aDestShapeId = rDestShapeId;
981  aHint.nDestGlueId = nDestGlueId;
982 
983  mpImpl->maConnections.push_back( aHint );
984 }
985 
987 {
988  const vector<ConnectionHint>::size_type nCount = mpImpl->maConnections.size();
989  for( vector<ConnectionHint>::size_type i = 0; i < nCount; i++ )
990  {
991  ConnectionHint& rHint = mpImpl->maConnections[i];
992  uno::Reference< beans::XPropertySet > xConnector( rHint.mxConnector, uno::UNO_QUERY );
993  if( xConnector.is() )
994  {
995  // #86637# remember line deltas
996  uno::Any aLine1Delta;
997  uno::Any aLine2Delta;
998  uno::Any aLine3Delta;
999  OUString aStr1("EdgeLine1Delta");
1000  OUString aStr2("EdgeLine2Delta");
1001  OUString aStr3("EdgeLine3Delta");
1002  aLine1Delta = xConnector->getPropertyValue(aStr1);
1003  aLine2Delta = xConnector->getPropertyValue(aStr2);
1004  aLine3Delta = xConnector->getPropertyValue(aStr3);
1005 
1006  // #86637# simply setting these values WILL force the connector to do
1007  // a new layout promptly. So the line delta values have to be rescued
1008  // and restored around connector changes.
1009  uno::Reference< drawing::XShape > xShape(
1010  mrImporter.getInterfaceToIdentifierMapper().getReference( rHint.aDestShapeId ), uno::UNO_QUERY );
1011  if( xShape.is() )
1012  {
1013  xConnector->setPropertyValue( rHint.bStart ? gsStartShape : gsEndShape, uno::Any(xShape) );
1014 
1015  sal_Int32 nGlueId = rHint.nDestGlueId < 4 ? rHint.nDestGlueId : getGluePointId( xShape, rHint.nDestGlueId );
1016  xConnector->setPropertyValue( rHint.bStart ? gsStartGluePointIndex : gsEndGluePointIndex, uno::Any(nGlueId) );
1017  }
1018 
1019  // #86637# restore line deltas
1020  xConnector->setPropertyValue(aStr1, aLine1Delta );
1021  xConnector->setPropertyValue(aStr2, aLine2Delta );
1022  xConnector->setPropertyValue(aStr3, aLine3Delta );
1023  }
1024  }
1025  mpImpl->maConnections.clear();
1026 }
1027 
1028 SvXMLImportPropertyMapper* XMLShapeImportHelper::CreateShapePropMapper( const uno::Reference< frame::XModel>& rModel, SvXMLImport& rImport )
1029 {
1031  rtl::Reference < XMLPropertySetMapper > xMapper = new XMLShapePropertySetMapper( xFactory, false );
1032  SvXMLImportPropertyMapper* pResult = new SvXMLImportPropertyMapper( xMapper, rImport );
1033 
1034  // chain text attributes
1036  return pResult;
1037 }
1038 
1041 void XMLShapeImportHelper::addGluePointMapping( css::uno::Reference< css::drawing::XShape > const & xShape,
1042  sal_Int32 nSourceId, sal_Int32 nDestinnationId )
1043 {
1044  if( mpPageContext )
1045  mpPageContext->maShapeGluePointsMap[xShape][nSourceId] = nDestinnationId;
1046 }
1047 
1049 void XMLShapeImportHelper::moveGluePointMapping( const css::uno::Reference< css::drawing::XShape >& xShape, const sal_Int32 n )
1050 {
1051  if( mpPageContext )
1052  {
1053  ShapeGluePointsMap::iterator aShapeIter( mpPageContext->maShapeGluePointsMap.find( xShape ) );
1054  if( aShapeIter != mpPageContext->maShapeGluePointsMap.end() )
1055  {
1056  for ( auto& rShapeId : (*aShapeIter).second )
1057  {
1058  if ( rShapeId.second != -1 )
1059  rShapeId.second += n;
1060  }
1061  }
1062  }
1063 }
1064 
1067 sal_Int32 XMLShapeImportHelper::getGluePointId( const css::uno::Reference< css::drawing::XShape >& xShape, sal_Int32 nSourceId )
1068 {
1069  if( mpPageContext )
1070  {
1071  ShapeGluePointsMap::iterator aShapeIter( mpPageContext->maShapeGluePointsMap.find( xShape ) );
1072  if( aShapeIter != mpPageContext->maShapeGluePointsMap.end() )
1073  {
1074  GluePointIdMap::iterator aIdIter = (*aShapeIter).second.find(nSourceId);
1075  if( aIdIter != (*aShapeIter).second.end() )
1076  return (*aIdIter).second;
1077  }
1078  }
1079 
1080  return -1;
1081 }
1082 
1084 void XMLShapeImportHelper::startPage( css::uno::Reference< css::drawing::XShapes > const & rShapes )
1085 {
1086  const std::shared_ptr<XMLShapeImportPageContextImpl> pOldContext = mpPageContext;
1087  mpPageContext = std::make_shared<XMLShapeImportPageContextImpl>();
1088  mpPageContext->mpNext = pOldContext;
1089  mpPageContext->mxShapes = rShapes;
1090 }
1091 
1093 void XMLShapeImportHelper::endPage( css::uno::Reference< css::drawing::XShapes > const & rShapes )
1094 {
1095  SAL_WARN_IF( !mpPageContext || (mpPageContext->mxShapes != rShapes), "xmloff", "wrong call to endPage(), no startPage called or wrong page" );
1096  if( nullptr == mpPageContext )
1097  return;
1098 
1100 
1101  mpPageContext = mpPageContext->mpNext;
1102 }
1103 
1106 {
1107  mpImpl->mbHandleProgressBar = true;
1108 }
1109 
1111 {
1112  return mpImpl->mbHandleProgressBar;
1113 }
1114 
1117 {
1118  return mpImpl->mbIsPresentationShapesSupported;
1119 }
1120 
1122 {
1123  if( !mxShapeTableImport.is() )
1124  {
1126  rtl::Reference< XMLPropertySetMapper > xPropertySetMapper( new XMLShapePropertySetMapper( xFactory.get(), false ) );
1127  mxShapeTableImport = new XMLTableImport( mrImporter, xPropertySetMapper, xFactory );
1128  }
1129 
1130  return mxShapeTableImport;
1131 }
1132 
1133 void SvXMLShapeContext::setHyperlink( const OUString& rHyperlink )
1134 {
1135  msHyperlink = rHyperlink;
1136 }
1137 
1138 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const SvXMLTokenMap & GetGroupShapeElemTokenMap()
sal_Int32 nIndex
css::uno::Reference< css::drawing::XShape > mxShape
Definition: eventimp.hxx:54
constexpr sal_uInt16 XML_NAMESPACE_OFFICE
bool operator<(const tSchXMLIndexWithPart &rFirst, const tSchXMLIndexWithPart &rSecond)
virtual SvXMLImportContextRef CreateChildContext(sal_uInt16 nPrefix, const OUString &rLocalName, const css::uno::Reference< css::xml::sax::XAttributeList > &xAttrList) override
Create a children element context.
Definition: ximpshap.cxx:3428
rtl::Reference< SvXMLImportPropertyMapper > mpPresPagePropsMapper
std::unique_ptr< SvXMLTokenMap > mpGroupShapeElemTokenMap
constexpr sal_uInt16 XML_NAMESPACE_CHART
constexpr sal_uInt16 XML_NAMESPACE_DR3D
const SvXMLTokenMap & Get3DSceneShapeElemTokenMap()
std::unique_ptr< SvXMLTokenMap > mp3DObjectAttrTokenMap
bool IsHandleProgressBarEnabled() const
const std::u16string_view gsStartShape(u"StartShape")
std::unique_ptr< SvXMLTokenMap > mpFrameShapeElemTokenMap
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...
virtual void processAttribute(sal_uInt16 nPrefix, const OUString &rLocalName, const OUString &rValue)
Definition: ximpshap.cxx:805
SvXMLNamespaceMap & GetNamespaceMap()
Definition: xmlimp.hxx:394
const rtl::Reference< XMLTableImport > & GetShapeTableImport()
rtl::Reference< SvXMLImportPropertyMapper > mpPropertySetMapper
const SvXMLTokenMap & Get3DPolygonBasedAttrTokenMap()
bool IsShapePositionInHoriL2R() const
Definition: xmlimp.cxx:1874
std::map< css::uno::Reference< css::drawing::XShape >, GluePointIdMap, XShapeCompareHelper > ShapeGluePointsMap
Definition: shapeimport.cxx:85
sal_uInt16 GetKeyByAttrName(const OUString &rAttrName, OUString *pPrefix, OUString *pLocalName, OUString *pNamespace) const
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
#define XML_TOKEN_MAP_END
Definition: xmltkmap.hxx:33
std::unique_ptr< SvXMLTokenMap > mp3DCubeObjectAttrTokenMap
std::shared_ptr< ShapeGroupContext > mpGroupContext
rtl::Reference< XMLTableImport > mxShapeTableImport
virtual ~XMLShapeImportHelper() override
const std::u16string_view gsEndShape(u"EndShape")
const SvXMLTokenMap & GetFrameShapeElemTokenMap()
int nCount
SvXMLShapeContext * CreateFrameChildContext(SvXMLImport &rImport, sal_uInt16 nPrefix, const OUString &rLocalName, const css::uno::Reference< css::xml::sax::XAttributeList > &xAttrList, css::uno::Reference< css::drawing::XShapes > const &rShapes, const css::uno::Reference< css::xml::sax::XAttributeList > &xFrameAttrList)
::comphelper::UnoInterfaceToUniqueIdentifierMapper & getInterfaceToIdentifierMapper()
Definition: xmlimp.cxx:1852
const SvXMLTokenMap & Get3DLightAttrTokenMap()
virtual void addShape(css::uno::Reference< css::drawing::XShape > &rShape, const css::uno::Reference< css::xml::sax::XAttributeList > &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...
rtl::Reference< SvXMLStylesContext > mxAutoStylesContext
constexpr sal_uInt16 XML_NAMESPACE_DRAW
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(...)
constexpr sal_uInt16 XML_NAMESPACE_SVG
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...
void AppendAttributeList(const css::uno::Reference< css::xml::sax::XAttributeList > &)
Definition: attrlist.cxx:167
#define DBG_ASSERT(sCon, aError)
virtual void finishShape(css::uno::Reference< css::drawing::XShape > &rShape, const css::uno::Reference< css::xml::sax::XAttributeList > &xAttrList, css::uno::Reference< css::drawing::XShapes > &rShapes)
this function is called whenever the implementation classes have finished importing a shape to the gi...
int i
std::unique_ptr< SvXMLTokenMap > mp3DSphereObjectAttrTokenMap
std::unique_ptr< SvXMLTokenMap > mp3DLightAttrTokenMap
uno_Any a
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:92
void startPage(css::uno::Reference< css::drawing::XShapes > const &rShapes)
this method must be calling before the first shape is imported for the given page.
std::unique_ptr< SvXMLTokenMap > mp3DSceneShapeElemTokenMap
static SvXMLImportPropertyMapper * CreateParaDefaultExtPropMapper(SvXMLImport &)
Definition: txtimp.cxx:1045
void addShapeEvents(SdXMLEventContextData &rData)
sal_uInt16 Get(sal_uInt16 nPrefix, const OUString &rLName) const
Definition: xmltkmap.cxx:99
const std::u16string_view gsStartGluePointIndex(u"StartGluePointIndex")
SvXMLShapeContext * Create3DSceneChildContext(SvXMLImport &rImport, sal_uInt16 nPrefix, const OUString &rLocalName, const css::uno::Reference< css::xml::sax::XAttributeList > &xAttrList, css::uno::Reference< css::drawing::XShapes > const &rShapes)
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
const SvXMLTokenMap & Get3DSphereObjectAttrTokenMap()
This class deliberately does not support XWeak, to improve performance when loading large documents...
Definition: xmlictxt.hxx:44
const std::u16string_view gsEndGluePointIndex(u"EndGluePointIndex")
void addShapeConnection(css::uno::Reference< css::drawing::XShape > const &rConnectorShape, bool bStart, const OUString &rDestShapeId, sal_Int32 nDestGlueId)
SvXMLShapeContext * CreateGroupChildContext(SvXMLImport &rImport, sal_uInt16 nPrefix, const OUString &rLocalName, const css::uno::Reference< css::xml::sax::XAttributeList > &xAttrList, css::uno::Reference< css::drawing::XShapes > const &rShapes, bool bTemporaryShape=false)
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:84
std::shared_ptr< XMLShapeImportPageContextImpl > mpNext
Definition: shapeimport.cxx:96
constexpr sal_uInt16 XML_NAMESPACE_TABLE
#define SAL_WARN_IF(condition, area, stream)
uno::Reference< drawing::XShapes > mxShapes
Definition: shapeimport.cxx:94
Handling of tokens in XML:
void SetStylesContext(SvXMLStylesContext *pNew)
rtl::Reference< XMLSdPropHdlFactory > mpSdPropHdlFactory
const css::uno::Reference< css::frame::XModel > & GetModel() const
Definition: xmlimp.hxx:400
this struct is created for each startPage() call and stores information that is needed during import ...
Definition: shapeimport.cxx:90
Reference< XSingleServiceFactory > xFactory
std::unique_ptr< SvXMLTokenMap > mp3DPolygonBasedAttrTokenMap
static SvXMLImportPropertyMapper * CreateParaExtPropMapper(SvXMLImport &)
Definition: txtimp.cxx:1038
void ChainImportMapper(const rtl::Reference< SvXMLImportPropertyMapper > &rMapper)
Definition: xmlimppr.cxx:76
this class is to enable adding members to the XMLShapeImportHelper without getting incompatible ...
const SvXMLTokenMap & Get3DObjectAttrTokenMap()
static SvXMLImportPropertyMapper * CreateShapePropMapper(const css::uno::Reference< css::frame::XModel > &rModel, SvXMLImport &rImport)
creates a property mapper for external chaining
bool IsTableShapeSupported() const
Definition: xmlimp.hxx:459
const SvXMLTokenMap & Get3DCubeObjectAttrTokenMap()