Branch libreoffice-5-0-4
[LibreOffice.git] / oox / source / export / shapes.cxx
blob387cd681604540aaf82fa5f9f334feaee1f7fcbe
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include <config_global.h>
23 #include <unotools/mediadescriptor.hxx>
24 #include <filter/msfilter/util.hxx>
25 #include "oox/core/xmlfilterbase.hxx"
26 #include "oox/export/shapes.hxx"
27 #include "oox/export/utils.hxx"
28 #include <oox/token/tokens.hxx>
30 #include <cstdio>
31 #include <initializer_list>
33 #include <com/sun/star/awt/CharSet.hpp>
34 #include <com/sun/star/awt/FontDescriptor.hpp>
35 #include <com/sun/star/awt/FontSlant.hpp>
36 #include <com/sun/star/awt/FontWeight.hpp>
37 #include <com/sun/star/awt/FontUnderline.hpp>
38 #include <com/sun/star/awt/Gradient.hpp>
39 #include <com/sun/star/beans/PropertyValues.hpp>
40 #include <com/sun/star/beans/XPropertySet.hpp>
41 #include <com/sun/star/beans/XPropertySetInfo.hpp>
42 #include <com/sun/star/beans/XPropertyState.hpp>
43 #include <com/sun/star/container/XEnumerationAccess.hpp>
44 #include <com/sun/star/document/XExporter.hpp>
45 #include <com/sun/star/drawing/FillStyle.hpp>
46 #include <com/sun/star/drawing/BitmapMode.hpp>
47 #include <com/sun/star/drawing/ConnectorType.hpp>
48 #include <com/sun/star/drawing/LineDash.hpp>
49 #include <com/sun/star/drawing/LineJoint.hpp>
50 #include <com/sun/star/drawing/LineStyle.hpp>
51 #include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
52 #include <com/sun/star/drawing/TextVerticalAdjust.hpp>
53 #include <com/sun/star/graphic/XGraphic.hpp>
54 #include <com/sun/star/i18n/ScriptType.hpp>
55 #include <com/sun/star/io/XOutputStream.hpp>
56 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
57 #include <com/sun/star/style/ParagraphAdjust.hpp>
58 #include <com/sun/star/text/XSimpleText.hpp>
59 #include <com/sun/star/text/XText.hpp>
60 #include <com/sun/star/text/XTextContent.hpp>
61 #include <com/sun/star/text/XTextDocument.hpp>
62 #include <com/sun/star/text/XTextField.hpp>
63 #include <com/sun/star/text/XTextRange.hpp>
64 #include <com/sun/star/table/XTable.hpp>
65 #include <com/sun/star/table/XColumnRowRange.hpp>
66 #include <com/sun/star/table/XCellRange.hpp>
67 #include <com/sun/star/table/XMergeableCell.hpp>
68 #include <com/sun/star/chart2/XChartDocument.hpp>
69 #include <com/sun/star/frame/XModel.hpp>
70 #include <com/sun/star/table/BorderLine2.hpp>
71 #include <tools/stream.hxx>
72 #include <vcl/cvtgrf.hxx>
73 #include <unotools/fontcvt.hxx>
74 #include <vcl/graph.hxx>
75 #include <vcl/outdev.hxx>
76 #include <svtools/grfmgr.hxx>
77 #include <rtl/strbuf.hxx>
78 #include <sfx2/app.hxx>
79 #include <svl/languageoptions.hxx>
80 #include <filter/msfilter/escherex.hxx>
81 #include <svx/svdoashp.hxx>
82 #include <svx/svdoole2.hxx>
83 #include <editeng/svxenum.hxx>
84 #include <svx/unoapi.hxx>
85 #include <oox/export/chartexport.hxx>
87 using namespace ::css;
88 using namespace ::css::beans;
89 using namespace ::css::uno;
90 using namespace ::css::drawing;
91 using namespace ::css::i18n;
92 using namespace ::css::table;
93 using namespace ::css::container;
94 using namespace ::css::document;
95 using namespace ::css::text;
97 using ::css::graphic::XGraphic;
98 using ::css::io::XOutputStream;
99 using ::css::lang::XComponent;
100 using ::css::chart2::XChartDocument;
101 using ::css::frame::XModel;
102 using ::css::sheet::XSpreadsheetDocument;
104 using ::oox::core::XmlFilterBase;
105 using ::sax_fastparser::FSHelperPtr;
107 #define IDS(x) OString(OStringLiteral(#x " ") + OString::number( mnShapeIdMax++ )).getStr()
109 namespace oox { namespace drawingml {
111 #define GETA(propName) \
112 GetProperty( rXPropSet, OUString(#propName))
114 #define GETAD(propName) \
115 ( GetPropertyAndState( rXPropSet, rXPropState, OUString(#propName), eState ) && eState == beans::PropertyState_DIRECT_VALUE )
117 #define GET(variable, propName) \
118 if ( GETA(propName) ) \
119 mAny >>= variable;
121 // not thread safe
122 int ShapeExport::mnEmbeddeDocumentCounter = 1;
124 ShapeExport::ShapeExport( sal_Int32 nXmlNamespace, FSHelperPtr pFS, ShapeHashMap* pShapeMap, XmlFilterBase* pFB, DocumentType eDocumentType, DMLTextExport* pTextExport )
125 : DrawingML( pFS, pFB, eDocumentType, pTextExport )
126 , mnShapeIdMax( 1 )
127 , mnPictureIdMax( 1 )
128 , mnXmlNamespace( nXmlNamespace )
129 , maFraction( 1, 576 )
130 , maMapModeSrc( MAP_100TH_MM )
131 , maMapModeDest( MAP_INCH, Point(), maFraction, maFraction )
132 , mpShapeMap( pShapeMap ? pShapeMap : &maShapeMap )
136 awt::Size ShapeExport::MapSize( const awt::Size& rSize ) const
138 Size aRetSize( OutputDevice::LogicToLogic( Size( rSize.Width, rSize.Height ), maMapModeSrc, maMapModeDest ) );
140 if ( !aRetSize.Width() )
141 aRetSize.Width()++;
142 if ( !aRetSize.Height() )
143 aRetSize.Height()++;
144 return awt::Size( aRetSize.Width(), aRetSize.Height() );
147 bool ShapeExport::NonEmptyText( Reference< XInterface > xIface )
149 Reference< XPropertySet > xPropSet( xIface, UNO_QUERY );
151 if( xPropSet.is() )
153 Reference< XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
154 if ( xPropSetInfo.is() )
156 if ( xPropSetInfo->hasPropertyByName( "IsEmptyPresentationObject" ) )
158 bool bIsEmptyPresObj = false;
159 if ( xPropSet->getPropertyValue( "IsEmptyPresentationObject" ) >>= bIsEmptyPresObj )
161 DBG(fprintf(stderr, "empty presentation object %d, props:\n", bIsEmptyPresObj));
162 if( bIsEmptyPresObj )
163 return true;
167 if ( xPropSetInfo->hasPropertyByName( "IsPresentationObject" ) )
169 bool bIsPresObj = false;
170 if ( xPropSet->getPropertyValue( "IsPresentationObject" ) >>= bIsPresObj )
172 DBG(fprintf(stderr, "presentation object %d, props:\n", bIsPresObj));
173 if( bIsPresObj )
174 return true;
180 Reference< XSimpleText > xText( xIface, UNO_QUERY );
182 if( xText.is() )
183 return xText->getString().getLength();
185 return false;
188 ShapeExport& ShapeExport::WriteBezierShape( Reference< XShape > xShape, bool bClosed )
190 DBG(fprintf(stderr, "write open bezier shape\n"));
192 FSHelperPtr pFS = GetFS();
193 pFS->startElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_sp : XML_wsp), FSEND );
195 tools::PolyPolygon aPolyPolygon = EscherPropertyContainer::GetPolyPolygon( xShape );
196 Rectangle aRect( aPolyPolygon.GetBoundRect() );
198 #if OSL_DEBUG_LEVEL > 0
199 awt::Size size = MapSize( awt::Size( aRect.GetWidth(), aRect.GetHeight() ) );
200 DBG(fprintf(stderr, "poly count %d\nsize: %d x %d", aPolyPolygon.Count(), int( size.Width ), int( size.Height )));
201 #endif
203 // non visual shape properties
204 if (GetDocumentType() != DOCUMENT_DOCX)
206 pFS->startElementNS( mnXmlNamespace, XML_nvSpPr, FSEND );
207 pFS->singleElementNS( mnXmlNamespace, XML_cNvPr,
208 XML_id, I32S( GetNewShapeID( xShape ) ),
209 XML_name, IDS( Freeform ),
210 FSEND );
212 pFS->singleElementNS( mnXmlNamespace, XML_cNvSpPr, FSEND );
213 if (GetDocumentType() != DOCUMENT_DOCX)
215 WriteNonVisualProperties( xShape );
216 pFS->endElementNS( mnXmlNamespace, XML_nvSpPr );
219 // visual shape properties
220 pFS->startElementNS( mnXmlNamespace, XML_spPr, FSEND );
221 WriteTransformation( aRect, XML_a );
222 WritePolyPolygon( aPolyPolygon );
223 Reference< XPropertySet > xProps( xShape, UNO_QUERY );
224 if( xProps.is() ) {
225 if( bClosed )
226 WriteFill( xProps );
227 WriteOutline( xProps );
230 pFS->endElementNS( mnXmlNamespace, XML_spPr );
232 // write text
233 WriteTextBox( xShape, mnXmlNamespace );
235 pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_sp : XML_wsp) );
237 return *this;
240 ShapeExport& ShapeExport::WriteClosedBezierShape( Reference< XShape > xShape )
242 return WriteBezierShape( xShape, true );
245 ShapeExport& ShapeExport::WriteOpenBezierShape( Reference< XShape > xShape )
247 return WriteBezierShape( xShape, false );
250 ShapeExport& ShapeExport::WriteGroupShape(uno::Reference<drawing::XShape> xShape)
252 FSHelperPtr pFS = GetFS();
253 bool bToplevel = !m_xParent.is();
254 if (!bToplevel)
255 mnXmlNamespace = XML_wpg;
256 pFS->startElementNS(mnXmlNamespace, (bToplevel ? XML_wgp : XML_grpSp), FSEND);
258 // non visual properties
259 pFS->singleElementNS(mnXmlNamespace, XML_cNvGrpSpPr, FSEND);
261 // visual properties
262 pFS->startElementNS(mnXmlNamespace, XML_grpSpPr, FSEND);
263 WriteShapeTransformation(xShape, XML_a);
264 pFS->endElementNS(mnXmlNamespace, XML_grpSpPr);
266 uno::Reference<drawing::XShapes> xGroupShape(xShape, uno::UNO_QUERY_THROW);
267 uno::Reference<drawing::XShape> xParent = m_xParent;
268 m_xParent = xShape;
269 for (sal_Int32 i = 0; i < xGroupShape->getCount(); ++i)
271 uno::Reference<drawing::XShape> xChild(xGroupShape->getByIndex(i), uno::UNO_QUERY_THROW);
272 sal_Int32 nSavedNamespace = mnXmlNamespace;
274 uno::Reference<lang::XServiceInfo> xServiceInfo(xChild, uno::UNO_QUERY_THROW);
275 if (xServiceInfo->supportsService("com.sun.star.drawing.GraphicObjectShape"))
276 mnXmlNamespace = XML_pic;
277 else
278 mnXmlNamespace = XML_wps;
279 WriteShape(xChild);
281 mnXmlNamespace = nSavedNamespace;
283 m_xParent = xParent;
285 pFS->endElementNS(mnXmlNamespace, (bToplevel ? XML_wgp : XML_grpSp));
286 return *this;
289 static bool lcl_IsOnBlacklist(OUString& rShapeType)
291 #if !HAVE_BROKEN_STATIC_INITILIZER_LIST
292 static
293 #endif
294 const std::initializer_list<OUStringLiteral> vBlacklist = {
295 OUStringLiteral("rectangle"),
296 OUStringLiteral("ellipse"),
297 OUStringLiteral("ring"),
298 OUStringLiteral("can"),
299 OUStringLiteral("cube"),
300 OUStringLiteral("paper"),
301 OUStringLiteral("frame"),
302 OUStringLiteral("smiley"),
303 OUStringLiteral("sun"),
304 OUStringLiteral("flower"),
305 OUStringLiteral("forbidden"),
306 OUStringLiteral("bracket-pair"),
307 OUStringLiteral("brace-pair"),
308 OUStringLiteral("col-60da8460"),
309 OUStringLiteral("col-502ad400"),
310 OUStringLiteral("quad-bevel"),
311 OUStringLiteral("cloud-callout"),
312 OUStringLiteral("line-callout-1"),
313 OUStringLiteral("line-callout-2"),
314 OUStringLiteral("line-callout-3"),
315 OUStringLiteral("paper"),
316 OUStringLiteral("vertical-scroll"),
317 OUStringLiteral("horizontal-scroll"),
318 OUStringLiteral("mso-spt34"),
319 OUStringLiteral("mso-spt75"),
320 OUStringLiteral("mso-spt164"),
321 OUStringLiteral("mso-spt180"),
322 OUStringLiteral("flowchart-process"),
323 OUStringLiteral("flowchart-alternate-process"),
324 OUStringLiteral("flowchart-decision"),
325 OUStringLiteral("flowchart-data"),
326 OUStringLiteral("flowchart-predefined-process"),
327 OUStringLiteral("flowchart-internal-storage"),
328 OUStringLiteral("flowchart-document"),
329 OUStringLiteral("flowchart-multidocument"),
330 OUStringLiteral("flowchart-terminator"),
331 OUStringLiteral("flowchart-preparation"),
332 OUStringLiteral("flowchart-manual-input"),
333 OUStringLiteral("flowchart-manual-operation"),
334 OUStringLiteral("flowchart-connector"),
335 OUStringLiteral("flowchart-off-page-connector"),
336 OUStringLiteral("flowchart-card"),
337 OUStringLiteral("flowchart-punched-tape"),
338 OUStringLiteral("flowchart-summing-junction"),
339 OUStringLiteral("flowchart-or"),
340 OUStringLiteral("flowchart-collate"),
341 OUStringLiteral("flowchart-sort"),
342 OUStringLiteral("flowchart-extract"),
343 OUStringLiteral("flowchart-merge"),
344 OUStringLiteral("flowchart-stored-data"),
345 OUStringLiteral("flowchart-delay"),
346 OUStringLiteral("flowchart-sequential-access"),
347 OUStringLiteral("flowchart-magnetic-disk"),
348 OUStringLiteral("flowchart-direct-access-storage"),
349 OUStringLiteral("flowchart-display")
352 return std::find(vBlacklist.begin(), vBlacklist.end(), rShapeType) != vBlacklist.end();
355 static bool lcl_IsOnWhitelist(OUString& rShapeType)
357 #if !HAVE_BROKEN_STATIC_INITILIZER_LIST
358 static
359 #endif
360 const std::initializer_list<OUStringLiteral> vWhitelist = {
361 OUStringLiteral("heart"),
362 OUStringLiteral("puzzle")
365 return std::find(vWhitelist.begin(), vWhitelist.end(), rShapeType) != vWhitelist.end();
369 ShapeExport& ShapeExport::WriteCustomShape( Reference< XShape > xShape )
371 DBG(fprintf(stderr, "write custom shape\n"));
373 Reference< XPropertySet > rXPropSet( xShape, UNO_QUERY );
374 bool bPredefinedHandlesUsed = true;
375 bool bHasHandles = false;
376 OUString sShapeType;
377 sal_uInt32 nMirrorFlags = 0;
378 MSO_SPT eShapeType = EscherPropertyContainer::GetCustomShapeType( xShape, nMirrorFlags, sShapeType );
379 SdrObjCustomShape* pShape = static_cast<SdrObjCustomShape*>( GetSdrObjectFromXShape( xShape ) );
380 bool bIsDefaultObject = EscherPropertyContainer::IsDefaultObject( pShape, eShapeType );
381 const char* sPresetShape = msfilter::util::GetOOXMLPresetGeometry( USS( sShapeType ) );
382 DBG(fprintf(stderr, "custom shape type: %s ==> %s\n", USS( sShapeType ), sPresetShape));
383 Sequence< PropertyValue > aGeometrySeq;
384 sal_Int32 nAdjustmentValuesIndex = -1;
386 bool bFlipH = false;
387 bool bFlipV = false;
389 if( GETA( CustomShapeGeometry ) ) {
390 DBG(fprintf(stderr, "got custom shape geometry\n"));
391 if( mAny >>= aGeometrySeq ) {
393 DBG(fprintf(stderr, "got custom shape geometry sequence\n"));
394 for( int i = 0; i < aGeometrySeq.getLength(); i++ ) {
395 const PropertyValue& rProp = aGeometrySeq[ i ];
396 DBG(fprintf(stderr, "geometry property: %s\n", USS( rProp.Name )));
398 if ( rProp.Name == "MirroredX" )
399 rProp.Value >>= bFlipH;
401 if ( rProp.Name == "MirroredY" )
402 rProp.Value >>= bFlipV;
403 if ( rProp.Name == "AdjustmentValues" )
404 nAdjustmentValuesIndex = i;
405 else if ( rProp.Name == "Handles" )
407 uno::Sequence<beans::PropertyValues> aHandles;
408 rProp.Value >>= aHandles;
409 if ( aHandles.getLength() )
410 bHasHandles = true;
411 if( !bIsDefaultObject )
412 bPredefinedHandlesUsed = false;
413 // TODO: update nAdjustmentsWhichNeedsToBeConverted here
415 else if ( rProp.Name == "PresetTextWarp" )
417 rProp.Value >>= m_presetWarp;
423 FSHelperPtr pFS = GetFS();
424 pFS->startElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_sp : XML_wsp), FSEND );
426 // non visual shape properties
427 if (GetDocumentType() != DOCUMENT_DOCX)
429 bool isVisible = true ;
430 if( GETA (Visible))
432 mAny >>= isVisible;
434 pFS->startElementNS( mnXmlNamespace, XML_nvSpPr, FSEND );
435 pFS->startElementNS( mnXmlNamespace, XML_cNvPr,
436 XML_id, I32S( GetNewShapeID( xShape ) ),
437 XML_name, IDS( CustomShape ),
438 XML_hidden, isVisible ? NULL : "1",
439 FSEND );
441 if( GETA( URL ) )
443 OUString sURL;
444 mAny >>= sURL;
445 if( !sURL.isEmpty() ) {
446 OUString sRelId = mpFB->addRelation( mpFS->getOutputStream(),
447 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
448 sURL, true );
450 mpFS->singleElementNS( XML_a, XML_hlinkClick,
451 FSNS( XML_r,XML_id ), USS( sRelId ),
452 FSEND );
455 pFS->endElementNS(mnXmlNamespace, XML_cNvPr);
456 pFS->singleElementNS( mnXmlNamespace, XML_cNvSpPr, FSEND );
457 WriteNonVisualProperties( xShape );
458 pFS->endElementNS( mnXmlNamespace, XML_nvSpPr );
460 else
461 pFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr, FSEND);
463 // visual shape properties
464 pFS->startElementNS( mnXmlNamespace, XML_spPr, FSEND );
465 // moon is flipped in MSO, and mso-spt89 (right up arrow) is mapped to leftUpArrow
466 if ( sShapeType == "moon" || sShapeType == "mso-spt89" )
467 WriteShapeTransformation( xShape, XML_a, !bFlipH, bFlipV, false);
468 else
469 WriteShapeTransformation( xShape, XML_a, bFlipH, bFlipV, false);
471 // we export non-primitive shapes to custom geometry
472 // we also export non-ooxml shapes which have handles/equations to custom geometry, because
473 // we cannot convert ODF equations to DrawingML equations. TODO: see what binary DOC export filter does.
474 // but our WritePolyPolygon() function is incomplete, therefore we use a blacklist
475 // we use a whitelist for shapes where mapping to MSO preset shape is not optimal
476 bool bCustGeom = true;
477 if( sShapeType == "ooxml-non-primitive" )
478 bCustGeom = true;
479 else if( sShapeType.startsWith("ooxml") )
480 bCustGeom = false;
481 else if( lcl_IsOnWhitelist(sShapeType) )
482 bCustGeom = true;
483 else if( lcl_IsOnBlacklist(sShapeType) )
484 bCustGeom = false;
485 else if( bHasHandles )
486 bCustGeom = true;
488 if (bHasHandles && bCustGeom && pShape)
490 WritePolyPolygon( tools::PolyPolygon( pShape->GetLineGeometry(true) ) );
492 else if (bCustGeom && pShape)
494 WriteCustomGeometry( xShape );
496 else // preset geometry
498 if( nAdjustmentValuesIndex != -1 )
500 sal_Int32 nAdjustmentsWhichNeedsToBeConverted = 0;
501 WritePresetShape( sPresetShape, eShapeType, bPredefinedHandlesUsed,
502 nAdjustmentsWhichNeedsToBeConverted, aGeometrySeq[ nAdjustmentValuesIndex ] );
504 else
505 WritePresetShape( sPresetShape );
507 if( rXPropSet.is() )
509 WriteFill( rXPropSet );
510 WriteOutline( rXPropSet );
511 WriteShapeEffects( rXPropSet );
512 WriteShape3DEffects( rXPropSet );
515 pFS->endElementNS( mnXmlNamespace, XML_spPr );
517 pFS->startElementNS( mnXmlNamespace, XML_style, FSEND );
518 WriteShapeStyle( rXPropSet );
519 pFS->endElementNS( mnXmlNamespace, XML_style );
521 // write text
522 WriteTextBox( xShape, mnXmlNamespace );
524 pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_sp : XML_wsp) );
526 return *this;
529 ShapeExport& ShapeExport::WriteEllipseShape( Reference< XShape > xShape )
531 DBG(fprintf(stderr, "write ellipse shape\n"));
533 FSHelperPtr pFS = GetFS();
535 pFS->startElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_sp : XML_wsp), FSEND );
537 // TODO: arc, section, cut, connector
539 // non visual shape properties
540 if (GetDocumentType() != DOCUMENT_DOCX)
542 pFS->startElementNS( mnXmlNamespace, XML_nvSpPr, FSEND );
543 pFS->singleElementNS( mnXmlNamespace, XML_cNvPr,
544 XML_id, I32S( GetNewShapeID( xShape ) ),
545 XML_name, IDS( Ellipse ),
546 FSEND );
547 pFS->singleElementNS( mnXmlNamespace, XML_cNvSpPr, FSEND );
548 WriteNonVisualProperties( xShape );
549 pFS->endElementNS( mnXmlNamespace, XML_nvSpPr );
551 else
552 pFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr, FSEND);
554 // visual shape properties
555 pFS->startElementNS( mnXmlNamespace, XML_spPr, FSEND );
556 WriteShapeTransformation( xShape, XML_a, false, false, false);
557 WritePresetShape( "ellipse" );
558 Reference< XPropertySet > xProps( xShape, UNO_QUERY );
559 if( xProps.is() )
561 WriteFill( xProps );
562 WriteOutline( xProps );
564 pFS->endElementNS( mnXmlNamespace, XML_spPr );
566 // write text
567 WriteTextBox( xShape, mnXmlNamespace );
569 pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_sp : XML_wsp) );
571 return *this;
574 ShapeExport& ShapeExport::WriteGraphicObjectShape( Reference< XShape > xShape )
576 WriteGraphicObjectShapePart( xShape );
578 return *this;
581 void ShapeExport::WriteGraphicObjectShapePart( Reference< XShape > xShape, const Graphic* pGraphic )
583 DBG(fprintf(stderr, "write graphic object shape\n"));
585 if( NonEmptyText( xShape ) )
587 // avoid treating all 'IsPresentationObject' objects as having text.
588 Reference< XSimpleText > xText( xShape, UNO_QUERY );
590 if( xText.is() && xText->getString().getLength() )
592 DBG(fprintf(stderr, "graphicObject: wrote only text\n"));
594 WriteTextShape( xShape );
596 //DBG(dump_pset(mXPropSet));
597 return;
601 DBG(fprintf(stderr, "graphicObject without text\n"));
603 OUString sGraphicURL;
604 Reference< XPropertySet > xShapeProps( xShape, UNO_QUERY );
605 if( !pGraphic && ( !xShapeProps.is() || !( xShapeProps->getPropertyValue( "GraphicURL" ) >>= sGraphicURL ) ) )
607 DBG(fprintf(stderr, "no graphic URL found\n"));
608 return;
611 FSHelperPtr pFS = GetFS();
613 if (GetDocumentType() != DOCUMENT_DOCX)
614 pFS->startElementNS( mnXmlNamespace, XML_pic, FSEND );
615 else
616 pFS->startElementNS( mnXmlNamespace, XML_pic,
617 FSNS(XML_xmlns, XML_pic), "http://schemas.openxmlformats.org/drawingml/2006/picture",
618 FSEND );
620 pFS->startElementNS( mnXmlNamespace, XML_nvPicPr, FSEND );
622 OUString sName, sDescr;
623 bool bHaveName, bHaveDesc;
625 if ( ( bHaveName= GetProperty( xShapeProps, "Name" ) ) )
626 mAny >>= sName;
627 if ( ( bHaveDesc = GetProperty( xShapeProps, "Description" ) ) )
628 mAny >>= sDescr;
630 pFS->singleElementNS( mnXmlNamespace, XML_cNvPr,
631 XML_id, I32S( GetNewShapeID( xShape ) ),
632 XML_name, bHaveName ? USS( sName ) : OString( "Picture " + OString::number( mnPictureIdMax++ )).getStr(),
633 XML_descr, bHaveDesc ? USS( sDescr ) : NULL,
634 FSEND );
635 // OOXTODO: //cNvPr children: XML_extLst, XML_hlinkClick, XML_hlinkHover
637 pFS->singleElementNS( mnXmlNamespace, XML_cNvPicPr,
638 // OOXTODO: XML_preferRelativeSize
639 FSEND );
641 WriteNonVisualProperties( xShape );
643 pFS->endElementNS( mnXmlNamespace, XML_nvPicPr );
645 pFS->startElementNS( mnXmlNamespace, XML_blipFill, FSEND );
647 WriteBlip( xShapeProps, sGraphicURL, false, pGraphic );
649 WriteSrcRect( xShapeProps, sGraphicURL );
651 // now we stretch always when we get pGraphic (when changing that
652 // behavior, test n#780830 for regression, where the OLE sheet might get tiled
653 bool bStretch = false;
654 if( !pGraphic && GetProperty( xShapeProps, "FillBitmapStretch" ) )
655 mAny >>= bStretch;
657 if ( pGraphic || bStretch )
658 pFS->singleElementNS( XML_a, XML_stretch, FSEND );
660 pFS->endElementNS( mnXmlNamespace, XML_blipFill );
662 // visual shape properties
663 pFS->startElementNS( mnXmlNamespace, XML_spPr, FSEND );
664 WriteShapeTransformation( xShape, XML_a, false, false, false);
665 WritePresetShape( "rect" );
666 // graphic object can come with the frame (bnc#654525)
667 WriteOutline( xShapeProps );
669 WriteShapeEffects( xShapeProps );
670 WriteShape3DEffects( xShapeProps );
672 pFS->endElementNS( mnXmlNamespace, XML_spPr );
674 pFS->endElementNS( mnXmlNamespace, XML_pic );
677 ShapeExport& ShapeExport::WriteConnectorShape( Reference< XShape > xShape )
679 bool bFlipH = false;
680 bool bFlipV = false;
682 DBG(fprintf(stderr, "write connector shape\n"));
684 FSHelperPtr pFS = GetFS();
686 const char* sGeometry = "line";
687 Reference< XPropertySet > rXPropSet( xShape, UNO_QUERY );
688 Reference< XPropertyState > rXPropState( xShape, UNO_QUERY );
689 awt::Point aStartPoint, aEndPoint;
690 Reference< XShape > rXShapeA;
691 Reference< XShape > rXShapeB;
692 PropertyState eState;
693 ConnectorType eConnectorType;
694 if( GETAD( EdgeKind ) ) {
695 mAny >>= eConnectorType;
697 switch( eConnectorType ) {
698 case ConnectorType_CURVE:
699 sGeometry = "curvedConnector3";
700 break;
701 case ConnectorType_STANDARD:
702 sGeometry = "bentConnector3";
703 break;
704 default:
705 case ConnectorType_LINE:
706 case ConnectorType_LINES:
707 sGeometry = "straightConnector1";
708 break;
711 if( GETAD( EdgeStartPoint ) ) {
712 mAny >>= aStartPoint;
713 if( GETAD( EdgeEndPoint ) ) {
714 mAny >>= aEndPoint;
717 GET( rXShapeA, EdgeStartConnection );
718 GET( rXShapeB, EdgeEndConnection );
720 EscherConnectorListEntry aConnectorEntry( xShape, aStartPoint, rXShapeA, aEndPoint, rXShapeB );
722 Rectangle aRect( Point( aStartPoint.X, aStartPoint.Y ), Point( aEndPoint.X, aEndPoint.Y ) );
723 if( aRect.getWidth() < 0 ) {
724 bFlipH = true;
725 aRect.setX( aEndPoint.X );
726 aRect.setWidth( aStartPoint.X - aEndPoint.X );
729 if( aRect.getHeight() < 0 ) {
730 bFlipV = true;
731 aRect.setY( aEndPoint.Y );
732 aRect.setHeight( aStartPoint.Y - aEndPoint.Y );
735 pFS->startElementNS( mnXmlNamespace, XML_cxnSp, FSEND );
737 // non visual shape properties
738 pFS->startElementNS( mnXmlNamespace, XML_nvCxnSpPr, FSEND );
739 pFS->singleElementNS( mnXmlNamespace, XML_cNvPr,
740 XML_id, I32S( GetNewShapeID( xShape ) ),
741 XML_name, IDS( Line ),
742 FSEND );
743 // non visual connector shape drawing properties
744 pFS->startElementNS( mnXmlNamespace, XML_cNvCxnSpPr, FSEND );
745 WriteConnectorConnections( aConnectorEntry, GetShapeID( rXShapeA ), GetShapeID( rXShapeB ) );
746 pFS->endElementNS( mnXmlNamespace, XML_cNvCxnSpPr );
747 pFS->singleElementNS( mnXmlNamespace, XML_nvPr, FSEND );
748 pFS->endElementNS( mnXmlNamespace, XML_nvCxnSpPr );
750 // visual shape properties
751 pFS->startElementNS( mnXmlNamespace, XML_spPr, FSEND );
752 WriteTransformation( aRect, XML_a, bFlipH, bFlipV );
753 // TODO: write adjustments (ppt export doesn't work well there either)
754 WritePresetShape( sGeometry );
755 Reference< XPropertySet > xShapeProps( xShape, UNO_QUERY );
756 if( xShapeProps.is() )
757 WriteOutline( xShapeProps );
758 pFS->endElementNS( mnXmlNamespace, XML_spPr );
760 // write text
761 WriteTextBox( xShape, mnXmlNamespace );
763 pFS->endElementNS( mnXmlNamespace, XML_cxnSp );
765 return *this;
768 ShapeExport& ShapeExport::WriteLineShape( Reference< XShape > xShape )
770 bool bFlipH = false;
771 bool bFlipV = false;
773 DBG(fprintf(stderr, "write line shape\n"));
775 FSHelperPtr pFS = GetFS();
777 pFS->startElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_sp : XML_wsp), FSEND );
779 tools::PolyPolygon aPolyPolygon = EscherPropertyContainer::GetPolyPolygon( xShape );
780 if( aPolyPolygon.Count() == 1 && aPolyPolygon[ 0 ].GetSize() == 2)
782 const Polygon& rPoly = aPolyPolygon[ 0 ];
784 bFlipH = ( rPoly[ 0 ].X() > rPoly[ 1 ].X() );
785 bFlipV = ( rPoly[ 0 ].Y() > rPoly[ 1 ].Y() );
788 // non visual shape properties
789 if (GetDocumentType() != DOCUMENT_DOCX)
791 pFS->startElementNS( mnXmlNamespace, XML_nvSpPr, FSEND );
792 pFS->singleElementNS( mnXmlNamespace, XML_cNvPr,
793 XML_id, I32S( GetNewShapeID( xShape ) ),
794 XML_name, IDS( Line ),
795 FSEND );
797 pFS->singleElementNS( mnXmlNamespace, XML_cNvSpPr, FSEND );
798 if (GetDocumentType() != DOCUMENT_DOCX)
800 WriteNonVisualProperties( xShape );
801 pFS->endElementNS( mnXmlNamespace, XML_nvSpPr );
804 // visual shape properties
805 pFS->startElementNS( mnXmlNamespace, XML_spPr, FSEND );
806 WriteShapeTransformation( xShape, XML_a, bFlipH, bFlipV, true);
807 WritePresetShape( "line" );
808 Reference< XPropertySet > xShapeProps( xShape, UNO_QUERY );
809 if( xShapeProps.is() )
810 WriteOutline( xShapeProps );
811 pFS->endElementNS( mnXmlNamespace, XML_spPr );
813 //write style
814 pFS->startElementNS( mnXmlNamespace, XML_style, FSEND );
815 WriteShapeStyle( xShapeProps );
816 pFS->endElementNS( mnXmlNamespace, XML_style );
818 // write text
819 WriteTextBox( xShape, mnXmlNamespace );
821 pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_sp : XML_wsp) );
823 return *this;
826 ShapeExport& ShapeExport::WriteNonVisualDrawingProperties( Reference< XShape > xShape, const char* pName )
828 GetFS()->singleElementNS( mnXmlNamespace, XML_cNvPr,
829 XML_id, I32S( GetNewShapeID( xShape ) ),
830 XML_name, pName,
831 FSEND );
833 return *this;
836 ShapeExport& ShapeExport::WriteNonVisualProperties( Reference< XShape > )
838 // Override to generate //nvPr elements.
839 return *this;
842 ShapeExport& ShapeExport::WriteRectangleShape( Reference< XShape > xShape )
844 DBG(fprintf(stderr, "write rectangle shape\n"));
846 FSHelperPtr pFS = GetFS();
848 pFS->startElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_sp : XML_wsp), FSEND );
850 sal_Int32 nRadius = 0;
852 Reference< XPropertySet > xShapeProps( xShape, UNO_QUERY );
853 if( xShapeProps.is() )
855 xShapeProps->getPropertyValue( "CornerRadius" ) >>= nRadius;
858 if( nRadius )
860 nRadius = MapSize( awt::Size( nRadius, 0 ) ).Width;
863 // non visual shape properties
864 if (GetDocumentType() == DOCUMENT_DOCX)
865 pFS->singleElementNS( mnXmlNamespace, XML_cNvSpPr, FSEND );
866 pFS->startElementNS( mnXmlNamespace, XML_nvSpPr, FSEND );
867 pFS->singleElementNS( mnXmlNamespace, XML_cNvPr,
868 XML_id, I32S( GetNewShapeID( xShape ) ),
869 XML_name, IDS( Rectangle ),
870 FSEND );
871 pFS->singleElementNS( mnXmlNamespace, XML_cNvSpPr, FSEND );
872 WriteNonVisualProperties( xShape );
873 pFS->endElementNS( mnXmlNamespace, XML_nvSpPr );
875 // visual shape properties
876 pFS->startElementNS( mnXmlNamespace, XML_spPr, FSEND );
877 WriteShapeTransformation( xShape, XML_a, false, false, false);
878 WritePresetShape( "rect" );
879 Reference< XPropertySet > xProps( xShape, UNO_QUERY );
880 if( xProps.is() )
882 WriteFill( xProps );
883 WriteOutline( xProps );
885 pFS->endElementNS( mnXmlNamespace, XML_spPr );
887 // write text
888 WriteTextBox( xShape, mnXmlNamespace );
890 pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_sp : XML_wsp) );
892 return *this;
895 typedef ShapeExport& (ShapeExport::*ShapeConverter)( Reference< XShape > );
896 typedef std::unordered_map< const char*, ShapeConverter, rtl::CStringHash, rtl::CStringEqual> NameToConvertMapType;
898 static const NameToConvertMapType& lcl_GetConverters(DrawingML::DocumentType eDocumentType)
900 static bool shape_map_inited = false;
901 static NameToConvertMapType shape_converters;
902 if( shape_map_inited )
904 return shape_converters;
907 shape_converters[ "com.sun.star.drawing.ClosedBezierShape" ] = &ShapeExport::WriteClosedBezierShape;
908 shape_converters[ "com.sun.star.drawing.ConnectorShape" ] = &ShapeExport::WriteConnectorShape;
909 shape_converters[ "com.sun.star.drawing.CustomShape" ] = &ShapeExport::WriteCustomShape;
910 shape_converters[ "com.sun.star.drawing.EllipseShape" ] = &ShapeExport::WriteEllipseShape;
911 shape_converters[ "com.sun.star.drawing.GraphicObjectShape" ] = &ShapeExport::WriteGraphicObjectShape;
912 shape_converters[ "com.sun.star.drawing.LineShape" ] = &ShapeExport::WriteLineShape;
913 shape_converters[ "com.sun.star.drawing.OpenBezierShape" ] = &ShapeExport::WriteOpenBezierShape;
914 shape_converters[ "com.sun.star.drawing.RectangleShape" ] = &ShapeExport::WriteRectangleShape;
915 shape_converters[ "com.sun.star.drawing.OLE2Shape" ] = &ShapeExport::WriteOLE2Shape;
916 shape_converters[ "com.sun.star.drawing.TableShape" ] = &ShapeExport::WriteTableShape;
917 shape_converters[ "com.sun.star.drawing.TextShape" ] = &ShapeExport::WriteTextShape;
919 shape_converters[ "com.sun.star.presentation.GraphicObjectShape" ] = &ShapeExport::WriteGraphicObjectShape;
920 shape_converters[ "com.sun.star.presentation.OLE2Shape" ] = &ShapeExport::WriteOLE2Shape;
921 shape_converters[ "com.sun.star.presentation.TableShape" ] = &ShapeExport::WriteTableShape;
922 shape_converters[ "com.sun.star.presentation.TextShape" ] = &ShapeExport::WriteTextShape;
924 shape_converters[ "com.sun.star.presentation.DateTimeShape" ] = &ShapeExport::WriteTextShape;
925 shape_converters[ "com.sun.star.presentation.FooterShape" ] = &ShapeExport::WriteTextShape;
926 shape_converters[ "com.sun.star.presentation.HeaderShape" ] = &ShapeExport::WriteTextShape;
927 shape_converters[ "com.sun.star.presentation.NotesShape" ] = &ShapeExport::WriteTextShape;
928 shape_converters[ "com.sun.star.presentation.OutlinerShape" ] = &ShapeExport::WriteTextShape;
929 shape_converters[ "com.sun.star.presentation.SlideNumberShape" ] = &ShapeExport::WriteTextShape;
930 shape_converters[ "com.sun.star.presentation.TitleTextShape" ] = &ShapeExport::WriteTextShape;
931 if (eDocumentType == DrawingML::DOCUMENT_DOCX)
932 shape_converters[ "com.sun.star.drawing.GroupShape" ] = &ShapeExport::WriteGroupShape;
933 shape_map_inited = true;
935 return shape_converters;
938 ShapeExport& ShapeExport::WriteShape( Reference< XShape > xShape )
940 OUString sShapeType = xShape->getShapeType();
941 DBG( fprintf( stderr, "write shape: %s\n", USS( sShapeType ) ) );
942 NameToConvertMapType::const_iterator aConverter = lcl_GetConverters(GetDocumentType()).find( USS( sShapeType ) );
943 if( aConverter == lcl_GetConverters(GetDocumentType()).end() )
945 DBG( fprintf( stderr, "unknown shape\n" ) );
946 return WriteUnknownShape( xShape );
948 (this->*(aConverter->second))( xShape );
950 return *this;
953 ShapeExport& ShapeExport::WriteTextBox( Reference< XInterface > xIface, sal_Int32 nXmlNamespace )
955 // In case this shape has an associated textbox, then export that, and we're done.
956 if (GetDocumentType() == DOCUMENT_DOCX && GetTextExport())
958 uno::Reference<beans::XPropertySet> xPropertySet(xIface, uno::UNO_QUERY);
959 if (xPropertySet.is())
961 uno::Reference<beans::XPropertySetInfo> xPropertySetInfo = xPropertySet->getPropertySetInfo();
962 if (xPropertySetInfo->hasPropertyByName("TextBox") && xPropertySet->getPropertyValue("TextBox").get<bool>())
964 GetTextExport()->WriteTextBox(uno::Reference<drawing::XShape>(xIface, uno::UNO_QUERY_THROW));
965 WriteText( xIface, m_presetWarp, /*bBodyPr=*/true, /*bText=*/false, /*nXmlNamespace=*/nXmlNamespace );
966 return *this;
971 if( NonEmptyText( xIface ) )
973 FSHelperPtr pFS = GetFS();
975 pFS->startElementNS( nXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_txBody : XML_txbx), FSEND );
976 WriteText( xIface, m_presetWarp, /*bBodyPr=*/(GetDocumentType() != DOCUMENT_DOCX), /*bText=*/true );
977 pFS->endElementNS( nXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_txBody : XML_txbx) );
978 if (GetDocumentType() == DOCUMENT_DOCX)
979 WriteText( xIface, m_presetWarp, /*bBodyPr=*/true, /*bText=*/false, /*nXmlNamespace=*/nXmlNamespace );
981 else if (GetDocumentType() == DOCUMENT_DOCX)
982 mpFS->singleElementNS(nXmlNamespace, XML_bodyPr, FSEND);
984 return *this;
987 void ShapeExport::WriteTable( Reference< XShape > rXShape )
989 OSL_TRACE("write table");
991 Reference< XTable > xTable;
992 Reference< XPropertySet > xPropSet( rXShape, UNO_QUERY );
994 mpFS->startElementNS( XML_a, XML_graphic, FSEND );
995 mpFS->startElementNS( XML_a, XML_graphicData, XML_uri, "http://schemas.openxmlformats.org/drawingml/2006/table", FSEND );
997 if ( xPropSet.is() && ( xPropSet->getPropertyValue( "Model" ) >>= xTable ) )
999 mpFS->startElementNS( XML_a, XML_tbl, FSEND );
1000 mpFS->singleElementNS( XML_a, XML_tblPr, FSEND );
1002 Reference< container::XIndexAccess > xColumns( xTable->getColumns(), UNO_QUERY_THROW );
1003 Reference< container::XIndexAccess > xRows( xTable->getRows(), UNO_QUERY_THROW );
1004 sal_uInt16 nRowCount = static_cast< sal_uInt16 >( xRows->getCount() );
1005 sal_uInt16 nColumnCount = static_cast< sal_uInt16 >( xColumns->getCount() );
1007 mpFS->startElementNS( XML_a, XML_tblGrid, FSEND );
1009 for ( sal_Int32 x = 0; x < nColumnCount; x++ )
1011 Reference< XPropertySet > xColPropSet( xColumns->getByIndex( x ), UNO_QUERY_THROW );
1012 sal_Int32 nWidth(0);
1013 xColPropSet->getPropertyValue( "Width" ) >>= nWidth;
1015 mpFS->singleElementNS( XML_a, XML_gridCol, XML_w, I64S(oox::drawingml::convertHmmToEmu(nWidth)), FSEND );
1018 mpFS->endElementNS( XML_a, XML_tblGrid );
1020 // map for holding the transpose index of the merged cells and pair<parentTransposeIndex, parentCell>
1021 typedef std::unordered_map<sal_Int32, std::pair<sal_Int32, Reference< XMergeableCell> > > transposeTableMap;
1022 transposeTableMap mergedCellMap;
1024 for( sal_Int32 nRow = 0; nRow < nRowCount; nRow++ )
1026 Reference< XPropertySet > xRowPropSet( xRows->getByIndex( nRow ), UNO_QUERY_THROW );
1027 sal_Int32 nRowHeight(0);
1029 xRowPropSet->getPropertyValue( "Height" ) >>= nRowHeight;
1031 mpFS->startElementNS( XML_a, XML_tr, XML_h, I64S( oox::drawingml::convertHmmToEmu( nRowHeight ) ), FSEND );
1032 for( sal_Int32 nColumn = 0; nColumn < nColumnCount; nColumn++ )
1034 Reference< XMergeableCell > xCell( xTable->getCellByPosition( nColumn, nRow ),
1035 UNO_QUERY_THROW );
1036 sal_Int32 transposedIndexofCell = (nRow * nColumnCount) + nColumn;
1038 if(xCell->getColumnSpan() > 1 && xCell->getRowSpan() > 1)
1040 // having both : horizontal and vertical merge
1041 mpFS->startElementNS(XML_a, XML_tc, XML_gridSpan,
1042 I32S(xCell->getColumnSpan()),
1043 XML_rowSpan, I32S(xCell->getRowSpan()),
1044 FSEND);
1045 // since, XMergeableCell doesn't have the information about
1046 // cell having hMerge or vMerge.
1047 // So, Populating the merged cell map in-order to use it to
1048 // decide the attribute for the individual cell.
1049 for(sal_Int32 columnIndex = nColumn; columnIndex < nColumn+xCell->getColumnSpan(); ++columnIndex)
1051 for(sal_Int32 rowIndex = nRow; rowIndex < nRow+xCell->getRowSpan(); ++rowIndex)
1053 sal_Int32 transposeIndexForMergeCell =
1054 (rowIndex * nColumnCount) + columnIndex;
1055 mergedCellMap[transposeIndexForMergeCell] =
1056 std::make_pair(transposedIndexofCell, xCell);
1061 else if(xCell->getColumnSpan() > 1)
1063 // having : horizontal merge
1064 mpFS->startElementNS(XML_a, XML_tc, XML_gridSpan,
1065 I32S(xCell->getColumnSpan()), FSEND);
1066 for(sal_Int32 columnIndex = nColumn; columnIndex < xCell->getColumnSpan(); ++columnIndex) {
1067 sal_Int32 transposeIndexForMergeCell = (nRow*nColumnCount) + columnIndex;
1068 mergedCellMap[transposeIndexForMergeCell] =
1069 std::make_pair(transposedIndexofCell, xCell);
1072 else if(xCell->getRowSpan() > 1)
1074 // having : vertical merge
1075 mpFS->startElementNS(XML_a, XML_tc, XML_rowSpan,
1076 I32S(xCell->getRowSpan()), FSEND);
1078 for(sal_Int32 rowIndex = nRow; rowIndex < xCell->getRowSpan(); ++rowIndex) {
1079 sal_Int32 transposeIndexForMergeCell = (rowIndex*nColumnCount) + nColumn;
1080 mergedCellMap[transposeIndexForMergeCell] =
1081 std::make_pair(transposedIndexofCell, xCell);
1084 else
1086 // now, the cell can be an independent cell or
1087 // it can be a cell which is been merged to some parent cell
1088 if(!xCell->isMerged())
1090 // independent cell
1091 mpFS->startElementNS( XML_a, XML_tc, FSEND );
1093 else
1095 // it a merged cell to some parent cell
1096 // find the parent cell for the current cell at hand
1097 transposeTableMap::iterator it = mergedCellMap.find(transposedIndexofCell);
1098 if(it != mergedCellMap.end())
1100 sal_Int32 transposeIndexOfParent = it->second.first;
1101 Reference< XMergeableCell > parentCell = it->second.second;
1102 // finding the row and column index for the parent cell from transposed index
1103 sal_Int32 parentColumnIndex = transposeIndexOfParent % nColumnCount;
1104 sal_Int32 parentRowIndex = transposeIndexOfParent / nColumnCount;
1105 if(nColumn == parentColumnIndex)
1107 // the cell is vertical merge and it might have gridspan
1108 if(parentCell->getColumnSpan() > 1)
1110 // vMerge and has gridSpan
1111 mpFS->startElementNS( XML_a, XML_tc,
1112 XML_vMerge, I32S(1),
1113 XML_gridSpan, I32S(xCell->getColumnSpan()),
1114 FSEND );
1116 else
1118 // only vMerge
1119 mpFS->startElementNS( XML_a, XML_tc,
1120 XML_vMerge, I32S(1), FSEND );
1123 else if(nRow == parentRowIndex)
1125 // the cell is horizontal merge and it might have rowspan
1126 if(parentCell->getRowSpan() > 1)
1128 // hMerge and has rowspan
1129 mpFS->startElementNS( XML_a, XML_tc,
1130 XML_hMerge, I32S(1),
1131 XML_rowSpan, I32S(xCell->getRowSpan()),
1132 FSEND );
1134 else
1136 // only hMerge
1137 mpFS->startElementNS( XML_a, XML_tc,
1138 XML_hMerge, I32S(1), FSEND );
1141 else
1143 // has hMerge and vMerge
1144 mpFS->startElementNS( XML_a, XML_tc,
1145 XML_vMerge, I32S(1),
1146 XML_hMerge, I32S(1),
1147 FSEND );
1152 WriteTextBox( xCell, XML_a );
1154 Reference< XPropertySet > xCellPropSet(xCell, UNO_QUERY_THROW);
1155 WriteTableCellProperties(xCellPropSet);
1157 mpFS->endElementNS( XML_a, XML_tc );
1160 mpFS->endElementNS( XML_a, XML_tr );
1163 mpFS->endElementNS( XML_a, XML_tbl );
1166 mpFS->endElementNS( XML_a, XML_graphicData );
1167 mpFS->endElementNS( XML_a, XML_graphic );
1170 void ShapeExport::WriteTableCellProperties(Reference< XPropertySet> xCellPropSet)
1172 sal_Int32 nLeftMargin(0), nRightMargin(0);
1174 Any aLeftMargin = xCellPropSet->getPropertyValue("TextLeftDistance");
1175 aLeftMargin >>= nLeftMargin;
1177 Any aRightMargin = xCellPropSet->getPropertyValue("TextRightDistance");
1178 aRightMargin >>= nRightMargin;
1180 mpFS->startElementNS( XML_a, XML_tcPr,
1181 XML_marL, nLeftMargin > 0 ? I32S( oox::drawingml::convertHmmToEmu( nLeftMargin ) ) : NULL,
1182 XML_marR, nRightMargin > 0 ? I32S( oox::drawingml::convertHmmToEmu( nRightMargin ) ): NULL,
1183 FSEND );
1185 // Write background fill for table cell.
1186 // TODO
1187 // tcW : Table cell width
1188 WriteTableCellBorders(xCellPropSet);
1189 DrawingML::WriteFill(xCellPropSet);
1190 mpFS->endElementNS( XML_a, XML_tcPr );
1193 void ShapeExport::WriteTableCellBorders(Reference< XPropertySet> xCellPropSet)
1195 BorderLine2 aBorderLine;
1197 // lnL - Left Border Line Properties of table cell
1198 xCellPropSet->getPropertyValue("LeftBorder") >>= aBorderLine;
1199 sal_Int32 nLeftBorder = aBorderLine.LineWidth;
1200 util::Color aLeftBorderColor = aBorderLine.Color;
1202 // While importing the table cell border line width, it converts EMU->Hmm then divided result by 2.
1203 // To get original value of LineWidth need to multiple by 2.
1204 nLeftBorder = nLeftBorder*2;
1205 nLeftBorder = oox::drawingml::convertHmmToEmu( nLeftBorder );
1207 if(nLeftBorder > 0)
1209 mpFS->startElementNS( XML_a, XML_lnL, XML_w, I32S(nLeftBorder), FSEND );
1210 DrawingML::WriteSolidFill(aLeftBorderColor);
1211 mpFS->endElementNS( XML_a, XML_lnL );
1214 // lnR - Right Border Line Properties of table cell
1215 xCellPropSet->getPropertyValue("RightBorder") >>= aBorderLine;
1216 sal_Int32 nRightBorder = aBorderLine.LineWidth;
1217 util::Color aRightBorderColor = aBorderLine.Color;
1218 nRightBorder = nRightBorder * 2 ;
1219 nRightBorder = oox::drawingml::convertHmmToEmu( nRightBorder );
1221 if(nRightBorder > 0)
1223 mpFS->startElementNS( XML_a, XML_lnR, XML_w, I32S(nRightBorder), FSEND);
1224 DrawingML::WriteSolidFill(aRightBorderColor);
1225 mpFS->endElementNS( XML_a, XML_lnR);
1228 // lnT - Top Border Line Properties of table cell
1229 xCellPropSet->getPropertyValue("TopBorder") >>= aBorderLine;
1230 sal_Int32 nTopBorder = aBorderLine.LineWidth;
1231 util::Color aTopBorderColor = aBorderLine.Color;
1232 nTopBorder = nTopBorder * 2;
1233 nTopBorder = oox::drawingml::convertHmmToEmu( nTopBorder );
1235 if(nTopBorder > 0)
1237 mpFS->startElementNS( XML_a, XML_lnT, XML_w, I32S(nTopBorder), FSEND);
1238 DrawingML::WriteSolidFill(aTopBorderColor);
1239 mpFS->endElementNS( XML_a, XML_lnT);
1242 // lnB - Bottom Border Line Properties of table cell
1243 xCellPropSet->getPropertyValue("BottomBorder") >>= aBorderLine;
1244 sal_Int32 nBottomBorder = aBorderLine.LineWidth;
1245 util::Color aBottomBorderColor = aBorderLine.Color;
1246 nBottomBorder = nBottomBorder * 2;
1247 nBottomBorder = oox::drawingml::convertHmmToEmu( nBottomBorder );
1249 if(nBottomBorder > 0)
1251 mpFS->startElementNS( XML_a, XML_lnB, XML_w, I32S(nBottomBorder), FSEND);
1252 DrawingML::WriteSolidFill(aBottomBorderColor);
1253 mpFS->endElementNS( XML_a, XML_lnB);
1257 ShapeExport& ShapeExport::WriteTableShape( Reference< XShape > xShape )
1259 FSHelperPtr pFS = GetFS();
1261 OSL_TRACE("write table shape");
1263 pFS->startElementNS( mnXmlNamespace, XML_graphicFrame, FSEND );
1265 pFS->startElementNS( mnXmlNamespace, XML_nvGraphicFramePr, FSEND );
1267 pFS->singleElementNS( mnXmlNamespace, XML_cNvPr,
1268 XML_id, I32S( GetNewShapeID( xShape ) ),
1269 XML_name, IDS(Table),
1270 FSEND );
1272 pFS->singleElementNS( mnXmlNamespace, XML_cNvGraphicFramePr,
1273 FSEND );
1275 if( GetDocumentType() == DOCUMENT_PPTX )
1276 pFS->singleElementNS( mnXmlNamespace, XML_nvPr,
1277 FSEND );
1278 pFS->endElementNS( mnXmlNamespace, XML_nvGraphicFramePr );
1280 WriteShapeTransformation( xShape, mnXmlNamespace, false);
1281 WriteTable( xShape );
1283 pFS->endElementNS( mnXmlNamespace, XML_graphicFrame );
1285 return *this;
1288 ShapeExport& ShapeExport::WriteTextShape( Reference< XShape > xShape )
1290 FSHelperPtr pFS = GetFS();
1292 pFS->startElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_sp : XML_wsp), FSEND );
1294 // non visual shape properties
1295 if (GetDocumentType() != DOCUMENT_DOCX)
1297 pFS->startElementNS( mnXmlNamespace, XML_nvSpPr, FSEND );
1298 WriteNonVisualDrawingProperties( xShape, IDS( TextShape ) );
1300 pFS->singleElementNS( mnXmlNamespace, XML_cNvSpPr, XML_txBox, "1", FSEND );
1301 if (GetDocumentType() != DOCUMENT_DOCX)
1303 WriteNonVisualProperties( xShape );
1304 pFS->endElementNS( mnXmlNamespace, XML_nvSpPr );
1307 // visual shape properties
1308 pFS->startElementNS( mnXmlNamespace, XML_spPr, FSEND );
1309 WriteShapeTransformation( xShape, XML_a, false, false, false);
1310 WritePresetShape( "rect" );
1311 uno::Reference<beans::XPropertySet> xPropertySet(xShape, UNO_QUERY);
1312 WriteBlipOrNormalFill(xPropertySet, "GraphicURL");
1313 WriteOutline(xPropertySet);
1314 pFS->endElementNS( mnXmlNamespace, XML_spPr );
1316 WriteTextBox( xShape, mnXmlNamespace );
1318 pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_sp : XML_wsp) );
1320 return *this;
1323 ShapeExport& ShapeExport::WriteOLE2Shape( Reference< XShape > xShape )
1325 Reference< XPropertySet > xPropSet( xShape, UNO_QUERY );
1326 if( xPropSet.is() ) {
1327 if( GetProperty( xPropSet, "Model" ) )
1329 Reference< XChartDocument > xChartDoc;
1330 mAny >>= xChartDoc;
1331 if( xChartDoc.is() )
1333 //export the chart
1334 Reference< XModel > xModel( xChartDoc, UNO_QUERY );
1335 ChartExport aChartExport( mnXmlNamespace, GetFS(), xModel, GetFB(), GetDocumentType() );
1336 static sal_Int32 nChartCount = 0;
1337 aChartExport.WriteChartObj( xShape, ++nChartCount );
1339 else
1341 const bool bSpreadSheet = Reference< XSpreadsheetDocument >( mAny, UNO_QUERY ).is();
1342 const bool bTextDocument = Reference< css::text::XTextDocument >( mAny, UNO_QUERY ).is();
1343 if( ( bSpreadSheet || bTextDocument ) && mpFB)
1345 Reference< XComponent > xDocument( mAny, UNO_QUERY );
1346 if( xDocument.is() )
1348 Reference< XOutputStream > xOutStream;
1349 if( bSpreadSheet )
1351 xOutStream = mpFB->openFragmentStream( OUStringBuffer()
1352 .appendAscii( GetComponentDir() )
1353 .appendAscii( "/embeddings/spreadsheet" )
1354 .append( static_cast<sal_Int32>(mnEmbeddeDocumentCounter) )
1355 .appendAscii( ".xlsx" )
1356 .makeStringAndClear(),
1357 "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" );
1359 else
1361 xOutStream = mpFB->openFragmentStream( OUStringBuffer()
1362 .appendAscii( GetComponentDir() )
1363 .appendAscii( "/embeddings/textdocument" )
1364 .append( static_cast<sal_Int32>(mnEmbeddeDocumentCounter) )
1365 .appendAscii( ".docx" )
1366 .makeStringAndClear(),
1367 "application/vnd.openxmlformats-officedocument.wordprocessingml.document" );
1370 // export the embedded document
1371 Sequence< PropertyValue > rMedia(1);
1373 rMedia[0].Name = utl::MediaDescriptor::PROP_STREAMFOROUTPUT();
1374 rMedia[0].Value <<= xOutStream;
1376 Reference< XExporter > xExporter;
1377 if( bSpreadSheet )
1379 xExporter.set(
1380 mpFB->getComponentContext()->getServiceManager()->
1381 createInstanceWithContext(
1382 "com.sun.star.comp.oox.xls.ExcelFilter",
1383 mpFB->getComponentContext() ),
1384 UNO_QUERY_THROW );
1386 else
1388 xExporter.set(
1389 mpFB->getComponentContext()->getServiceManager()->
1390 createInstanceWithContext(
1391 "com.sun.star.comp.Writer.WriterFilter",
1392 mpFB->getComponentContext() ),
1393 UNO_QUERY_THROW );
1396 xExporter->setSourceDocument( xDocument );
1397 Reference< XFilter >( xExporter, UNO_QUERY_THROW )->
1398 filter( rMedia );
1400 xOutStream->closeOutput();
1402 OUString sRelId;
1403 if( bSpreadSheet )
1405 sRelId = mpFB->addRelation( mpFS->getOutputStream(),
1406 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/package",
1407 OUStringBuffer()
1408 .appendAscii( GetRelationCompPrefix() )
1409 .appendAscii( "embeddings/spreadsheet" )
1410 .append( static_cast<sal_Int32>(mnEmbeddeDocumentCounter++) )
1411 .appendAscii( ".xlsx" )
1412 .makeStringAndClear() );
1414 else
1416 sRelId = mpFB->addRelation( mpFS->getOutputStream(),
1417 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/package",
1418 OUStringBuffer()
1419 .appendAscii( GetRelationCompPrefix() )
1420 .appendAscii( "embeddings/textdocument" )
1421 .append( static_cast<sal_Int32>(mnEmbeddeDocumentCounter++) )
1422 .appendAscii( ".docx" )
1423 .makeStringAndClear() );
1426 mpFS->startElementNS( mnXmlNamespace, XML_graphicFrame, FSEND );
1428 mpFS->startElementNS( mnXmlNamespace, XML_nvGraphicFramePr, FSEND );
1430 mpFS->singleElementNS( mnXmlNamespace, XML_cNvPr,
1431 XML_id, I32S( GetNewShapeID( xShape ) ),
1432 XML_name, IDS(Object),
1433 FSEND );
1435 mpFS->singleElementNS( mnXmlNamespace, XML_cNvGraphicFramePr,
1436 FSEND );
1438 if( GetDocumentType() == DOCUMENT_PPTX )
1439 mpFS->singleElementNS( mnXmlNamespace, XML_nvPr,
1440 FSEND );
1441 mpFS->endElementNS( mnXmlNamespace, XML_nvGraphicFramePr );
1443 WriteShapeTransformation( xShape, mnXmlNamespace );
1445 mpFS->startElementNS( XML_a, XML_graphic, FSEND );
1446 mpFS->startElementNS( XML_a, XML_graphicData,
1447 XML_uri, "http://schemas.openxmlformats.org/presentationml/2006/ole",
1448 FSEND );
1449 if( bSpreadSheet )
1451 mpFS->startElementNS( mnXmlNamespace, XML_oleObj,
1452 XML_name, "Spreadsheet",
1453 FSNS(XML_r, XML_id), USS( sRelId ),
1454 FSEND );
1456 else
1458 mpFS->startElementNS( mnXmlNamespace, XML_oleObj,
1459 XML_name, "Document",
1460 FSNS(XML_r, XML_id), USS( sRelId ),
1461 // The spec says that this is a required attribute, but PowerPoint can only handle an empty value.
1462 XML_spid, "",
1463 FSEND );
1466 mpFS->singleElementNS( mnXmlNamespace, XML_embed, FSEND );
1468 // pic element
1469 SdrObject* pSdrOLE2( GetSdrObjectFromXShape( xShape ) );
1470 // The spec doesn't allow <p:pic> here, but PowerPoint requires it.
1471 bool bEcma = mpFB->getVersion() == oox::core::ECMA_DIALECT;
1472 if ( pSdrOLE2 && pSdrOLE2->ISA( SdrOle2Obj ) && bEcma)
1474 const Graphic* pGraphic = static_cast<SdrOle2Obj*>(pSdrOLE2)->GetGraphic();
1475 if ( pGraphic )
1476 WriteGraphicObjectShapePart( xShape, pGraphic );
1479 mpFS->endElementNS( mnXmlNamespace, XML_oleObj );
1481 mpFS->endElementNS( XML_a, XML_graphicData );
1482 mpFS->endElementNS( XML_a, XML_graphic );
1484 mpFS->endElementNS( mnXmlNamespace, XML_graphicFrame );
1490 return *this;
1493 ShapeExport& ShapeExport::WriteUnknownShape( Reference< XShape > )
1495 // Override this method to do something useful.
1496 return *this;
1499 size_t ShapeExport::ShapeHash::operator()( const Reference < XShape > rXShape ) const
1501 return rXShape->getShapeType().hashCode();
1504 sal_Int32 ShapeExport::GetNewShapeID( const Reference< XShape > rXShape )
1506 return GetNewShapeID( rXShape, GetFB() );
1509 sal_Int32 ShapeExport::GetNewShapeID( const Reference< XShape > rXShape, XmlFilterBase* pFB )
1511 if( !rXShape.is() )
1512 return -1;
1514 sal_Int32 nID = pFB->GetUniqueId();
1516 (*mpShapeMap)[ rXShape ] = nID;
1518 return nID;
1521 sal_Int32 ShapeExport::GetShapeID( const Reference< XShape > rXShape )
1523 return GetShapeID( rXShape, mpShapeMap );
1526 sal_Int32 ShapeExport::GetShapeID( const Reference< XShape > rXShape, ShapeHashMap* pShapeMap )
1528 if( !rXShape.is() )
1529 return -1;
1531 ShapeHashMap::const_iterator aIter = pShapeMap->find( rXShape );
1533 if( aIter == pShapeMap->end() )
1534 return -1;
1536 return aIter->second;
1541 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */