Line data Source code
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 :
25 : #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
26 : #include <com/sun/star/document/XDocumentProperties.hpp>
27 : #include <com/sun/star/drawing/XShape.hpp>
28 : #include <com/sun/star/i18n/ScriptType.hpp>
29 : #include <com/sun/star/frame/XModel.hpp>
30 : #include <com/sun/star/xml/dom/XDocument.hpp>
31 : #include <com/sun/star/xml/sax/XSAXSerializable.hpp>
32 : #include <com/sun/star/xml/sax/Writer.hpp>
33 :
34 : #include <oox/token/tokens.hxx>
35 : #include <oox/export/drawingml.hxx>
36 : #include <oox/export/vmlexport.hxx>
37 : #include <oox/export/chartexport.hxx>
38 : #include <oox/export/shapes.hxx>
39 :
40 : #include <map>
41 : #include <algorithm>
42 :
43 : #include <IMark.hxx>
44 : #include <docsh.hxx>
45 : #include <ndtxt.hxx>
46 : #include <wrtww8.hxx>
47 : #include <fltini.hxx>
48 : #include <fmtline.hxx>
49 : #include <fmtpdsc.hxx>
50 : #include <frmfmt.hxx>
51 : #include <section.hxx>
52 : #include <ftninfo.hxx>
53 : #include <pagedesc.hxx>
54 :
55 : #include <editeng/unoprnms.hxx>
56 : #include <editeng/editobj.hxx>
57 : #include <editeng/outlobj.hxx>
58 : #include <editeng/brushitem.hxx>
59 :
60 : #include <docary.hxx>
61 : #include <numrule.hxx>
62 : #include <charfmt.hxx>
63 : #include <viewsh.hxx>
64 : #include <viewopt.hxx>
65 :
66 : #include "ww8par.hxx"
67 : #include "ww8scan.hxx"
68 : #include <oox/token/properties.hxx>
69 : #include <comphelper/embeddedobjectcontainer.hxx>
70 : #include <comphelper/string.hxx>
71 : #include <rtl/ustrbuf.hxx>
72 : #include <vcl/font.hxx>
73 :
74 : using namespace sax_fastparser;
75 : using namespace ::comphelper;
76 : using namespace ::com::sun::star;
77 : using namespace ::oox;
78 :
79 : using oox::vml::VMLExport;
80 :
81 : using sw::mark::IMark;
82 :
83 201358 : AttributeOutputBase& DocxExport::AttrOutput() const
84 : {
85 201358 : return *m_pAttrOutput;
86 : }
87 :
88 4 : MSWordSections& DocxExport::Sections() const
89 : {
90 4 : return *m_pSections;
91 : }
92 :
93 38145 : bool DocxExport::CollapseScriptsforWordOk( sal_uInt16 nScript, sal_uInt16 nWhich )
94 : {
95 : // TODO FIXME is this actually true for docx? - this is ~copied from WW8
96 38145 : if ( nScript == i18n::ScriptType::ASIAN )
97 : {
98 : // for asian in ww8, there is only one fontsize
99 : // and one fontstyle (posture/weight)
100 4 : switch ( nWhich )
101 : {
102 : case RES_CHRATR_FONTSIZE:
103 : case RES_CHRATR_POSTURE:
104 : case RES_CHRATR_WEIGHT:
105 1 : return false;
106 : default:
107 3 : break;
108 : }
109 : }
110 38141 : else if ( nScript != i18n::ScriptType::COMPLEX )
111 : {
112 : // for western in ww8, there is only one fontsize
113 : // and one fontstyle (posture/weight)
114 38137 : switch ( nWhich )
115 : {
116 : case RES_CHRATR_CJK_FONTSIZE:
117 : case RES_CHRATR_CJK_POSTURE:
118 : case RES_CHRATR_CJK_WEIGHT:
119 7495 : return false;
120 : default:
121 30642 : break;
122 : }
123 : }
124 30649 : return true;
125 : }
126 :
127 11678 : void DocxExport::AppendBookmarks( const SwTxtNode& rNode, sal_Int32 nAktPos, sal_Int32 nLen )
128 : {
129 11678 : std::vector< OUString > aStarts;
130 23356 : std::vector< OUString > aEnds;
131 :
132 23356 : IMarkVector aMarks;
133 11678 : if ( GetBookmarks( rNode, nAktPos, nAktPos + nLen, aMarks ) )
134 : {
135 1966 : for ( IMarkVector::const_iterator it = aMarks.begin(), end = aMarks.end();
136 : it != end; ++it )
137 : {
138 1162 : IMark* pMark = (*it);
139 :
140 1162 : const sal_Int32 nStart = pMark->GetMarkStart().nContent.GetIndex();
141 1162 : const sal_Int32 nEnd = pMark->GetMarkEnd().nContent.GetIndex();
142 :
143 1162 : if ( nStart == nAktPos )
144 779 : aStarts.push_back( pMark->GetName() );
145 :
146 1162 : if ( nEnd == nAktPos )
147 763 : aEnds.push_back( pMark->GetName() );
148 : }
149 : }
150 :
151 23356 : m_pAttrOutput->WriteBookmarks_Impl( aStarts, aEnds );
152 11678 : }
153 :
154 2 : void DocxExport::AppendBookmark( const OUString& rName, bool /*bSkip*/ )
155 : {
156 2 : std::vector< OUString > aStarts;
157 4 : std::vector< OUString > aEnds;
158 :
159 2 : aStarts.push_back( rName );
160 2 : aEnds.push_back( rName );
161 :
162 4 : m_pAttrOutput->WriteBookmarks_Impl( aStarts, aEnds );
163 2 : }
164 :
165 11678 : void DocxExport::AppendAnnotationMarks( const SwTxtNode& rNode, sal_Int32 nAktPos, sal_Int32 nLen )
166 : {
167 11678 : std::vector< OUString > aStarts;
168 23356 : std::vector< OUString > aEnds;
169 :
170 23356 : IMarkVector aMarks;
171 11678 : if ( GetAnnotationMarks( rNode, nAktPos, nAktPos + nLen, aMarks ) )
172 : {
173 31 : for ( IMarkVector::const_iterator it = aMarks.begin(), end = aMarks.end();
174 : it != end; ++it )
175 : {
176 16 : IMark* pMark = (*it);
177 :
178 16 : const sal_Int32 nStart = pMark->GetMarkStart().nContent.GetIndex();
179 16 : const sal_Int32 nEnd = pMark->GetMarkEnd().nContent.GetIndex();
180 :
181 16 : if ( nStart == nAktPos )
182 6 : aStarts.push_back( pMark->GetName() );
183 :
184 16 : if ( nEnd == nAktPos )
185 4 : aEnds.push_back( pMark->GetName() );
186 : }
187 : }
188 :
189 23356 : m_pAttrOutput->WriteAnnotationMarks_Impl( aStarts, aEnds );
190 11678 : }
191 :
192 260 : void DocxExport::ExportGrfBullet(const SwTxtNode&)
193 : {
194 : // Just collect the bullets for now, numbering.xml is not yet started.
195 260 : CollectGrfsOfBullets();
196 260 : }
197 :
198 0 : OString DocxExport::AddRelation( const OUString& rType, const OUString& rTarget )
199 : {
200 : OUString sId = m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
201 0 : rType, rTarget, true );
202 :
203 0 : return OUStringToOString( sId, RTL_TEXTENCODING_UTF8 );
204 : }
205 :
206 3337 : bool DocxExport::DisallowInheritingOutlineNumbering( const SwFmt& rFmt )
207 : {
208 3337 : bool bRet( false );
209 :
210 3337 : if (SFX_ITEM_SET != rFmt.GetItemState(RES_PARATR_NUMRULE, false))
211 : {
212 3259 : if (const SwFmt *pParent = rFmt.DerivedFrom())
213 : {
214 3259 : if (((const SwTxtFmtColl*)pParent)->IsAssignedToListLevelOfOutlineStyle())
215 : {
216 0 : ::sax_fastparser::FSHelperPtr pSerializer = m_pAttrOutput->GetSerializer( );
217 : // Level 9 disables the outline
218 : pSerializer->singleElementNS( XML_w, XML_outlineLvl,
219 : FSNS( XML_w, XML_val ), "9" ,
220 0 : FSEND );
221 :
222 0 : bRet = true;
223 : }
224 : }
225 : }
226 :
227 3337 : return bRet;
228 : }
229 :
230 298 : void DocxExport::WriteHeadersFooters( sal_uInt8 nHeadFootFlags,
231 : const SwFrmFmt& rFmt, const SwFrmFmt& rLeftFmt, const SwFrmFmt& rFirstPageFmt, sal_uInt8 /*nBreakCode*/ )
232 : {
233 298 : m_nHeadersFootersInSection = 1;
234 : // Turn ON flag for 'Writing Headers \ Footers'
235 298 : m_pAttrOutput->SetWritingHeaderFooter( true );
236 :
237 : // headers
238 298 : if ( nHeadFootFlags & nsHdFtFlags::WW8_HEADER_EVEN )
239 4 : WriteHeaderFooter( rLeftFmt, true, "even" );
240 :
241 298 : if ( nHeadFootFlags & nsHdFtFlags::WW8_HEADER_ODD )
242 56 : WriteHeaderFooter( rFmt, true, "default" );
243 :
244 298 : if ( nHeadFootFlags & nsHdFtFlags::WW8_HEADER_FIRST )
245 15 : WriteHeaderFooter( rFirstPageFmt, true, "first" );
246 :
247 : // footers
248 298 : if ( nHeadFootFlags & nsHdFtFlags::WW8_FOOTER_EVEN )
249 4 : WriteHeaderFooter( rLeftFmt, false, "even" );
250 :
251 298 : if ( nHeadFootFlags & nsHdFtFlags::WW8_FOOTER_ODD )
252 68 : WriteHeaderFooter( rFmt, false, "default" );
253 :
254 298 : if ( nHeadFootFlags & nsHdFtFlags::WW8_FOOTER_FIRST )
255 9 : WriteHeaderFooter( rFirstPageFmt, false, "first" );
256 :
257 298 : if ( nHeadFootFlags & ( nsHdFtFlags::WW8_FOOTER_EVEN | nsHdFtFlags::WW8_HEADER_EVEN ))
258 7 : m_aSettings.evenAndOddHeaders = true;
259 :
260 : // Turn OFF flag for 'Writing Headers \ Footers'
261 298 : m_pAttrOutput->SetWritingHeaderFooter( false );
262 298 : m_pAttrOutput->switchHeaderFooter(false, -1);
263 : #if OSL_DEBUG_LEVEL > 1
264 : fprintf( stderr, "DocxExport::WriteHeadersFooters() - nBreakCode introduced, but ignored\n" );
265 : #endif
266 298 : }
267 :
268 218 : void DocxExport::OutputField( const SwField* pFld, ww::eField eFldType, const OUString& rFldCmd, sal_uInt8 nMode )
269 : {
270 218 : m_pAttrOutput->WriteField_Impl( pFld, eFldType, rFldCmd, nMode );
271 218 : }
272 :
273 1 : void DocxExport::WriteFormData( const ::sw::mark::IFieldmark& rFieldmark )
274 : {
275 1 : m_pAttrOutput->WriteFormData_Impl( rFieldmark );
276 1 : }
277 :
278 0 : void DocxExport::WriteHyperlinkData( const ::sw::mark::IFieldmark& /*rFieldmark*/ )
279 : {
280 : #if OSL_DEBUG_LEVEL > 1
281 : fprintf( stderr, "TODO DocxExport::WriteHyperlinkData()\n" );
282 : #endif
283 0 : }
284 :
285 0 : void DocxExport::DoComboBox(const OUString& rName,
286 : const OUString& rHelp,
287 : const OUString& rToolTip,
288 : const OUString& rSelected,
289 : uno::Sequence<OUString>& rListItems)
290 : {
291 0 : m_pDocumentFS->startElementNS( XML_w, XML_ffData, FSEND );
292 :
293 : m_pDocumentFS->singleElementNS( XML_w, XML_name,
294 : FSNS( XML_w, XML_val ), OUStringToOString( rName, RTL_TEXTENCODING_UTF8 ).getStr(),
295 0 : FSEND );
296 :
297 0 : m_pDocumentFS->singleElementNS( XML_w, XML_enabled, FSEND );
298 :
299 0 : if ( !rHelp.isEmpty() )
300 : m_pDocumentFS->singleElementNS( XML_w, XML_helpText,
301 : FSNS( XML_w, XML_val ), OUStringToOString( rHelp, RTL_TEXTENCODING_UTF8 ).getStr(),
302 0 : FSEND );
303 :
304 0 : if ( !rToolTip.isEmpty() )
305 : m_pDocumentFS->singleElementNS( XML_w, XML_statusText,
306 : FSNS( XML_w, XML_val ), OUStringToOString( rToolTip, RTL_TEXTENCODING_UTF8 ).getStr(),
307 0 : FSEND );
308 :
309 0 : m_pDocumentFS->startElementNS( XML_w, XML_ddList, FSEND );
310 :
311 : // Output the 0-based index of the selected value
312 0 : sal_uInt32 nListItems = rListItems.getLength();
313 0 : sal_Int32 nId = 0;
314 0 : sal_uInt32 nI = 0;
315 0 : while ( ( nI < nListItems ) && ( nId == 0 ) )
316 : {
317 0 : if ( rListItems[nI] == rSelected )
318 0 : nId = nI;
319 0 : nI++;
320 : }
321 :
322 : m_pDocumentFS->singleElementNS( XML_w, XML_result,
323 : FSNS( XML_w, XML_val ), OString::number( nId ).getStr( ),
324 0 : FSEND );
325 :
326 : // Loop over the entries
327 :
328 0 : for (sal_uInt32 i = 0; i < nListItems; i++)
329 : {
330 : m_pDocumentFS->singleElementNS( XML_w, XML_listEntry,
331 0 : FSNS( XML_w, XML_val ), OUStringToOString( rListItems[i], RTL_TEXTENCODING_UTF8 ).getStr(),
332 0 : FSEND );
333 : }
334 :
335 0 : m_pDocumentFS->endElementNS( XML_w, XML_ddList );
336 :
337 0 : m_pDocumentFS->endElementNS( XML_w, XML_ffData );
338 0 : }
339 :
340 0 : void DocxExport::DoFormText(const SwInputField* /*pFld*/)
341 : {
342 : OSL_TRACE( "TODO DocxExport::ForFormText()" );
343 0 : }
344 :
345 20 : OString DocxExport::OutputChart( uno::Reference< frame::XModel >& xModel, sal_Int32 nCount, ::sax_fastparser::FSHelperPtr m_pSerializer )
346 : {
347 20 : OUString aFileName = "charts/chart" + OUString::number(nCount) + ".xml";
348 : OUString sId = m_pFilter->addRelation( m_pSerializer->getOutputStream(),
349 : "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart",
350 40 : aFileName );
351 20 : aFileName = "word/charts/chart" + OUString::number(nCount) + ".xml";
352 : ::sax_fastparser::FSHelperPtr pChartFS =
353 : m_pFilter->openFragmentStreamWithSerializer( aFileName,
354 40 : "application/vnd.openxmlformats-officedocument.drawingml.chart+xml" );
355 :
356 40 : oox::drawingml::ChartExport aChartExport( XML_w, pChartFS, xModel, m_pFilter, oox::drawingml::DrawingML::DOCUMENT_DOCX );
357 20 : aChartExport.ExportContent();
358 40 : return OUStringToOString( sId, RTL_TEXTENCODING_UTF8 );
359 : }
360 :
361 7 : OString DocxExport::WriteOLEObject( SwOLEObj& rObject, const OUString& sMediaType, const OUString& sRelationType )
362 : {
363 7 : uno::Reference <embed::XEmbeddedObject> xObj( rObject.GetOleRef() );
364 7 : comphelper::EmbeddedObjectContainer* aContainer = rObject.GetObject().GetContainer();
365 14 : uno::Reference< io::XInputStream > xInStream = aContainer->GetObjectStream( xObj, NULL );
366 :
367 14 : OUString sFileName = "embeddings/oleObject" + OUString::number( ++m_nOLEObjects ) + ".bin";
368 7 : uno::Reference< io::XOutputStream > xOutStream = GetFilter().openFragmentStream( OUStringBuffer()
369 14 : .appendAscii( "word/" )
370 7 : .append( sFileName )
371 : .makeStringAndClear(),
372 21 : sMediaType );
373 14 : OUString sId;
374 7 : if( lcl_CopyStream( xInStream, xOutStream ) )
375 :
376 12 : sId = m_pFilter->addRelation( GetFS()->getOutputStream(),
377 6 : sRelationType, sFileName, false );
378 :
379 14 : return OUStringToOString( sId, RTL_TEXTENCODING_UTF8 );
380 : }
381 :
382 : // function copied from embeddedobj/source/msole/oleembed.cxx
383 7 : bool DocxExport::lcl_CopyStream( uno::Reference<io::XInputStream> xIn, uno::Reference<io::XOutputStream> xOut )
384 : {
385 7 : if( !xIn.is() || !xOut.is() )
386 1 : return false;
387 :
388 6 : const sal_Int32 nChunkSize = 4096;
389 6 : uno::Sequence< sal_Int8 > aData(nChunkSize);
390 6 : sal_Int32 nTotalRead = 0;
391 6 : sal_Int32 nRead = 0;
392 96 : do
393 : {
394 96 : nRead = xIn->readBytes(aData, nChunkSize);
395 96 : nTotalRead += nRead;
396 96 : xOut->writeBytes(aData);
397 : } while (nRead == nChunkSize);
398 6 : return nTotalRead != 0;
399 : }
400 :
401 160 : void DocxExport::OutputDML(uno::Reference<drawing::XShape>& xShape)
402 : {
403 160 : uno::Reference<lang::XServiceInfo> xServiceInfo(xShape, uno::UNO_QUERY_THROW);
404 160 : sal_Int32 nNamespace = XML_wps;
405 160 : if (xServiceInfo->supportsService("com.sun.star.drawing.GroupShape"))
406 17 : nNamespace = XML_wpg;
407 143 : else if (xServiceInfo->supportsService("com.sun.star.drawing.GraphicObjectShape"))
408 22 : nNamespace = XML_pic;
409 320 : oox::drawingml::ShapeExport aExport(nNamespace, m_pAttrOutput->GetSerializer(), 0, m_pFilter, oox::drawingml::DrawingML::DOCUMENT_DOCX, m_pAttrOutput);
410 320 : aExport.WriteShape(xShape);
411 160 : }
412 :
413 272 : void DocxExport::ExportDocument_Impl()
414 : {
415 : // Set the 'Track Revisions' flag in the settings structure
416 272 : m_aSettings.trackRevisions = 0 != ( nsRedlineMode_t::REDLINE_ON & mnRedlineMode );
417 :
418 272 : InitStyles();
419 :
420 : // init sections
421 272 : m_pSections = new MSWordSections( *this );
422 :
423 : // Make sure images are counted from one, even when exporting multiple documents.
424 272 : oox::drawingml::DrawingML::ResetCounters();
425 :
426 272 : WriteMainText();
427 :
428 272 : WriteFootnotesEndnotes();
429 :
430 272 : WritePostitFields();
431 :
432 272 : WriteNumbering();
433 :
434 272 : WriteFonts();
435 :
436 272 : WriteSettings();
437 :
438 272 : WriteTheme();
439 :
440 272 : WriteGlossary();
441 :
442 272 : WriteCustomXml();
443 :
444 272 : WriteActiveX();
445 :
446 272 : WriteEmbeddings();
447 :
448 272 : delete pStyles, pStyles = NULL;
449 272 : delete m_pSections, m_pSections = NULL;
450 272 : }
451 :
452 0 : void DocxExport::OutputPageSectionBreaks( const SwTxtNode& )
453 : {
454 : OSL_TRACE( "TODO DocxExport::OutputPageSectionBreaks( const SwTxtNode& )" );
455 0 : }
456 :
457 17 : void DocxExport::AppendSection( const SwPageDesc *pPageDesc, const SwSectionFmt* pFmt, sal_uLong nLnNum )
458 : {
459 17 : AttrOutput().SectionBreak( msword::PageBreak, m_pSections->CurrentSectionInfo() );
460 17 : m_pSections->AppendSection( pPageDesc, pFmt, nLnNum );
461 17 : }
462 :
463 1719 : void DocxExport::OutputEndNode( const SwEndNode& rEndNode )
464 : {
465 1719 : MSWordExportBase::OutputEndNode( rEndNode );
466 :
467 1719 : if ( TXT_MAINTEXT == nTxtTyp && rEndNode.StartOfSectionNode()->IsSectionNode() )
468 : {
469 : // this originally comes from WW8Export::WriteText(), and looks like it
470 : // could have some code common with SectionNode()...
471 :
472 0 : const SwSection& rSect = rEndNode.StartOfSectionNode()->GetSectionNode()->GetSection();
473 0 : if ( bStartTOX && TOX_CONTENT_SECTION == rSect.GetType() )
474 0 : bStartTOX = false;
475 :
476 0 : SwNodeIndex aIdx( rEndNode, 1 );
477 0 : const SwNode& rNd = aIdx.GetNode();
478 0 : if ( rNd.IsEndNode() && rNd.StartOfSectionNode()->IsSectionNode() )
479 1719 : return;
480 :
481 0 : bool isInTable = IsInTable();
482 0 : if ( !rNd.IsSectionNode() && isInTable ) // No sections in table
483 : {
484 0 : const SwSectionFmt* pParentFmt = rSect.GetFmt()->GetParent();
485 0 : if( !pParentFmt )
486 0 : pParentFmt = (SwSectionFmt*)0xFFFFFFFF;
487 :
488 : sal_uLong nRstLnNum;
489 0 : if( rNd.IsCntntNode() )
490 0 : nRstLnNum = const_cast< SwCntntNode* >( rNd.GetCntntNode() )->GetSwAttrSet().GetLineNumber().GetStartValue();
491 : else
492 0 : nRstLnNum = 0;
493 :
494 0 : AttrOutput().SectionBreak( msword::PageBreak, m_pSections->CurrentSectionInfo( ) );
495 0 : m_pSections->AppendSection( pAktPageDesc, pParentFmt, nRstLnNum );
496 0 : }
497 : }
498 : }
499 :
500 0 : void DocxExport::OutputTableNode( const SwTableNode& )
501 : {
502 : OSL_TRACE( "TODO DocxExport::OutputTableNode( const SwTableNode& )" );
503 0 : }
504 :
505 0 : void DocxExport::OutputGrfNode( const SwGrfNode& )
506 : {
507 : OSL_TRACE( "TODO DocxExport::OutputGrfNode( const SwGrfNode& )" );
508 0 : }
509 :
510 0 : void DocxExport::OutputOLENode( const SwOLENode& )
511 : {
512 : OSL_TRACE( "TODO DocxExport::OutputOLENode( const SwOLENode& )" );
513 0 : }
514 :
515 0 : void DocxExport::OutputLinkedOLE( const OUString& )
516 : {
517 : // Nothing to implement here: WW8 only
518 0 : }
519 :
520 17 : sal_uLong DocxExport::ReplaceCr( sal_uInt8 )
521 : {
522 : // Completely unused for Docx export... only here for code sharing
523 : // purpose with binary export
524 17 : return 0;
525 : }
526 :
527 11 : void DocxExport::PrepareNewPageDesc( const SfxItemSet* pSet,
528 : const SwNode& rNd, const SwFmtPageDesc* pNewPgDescFmt,
529 : const SwPageDesc* pNewPgDesc )
530 : {
531 : // tell the attribute output that we are ready to write the section
532 : // break [has to be output inside paragraph properties]
533 11 : AttrOutput().SectionBreak( msword::PageBreak, m_pSections->CurrentSectionInfo() );
534 :
535 11 : const SwSectionFmt* pFmt = GetSectionFormat( rNd );
536 11 : const sal_uLong nLnNm = GetSectionLineNo( pSet, rNd );
537 :
538 : OSL_ENSURE( pNewPgDescFmt || pNewPgDesc, "Neither page desc format nor page desc provided." );
539 :
540 11 : if ( pNewPgDescFmt )
541 : {
542 6 : m_pSections->AppendSection( *pNewPgDescFmt, rNd, pFmt, nLnNm );
543 : }
544 5 : else if ( pNewPgDesc )
545 : {
546 5 : m_pSections->AppendSection( pNewPgDesc, rNd, pFmt, nLnNm );
547 : }
548 :
549 11 : }
550 :
551 272 : void DocxExport::InitStyles()
552 : {
553 272 : pStyles = new MSWordStyles( *this, /*bListStyles =*/ true );
554 :
555 : // setup word/styles.xml and the relations + content type
556 : m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
557 : "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles",
558 272 : "styles.xml" );
559 :
560 : ::sax_fastparser::FSHelperPtr pStylesFS =
561 : m_pFilter->openFragmentStreamWithSerializer( "word/styles.xml",
562 272 : "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml" );
563 :
564 : // switch the serializer to redirect the output to word/styles.xml
565 272 : m_pAttrOutput->SetSerializer( pStylesFS );
566 :
567 : // do the work
568 272 : pStyles->OutputStylesTable();
569 :
570 : // switch the serializer back
571 272 : m_pAttrOutput->SetSerializer( m_pDocumentFS );
572 272 : }
573 :
574 272 : void DocxExport::WriteFootnotesEndnotes()
575 : {
576 272 : if ( m_pAttrOutput->HasFootnotes() )
577 : {
578 : // setup word/styles.xml and the relations + content type
579 : m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
580 : "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes",
581 2 : "footnotes.xml" );
582 :
583 : ::sax_fastparser::FSHelperPtr pFootnotesFS =
584 : m_pFilter->openFragmentStreamWithSerializer( "word/footnotes.xml",
585 2 : "application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml" );
586 :
587 : // switch the serializer to redirect the output to word/footnotes.xml
588 2 : m_pAttrOutput->SetSerializer( pFootnotesFS );
589 :
590 : // do the work
591 2 : m_pAttrOutput->FootnotesEndnotes( true );
592 :
593 : // switch the serializer back
594 2 : m_pAttrOutput->SetSerializer( m_pDocumentFS );
595 : }
596 :
597 272 : if ( m_pAttrOutput->HasEndnotes() )
598 : {
599 : // setup word/styles.xml and the relations + content type
600 : m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
601 : "http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes",
602 1 : "endnotes.xml" );
603 :
604 : ::sax_fastparser::FSHelperPtr pEndnotesFS =
605 : m_pFilter->openFragmentStreamWithSerializer( "word/endnotes.xml",
606 1 : "application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml" );
607 :
608 : // switch the serializer to redirect the output to word/endnotes.xml
609 1 : m_pAttrOutput->SetSerializer( pEndnotesFS );
610 :
611 : // do the work
612 1 : m_pAttrOutput->FootnotesEndnotes( false );
613 :
614 : // switch the serializer back
615 1 : m_pAttrOutput->SetSerializer( m_pDocumentFS );
616 : }
617 272 : }
618 :
619 272 : void DocxExport::WritePostitFields()
620 : {
621 272 : if ( m_pAttrOutput->HasPostitFields() )
622 : {
623 : m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
624 : "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments",
625 3 : "comments.xml" );
626 :
627 : ::sax_fastparser::FSHelperPtr pPostitFS =
628 : m_pFilter->openFragmentStreamWithSerializer( "word/comments.xml",
629 3 : "application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml" );
630 :
631 3 : pPostitFS->startElementNS( XML_w, XML_comments, MainXmlNamespaces( pPostitFS ));
632 3 : m_pAttrOutput->SetSerializer( pPostitFS );
633 3 : m_pAttrOutput->WritePostitFields();
634 3 : m_pAttrOutput->SetSerializer( m_pDocumentFS );
635 3 : pPostitFS->endElementNS( XML_w, XML_comments );
636 : }
637 272 : }
638 :
639 272 : void DocxExport::WriteNumbering()
640 : {
641 272 : if ( !pUsedNumTbl )
642 516 : return; // no numbering is used
643 :
644 : m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
645 : "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering",
646 28 : "numbering.xml" );
647 :
648 : ::sax_fastparser::FSHelperPtr pNumberingFS = m_pFilter->openFragmentStreamWithSerializer( "word/numbering.xml",
649 28 : "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml" );
650 :
651 : // switch the serializer to redirect the output to word/nubering.xml
652 28 : m_pAttrOutput->SetSerializer( pNumberingFS );
653 :
654 : pNumberingFS->startElementNS( XML_w, XML_numbering,
655 : FSNS( XML_xmlns, XML_w ), "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
656 : FSNS( XML_xmlns, XML_o ), "urn:schemas-microsoft-com:office:office",
657 : FSNS( XML_xmlns, XML_r ), "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
658 : FSNS( XML_xmlns, XML_v ), "urn:schemas-microsoft-com:vml",
659 28 : FSEND );
660 :
661 28 : BulletDefinitions();
662 :
663 28 : AbstractNumberingDefinitions();
664 :
665 28 : NumberingDefinitions();
666 :
667 28 : pNumberingFS->endElementNS( XML_w, XML_numbering );
668 :
669 : // switch the serializer back
670 28 : m_pAttrOutput->SetSerializer( m_pDocumentFS );
671 : }
672 :
673 156 : void DocxExport::WriteHeaderFooter( const SwFmt& rFmt, bool bHeader, const char* pType )
674 : {
675 : // setup the xml stream
676 156 : OUString aRelId;
677 312 : ::sax_fastparser::FSHelperPtr pFS;
678 156 : if ( bHeader )
679 : {
680 75 : OUString aName( OUStringBuffer().append("header").append( ++m_nHeaders ).append(".xml").makeStringAndClear() );
681 :
682 150 : aRelId = m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
683 : "http://schemas.openxmlformats.org/officeDocument/2006/relationships/header",
684 75 : aName );
685 :
686 150 : pFS = m_pFilter->openFragmentStreamWithSerializer( OUStringBuffer().append("word/").append( aName ).makeStringAndClear(),
687 75 : "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml" );
688 :
689 75 : pFS->startElementNS( XML_w, XML_hdr, MainXmlNamespaces( pFS ));
690 : }
691 : else
692 : {
693 81 : OUString aName( OUStringBuffer().append("footer").append( ++m_nFooters ).append(".xml").makeStringAndClear() );
694 :
695 162 : aRelId = m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
696 : "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer",
697 81 : aName );
698 :
699 162 : pFS = m_pFilter->openFragmentStreamWithSerializer( OUStringBuffer().append("word/").append( aName ).makeStringAndClear(),
700 81 : "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml" );
701 :
702 81 : pFS->startElementNS( XML_w, XML_ftr, MainXmlNamespaces( pFS ));
703 : }
704 :
705 : // switch the serializer to redirect the output to word/styles.xml
706 156 : m_pAttrOutput->SetSerializer( pFS );
707 156 : m_pVMLExport->SetFS( pFS );
708 156 : m_pSdrExport->setSerializer(pFS);
709 156 : SetFS( pFS );
710 156 : m_pAttrOutput->switchHeaderFooter(true, m_nHeadersFootersInSection++);
711 : // do the work
712 156 : WriteHeaderFooterText( rFmt, bHeader );
713 :
714 : // switch the serializer back
715 156 : m_pAttrOutput->SetSerializer( m_pDocumentFS );
716 156 : m_pVMLExport->SetFS( m_pDocumentFS );
717 156 : m_pSdrExport->setSerializer(m_pDocumentFS);
718 156 : SetFS( m_pDocumentFS );
719 :
720 : // close the tag
721 : sal_Int32 nReference;
722 156 : if ( bHeader )
723 : {
724 75 : pFS->endElementNS( XML_w, XML_hdr );
725 75 : nReference = XML_headerReference;
726 : }
727 : else
728 : {
729 81 : pFS->endElementNS( XML_w, XML_ftr );
730 81 : nReference = XML_footerReference;
731 : }
732 :
733 : // and write the reference
734 : m_pDocumentFS->singleElementNS( XML_w, nReference,
735 : FSNS( XML_w, XML_type ), pType,
736 : FSNS( XML_r, XML_id ), OUStringToOString( aRelId, RTL_TEXTENCODING_UTF8 ).getStr(),
737 312 : FSEND );
738 156 : }
739 :
740 272 : void DocxExport::WriteFonts()
741 : {
742 : m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
743 : "http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable",
744 272 : "fontTable.xml" );
745 :
746 : ::sax_fastparser::FSHelperPtr pFS = m_pFilter->openFragmentStreamWithSerializer(
747 : "word/fontTable.xml",
748 272 : "application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml" );
749 :
750 : pFS->startElementNS( XML_w, XML_fonts,
751 : FSNS( XML_xmlns, XML_w ), "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
752 : FSNS( XML_xmlns, XML_r ), "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
753 272 : FSEND );
754 :
755 : // switch the serializer to redirect the output to word/styles.xml
756 272 : m_pAttrOutput->SetSerializer( pFS );
757 :
758 : // do the work
759 272 : maFontHelper.WriteFontTable( *m_pAttrOutput );
760 :
761 : // switch the serializer back
762 272 : m_pAttrOutput->SetSerializer( m_pDocumentFS );
763 :
764 272 : pFS->endElementNS( XML_w, XML_fonts );
765 272 : }
766 :
767 272 : void DocxExport::WriteProperties( )
768 : {
769 : // Write the core properties
770 272 : SwDocShell* pDocShell( pDoc->GetDocShell( ) );
771 272 : uno::Reference<document::XDocumentProperties> xDocProps;
772 272 : if ( pDocShell )
773 : {
774 : uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
775 272 : pDocShell->GetModel( ), uno::UNO_QUERY );
776 272 : xDocProps = xDPS->getDocumentProperties();
777 : }
778 :
779 272 : m_pFilter->exportDocumentProperties( xDocProps );
780 272 : }
781 :
782 272 : void DocxExport::WriteSettings()
783 : {
784 272 : SwViewShell *pViewShell(pDoc->GetCurrentViewShell());
785 272 : if( !pViewShell && !m_aSettings.hasData() && !m_pAttrOutput->HasFootnotes() && !m_pAttrOutput->HasEndnotes())
786 272 : return;
787 :
788 : m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
789 : "http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings",
790 272 : "settings.xml" );
791 :
792 : ::sax_fastparser::FSHelperPtr pFS = m_pFilter->openFragmentStreamWithSerializer(
793 : "word/settings.xml",
794 272 : "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml" );
795 :
796 : pFS->startElementNS( XML_w, XML_settings,
797 : FSNS( XML_xmlns, XML_w ), "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
798 272 : FSEND );
799 :
800 : // Zoom
801 272 : if (pViewShell)
802 : {
803 272 : OString aZoom(OString::number(pViewShell->GetViewOptions()->GetZoom()));
804 272 : pFS->singleElementNS(XML_w, XML_zoom, FSNS(XML_w, XML_percent), aZoom.getStr(), FSEND);
805 : }
806 :
807 : // Display Background Shape
808 272 : if (boost::optional<const SvxBrushItem*> oBrush = getBackground())
809 : {
810 : // Turn on the 'displayBackgroundShape'
811 3 : pFS->singleElementNS( XML_w, XML_displayBackgroundShape, FSEND );
812 272 : }
813 :
814 : // Track Changes
815 272 : if ( m_aSettings.trackRevisions )
816 8 : pFS->singleElementNS( XML_w, XML_trackRevisions, FSEND );
817 :
818 : // Mirror Margins
819 272 : if(isMirroredMargin())
820 3 : pFS->singleElementNS( XML_w, XML_mirrorMargins, FSEND );
821 :
822 : // Embed Fonts
823 272 : if( pDoc->get( IDocumentSettingAccess::EMBED_FONTS ))
824 0 : pFS->singleElementNS( XML_w, XML_embedTrueTypeFonts, FSEND );
825 :
826 : // Embed System Fonts
827 272 : if( pDoc->get( IDocumentSettingAccess::EMBED_SYSTEM_FONTS ))
828 19 : pFS->singleElementNS( XML_w, XML_embedSystemFonts, FSEND );
829 :
830 : // Default Tab Stop
831 272 : if( m_aSettings.defaultTabStop != 0 )
832 : pFS->singleElementNS( XML_w, XML_defaultTabStop, FSNS( XML_w, XML_val ),
833 272 : OString::number( m_aSettings.defaultTabStop).getStr(), FSEND );
834 :
835 : // Even and Odd Headers
836 272 : if( m_aSettings.evenAndOddHeaders )
837 5 : pFS->singleElementNS( XML_w, XML_evenAndOddHeaders, FSEND );
838 :
839 : // Has Footnotes
840 272 : if( m_pAttrOutput->HasFootnotes())
841 2 : m_pAttrOutput->WriteFootnoteEndnotePr( pFS, XML_footnotePr, pDoc->GetFtnInfo(), XML_footnote );
842 :
843 : // Has Endnotes
844 272 : if( m_pAttrOutput->HasEndnotes())
845 1 : m_pAttrOutput->WriteFootnoteEndnotePr( pFS, XML_endnotePr, pDoc->GetEndNoteInfo(), XML_endnote );
846 :
847 : // Has themeFontLang information
848 544 : uno::Reference< beans::XPropertySet > xPropSet( pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
849 :
850 544 : uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
851 544 : OUString pName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
852 272 : if ( xPropSetInfo->hasPropertyByName( pName ) )
853 : {
854 272 : uno::Sequence< beans::PropertyValue > propList;
855 272 : xPropSet->getPropertyValue( pName ) >>= propList;
856 3278 : for( sal_Int32 i=0; i < propList.getLength(); ++i )
857 : {
858 3006 : if ( propList[i].Name == "ThemeFontLangProps" )
859 : {
860 254 : uno::Sequence< beans::PropertyValue > themeFontLangProps;
861 254 : propList[i].Value >>= themeFontLangProps;
862 508 : OUString aValues[3];
863 1016 : for( sal_Int32 j=0; j < themeFontLangProps.getLength(); ++j )
864 : {
865 762 : if( themeFontLangProps[j].Name == "val" )
866 231 : themeFontLangProps[j].Value >>= aValues[0];
867 531 : else if( themeFontLangProps[j].Name == "eastAsia" )
868 79 : themeFontLangProps[j].Value >>= aValues[1];
869 452 : else if( themeFontLangProps[j].Name == "bidi" )
870 99 : themeFontLangProps[j].Value >>= aValues[2];
871 : }
872 : pFS->singleElementNS( XML_w, XML_themeFontLang,
873 : FSNS( XML_w, XML_val ), OUStringToOString( aValues[0], RTL_TEXTENCODING_UTF8 ).getStr(),
874 : FSNS( XML_w, XML_eastAsia ), OUStringToOString( aValues[1], RTL_TEXTENCODING_UTF8 ).getStr(),
875 : FSNS( XML_w, XML_bidi ), OUStringToOString( aValues[2], RTL_TEXTENCODING_UTF8 ).getStr(),
876 508 : FSEND );
877 : }
878 2752 : else if ( propList[i].Name == "CompatSettings" )
879 : {
880 254 : pFS->startElementNS( XML_w, XML_compat, FSEND );
881 :
882 254 : uno::Sequence< beans::PropertyValue > aCompatSettingsSequence;
883 254 : propList[i].Value >>= aCompatSettingsSequence;
884 962 : for(sal_Int32 j=0; j < aCompatSettingsSequence.getLength(); ++j)
885 : {
886 708 : uno::Sequence< beans::PropertyValue > aCompatSetting;
887 708 : aCompatSettingsSequence[j].Value >>= aCompatSetting;
888 1416 : OUString aName;
889 1416 : OUString aUri;
890 1416 : OUString aValue;
891 :
892 2832 : for(sal_Int32 k=0; k < aCompatSetting.getLength(); ++k)
893 : {
894 2124 : if( aCompatSetting[k].Name == "name" )
895 708 : aCompatSetting[k].Value >>= aName;
896 1416 : else if( aCompatSetting[k].Name == "uri" )
897 708 : aCompatSetting[k].Value >>= aUri;
898 708 : else if( aCompatSetting[k].Name == "val" )
899 708 : aCompatSetting[k].Value >>= aValue;
900 : }
901 : pFS->singleElementNS( XML_w, XML_compatSetting,
902 : FSNS( XML_w, XML_name ), OUStringToOString(aName, RTL_TEXTENCODING_UTF8).getStr(),
903 : FSNS( XML_w, XML_uri ), OUStringToOString(aUri, RTL_TEXTENCODING_UTF8).getStr(),
904 : FSNS( XML_w, XML_val ), OUStringToOString(aValue, RTL_TEXTENCODING_UTF8).getStr(),
905 708 : FSEND);
906 708 : }
907 :
908 254 : pFS->endElementNS( XML_w, XML_compat );
909 : }
910 272 : }
911 : }
912 :
913 544 : pFS->endElementNS( XML_w, XML_settings );
914 : }
915 :
916 272 : void DocxExport::WriteTheme()
917 : {
918 272 : uno::Reference< beans::XPropertySet > xPropSet( pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
919 :
920 505 : uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
921 505 : OUString pName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
922 272 : if ( !xPropSetInfo->hasPropertyByName( pName ) )
923 0 : return;
924 :
925 505 : uno::Reference<xml::dom::XDocument> themeDom;
926 505 : uno::Sequence< beans::PropertyValue > propList;
927 272 : xPropSet->getPropertyValue( pName ) >>= propList;
928 2307 : for ( sal_Int32 nProp=0; nProp < propList.getLength(); ++nProp )
929 : {
930 2289 : OUString propName = propList[nProp].Name;
931 2289 : if ( propName == "OOXTheme" )
932 : {
933 254 : propList[nProp].Value >>= themeDom;
934 254 : break;
935 : }
936 2035 : }
937 :
938 : // no theme dom to write
939 272 : if ( !themeDom.is() )
940 39 : return;
941 :
942 : m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
943 : "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme",
944 233 : "theme/theme1.xml" );
945 :
946 466 : uno::Reference< xml::sax::XSAXSerializable > serializer( themeDom, uno::UNO_QUERY );
947 466 : uno::Reference< xml::sax::XWriter > writer = xml::sax::Writer::create( comphelper::getProcessComponentContext() );
948 466 : writer->setOutputStream( GetFilter().openFragmentStream( "word/theme/theme1.xml",
949 466 : "application/vnd.openxmlformats-officedocument.theme+xml" ) );
950 233 : serializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
951 466 : uno::Sequence< beans::StringPair >() );
952 : }
953 :
954 272 : void DocxExport::WriteGlossary()
955 : {
956 272 : uno::Reference< beans::XPropertySet > xPropSet( pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
957 :
958 281 : uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
959 281 : OUString pName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
960 272 : if ( !xPropSetInfo->hasPropertyByName( pName ) )
961 0 : return;
962 :
963 281 : uno::Reference<xml::dom::XDocument> glossaryDocDom;
964 281 : uno::Sequence< uno::Sequence< uno::Any> > glossaryDomList;
965 281 : uno::Sequence< beans::PropertyValue > propList;
966 272 : xPropSet->getPropertyValue( pName ) >>= propList;
967 272 : sal_Int32 collectedProperties = 0;
968 2053 : for ( sal_Int32 nProp=0; nProp < propList.getLength(); ++nProp )
969 : {
970 2035 : OUString propName = propList[nProp].Name;
971 2035 : if ( propName == "OOXGlossary" )
972 : {
973 254 : propList[nProp].Value >>= glossaryDocDom;
974 254 : collectedProperties++;
975 : }
976 2035 : if (propName == "OOXGlossaryDom")
977 : {
978 254 : propList[nProp].Value >>= glossaryDomList;
979 254 : collectedProperties++;
980 : }
981 2035 : if (collectedProperties == 2)
982 254 : break;
983 1781 : }
984 :
985 : // no glossary dom to write
986 272 : if ( !glossaryDocDom.is() )
987 263 : return;
988 :
989 : m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
990 : "http://schemas.openxmlformats.org/officeDocument/2006/relationships/glossaryDocument",
991 9 : "glossary/document.xml" );
992 :
993 9 : uno::Reference< io::XOutputStream > xOutputStream = GetFilter().openFragmentStream( "word/glossary/document.xml",
994 27 : "application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml" );
995 :
996 18 : uno::Reference< xml::sax::XSAXSerializable > serializer( glossaryDocDom, uno::UNO_QUERY );
997 18 : uno::Reference< xml::sax::XWriter > writer = xml::sax::Writer::create( comphelper::getProcessComponentContext() );
998 9 : writer->setOutputStream( xOutputStream );
999 9 : serializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
1000 9 : uno::Sequence< beans::StringPair >() );
1001 :
1002 9 : sal_Int32 length = glossaryDomList.getLength();
1003 45 : for ( int i =0; i < length; i++)
1004 : {
1005 36 : uno::Sequence< uno::Any> glossaryElement = glossaryDomList[i];
1006 72 : OUString gTarget, gType, gId, contentType;
1007 72 : uno::Reference<xml::dom::XDocument> xDom;
1008 36 : glossaryElement[0] >>= xDom;
1009 36 : glossaryElement[1] >>= gId;
1010 36 : glossaryElement[2] >>= gType;
1011 36 : glossaryElement[3] >>= gTarget;
1012 36 : glossaryElement[4] >>= contentType;
1013 36 : gId = gId.copy(3); //"rId" only save the numeric value
1014 :
1015 72 : PropertySet aProps(xOutputStream);
1016 36 : aProps.setAnyProperty( PROP_RelId, uno::makeAny( sal_Int32( gId.toInt32() )));
1017 36 : m_pFilter->addRelation( xOutputStream, gType, gTarget);
1018 72 : uno::Reference< xml::sax::XSAXSerializable > gserializer( xDom, uno::UNO_QUERY );
1019 36 : writer->setOutputStream(GetFilter().openFragmentStream( "word/glossary/" + gTarget, contentType ) );
1020 36 : gserializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
1021 36 : uno::Sequence< beans::StringPair >() );
1022 45 : }
1023 : }
1024 :
1025 272 : void DocxExport::WriteCustomXml()
1026 : {
1027 272 : uno::Reference< beans::XPropertySet > xPropSet( pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
1028 :
1029 544 : uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
1030 544 : OUString pName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
1031 272 : if ( !xPropSetInfo->hasPropertyByName( pName ) )
1032 272 : return;
1033 :
1034 544 : uno::Sequence<uno::Reference<xml::dom::XDocument> > customXmlDomlist;
1035 544 : uno::Sequence<uno::Reference<xml::dom::XDocument> > customXmlDomPropslist;
1036 544 : uno::Sequence< beans::PropertyValue > propList;
1037 272 : xPropSet->getPropertyValue( pName ) >>= propList;
1038 1037 : for ( sal_Int32 nProp=0; nProp < propList.getLength(); ++nProp )
1039 : {
1040 1019 : OUString propName = propList[nProp].Name;
1041 1019 : if ( propName == "OOXCustomXml" )
1042 : {
1043 254 : propList[nProp].Value >>= customXmlDomlist;
1044 254 : break;
1045 : }
1046 765 : }
1047 :
1048 1291 : for ( sal_Int32 nProp=0; nProp < propList.getLength(); ++nProp )
1049 : {
1050 1273 : OUString propName = propList[nProp].Name;
1051 1273 : if ( propName == "OOXCustomXmlProps" )
1052 : {
1053 254 : propList[nProp].Value >>= customXmlDomPropslist;
1054 254 : break;
1055 : }
1056 1019 : }
1057 :
1058 350 : for (sal_Int32 j = 0; j < customXmlDomlist.getLength(); j++) {
1059 :
1060 78 : uno::Reference<xml::dom::XDocument> customXmlDom = customXmlDomlist[j];
1061 156 : uno::Reference<xml::dom::XDocument> customXmlDomProps = customXmlDomPropslist[j];
1062 78 : if ( customXmlDom.is() )
1063 : {
1064 : m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
1065 : "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml",
1066 78 : "../customXml/item"+OUString::number((j+1))+".xml" );
1067 :
1068 78 : uno::Reference< xml::sax::XSAXSerializable > serializer( customXmlDom, uno::UNO_QUERY );
1069 156 : uno::Reference< xml::sax::XWriter > writer = xml::sax::Writer::create( comphelper::getProcessComponentContext() );
1070 312 : writer->setOutputStream( GetFilter().openFragmentStream( "customXml/item"+OUString::number((j+1))+".xml",
1071 312 : "application/xml" ) );
1072 78 : serializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
1073 156 : uno::Sequence< beans::StringPair >() );
1074 : }
1075 :
1076 78 : if ( customXmlDomProps.is() )
1077 : {
1078 :
1079 78 : uno::Reference< xml::sax::XSAXSerializable > serializer( customXmlDomProps, uno::UNO_QUERY );
1080 156 : uno::Reference< xml::sax::XWriter > writer = xml::sax::Writer::create( comphelper::getProcessComponentContext() );
1081 312 : writer->setOutputStream( GetFilter().openFragmentStream( "customXml/itemProps"+OUString::number((j+1))+".xml",
1082 312 : "application/vnd.openxmlformats-officedocument.customXmlProperties+xml" ) );
1083 78 : serializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
1084 78 : uno::Sequence< beans::StringPair >() );
1085 :
1086 : // Adding itemprops's relationship entry to item.xml.rels file
1087 234 : m_pFilter->addRelation( GetFilter().openFragmentStream( "customXml/item"+OUString::number((j+1))+".xml",
1088 : "application/xml" ) ,
1089 : "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps",
1090 390 : "itemProps"+OUString::number((j+1))+".xml" );
1091 :
1092 : }
1093 350 : }
1094 : }
1095 :
1096 272 : void DocxExport::WriteActiveX()
1097 : {
1098 272 : uno::Reference< beans::XPropertySet > xPropSet( pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
1099 :
1100 544 : uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
1101 544 : OUString pName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
1102 272 : if ( !xPropSetInfo->hasPropertyByName( pName ) )
1103 272 : return;
1104 :
1105 544 : uno::Sequence<uno::Reference<xml::dom::XDocument> > activeXDomlist;
1106 544 : uno::Sequence<uno::Reference<io::XInputStream> > activeXBinList;
1107 544 : uno::Sequence< beans::PropertyValue > propList;
1108 272 : xPropSet->getPropertyValue( pName ) >>= propList;
1109 529 : for ( sal_Int32 nProp=0; nProp < propList.getLength(); ++nProp )
1110 : {
1111 511 : OUString propName = propList[nProp].Name;
1112 511 : if ( propName == "OOXActiveX" )
1113 : {
1114 254 : propList[nProp].Value >>= activeXDomlist;
1115 254 : break;
1116 : }
1117 257 : }
1118 :
1119 783 : for ( sal_Int32 nProp=0; nProp < propList.getLength(); ++nProp )
1120 : {
1121 765 : OUString propName = propList[nProp].Name;
1122 765 : if ( propName == "OOXActiveXBin" )
1123 : {
1124 254 : propList[nProp].Value >>= activeXBinList;
1125 254 : break;
1126 : }
1127 511 : }
1128 :
1129 735 : for (sal_Int32 j = 0; j < activeXDomlist.getLength(); j++)
1130 : {
1131 463 : uno::Reference<xml::dom::XDocument> activeXDom = activeXDomlist[j];
1132 926 : uno::Reference<io::XInputStream> activeXBin = activeXBinList[j];
1133 :
1134 463 : if ( activeXDom.is() )
1135 : {
1136 : m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
1137 : "http://schemas.openxmlformats.org/officeDocument/2006/relationships/control",
1138 463 : "activeX/activeX"+OUString::number((j+1))+".xml" );
1139 :
1140 463 : uno::Reference< xml::sax::XSAXSerializable > serializer( activeXDom, uno::UNO_QUERY );
1141 926 : uno::Reference< xml::sax::XWriter > writer = xml::sax::Writer::create( comphelper::getProcessComponentContext() );
1142 1852 : writer->setOutputStream( GetFilter().openFragmentStream( "word/activeX/activeX"+OUString::number((j+1))+".xml",
1143 1852 : "application/vnd.ms-office.activeX+xml" ) );
1144 463 : serializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
1145 926 : uno::Sequence< beans::StringPair >() );
1146 : }
1147 :
1148 463 : if ( activeXBin.is() )
1149 : {
1150 1389 : uno::Reference< io::XOutputStream > xOutStream = GetFilter().openFragmentStream("word/activeX/activeX"+OUString::number((j+1))+".bin",
1151 1852 : "application/vnd.ms-office.activeX");
1152 :
1153 : try
1154 : {
1155 463 : sal_Int32 nBufferSize = 512;
1156 463 : uno::Sequence< sal_Int8 > aDataBuffer(nBufferSize);
1157 : sal_Int32 nRead;
1158 1060 : do
1159 : {
1160 1060 : nRead = activeXBin->readBytes( aDataBuffer, nBufferSize );
1161 1060 : if( nRead )
1162 : {
1163 597 : if( nRead < nBufferSize )
1164 : {
1165 453 : nBufferSize = nRead;
1166 453 : aDataBuffer.realloc(nRead);
1167 : }
1168 597 : xOutStream->writeBytes( aDataBuffer );
1169 : }
1170 : }
1171 : while( nRead );
1172 463 : xOutStream->flush();
1173 : }
1174 0 : catch(const uno::Exception&)
1175 : {
1176 : SAL_WARN("sw.ww8", "WriteActiveX() ::Failed to copy Inputstream to outputstream exception catched!");
1177 : }
1178 :
1179 463 : xOutStream->closeOutput();
1180 : // Adding itemprops's relationship entry to item.xml.rels file
1181 1389 : m_pFilter->addRelation( GetFilter().openFragmentStream( "/word/activeX/activeX"+OUString::number((j+1))+".xml",
1182 : "application/vnd.ms-office.activeX+xml" ) ,
1183 : "http://schemas.microsoft.com/office/2006/relationships/activeXControlBinary",
1184 1852 : "activeX"+OUString::number((j+1))+".bin" );
1185 :
1186 : }
1187 735 : }
1188 : }
1189 :
1190 272 : void DocxExport::WriteEmbeddings()
1191 : {
1192 272 : uno::Reference< beans::XPropertySet > xPropSet( pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
1193 :
1194 544 : uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
1195 544 : OUString pName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
1196 272 : if ( !xPropSetInfo->hasPropertyByName( pName ) )
1197 272 : return;
1198 :
1199 544 : uno::Sequence< beans::PropertyValue > embeddingsList;
1200 544 : uno::Sequence< beans::PropertyValue > propList;
1201 272 : xPropSet->getPropertyValue( pName ) >>= propList;
1202 1545 : for ( sal_Int32 nProp=0; nProp < propList.getLength(); ++nProp )
1203 : {
1204 1527 : OUString propName = propList[nProp].Name;
1205 1527 : if ( propName == "OOXEmbeddings" )
1206 : {
1207 254 : propList[nProp].Value >>= embeddingsList;
1208 254 : break;
1209 : }
1210 1273 : }
1211 291 : for (sal_Int32 j = 0; j < embeddingsList.getLength(); j++)
1212 : {
1213 19 : OUString embeddingPath = embeddingsList[j].Name;
1214 38 : uno::Reference<io::XInputStream> embeddingsStream;
1215 19 : embeddingsList[j].Value >>= embeddingsStream;
1216 :
1217 38 : OUString contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
1218 19 : if (embeddingPath.endsWith(OUString(".xlsm")))
1219 1 : contentType = "application/vnd.ms-excel.sheet.macroEnabled.12";
1220 18 : else if (embeddingPath.endsWith(OUString(".bin")))
1221 0 : contentType = "application/vnd.openxmlformats-officedocument.oleObject";
1222 :
1223 19 : if ( embeddingsStream.is() )
1224 : {
1225 19 : uno::Reference< io::XOutputStream > xOutStream = GetFilter().openFragmentStream(embeddingPath,
1226 19 : contentType);
1227 : try
1228 : {
1229 19 : sal_Int32 nBufferSize = 512;
1230 19 : uno::Sequence< sal_Int8 > aDataBuffer(nBufferSize);
1231 : sal_Int32 nRead;
1232 469 : do
1233 : {
1234 469 : nRead = embeddingsStream->readBytes( aDataBuffer, nBufferSize );
1235 469 : if( nRead )
1236 : {
1237 450 : if( nRead < nBufferSize )
1238 : {
1239 18 : nBufferSize = nRead;
1240 18 : aDataBuffer.realloc(nRead);
1241 : }
1242 450 : xOutStream->writeBytes( aDataBuffer );
1243 : }
1244 : }
1245 : while( nRead );
1246 19 : xOutStream->flush();
1247 : }
1248 0 : catch(const uno::Exception&)
1249 : {
1250 : SAL_WARN("sw.ww8", "WriteEmbeddings() ::Failed to copy Inputstream to outputstream exception catched!");
1251 : }
1252 19 : xOutStream->closeOutput();
1253 : }
1254 291 : }
1255 : }
1256 :
1257 162 : VMLExport& DocxExport::VMLExporter()
1258 : {
1259 162 : return *m_pVMLExport;
1260 : }
1261 :
1262 27087 : DocxSdrExport& DocxExport::SdrExporter()
1263 : {
1264 27087 : return *m_pSdrExport;
1265 : }
1266 :
1267 272 : bool DocxExport::isMirroredMargin()
1268 : {
1269 272 : bool bMirroredMargins = false;
1270 272 : if ( nsUseOnPage::PD_MIRROR == (nsUseOnPage::PD_MIRROR & pDoc->GetPageDesc(0).ReadUseOn()) )
1271 : {
1272 3 : bMirroredMargins = true;
1273 : }
1274 272 : return bMirroredMargins;
1275 : }
1276 :
1277 544 : boost::optional<const SvxBrushItem*> DocxExport::getBackground()
1278 : {
1279 544 : boost::optional<const SvxBrushItem*> oRet;
1280 544 : const SwFrmFmt &rFmt = pDoc->GetPageDesc(0).GetMaster();
1281 544 : const SfxPoolItem* pItem = 0;
1282 544 : SfxItemState eState = rFmt.GetItemState(RES_BACKGROUND, true, &pItem);
1283 :
1284 544 : if (SFX_ITEM_SET == eState && pItem)
1285 : {
1286 : // The 'color' is set for the first page style - take it and use it as the background color of the entire DOCX
1287 8 : const SvxBrushItem* pBrush = (const SvxBrushItem*)pItem;
1288 8 : if (pBrush->GetColor().GetColor() != COL_AUTO)
1289 6 : oRet.reset(pBrush);
1290 : }
1291 544 : return oRet;
1292 : }
1293 :
1294 272 : void DocxExport::WriteMainText()
1295 : {
1296 : // setup the namespaces
1297 272 : m_pDocumentFS->startElementNS( XML_w, XML_document, MainXmlNamespaces( m_pDocumentFS ));
1298 :
1299 : // Write background page color
1300 272 : if (boost::optional<const SvxBrushItem*> oBrush = getBackground())
1301 : {
1302 3 : Color backgroundColor = (*oBrush)->GetColor();
1303 3 : OString aBackgroundColorStr = msfilter::util::ConvertColor(backgroundColor);
1304 :
1305 3 : m_pDocumentFS->singleElementNS( XML_w, XML_background, FSNS( XML_w, XML_color ), aBackgroundColorStr, FSEND );
1306 272 : }
1307 :
1308 : // body
1309 272 : m_pDocumentFS->startElementNS( XML_w, XML_body, FSEND );
1310 :
1311 272 : pCurPam->GetPoint()->nNode = pDoc->GetNodes().GetEndOfContent().StartOfSectionNode()->GetIndex();
1312 :
1313 : // the text
1314 272 : WriteText();
1315 :
1316 : // the last section info
1317 272 : const WW8_SepInfo *pSectionInfo = m_pSections? m_pSections->CurrentSectionInfo(): NULL;
1318 272 : if ( pSectionInfo )
1319 272 : SectionProperties( *pSectionInfo );
1320 :
1321 : // finish body and document
1322 272 : m_pDocumentFS->endElementNS( XML_w, XML_body );
1323 272 : m_pDocumentFS->endElementNS( XML_w, XML_document );
1324 272 : }
1325 :
1326 431 : XFastAttributeListRef DocxExport::MainXmlNamespaces( FSHelperPtr serializer )
1327 : {
1328 431 : FastAttributeList* pAttr = serializer->createAttrList();
1329 431 : pAttr->add( FSNS( XML_xmlns, XML_o ), "urn:schemas-microsoft-com:office:office" );
1330 431 : pAttr->add( FSNS( XML_xmlns, XML_r ), "http://schemas.openxmlformats.org/officeDocument/2006/relationships" );
1331 431 : pAttr->add( FSNS( XML_xmlns, XML_v ), "urn:schemas-microsoft-com:vml" );
1332 431 : pAttr->add( FSNS( XML_xmlns, XML_w ), "http://schemas.openxmlformats.org/wordprocessingml/2006/main" );
1333 431 : pAttr->add( FSNS( XML_xmlns, XML_w10 ), "urn:schemas-microsoft-com:office:word" );
1334 431 : pAttr->add( FSNS( XML_xmlns, XML_wp ), "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" );
1335 431 : pAttr->add( FSNS( XML_xmlns, XML_wps ), "http://schemas.microsoft.com/office/word/2010/wordprocessingShape" );
1336 431 : pAttr->add( FSNS( XML_xmlns, XML_wpg ), "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" );
1337 431 : pAttr->add( FSNS( XML_xmlns, XML_mc ), "http://schemas.openxmlformats.org/markup-compatibility/2006" );
1338 431 : pAttr->add( FSNS( XML_xmlns, XML_wp14 ), "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" );
1339 431 : pAttr->add( FSNS( XML_xmlns, XML_w14 ), "http://schemas.microsoft.com/office/word/2010/wordml" );
1340 431 : pAttr->add( FSNS( XML_mc, XML_Ignorable ), "w14 wp14" );
1341 431 : return XFastAttributeListRef( pAttr );
1342 : }
1343 :
1344 8062 : bool DocxExport::ignoreAttributeForStyles( sal_uInt16 nWhich ) const
1345 : {
1346 8062 : if( nWhich == RES_TEXTGRID )
1347 428 : return true; // w:docGrid is written only to document.xml, not to styles.xml
1348 7634 : return MSWordExportBase::ignoreAttributeForStyles( nWhich );
1349 : }
1350 :
1351 5 : void DocxExport::WriteOutliner(const OutlinerParaObject& rParaObj, sal_uInt8 nTyp)
1352 : {
1353 5 : const EditTextObject& rEditObj = rParaObj.GetTextObject();
1354 5 : MSWord_SdrAttrIter aAttrIter( *this, rEditObj, nTyp );
1355 :
1356 5 : sal_Int32 nPara = rEditObj.GetParagraphCount();
1357 10 : for( sal_Int32 n = 0; n < nPara; ++n )
1358 : {
1359 5 : if( n )
1360 0 : aAttrIter.NextPara( n );
1361 :
1362 5 : AttrOutput().StartParagraph( ww8::WW8TableNodeInfo::Pointer_t());
1363 5 : rtl_TextEncoding eChrSet = aAttrIter.GetNodeCharSet();
1364 5 : OUString aStr( rEditObj.GetText( n ));
1365 5 : sal_Int32 nAktPos = 0;
1366 5 : const sal_Int32 nEnd = aStr.getLength();
1367 5 : do {
1368 5 : AttrOutput().StartRun( NULL );
1369 5 : const sal_Int32 nNextAttr = std::min(aAttrIter.WhereNext(), nEnd);
1370 5 : rtl_TextEncoding eNextChrSet = aAttrIter.GetNextCharSet();
1371 :
1372 5 : bool bTxtAtr = aAttrIter.IsTxtAttr( nAktPos );
1373 5 : if( !bTxtAtr )
1374 : {
1375 5 : if( nAktPos == 0 && nNextAttr - nAktPos == aStr.getLength())
1376 5 : AttrOutput().RunText( aStr, eChrSet );
1377 : else
1378 : {
1379 0 : OUString tmp( aStr.copy( nAktPos, nNextAttr - nAktPos ));
1380 0 : AttrOutput().RunText( tmp, eChrSet );
1381 : }
1382 : }
1383 5 : AttrOutput().StartRunProperties();
1384 5 : aAttrIter.OutAttr( nAktPos );
1385 5 : AttrOutput().EndRunProperties( NULL );
1386 :
1387 5 : nAktPos = nNextAttr;
1388 5 : eChrSet = eNextChrSet;
1389 5 : aAttrIter.NextPos();
1390 5 : AttrOutput().EndRun();
1391 5 : } while( nAktPos < nEnd );
1392 : // aAttrIter.OutParaAttr(false);
1393 5 : AttrOutput().EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t());
1394 10 : }
1395 5 : }
1396 :
1397 584 : void DocxExport::SetFS( ::sax_fastparser::FSHelperPtr pFS )
1398 : {
1399 584 : mpFS = pFS;
1400 584 : }
1401 :
1402 272 : DocxExport::DocxExport( DocxExportFilter *pFilter, SwDoc *pDocument, SwPaM *pCurrentPam, SwPaM *pOriginalPam )
1403 : : MSWordExportBase( pDocument, pCurrentPam, pOriginalPam ),
1404 : m_pFilter( pFilter ),
1405 : m_pAttrOutput( NULL ),
1406 : m_pSections( NULL ),
1407 : m_nHeaders( 0 ),
1408 : m_nFooters( 0 ),
1409 : m_nOLEObjects( 0 ),
1410 : m_nHeadersFootersInSection(0),
1411 : m_pVMLExport( NULL ),
1412 272 : m_pSdrExport( NULL )
1413 : {
1414 : // Write the document properies
1415 272 : WriteProperties( );
1416 :
1417 : // relations for the document
1418 : m_pFilter->addRelation( "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
1419 272 : "word/document.xml" );
1420 :
1421 : // the actual document
1422 544 : m_pDocumentFS = m_pFilter->openFragmentStreamWithSerializer( "word/document.xml",
1423 272 : "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml" );
1424 :
1425 272 : SetFS(m_pDocumentFS);
1426 :
1427 : // the DrawingML access
1428 272 : m_pDrawingML = new oox::drawingml::DrawingML( m_pDocumentFS, m_pFilter, oox::drawingml::DrawingML::DOCUMENT_DOCX );
1429 :
1430 : // the attribute output for the document
1431 272 : m_pAttrOutput = new DocxAttributeOutput( *this, m_pDocumentFS, m_pDrawingML );
1432 :
1433 : // the related VMLExport
1434 272 : m_pVMLExport = new VMLExport( m_pDocumentFS, m_pAttrOutput );
1435 :
1436 : // the related drawing export
1437 272 : m_pSdrExport = new DocxSdrExport( *this, m_pDocumentFS, m_pDrawingML );
1438 272 : }
1439 :
1440 544 : DocxExport::~DocxExport()
1441 : {
1442 272 : delete m_pSdrExport, m_pSdrExport = NULL;
1443 272 : delete m_pVMLExport, m_pVMLExport = NULL;
1444 272 : delete m_pAttrOutput, m_pAttrOutput = NULL;
1445 272 : delete m_pDrawingML, m_pDrawingML = NULL;
1446 272 : }
1447 :
1448 272 : DocxSettingsData::DocxSettingsData()
1449 : : evenAndOddHeaders( false )
1450 : , defaultTabStop( 0 )
1451 272 : , trackRevisions( false )
1452 : {
1453 272 : }
1454 :
1455 0 : bool DocxSettingsData::hasData() const
1456 : {
1457 0 : if( evenAndOddHeaders )
1458 0 : return true;
1459 0 : if( defaultTabStop != 0 )
1460 0 : return true;
1461 0 : if ( trackRevisions )
1462 0 : return true;
1463 :
1464 0 : return false;
1465 33 : }
1466 :
1467 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|