update credits
[LibreOffice.git] / sw / source / filter / ww8 / wrtw8nds.cxx
blob330d70c44d9b1ff31251510cb32570890d9331e3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <vector>
22 #include <list>
23 #include <utility>
24 #include <algorithm>
25 #include <functional>
26 #include <iostream>
28 #include <hintids.hxx>
29 #include <comphelper/string.hxx>
30 #include <tools/urlobj.hxx>
31 #include <editeng/boxitem.hxx>
32 #include <editeng/cmapitem.hxx>
33 #include <editeng/langitem.hxx>
34 #include <editeng/svxfont.hxx>
35 #include <editeng/lrspitem.hxx>
36 #include <editeng/brushitem.hxx>
37 #include <editeng/fontitem.hxx>
38 #include <editeng/keepitem.hxx>
39 #include <editeng/fhgtitem.hxx>
40 #include <editeng/ulspitem.hxx>
41 #include <editeng/formatbreakitem.hxx>
42 #include <editeng/frmdiritem.hxx>
43 #include <editeng/tstpitem.hxx>
44 #include "svl/urihelper.hxx"
45 #include <svl/whiter.hxx>
46 #include <fmtpdsc.hxx>
47 #include <fmtfsize.hxx>
48 #include <fmtornt.hxx>
49 #include <fmtlsplt.hxx>
50 #include <fmtflcnt.hxx>
51 #include <fmtanchr.hxx>
52 #include <fmtcntnt.hxx>
53 #include <frmatr.hxx>
54 #include <paratr.hxx>
55 #include <txatbase.hxx>
56 #include <fmtinfmt.hxx>
57 #include <fmtrfmrk.hxx>
58 #include <fchrfmt.hxx>
59 #include <fmtautofmt.hxx>
60 #include <charfmt.hxx>
61 #include <tox.hxx>
62 #include <ndtxt.hxx>
63 #include <pam.hxx>
64 #include <doc.hxx>
65 #include <docary.hxx>
66 #include <swtable.hxx>
67 #include <swtblfmt.hxx>
68 #include <section.hxx>
69 #include <pagedesc.hxx>
70 #include <swrect.hxx>
71 #include <reffld.hxx>
72 #include <redline.hxx>
73 #include <wrtswtbl.hxx>
74 #include <htmltbl.hxx>
75 #include <txttxmrk.hxx>
76 #include <fmtline.hxx>
77 #include <fmtruby.hxx>
78 #include <breakit.hxx>
79 #include <txtatr.hxx>
80 #include <fmtsrnd.hxx>
81 #include <fmtrowsplt.hxx>
82 #include <com/sun/star/i18n/ScriptType.hpp>
83 #include <com/sun/star/i18n/WordType.hpp>
85 #include <doctok/sprmids.hxx>
87 #include "writerhelper.hxx"
88 #include "writerwordglue.hxx"
89 #include <numrule.hxx>
90 #include "wrtww8.hxx"
91 #include "ww8par.hxx"
92 #include <IMark.hxx>
93 #include "ww8attributeoutput.hxx"
95 #include <ndgrf.hxx>
96 #include <ndole.hxx>
98 #include <cstdio>
100 using namespace ::com::sun::star;
101 using namespace ::com::sun::star::i18n;
102 using namespace sw::util;
103 using namespace sw::types;
104 using namespace sw::mark;
105 using namespace nsFieldFlags;
107 static String lcl_getFieldCode( const IFieldmark* pFieldmark ) {
108 OSL_ENSURE(pFieldmark!=NULL, "where is my fieldmark???");
110 if ( !pFieldmark) {
111 return String();
112 } else if ( pFieldmark->GetFieldname( ) == ODF_FORMTEXT ) {
113 return OUString(" FORMTEXT ");
114 } else if ( pFieldmark->GetFieldname( ) == ODF_FORMDROPDOWN ) {
115 return OUString(" FORMDROPDOWN ");
116 } else if ( pFieldmark->GetFieldname( ) == ODF_FORMCHECKBOX ) {
117 return OUString(" FORMCHECKBOX ");
118 } else if ( pFieldmark->GetFieldname( ) == ODF_TOC ) {
119 return OUString(" TOC ");
120 } else if ( pFieldmark->GetFieldname( ) == ODF_HYPERLINK ) {
121 return OUString(" HYPERLINK ");
122 } else if ( pFieldmark->GetFieldname( ) == ODF_PAGEREF ) {
123 return OUString(" PAGEREF ");
124 } else {
125 return pFieldmark->GetFieldname();
129 static ww::eField lcl_getFieldId( const IFieldmark* pFieldmark ) {
130 OSL_ENSURE(pFieldmark!=NULL, "where is my fieldmark???");
131 if ( !pFieldmark ) {
132 return ww::eUNKNOWN;
133 } else if ( pFieldmark->GetFieldname( ) == ODF_FORMTEXT ) {
134 return ww::eFORMTEXT;
135 } else if ( pFieldmark->GetFieldname( ) == ODF_FORMDROPDOWN ) {
136 return ww::eFORMDROPDOWN;
137 } else if ( pFieldmark->GetFieldname( ) == ODF_FORMCHECKBOX ) {
138 return ww::eFORMCHECKBOX;
139 } else if ( pFieldmark->GetFieldname( ) == ODF_TOC ) {
140 return ww::eTOC;
141 } else if ( pFieldmark->GetFieldname( ) == ODF_HYPERLINK ) {
142 return ww::eHYPERLINK;
143 } else if ( pFieldmark->GetFieldname( ) == ODF_PAGEREF ) {
144 return ww::ePAGEREF;
145 } else {
146 return ww::eUNKNOWN;
150 MSWordAttrIter::MSWordAttrIter( MSWordExportBase& rExport )
151 : pOld( rExport.pChpIter ), m_rExport( rExport )
153 m_rExport.pChpIter = this;
156 MSWordAttrIter::~MSWordAttrIter()
158 m_rExport.pChpIter = pOld;
161 class sortswflys :
162 public std::binary_function<const sw::Frame&, const sw::Frame&, bool>
164 public:
165 bool operator()(const sw::Frame &rOne, const sw::Frame &rTwo) const
167 return rOne.GetPosition() < rTwo.GetPosition();
171 void SwWW8AttrIter::IterToCurrent()
173 OSL_ENSURE(maCharRuns.begin() != maCharRuns.end(), "Impossible");
174 mnScript = maCharRunIter->mnScript;
175 meChrSet = maCharRunIter->meCharSet;
176 mbCharIsRTL = maCharRunIter->mbRTL;
179 SwWW8AttrIter::SwWW8AttrIter(MSWordExportBase& rWr, const SwTxtNode& rTxtNd) :
180 MSWordAttrIter(rWr),
181 rNd(rTxtNd),
182 maCharRuns(GetPseudoCharRuns(rTxtNd, 0, !rWr.SupportsUnicode())),
183 pCurRedline(0),
184 nAktSwPos(0),
185 nCurRedlinePos(USHRT_MAX),
186 mrSwFmtDrop(rTxtNd.GetSwAttrSet().GetDrop())
189 SwPosition aPos(rTxtNd);
190 if (FRMDIR_HORI_RIGHT_TOP == rWr.pDoc->GetTextDirection(aPos))
191 mbParaIsRTL = true;
192 else
193 mbParaIsRTL = false;
195 maCharRunIter = maCharRuns.begin();
196 IterToCurrent();
199 #i2916#
200 Get list of any graphics which may be anchored from this paragraph.
202 maFlyFrms = GetFramesInNode(rWr.maFrames, rNd);
203 std::sort(maFlyFrms.begin(), maFlyFrms.end(), sortswflys());
206 #i18480#
207 If we are inside a frame then anything anchored inside this frame can
208 only be supported by word anchored inline ("as character"), so force
209 this in the supportable case.
211 if (rWr.SupportsUnicode() && rWr.bInWriteEscher)
213 std::for_each(maFlyFrms.begin(), maFlyFrms.end(),
214 std::mem_fun_ref(&sw::Frame::ForceTreatAsInline));
217 maFlyIter = maFlyFrms.begin();
219 if ( !m_rExport.pDoc->GetRedlineTbl().empty() )
221 SwPosition aPosition( rNd, SwIndex( (SwTxtNode*)&rNd ) );
222 pCurRedline = m_rExport.pDoc->GetRedline( aPosition, &nCurRedlinePos );
225 nAktSwPos = SearchNext(1);
228 xub_StrLen lcl_getMinPos( xub_StrLen pos1, xub_StrLen pos2 )
230 xub_StrLen min = STRING_NOTFOUND;
231 if ( pos1 == STRING_NOTFOUND && pos2 != STRING_NOTFOUND )
232 min = pos2;
233 else if ( pos2 == STRING_NOTFOUND && pos1 != STRING_NOTFOUND )
234 min = pos1;
235 else if ( pos1 != STRING_NOTFOUND && pos2 != STRING_NOTFOUND )
237 if ( pos1 < pos2 )
238 min = pos1;
239 else
240 min = pos2;
243 return min;
246 xub_StrLen SwWW8AttrIter::SearchNext( xub_StrLen nStartPos )
248 xub_StrLen nPos;
249 xub_StrLen nMinPos = STRING_MAXLEN;
250 xub_StrLen i=0;
252 const String aTxt = rNd.GetTxt();
253 xub_StrLen fieldEndPos = aTxt.Search(CH_TXT_ATR_FIELDEND, nStartPos);
254 xub_StrLen fieldStartPos = aTxt.Search(CH_TXT_ATR_FIELDSTART, nStartPos);
255 xub_StrLen formElementPos = aTxt.Search(CH_TXT_ATR_FORMELEMENT, nStartPos);
257 xub_StrLen pos = lcl_getMinPos( fieldEndPos, fieldStartPos );
258 pos = lcl_getMinPos( pos, formElementPos );
260 if (pos!=STRING_NOTFOUND)
261 nMinPos=pos;
263 // first the redline, then the attributes
264 if( pCurRedline )
266 const SwPosition* pEnd = pCurRedline->End();
267 if (pEnd->nNode == rNd && ((i = pEnd->nContent.GetIndex()) >= nStartPos) && i < nMinPos )
268 nMinPos = i;
271 if ( nCurRedlinePos < m_rExport.pDoc->GetRedlineTbl().size() )
273 // nCurRedlinePos point to the next redline
274 nPos = nCurRedlinePos;
275 if( pCurRedline )
276 ++nPos;
278 for ( ; nPos < m_rExport.pDoc->GetRedlineTbl().size(); ++nPos )
280 const SwRedline* pRedl = m_rExport.pDoc->GetRedlineTbl()[ nPos ];
282 const SwPosition* pStt = pRedl->Start();
283 const SwPosition* pEnd = pStt == pRedl->GetPoint()
284 ? pRedl->GetMark()
285 : pRedl->GetPoint();
287 if( pStt->nNode == rNd )
289 if( ( i = pStt->nContent.GetIndex() ) >= nStartPos &&
290 i < nMinPos )
291 nMinPos = i;
293 else
294 break;
296 if( pEnd->nNode == rNd &&
297 ( i = pEnd->nContent.GetIndex() ) < nMinPos &&
298 i >= nStartPos )
299 nMinPos = i;
304 if (mrSwFmtDrop.GetWholeWord() && nStartPos <= rNd.GetDropLen(0))
305 nMinPos = rNd.GetDropLen(0);
306 else if(nStartPos <= mrSwFmtDrop.GetChars())
307 nMinPos = mrSwFmtDrop.GetChars();
309 if(const SwpHints* pTxtAttrs = rNd.GetpSwpHints())
312 // can be optimized if we consider that the TxtAttrs are sorted by start position.
313 // but then we'd have to save 2 indices
314 for( i = 0; i < pTxtAttrs->Count(); i++ )
316 const SwTxtAttr* pHt = (*pTxtAttrs)[i];
317 nPos = *pHt->GetStart(); // first Attr characters
318 if( nPos >= nStartPos && nPos <= nMinPos )
319 nMinPos = nPos;
321 if( pHt->GetEnd() ) // Attr with end
323 nPos = *pHt->GetEnd(); // last Attr character + 1
324 if( nPos >= nStartPos && nPos <= nMinPos )
325 nMinPos = nPos;
327 if (pHt->HasDummyChar())
329 // pos + 1 because of CH_TXTATR in Text
330 nPos = *pHt->GetStart() + 1;
331 if( nPos >= nStartPos && nPos <= nMinPos )
332 nMinPos = nPos;
337 if (maCharRunIter != maCharRuns.end())
339 if (maCharRunIter->mnEndPos < nMinPos)
340 nMinPos = maCharRunIter->mnEndPos;
341 IterToCurrent();
345 #i2916#
346 Check to see if there are any graphics anchored to characters in this
347 paragraph's text. Set nMinPos to 1 past the placement for anchored to
348 character because anchors in Word appear after the character they are
349 anchored to.
351 if (maFlyIter != maFlyFrms.end())
353 const SwPosition &rAnchor = maFlyIter->GetPosition();
355 nPos = rAnchor.nContent.GetIndex();
356 if (nPos >= nStartPos && nPos <= nMinPos)
357 nMinPos = nPos;
359 if (maFlyIter->GetFrmFmt().GetAnchor().GetAnchorId() == FLY_AT_CHAR)
361 ++nPos;
362 if (nPos >= nStartPos && nPos <= nMinPos)
363 nMinPos = nPos;
367 //nMinPos found and not going to change at this point
369 if (maCharRunIter != maCharRuns.end())
371 if (maCharRunIter->mnEndPos == nMinPos)
372 ++maCharRunIter;
375 return nMinPos;
378 static bool lcl_isFontsizeItem( const SfxPoolItem& rItem )
380 return ( rItem.Which( ) == RES_CHRATR_FONTSIZE ||
381 rItem.Which( ) == RES_CHRATR_CJK_FONTSIZE ||
382 rItem.Which( ) == RES_CHRATR_CTL_FONTSIZE );
385 void SwWW8AttrIter::OutAttr( xub_StrLen nSwPos, bool bRuby )
387 m_rExport.AttrOutput().RTLAndCJKState( IsCharRTL(), GetScript() );
390 Depending on whether text is in CTL/CJK or Western, get the id of that
391 script, the idea is that the font that is actually in use to render this
392 range of text ends up in pFont
394 sal_uInt16 nFontId = GetWhichOfScript( RES_CHRATR_FONT, GetScript() );
396 const SvxFontItem &rParentFont = ItemGet<SvxFontItem>(
397 (const SwTxtFmtColl&)rNd.GetAnyFmtColl(), nFontId);
398 const SvxFontItem *pFont = &rParentFont;
400 SfxItemSet aExportSet(*rNd.GetSwAttrSet().GetPool(),
401 RES_CHRATR_BEGIN, RES_TXTATR_END - 1);
403 //The hard formatting properties that affect the entire paragraph
404 if (rNd.HasSwAttrSet())
406 sal_Bool bDeep = sal_False;
407 // only copy hard attributes - bDeep = false
408 aExportSet.Set(rNd.GetSwAttrSet(), bDeep);
409 // get the current font item. Use rNd.GetSwAttrSet instead of aExportSet:
410 const SvxFontItem &rNdFont = ItemGet<SvxFontItem>(rNd.GetSwAttrSet(), nFontId);
411 pFont = &rNdFont;
412 aExportSet.ClearItem(nFontId);
415 //The additional hard formatting properties that affect this range in the
416 //paragraph
417 sw::PoolItems aRangeItems;
418 if (const SwpHints* pTxtAttrs = rNd.GetpSwpHints())
420 for (xub_StrLen i = 0; i < pTxtAttrs->Count(); ++i)
422 const SwTxtAttr* pHt = (*pTxtAttrs)[i];
423 const xub_StrLen* pEnd = pHt->GetEnd();
425 if (pEnd ? ( nSwPos >= *pHt->GetStart() && nSwPos < *pEnd)
426 : nSwPos == *pHt->GetStart() )
428 sal_uInt16 nWhich = pHt->GetAttr().Which();
429 if (nWhich == RES_TXTATR_AUTOFMT)
431 const SwFmtAutoFmt& rAutoFmt = static_cast<const SwFmtAutoFmt&>(pHt->GetAttr());
432 const boost::shared_ptr<SfxItemSet> pSet = rAutoFmt.GetStyleHandle();
433 SfxWhichIter aIter( *pSet );
434 const SfxPoolItem* pItem;
435 sal_uInt16 nWhichId = aIter.FirstWhich();
436 while( nWhichId )
438 if( SFX_ITEM_SET == pSet->GetItemState( nWhichId, sal_False, &pItem ))
440 if (nWhichId == nFontId)
441 pFont = &(item_cast<SvxFontItem>(*pItem));
442 else
443 aRangeItems[nWhichId] = pItem;
445 nWhichId = aIter.NextWhich();
448 else
449 aRangeItems[nWhich] = (&(pHt->GetAttr()));
451 else if (nSwPos < *pHt->GetStart())
452 break;
457 For #i24291# we need to explictly remove any properties from the
458 aExportSet which a SwCharFmt would override, we can't rely on word doing
459 this for us like writer does
461 const SwFmtCharFmt *pCharFmtItem =
462 HasItem< SwFmtCharFmt >( aRangeItems, RES_TXTATR_CHARFMT );
463 if ( pCharFmtItem )
464 ClearOverridesFromSet( *pCharFmtItem, aExportSet );
466 sw::PoolItems aExportItems;
467 GetPoolItems( aExportSet, aExportItems, false );
469 sw::cPoolItemIter aEnd = aRangeItems.end();
470 for ( sw::cPoolItemIter aI = aRangeItems.begin(); aI != aEnd; ++aI )
472 if ( !bRuby || !lcl_isFontsizeItem( *aI->second ) )
473 aExportItems[aI->first] = aI->second;
476 if ( !aExportItems.empty() )
478 const SwModify* pOldMod = m_rExport.pOutFmtNode;
479 m_rExport.pOutFmtNode = &rNd;
480 m_rExport.m_aCurrentCharPropStarts.push( nSwPos );
482 m_rExport.ExportPoolItemsToCHP( aExportItems, GetScript() );
484 // HasTextItem only allowed in the above range
485 m_rExport.m_aCurrentCharPropStarts.pop();
486 m_rExport.pOutFmtNode = pOldMod;
489 OSL_ENSURE( pFont, "must be *some* font associated with this txtnode" );
490 if ( pFont )
492 SvxFontItem aFont( *pFont );
495 If we are a nonunicode aware format then we set the charset we want to
496 use for export of this range. If necessary this will generate a pseudo
497 font to use for this range.
499 So now we are guaranteed to have a font with the correct charset set
500 for WW6/95 which will match the script we have exported this range in,
501 this makes older nonunicode aware versions of word display the correct
502 characters.
504 if ( !m_rExport.SupportsUnicode() )
505 aFont.SetCharSet( GetCharSet() );
507 if ( rParentFont != aFont )
508 m_rExport.AttrOutput().OutputItem( aFont );
512 void SwWW8AttrIter::OutFlys(xub_StrLen nSwPos)
515 #i2916#
516 May have an anchored graphic to be placed, loop through sorted array
517 and output all at this position
519 while ( maFlyIter != maFlyFrms.end() )
521 const SwPosition &rAnchor = maFlyIter->GetPosition();
522 xub_StrLen nPos = rAnchor.nContent.GetIndex();
524 if ( nPos != nSwPos )
525 break;
526 else
528 m_rExport.AttrOutput().OutputFlyFrame( *maFlyIter );
529 ++maFlyIter;
534 bool SwWW8AttrIter::IsTxtAttr( xub_StrLen nSwPos )
536 // search for attrs with CH_TXTATR
537 if (const SwpHints* pTxtAttrs = rNd.GetpSwpHints())
539 for (sal_uInt16 i = 0; i < pTxtAttrs->Count(); ++i)
541 const SwTxtAttr* pHt = (*pTxtAttrs)[i];
542 if ( pHt->HasDummyChar() && (*pHt->GetStart() == nSwPos) )
543 return true;
547 return false;
550 bool SwWW8AttrIter::IsDropCap( int nSwPos )
552 // see if the current position falls on a DropCap
553 int nDropChars = mrSwFmtDrop.GetChars();
554 bool bWholeWord = mrSwFmtDrop.GetWholeWord();
555 if (bWholeWord)
557 short nWordLen = rNd.GetDropLen(0);
558 if(nSwPos == nWordLen && nSwPos != 0)
559 return true;
561 else
563 if (nSwPos == nDropChars && nSwPos != 0)
564 return true;
566 return false;
569 bool SwWW8AttrIter::RequiresImplicitBookmark()
571 SwImplBookmarksIter bkmkIterEnd = m_rExport.maImplicitBookmarks.end();
572 for ( SwImplBookmarksIter aIter = m_rExport.maImplicitBookmarks.begin(); aIter != bkmkIterEnd; ++aIter )
574 sal_uLong sample = aIter->second;
576 if ( sample == rNd.GetIndex() )
577 return true;
579 return false;
582 //HasItem is for the summary of the double attributes: Underline and WordlineMode as TextItems.
583 // OutAttr () calls the output function, which can call HasItem() for other items at the attribute's start position.
584 // Only attributes with end can be queried.
585 // It searches with bDeep
586 const SfxPoolItem* SwWW8AttrIter::HasTextItem( sal_uInt16 nWhich ) const
588 const SfxPoolItem* pRet = 0;
589 const SwpHints* pTxtAttrs = rNd.GetpSwpHints();
591 if (pTxtAttrs && !m_rExport.m_aCurrentCharPropStarts.empty())
593 xub_StrLen nTmpSwPos = m_rExport.m_aCurrentCharPropStarts.top();
594 for (sal_uInt16 i = 0; i < pTxtAttrs->Count(); ++i)
596 const SwTxtAttr* pHt = (*pTxtAttrs)[i];
597 const SfxPoolItem* pItem = &pHt->GetAttr();
598 const xub_StrLen* pAtrEnd = 0;
599 if( 0 != ( pAtrEnd = pHt->GetEnd() ) && // only Attr with an end
600 nWhich == pItem->Which() &&
601 nTmpSwPos >= *pHt->GetStart() && nTmpSwPos < *pAtrEnd )
603 pRet = pItem; // found it
604 break;
606 else if (nTmpSwPos < *pHt->GetStart())
607 break; // nothing more to come
610 return pRet;
613 void WW8Export::GetCurrentItems(ww::bytes &rItems) const
615 rItems.insert(rItems.end(), pO->begin(), pO->end());
618 const SfxPoolItem& SwWW8AttrIter::GetItem(sal_uInt16 nWhich) const
620 const SfxPoolItem* pRet = HasTextItem(nWhich);
621 return pRet ? *pRet : rNd.SwCntntNode::GetAttr(nWhich);
624 void WW8AttributeOutput::StartRuby( const SwTxtNode& rNode, xub_StrLen /*nPos*/, const SwFmtRuby& rRuby )
626 String aStr( FieldString( ww::eEQ ) );
627 aStr.AppendAscii( "\\* jc" );
628 sal_Int32 nJC = 0;
629 sal_Char cDirective = 0;
630 switch ( rRuby.GetAdjustment() )
632 case 0:
633 nJC = 3;
634 cDirective = 'l';
635 break;
636 case 1:
637 //defaults to 0
638 break;
639 case 2:
640 nJC = 4;
641 cDirective = 'r';
642 break;
643 case 3:
644 nJC = 1;
645 cDirective = 'd';
646 break;
647 case 4:
648 nJC = 2;
649 cDirective = 'd';
650 break;
651 default:
652 OSL_ENSURE( !this,"Unhandled Ruby justication code" );
653 break;
655 aStr += OUString::number( nJC );
658 MS needs to know the name and size of the font used in the ruby item,
659 but we coud have written it in a mixture of asian and western
660 scripts, and each of these can be a different font and size than the
661 other, so we make a guess based upon the first character of the text,
662 defaulting to asian.
664 sal_uInt16 nRubyScript;
665 if( g_pBreakIt->GetBreakIter().is() )
666 nRubyScript = g_pBreakIt->GetBreakIter()->getScriptType( rRuby.GetText(), 0);
667 else
668 nRubyScript = i18n::ScriptType::ASIAN;
670 const SwTxtRuby* pRubyTxt = rRuby.GetTxtRuby();
671 const SwCharFmt* pFmt = pRubyTxt ? pRubyTxt->GetCharFmt() : 0;
672 String sFamilyName;
673 long nHeight;
674 if ( pFmt )
676 const SvxFontItem &rFont = ItemGet< SvxFontItem >( *pFmt,
677 GetWhichOfScript(RES_CHRATR_FONT,nRubyScript) );
678 sFamilyName = rFont.GetFamilyName();
680 const SvxFontHeightItem &rHeight = ItemGet< SvxFontHeightItem >( *pFmt,
681 GetWhichOfScript( RES_CHRATR_FONTSIZE, nRubyScript ) );
682 nHeight = rHeight.GetHeight();
684 else
686 /*Get defaults if no formatting on ruby text*/
688 const SfxItemPool *pPool = rNode.GetSwAttrSet().GetPool();
689 pPool = pPool ? pPool : &m_rWW8Export.pDoc->GetAttrPool();
691 const SvxFontItem &rFont = DefaultItemGet< SvxFontItem >( *pPool,
692 GetWhichOfScript( RES_CHRATR_FONT,nRubyScript ) );
693 sFamilyName = rFont.GetFamilyName();
695 const SvxFontHeightItem &rHeight = DefaultItemGet< SvxFontHeightItem >
696 ( *pPool, GetWhichOfScript( RES_CHRATR_FONTSIZE, nRubyScript ) );
697 nHeight = rHeight.GetHeight();
699 nHeight = (nHeight + 5)/10;
701 aStr.AppendAscii( " \\* \"Font:" );
702 aStr.Append( sFamilyName );
703 aStr.AppendAscii( "\" \\* hps" );
704 aStr += OUString::number( nHeight );
705 aStr.AppendAscii( " \\o" );
706 if ( cDirective )
708 aStr.AppendAscii( "\\a" );
709 aStr.Append( cDirective );
711 aStr.AppendAscii( "(\\s\\up " );
714 if ( g_pBreakIt->GetBreakIter().is() )
715 nRubyScript = g_pBreakIt->GetBreakIter()->getScriptType( rNode.GetTxt(),
716 *( pRubyTxt->GetStart() ) );
717 else
718 nRubyScript = i18n::ScriptType::ASIAN;
720 const SwAttrSet& rSet = rNode.GetSwAttrSet();
721 const SvxFontHeightItem &rHeightItem =
722 ( const SvxFontHeightItem& )rSet.Get(
723 GetWhichOfScript( RES_CHRATR_FONTSIZE, nRubyScript ) );
724 nHeight = (rHeightItem.GetHeight() + 10)/20-1;
725 aStr += OUString::number(nHeight);
726 aStr += '(';
727 aStr += rRuby.GetText();
728 aStr.AppendAscii( ")" );
730 // The parameter separator depends on the FIB.lid
731 if ( m_rWW8Export.pFib->getNumDecimalSep() == '.' )
732 aStr.AppendAscii( "," );
733 else
734 aStr.AppendAscii( ";" );
736 m_rWW8Export.OutputField( 0, ww::eEQ, aStr,
737 WRITEFIELD_START | WRITEFIELD_CMD_START );
740 void WW8AttributeOutput::EndRuby()
742 m_rWW8Export.WriteChar( ')' );
743 m_rWW8Export.OutputField( 0, ww::eEQ, aEmptyStr, WRITEFIELD_END | WRITEFIELD_CLOSE );
746 /*#i15387# Better ideas welcome*/
747 String &TruncateBookmark( String &rRet )
749 if ( rRet.Len() > 40 )
750 rRet.Erase( 40 );
751 OSL_ENSURE( rRet.Len() <= 40, "Word cannot have bookmarks longer than 40 chars" );
752 return rRet;
755 bool AttributeOutputBase::AnalyzeURL( const String& rUrl, const String& /*rTarget*/, String* pLinkURL, String* pMark )
757 bool bBookMarkOnly = false;
759 INetURLObject aURL( rUrl );
760 String sMark;
761 String sURL;
763 if ( rUrl.Len() > 1 && rUrl.GetChar(0) == INET_MARK_TOKEN )
765 sMark = BookmarkToWriter( rUrl.Copy(1) );
767 xub_StrLen nPos = sMark.SearchBackward( cMarkSeparator );
769 String sRefType(comphelper::string::remove(sMark.Copy(nPos+1), ' '));
771 // #i21465# Only interested in outline references
772 if ( sRefType.EqualsAscii( pMarkToOutline ) )
774 String sLink = sMark.Copy(0, nPos);
775 SwImplBookmarksIter bkmkIterEnd = GetExport().maImplicitBookmarks.end();
776 for ( SwImplBookmarksIter aIter = GetExport().maImplicitBookmarks.begin(); aIter != bkmkIterEnd; ++aIter )
778 String bkmkName = aIter->first;
780 if ( bkmkName == sLink )
782 sMark = String( "_toc" );
783 sMark += OUString::number( aIter->second );
788 else
790 sURL = aURL.GetURLNoMark( INetURLObject::DECODE_UNAMBIGUOUS );
791 sMark = aURL.GetMark( INetURLObject::DECODE_UNAMBIGUOUS );
795 if ( sMark.Len() && !sURL.Len() )
796 bBookMarkOnly = true;
800 *pMark = sMark;
801 *pLinkURL = sURL;
802 return bBookMarkOnly;
805 bool WW8AttributeOutput::AnalyzeURL( const String& rUrl, const String& rTarget, String* pLinkURL, String* pMark )
807 bool bBookMarkOnly = AttributeOutputBase::AnalyzeURL( rUrl, rTarget, pLinkURL, pMark );
809 String sURL = *pLinkURL;
810 String sMark = *pMark;
812 if ( sURL.Len() )
813 sURL = URIHelper::simpleNormalizedMakeRelative( m_rWW8Export.GetWriter().GetBaseURL(), sURL );
815 if ( bBookMarkOnly )
816 sURL = FieldString( ww::eHYPERLINK );
817 else
819 String sFld( FieldString( ww::eHYPERLINK ) );
820 sFld.AppendAscii( "\"" );
821 sURL.Insert( sFld, 0 );
822 sURL += '\"';
825 if ( sMark.Len() )
826 ( ( sURL.AppendAscii( " \\l \"" ) ) += sMark ) += '\"';
828 if ( rTarget.Len() )
829 ( sURL.AppendAscii( " \\n " ) ) += rTarget;
831 *pLinkURL = sURL;
832 *pMark = sMark;
834 return bBookMarkOnly;
837 bool WW8AttributeOutput::StartURL( const String &rUrl, const String &rTarget )
839 // hyperlinks only in WW8
840 if ( !m_rWW8Export.bWrtWW8 )
841 return false;
843 INetURLObject aURL( rUrl );
844 String sURL;
845 String sMark;
847 bool bBookMarkOnly = AnalyzeURL( rUrl, rTarget, &sURL, &sMark );
850 m_rWW8Export.OutputField( 0, ww::eHYPERLINK, sURL, WRITEFIELD_START | WRITEFIELD_CMD_START );
852 // write the refence to the "picture" structure
853 sal_uLong nDataStt = m_rWW8Export.pDataStrm->Tell();
854 m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell() );
856 // WinWord 2000 doesn't write this - so its a temp solution by W97 ?
857 m_rWW8Export.WriteChar( 0x01 );
859 static sal_uInt8 aArr1[] = {
860 0x03, 0x6a, 0,0,0,0, // sprmCPicLocation
862 0x06, 0x08, 0x01, // sprmCFData
863 0x55, 0x08, 0x01, // sprmCFSpec
864 0x02, 0x08, 0x01 // sprmCFFldVanish
866 sal_uInt8* pDataAdr = aArr1 + 2;
867 Set_UInt32( pDataAdr, nDataStt );
869 m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), sizeof( aArr1 ), aArr1 );
871 m_rWW8Export.OutputField( 0, ww::eHYPERLINK, sURL, WRITEFIELD_CMD_END );
873 // now write the picture structur
874 sURL = aURL.GetURLNoMark();
876 // Compare the URL written by AnalyzeURL with the original one to see if
877 // the output URL is absolute or relative.
878 String sRelativeURL;
879 if ( rUrl.Len() )
880 sRelativeURL = URIHelper::simpleNormalizedMakeRelative( m_rWW8Export.GetWriter().GetBaseURL(), rUrl );
881 bool bAbsolute = sRelativeURL.Equals( rUrl );
883 static sal_uInt8 aURLData1[] = {
884 0,0,0,0, // len of struct
885 0x44,0, // the start of "next" data
886 0,0,0,0,0,0,0,0,0,0, // PIC-Structure!
887 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // |
888 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // |
889 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // |
890 0,0,0,0, // /
892 static sal_uInt8 MAGIC_A[] = {
893 // start of "next" data
894 0xD0,0xC9,0xEA,0x79,0xF9,0xBA,0xCE,0x11,
895 0x8C,0x82,0x00,0xAA,0x00,0x4B,0xA9,0x0B
898 m_rWW8Export.pDataStrm->Write( aURLData1, sizeof( aURLData1 ) );
899 /* Write HFD Structure */
900 sal_uInt8 nAnchor = 0x00;
901 if ( sMark.Len() )
902 nAnchor = 0x08;
903 m_rWW8Export.pDataStrm->Write( &nAnchor, 1 ); // HFDBits
904 m_rWW8Export.pDataStrm->Write( MAGIC_A, sizeof(MAGIC_A) ); //clsid
906 /* Write Hyperlink Object see [MS-OSHARED] spec*/
907 SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, 0x00000002);
908 sal_uInt32 nFlag = bBookMarkOnly ? 0 : 0x01;
909 if ( bAbsolute )
910 nFlag |= 0x02;
911 if ( sMark.Len() )
912 nFlag |= 0x08;
913 SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, nFlag );
915 INetProtocol eProto = aURL.GetProtocol();
916 if ( eProto == INET_PROT_FILE || eProto == INET_PROT_SMB )
918 // version 1 (for a document)
920 static sal_uInt8 MAGIC_C[] = {
921 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
922 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46,
923 0x00, 0x00
926 static sal_uInt8 MAGIC_D[] = {
927 0xFF, 0xFF, 0xAD, 0xDE, 0x00, 0x00, 0x00, 0x00,
928 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
929 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
932 // save the links to files as relative
933 sURL = URIHelper::simpleNormalizedMakeRelative( m_rWW8Export.GetWriter().GetBaseURL(), sURL );
934 if ( eProto == INET_PROT_FILE && sURL.EqualsAscii( "/", 0, 1 ) )
935 sURL = aURL.PathToFileName();
937 // special case for the absolute windows names
938 // (convert '/c:/foo/bar.doc' into 'c:\foo\bar.doc')
939 sal_Unicode aDrive = ( sURL.Len() > 1 )? sURL.GetChar( 1 ): 0;
940 if ( sURL.EqualsAscii( "/", 0, 1 ) &&
941 ( ( aDrive >= 'A' && aDrive <= 'Z' ) || ( aDrive >= 'a' && aDrive <= 'z' ) ) &&
942 sURL.EqualsAscii( ":", 2, 1 ) )
944 sURL.Erase( 0, 1 );
945 sURL.SearchAndReplaceAll( '/', '\\' );
948 // n#261623 convert smb notation to '\\'
949 const char pSmb[] = "smb://";
950 if ( eProto == INET_PROT_SMB &&
951 sURL.EqualsAscii( pSmb, 0, sizeof( pSmb ) - 1 ) )
953 sURL.Erase( 0, sizeof( pSmb ) - 3 );
954 sURL.SearchAndReplaceAll( '/', '\\' );
957 m_rWW8Export.pDataStrm->Write( MAGIC_C, sizeof(MAGIC_C) );
958 SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, sURL.Len()+1 );
959 SwWW8Writer::WriteString8( *m_rWW8Export.pDataStrm, sURL, true,
960 RTL_TEXTENCODING_MS_1252 );
961 m_rWW8Export.pDataStrm->Write( MAGIC_D, sizeof( MAGIC_D ) );
963 SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, 2*sURL.Len() + 6 );
964 SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, 2*sURL.Len() );
965 SwWW8Writer::WriteShort( *m_rWW8Export.pDataStrm, 3 );
966 SwWW8Writer::WriteString16( *m_rWW8Export.pDataStrm, sURL, false );
968 else if ( eProto != INET_PROT_NOT_VALID )
970 // version 2 (simple url)
971 // an write some data to the data stream, but dont ask
972 // what the data mean, except for the URL.
973 // The First piece is the WW8_PIC structure.
974 static sal_uInt8 MAGIC_B[] = {
975 0xE0,0xC9,0xEA,0x79,0xF9,0xBA,0xCE,0x11,
976 0x8C,0x82,0x00,0xAA,0x00,0x4B,0xA9,0x0B
979 m_rWW8Export.pDataStrm->Write( MAGIC_B, sizeof(MAGIC_B) );
980 SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, 2 * ( sURL.Len() + 1 ) );
981 SwWW8Writer::WriteString16( *m_rWW8Export.pDataStrm, sURL, true );
984 if ( sMark.Len() )
986 SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, sMark.Len()+1 );
987 SwWW8Writer::WriteString16( *m_rWW8Export.pDataStrm, sMark, true );
989 SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, nDataStt,
990 m_rWW8Export.pDataStrm->Tell() - nDataStt );
992 return true;
995 bool WW8AttributeOutput::EndURL()
997 // hyperlinks only in WW8
998 if ( !m_rWW8Export.bWrtWW8 )
999 return false;
1001 m_rWW8Export.OutputField( 0, ww::eHYPERLINK, aEmptyStr, WRITEFIELD_CLOSE );
1003 return true;
1006 String BookmarkToWord(const String &rBookmark)
1008 String sRet(INetURLObject::encode(rBookmark,
1009 INetURLObject::PART_REL_SEGMENT_EXTRA, '%',
1010 INetURLObject::ENCODE_ALL, RTL_TEXTENCODING_ASCII_US));
1011 return TruncateBookmark(sRet);
1014 String BookmarkToWriter(const String &rBookmark)
1016 return INetURLObject::decode(rBookmark, '%',
1017 INetURLObject::DECODE_UNAMBIGUOUS, RTL_TEXTENCODING_ASCII_US);
1020 void SwWW8AttrIter::OutSwFmtRefMark(const SwFmtRefMark& rAttr, bool)
1022 if ( m_rExport.HasRefToObject( REF_SETREFATTR, &rAttr.GetRefName(), 0 ) )
1023 m_rExport.AppendBookmark( m_rExport.GetBookmarkName( REF_SETREFATTR,
1024 &rAttr.GetRefName(), 0 ));
1027 void WW8AttributeOutput::FieldVanish( const String& rTxt, ww::eField /*eType*/ )
1029 ww::bytes aItems;
1030 m_rWW8Export.GetCurrentItems( aItems );
1032 // sprmCFFldVanish
1033 if ( m_rWW8Export.bWrtWW8 )
1034 SwWW8Writer::InsUInt16( aItems, NS_sprm::LN_CFFldVanish );
1035 else
1036 aItems.push_back( 67 );
1037 aItems.push_back( 1 );
1039 sal_uInt16 nStt_sprmCFSpec = aItems.size();
1041 // sprmCFSpec -- fSpec-Attribut true
1042 if ( m_rWW8Export.bWrtWW8 )
1043 SwWW8Writer::InsUInt16( aItems, 0x855 );
1044 else
1045 aItems.push_back( 117 );
1046 aItems.push_back( 1 );
1048 m_rWW8Export.WriteChar( '\x13' );
1049 m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), aItems.size(),
1050 aItems.data() );
1051 m_rWW8Export.OutSwString( rTxt, 0, rTxt.Len(), m_rWW8Export.IsUnicode(),
1052 RTL_TEXTENCODING_MS_1252 );
1053 m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), nStt_sprmCFSpec,
1054 aItems.data() );
1055 m_rWW8Export.WriteChar( '\x15' );
1056 m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), aItems.size(),
1057 aItems.data() );
1060 void AttributeOutputBase::TOXMark( const SwTxtNode& rNode, const SwTOXMark& rAttr )
1062 // its a field; so get the Text form the Node and build the field
1063 String sTxt;
1064 ww::eField eType = ww::eNONE;
1066 const SwTxtTOXMark& rTxtTOXMark = *rAttr.GetTxtTOXMark();
1067 const xub_StrLen* pTxtEnd = rTxtTOXMark.GetEnd();
1068 if ( pTxtEnd ) // has range?
1070 sTxt = rNode.GetExpandTxt( *rTxtTOXMark.GetStart(),
1071 *pTxtEnd - *rTxtTOXMark.GetStart() );
1073 else
1074 sTxt = rAttr.GetAlternativeText();
1076 switch ( rAttr.GetTOXType()->GetType() )
1078 case TOX_INDEX:
1079 eType = ww::eXE;
1080 if ( rAttr.GetPrimaryKey().Len() )
1082 if ( rAttr.GetSecondaryKey().Len() )
1084 sTxt.Insert( ':', 0 );
1085 sTxt.Insert( rAttr.GetSecondaryKey(), 0 );
1088 sTxt.Insert( ':', 0 );
1089 sTxt.Insert( rAttr.GetPrimaryKey(), 0 );
1091 sTxt.InsertAscii( " XE \"", 0 );
1092 sTxt.InsertAscii( "\" " );
1093 break;
1095 case TOX_USER:
1096 ( sTxt.AppendAscii( "\" \\f \"" ) )
1097 += (sal_Char)( 'A' + GetExport( ).GetId( *rAttr.GetTOXType() ) );
1098 // fall through - no break;
1099 case TOX_CONTENT:
1101 eType = ww::eTC;
1102 sTxt.InsertAscii( " TC \"", 0 );
1103 sal_uInt16 nLvl = rAttr.GetLevel();
1104 if (nLvl > WW8ListManager::nMaxLevel)
1105 nLvl = WW8ListManager::nMaxLevel;
1107 ((sTxt.AppendAscii( "\" \\l " ))
1108 += OUString::number( nLvl )) += ' ';
1110 break;
1111 default:
1112 OSL_ENSURE( !this, "Unhandled option for toc export" );
1113 break;
1116 if ( sTxt.Len() )
1117 FieldVanish( sTxt, eType );
1120 int SwWW8AttrIter::OutAttrWithRange(xub_StrLen nPos)
1122 int nRet = 0;
1123 if ( const SwpHints* pTxtAttrs = rNd.GetpSwpHints() )
1125 m_rExport.m_aCurrentCharPropStarts.push( nPos );
1126 const xub_StrLen* pEnd;
1127 for ( sal_uInt16 i = 0; i < pTxtAttrs->Count(); ++i )
1129 const SwTxtAttr* pHt = (*pTxtAttrs)[i];
1130 const SfxPoolItem* pItem = &pHt->GetAttr();
1131 switch ( pItem->Which() )
1133 case RES_TXTATR_INETFMT:
1134 if ( nPos == *pHt->GetStart() )
1136 const SwFmtINetFmt *rINet = static_cast< const SwFmtINetFmt* >( pItem );
1137 if ( m_rExport.AttrOutput().StartURL( rINet->GetValue(), rINet->GetTargetFrame() ) )
1138 ++nRet;
1140 if ( 0 != ( pEnd = pHt->GetEnd() ) && nPos == *pEnd )
1142 if ( m_rExport.AttrOutput().EndURL() )
1143 --nRet;
1145 break;
1146 case RES_TXTATR_REFMARK:
1147 if ( nPos == *pHt->GetStart() )
1149 OutSwFmtRefMark( *static_cast< const SwFmtRefMark* >( pItem ), true );
1150 ++nRet;
1152 if ( 0 != ( pEnd = pHt->GetEnd() ) && nPos == *pEnd )
1154 OutSwFmtRefMark( *static_cast< const SwFmtRefMark* >( pItem ), false );
1155 --nRet;
1157 break;
1158 case RES_TXTATR_TOXMARK:
1159 if ( nPos == *pHt->GetStart() )
1160 m_rExport.AttrOutput().TOXMark( rNd, *static_cast< const SwTOXMark* >( pItem ) );
1161 break;
1162 case RES_TXTATR_CJK_RUBY:
1163 if ( nPos == *pHt->GetStart() )
1165 m_rExport.AttrOutput().StartRuby( rNd, nPos, *static_cast< const SwFmtRuby* >( pItem ) );
1166 ++nRet;
1168 if ( 0 != ( pEnd = pHt->GetEnd() ) && nPos == *pEnd )
1170 m_rExport.AttrOutput().EndRuby();
1171 --nRet;
1173 break;
1176 m_rExport.m_aCurrentCharPropStarts.pop(); // HasTextItem only allowed in the above range
1178 return nRet;
1181 bool SwWW8AttrIter::IsRedlineAtEnd( xub_StrLen nEnd ) const
1183 bool bRet = false;
1184 // search next Redline
1185 for( sal_uInt16 nPos = nCurRedlinePos;
1186 nPos < m_rExport.pDoc->GetRedlineTbl().size(); ++nPos )
1188 const SwPosition* pEnd = m_rExport.pDoc->GetRedlineTbl()[ nPos ]->End();
1189 if( pEnd->nNode == rNd )
1191 if( pEnd->nContent.GetIndex() == nEnd )
1193 bRet = true;
1194 break;
1197 else
1198 break;
1200 return bRet;
1203 const SwRedlineData* SwWW8AttrIter::GetRedline( xub_StrLen nPos )
1205 if( pCurRedline )
1207 const SwPosition* pEnd = pCurRedline->End();
1208 if( pEnd->nNode == rNd &&
1209 pEnd->nContent.GetIndex() <= nPos )
1211 pCurRedline = 0;
1212 ++nCurRedlinePos;
1214 else
1216 // write data of current redline
1217 return &( pCurRedline->GetRedlineData() );
1221 if( !pCurRedline )
1223 // search next Redline
1224 for( ; nCurRedlinePos < m_rExport.pDoc->GetRedlineTbl().size();
1225 ++nCurRedlinePos )
1227 const SwRedline* pRedl = m_rExport.pDoc->GetRedlineTbl()[ nCurRedlinePos ];
1229 const SwPosition* pStt = pRedl->Start();
1230 const SwPosition* pEnd = pStt == pRedl->GetPoint()
1231 ? pRedl->GetMark()
1232 : pRedl->GetPoint();
1234 if( pStt->nNode == rNd )
1236 if( pStt->nContent.GetIndex() >= nPos )
1238 if( pStt->nContent.GetIndex() == nPos )
1240 // write data of this redline
1241 pCurRedline = pRedl;
1242 return &( pCurRedline->GetRedlineData() );
1244 break;
1247 else
1248 break;
1250 if( pEnd->nNode == rNd &&
1251 pEnd->nContent.GetIndex() < nPos )
1253 pCurRedline = pRedl;
1254 break;
1258 return NULL;
1262 short MSWordExportBase::GetCurrentPageDirection() const
1264 const SwFrmFmt &rFmt = pAktPageDesc
1265 ? pAktPageDesc->GetMaster()
1266 : pDoc->GetPageDesc( 0 ).GetMaster();
1267 return rFmt.GetFrmDir().GetValue();
1270 short MSWordExportBase::GetDefaultFrameDirection( ) const
1272 short nDir = FRMDIR_ENVIRONMENT;
1274 if ( bOutPageDescs )
1275 nDir = GetCurrentPageDirection( );
1276 else if ( pOutFmtNode )
1278 if ( bOutFlyFrmAttrs ) //frame
1280 nDir = TrueFrameDirection( *( const SwFrmFmt * ) pOutFmtNode );
1282 else if ( pOutFmtNode->ISA( SwCntntNode ) ) //pagagraph
1284 const SwCntntNode *pNd = ( const SwCntntNode * ) pOutFmtNode;
1285 SwPosition aPos( *pNd );
1286 nDir = pDoc->GetTextDirection( aPos );
1288 else if ( pOutFmtNode->ISA( SwTxtFmtColl ) )
1289 nDir = FRMDIR_HORI_LEFT_TOP; //what else can we do :-(
1292 if ( nDir == FRMDIR_ENVIRONMENT )
1293 nDir = FRMDIR_HORI_LEFT_TOP; //Set something
1295 return nDir;
1298 short MSWordExportBase::TrueFrameDirection( const SwFrmFmt &rFlyFmt ) const
1300 const SwFrmFmt *pFlyFmt = &rFlyFmt;
1301 const SvxFrameDirectionItem* pItem = 0;
1302 while ( pFlyFmt )
1304 pItem = &pFlyFmt->GetFrmDir();
1305 if ( FRMDIR_ENVIRONMENT == pItem->GetValue() )
1307 pItem = 0;
1308 const SwFmtAnchor* pAnchor = &pFlyFmt->GetAnchor();
1309 if ((FLY_AT_PAGE != pAnchor->GetAnchorId()) &&
1310 pAnchor->GetCntntAnchor() )
1312 pFlyFmt = pAnchor->GetCntntAnchor()->nNode.GetNode().GetFlyFmt();
1314 else
1315 pFlyFmt = 0;
1317 else
1318 pFlyFmt = 0;
1321 short nRet;
1322 if ( pItem )
1323 nRet = pItem->GetValue();
1324 else
1325 nRet = GetCurrentPageDirection();
1327 OSL_ENSURE( nRet != FRMDIR_ENVIRONMENT, "leaving with environment direction" );
1328 return nRet;
1331 const SvxBrushItem* WW8Export::GetCurrentPageBgBrush() const
1333 const SwFrmFmt &rFmt = pAktPageDesc
1334 ? pAktPageDesc->GetMaster()
1335 : pDoc->GetPageDesc(0).GetMaster();
1337 const SfxPoolItem* pItem = 0;
1338 //If not set, or "no fill", get real bg
1339 SfxItemState eState = rFmt.GetItemState(RES_BACKGROUND, true, &pItem);
1341 const SvxBrushItem* pRet = (const SvxBrushItem*)pItem;
1342 if (SFX_ITEM_SET != eState || (!pRet->GetGraphic() &&
1343 pRet->GetColor() == COL_TRANSPARENT))
1345 pRet = &(DefaultItemGet<SvxBrushItem>(*pDoc,RES_BACKGROUND));
1347 return pRet;
1350 SvxBrushItem WW8Export::TrueFrameBgBrush(const SwFrmFmt &rFlyFmt) const
1352 const SwFrmFmt *pFlyFmt = &rFlyFmt;
1353 const SvxBrushItem* pRet = 0;
1355 while (pFlyFmt)
1357 //If not set, or "no fill", get real bg
1358 const SfxPoolItem* pItem = 0;
1359 SfxItemState eState =
1360 pFlyFmt->GetItemState(RES_BACKGROUND, true, &pItem);
1361 pRet = (const SvxBrushItem*)pItem;
1362 if (SFX_ITEM_SET != eState || (!pRet->GetGraphic() &&
1363 pRet->GetColor() == COL_TRANSPARENT))
1365 pRet = 0;
1366 const SwFmtAnchor* pAnchor = &pFlyFmt->GetAnchor();
1367 if ((FLY_AT_PAGE != pAnchor->GetAnchorId()) &&
1368 pAnchor->GetCntntAnchor())
1370 pFlyFmt =
1371 pAnchor->GetCntntAnchor()->nNode.GetNode().GetFlyFmt();
1373 else
1374 pFlyFmt = 0;
1376 else
1377 pFlyFmt = 0;
1380 if (!pRet)
1381 pRet = GetCurrentPageBgBrush();
1383 const Color aTmpColor( COL_WHITE );
1384 SvxBrushItem aRet( aTmpColor, RES_BACKGROUND );
1385 if (pRet && (pRet->GetGraphic() ||( pRet->GetColor() != COL_TRANSPARENT)))
1386 aRet = *pRet;
1388 return aRet;
1393 Convert characters that need to be converted, the basic replacements and the
1394 ridicously complicated title case attribute mapping to hardcoded upper case
1395 because word doesn't have the feature
1397 String SwWW8AttrIter::GetSnippet(const String &rStr, xub_StrLen nAktPos,
1398 xub_StrLen nLen) const
1400 String aSnippet(rStr, nAktPos, nLen);
1401 if (!nLen)
1402 return aSnippet;
1404 // 0x0a ( Hard Line Break ) -> 0x0b
1405 // 0xad ( soft hyphen ) -> 0x1f
1406 // 0x2011 ( hard hyphen ) -> 0x1e
1407 aSnippet.SearchAndReplaceAll(0x0A, 0x0B);
1408 aSnippet.SearchAndReplaceAll(CHAR_HARDHYPHEN, 0x1e);
1409 aSnippet.SearchAndReplaceAll(CHAR_SOFTHYPHEN, 0x1f);
1411 m_rExport.m_aCurrentCharPropStarts.push( nAktPos );
1412 const SfxPoolItem &rItem = GetItem(RES_CHRATR_CASEMAP);
1414 if (SVX_CASEMAP_TITEL == ((const SvxCaseMapItem&)rItem).GetValue())
1416 sal_uInt16 nScriptType = i18n::ScriptType::LATIN;
1417 if (g_pBreakIt->GetBreakIter().is())
1418 nScriptType = g_pBreakIt->GetBreakIter()->getScriptType(aSnippet, 0);
1420 LanguageType nLanguage;
1421 switch (nScriptType)
1423 case i18n::ScriptType::ASIAN:
1424 nLanguage = ((const SvxLanguageItem&)GetItem(RES_CHRATR_CJK_LANGUAGE)).GetLanguage();
1425 break;
1426 case i18n::ScriptType::COMPLEX:
1427 nLanguage = ((const SvxLanguageItem&)GetItem(RES_CHRATR_CTL_LANGUAGE)).GetLanguage();
1428 break;
1429 case i18n::ScriptType::LATIN:
1430 default:
1431 nLanguage = ((const SvxLanguageItem&)GetItem(RES_CHRATR_LANGUAGE)).GetLanguage();
1432 break;
1435 SvxFont aFontHelper;
1436 aFontHelper.SetCaseMap(SVX_CASEMAP_TITEL);
1437 aFontHelper.SetLanguage(nLanguage);
1438 aSnippet = aFontHelper.CalcCaseMap(aSnippet);
1440 //If we weren't at the begin of a word undo the case change.
1441 //not done before doing the casemap because the sequence might start
1442 //with whitespace
1443 if (g_pBreakIt->GetBreakIter().is() && !g_pBreakIt->GetBreakIter()->isBeginWord(
1444 rStr, nAktPos, g_pBreakIt->GetLocale(nLanguage),
1445 i18n::WordType::ANYWORD_IGNOREWHITESPACES ) )
1447 aSnippet.SetChar(0, rStr.GetChar(nAktPos));
1450 m_rExport.m_aCurrentCharPropStarts.pop();
1452 return aSnippet;
1455 /** Delivers the right paragraph style
1457 Because of the different style handling for delete operations,
1458 the track changes have to be analysed. A deletion, starting in paragraph A
1459 with style A, ending in paragraph B with style B, needs a hack.
1461 static SwTxtFmtColl& lcl_getFormatCollection( MSWordExportBase& rExport, const SwTxtNode* pTxtNode )
1463 sal_uInt16 nPos = 0;
1464 sal_uInt16 nMax = rExport.pDoc->GetRedlineTbl().size();
1465 while( nPos < nMax )
1467 const SwRedline* pRedl = rExport.pDoc->GetRedlineTbl()[ nPos++ ];
1468 const SwPosition* pStt = pRedl->Start();
1469 const SwPosition* pEnd = pStt == pRedl->GetPoint()
1470 ? pRedl->GetMark()
1471 : pRedl->GetPoint();
1472 // Looking for deletions, which ends in current pTxtNode
1473 if( nsRedlineType_t::REDLINE_DELETE == pRedl->GetRedlineData().GetType() &&
1474 pEnd->nNode == *pTxtNode && pStt->nNode != *pTxtNode &&
1475 pStt->nNode.GetNode().IsTxtNode() )
1477 pTxtNode = pStt->nNode.GetNode().GetTxtNode();
1478 nMax = nPos;
1479 nPos = 0;
1482 return static_cast<SwTxtFmtColl&>( pTxtNode->GetAnyFmtColl() );
1485 void WW8AttributeOutput::FormatDrop( const SwTxtNode& rNode, const SwFmtDrop &rSwFmtDrop, sal_uInt16 nStyle,
1486 ww8::WW8TableNodeInfo::Pointer_t pTextNodeInfo, ww8::WW8TableNodeInfoInner::Pointer_t pTextNodeInfoInner )
1488 short nDropLines = rSwFmtDrop.GetLines();
1489 short nDistance = rSwFmtDrop.GetDistance();
1490 int rFontHeight, rDropHeight, rDropDescent;
1492 SVBT16 nSty;
1493 ShortToSVBT16( nStyle, nSty );
1494 m_rWW8Export.pO->insert( m_rWW8Export.pO->end(), (sal_uInt8*)&nSty, (sal_uInt8*)&nSty+2 ); // Style #
1496 if ( m_rWW8Export.bWrtWW8 )
1498 m_rWW8Export.InsUInt16( NS_sprm::LN_PPc ); // Alignment (sprmPPc)
1499 m_rWW8Export.pO->push_back( 0x20 );
1501 m_rWW8Export.InsUInt16( NS_sprm::LN_PWr ); // Wrapping (sprmPWr)
1502 m_rWW8Export.pO->push_back( 0x02 );
1504 m_rWW8Export.InsUInt16( NS_sprm::LN_PDcs ); // Dropcap (sprmPDcs)
1505 int nDCS = ( nDropLines << 3 ) | 0x01;
1506 m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( nDCS ) );
1508 m_rWW8Export.InsUInt16( NS_sprm::LN_PDxaFromText ); // Distance from text (sprmPDxaFromText)
1509 m_rWW8Export.InsUInt16( nDistance );
1511 if ( rNode.GetDropSize( rFontHeight, rDropHeight, rDropDescent ) )
1513 m_rWW8Export.InsUInt16( NS_sprm::LN_PDyaLine ); // Line spacing
1514 m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( -rDropHeight ) );
1515 m_rWW8Export.InsUInt16( 0 );
1518 else
1520 m_rWW8Export.pO->push_back( 29 ); // Alignment (sprmPPc)
1521 m_rWW8Export.pO->push_back( 0x20 );
1523 m_rWW8Export.pO->push_back( 37 ); // Wrapping (sprmPWr)
1524 m_rWW8Export.pO->push_back( 0x02 );
1526 m_rWW8Export.pO->push_back( 46 ); // Dropcap (sprmPDcs)
1527 int nDCS = ( nDropLines << 3 ) | 0x01;
1528 m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( nDCS ) );
1530 m_rWW8Export.pO->push_back( 49 ); // Distance from text (sprmPDxaFromText)
1531 m_rWW8Export.InsUInt16( nDistance );
1533 if (rNode.GetDropSize(rFontHeight, rDropHeight, rDropDescent))
1535 m_rWW8Export.pO->push_back( 20 ); // Line spacing
1536 m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( -rDropHeight ) );
1537 m_rWW8Export.InsUInt16( 0 );
1541 m_rWW8Export.WriteCR( pTextNodeInfoInner );
1543 if ( pTextNodeInfo.get() != NULL )
1545 #ifdef DBG_UTIL
1546 SAL_INFO( "sw.ww8", pTextNodeInfo->toString());
1547 #endif
1548 TableInfoCell( pTextNodeInfoInner );
1551 m_rWW8Export.pPapPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), m_rWW8Export.pO->size(), m_rWW8Export.pO->data() );
1552 m_rWW8Export.pO->clear();
1554 if ( rNode.GetDropSize( rFontHeight, rDropHeight, rDropDescent ) )
1556 if ( m_rWW8Export.bWrtWW8 )
1558 const SwCharFmt *pSwCharFmt = rSwFmtDrop.GetCharFmt();
1559 if ( pSwCharFmt )
1561 m_rWW8Export.InsUInt16( NS_sprm::LN_CIstd );
1562 m_rWW8Export.InsUInt16( m_rWW8Export.GetId( *pSwCharFmt ) );
1565 m_rWW8Export.InsUInt16( NS_sprm::LN_CHpsPos ); // Lower the chars
1566 m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( -((nDropLines - 1)*rDropDescent) / 10 ) );
1568 m_rWW8Export.InsUInt16( NS_sprm::LN_CHps ); // Font Size
1569 m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( rFontHeight / 10 ) );
1571 else
1573 const SwCharFmt *pSwCharFmt = rSwFmtDrop.GetCharFmt();
1574 if ( pSwCharFmt )
1576 m_rWW8Export.InsUInt16( 80 );
1577 m_rWW8Export.InsUInt16( m_rWW8Export.GetId( *pSwCharFmt ) );
1580 m_rWW8Export.pO->push_back( 101 ); // Lower the chars
1581 m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( -((nDropLines - 1)*rDropDescent) / 10 ) );
1583 m_rWW8Export.pO->push_back( 99 ); // Font Size
1584 m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( rFontHeight / 10 ) );
1588 m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), m_rWW8Export.pO->size(), m_rWW8Export.pO->data() );
1589 m_rWW8Export.pO->clear();
1592 xub_StrLen MSWordExportBase::GetNextPos( SwWW8AttrIter* aAttrIter, const SwTxtNode& rNode, xub_StrLen nAktPos )
1594 // Get the bookmarks for the normal run
1595 xub_StrLen nNextPos = aAttrIter->WhereNext();
1596 xub_StrLen nNextBookmark = nNextPos;
1598 if( nNextBookmark > nAktPos ) //no need to search for bookmarks otherwise (checked in UpdatePosition())
1600 GetSortedBookmarks( rNode, nAktPos, nNextBookmark - nAktPos );
1601 NearestBookmark( nNextBookmark, nAktPos, false );
1603 return std::min( nNextPos, nNextBookmark );
1606 void MSWordExportBase::UpdatePosition( SwWW8AttrIter* aAttrIter, xub_StrLen nAktPos, xub_StrLen /*nEnd*/ )
1608 xub_StrLen nNextPos;
1610 // go to next attribute if no bookmark is found or if the bookmark is behind the next attribute position
1611 // It may happened that the WhereNext() wasn't used in the previous increment because there was a
1612 // bookmark before it. Use that position before trying to find another one.
1613 bool bNextBookmark = NearestBookmark( nNextPos, nAktPos, true );
1614 if( nAktPos == aAttrIter->WhereNext() && ( !bNextBookmark || nNextPos > aAttrIter->WhereNext() ) )
1615 aAttrIter->NextPos();
1618 bool MSWordExportBase::GetBookmarks( const SwTxtNode& rNd, xub_StrLen nStt,
1619 xub_StrLen nEnd, IMarkVector& rArr )
1621 IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
1622 sal_uLong nNd = rNd.GetIndex( );
1624 const sal_Int32 nMarks = pMarkAccess->getMarksCount();
1625 for ( sal_Int32 i = 0; i < nMarks; i++ )
1627 IMark* pMark = ( pMarkAccess->getMarksBegin() + i )->get();
1629 // Only keep the bookmarks starting or ending in this node
1630 if ( pMark->GetMarkStart().nNode == nNd ||
1631 pMark->GetMarkEnd().nNode == nNd )
1633 xub_StrLen nBStart = pMark->GetMarkStart().nContent.GetIndex();
1634 xub_StrLen nBEnd = pMark->GetMarkEnd().nContent.GetIndex();
1636 // Keep only the bookmars starting or ending in the snippet
1637 bool bIsStartOk = ( nBStart >= nStt ) && ( nBStart <= nEnd );
1638 bool bIsEndOk = ( nBEnd >= nStt ) && ( nBEnd <= nEnd );
1640 IFieldmark* pFieldmark = dynamic_cast<IFieldmark*>(pMark);
1641 if (pFieldmark && pFieldmark->GetFieldname() == ODF_COMMENTRANGE)
1642 continue;
1644 if ( bIsStartOk || bIsEndOk )
1645 rArr.push_back( pMark );
1648 return ( rArr.size() > 0 );
1651 class CompareMarksEnd : public std::binary_function < const IMark *, const IMark *, bool >
1653 public:
1654 inline bool operator() ( const IMark * pOneB, const IMark * pTwoB ) const
1656 xub_StrLen nOEnd = pOneB->GetMarkEnd().nContent.GetIndex();
1657 xub_StrLen nTEnd = pTwoB->GetMarkEnd().nContent.GetIndex();
1659 return nOEnd < nTEnd;
1663 bool MSWordExportBase::NearestBookmark( xub_StrLen& rNearest, const xub_StrLen nAktPos, bool bNextPositionOnly )
1665 bool bHasBookmark = false;
1667 if ( !m_rSortedMarksStart.empty() )
1669 IMark* pMarkStart = m_rSortedMarksStart.front();
1670 xub_StrLen nNext = pMarkStart->GetMarkStart().nContent.GetIndex();
1671 if( !bNextPositionOnly || (nNext > nAktPos ))
1673 rNearest = nNext;
1674 bHasBookmark = true;
1678 if ( !m_rSortedMarksEnd.empty() )
1680 IMark* pMarkEnd = m_rSortedMarksEnd[0];
1681 xub_StrLen nNext = pMarkEnd->GetMarkEnd().nContent.GetIndex();
1682 if( !bNextPositionOnly || nNext > nAktPos )
1684 if ( !bHasBookmark )
1685 rNearest = nNext;
1686 else
1687 rNearest = std::min( rNearest, nNext );
1688 bHasBookmark = true;
1692 return bHasBookmark;
1695 void MSWordExportBase::GetSortedBookmarks( const SwTxtNode& rNode, xub_StrLen nAktPos, xub_StrLen nLen )
1697 IMarkVector aMarksStart;
1698 if ( GetBookmarks( rNode, nAktPos, nAktPos + nLen, aMarksStart ) )
1700 IMarkVector aSortedEnd;
1701 IMarkVector aSortedStart;
1702 for ( IMarkVector::const_iterator it = aMarksStart.begin(), end = aMarksStart.end();
1703 it != end; ++it )
1705 IMark* pMark = (*it);
1707 // Remove the positions egals to the current pos
1708 xub_StrLen nStart = pMark->GetMarkStart().nContent.GetIndex();
1709 xub_StrLen nEnd = pMark->GetMarkEnd().nContent.GetIndex();
1711 if ( nStart > nAktPos && ( pMark->GetMarkStart().nNode == rNode.GetIndex()) )
1712 aSortedStart.push_back( pMark );
1714 if ( nEnd > nAktPos && nEnd <= ( nAktPos + nLen ) && (pMark->GetMarkEnd().nNode == rNode.GetIndex()) )
1715 aSortedEnd.push_back( pMark );
1718 // Sort the bookmarks by end position
1719 std::sort( aSortedEnd.begin(), aSortedEnd.end(), CompareMarksEnd() );
1721 m_rSortedMarksStart.swap( aSortedStart );
1722 m_rSortedMarksEnd.swap( aSortedEnd );
1724 else
1726 m_rSortedMarksStart.clear( );
1727 m_rSortedMarksEnd.clear( );
1731 void MSWordExportBase::OutputTextNode( const SwTxtNode& rNode )
1733 SAL_INFO( "sw.ww8", "<OutWW8_SwTxtNode>" );
1735 ww8::WW8TableNodeInfo::Pointer_t pTextNodeInfo( mpTableInfo->getTableNodeInfo( &rNode ) );
1737 //For i120928,identify the last node
1738 bool bLastCR = false;
1739 bool bExported = false;
1741 SwNodeIndex aNextIdx(rNode,1);
1742 SwNodeIndex aLastIdx(rNode.GetNodes().GetEndOfContent());
1743 if (aNextIdx == aLastIdx)
1744 bLastCR = true;
1747 AttrOutput().StartParagraph( pTextNodeInfo );
1749 bool bFlyInTable = mpParentFrame && IsInTable();
1751 if ( !bFlyInTable )
1752 nStyleBeforeFly = GetId( lcl_getFormatCollection( *this, &rNode ) );
1754 // nStyleBeforeFly may change when we recurse into another node, so we
1755 // have to remember it in nStyle
1756 sal_uInt16 nStyle = nStyleBeforeFly;
1758 SwWW8AttrIter aAttrIter( *this, rNode );
1759 rtl_TextEncoding eChrSet = aAttrIter.GetCharSet();
1761 if ( bStartTOX )
1763 // ignore TOX header section
1764 const SwSectionNode* pSectNd = rNode.FindSectionNode();
1765 if ( pSectNd && TOX_CONTENT_SECTION == pSectNd->GetSection().GetType() )
1767 AttrOutput().StartTOX( pSectNd->GetSection() );
1768 m_aCurrentCharPropStarts.push( 0 );
1772 const SwSection* pTOXSect = 0;
1773 if( bInWriteTOX )
1775 // check for end of TOX
1776 SwNodeIndex aIdx( rNode, 1 );
1777 if( !aIdx.GetNode().IsTxtNode() )
1779 const SwSectionNode* pTOXSectNd = rNode.FindSectionNode();
1780 if ( pTOXSectNd )
1782 pTOXSect = &pTOXSectNd->GetSection();
1784 const SwNode* pNxt = rNode.GetNodes().GoNext( &aIdx );
1785 if( pNxt && pNxt->FindSectionNode() == pTOXSectNd )
1786 pTOXSect = 0;
1791 if ( aAttrIter.RequiresImplicitBookmark() )
1793 String sBkmkName = String( "_toc" );
1794 sBkmkName += OUString::number( rNode.GetIndex() );
1795 AppendWordBookmark( sBkmkName );
1798 String aStr( rNode.GetTxt() );
1800 xub_StrLen nAktPos = 0;
1801 xub_StrLen const nEnd = aStr.Len();
1802 bool bRedlineAtEnd = false;
1803 int nOpenAttrWithRange = 0;
1805 ww8::WW8TableNodeInfoInner::Pointer_t pTextNodeInfoInner;
1806 if ( pTextNodeInfo.get() != NULL )
1807 pTextNodeInfoInner = pTextNodeInfo->getFirstInner();
1809 do {
1810 const SwRedlineData* pRedlineData = aAttrIter.GetRedline( nAktPos );
1812 xub_StrLen nNextAttr = GetNextPos( &aAttrIter, rNode, nAktPos );
1813 // Is this the only run in this paragraph and it's empty?
1814 bool bSingleEmptyRun = nAktPos == 0 && nNextAttr == 0;
1815 AttrOutput().StartRun( pRedlineData, bSingleEmptyRun );
1816 if( nTxtTyp == TXT_FTN || nTxtTyp == TXT_EDN )
1817 AttrOutput().FootnoteEndnoteRefTag();
1819 if( nNextAttr > nEnd )
1820 nNextAttr = nEnd;
1822 aAttrIter.OutFlys( nAktPos );
1823 // Append bookmarks in this range after flys, exclusive of final
1824 // position of this range
1825 AppendBookmarks( rNode, nAktPos, nNextAttr - nAktPos );
1826 bool bTxtAtr = aAttrIter.IsTxtAttr( nAktPos );
1827 nOpenAttrWithRange += aAttrIter.OutAttrWithRange(nAktPos);
1829 xub_StrLen nLen = nNextAttr - nAktPos;
1830 if ( !bTxtAtr && nLen )
1832 sal_Unicode ch = aStr.GetChar( nAktPos );
1833 int ofs = ( ch == CH_TXT_ATR_FIELDSTART || ch == CH_TXT_ATR_FIELDEND || ch == CH_TXT_ATR_FORMELEMENT? 1: 0 );
1835 IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
1836 if ( ch == CH_TXT_ATR_FIELDSTART )
1838 SwPosition aPosition( rNode, SwIndex( const_cast< SwTxtNode* >( &rNode ), nAktPos ) );
1839 ::sw::mark::IFieldmark const * const pFieldmark = pMarkAccess->getFieldmarkFor( aPosition );
1840 OSL_ENSURE( pFieldmark, "Looks like this doc is broken...; where is the Fieldmark for the FIELDSTART??" );
1842 if ( pFieldmark && pFieldmark->GetFieldname() == ODF_FORMTEXT )
1843 AppendBookmark( pFieldmark->GetName(), false );
1844 ww::eField eFieldId = lcl_getFieldId( pFieldmark );
1845 String sCode = lcl_getFieldCode( pFieldmark );
1846 if ( pFieldmark && pFieldmark->GetFieldname() == ODF_UNHANDLED )
1848 IFieldmark::parameter_map_t::const_iterator it = pFieldmark->GetParameters()->find( ODF_ID_PARAM );
1849 if ( it != pFieldmark->GetParameters()->end() )
1851 OUString sFieldId;
1852 it->second >>= sFieldId;
1853 eFieldId = (ww::eField)sFieldId.toInt32();
1856 it = pFieldmark->GetParameters()->find( ODF_CODE_PARAM );
1857 if ( it != pFieldmark->GetParameters()->end() )
1859 OUString sOUCode;
1860 it->second >>= sOUCode;
1861 sCode = sOUCode;
1865 bool bCommentRange = pFieldmark && pFieldmark->GetFieldname() == ODF_COMMENTRANGE;
1866 if (bCommentRange)
1867 AttrOutput().WritePostitFieldStart();
1868 else
1869 OutputField( NULL, eFieldId, sCode, WRITEFIELD_START | WRITEFIELD_CMD_START );
1871 if ( pFieldmark && pFieldmark->GetFieldname( ) == ODF_FORMTEXT )
1872 WriteFormData( *pFieldmark );
1873 else if ( pFieldmark && pFieldmark->GetFieldname( ) == ODF_HYPERLINK )
1874 WriteHyperlinkData( *pFieldmark );
1875 if (!bCommentRange)
1876 OutputField( NULL, lcl_getFieldId( pFieldmark ), String(), WRITEFIELD_CMD_END );
1878 if ( pFieldmark && pFieldmark->GetFieldname() == ODF_UNHANDLED )
1880 // Check for the presence of a linked OLE object
1881 IFieldmark::parameter_map_t::const_iterator it = pFieldmark->GetParameters()->find( ODF_OLE_PARAM );
1882 if ( it != pFieldmark->GetParameters()->end() )
1884 OUString sOleId;
1885 uno::Any aValue = it->second;
1886 aValue >>= sOleId;
1887 if ( !sOleId.isEmpty() )
1888 OutputLinkedOLE( sOleId );
1892 else if ( ch == CH_TXT_ATR_FIELDEND )
1894 SwPosition aPosition( rNode, SwIndex( const_cast< SwTxtNode* >( &rNode ), nAktPos ) );
1895 ::sw::mark::IFieldmark const * const pFieldmark = pMarkAccess->getFieldmarkFor( aPosition );
1897 OSL_ENSURE( pFieldmark, "Looks like this doc is broken...; where is the Fieldmark for the FIELDEND??" );
1899 ww::eField eFieldId = lcl_getFieldId( pFieldmark );
1900 if ( pFieldmark && pFieldmark->GetFieldname() == ODF_UNHANDLED )
1902 IFieldmark::parameter_map_t::const_iterator it = pFieldmark->GetParameters()->find( ODF_ID_PARAM );
1903 if ( it != pFieldmark->GetParameters()->end() )
1905 OUString sFieldId;
1906 it->second >>= sFieldId;
1907 eFieldId = (ww::eField)sFieldId.toInt32();
1911 if (pFieldmark && pFieldmark->GetFieldname() == ODF_COMMENTRANGE)
1912 AttrOutput().WritePostitFieldEnd();
1913 else
1914 OutputField( NULL, eFieldId, String(), WRITEFIELD_CLOSE );
1916 if ( pFieldmark && pFieldmark->GetFieldname() == ODF_FORMTEXT )
1917 AppendBookmark( pFieldmark->GetName(), false );
1919 else if ( ch == CH_TXT_ATR_FORMELEMENT )
1921 SwPosition aPosition( rNode, SwIndex( const_cast< SwTxtNode* >( &rNode ), nAktPos ) );
1922 ::sw::mark::IFieldmark const * const pFieldmark = pMarkAccess->getFieldmarkFor( aPosition );
1923 OSL_ENSURE( pFieldmark, "Looks like this doc is broken...; where is the Fieldmark for the FIELDSTART??" );
1925 bool isDropdownOrCheckbox = pFieldmark && (pFieldmark->GetFieldname( ) == ODF_FORMDROPDOWN ||
1926 pFieldmark->GetFieldname( ) == ODF_FORMCHECKBOX );
1928 if ( isDropdownOrCheckbox )
1929 AppendBookmark( pFieldmark->GetName(), 0 );
1930 OutputField( NULL, lcl_getFieldId( pFieldmark ),
1931 lcl_getFieldCode( pFieldmark ),
1932 WRITEFIELD_START | WRITEFIELD_CMD_START );
1933 if ( isDropdownOrCheckbox )
1934 WriteFormData( *pFieldmark );
1935 OutputField( NULL, lcl_getFieldId( pFieldmark ), String(), WRITEFIELD_CLOSE );
1936 if ( isDropdownOrCheckbox )
1937 AppendBookmark( pFieldmark->GetName(), false );
1939 nLen -= static_cast< sal_uInt16 >( ofs );
1941 String aSnippet( aAttrIter.GetSnippet( aStr, nAktPos + static_cast< sal_uInt16 >( ofs ), nLen ) );
1942 if ( ( nTxtTyp == TXT_EDN || nTxtTyp == TXT_FTN ) && nAktPos == 0 && nLen > 0 )
1944 // Insert tab for aesthetic puposes #i24762#
1945 if ( aSnippet.GetChar( 0 ) != 0x09 )
1946 aSnippet.Insert( 0x09, 0 );
1948 AttrOutput().RunText( aSnippet, eChrSet );
1951 if ( aAttrIter.IsDropCap( nNextAttr ) )
1952 AttrOutput().FormatDrop( rNode, aAttrIter.GetSwFmtDrop(), nStyle, pTextNodeInfo, pTextNodeInfoInner );
1954 if (0 != nEnd)
1956 // Output the character attributes
1957 // #i51277# do this before writing flys at end of paragraph
1958 AttrOutput().StartRunProperties();
1959 aAttrIter.OutAttr( nAktPos );
1960 AttrOutput().EndRunProperties( pRedlineData );
1963 // At the end of line, output the attributes until the CR.
1964 // Exception: footnotes at the end of line
1965 if ( nNextAttr == nEnd )
1967 OSL_ENSURE( nOpenAttrWithRange >= 0, "odd to see this happening, expected >= 0" );
1968 if ( !bTxtAtr && nOpenAttrWithRange <= 0 )
1970 if ( aAttrIter.IsRedlineAtEnd( nEnd ) )
1971 bRedlineAtEnd = true;
1972 else
1974 // insert final graphic anchors if any before CR
1975 aAttrIter.OutFlys( nEnd );
1976 // insert final bookmarks if any before CR and after flys
1977 AppendBookmarks( rNode, nEnd, 1 );
1978 if ( pTOXSect )
1980 m_aCurrentCharPropStarts.pop();
1981 AttrOutput().EndTOX( *pTOXSect );
1983 //For i120928,the position of the bullet's graphic is at end of doc
1984 if (bLastCR && (!bExported))
1986 ExportGrfBullet(rNode);
1987 bExported = true;
1990 WriteCR( pTextNodeInfoInner );
1995 if (0 == nEnd)
1997 // Output the character attributes
1998 // do it after WriteCR for an empty paragraph (otherwise
1999 // WW8_WrFkp::Append throws SPRMs away...)
2000 AttrOutput().StartRunProperties();
2001 aAttrIter.OutAttr( nAktPos );
2002 AttrOutput().EndRunProperties( pRedlineData );
2005 // Exception: footnotes at the end of line
2006 if ( nNextAttr == nEnd )
2008 OSL_ENSURE(nOpenAttrWithRange >= 0,
2009 "odd to see this happening, expected >= 0");
2010 bool bAttrWithRange = (nOpenAttrWithRange > 0);
2011 if ( nAktPos != nEnd )
2013 nOpenAttrWithRange += aAttrIter.OutAttrWithRange(nEnd);
2014 OSL_ENSURE(nOpenAttrWithRange == 0,
2015 "odd to see this happening, expected 0");
2018 AttrOutput().OutputFKP();
2020 if ( bTxtAtr || bAttrWithRange || bRedlineAtEnd )
2022 // insert final graphic anchors if any before CR
2023 aAttrIter.OutFlys( nEnd );
2024 // insert final bookmarks if any before CR and after flys
2025 AppendBookmarks( rNode, nEnd, 1 );
2026 // #i120928 - position of the bullet's graphic is at end of doc
2027 if (bLastCR && (!bExported))
2029 ExportGrfBullet(rNode);
2030 bExported = true;
2033 if ( pTOXSect )
2035 m_aCurrentCharPropStarts.pop();
2036 AttrOutput().EndTOX( *pTOXSect );
2039 WriteCR( pTextNodeInfoInner );
2041 if ( bRedlineAtEnd )
2043 AttrOutput().Redline( aAttrIter.GetRedline( nEnd ) );
2044 AttrOutput().OutputFKP();
2049 AttrOutput().WritePostitFieldReference();
2051 AttrOutput().EndRun();
2053 nAktPos = nNextAttr;
2054 UpdatePosition( &aAttrIter, nAktPos, nEnd );
2055 eChrSet = aAttrIter.GetCharSet();
2057 while ( nAktPos < nEnd );
2059 AttrOutput().StartParagraphProperties( rNode );
2061 AttrOutput().ParagraphStyle( nStyle );
2063 if ( mpParentFrame && IsInTable() ) // Fly-Attrs
2064 OutputFormat( mpParentFrame->GetFrmFmt(), false, false, true );
2066 if ( pTextNodeInfo.get() != NULL )
2068 #ifdef DBG_UTIL
2069 SAL_INFO( "sw.ww8", pTextNodeInfo->toString());
2070 #endif
2072 AttrOutput().TableInfoCell( pTextNodeInfoInner );
2073 if (pTextNodeInfoInner->isFirstInTable())
2075 const SwTable * pTable = pTextNodeInfoInner->getTable();
2077 const SwTableFmt * pTabFmt = pTable->GetTableFmt();
2078 if (pTabFmt != NULL)
2080 if (pTabFmt->GetBreak().GetBreak() == SVX_BREAK_PAGE_BEFORE)
2081 AttrOutput().PageBreakBefore(true);
2086 if ( !bFlyInTable )
2088 SfxItemSet* pTmpSet = 0;
2089 const sal_uInt8 nPrvNxtNd = rNode.HasPrevNextLayNode();
2091 if( (ND_HAS_PREV_LAYNODE|ND_HAS_NEXT_LAYNODE ) != nPrvNxtNd )
2093 const SfxPoolItem* pItem;
2094 if( SFX_ITEM_SET == rNode.GetSwAttrSet().GetItemState(
2095 RES_UL_SPACE, true, &pItem ) &&
2096 ( ( !( ND_HAS_PREV_LAYNODE & nPrvNxtNd ) &&
2097 ((SvxULSpaceItem*)pItem)->GetUpper()) ||
2098 ( !( ND_HAS_NEXT_LAYNODE & nPrvNxtNd ) &&
2099 ((SvxULSpaceItem*)pItem)->GetLower()) ))
2101 pTmpSet = new SfxItemSet( rNode.GetSwAttrSet() );
2102 SvxULSpaceItem aUL( *(SvxULSpaceItem*)pItem );
2103 // #i25901#- consider compatibility option
2104 if (!pDoc->get(IDocumentSettingAccess::PARA_SPACE_MAX_AT_PAGES))
2106 if( !(ND_HAS_PREV_LAYNODE & nPrvNxtNd ))
2107 aUL.SetUpper( 0 );
2109 // #i25901# - consider compatibility option
2110 if (!pDoc->get(IDocumentSettingAccess::ADD_PARA_SPACING_TO_TABLE_CELLS))
2112 if( !(ND_HAS_NEXT_LAYNODE & nPrvNxtNd ))
2113 aUL.SetLower( 0 );
2115 pTmpSet->Put( aUL );
2119 bool bParaRTL = false;
2120 const SvxFrameDirectionItem* pItem = (const SvxFrameDirectionItem*)
2121 rNode.GetSwAttrSet().GetItem(RES_FRAMEDIR);
2122 if ( aAttrIter.IsParaRTL())
2123 bParaRTL = true;
2125 if( rNode.IsNumbered())
2127 const SwNumRule* pRule = rNode.GetNumRule();
2128 sal_uInt8 nLvl = static_cast< sal_uInt8 >( rNode.GetActualListLevel() );
2129 const SwNumFmt* pFmt = pRule->GetNumFmt( nLvl );
2130 if( !pFmt )
2131 pFmt = &pRule->Get( nLvl );
2133 if( !pTmpSet )
2134 pTmpSet = new SfxItemSet( rNode.GetSwAttrSet() );
2136 SvxLRSpaceItem aLR(ItemGet<SvxLRSpaceItem>(*pTmpSet, RES_LR_SPACE));
2137 // #i86652#
2138 if ( pFmt->GetPositionAndSpaceMode() ==
2139 SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
2141 aLR.SetTxtLeft( aLR.GetTxtLeft() + pFmt->GetAbsLSpace() );
2144 if( rNode.IsNumbered() && rNode.IsCountedInList() )
2146 // #i86652#
2147 if ( pFmt->GetPositionAndSpaceMode() ==
2148 SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
2150 if (bParaRTL)
2151 aLR.SetTxtFirstLineOfstValue(pFmt->GetAbsLSpace() - pFmt->GetFirstLineOffset());
2152 else
2153 aLR.SetTxtFirstLineOfst(GetWordFirstLineOffset(*pFmt));
2156 // correct fix for issue i94187
2157 if (SFX_ITEM_SET !=
2158 pTmpSet->GetItemState(RES_PARATR_NUMRULE, false) )
2160 // List style set via paragraph style - then put it into the itemset.
2161 // This is needed to get list level and list id exported for
2162 // the paragraph.
2163 pTmpSet->Put( SwNumRuleItem( pRule->GetName() ));
2165 // Put indent values into the itemset in case that the list
2166 // style is applied via paragraph style and the list level
2167 // indent values are not applicable.
2168 if ( pFmt->GetPositionAndSpaceMode() ==
2169 SvxNumberFormat::LABEL_ALIGNMENT &&
2170 !rNode.AreListLevelIndentsApplicable() )
2172 pTmpSet->Put( aLR );
2176 else
2177 pTmpSet->ClearItem(RES_PARATR_NUMRULE);
2179 // #i86652#
2180 if ( pFmt->GetPositionAndSpaceMode() ==
2181 SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
2183 pTmpSet->Put(aLR);
2185 //#i21847#
2186 SvxTabStopItem aItem(
2187 ItemGet<SvxTabStopItem>(*pTmpSet, RES_PARATR_TABSTOP));
2188 SvxTabStop aTabStop(pFmt->GetAbsLSpace());
2189 aItem.Insert(aTabStop);
2190 pTmpSet->Put(aItem);
2192 MSWordExportBase::CorrectTabStopInSet(*pTmpSet, pFmt->GetAbsLSpace());
2197 If a given para is using the FRMDIR_ENVIRONMENT direction we
2198 cannot export that, its its ltr then that's ok as thats word's
2199 default. Otherwise we must add a RTL attribute to our export list
2201 pItem = (const SvxFrameDirectionItem*)
2202 rNode.GetSwAttrSet().GetItem(RES_FRAMEDIR);
2203 if (
2204 (!pItem || pItem->GetValue() == FRMDIR_ENVIRONMENT) &&
2205 aAttrIter.IsParaRTL()
2208 if ( !pTmpSet )
2209 pTmpSet = new SfxItemSet(rNode.GetSwAttrSet());
2211 pTmpSet->Put(SvxFrameDirectionItem(FRMDIR_HORI_RIGHT_TOP, RES_FRAMEDIR));
2213 // move code for handling of numbered,
2214 // but not counted paragraphs to this place. Otherwise, the paragraph
2215 // isn't exported as numbered, but not counted, if no other attribute
2216 // is found in <pTmpSet>
2217 // #i44815# adjust numbering/indents for numbered paragraphs
2218 // without number (NO_NUMLEVEL)
2219 // #i47013# need to check rNode.GetNumRule()!=NULL as well.
2220 if ( ! rNode.IsCountedInList() && rNode.GetNumRule()!=NULL )
2222 // WW8 does not know numbered paragraphs without number
2223 // (NO_NUMLEVEL). In WW8AttributeOutput::ParaNumRule(), we will export
2224 // the RES_PARATR_NUMRULE as list-id 0, which in WW8 means
2225 // no numbering. Here, we will adjust the indents to match
2226 // visually.
2228 if ( !pTmpSet )
2229 pTmpSet = new SfxItemSet(rNode.GetSwAttrSet());
2231 // create new LRSpace item, based on the current (if present)
2232 const SfxPoolItem* pPoolItem = NULL;
2233 pTmpSet->GetItemState(RES_LR_SPACE, sal_True, &pPoolItem);
2234 SvxLRSpaceItem aLRSpace(
2235 ( pPoolItem == NULL )
2236 ? SvxLRSpaceItem(0, 0, 0, 0, RES_LR_SPACE)
2237 : *static_cast<const SvxLRSpaceItem*>( pPoolItem ) );
2239 // new left margin = old left + label space
2240 const SwNumRule* pRule = rNode.GetNumRule();
2241 const SwNumFmt& rNumFmt = pRule->Get( static_cast< sal_uInt16 >(rNode.GetActualListLevel()) );
2242 // #i86652#
2243 if ( rNumFmt.GetPositionAndSpaceMode() ==
2244 SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
2246 aLRSpace.SetTxtLeft( aLRSpace.GetLeft() + rNumFmt.GetAbsLSpace() );
2248 // new first line indent = 0
2249 // (first line indent is ignored for NO_NUMLEVEL)
2250 if (!bParaRTL)
2251 aLRSpace.SetTxtFirstLineOfst( 0 );
2253 // put back the new item
2254 pTmpSet->Put( aLRSpace );
2257 // assure that numbering rule is in <pTmpSet>
2258 if (SFX_ITEM_SET != pTmpSet->GetItemState(RES_PARATR_NUMRULE, false) )
2260 pTmpSet->Put( SwNumRuleItem( pRule->GetName() ));
2264 // #i75457#
2265 // Export page break after attribute from paragraph style.
2266 // If page break attribute at the text node exist, an existing page
2267 // break after at the paragraph style hasn't got to be considered.
2268 if ( !rNode.GetpSwAttrSet() ||
2269 SFX_ITEM_SET != rNode.GetpSwAttrSet()->GetItemState(RES_BREAK, false) )
2271 const SvxFmtBreakItem* pBreakAtParaStyle =
2272 &(ItemGet<SvxFmtBreakItem>(rNode.GetSwAttrSet(), RES_BREAK));
2273 if ( pBreakAtParaStyle &&
2274 pBreakAtParaStyle->GetBreak() == SVX_BREAK_PAGE_AFTER )
2276 if ( !pTmpSet )
2278 pTmpSet = new SfxItemSet(rNode.GetSwAttrSet());
2280 pTmpSet->Put( *pBreakAtParaStyle );
2282 else if( pTmpSet )
2283 { // Even a pagedesc item is set, the break item can be set 'NONE',
2284 // this has to be overruled.
2285 const SwFmtPageDesc& rPageDescAtParaStyle =
2286 ItemGet<SwFmtPageDesc>( rNode, RES_PAGEDESC );
2287 if( rPageDescAtParaStyle.KnowsPageDesc() )
2288 pTmpSet->ClearItem( RES_BREAK );
2292 // #i76520# Emulate non-splitting tables
2293 if ( bOutTable )
2295 const SwTableNode* pTableNode = rNode.FindTableNode();
2297 if ( pTableNode )
2299 const SwTable& rTable = pTableNode->GetTable();
2300 const SvxFmtKeepItem& rKeep = rTable.GetFrmFmt()->GetKeep();
2301 const bool bKeep = rKeep.GetValue();
2302 const bool bDontSplit = !bKeep ?
2303 !rTable.GetFrmFmt()->GetLayoutSplit().GetValue() :
2304 false;
2306 if ( bKeep || bDontSplit )
2308 // bKeep: set keep at first paragraphs in all lines
2309 // bDontSplit : set keep at first paragraphs in all lines except from last line
2310 // but only for non-complex tables
2311 const SwTableBox* pBox = rNode.GetTblBox();
2312 const SwTableLine* pLine = pBox ? pBox->GetUpper() : 0;
2314 if ( pLine && !pLine->GetUpper() )
2316 // check if box is first in that line:
2317 if ( 0 == pLine->GetTabBoxes().GetPos( pBox ) && pBox->GetSttNd() )
2319 // check if paragraph is first in that line:
2320 if ( 1 == ( rNode.GetIndex() - pBox->GetSttNd()->GetIndex() ) )
2322 bool bSetAtPara = false;
2323 if ( bKeep )
2324 bSetAtPara = true;
2325 else if ( bDontSplit )
2327 // check if pLine isn't last line in table
2328 if ( rTable.GetTabLines().size() - rTable.GetTabLines().GetPos( pLine ) != 1 )
2329 bSetAtPara = true;
2332 if ( bSetAtPara )
2334 if ( !pTmpSet )
2335 pTmpSet = new SfxItemSet(rNode.GetSwAttrSet());
2337 const SvxFmtKeepItem aKeepItem( sal_True, RES_KEEP );
2338 pTmpSet->Put( aKeepItem );
2347 const SfxItemSet* pNewSet = pTmpSet ? pTmpSet : rNode.GetpSwAttrSet();
2348 if( pNewSet )
2349 { // Para-Attrs
2350 pStyAttr = &rNode.GetAnyFmtColl().GetAttrSet();
2352 const SwModify* pOldMod = pOutFmtNode;
2353 pOutFmtNode = &rNode;
2355 // Pap-Attrs, so script is not necessary
2356 OutputItemSet( *pNewSet, true, false, i18n::ScriptType::LATIN, false);
2358 pStyAttr = 0;
2359 pOutFmtNode = pOldMod;
2361 if( pNewSet != rNode.GetpSwAttrSet() )
2362 delete pNewSet;
2366 AttrOutput().EndParagraphProperties();
2368 AttrOutput().EndParagraph( pTextNodeInfoInner );
2370 SAL_INFO( "sw.ww8", "</OutWW8_SwTxtNode>" );
2373 void WW8AttributeOutput::TableNodeInfo( ww8::WW8TableNodeInfo::Pointer_t pNodeInfo )
2375 SVBT16 nSty;
2376 ShortToSVBT16( GetExport().nStyleBeforeFly, nSty );
2378 ww8::WW8TableNodeInfo::Inners_t::const_iterator aIt( pNodeInfo->getInners().begin() );
2379 ww8::WW8TableNodeInfo::Inners_t::const_iterator aItEnd( pNodeInfo->getInners().end() );
2381 while (aIt != aItEnd)
2383 ww8::WW8TableNodeInfoInner::Pointer_t pInner = aIt->second;
2384 if ( pInner->isEndOfCell() )
2386 TableRowEnd( pInner->getDepth() );
2388 m_rWW8Export.pO->insert( m_rWW8Export.pO->end(), (sal_uInt8*)&nSty, (sal_uInt8*)&nSty+2); // Style #
2389 TableInfoRow( pInner );
2390 m_rWW8Export.pPapPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), m_rWW8Export.pO->size(), m_rWW8Export.pO->data());
2391 m_rWW8Export.pO->clear();
2394 if ( pInner->isEndOfLine() )
2398 ++aIt;
2402 // Tables
2404 void WW8AttributeOutput::EmptyParagraph()
2406 m_rWW8Export.WriteStringAsPara( aEmptyStr );
2409 bool MSWordExportBase::NoPageBreakSection( const SfxItemSet* pSet )
2411 bool bRet = false;
2412 const SfxPoolItem* pI;
2413 if( pSet)
2415 bool bNoPageBreak = false;
2416 if ( SFX_ITEM_ON != pSet->GetItemState(RES_PAGEDESC, true, &pI)
2417 || 0 == ((SwFmtPageDesc*)pI)->GetPageDesc() )
2419 bNoPageBreak = true;
2422 if (bNoPageBreak)
2424 if (SFX_ITEM_ON != pSet->GetItemState(RES_BREAK, true, &pI))
2425 bNoPageBreak = true;
2426 else
2428 SvxBreak eBreak = ((const SvxFmtBreakItem*)pI)->GetBreak();
2429 switch (eBreak)
2431 case SVX_BREAK_PAGE_BEFORE:
2432 case SVX_BREAK_PAGE_AFTER:
2433 bNoPageBreak = false;
2434 break;
2435 default:
2436 break;
2440 bRet = bNoPageBreak;
2442 return bRet;
2446 void MSWordExportBase::OutputSectionNode( const SwSectionNode& rSectionNode )
2448 const SwSection& rSection = rSectionNode.GetSection();
2450 SwNodeIndex aIdx( rSectionNode, 1 );
2451 const SwNode& rNd = aIdx.GetNode();
2452 if ( !rNd.IsSectionNode() && !IsInTable() ) //No sections in table
2454 // if the first Node inside the section has an own
2455 // PageDesc or PageBreak attribut, then dont write
2456 // here the section break
2457 sal_uLong nRstLnNum = 0;
2458 const SfxItemSet* pSet;
2459 if ( rNd.IsTableNode() )
2460 pSet = &rNd.GetTableNode()->GetTable().GetFrmFmt()->GetAttrSet();
2461 else if ( rNd.IsCntntNode() )
2463 pSet = &rNd.GetCntntNode()->GetSwAttrSet();
2464 nRstLnNum = ((SwFmtLineNumber&)pSet->Get(
2465 RES_LINENUMBER )).GetStartValue();
2467 else
2468 pSet = 0;
2470 if ( pSet && NoPageBreakSection( pSet ) )
2471 pSet = 0;
2473 if ( !pSet )
2475 // new Section with no own PageDesc/-Break
2476 // -> write follow section break;
2477 const SwSectionFmt& rFmt = *rSection.GetFmt();
2478 ReplaceCr( msword::PageBreak ); // Indikator fuer Page/Section-Break
2480 // Get the page in use at the top of this section
2481 SwNodeIndex aIdxTmp(rSectionNode, 1);
2482 const SwPageDesc *pCurrent =
2483 SwPageDesc::GetPageDescOfNode(aIdxTmp.GetNode());
2484 if (!pCurrent)
2485 pCurrent = pAktPageDesc;
2487 AppendSection( pCurrent, &rFmt, nRstLnNum );
2490 if ( TOX_CONTENT_SECTION == rSection.GetType() )
2491 bStartTOX = true;
2495 void WW8Export::AppendSection( const SwPageDesc *pPageDesc, const SwSectionFmt* pFmt, sal_uLong nLnNum )
2497 pSepx->AppendSep(Fc2Cp(Strm().Tell()), pPageDesc, pFmt, nLnNum);
2500 // Flys
2502 void WW8Export::OutWW6FlyFrmsInCntnt( const SwTxtNode& rNd )
2504 OSL_ENSURE(!bWrtWW8, "I shouldn't be needed for Word >=8");
2505 if ( bWrtWW8 )
2506 return;
2508 if (const SwpHints* pTxtAttrs = rNd.GetpSwpHints())
2510 for( sal_uInt16 n=0; n < pTxtAttrs->Count(); ++n )
2512 const SwTxtAttr* pAttr = (*pTxtAttrs)[ n ];
2513 if( RES_TXTATR_FLYCNT == pAttr->Which() )
2515 // attribute bound to a character
2516 const SwFmtFlyCnt& rFlyCntnt = pAttr->GetFlyCnt();
2517 const SwFlyFrmFmt& rFlyFrmFmt = *(SwFlyFrmFmt*)rFlyCntnt.GetFrmFmt();
2518 const SwNodeIndex* pNodeIndex = rFlyFrmFmt.GetCntnt().GetCntntIdx();
2520 if( pNodeIndex )
2522 sal_uLong nStt = pNodeIndex->GetIndex()+1,
2523 nEnd = pNodeIndex->GetNode().EndOfSectionIndex();
2525 if( (nStt < nEnd) && !pDoc->GetNodes()[ nStt ]->IsNoTxtNode() )
2527 Point aOffset;
2528 // get rectangle (bounding box?) of Fly and paragraph
2529 SwRect aParentRect(rNd.FindLayoutRect(false, &aOffset)),
2530 aFlyRect(rFlyFrmFmt.FindLayoutRect(false, &aOffset ) );
2532 aOffset = aFlyRect.Pos() - aParentRect.Pos();
2534 // let PaM point to content of Fly-frame format
2535 SaveData( nStt, nEnd );
2537 // is analysed in OutputFormat()
2538 pFlyOffset = &aOffset;
2539 eNewAnchorType = rFlyFrmFmt.GetAnchor().GetAnchorId();
2540 sw::Frame aFrm(rFlyFrmFmt, SwPosition(rNd));
2541 mpParentFrame = &aFrm;
2542 // Ok, write it out:
2543 WriteText();
2545 RestoreData();
2553 void WW8AttributeOutput::OutputFlyFrame_Impl( const sw::Frame& rFmt, const Point& rNdTopLeft )
2555 const SwFrmFmt &rFrmFmt = rFmt.GetFrmFmt();
2556 const SwFmtAnchor& rAnch = rFrmFmt.GetAnchor();
2558 bool bUseEscher = m_rWW8Export.bWrtWW8;
2560 if ( m_rWW8Export.bWrtWW8 && rFmt.IsInline() )
2562 sw::Frame::WriterSource eType = rFmt.GetWriterType();
2563 if ((eType == sw::Frame::eGraphic) || (eType == sw::Frame::eOle))
2564 bUseEscher = false;
2565 else
2566 bUseEscher = true;
2569 A special case for converting some inline form controls to form fields
2570 when in winword 8+ mode
2572 if ((bUseEscher == true) && (eType == sw::Frame::eFormControl))
2574 if ( m_rWW8Export.MiserableFormFieldExportHack( rFrmFmt ) )
2575 return ;
2579 if (bUseEscher)
2581 OSL_ENSURE( m_rWW8Export.bWrtWW8, "this has gone horribly wrong" );
2582 // write as escher
2583 m_rWW8Export.AppendFlyInFlys(rFmt, rNdTopLeft);
2585 else
2587 bool bDone = false;
2589 // Hole vom Node und vom letzten Node die Position in der Section
2590 const SwNodeIndex* pNodeIndex = rFrmFmt.GetCntnt().GetCntntIdx();
2592 sal_uLong nStt = pNodeIndex ? pNodeIndex->GetIndex()+1 : 0;
2593 sal_uLong nEnd = pNodeIndex ? pNodeIndex->GetNode().EndOfSectionIndex() : 0;
2595 if( nStt >= nEnd ) // no range, hence no valid node
2596 return;
2598 if ( !m_rWW8Export.IsInTable() && rFmt.IsInline() )
2600 //Test to see if this textbox contains only a single graphic/ole
2601 SwTxtNode* pParTxtNode = rAnch.GetCntntAnchor()->nNode.GetNode().GetTxtNode();
2602 if ( pParTxtNode && !m_rWW8Export.pDoc->GetNodes()[ nStt ]->IsNoTxtNode() )
2603 bDone = true;
2605 if( !bDone )
2608 m_rWW8Export.SaveData( nStt, nEnd );
2610 Point aOffset;
2611 if ( m_rWW8Export.mpParentFrame )
2613 /* Munge flys in fly into absolutely positioned elements for word 6 */
2614 const SwTxtNode* pParTxtNode = rAnch.GetCntntAnchor()->nNode.GetNode().GetTxtNode();
2615 const SwRect aPageRect = pParTxtNode->FindPageFrmRect( sal_False, 0, sal_False );
2617 aOffset = rFrmFmt.FindLayoutRect().Pos();
2618 aOffset -= aPageRect.Pos();
2620 m_rWW8Export.pFlyOffset = &aOffset;
2621 m_rWW8Export.eNewAnchorType = FLY_AT_PAGE;
2624 m_rWW8Export.mpParentFrame = &rFmt;
2625 if (
2626 m_rWW8Export.IsInTable() &&
2627 (FLY_AT_PAGE != rAnch.GetAnchorId()) &&
2628 !m_rWW8Export.pDoc->GetNodes()[ nStt ]->IsNoTxtNode()
2631 // note: set Flag bOutTable again,
2632 // because we deliver the normal content of the table cell, and no border
2633 // ( Flag was deleted above in aSaveData() )
2634 m_rWW8Export.bOutTable = true;
2635 const String& rName = rFrmFmt.GetName();
2636 m_rWW8Export.StartCommentOutput(rName);
2637 m_rWW8Export.WriteText();
2638 m_rWW8Export.EndCommentOutput(rName);
2640 else
2641 m_rWW8Export.WriteText();
2643 m_rWW8Export.RestoreData();
2648 void AttributeOutputBase::OutputFlyFrame( const sw::Frame& rFmt )
2650 if ( !rFmt.GetCntntNode() )
2651 return;
2653 const SwCntntNode &rNode = *rFmt.GetCntntNode();
2654 Point aNdPos, aPgPos;
2655 Point* pLayPos;
2656 bool bValidNdPos = false, bValidPgPos = false;
2658 if (FLY_AT_PAGE == rFmt.GetFrmFmt().GetAnchor().GetAnchorId())
2660 // get the Layout Node-Position.
2661 if ( !bValidPgPos )
2663 aPgPos = rNode.FindPageFrmRect(false, &aPgPos).Pos();
2664 bValidPgPos = true;
2666 pLayPos = &aPgPos;
2668 else
2670 // get the Layout Node-Position.
2671 if ( !bValidNdPos )
2673 aNdPos = rNode.FindLayoutRect(false, &aNdPos).Pos();
2674 bValidNdPos = true;
2676 pLayPos = &aNdPos;
2679 OutputFlyFrame_Impl( rFmt, *pLayPos );
2682 // write data of any redline
2683 void WW8AttributeOutput::Redline( const SwRedlineData* pRedline )
2685 if ( !pRedline )
2686 return;
2688 if ( pRedline->Next() )
2689 Redline( pRedline->Next() );
2691 static sal_uInt16 aSprmIds[ 2 * 2 * 3 ] =
2693 // Ids for insert
2694 NS_sprm::LN_CFRMark, NS_sprm::LN_CIbstRMark, NS_sprm::LN_CDttmRMark, // for WW8
2695 0x0042, 0x0045, 0x0046, // for WW6
2696 // Ids for delete
2697 NS_sprm::LN_CFRMarkDel, NS_sprm::LN_CIbstRMarkDel, NS_sprm::LN_CDttmRMarkDel, // for WW8
2698 0x0041, 0x0045, 0x0046 // for WW6
2701 const sal_uInt16* pSprmIds = 0;
2702 switch( pRedline->GetType() )
2704 case nsRedlineType_t::REDLINE_INSERT:
2705 pSprmIds = aSprmIds;
2706 break;
2708 case nsRedlineType_t::REDLINE_DELETE:
2709 pSprmIds = aSprmIds + (2 * 3);
2710 break;
2712 case nsRedlineType_t::REDLINE_FORMAT:
2713 if( m_rWW8Export.bWrtWW8 )
2715 m_rWW8Export.InsUInt16( NS_sprm::LN_CPropRMark );
2716 m_rWW8Export.pO->push_back( 7 ); // len
2717 m_rWW8Export.pO->push_back( 1 );
2718 m_rWW8Export.InsUInt16( m_rWW8Export.AddRedlineAuthor( pRedline->GetAuthor() ) );
2719 m_rWW8Export.InsUInt32( sw::ms::DateTime2DTTM( pRedline->GetTimeStamp() ));
2721 break;
2722 default:
2723 OSL_ENSURE(!this, "Unhandled redline type for export");
2724 break;
2727 if ( pSprmIds )
2729 if ( !m_rWW8Export.bWrtWW8 )
2730 pSprmIds += 3;
2732 if ( m_rWW8Export.bWrtWW8 )
2733 m_rWW8Export.InsUInt16( pSprmIds[0] );
2734 else
2735 m_rWW8Export.pO->push_back( msword_cast<sal_uInt8>(pSprmIds[0]) );
2736 m_rWW8Export.pO->push_back( 1 );
2738 if ( m_rWW8Export.bWrtWW8 )
2739 m_rWW8Export.InsUInt16( pSprmIds[1] );
2740 else
2741 m_rWW8Export.pO->push_back( msword_cast<sal_uInt8>(pSprmIds[1]) );
2742 m_rWW8Export.InsUInt16( m_rWW8Export.AddRedlineAuthor( pRedline->GetAuthor() ) );
2744 if ( m_rWW8Export.bWrtWW8 )
2745 m_rWW8Export.InsUInt16( pSprmIds[2] );
2746 else
2747 m_rWW8Export.pO->push_back( msword_cast<sal_uInt8>(pSprmIds[2]) );
2748 m_rWW8Export.InsUInt32( sw::ms::DateTime2DTTM( pRedline->GetTimeStamp() ));
2753 void MSWordExportBase::OutputContentNode( const SwCntntNode& rNode )
2755 switch ( rNode.GetNodeType() )
2757 case ND_TEXTNODE:
2759 const SwTxtNode& rTextNode = *rNode.GetTxtNode();
2760 if( !mbOutOutlineOnly || rTextNode.IsOutline() )
2761 OutputTextNode( rTextNode );
2763 break;
2764 case ND_GRFNODE:
2765 OutputGrfNode( *rNode.GetGrfNode() );
2766 break;
2767 case ND_OLENODE:
2768 OutputOLENode( *rNode.GetOLENode() );
2769 break;
2770 default:
2771 OSL_TRACE("Unhandled node, type == %d", rNode.GetNodeType() );
2772 break;
2776 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */