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 "docxexport.hxx"
21 #include "docxexportfilter.hxx"
22 #include "docxattributeoutput.hxx"
23 #include "docxsdrexport.hxx"
24 #include "docxhelper.hxx"
25
26 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
27 #include <com/sun/star/document/XDocumentProperties.hpp>
28 #include <com/sun/star/document/XStorageBasedDocument.hpp>
29 #include <com/sun/star/drawing/XShape.hpp>
30 #include <com/sun/star/i18n/ScriptType.hpp>
31 #include <com/sun/star/frame/XModel.hpp>
32 #include <com/sun/star/xml/dom/XDocument.hpp>
33 #include <com/sun/star/xml/sax/XSAXSerializable.hpp>
34 #include <com/sun/star/xml/sax/Writer.hpp>
35 #include <com/sun/star/awt/XControlModel.hpp>
36 #include <com/sun/star/sdb/CommandType.hpp>
37
38 #include <oox/token/namespaces.hxx>
39 #include <oox/token/tokens.hxx>
40 #include <oox/export/drawingml.hxx>
41 #include <oox/export/vmlexport.hxx>
42 #include <oox/export/chartexport.hxx>
43 #include <oox/export/shapes.hxx>
44 #include <oox/helper/propertyset.hxx>
45 #include <oox/token/relationship.hxx>
46 #include <oox/helper/binaryoutputstream.hxx>
47 #include <oox/ole/olestorage.hxx>
48 #include <oox/ole/olehelper.hxx>
49
50 #include <map>
51 #include <algorithm>
52
53 #include <IMark.hxx>
54 #include <IDocumentSettingAccess.hxx>
55 #include <IDocumentLayoutAccess.hxx>
56 #include <IDocumentStylePoolAccess.hxx>
57 #include <docsh.hxx>
58 #include <ndtxt.hxx>
59 #include "wrtww8.hxx"
60 #include <fltini.hxx>
61 #include <fmtline.hxx>
62 #include <fmtpdsc.hxx>
63 #include <frmfmt.hxx>
64 #include <section.hxx>
65 #include <ftninfo.hxx>
66 #include <pagedesc.hxx>
67 #include <poolfmt.hxx>
68 #include <swdbdata.hxx>
69
70 #include <editeng/unoprnms.hxx>
71 #include <editeng/editobj.hxx>
72 #include <editeng/outlobj.hxx>
73 #include <editeng/brushitem.hxx>
74 #include <editeng/hyphenzoneitem.hxx>
75
76 #include <docary.hxx>
77 #include <numrule.hxx>
78 #include <charfmt.hxx>
79 #include <viewsh.hxx>
80 #include <viewopt.hxx>
81
82 #include "ww8par.hxx"
83 #include "ww8scan.hxx"
84 #include <oox/token/properties.hxx>
85 #include <comphelper/processfactory.hxx>
86 #include <comphelper/sequence.hxx>
87 #include <comphelper/storagehelper.hxx>
88 #include <rtl/ustrbuf.hxx>
89 #include <sal/log.hxx>
90 #include <vcl/font.hxx>
91 #include <unotools/ucbstreamhelper.hxx>
92 #include <tools/diagnose_ex.h>
93
94 using namespace sax_fastparser;
95 using namespace ::comphelper;
96 using namespace ::com::sun::star;
97 using namespace ::oox;
98
99 using oox::vml::VMLExport;
100
101 using sw::mark::IMark;
102
AttrOutput() const103 AttributeOutputBase& DocxExport::AttrOutput() const
104 {
105 return *m_pAttrOutput;
106 }
107
DocxAttrOutput() const108 DocxAttributeOutput& DocxExport::DocxAttrOutput() const
109 {
110 return *m_pAttrOutput;
111 }
112
Sections() const113 MSWordSections& DocxExport::Sections() const
114 {
115 return *m_pSections;
116 }
117
CollapseScriptsforWordOk(sal_uInt16 nScript,sal_uInt16 nWhich)118 bool DocxExport::CollapseScriptsforWordOk( sal_uInt16 nScript, sal_uInt16 nWhich )
119 {
120 // TODO FIXME is this actually true for docx? - this is ~copied from WW8
121 if ( nScript == i18n::ScriptType::ASIAN )
122 {
123 // for asian in ww8, there is only one fontsize
124 // and one fontstyle (posture/weight)
125 switch ( nWhich )
126 {
127 case RES_CHRATR_FONTSIZE:
128 case RES_CHRATR_POSTURE:
129 case RES_CHRATR_WEIGHT:
130 return false;
131 default:
132 break;
133 }
134 }
135 else if ( nScript != i18n::ScriptType::COMPLEX )
136 {
137 // for western in ww8, there is only one fontsize
138 // and one fontstyle (posture/weight)
139 switch ( nWhich )
140 {
141 case RES_CHRATR_CJK_FONTSIZE:
142 case RES_CHRATR_CJK_POSTURE:
143 case RES_CHRATR_CJK_WEIGHT:
144 return false;
145 default:
146 break;
147 }
148 }
149 return true;
150 }
151
AppendBookmarks(const SwTextNode & rNode,sal_Int32 nCurrentPos,sal_Int32 nLen)152 void DocxExport::AppendBookmarks( const SwTextNode& rNode, sal_Int32 nCurrentPos, sal_Int32 nLen )
153 {
154 std::vector< OUString > aStarts;
155 std::vector< OUString > aEnds;
156
157 IMarkVector aMarks;
158 if ( GetBookmarks( rNode, nCurrentPos, nCurrentPos + nLen, aMarks ) )
159 {
160 for ( IMark* pMark : aMarks )
161 {
162 const sal_Int32 nStart = pMark->GetMarkStart().nContent.GetIndex();
163 const sal_Int32 nEnd = pMark->GetMarkEnd().nContent.GetIndex();
164
165 if ( nStart == nCurrentPos )
166 aStarts.push_back( pMark->GetName() );
167
168 if ( nEnd == nCurrentPos )
169 aEnds.push_back( pMark->GetName() );
170 }
171 }
172
173 const OUString& aStr( rNode.GetText() );
174 const sal_Int32 nEnd = aStr.getLength();
175
176 if ( nCurrentPos == nEnd )
177 m_pAttrOutput->WriteFinalBookmarks_Impl( aStarts, aEnds );
178 else
179 m_pAttrOutput->WriteBookmarks_Impl( aStarts, aEnds );
180 }
181
AppendBookmark(const OUString & rName)182 void DocxExport::AppendBookmark( const OUString& rName )
183 {
184 std::vector< OUString > aStarts;
185 std::vector< OUString > aEnds;
186
187 aStarts.push_back( rName );
188 aEnds.push_back( rName );
189
190 m_pAttrOutput->WriteBookmarks_Impl( aStarts, aEnds );
191 }
192
AppendAnnotationMarks(const SwWW8AttrIter & rAttrs,sal_Int32 nCurrentPos,sal_Int32 nLen)193 void DocxExport::AppendAnnotationMarks( const SwWW8AttrIter& rAttrs, sal_Int32 nCurrentPos, sal_Int32 nLen )
194 {
195 std::vector< OUString > aStarts;
196 std::vector< OUString > aEnds;
197
198 IMarkVector aMarks;
199 if (GetAnnotationMarks(rAttrs, nCurrentPos, nCurrentPos + nLen, aMarks))
200 {
201 for ( IMark* pMark : aMarks )
202 {
203 const sal_Int32 nStart = pMark->GetMarkStart().nContent.GetIndex();
204 const sal_Int32 nEnd = pMark->GetMarkEnd().nContent.GetIndex();
205
206 if ( nStart == nCurrentPos )
207 aStarts.push_back( pMark->GetName() );
208
209 if ( nEnd == nCurrentPos )
210 aEnds.push_back( pMark->GetName() );
211 }
212 }
213
214 m_pAttrOutput->WriteAnnotationMarks_Impl( aStarts, aEnds );
215 }
216
ExportGrfBullet(const SwTextNode &)217 void DocxExport::ExportGrfBullet(const SwTextNode&)
218 {
219 // Just collect the bullets for now, numbering.xml is not yet started.
220 CollectGrfsOfBullets();
221 }
222
AddRelation(const OUString & rType,const OUString & rTarget)223 OString DocxExport::AddRelation( const OUString& rType, const OUString& rTarget )
224 {
225 OUString sId = m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
226 rType, rTarget, true );
227
228 return sId.toUtf8();
229 }
230
DisallowInheritingOutlineNumbering(const SwFormat & rFormat)231 bool DocxExport::DisallowInheritingOutlineNumbering( const SwFormat& rFormat )
232 {
233 bool bRet( false );
234
235 if (SfxItemState::SET != rFormat.GetItemState(RES_PARATR_NUMRULE, false))
236 {
237 if (const SwFormat *pParent = rFormat.DerivedFrom())
238 {
239 if (static_cast<const SwTextFormatColl*>(pParent)->IsAssignedToListLevelOfOutlineStyle())
240 {
241 ::sax_fastparser::FSHelperPtr pSerializer = m_pAttrOutput->GetSerializer( );
242 // Level 9 disables the outline
243 pSerializer->singleElementNS(XML_w, XML_outlineLvl, FSNS(XML_w, XML_val), "9");
244
245 bRet = true;
246 }
247 }
248 }
249
250 return bRet;
251 }
252
WriteHeadersFooters(sal_uInt8 nHeadFootFlags,const SwFrameFormat & rFormat,const SwFrameFormat & rLeftFormat,const SwFrameFormat & rFirstPageFormat,sal_uInt8 nBreakCode)253 void DocxExport::WriteHeadersFooters( sal_uInt8 nHeadFootFlags,
254 const SwFrameFormat& rFormat, const SwFrameFormat& rLeftFormat, const SwFrameFormat& rFirstPageFormat, sal_uInt8 nBreakCode )
255 {
256 m_nHeadersFootersInSection = 1;
257
258 // document setting indicating the requirement of EVEN and ODD for both headers and footers
259 if ( nHeadFootFlags & ( nsHdFtFlags::WW8_FOOTER_EVEN | nsHdFtFlags::WW8_HEADER_EVEN ))
260 m_aSettings.evenAndOddHeaders = true;
261
262 // Turn ON flag for 'Writing Headers \ Footers'
263 m_pAttrOutput->SetWritingHeaderFooter( true );
264
265 // headers
266 if ( nHeadFootFlags & nsHdFtFlags::WW8_HEADER_EVEN )
267 WriteHeaderFooter( &rLeftFormat, true, "even" );
268 else if ( m_aSettings.evenAndOddHeaders )
269 {
270 if ( nHeadFootFlags & nsHdFtFlags::WW8_HEADER_ODD )
271 WriteHeaderFooter( &rFormat, true, "even" );
272 else if ( m_bHasHdr && nBreakCode == 2 )
273 WriteHeaderFooter( nullptr, true, "even" );
274 }
275
276 if ( nHeadFootFlags & nsHdFtFlags::WW8_HEADER_ODD )
277 WriteHeaderFooter( &rFormat, true, "default" );
278
279 if ( nHeadFootFlags & nsHdFtFlags::WW8_HEADER_FIRST )
280 WriteHeaderFooter( &rFirstPageFormat, true, "first" );
281
282 if( (nHeadFootFlags & (nsHdFtFlags::WW8_HEADER_EVEN
283 | nsHdFtFlags::WW8_HEADER_ODD
284 | nsHdFtFlags::WW8_HEADER_FIRST)) == 0
285 && m_bHasHdr && nBreakCode == 2 ) // 2: nexPage
286 WriteHeaderFooter( nullptr, true, "default" );
287
288
289 // footers
290 if ( nHeadFootFlags & nsHdFtFlags::WW8_FOOTER_EVEN )
291 WriteHeaderFooter( &rLeftFormat, false, "even" );
292 else if ( m_aSettings.evenAndOddHeaders )
293 {
294 if ( nHeadFootFlags & nsHdFtFlags::WW8_FOOTER_ODD )
295 WriteHeaderFooter( &rFormat, false, "even" );
296 else if ( m_bHasFtr && nBreakCode == 2 )
297 WriteHeaderFooter( nullptr, false, "even");
298 }
299
300 if ( nHeadFootFlags & nsHdFtFlags::WW8_FOOTER_ODD )
301 WriteHeaderFooter( &rFormat, false, "default" );
302
303 if ( nHeadFootFlags & nsHdFtFlags::WW8_FOOTER_FIRST )
304 WriteHeaderFooter( &rFirstPageFormat, false, "first" );
305
306 if( (nHeadFootFlags & (nsHdFtFlags::WW8_FOOTER_EVEN
307 | nsHdFtFlags::WW8_FOOTER_ODD
308 | nsHdFtFlags::WW8_FOOTER_FIRST)) == 0
309 && m_bHasFtr && nBreakCode == 2 ) // 2: nexPage
310 WriteHeaderFooter( nullptr, false, "default");
311
312 // Turn OFF flag for 'Writing Headers \ Footers'
313 m_pAttrOutput->SetWritingHeaderFooter( false );
314 }
315
OutputField(const SwField * pField,ww::eField eFieldType,const OUString & rFieldCmd,FieldFlags nMode)316 void DocxExport::OutputField( const SwField* pField, ww::eField eFieldType, const OUString& rFieldCmd, FieldFlags nMode )
317 {
318 m_pAttrOutput->WriteField_Impl( pField, eFieldType, rFieldCmd, nMode );
319 }
320
WriteFormData(const::sw::mark::IFieldmark & rFieldmark)321 void DocxExport::WriteFormData( const ::sw::mark::IFieldmark& rFieldmark )
322 {
323 m_pAttrOutput->WriteFormData_Impl( rFieldmark );
324 }
325
WriteHyperlinkData(const::sw::mark::IFieldmark &)326 void DocxExport::WriteHyperlinkData( const ::sw::mark::IFieldmark& /*rFieldmark*/ )
327 {
328 #if OSL_DEBUG_LEVEL > 1
329 fprintf( stderr, "TODO DocxExport::WriteHyperlinkData()\n" );
330 #endif
331 }
332
DoComboBox(const OUString & rName,const OUString & rHelp,const OUString & rToolTip,const OUString & rSelected,const uno::Sequence<OUString> & rListItems)333 void DocxExport::DoComboBox(const OUString& rName,
334 const OUString& rHelp,
335 const OUString& rToolTip,
336 const OUString& rSelected,
337 const uno::Sequence<OUString>& rListItems)
338 {
339 m_pDocumentFS->startElementNS(XML_w, XML_ffData);
340
341 m_pDocumentFS->singleElementNS(XML_w, XML_name, FSNS(XML_w, XML_val), rName.toUtf8());
342
343 m_pDocumentFS->singleElementNS(XML_w, XML_enabled);
344
345 if ( !rHelp.isEmpty() )
346 m_pDocumentFS->singleElementNS(XML_w, XML_helpText, FSNS(XML_w, XML_val), rHelp.toUtf8());
347
348 if ( !rToolTip.isEmpty() )
349 m_pDocumentFS->singleElementNS( XML_w, XML_statusText,
350 FSNS( XML_w, XML_val ), rToolTip.toUtf8() );
351
352 m_pDocumentFS->startElementNS(XML_w, XML_ddList);
353
354 // Output the 0-based index of the selected value
355 sal_Int32 nId = comphelper::findValue(rListItems, rSelected);
356 if (nId == -1)
357 nId = 0;
358
359 m_pDocumentFS->singleElementNS(XML_w, XML_result, FSNS(XML_w, XML_val), OString::number(nId));
360
361 // unfortunately Word 2013 refuses to load DOCX with more than 25 listEntry
362 SAL_WARN_IF(25 < rListItems.getLength(), "sw.ww8", "DocxExport::DoComboBox data loss with more than 25 entries");
363 auto const nSize(std::min(sal_Int32(25), rListItems.getLength()));
364 for (auto i = 0; i < nSize; ++i)
365 {
366 m_pDocumentFS->singleElementNS( XML_w, XML_listEntry,
367 FSNS(XML_w, XML_val), rListItems[i].toUtf8() );
368 }
369
370 m_pDocumentFS->endElementNS( XML_w, XML_ddList );
371
372 m_pDocumentFS->endElementNS( XML_w, XML_ffData );
373 }
374
DoFormText(const SwInputField * pField)375 void DocxExport::DoFormText(const SwInputField* pField)
376 {
377 assert(pField);
378 const OUString sStr = FieldString(ww::eFILLIN) + "\"" + pField->GetPar2() + "\"";
379 OutputField(pField, ww::eFILLIN, sStr);
380 }
381
OutputChart(uno::Reference<frame::XModel> const & xModel,sal_Int32 nCount,::sax_fastparser::FSHelperPtr const & m_pSerializer)382 OString DocxExport::OutputChart( uno::Reference< frame::XModel > const & xModel, sal_Int32 nCount, ::sax_fastparser::FSHelperPtr const & m_pSerializer )
383 {
384 OUString aFileName = "charts/chart" + OUString::number(nCount) + ".xml";
385 OUString sId = m_pFilter->addRelation( m_pSerializer->getOutputStream(),
386 oox::getRelationship(Relationship::CHART),
387 aFileName );
388 aFileName = "word/charts/chart" + OUString::number(nCount) + ".xml";
389 ::sax_fastparser::FSHelperPtr pChartFS =
390 m_pFilter->openFragmentStreamWithSerializer( aFileName,
391 "application/vnd.openxmlformats-officedocument.drawingml.chart+xml" );
392
393 oox::drawingml::ChartExport aChartExport(XML_w, pChartFS, xModel, m_pFilter, oox::drawingml::DOCUMENT_DOCX);
394 aChartExport.ExportContent();
395 return OUStringToOString( sId, RTL_TEXTENCODING_UTF8 );
396 }
397
WriteOLEObject(SwOLEObj & rObject,OUString & io_rProgID)398 OString DocxExport::WriteOLEObject(SwOLEObj& rObject, OUString & io_rProgID)
399 {
400 uno::Reference <embed::XEmbeddedObject> xObj( rObject.GetOleRef() );
401 uno::Reference<uno::XComponentContext> const xContext(
402 GetFilter().getComponentContext());
403
404 OUString sMediaType;
405 OUString sRelationType;
406 OUString sSuffix;
407 const char * pProgID(nullptr);
408
409 uno::Reference<io::XInputStream> const xInStream =
410 oox::GetOLEObjectStream(xContext, xObj, io_rProgID,
411 sMediaType, sRelationType, sSuffix, pProgID);
412
413 if (!xInStream.is())
414 {
415 return OString();
416 }
417
418 assert(!sMediaType.isEmpty());
419 assert(!sRelationType.isEmpty());
420 assert(!sSuffix.isEmpty());
421 OUString sFileName = "embeddings/oleObject" + OUString::number( ++m_nOLEObjects ) + "." + sSuffix;
422 uno::Reference<io::XOutputStream> const xOutStream =
423 GetFilter().openFragmentStream("word/" + sFileName, sMediaType);
424 assert(xOutStream.is()); // no reason why that could fail
425
426 try
427 {
428 ::comphelper::OStorageHelper::CopyInputToOutput(xInStream, xOutStream);
429 }
430 catch (uno::Exception const&)
431 {
432 TOOLS_WARN_EXCEPTION("sw.ww8", "DocxExport::WriteOLEObject");
433 return OString();
434 }
435
436 OUString const sId = m_pFilter->addRelation( GetFS()->getOutputStream(),
437 sRelationType, sFileName );
438 if (pProgID)
439 {
440 io_rProgID = OUString::createFromAscii(pProgID);
441 }
442
443 return OUStringToOString( sId, RTL_TEXTENCODING_UTF8 );
444 }
445
WriteActiveXObject(const uno::Reference<drawing::XShape> & rxShape,const uno::Reference<awt::XControlModel> & rxControlModel)446 std::pair<OString, OString> DocxExport::WriteActiveXObject(const uno::Reference<drawing::XShape>& rxShape,
447 const uno::Reference<awt::XControlModel>& rxControlModel)
448 {
449 ++m_nActiveXControls;
450
451 // Write out ActiveX binary
452 const OUString sBinaryFileName = "word/activeX/activeX" + OUString::number(m_nActiveXControls) + ".bin";
453
454 OString sGUID;
455 OString sName;
456 uno::Reference<io::XStream> xOutStorage(m_pFilter->openFragmentStream(sBinaryFileName, "application/vnd.ms-office.activeX"), uno::UNO_QUERY);
457 if(xOutStorage.is())
458 {
459 oox::ole::OleStorage aOleStorage(m_pFilter->getComponentContext(), xOutStorage, false);
460 uno::Reference<io::XOutputStream> xOutputStream(aOleStorage.openOutputStream("contents"), uno::UNO_SET_THROW);
461 uno::Reference< css::frame::XModel > xModel( m_pDoc->GetDocShell() ? m_pDoc->GetDocShell()->GetModel() : nullptr );
462 oox::ole::OleFormCtrlExportHelper exportHelper(comphelper::getProcessComponentContext(), xModel, rxControlModel);
463 if ( !exportHelper.isValid() )
464 return std::make_pair<OString, OString>(OString(), OString());
465 sGUID = OUStringToOString(exportHelper.getGUID(), RTL_TEXTENCODING_UTF8);
466 sName = OUStringToOString(exportHelper.getName(), RTL_TEXTENCODING_UTF8);
467 exportHelper.exportControl(xOutputStream, rxShape->getSize(), true);
468 aOleStorage.commit();
469 }
470
471 // Write out ActiveX fragment
472 const OUString sXMLFileName = "word/activeX/activeX" + OUString::number( m_nActiveXControls ) + ".xml";
473 ::sax_fastparser::FSHelperPtr pActiveXFS = m_pFilter->openFragmentStreamWithSerializer(sXMLFileName, "application/vnd.ms-office.activeX+xml" );
474
475 const OUString sBinaryId = m_pFilter->addRelation( pActiveXFS->getOutputStream(),
476 oox::getRelationship(Relationship::ACTIVEXCONTROLBINARY),
477 sBinaryFileName.copy(sBinaryFileName.lastIndexOf("/") + 1) );
478
479 pActiveXFS->singleElementNS(XML_ax, XML_ocx,
480 FSNS(XML_xmlns, XML_ax), m_pFilter->getNamespaceURL(OOX_NS(ax)).toUtf8(),
481 FSNS(XML_xmlns, XML_r), m_pFilter->getNamespaceURL(OOX_NS(officeRel)).toUtf8(),
482 FSNS(XML_ax, XML_classid), "{" + sGUID + "}",
483 FSNS(XML_ax, XML_persistence), "persistStorage",
484 FSNS(XML_r, XML_id), sBinaryId.toUtf8());
485
486 OString sXMLId = OUStringToOString(m_pFilter->addRelation(m_pDocumentFS->getOutputStream(),
487 oox::getRelationship(Relationship::CONTROL),
488 sXMLFileName.copy(sBinaryFileName.indexOf("/") + 1)),
489 RTL_TEXTENCODING_UTF8);
490
491 return std::pair<OString, OString>(sXMLId, sName);
492 }
493
OutputDML(uno::Reference<drawing::XShape> const & xShape)494 void DocxExport::OutputDML(uno::Reference<drawing::XShape> const & xShape)
495 {
496 uno::Reference<lang::XServiceInfo> xServiceInfo(xShape, uno::UNO_QUERY_THROW);
497 sal_Int32 nNamespace = XML_wps;
498 if (xServiceInfo->supportsService("com.sun.star.drawing.GroupShape"))
499 nNamespace = XML_wpg;
500 else if (xServiceInfo->supportsService("com.sun.star.drawing.GraphicObjectShape"))
501 nNamespace = XML_pic;
502 oox::drawingml::ShapeExport aExport(nNamespace, m_pAttrOutput->GetSerializer(), nullptr, m_pFilter, oox::drawingml::DOCUMENT_DOCX, m_pAttrOutput.get());
503 aExport.WriteShape(xShape);
504 }
505
ExportDocument_Impl()506 ErrCode DocxExport::ExportDocument_Impl()
507 {
508 // Set the 'Reviewing' flags in the settings structure
509 m_aSettings.revisionView = m_bOrigShowChanges;
510 m_aSettings.trackRevisions = bool( RedlineFlags::On & m_nOrigRedlineFlags );
511
512 InitStyles();
513
514 // init sections
515 m_pSections.reset(new MSWordSections( *this ));
516
517 // Make sure images are counted from one, even when exporting multiple documents.
518 oox::drawingml::DrawingML::ResetCounters();
519
520 WriteMainText();
521
522 WriteFootnotesEndnotes();
523
524 WritePostitFields();
525
526 WriteNumbering();
527
528 WriteFonts();
529
530 WriteSettings();
531
532 WriteTheme();
533
534 WriteGlossary();
535
536 WriteCustomXml();
537
538 WriteEmbeddings();
539
540 WriteVBA();
541
542 m_aLinkedTextboxesHelper.clear(); //final cleanup
543 m_pStyles.reset();
544 m_pSections.reset();
545
546 return ERRCODE_NONE;
547 }
548
AppendSection(const SwPageDesc * pPageDesc,const SwSectionFormat * pFormat,sal_uLong nLnNum)549 void DocxExport::AppendSection( const SwPageDesc *pPageDesc, const SwSectionFormat* pFormat, sal_uLong nLnNum )
550 {
551 AttrOutput().SectionBreak( msword::PageBreak, false, m_pSections->CurrentSectionInfo() );
552 m_pSections->AppendSection( pPageDesc, pFormat, nLnNum, m_pAttrOutput->IsFirstParagraph() );
553 }
554
OutputEndNode(const SwEndNode & rEndNode)555 void DocxExport::OutputEndNode( const SwEndNode& rEndNode )
556 {
557 MSWordExportBase::OutputEndNode( rEndNode );
558
559 if ( TXT_MAINTEXT == m_nTextTyp && rEndNode.StartOfSectionNode()->IsSectionNode() )
560 {
561 // this originally comes from WW8Export::WriteText(), and looks like it
562 // could have some code common with SectionNode()...
563
564 const SwSection& rSect = rEndNode.StartOfSectionNode()->GetSectionNode()->GetSection();
565 if ( m_bStartTOX && TOX_CONTENT_SECTION == rSect.GetType() )
566 m_bStartTOX = false;
567
568 SwNodeIndex aIdx( rEndNode, 1 );
569 const SwNode& rNd = aIdx.GetNode();
570 if ( rNd.IsEndNode() && rNd.StartOfSectionNode()->IsSectionNode() )
571 return;
572
573 bool isInTable = IsInTable();
574 if ( !rNd.IsSectionNode() && isInTable ) // No sections in table
575 {
576 const SwSectionFormat* pParentFormat = rSect.GetFormat()->GetParent();
577 if( !pParentFormat )
578 pParentFormat = reinterpret_cast<SwSectionFormat*>(sal_IntPtr(-1));
579
580 sal_uLong nRstLnNum;
581 if( rNd.IsContentNode() )
582 nRstLnNum = rNd.GetContentNode()->GetSwAttrSet().GetLineNumber().GetStartValue();
583 else
584 nRstLnNum = 0;
585
586 AppendSection( m_pCurrentPageDesc, pParentFormat, nRstLnNum );
587 }
588 else
589 {
590 AttrOutput().SectionBreaks( rEndNode );
591 }
592 }
593 else if (TXT_MAINTEXT == m_nTextTyp && rEndNode.StartOfSectionNode()->IsTableNode())
594 // End node of a table: see if a section break should be written after the table.
595 AttrOutput().SectionBreaks(rEndNode);
596 }
597
OutputGrfNode(const SwGrfNode &)598 void DocxExport::OutputGrfNode( const SwGrfNode& )
599 {
600 SAL_INFO("sw.ww8", "TODO DocxExport::OutputGrfNode( const SwGrfNode& )" );
601 }
602
OutputOLENode(const SwOLENode &)603 void DocxExport::OutputOLENode( const SwOLENode& )
604 {
605 SAL_INFO("sw.ww8", "TODO DocxExport::OutputOLENode( const SwOLENode& )" );
606 }
607
OutputLinkedOLE(const OUString &)608 void DocxExport::OutputLinkedOLE( const OUString& )
609 {
610 // Nothing to implement here: WW8 only
611 }
612
ReplaceCr(sal_uInt8)613 sal_uLong DocxExport::ReplaceCr( sal_uInt8 )
614 {
615 // Completely unused for Docx export... only here for code sharing
616 // purpose with binary export
617 return 0;
618 }
619
PrepareNewPageDesc(const SfxItemSet * pSet,const SwNode & rNd,const SwFormatPageDesc * pNewPgDescFormat,const SwPageDesc * pNewPgDesc)620 void DocxExport::PrepareNewPageDesc( const SfxItemSet* pSet,
621 const SwNode& rNd, const SwFormatPageDesc* pNewPgDescFormat,
622 const SwPageDesc* pNewPgDesc )
623 {
624 // tell the attribute output that we are ready to write the section
625 // break [has to be output inside paragraph properties]
626 AttrOutput().SectionBreak( msword::PageBreak, false, m_pSections->CurrentSectionInfo() );
627
628 const SwSectionFormat* pFormat = GetSectionFormat( rNd );
629 const sal_uLong nLnNm = GetSectionLineNo( pSet, rNd );
630
631 OSL_ENSURE( pNewPgDescFormat || pNewPgDesc, "Neither page desc format nor page desc provided." );
632
633 if ( pNewPgDescFormat )
634 {
635 m_pSections->AppendSection( *pNewPgDescFormat, rNd, pFormat, nLnNm );
636 }
637 else if ( pNewPgDesc )
638 {
639 m_pSections->AppendSection( pNewPgDesc, rNd, pFormat, nLnNm );
640 }
641
642 }
643
InitStyles()644 void DocxExport::InitStyles()
645 {
646 m_pStyles.reset(new MSWordStyles( *this, /*bListStyles =*/ true ));
647
648 // setup word/styles.xml and the relations + content type
649 m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
650 oox::getRelationship(Relationship::STYLES),
651 "styles.xml" );
652
653 ::sax_fastparser::FSHelperPtr pStylesFS =
654 m_pFilter->openFragmentStreamWithSerializer( "word/styles.xml",
655 "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml" );
656
657 // switch the serializer to redirect the output to word/styles.xml
658 m_pAttrOutput->SetSerializer( pStylesFS );
659
660 // do the work
661 m_pStyles->OutputStylesTable();
662
663 // switch the serializer back
664 m_pAttrOutput->SetSerializer( m_pDocumentFS );
665 }
666
WriteFootnotesEndnotes()667 void DocxExport::WriteFootnotesEndnotes()
668 {
669 if ( m_pAttrOutput->HasFootnotes() )
670 {
671 // setup word/styles.xml and the relations + content type
672 m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
673 oox::getRelationship(Relationship::FOOTNOTES),
674 "footnotes.xml" );
675
676 ::sax_fastparser::FSHelperPtr pFootnotesFS =
677 m_pFilter->openFragmentStreamWithSerializer( "word/footnotes.xml",
678 "application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml" );
679
680 // switch the serializer to redirect the output to word/footnotes.xml
681 m_pAttrOutput->SetSerializer( pFootnotesFS );
682 // tdf#99227
683 m_pSdrExport->setSerializer( pFootnotesFS );
684 // tdf#107969
685 m_pVMLExport->SetFS(pFootnotesFS);
686
687 // do the work
688 m_pAttrOutput->FootnotesEndnotes( true );
689
690 // switch the serializer back
691 m_pVMLExport->SetFS(m_pDocumentFS);
692 m_pSdrExport->setSerializer( m_pDocumentFS );
693 m_pAttrOutput->SetSerializer( m_pDocumentFS );
694 }
695
696 if ( m_pAttrOutput->HasEndnotes() )
697 {
698 // setup word/styles.xml and the relations + content type
699 m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
700 oox::getRelationship(Relationship::ENDNOTES),
701 "endnotes.xml" );
702
703 ::sax_fastparser::FSHelperPtr pEndnotesFS =
704 m_pFilter->openFragmentStreamWithSerializer( "word/endnotes.xml",
705 "application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml" );
706
707 // switch the serializer to redirect the output to word/endnotes.xml
708 m_pAttrOutput->SetSerializer( pEndnotesFS );
709 // tdf#99227
710 m_pSdrExport->setSerializer( pEndnotesFS );
711 // tdf#107969
712 m_pVMLExport->SetFS(pEndnotesFS);
713
714 // do the work
715 m_pAttrOutput->FootnotesEndnotes( false );
716
717 // switch the serializer back
718 m_pVMLExport->SetFS(m_pDocumentFS);
719 m_pSdrExport->setSerializer( m_pDocumentFS );
720 m_pAttrOutput->SetSerializer( m_pDocumentFS );
721 }
722 }
723
WritePostitFields()724 void DocxExport::WritePostitFields()
725 {
726 if ( m_pAttrOutput->HasPostitFields() )
727 {
728 m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
729 oox::getRelationship(Relationship::COMMENTS),
730 "comments.xml" );
731
732 ::sax_fastparser::FSHelperPtr pPostitFS =
733 m_pFilter->openFragmentStreamWithSerializer( "word/comments.xml",
734 "application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml" );
735
736 pPostitFS->startElementNS( XML_w, XML_comments, MainXmlNamespaces());
737 m_pAttrOutput->SetSerializer( pPostitFS );
738 m_pAttrOutput->WritePostitFields();
739 m_pAttrOutput->SetSerializer( m_pDocumentFS );
740 pPostitFS->endElementNS( XML_w, XML_comments );
741 }
742 }
743
WriteNumbering()744 void DocxExport::WriteNumbering()
745 {
746 if ( !m_pUsedNumTable )
747 return; // no numbering is used
748
749 m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
750 oox::getRelationship(Relationship::NUMBERING),
751 "numbering.xml" );
752
753 ::sax_fastparser::FSHelperPtr pNumberingFS = m_pFilter->openFragmentStreamWithSerializer( "word/numbering.xml",
754 "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml" );
755
756 // switch the serializer to redirect the output to word/numbering.xml
757 m_pAttrOutput->SetSerializer( pNumberingFS );
758 m_pDrawingML->SetFS( pNumberingFS );
759
760 pNumberingFS->startElementNS( XML_w, XML_numbering,
761 FSNS( XML_xmlns, XML_w ), m_pFilter->getNamespaceURL(OOX_NS(doc)).toUtf8(),
762 FSNS( XML_xmlns, XML_o ), m_pFilter->getNamespaceURL(OOX_NS(vmlOffice)).toUtf8(),
763 FSNS( XML_xmlns, XML_r ), m_pFilter->getNamespaceURL(OOX_NS(officeRel)).toUtf8(),
764 FSNS( XML_xmlns, XML_v ), m_pFilter->getNamespaceURL(OOX_NS(vml)).toUtf8() );
765
766 BulletDefinitions();
767
768 AbstractNumberingDefinitions();
769
770 NumberingDefinitions();
771
772 pNumberingFS->endElementNS( XML_w, XML_numbering );
773
774 // switch the serializer back
775 m_pDrawingML->SetFS( m_pDocumentFS );
776 m_pAttrOutput->SetSerializer( m_pDocumentFS );
777 }
778
WriteHeaderFooter(const SwFormat * pFormat,bool bHeader,const char * pType)779 void DocxExport::WriteHeaderFooter( const SwFormat* pFormat, bool bHeader, const char* pType )
780 {
781 // setup the xml stream
782 OUString aRelId;
783 ::sax_fastparser::FSHelperPtr pFS;
784 if ( bHeader )
785 {
786 OUString aName( "header" + OUString::number( ++m_nHeaders ) + ".xml" );
787
788 aRelId = m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
789 oox::getRelationship(Relationship::HEADER),
790 aName );
791
792 pFS = m_pFilter->openFragmentStreamWithSerializer( "word/" + aName,
793 "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml" );
794
795 pFS->startElementNS( XML_w, XML_hdr, MainXmlNamespaces());
796 }
797 else
798 {
799 OUString aName( "footer" + OUString::number( ++m_nFooters ) + ".xml" );
800
801 aRelId = m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
802 oox::getRelationship(Relationship::FOOTER),
803 aName );
804
805 pFS = m_pFilter->openFragmentStreamWithSerializer( "word/" + aName,
806 "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml" );
807
808 pFS->startElementNS( XML_w, XML_ftr, MainXmlNamespaces());
809 }
810
811 // switch the serializer to redirect the output to word/styles.xml
812 m_pAttrOutput->SetSerializer( pFS );
813 m_pVMLExport->SetFS( pFS );
814 m_pSdrExport->setSerializer(pFS);
815 SetFS( pFS );
816 {
817 DocxTableExportContext aTableExportContext(*m_pAttrOutput);
818 //When the stream changes the cache which is maintained for the graphics in case of alternate content is not cleared.
819 //So clearing the alternate content graphic cache.
820 m_pAttrOutput->PushRelIdCache();
821 // do the work
822 if (pFormat == nullptr)
823 AttrOutput().EmptyParagraph();
824 else
825 WriteHeaderFooterText(*pFormat, bHeader);
826 m_pAttrOutput->PopRelIdCache();
827 m_pAttrOutput->EndParaSdtBlock();
828 }
829
830 // switch the serializer back
831 m_pAttrOutput->SetSerializer( m_pDocumentFS );
832 m_pVMLExport->SetFS( m_pDocumentFS );
833 m_pSdrExport->setSerializer(m_pDocumentFS);
834 SetFS( m_pDocumentFS );
835
836 // close the tag
837 sal_Int32 nReference;
838 if ( bHeader )
839 {
840 pFS->endElementNS( XML_w, XML_hdr );
841 nReference = XML_headerReference;
842 }
843 else
844 {
845 pFS->endElementNS( XML_w, XML_ftr );
846 nReference = XML_footerReference;
847 }
848
849 // and write the reference
850 m_pDocumentFS->singleElementNS( XML_w, nReference,
851 FSNS( XML_w, XML_type ), pType,
852 FSNS( XML_r, XML_id ), aRelId.toUtf8() );
853 }
854
WriteFonts()855 void DocxExport::WriteFonts()
856 {
857 m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
858 oox::getRelationship(Relationship::FONTTABLE),
859 "fontTable.xml" );
860
861 ::sax_fastparser::FSHelperPtr pFS = m_pFilter->openFragmentStreamWithSerializer(
862 "word/fontTable.xml",
863 "application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml" );
864
865 pFS->startElementNS( XML_w, XML_fonts,
866 FSNS( XML_xmlns, XML_w ), m_pFilter->getNamespaceURL(OOX_NS(doc)).toUtf8(),
867 FSNS( XML_xmlns, XML_r ), m_pFilter->getNamespaceURL(OOX_NS(officeRel)).toUtf8() );
868
869 // switch the serializer to redirect the output to word/styles.xml
870 m_pAttrOutput->SetSerializer( pFS );
871
872 // do the work
873 m_aFontHelper.WriteFontTable( *m_pAttrOutput );
874
875 // switch the serializer back
876 m_pAttrOutput->SetSerializer( m_pDocumentFS );
877
878 pFS->endElementNS( XML_w, XML_fonts );
879 }
880
WriteProperties()881 void DocxExport::WriteProperties( )
882 {
883 // Write the core properties
884 SwDocShell* pDocShell( m_pDoc->GetDocShell( ) );
885 uno::Reference<document::XDocumentProperties> xDocProps;
886 bool bSecurityOptOpenReadOnly = false;
887 if ( pDocShell )
888 {
889 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
890 pDocShell->GetModel( ), uno::UNO_QUERY );
891 xDocProps = xDPS->getDocumentProperties();
892 bSecurityOptOpenReadOnly = pDocShell->IsSecurityOptOpenReadOnly();
893 }
894
895 m_pFilter->exportDocumentProperties( xDocProps, bSecurityOptOpenReadOnly );
896 }
897
WriteSettings()898 void DocxExport::WriteSettings()
899 {
900 SwViewShell *pViewShell(m_pDoc->getIDocumentLayoutAccess().GetCurrentViewShell());
901 if( !pViewShell && !m_aSettings.hasData() && !m_pAttrOutput->HasFootnotes() && !m_pAttrOutput->HasEndnotes())
902 return;
903
904 m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
905 oox::getRelationship(Relationship::SETTINGS),
906 "settings.xml" );
907
908 ::sax_fastparser::FSHelperPtr pFS = m_pFilter->openFragmentStreamWithSerializer(
909 "word/settings.xml",
910 "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml" );
911
912 pFS->startElementNS( XML_w, XML_settings,
913 FSNS( XML_xmlns, XML_w ), m_pFilter->getNamespaceURL(OOX_NS(doc)).toUtf8() );
914
915 // View
916 if (pViewShell && pViewShell->GetViewOptions()->getBrowseMode())
917 {
918 pFS->singleElementNS(XML_w, XML_view, FSNS(XML_w, XML_val), "web");
919 }
920
921 // Zoom
922 if (pViewShell)
923 {
924 rtl::Reference<sax_fastparser::FastAttributeList> pAttributeList(
925 sax_fastparser::FastSerializerHelper::createAttrList());
926
927 switch (pViewShell->GetViewOptions()->GetZoomType())
928 {
929 case SvxZoomType::WHOLEPAGE:
930 pAttributeList->add(FSNS(XML_w, XML_val), "fullPage");
931 break;
932 case SvxZoomType::PAGEWIDTH:
933 pAttributeList->add(FSNS(XML_w, XML_val), "bestFit");
934 break;
935 case SvxZoomType::OPTIMAL:
936 pAttributeList->add(FSNS(XML_w, XML_val), "textFit");
937 break;
938 default:
939 break;
940 }
941
942 OString aZoom(OString::number(pViewShell->GetViewOptions()->GetZoom()));
943 pAttributeList->add(FSNS(XML_w, XML_percent), aZoom);
944 sax_fastparser::XFastAttributeListRef xAttributeList(pAttributeList.get());
945 pFS->singleElementNS(XML_w, XML_zoom, xAttributeList);
946 }
947
948 // Display Background Shape
949 if (std::shared_ptr<SvxBrushItem> oBrush = getBackground(); oBrush)
950 {
951 // Turn on the 'displayBackgroundShape'
952 pFS->singleElementNS(XML_w, XML_displayBackgroundShape);
953 }
954
955 // Track Changes
956 if ( !m_aSettings.revisionView )
957 pFS->singleElementNS( XML_w, XML_revisionView,
958 FSNS( XML_w, XML_insDel ), "0",
959 FSNS( XML_w, XML_formatting ), "0" );
960
961 if ( m_aSettings.trackRevisions )
962 pFS->singleElementNS(XML_w, XML_trackRevisions);
963
964 // Mirror Margins
965 if(isMirroredMargin())
966 pFS->singleElementNS(XML_w, XML_mirrorMargins);
967
968 // Embed Fonts
969 if( m_pDoc->getIDocumentSettingAccess().get( DocumentSettingId::EMBED_FONTS ))
970 pFS->singleElementNS(XML_w, XML_embedTrueTypeFonts);
971
972 // Embed System Fonts
973 if( m_pDoc->getIDocumentSettingAccess().get( DocumentSettingId::EMBED_SYSTEM_FONTS ))
974 pFS->singleElementNS(XML_w, XML_embedSystemFonts);
975
976 // Default Tab Stop
977 if( m_aSettings.defaultTabStop != 0 )
978 pFS->singleElementNS( XML_w, XML_defaultTabStop, FSNS( XML_w, XML_val ),
979 OString::number(m_aSettings.defaultTabStop) );
980
981 // Do not justify lines with manual break
982 if( m_pDoc->getIDocumentSettingAccess().get( DocumentSettingId::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK ))
983 {
984 pFS->startElementNS(XML_w, XML_compat);
985 pFS->singleElementNS(XML_w, XML_doNotExpandShiftReturn);
986 pFS->endElementNS( XML_w, XML_compat );
987 }
988
989 // export current mail merge database and table names
990 SwDBData aData = m_pDoc->GetDBData();
991 if ( !aData.sDataSource.isEmpty() && aData.nCommandType == css::sdb::CommandType::TABLE && !aData.sCommand.isEmpty() )
992 {
993 OUString sDataSource =
994 "SELECT * FROM " +
995 aData.sDataSource + // current database
996 ".dbo." + // default database owner
997 aData.sCommand + // sheet name
998 "$"; // sheet identifier
999 pFS->startElementNS( XML_w, XML_mailMerge );
1000 pFS->singleElementNS(XML_w, XML_mainDocumentType,
1001 FSNS( XML_w, XML_val ), "formLetters" );
1002 pFS->singleElementNS(XML_w, XML_dataType,
1003 FSNS( XML_w, XML_val ), "textFile" );
1004 pFS->singleElementNS( XML_w, XML_query,
1005 FSNS( XML_w, XML_val ), OUStringToOString( sDataSource, RTL_TEXTENCODING_UTF8 ).getStr() );
1006 pFS->endElementNS( XML_w, XML_mailMerge );
1007 }
1008
1009 // Automatic hyphenation: it's a global setting in Word, it's a paragraph setting in Writer.
1010 // Set it's value to "auto" and disable on paragraph level, if no hyphenation is used there.
1011 pFS->singleElementNS(XML_w, XML_autoHyphenation, FSNS(XML_w, XML_val), "true");
1012
1013 // Hyphenation details set depending on default style
1014 SwTextFormatColl* pColl = m_pDoc->getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD, /*bRegardLanguage=*/false);
1015 const SfxPoolItem* pItem;
1016 if (pColl && SfxItemState::SET == pColl->GetItemState(RES_PARATR_HYPHENZONE, false, &pItem))
1017 {
1018 if (static_cast<const SvxHyphenZoneItem*>(pItem)->IsNoCapsHyphenation())
1019 pFS->singleElementNS(XML_w, XML_doNotHyphenateCaps);
1020 }
1021
1022 // Even and Odd Headers
1023 if( m_aSettings.evenAndOddHeaders )
1024 pFS->singleElementNS(XML_w, XML_evenAndOddHeaders);
1025
1026 // Has Footnotes
1027 if( m_pAttrOutput->HasFootnotes())
1028 DocxAttributeOutput::WriteFootnoteEndnotePr( pFS, XML_footnotePr, m_pDoc->GetFootnoteInfo(), XML_footnote );
1029
1030 // Has Endnotes
1031 if( m_pAttrOutput->HasEndnotes())
1032 DocxAttributeOutput::WriteFootnoteEndnotePr( pFS, XML_endnotePr, m_pDoc->GetEndNoteInfo(), XML_endnote );
1033
1034 // Has themeFontLang information
1035 uno::Reference< beans::XPropertySet > xPropSet( m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
1036
1037 bool hasProtectionProperties = false;
1038 bool bHasRedlineProtectionKey = false;
1039 bool bHasDummyRedlineProtectionKey = false;
1040 uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
1041 if ( xPropSetInfo->hasPropertyByName( "RedlineProtectionKey" ) )
1042 {
1043 uno::Sequence<sal_Int8> aKey;
1044 xPropSet->getPropertyValue( "RedlineProtectionKey" ) >>= aKey;
1045 bHasRedlineProtectionKey = aKey.hasElements();
1046 bHasDummyRedlineProtectionKey = aKey.getLength() == 1 && aKey[0] == 1;
1047 }
1048 const OUString aGrabBagName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
1049 if ( xPropSetInfo->hasPropertyByName( aGrabBagName ) )
1050 {
1051 uno::Sequence< beans::PropertyValue > propList;
1052 xPropSet->getPropertyValue( aGrabBagName ) >>= propList;
1053
1054 for( const auto& rProp : std::as_const(propList) )
1055 {
1056 if ( rProp.Name == "ThemeFontLangProps" )
1057 {
1058 uno::Sequence< beans::PropertyValue > themeFontLangProps;
1059 rProp.Value >>= themeFontLangProps;
1060 OUString aValues[3];
1061 for( const auto& rThemeFontLangProp : std::as_const(themeFontLangProps) )
1062 {
1063 if( rThemeFontLangProp.Name == "val" )
1064 rThemeFontLangProp.Value >>= aValues[0];
1065 else if( rThemeFontLangProp.Name == "eastAsia" )
1066 rThemeFontLangProp.Value >>= aValues[1];
1067 else if( rThemeFontLangProp.Name == "bidi" )
1068 rThemeFontLangProp.Value >>= aValues[2];
1069 }
1070 pFS->singleElementNS( XML_w, XML_themeFontLang,
1071 FSNS( XML_w, XML_val ), aValues[0].toUtf8(),
1072 FSNS( XML_w, XML_eastAsia ), aValues[1].toUtf8(),
1073 FSNS( XML_w, XML_bidi ), aValues[2].toUtf8() );
1074 }
1075 else if ( rProp.Name == "CompatSettings" )
1076 {
1077 pFS->startElementNS(XML_w, XML_compat);
1078
1079 uno::Sequence< beans::PropertyValue > aCompatSettingsSequence;
1080 rProp.Value >>= aCompatSettingsSequence;
1081
1082 for(const auto& rCompatSetting : std::as_const(aCompatSettingsSequence))
1083 {
1084 uno::Sequence< beans::PropertyValue > aCompatSetting;
1085 rCompatSetting.Value >>= aCompatSetting;
1086 OUString aName;
1087 OUString aUri;
1088 OUString aValue;
1089
1090 for(const auto& rPropVal : std::as_const(aCompatSetting))
1091 {
1092 if( rPropVal.Name == "name" )
1093 rPropVal.Value >>= aName;
1094 else if( rPropVal.Name == "uri" )
1095 rPropVal.Value >>= aUri;
1096 else if( rPropVal.Name == "val" )
1097 rPropVal.Value >>= aValue;
1098 }
1099 pFS->singleElementNS( XML_w, XML_compatSetting,
1100 FSNS( XML_w, XML_name ), aName.toUtf8(),
1101 FSNS( XML_w, XML_uri ), aUri.toUtf8(),
1102 FSNS( XML_w, XML_val ), aValue.toUtf8());
1103 }
1104
1105 pFS->endElementNS( XML_w, XML_compat );
1106 }
1107 else if (rProp.Name == "DocumentProtection")
1108 {
1109
1110 uno::Sequence< beans::PropertyValue > rAttributeList;
1111 rProp.Value >>= rAttributeList;
1112
1113 if (rAttributeList.hasElements())
1114 {
1115 sax_fastparser::FastAttributeList* pAttributeList = sax_fastparser::FastSerializerHelper::createAttrList();
1116 bool bIsProtectionTrackChanges = false;
1117 for (const auto& rAttribute : std::as_const(rAttributeList))
1118 {
1119 static DocxStringTokenMap const aTokens[] =
1120 {
1121 { "edit", XML_edit },
1122 { "enforcement", XML_enforcement },
1123 { "formatting", XML_formatting },
1124 { "cryptProviderType", XML_cryptProviderType },
1125 { "cryptAlgorithmClass", XML_cryptAlgorithmClass },
1126 { "cryptAlgorithmType", XML_cryptAlgorithmType },
1127 { "cryptAlgorithmSid", XML_cryptAlgorithmSid },
1128 { "cryptSpinCount", XML_cryptSpinCount },
1129 { "hash", XML_hash },
1130 { "salt", XML_salt },
1131 { nullptr, 0 }
1132 };
1133
1134 if (sal_Int32 nToken = DocxStringGetToken(aTokens, rAttribute.Name))
1135 {
1136 OUString sValue = rAttribute.Value.get<OUString>();
1137 pAttributeList->add(FSNS(XML_w, nToken), sValue.toUtf8());
1138 if ( nToken == XML_edit && sValue == "trackedChanges" )
1139 bIsProtectionTrackChanges = true;
1140 }
1141 }
1142
1143 // we have document protection from input DOCX file
1144 // and in the case of change tracking protection, we didn't modify it
1145 hasProtectionProperties = !bIsProtectionTrackChanges || bHasDummyRedlineProtectionKey;
1146 if ( hasProtectionProperties )
1147 {
1148 sax_fastparser::XFastAttributeListRef xAttributeList(pAttributeList);
1149 pFS->singleElementNS(XML_w, XML_documentProtection, xAttributeList);
1150 }
1151
1152 }
1153 }
1154 else if (rProp.Name == "HyphenationZone")
1155 {
1156 sal_Int16 nHyphenationZone;
1157 rProp.Value >>= nHyphenationZone;
1158 if (nHyphenationZone > 0)
1159 pFS->singleElementNS(XML_w, XML_hyphenationZone, FSNS(XML_w, XML_val),
1160 OString::number(nHyphenationZone));
1161 }
1162 }
1163 }
1164
1165 if (! hasProtectionProperties)
1166 {
1167 // Protect form - highest priority
1168 // Section-specific write protection
1169 if (m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_FORM) ||
1170 m_pSections->DocumentIsProtected())
1171 {
1172 // we have form protection from Writer or from input ODT file
1173
1174 pFS->singleElementNS(XML_w, XML_documentProtection,
1175 FSNS(XML_w, XML_edit), "forms",
1176 FSNS(XML_w, XML_enforcement), "true");
1177 }
1178 // Protect Change Tracking - next priority
1179 else if ( bHasRedlineProtectionKey && !bHasDummyRedlineProtectionKey )
1180 {
1181 // we have change tracking protection from Writer or from input ODT file
1182
1183 pFS->singleElementNS(XML_w, XML_documentProtection,
1184 FSNS(XML_w, XML_edit), "trackedChanges",
1185 FSNS(XML_w, XML_enforcement), "1");
1186 }
1187 }
1188
1189 // finish settings.xml
1190 pFS->endElementNS( XML_w, XML_settings );
1191 }
1192
WriteTheme()1193 void DocxExport::WriteTheme()
1194 {
1195 uno::Reference< beans::XPropertySet > xPropSet( m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
1196
1197 uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
1198 OUString aName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
1199 if ( !xPropSetInfo->hasPropertyByName( aName ) )
1200 return;
1201
1202 uno::Reference<xml::dom::XDocument> themeDom;
1203 uno::Sequence< beans::PropertyValue > propList;
1204 xPropSet->getPropertyValue( aName ) >>= propList;
1205 auto pProp = std::find_if(propList.begin(), propList.end(),
1206 [](const beans::PropertyValue& rProp) { return rProp.Name == "OOXTheme"; });
1207 if (pProp != propList.end())
1208 pProp->Value >>= themeDom;
1209
1210 // no theme dom to write
1211 if ( !themeDom.is() )
1212 return;
1213
1214 m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
1215 oox::getRelationship(Relationship::THEME),
1216 "theme/theme1.xml" );
1217
1218 uno::Reference< xml::sax::XSAXSerializable > serializer( themeDom, uno::UNO_QUERY );
1219 uno::Reference< xml::sax::XWriter > writer = xml::sax::Writer::create( comphelper::getProcessComponentContext() );
1220 writer->setOutputStream( GetFilter().openFragmentStream( "word/theme/theme1.xml",
1221 "application/vnd.openxmlformats-officedocument.theme+xml" ) );
1222 serializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
1223 uno::Sequence< beans::StringPair >() );
1224 }
1225
WriteGlossary()1226 void DocxExport::WriteGlossary()
1227 {
1228 uno::Reference< beans::XPropertySet > xPropSet( m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
1229
1230 uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
1231 OUString aName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
1232 if ( !xPropSetInfo->hasPropertyByName( aName ) )
1233 return;
1234
1235 uno::Reference<xml::dom::XDocument> glossaryDocDom;
1236 uno::Sequence< uno::Sequence< uno::Any> > glossaryDomList;
1237 uno::Sequence< beans::PropertyValue > propList;
1238 xPropSet->getPropertyValue( aName ) >>= propList;
1239 sal_Int32 collectedProperties = 0;
1240 for ( const auto& rProp : std::as_const(propList) )
1241 {
1242 OUString propName = rProp.Name;
1243 if ( propName == "OOXGlossary" )
1244 {
1245 rProp.Value >>= glossaryDocDom;
1246 collectedProperties++;
1247 }
1248 if (propName == "OOXGlossaryDom")
1249 {
1250 rProp.Value >>= glossaryDomList;
1251 collectedProperties++;
1252 }
1253 if (collectedProperties == 2)
1254 break;
1255 }
1256
1257 // no glossary dom to write
1258 if ( !glossaryDocDom.is() )
1259 return;
1260
1261 m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
1262 oox::getRelationship(Relationship::GLOSSARYDOCUMENT),
1263 "glossary/document.xml" );
1264
1265 uno::Reference< io::XOutputStream > xOutputStream = GetFilter().openFragmentStream( "word/glossary/document.xml",
1266 "application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml" );
1267
1268 uno::Reference< xml::sax::XSAXSerializable > serializer( glossaryDocDom, uno::UNO_QUERY );
1269 uno::Reference< xml::sax::XWriter > writer = xml::sax::Writer::create( comphelper::getProcessComponentContext() );
1270 writer->setOutputStream( xOutputStream );
1271 serializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
1272 uno::Sequence< beans::StringPair >() );
1273
1274 for ( const uno::Sequence< uno::Any>& glossaryElement : std::as_const(glossaryDomList))
1275 {
1276 OUString gTarget, gType, gId, contentType;
1277 uno::Reference<xml::dom::XDocument> xDom;
1278 glossaryElement[0] >>= xDom;
1279 glossaryElement[1] >>= gId;
1280 glossaryElement[2] >>= gType;
1281 glossaryElement[3] >>= gTarget;
1282 glossaryElement[4] >>= contentType;
1283 gId = gId.copy(3); //"rId" only save the numeric value
1284
1285 PropertySet aProps(xOutputStream);
1286 aProps.setAnyProperty( PROP_RelId, uno::makeAny( gId.toInt32() ));
1287 m_pFilter->addRelation( xOutputStream, gType, gTarget);
1288 uno::Reference< xml::sax::XSAXSerializable > gserializer( xDom, uno::UNO_QUERY );
1289 writer->setOutputStream(GetFilter().openFragmentStream( "word/glossary/" + gTarget, contentType ) );
1290 gserializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
1291 uno::Sequence< beans::StringPair >() );
1292 }
1293 }
1294
WriteCustomXml()1295 void DocxExport::WriteCustomXml()
1296 {
1297 uno::Reference< beans::XPropertySet > xPropSet( m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
1298
1299 uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
1300 static const OUString aName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
1301 if ( !xPropSetInfo->hasPropertyByName( aName ) )
1302 return;
1303
1304 uno::Sequence<uno::Reference<xml::dom::XDocument> > customXmlDomlist;
1305 uno::Sequence<uno::Reference<xml::dom::XDocument> > customXmlDomPropslist;
1306 uno::Sequence< beans::PropertyValue > propList;
1307 xPropSet->getPropertyValue( aName ) >>= propList;
1308 auto pProp = std::find_if(propList.begin(), propList.end(),
1309 [](const beans::PropertyValue& rProp) { return rProp.Name == "OOXCustomXml"; });
1310 if (pProp != propList.end())
1311 pProp->Value >>= customXmlDomlist;
1312
1313 pProp = std::find_if(propList.begin(), propList.end(),
1314 [](const beans::PropertyValue& rProp) { return rProp.Name == "OOXCustomXmlProps"; });
1315 if (pProp != propList.end())
1316 pProp->Value >>= customXmlDomPropslist;
1317
1318 for (sal_Int32 j = 0; j < customXmlDomlist.getLength(); j++)
1319 {
1320 uno::Reference<xml::dom::XDocument> customXmlDom = customXmlDomlist[j];
1321 uno::Reference<xml::dom::XDocument> customXmlDomProps = customXmlDomPropslist[j];
1322 if (customXmlDom.is())
1323 {
1324 m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
1325 oox::getRelationship(Relationship::CUSTOMXML),
1326 "../customXml/item"+OUString::number((j+1))+".xml" );
1327
1328 uno::Reference< xml::sax::XSAXSerializable > serializer( customXmlDom, uno::UNO_QUERY );
1329 uno::Reference< xml::sax::XWriter > writer = xml::sax::Writer::create( comphelper::getProcessComponentContext() );
1330 writer->setOutputStream( GetFilter().openFragmentStream( "customXml/item"+OUString::number((j+1))+".xml",
1331 "application/xml" ) );
1332 serializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
1333 uno::Sequence< beans::StringPair >() );
1334 }
1335
1336 if (customXmlDomProps.is())
1337 {
1338 uno::Reference< xml::sax::XSAXSerializable > serializer( customXmlDomProps, uno::UNO_QUERY );
1339 uno::Reference< xml::sax::XWriter > writer = xml::sax::Writer::create( comphelper::getProcessComponentContext() );
1340 writer->setOutputStream( GetFilter().openFragmentStream( "customXml/itemProps"+OUString::number((j+1))+".xml",
1341 "application/vnd.openxmlformats-officedocument.customXmlProperties+xml" ) );
1342 serializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
1343 uno::Sequence< beans::StringPair >() );
1344
1345 // Adding itemprops's relationship entry to item.xml.rels file
1346 m_pFilter->addRelation( GetFilter().openFragmentStream( "customXml/item"+OUString::number((j+1))+".xml",
1347 "application/xml" ) ,
1348 oox::getRelationship(Relationship::CUSTOMXMLPROPS),
1349 "itemProps"+OUString::number((j+1))+".xml" );
1350 }
1351 }
1352 }
1353
WriteVBA()1354 void DocxExport::WriteVBA()
1355 {
1356 uno::Reference<document::XStorageBasedDocument> xStorageBasedDocument(m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY);
1357 if (!xStorageBasedDocument.is())
1358 return;
1359
1360 uno::Reference<embed::XStorage> xDocumentStorage = xStorageBasedDocument->getDocumentStorage();
1361 OUString aMacrosName("_MS_VBA_Macros");
1362 if (!xDocumentStorage.is() || !xDocumentStorage->hasByName(aMacrosName))
1363 return;
1364
1365 const sal_Int32 nOpenMode = embed::ElementModes::READ;
1366 uno::Reference<io::XStream> xMacrosStream = xDocumentStorage->openStreamElement(aMacrosName, nOpenMode);
1367 uno::Reference<io::XOutputStream> xProjectStream;
1368 if (xMacrosStream.is())
1369 {
1370 // First handle the project stream, this sets xProjectStream.
1371 std::unique_ptr<SvStream> pIn(utl::UcbStreamHelper::CreateStream(xMacrosStream));
1372
1373 xProjectStream = GetFilter().openFragmentStream("word/vbaProject.bin", "application/vnd.ms-office.vbaProject");
1374 uno::Reference<io::XStream> xOutputStream(xProjectStream, uno::UNO_QUERY);
1375 if (!xOutputStream.is())
1376 return;
1377 std::unique_ptr<SvStream> pOut(utl::UcbStreamHelper::CreateStream(xOutputStream));
1378
1379 // Write the stream.
1380 pOut->WriteStream(*pIn);
1381
1382 // Write the relationship.
1383 m_pFilter->addRelation(m_pDocumentFS->getOutputStream(), oox::getRelationship(Relationship::VBAPROJECT), "vbaProject.bin");
1384 }
1385
1386 OUString aDataName("_MS_VBA_Macros_XML");
1387 if (!xDocumentStorage.is() || !xDocumentStorage->hasByName(aDataName))
1388 return;
1389
1390 uno::Reference<io::XStream> xDataStream = xDocumentStorage->openStreamElement(aDataName, nOpenMode);
1391 if (xDataStream.is())
1392 {
1393 // Then the data stream, which wants to work with an already set
1394 // xProjectStream.
1395 std::unique_ptr<SvStream> pIn(utl::UcbStreamHelper::CreateStream(xDataStream));
1396
1397 uno::Reference<io::XStream> xOutputStream(GetFilter().openFragmentStream("word/vbaData.xml", "application/vnd.ms-word.vbaData+xml"), uno::UNO_QUERY);
1398 if (!xOutputStream.is())
1399 return;
1400 std::unique_ptr<SvStream> pOut(utl::UcbStreamHelper::CreateStream(xOutputStream));
1401
1402 // Write the stream.
1403 pOut->WriteStream(*pIn);
1404
1405 // Write the relationship.
1406 if (!xProjectStream.is())
1407 return;
1408
1409 m_pFilter->addRelation(xProjectStream, oox::getRelationship(Relationship::WORDVBADATA), "vbaData.xml");
1410 }
1411 }
1412
WriteEmbeddings()1413 void DocxExport::WriteEmbeddings()
1414 {
1415 uno::Reference< beans::XPropertySet > xPropSet( m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
1416
1417 uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
1418 OUString aName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
1419 if ( !xPropSetInfo->hasPropertyByName( aName ) )
1420 return;
1421
1422 uno::Sequence< beans::PropertyValue > embeddingsList;
1423 uno::Sequence< beans::PropertyValue > propList;
1424 xPropSet->getPropertyValue( aName ) >>= propList;
1425 auto pProp = std::find_if(propList.begin(), propList.end(),
1426 [](const beans::PropertyValue& rProp) { return rProp.Name == "OOXEmbeddings"; });
1427 if (pProp != propList.end())
1428 pProp->Value >>= embeddingsList;
1429 for (const auto& rEmbedding : std::as_const(embeddingsList))
1430 {
1431 OUString embeddingPath = rEmbedding.Name;
1432 uno::Reference<io::XInputStream> embeddingsStream;
1433 rEmbedding.Value >>= embeddingsStream;
1434
1435 OUString contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
1436 // FIXME: this .xlsm hack is silly - if anything the mime-type for an existing embedded object should be read from [Content_Types].xml
1437 if (embeddingPath.endsWith(".xlsm"))
1438 contentType = "application/vnd.ms-excel.sheet.macroEnabled.12";
1439 else if (embeddingPath.endsWith(".bin"))
1440 contentType = "application/vnd.openxmlformats-officedocument.oleObject";
1441
1442 if ( embeddingsStream.is() )
1443 {
1444 uno::Reference< io::XOutputStream > xOutStream = GetFilter().openFragmentStream(embeddingPath,
1445 contentType);
1446 try
1447 {
1448 sal_Int32 nBufferSize = 512;
1449 uno::Sequence< sal_Int8 > aDataBuffer(nBufferSize);
1450 sal_Int32 nRead;
1451 do
1452 {
1453 nRead = embeddingsStream->readBytes( aDataBuffer, nBufferSize );
1454 if( nRead )
1455 {
1456 if( nRead < nBufferSize )
1457 {
1458 nBufferSize = nRead;
1459 aDataBuffer.realloc(nRead);
1460 }
1461 xOutStream->writeBytes( aDataBuffer );
1462 }
1463 }
1464 while( nRead );
1465 xOutStream->flush();
1466 }
1467 catch(const uno::Exception&)
1468 {
1469 TOOLS_WARN_EXCEPTION("sw.ww8", "WriteEmbeddings() ::Failed to copy Inputstream to outputstream exception caught");
1470 }
1471 xOutStream->closeOutput();
1472 }
1473 }
1474 }
1475
isMirroredMargin()1476 bool DocxExport::isMirroredMargin()
1477 {
1478 bool bMirroredMargins = false;
1479 if ( UseOnPage::Mirror == (UseOnPage::Mirror & m_pDoc->GetPageDesc(0).ReadUseOn()) )
1480 {
1481 bMirroredMargins = true;
1482 }
1483 return bMirroredMargins;
1484 }
1485
WriteMainText()1486 void DocxExport::WriteMainText()
1487 {
1488 // setup the namespaces
1489 m_pDocumentFS->startElementNS( XML_w, XML_document, MainXmlNamespaces());
1490
1491 if ( getenv("SW_DEBUG_DOM") )
1492 {
1493 m_pDoc->dumpAsXml();
1494 }
1495
1496 // reset the incrementing linked-textboxes chain ID before re-saving.
1497 m_nLinkedTextboxesChainId=0;
1498 m_aLinkedTextboxesHelper.clear();
1499
1500 // Write background page color
1501 if (std::shared_ptr<SvxBrushItem> oBrush = getBackground(); oBrush)
1502 {
1503 Color backgroundColor = oBrush->GetColor();
1504 OString aBackgroundColorStr = msfilter::util::ConvertColor(backgroundColor);
1505
1506 m_pDocumentFS->singleElementNS(XML_w, XML_background, FSNS(XML_w, XML_color),
1507 aBackgroundColorStr);
1508 }
1509
1510 // body
1511 m_pDocumentFS->startElementNS(XML_w, XML_body);
1512
1513 m_pCurPam->GetPoint()->nNode = m_pDoc->GetNodes().GetEndOfContent().StartOfSectionNode()->GetIndex();
1514
1515 // the text
1516 WriteText();
1517
1518 // clear linked textboxes since old ones can't be linked to frames in a different section (correct?)
1519 m_aLinkedTextboxesHelper.clear();
1520
1521 // the last section info
1522 m_pAttrOutput->EndParaSdtBlock();
1523 const WW8_SepInfo *pSectionInfo = m_pSections? m_pSections->CurrentSectionInfo(): nullptr;
1524 if ( pSectionInfo )
1525 SectionProperties( *pSectionInfo );
1526
1527 // finish body and document
1528 m_pDocumentFS->endElementNS( XML_w, XML_body );
1529 m_pDocumentFS->endElementNS( XML_w, XML_document );
1530 }
1531
MainXmlNamespaces()1532 XFastAttributeListRef DocxExport::MainXmlNamespaces()
1533 {
1534 FastAttributeList* pAttr = FastSerializerHelper::createAttrList();
1535 pAttr->add( FSNS( XML_xmlns, XML_o ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(vmlOffice)), RTL_TEXTENCODING_UTF8).getStr() );
1536 pAttr->add( FSNS( XML_xmlns, XML_r ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(officeRel)), RTL_TEXTENCODING_UTF8).getStr() );
1537 pAttr->add( FSNS( XML_xmlns, XML_v ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(vml)), RTL_TEXTENCODING_UTF8).getStr() );
1538 pAttr->add( FSNS( XML_xmlns, XML_w ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(doc)), RTL_TEXTENCODING_UTF8).getStr() );
1539 pAttr->add( FSNS( XML_xmlns, XML_w10 ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(vmlWord)), RTL_TEXTENCODING_UTF8).getStr() );
1540 pAttr->add( FSNS( XML_xmlns, XML_wp ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(dmlWordDr)), RTL_TEXTENCODING_UTF8).getStr() );
1541 pAttr->add( FSNS( XML_xmlns, XML_wps ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(wps)), RTL_TEXTENCODING_UTF8).getStr() );
1542 pAttr->add( FSNS( XML_xmlns, XML_wpg ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(wpg)), RTL_TEXTENCODING_UTF8).getStr() );
1543 pAttr->add( FSNS( XML_xmlns, XML_mc ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(mce)), RTL_TEXTENCODING_UTF8).getStr() );
1544 pAttr->add( FSNS( XML_xmlns, XML_wp14 ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(wp14)), RTL_TEXTENCODING_UTF8).getStr() );
1545 pAttr->add( FSNS( XML_xmlns, XML_w14 ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(w14)), RTL_TEXTENCODING_UTF8).getStr() );
1546 pAttr->add( FSNS( XML_mc, XML_Ignorable ), "w14 wp14" );
1547 return XFastAttributeListRef( pAttr );
1548 }
1549
ignoreAttributeForStyleDefaults(sal_uInt16 nWhich) const1550 bool DocxExport::ignoreAttributeForStyleDefaults( sal_uInt16 nWhich ) const
1551 {
1552 if( nWhich == RES_TEXTGRID )
1553 return true; // w:docGrid is written only to document.xml, not to styles.xml
1554 if (nWhich == RES_PARATR_HYPHENZONE)
1555 return true; // w:suppressAutoHyphens is only a formatting exception, not a default
1556 return MSWordExportBase::ignoreAttributeForStyleDefaults( nWhich );
1557 }
1558
WriteOutliner(const OutlinerParaObject & rParaObj,sal_uInt8 nTyp)1559 void DocxExport::WriteOutliner(const OutlinerParaObject& rParaObj, sal_uInt8 nTyp)
1560 {
1561 const EditTextObject& rEditObj = rParaObj.GetTextObject();
1562 MSWord_SdrAttrIter aAttrIter( *this, rEditObj, nTyp );
1563
1564 sal_Int32 nPara = rEditObj.GetParagraphCount();
1565 for( sal_Int32 n = 0; n < nPara; ++n )
1566 {
1567 if( n )
1568 aAttrIter.NextPara( n );
1569
1570 AttrOutput().StartParagraph( ww8::WW8TableNodeInfo::Pointer_t());
1571 rtl_TextEncoding eChrSet = aAttrIter.GetNodeCharSet();
1572 OUString aStr( rEditObj.GetText( n ));
1573 sal_Int32 nCurrentPos = 0;
1574 const sal_Int32 nEnd = aStr.getLength();
1575 do {
1576 AttrOutput().StartRun( nullptr, 0 );
1577 const sal_Int32 nNextAttr = std::min(aAttrIter.WhereNext(), nEnd);
1578 rtl_TextEncoding eNextChrSet = aAttrIter.GetNextCharSet();
1579
1580 bool bTextAtr = aAttrIter.IsTextAttr( nCurrentPos );
1581 if( !bTextAtr )
1582 {
1583 if( nCurrentPos == 0 && nNextAttr - nCurrentPos == aStr.getLength())
1584 AttrOutput().RunText( aStr, eChrSet );
1585 else
1586 {
1587 OUString tmp( aStr.copy( nCurrentPos, nNextAttr - nCurrentPos ));
1588 AttrOutput().RunText( tmp, eChrSet );
1589 }
1590 }
1591 AttrOutput().StartRunProperties();
1592 aAttrIter.OutAttr( nCurrentPos );
1593 AttrOutput().EndRunProperties( nullptr );
1594
1595 nCurrentPos = nNextAttr;
1596 eChrSet = eNextChrSet;
1597 aAttrIter.NextPos();
1598
1599 AttrOutput().EndRun( nullptr, 0 );
1600
1601 } while( nCurrentPos < nEnd );
1602 // aAttrIter.OutParaAttr(false);
1603 AttrOutput().EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t());
1604 }
1605 }
1606
SetFS(::sax_fastparser::FSHelperPtr const & pFS)1607 void DocxExport::SetFS( ::sax_fastparser::FSHelperPtr const & pFS )
1608 {
1609 mpFS = pFS;
1610 }
1611
DocxExport(DocxExportFilter * pFilter,SwDoc * pDocument,std::shared_ptr<SwUnoCursor> & pCurrentPam,SwPaM * pOriginalPam,bool bDocm,bool bTemplate)1612 DocxExport::DocxExport(DocxExportFilter* pFilter, SwDoc* pDocument,
1613 std::shared_ptr<SwUnoCursor> & pCurrentPam,
1614 SwPaM* pOriginalPam, bool bDocm, bool bTemplate)
1615 : MSWordExportBase( pDocument, pCurrentPam, pOriginalPam ),
1616 m_pFilter( pFilter ),
1617 m_nHeaders( 0 ),
1618 m_nFooters( 0 ),
1619 m_nOLEObjects( 0 ),
1620 m_nActiveXControls( 0 ),
1621 m_nHeadersFootersInSection(0),
1622 m_bDocm(bDocm),
1623 m_bTemplate(bTemplate)
1624 {
1625 // Write the document properties
1626 WriteProperties( );
1627
1628 // relations for the document
1629 m_pFilter->addRelation( oox::getRelationship(Relationship::OFFICEDOCUMENT),
1630 "word/document.xml" );
1631
1632 // Set media type depending of document type
1633 OUString aMediaType;
1634 if (m_bDocm)
1635 {
1636 if (m_bTemplate)
1637 {
1638 aMediaType = "application/vnd.ms-word.template.macroEnabledTemplate.main+xml";
1639 }
1640 else
1641 {
1642 aMediaType = "application/vnd.ms-word.document.macroEnabled.main+xml";
1643 }
1644 }
1645 else
1646 {
1647 if (m_bTemplate)
1648 {
1649 aMediaType = "application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml";
1650 }
1651 else
1652 {
1653 aMediaType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml";
1654 }
1655 }
1656
1657
1658 // the actual document
1659 m_pDocumentFS = m_pFilter->openFragmentStreamWithSerializer( "word/document.xml", aMediaType );
1660
1661 SetFS(m_pDocumentFS);
1662
1663 // the DrawingML access
1664 m_pDrawingML.reset(new oox::drawingml::DrawingML(m_pDocumentFS, m_pFilter, oox::drawingml::DOCUMENT_DOCX));
1665
1666 // the attribute output for the document
1667 m_pAttrOutput.reset(new DocxAttributeOutput( *this, m_pDocumentFS, m_pDrawingML.get() ));
1668
1669 // the related VMLExport
1670 m_pVMLExport.reset(new VMLExport( m_pDocumentFS, m_pAttrOutput.get() ));
1671
1672 // the related drawing export
1673 m_pSdrExport.reset(new DocxSdrExport( *this, m_pDocumentFS, m_pDrawingML.get() ));
1674 }
1675
~DocxExport()1676 DocxExport::~DocxExport()
1677 {
1678 }
1679
DocxSettingsData()1680 DocxSettingsData::DocxSettingsData()
1681 : evenAndOddHeaders( false )
1682 , defaultTabStop( 0 )
1683 , revisionView( true )
1684 , trackRevisions( false )
1685 {
1686 }
1687
hasData() const1688 bool DocxSettingsData::hasData() const
1689 {
1690 if( evenAndOddHeaders )
1691 return true;
1692 if( defaultTabStop != 0 )
1693 return true;
1694 if ( !revisionView )
1695 return true;
1696 if ( trackRevisions )
1697 return true;
1698
1699 return false;
1700 }
1701
1702 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1703