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