1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sw.hxx" 30 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */ 31 32 #include <vector> 33 #include <list> 34 #include <utility> 35 #include <algorithm> 36 #include <functional> 37 #include <iostream> 38 #if OSL_DEBUG_LEVEL > 0 39 # include <cstdio> 40 #endif 41 42 #include <hintids.hxx> 43 #include <tools/urlobj.hxx> 44 #include <editeng/boxitem.hxx> 45 #include <editeng/cmapitem.hxx> 46 #include <editeng/langitem.hxx> 47 #include <editeng/svxfont.hxx> 48 #include <editeng/lrspitem.hxx> 49 #include <editeng/brshitem.hxx> 50 #include <editeng/fontitem.hxx> 51 #include <editeng/keepitem.hxx> 52 #include <editeng/fhgtitem.hxx> 53 #include <editeng/ulspitem.hxx> 54 #include <editeng/brkitem.hxx> 55 #include <editeng/frmdiritem.hxx> 56 #include <editeng/tstpitem.hxx> 57 #include "svl/urihelper.hxx" 58 #include <svl/whiter.hxx> 59 #include <fmtpdsc.hxx> 60 #include <fmtfsize.hxx> 61 #include <fmtornt.hxx> 62 #include <fmtlsplt.hxx> 63 #include <fmtflcnt.hxx> 64 #include <fmtanchr.hxx> 65 #include <fmtcntnt.hxx> 66 #include <frmatr.hxx> 67 #include <paratr.hxx> 68 #include <txatbase.hxx> 69 #include <fmtinfmt.hxx> 70 #include <fmtrfmrk.hxx> 71 #include <fchrfmt.hxx> 72 #include <fmtautofmt.hxx> 73 #include <charfmt.hxx> 74 #include <tox.hxx> 75 #include <ndtxt.hxx> 76 #include <pam.hxx> 77 #include <doc.hxx> 78 #include <docary.hxx> 79 #include <swtable.hxx> 80 #include <swtblfmt.hxx> 81 #include <section.hxx> 82 #include <pagedesc.hxx> 83 #include <swrect.hxx> 84 #include <reffld.hxx> 85 #include <redline.hxx> 86 #include <wrtswtbl.hxx> 87 #include <htmltbl.hxx> 88 #include <txttxmrk.hxx> 89 #include <fmtline.hxx> 90 #include <fmtruby.hxx> 91 #include <breakit.hxx> 92 #include <txtatr.hxx> 93 #include <fmtsrnd.hxx> 94 #include <fmtrowsplt.hxx> 95 #include <com/sun/star/i18n/ScriptType.hdl> 96 #include <com/sun/star/i18n/WordType.hpp> 97 98 #include <writerfilter/doctok/sprmids.hxx> 99 100 #include "writerhelper.hxx" 101 #include "writerwordglue.hxx" 102 #include <numrule.hxx> 103 #include "wrtww8.hxx" 104 #include "ww8par.hxx" 105 #include <IMark.hxx> 106 #include "ww8attributeoutput.hxx" 107 108 #include <ndgrf.hxx> 109 #include <ndole.hxx> 110 111 #include <cstdio> 112 113 using namespace ::com::sun::star; 114 using namespace ::com::sun::star::i18n; 115 using namespace sw::util; 116 using namespace sw::types; 117 using namespace sw::mark; 118 using namespace nsFieldFlags; 119 120 121 static String lcl_getFieldCode( const IFieldmark* pFieldmark ) { 122 ASSERT(pFieldmark!=NULL, "where is my fieldmark???"); 123 if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMTEXT ) ) { 124 return String::CreateFromAscii(" FORMTEXT "); 125 } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMDROPDOWN ) ) { 126 return String::CreateFromAscii(" FORMDROPDOWN "); 127 } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMCHECKBOX ) ) { 128 return String::CreateFromAscii(" FORMCHECKBOX "); 129 } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_TOC ) ) { 130 return String::CreateFromAscii(" TOC "); 131 } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_HYPERLINK ) ) { 132 return String::CreateFromAscii(" HYPERLINK "); 133 } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_PAGEREF ) ) { 134 return String::CreateFromAscii(" PAGEREF "); 135 } else { 136 return pFieldmark->GetFieldname(); 137 } 138 } 139 140 ww::eField lcl_getFieldId( const IFieldmark* pFieldmark ) { 141 ASSERT(pFieldmark!=NULL, "where is my fieldmark???"); 142 if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMTEXT ) ) { 143 return ww::eFORMTEXT; 144 } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMDROPDOWN ) ) { 145 return ww::eFORMDROPDOWN; 146 } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMCHECKBOX ) ) { 147 return ww::eFORMCHECKBOX; 148 } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_TOC ) ) { 149 return ww::eTOC; 150 } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_HYPERLINK ) ) { 151 return ww::eHYPERLINK; 152 } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_PAGEREF ) ) { 153 return ww::ePAGEREF; 154 } else { 155 return ww::eUNKNOWN; 156 } 157 } 158 159 /* */ 160 161 MSWordAttrIter::MSWordAttrIter( MSWordExportBase& rExport ) 162 : pOld( rExport.pChpIter ), m_rExport( rExport ) 163 { 164 m_rExport.pChpIter = this; 165 } 166 167 MSWordAttrIter::~MSWordAttrIter() 168 { 169 m_rExport.pChpIter = pOld; 170 } 171 172 // Die Klasse SwAttrIter ist eine Hilfe zum Aufbauen der Fkp.chpx. 173 // Dabei werden nur Zeichen-Attribute beachtet; Absatz-Attribute brauchen 174 // diese Behandlung nicht. 175 // Die Absatz- und Textattribute des Writers kommen rein, und es wird 176 // mit Where() die naechste Position geliefert, an der sich die Attribute 177 // aendern. IsTxtAtr() sagt, ob sich an der mit Where() gelieferten Position 178 // ein Attribut ohne Ende und mit \xff im Text befindet. 179 // Mit OutAttr() werden die Attribute an der angegebenen SwPos 180 // ausgegeben. 181 182 class WW8SwAttrIter : public MSWordAttrIter 183 { 184 private: 185 const SwTxtNode& rNd; 186 187 CharRuns maCharRuns; 188 cCharRunIter maCharRunIter; 189 190 rtl_TextEncoding meChrSet; 191 sal_uInt16 mnScript; 192 bool mbCharIsRTL; 193 194 const SwRedline* pCurRedline; 195 xub_StrLen nAktSwPos; 196 sal_uInt16 nCurRedlinePos; 197 198 bool mbParaIsRTL; 199 200 const SwFmtDrop &mrSwFmtDrop; 201 202 sw::Frames maFlyFrms; // #i2916# 203 sw::FrameIter maFlyIter; 204 205 xub_StrLen SearchNext( xub_StrLen nStartPos ); 206 void FieldVanish( const String& rTxt ); 207 208 void OutSwFmtRefMark(const SwFmtRefMark& rAttr, bool bStart); 209 210 void IterToCurrent(); 211 212 //No copying 213 WW8SwAttrIter(const WW8SwAttrIter&); 214 WW8SwAttrIter& operator=(const WW8SwAttrIter&); 215 public: 216 WW8SwAttrIter( MSWordExportBase& rWr, const SwTxtNode& rNd ); 217 218 bool IsTxtAttr( xub_StrLen nSwPos ); 219 bool IsRedlineAtEnd( xub_StrLen nPos ) const; 220 bool IsDropCap( int nSwPos ); 221 bool RequiresImplicitBookmark(); 222 223 void NextPos() { nAktSwPos = SearchNext( nAktSwPos + 1 ); } 224 225 void OutAttr( xub_StrLen nSwPos ); 226 virtual const SfxPoolItem* HasTextItem( sal_uInt16 nWhich ) const; 227 virtual const SfxPoolItem& GetItem( sal_uInt16 nWhich ) const; 228 int OutAttrWithRange(xub_StrLen nPos); 229 const SwRedlineData* GetRedline( xub_StrLen nPos ); 230 void OutFlys(xub_StrLen nSwPos); 231 232 xub_StrLen WhereNext() const { return nAktSwPos; } 233 sal_uInt16 GetScript() const { return mnScript; } 234 bool IsCharRTL() const { return mbCharIsRTL; } 235 bool IsParaRTL() const { return mbParaIsRTL; } 236 rtl_TextEncoding GetCharSet() const { return meChrSet; } 237 String GetSnippet(const String &rStr, xub_StrLen nAktPos, 238 xub_StrLen nLen) const; 239 const SwFmtDrop& GetSwFmtDrop() const { return mrSwFmtDrop; } 240 }; 241 242 class sortswflys : 243 public std::binary_function<const sw::Frame&, const sw::Frame&, bool> 244 { 245 public: 246 bool operator()(const sw::Frame &rOne, const sw::Frame &rTwo) const 247 { 248 return rOne.GetPosition() < rTwo.GetPosition(); 249 } 250 }; 251 252 void WW8SwAttrIter::IterToCurrent() 253 { 254 ASSERT(maCharRuns.begin() != maCharRuns.end(), "Impossible"); 255 mnScript = maCharRunIter->mnScript; 256 meChrSet = maCharRunIter->meCharSet; 257 mbCharIsRTL = maCharRunIter->mbRTL; 258 } 259 260 WW8SwAttrIter::WW8SwAttrIter(MSWordExportBase& rWr, const SwTxtNode& rTxtNd) : 261 MSWordAttrIter(rWr), 262 rNd(rTxtNd), 263 maCharRuns(GetPseudoCharRuns(rTxtNd, 0, !rWr.HackIsWW8OrHigher())), 264 pCurRedline(0), 265 nAktSwPos(0), 266 nCurRedlinePos(USHRT_MAX), 267 mrSwFmtDrop(rTxtNd.GetSwAttrSet().GetDrop()) 268 { 269 270 SwPosition aPos(rTxtNd); 271 if (FRMDIR_HORI_RIGHT_TOP == rWr.pDoc->GetTextDirection(aPos)) 272 mbParaIsRTL = true; 273 else 274 mbParaIsRTL = false; 275 276 maCharRunIter = maCharRuns.begin(); 277 IterToCurrent(); 278 279 /* 280 #i2916# 281 Get list of any graphics which may be anchored from this paragraph. 282 */ 283 maFlyFrms = GetFramesInNode(rWr.maFrames, rNd); 284 std::sort(maFlyFrms.begin(), maFlyFrms.end(), sortswflys()); 285 286 /* 287 #i18480# 288 If we are inside a frame then anything anchored inside this frame can 289 only be supported by word anchored inline ("as character"), so force 290 this in the supportable case. 291 */ 292 if (rWr.HackIsWW8OrHigher() && rWr.bInWriteEscher) 293 { 294 std::for_each(maFlyFrms.begin(), maFlyFrms.end(), 295 std::mem_fun_ref(&sw::Frame::ForceTreatAsInline)); 296 } 297 298 maFlyIter = maFlyFrms.begin(); 299 300 if ( m_rExport.pDoc->GetRedlineTbl().Count() ) 301 { 302 SwPosition aPosition( rNd, SwIndex( (SwTxtNode*)&rNd ) ); 303 pCurRedline = m_rExport.pDoc->GetRedline( aPosition, &nCurRedlinePos ); 304 } 305 306 nAktSwPos = SearchNext(1); 307 } 308 309 xub_StrLen lcl_getMinPos( xub_StrLen pos1, xub_StrLen pos2 ) 310 { 311 xub_StrLen min = STRING_NOTFOUND; 312 if ( pos1 == STRING_NOTFOUND && pos2 != STRING_NOTFOUND ) 313 min = pos2; 314 else if ( pos2 == STRING_NOTFOUND && pos1 != STRING_NOTFOUND ) 315 min = pos1; 316 else if ( pos2 != STRING_NOTFOUND && pos2 != STRING_NOTFOUND ) 317 { 318 if ( pos1 < pos2 ) 319 min = pos1; 320 else 321 min = pos2; 322 } 323 324 return min; 325 } 326 327 xub_StrLen WW8SwAttrIter::SearchNext( xub_StrLen nStartPos ) 328 { 329 xub_StrLen nPos; 330 xub_StrLen nMinPos = STRING_MAXLEN; 331 xub_StrLen i=0; 332 333 const String aTxt = rNd.GetTxt(); 334 xub_StrLen fieldEndPos = aTxt.Search(CH_TXT_ATR_FIELDEND, nStartPos); 335 xub_StrLen fieldStartPos = aTxt.Search(CH_TXT_ATR_FIELDSTART, nStartPos); 336 xub_StrLen formElementPos = aTxt.Search(CH_TXT_ATR_FORMELEMENT, nStartPos); 337 338 xub_StrLen pos = lcl_getMinPos( fieldEndPos, fieldStartPos ); 339 pos = lcl_getMinPos( pos, formElementPos ); 340 341 if (pos!=STRING_NOTFOUND) 342 nMinPos=pos; 343 344 // first the redline, then the attributes 345 if( pCurRedline ) 346 { 347 const SwPosition* pEnd = pCurRedline->End(); 348 if (pEnd->nNode == rNd && ((i = pEnd->nContent.GetIndex()) >= nStartPos) && i < nMinPos ) 349 nMinPos = i; 350 } 351 352 if ( nCurRedlinePos < m_rExport.pDoc->GetRedlineTbl().Count() ) 353 { 354 // nCurRedlinePos point to the next redline 355 nPos = nCurRedlinePos; 356 if( pCurRedline ) 357 ++nPos; 358 359 for ( ; nPos < m_rExport.pDoc->GetRedlineTbl().Count(); ++nPos ) 360 { 361 const SwRedline* pRedl = m_rExport.pDoc->GetRedlineTbl()[ nPos ]; 362 363 const SwPosition* pStt = pRedl->Start(); 364 const SwPosition* pEnd = pStt == pRedl->GetPoint() 365 ? pRedl->GetMark() 366 : pRedl->GetPoint(); 367 368 if( pStt->nNode == rNd ) 369 { 370 if( ( i = pStt->nContent.GetIndex() ) >= nStartPos && 371 i < nMinPos ) 372 nMinPos = i; 373 } 374 else 375 break; 376 377 if( pEnd->nNode == rNd && 378 ( i = pEnd->nContent.GetIndex() ) < nMinPos && 379 i >= nStartPos ) 380 nMinPos = i; 381 } 382 } 383 384 385 if (mrSwFmtDrop.GetWholeWord() && nStartPos <= rNd.GetDropLen(0)) 386 nMinPos = rNd.GetDropLen(0); 387 else if(nStartPos <= mrSwFmtDrop.GetChars()) 388 nMinPos = mrSwFmtDrop.GetChars(); 389 390 if(const SwpHints* pTxtAttrs = rNd.GetpSwpHints()) 391 { 392 393 // kann noch optimiert werden, wenn ausgenutzt wird, dass die TxtAttrs 394 // nach der Anfangsposition geordnet sind. Dann muessten 395 // allerdings noch 2 Indices gemerkt werden 396 for( i = 0; i < pTxtAttrs->Count(); i++ ) 397 { 398 const SwTxtAttr* pHt = (*pTxtAttrs)[i]; 399 nPos = *pHt->GetStart(); // gibt erstes Attr-Zeichen 400 if( nPos >= nStartPos && nPos <= nMinPos ) 401 nMinPos = nPos; 402 403 if( pHt->GetEnd() ) // Attr mit Ende 404 { 405 nPos = *pHt->GetEnd(); // gibt letztes Attr-Zeichen + 1 406 if( nPos >= nStartPos && nPos <= nMinPos ) 407 nMinPos = nPos; 408 } 409 if (pHt->HasDummyChar()) 410 { 411 // pos + 1 because of CH_TXTATR in Text 412 nPos = *pHt->GetStart() + 1; 413 if( nPos >= nStartPos && nPos <= nMinPos ) 414 nMinPos = nPos; 415 } 416 } 417 } 418 419 if (maCharRunIter != maCharRuns.end()) 420 { 421 if (maCharRunIter->mnEndPos < nMinPos) 422 nMinPos = maCharRunIter->mnEndPos; 423 IterToCurrent(); 424 } 425 426 /* 427 #i2916# 428 Check to see if there are any graphics anchored to characters in this 429 paragraph's text. Set nMinPos to 1 past the placement for anchored to 430 character because anchors in Word appear after the character they are 431 anchored to. 432 */ 433 if (maFlyIter != maFlyFrms.end()) 434 { 435 const SwPosition &rAnchor = maFlyIter->GetPosition(); 436 437 nPos = rAnchor.nContent.GetIndex(); 438 if (nPos >= nStartPos && nPos <= nMinPos) 439 nMinPos = nPos; 440 441 if (maFlyIter->GetFrmFmt().GetAnchor().GetAnchorId() == FLY_AT_CHAR) 442 { 443 ++nPos; 444 if (nPos >= nStartPos && nPos <= nMinPos) 445 nMinPos = nPos; 446 } 447 } 448 449 //nMinPos found and not going to change at this point 450 451 if (maCharRunIter != maCharRuns.end()) 452 { 453 if (maCharRunIter->mnEndPos == nMinPos) 454 ++maCharRunIter; 455 } 456 457 return nMinPos; 458 } 459 460 void WW8SwAttrIter::OutAttr( xub_StrLen nSwPos ) 461 { 462 m_rExport.AttrOutput().RTLAndCJKState( IsCharRTL(), GetScript() ); 463 464 /* 465 Depending on whether text is in CTL/CJK or Western, get the id of that 466 script, the idea is that the font that is actually in use to render this 467 range of text ends up in pFont 468 */ 469 sal_uInt16 nFontId = GetWhichOfScript( RES_CHRATR_FONT, GetScript() ); 470 471 const SvxFontItem &rParentFont = ItemGet<SvxFontItem>( 472 (const SwTxtFmtColl&)rNd.GetAnyFmtColl(), nFontId); 473 const SvxFontItem *pFont = &rParentFont; 474 475 SfxItemSet aExportSet(*rNd.GetSwAttrSet().GetPool(), 476 RES_CHRATR_BEGIN, RES_TXTATR_END - 1); 477 478 //The hard formatting properties that affect the entire paragraph 479 if (rNd.HasSwAttrSet()) 480 { 481 sal_Bool bDeep = sal_False; 482 // only copy hard attributes - bDeep = false 483 aExportSet.Set(rNd.GetSwAttrSet(), bDeep); 484 // get the current font item. Use rNd.GetSwAttrSet instead of aExportSet: 485 const SvxFontItem &rNdFont = ItemGet<SvxFontItem>(rNd.GetSwAttrSet(), nFontId); 486 pFont = &rNdFont; 487 aExportSet.ClearItem(nFontId); 488 } 489 490 //The additional hard formatting properties that affect this range in the 491 //paragraph 492 sw::PoolItems aRangeItems; 493 if (const SwpHints* pTxtAttrs = rNd.GetpSwpHints()) 494 { 495 for (xub_StrLen i = 0; i < pTxtAttrs->Count(); ++i) 496 { 497 const SwTxtAttr* pHt = (*pTxtAttrs)[i]; 498 const xub_StrLen* pEnd = pHt->GetEnd(); 499 500 if (pEnd ? ( nSwPos >= *pHt->GetStart() && nSwPos < *pEnd) 501 : nSwPos == *pHt->GetStart() ) 502 { 503 sal_uInt16 nWhich = pHt->GetAttr().Which(); 504 if (nWhich == RES_TXTATR_AUTOFMT) 505 { 506 const SwFmtAutoFmt& rAutoFmt = static_cast<const SwFmtAutoFmt&>(pHt->GetAttr()); 507 const boost::shared_ptr<SfxItemSet> pSet = rAutoFmt.GetStyleHandle(); 508 SfxWhichIter aIter( *pSet ); 509 const SfxPoolItem* pItem; 510 sal_uInt16 nWhichId = aIter.FirstWhich(); 511 while( nWhichId ) 512 { 513 if( SFX_ITEM_SET == pSet->GetItemState( nWhichId, sal_False, &pItem )) 514 { 515 if (nWhichId == nFontId) 516 pFont = &(item_cast<SvxFontItem>(*pItem)); 517 else 518 aRangeItems[nWhichId] = pItem; 519 } 520 nWhichId = aIter.NextWhich(); 521 } 522 } 523 else 524 aRangeItems[nWhich] = (&(pHt->GetAttr())); 525 } 526 else if (nSwPos < *pHt->GetStart()) 527 break; 528 } 529 } 530 531 /* 532 For #i24291# we need to explictly remove any properties from the 533 aExportSet which a SwCharFmt would override, we can't rely on word doing 534 this for us like writer does 535 */ 536 const SwFmtCharFmt *pCharFmtItem = 537 HasItem< SwFmtCharFmt >( aRangeItems, RES_TXTATR_CHARFMT ); 538 if ( pCharFmtItem ) 539 ClearOverridesFromSet( *pCharFmtItem, aExportSet ); 540 541 sw::PoolItems aExportItems; 542 GetPoolItems( aExportSet, aExportItems, false ); 543 544 sw::cPoolItemIter aEnd = aRangeItems.end(); 545 for ( sw::cPoolItemIter aI = aRangeItems.begin(); aI != aEnd; ++aI ) 546 aExportItems[aI->first] = aI->second; 547 548 if ( !aExportItems.empty() ) 549 { 550 const SwModify* pOldMod = m_rExport.pOutFmtNode; 551 m_rExport.pOutFmtNode = &rNd; 552 m_rExport.m_aCurrentCharPropStarts.push( nSwPos ); 553 554 m_rExport.ExportPoolItemsToCHP( aExportItems, GetScript() ); 555 556 // HasTextItem nur in dem obigen Bereich erlaubt 557 m_rExport.m_aCurrentCharPropStarts.pop(); 558 m_rExport.pOutFmtNode = pOldMod; 559 } 560 561 ASSERT( pFont, "must be *some* font associated with this txtnode" ); 562 if ( pFont ) 563 { 564 SvxFontItem aFont( *pFont ); 565 566 /* 567 If we are a nonunicode aware format then we set the charset we want to 568 use for export of this range. If necessary this will generate a pseudo 569 font to use for this range. 570 571 So now we are guaranteed to have a font with the correct charset set 572 for WW6/95 which will match the script we have exported this range in, 573 this makes older nonunicode aware versions of word display the correct 574 characters. 575 */ 576 if ( !m_rExport.HackIsWW8OrHigher() ) 577 aFont.SetCharSet( GetCharSet() ); 578 579 if ( rParentFont != aFont ) 580 m_rExport.AttrOutput().OutputItem( aFont ); 581 } 582 } 583 584 void WW8SwAttrIter::OutFlys(xub_StrLen nSwPos) 585 { 586 /* 587 #i2916# 588 May have an anchored graphic to be placed, loop through sorted array 589 and output all at this position 590 */ 591 while ( maFlyIter != maFlyFrms.end() ) 592 { 593 const SwPosition &rAnchor = maFlyIter->GetPosition(); 594 xub_StrLen nPos = rAnchor.nContent.GetIndex(); 595 596 if ( nPos != nSwPos ) 597 break; 598 else 599 { 600 m_rExport.AttrOutput().OutputFlyFrame( *maFlyIter ); 601 ++maFlyIter; 602 } 603 } 604 } 605 606 bool WW8SwAttrIter::IsTxtAttr( xub_StrLen nSwPos ) 607 { 608 // search for attrs with CH_TXTATR 609 if (const SwpHints* pTxtAttrs = rNd.GetpSwpHints()) 610 { 611 for (sal_uInt16 i = 0; i < pTxtAttrs->Count(); ++i) 612 { 613 const SwTxtAttr* pHt = (*pTxtAttrs)[i]; 614 if ( pHt->HasDummyChar() && (*pHt->GetStart() == nSwPos) ) 615 return true; 616 } 617 } 618 619 return false; 620 } 621 622 bool WW8SwAttrIter::IsDropCap( int nSwPos ) 623 { 624 // see if the current position falls on a DropCap 625 int nDropChars = mrSwFmtDrop.GetChars(); 626 bool bWholeWord = mrSwFmtDrop.GetWholeWord(); 627 if (bWholeWord) 628 { 629 short nWordLen = rNd.GetDropLen(0); 630 if(nSwPos == nWordLen && nSwPos != 0) 631 return true; 632 } 633 else 634 { 635 if (nSwPos == nDropChars && nSwPos != 0) 636 return true; 637 } 638 return false; 639 } 640 641 bool WW8SwAttrIter::RequiresImplicitBookmark() 642 { 643 SwImplBookmarksIter bkmkIterEnd = m_rExport.maImplicitBookmarks.end(); 644 for ( SwImplBookmarksIter aIter = m_rExport.maImplicitBookmarks.begin(); aIter != bkmkIterEnd; ++aIter ) 645 { 646 sal_uLong sample = aIter->second; 647 648 if ( sample == rNd.GetIndex() ) 649 return true; 650 } 651 return false; 652 } 653 654 // HasItem ist fuer die Zusammenfassung des Doppel-Attributes Underline 655 // und WordLineMode als TextItems. OutAttr() ruft die Ausgabefunktion, 656 // die dann ueber HasItem() nach anderen Items an der 657 // Attribut-Anfangposition fragen kann. 658 // Es koennen nur Attribute mit Ende abgefragt werden. 659 // Es wird mit bDeep gesucht 660 const SfxPoolItem* WW8SwAttrIter::HasTextItem( sal_uInt16 nWhich ) const 661 { 662 const SfxPoolItem* pRet = 0; 663 const SwpHints* pTxtAttrs = rNd.GetpSwpHints(); 664 xub_StrLen nTmpSwPos = m_rExport.m_aCurrentCharPropStarts.top(); 665 if (pTxtAttrs) 666 { 667 for (sal_uInt16 i = 0; i < pTxtAttrs->Count(); ++i) 668 { 669 const SwTxtAttr* pHt = (*pTxtAttrs)[i]; 670 const SfxPoolItem* pItem = &pHt->GetAttr(); 671 const xub_StrLen* pAtrEnd = 0; 672 if( 0 != ( pAtrEnd = pHt->GetEnd() ) && // nur Attr mit Ende 673 nWhich == pItem->Which() && // 674 nTmpSwPos >= *pHt->GetStart() && nTmpSwPos < *pAtrEnd ) 675 { 676 pRet = pItem; // gefunden 677 break; 678 } 679 else if (nTmpSwPos < *pHt->GetStart()) 680 break; // dann kommt da nichts mehr 681 } 682 } 683 return pRet; 684 } 685 686 void WW8Export::GetCurrentItems(WW8Bytes& rItems) const 687 { 688 sal_uInt16 nEnd = pO ? pO->Count() : 0; 689 for (sal_uInt16 nI = 0; nI < nEnd; ++nI) 690 rItems.Insert((*pO)[nI], rItems.Count()); 691 } 692 693 const SfxPoolItem& WW8SwAttrIter::GetItem(sal_uInt16 nWhich) const 694 { 695 const SfxPoolItem* pRet = HasTextItem(nWhich); 696 return pRet ? *pRet : rNd.SwCntntNode::GetAttr(nWhich); 697 } 698 699 void WW8AttributeOutput::StartRuby( const SwTxtNode& rNode, const SwFmtRuby& rRuby ) 700 { 701 String aStr( FieldString( ww::eEQ ) ); 702 aStr.APPEND_CONST_ASC( "\\* jc" ); 703 sal_Int32 nJC = 0; 704 sal_Char cDirective = 0; 705 switch ( rRuby.GetAdjustment() ) 706 { 707 case 0: 708 nJC = 3; 709 cDirective = 'l'; 710 break; 711 case 1: 712 //defaults to 0 713 break; 714 case 2: 715 nJC = 4; 716 cDirective = 'r'; 717 break; 718 case 3: 719 nJC = 1; 720 cDirective = 'd'; 721 break; 722 case 4: 723 nJC = 2; 724 cDirective = 'd'; 725 break; 726 default: 727 ASSERT( !this,"Unhandled Ruby justication code" ); 728 break; 729 } 730 aStr += String::CreateFromInt32( nJC ); 731 732 /* 733 MS needs to know the name and size of the font used in the ruby item, 734 but we coud have written it in a mixture of asian and western 735 scripts, and each of these can be a different font and size than the 736 other, so we make a guess based upon the first character of the text, 737 defaulting to asian. 738 */ 739 sal_uInt16 nRubyScript; 740 if( pBreakIt->GetBreakIter().is() ) 741 nRubyScript = pBreakIt->GetBreakIter()->getScriptType( rRuby.GetText(), 0); 742 else 743 nRubyScript = i18n::ScriptType::ASIAN; 744 745 const SwTxtRuby* pRubyTxt = rRuby.GetTxtRuby(); 746 const SwCharFmt* pFmt = pRubyTxt ? pRubyTxt->GetCharFmt() : 0; 747 String sFamilyName; 748 long nHeight; 749 if ( pFmt ) 750 { 751 const SvxFontItem &rFont = ItemGet< SvxFontItem >( *pFmt, 752 GetWhichOfScript(RES_CHRATR_FONT,nRubyScript) ); 753 sFamilyName = rFont.GetFamilyName(); 754 755 const SvxFontHeightItem &rHeight = ItemGet< SvxFontHeightItem >( *pFmt, 756 GetWhichOfScript( RES_CHRATR_FONTSIZE, nRubyScript ) ); 757 nHeight = rHeight.GetHeight(); 758 } 759 else 760 { 761 /*Get defaults if no formatting on ruby text*/ 762 763 const SfxItemPool *pPool = rNode.GetSwAttrSet().GetPool(); 764 const SfxItemPool &rPool = pPool ? *pPool : m_rWW8Export.pDoc->GetAttrPool(); 765 766 const SvxFontItem &rFont = DefaultItemGet< SvxFontItem >( rPool, 767 GetWhichOfScript( RES_CHRATR_FONT,nRubyScript ) ); 768 sFamilyName = rFont.GetFamilyName(); 769 770 const SvxFontHeightItem &rHeight = DefaultItemGet< SvxFontHeightItem > 771 ( rPool, GetWhichOfScript( RES_CHRATR_FONTSIZE, nRubyScript ) ); 772 nHeight = rHeight.GetHeight(); 773 } 774 nHeight = (nHeight + 5)/10; 775 776 aStr.APPEND_CONST_ASC( " \\* \"Font:" ); 777 aStr.Append( sFamilyName ); 778 aStr.APPEND_CONST_ASC( "\" \\* hps" ); 779 aStr += String::CreateFromInt32( nHeight ); 780 aStr.APPEND_CONST_ASC( " \\o" ); 781 if ( cDirective ) 782 { 783 aStr.APPEND_CONST_ASC( "\\a" ); 784 aStr.Append( cDirective ); 785 } 786 aStr.APPEND_CONST_ASC( "(\\s\\up " ); 787 788 789 if ( pBreakIt->GetBreakIter().is() ) 790 nRubyScript = pBreakIt->GetBreakIter()->getScriptType( rNode.GetTxt(), 791 *( pRubyTxt->GetStart() ) ); 792 else 793 nRubyScript = i18n::ScriptType::ASIAN; 794 795 const SwAttrSet& rSet = rNode.GetSwAttrSet(); 796 const SvxFontHeightItem &rHeightItem = 797 ( const SvxFontHeightItem& )rSet.Get( 798 GetWhichOfScript( RES_CHRATR_FONTSIZE, nRubyScript ) ); 799 nHeight = (rHeightItem.GetHeight() + 10)/20-1; 800 aStr += String::CreateFromInt32(nHeight); 801 aStr += '('; 802 aStr += rRuby.GetText(); 803 aStr.APPEND_CONST_ASC( ");" ); 804 m_rWW8Export.OutputField( 0, ww::eEQ, aStr, 805 WRITEFIELD_START | WRITEFIELD_CMD_START ); 806 } 807 808 void WW8AttributeOutput::EndRuby() 809 { 810 m_rWW8Export.WriteChar( ')' ); 811 m_rWW8Export.OutputField( 0, ww::eEQ, aEmptyStr, WRITEFIELD_END | WRITEFIELD_CLOSE ); 812 } 813 814 /*#i15387# Better ideas welcome*/ 815 String &TruncateBookmark( String &rRet ) 816 { 817 if ( rRet.Len() > 40 ) 818 rRet.Erase( 40 ); 819 ASSERT( rRet.Len() <= 40, "Word cannot have bookmarks longer than 40 chars" ); 820 return rRet; 821 } 822 823 bool AttributeOutputBase::AnalyzeURL( const String& rUrl, const String& /*rTarget*/, String* pLinkURL, String* pMark ) 824 { 825 bool bBookMarkOnly = false; 826 827 INetURLObject aURL( rUrl ); 828 String sMark; 829 String sURL; 830 831 if ( rUrl.Len() > 1 && rUrl.GetChar(0) == INET_MARK_TOKEN ) 832 { 833 sMark = BookmarkToWriter( rUrl.Copy(1) ); 834 835 xub_StrLen nPos = sMark.SearchBackward( cMarkSeperator ); 836 837 String sRefType( sMark.Copy( nPos+1 ) ); 838 sRefType.EraseAllChars(); 839 840 // i21465 Only interested in outline references 841 if ( sRefType.EqualsAscii( pMarkToOutline ) ) 842 { 843 String sLink = sMark.Copy(0, nPos); 844 SwImplBookmarksIter bkmkIterEnd = GetExport().maImplicitBookmarks.end(); 845 for ( SwImplBookmarksIter aIter = GetExport().maImplicitBookmarks.begin(); aIter != bkmkIterEnd; ++aIter ) 846 { 847 String bkmkName = aIter->first; 848 849 if ( bkmkName == sLink ) 850 { 851 sMark = String( RTL_CONSTASCII_STRINGPARAM( "_toc" ) ); 852 sMark += String::CreateFromInt32( aIter->second ); 853 } 854 } 855 } 856 } 857 else 858 { 859 sURL = aURL.GetURLNoMark( INetURLObject::DECODE_UNAMBIGUOUS ); 860 sMark = aURL.GetMark( INetURLObject::DECODE_UNAMBIGUOUS ); 861 862 } 863 864 if ( sMark.Len() && !sURL.Len() ) 865 bBookMarkOnly = true; 866 867 868 869 *pMark = sMark; 870 *pLinkURL = sURL; 871 return bBookMarkOnly; 872 } 873 874 bool WW8AttributeOutput::AnalyzeURL( const String& rUrl, const String& rTarget, String* pLinkURL, String* pMark ) 875 { 876 bool bBookMarkOnly = AttributeOutputBase::AnalyzeURL( rUrl, rTarget, pLinkURL, pMark ); 877 878 String sURL = *pLinkURL; 879 String sMark = *pMark; 880 881 if ( sURL.Len() ) 882 sURL = URIHelper::simpleNormalizedMakeRelative( m_rWW8Export.GetWriter().GetBaseURL(), sURL ); 883 884 if ( bBookMarkOnly ) 885 sURL = FieldString( ww::eHYPERLINK ); 886 else 887 { 888 String sFld( FieldString( ww::eHYPERLINK ) ); 889 sFld.APPEND_CONST_ASC( "\"" ); 890 sURL.Insert( sFld, 0 ); 891 sURL += '\"'; 892 } 893 894 if ( sMark.Len() ) 895 ( ( sURL.APPEND_CONST_ASC( " \\l \"" ) ) += sMark ) += '\"'; 896 897 if ( rTarget.Len() ) 898 ( sURL.APPEND_CONST_ASC( " \\n " ) ) += rTarget; 899 900 *pLinkURL = sURL; 901 *pMark = sMark; 902 903 return bBookMarkOnly; 904 } 905 906 bool WW8AttributeOutput::StartURL( const String &rUrl, const String &rTarget ) 907 { 908 // hyperlinks only in WW8 909 if ( !m_rWW8Export.bWrtWW8 ) 910 return false; 911 912 INetURLObject aURL( rUrl ); 913 String sURL; 914 String sMark; 915 916 bool bBookMarkOnly = AnalyzeURL( rUrl, rTarget, &sURL, &sMark ); 917 918 919 m_rWW8Export.OutputField( 0, ww::eHYPERLINK, sURL, WRITEFIELD_START | WRITEFIELD_CMD_START ); 920 921 // write the refence to the "picture" structure 922 sal_uLong nDataStt = m_rWW8Export.pDataStrm->Tell(); 923 m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell() ); 924 925 // WinWord 2000 doesn't write this - so its a temp solution by W97 ? 926 m_rWW8Export.WriteChar( 0x01 ); 927 928 static sal_uInt8 aArr1[] = { 929 0x03, 0x6a, 0,0,0,0, // sprmCPicLocation 930 931 0x06, 0x08, 0x01, // sprmCFData 932 0x55, 0x08, 0x01, // sprmCFSpec 933 0x02, 0x08, 0x01 // sprmCFFldVanish 934 }; 935 sal_uInt8* pDataAdr = aArr1 + 2; 936 Set_UInt32( pDataAdr, nDataStt ); 937 938 m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), sizeof( aArr1 ), aArr1 ); 939 940 m_rWW8Export.OutputField( 0, ww::eHYPERLINK, sURL, WRITEFIELD_CMD_END ); 941 942 // now write the picture structur 943 sURL = aURL.GetURLNoMark(); 944 945 //all links end up in the data stream as absolute references. 946 bool bAbsolute = !bBookMarkOnly; 947 948 static sal_uInt8 __READONLY_DATA aURLData1[] = { 949 0,0,0,0, // len of struct 950 0x44,0, // the start of "next" data 951 0,0,0,0,0,0,0,0,0,0, // PIC-Structure! 952 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // | 953 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // | 954 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // | 955 0,0,0,0, // / 956 }; 957 static sal_uInt8 __READONLY_DATA MAGIC_A[] = { 958 // start of "next" data 959 0xD0,0xC9,0xEA,0x79,0xF9,0xBA,0xCE,0x11, 960 0x8C,0x82,0x00,0xAA,0x00,0x4B,0xA9,0x0B 961 }; 962 963 m_rWW8Export.pDataStrm->Write( aURLData1, sizeof( aURLData1 ) ); 964 sal_uInt8 nAnchor = 0x00; 965 if ( sMark.Len() ) 966 nAnchor = 0x08; 967 m_rWW8Export.pDataStrm->Write( &nAnchor, 1 ); 968 m_rWW8Export.pDataStrm->Write( MAGIC_A, sizeof(MAGIC_A) ); 969 SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, 0x00000002); 970 sal_uInt32 nFlag = bBookMarkOnly ? 0 : 0x01; 971 if ( bAbsolute ) 972 nFlag |= 0x02; 973 if ( sMark.Len() ) 974 nFlag |= 0x08; 975 SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, nFlag ); 976 977 INetProtocol eProto = aURL.GetProtocol(); 978 if ( eProto == INET_PROT_FILE ) 979 { 980 // version 1 (for a document) 981 982 static sal_uInt8 __READONLY_DATA MAGIC_C[] = { 983 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 984 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 985 0x00, 0x00 986 }; 987 988 static sal_uInt8 __READONLY_DATA MAGIC_D[] = { 989 0xFF, 0xFF, 0xAD, 0xDE, 0x00, 0x00, 0x00, 0x00, 990 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 991 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 992 }; 993 994 // save the links to files as relative 995 sURL = URIHelper::simpleNormalizedMakeRelative( m_rWW8Export.GetWriter().GetBaseURL(), sURL ); 996 if ( sURL.EqualsAscii( "/", 0, 1 ) ) 997 sURL = aURL.PathToFileName(); 998 999 // special case for the absolute windows names 1000 // (convert '/c:/foo/bar.doc' into 'c:\foo\bar.doc') 1001 sal_Unicode aDrive = ( sURL.Len() > 1 )? sURL.GetChar( 1 ): 0; 1002 if ( sURL.EqualsAscii( "/", 0, 1 ) && 1003 ( ( aDrive >= 'A' && aDrive <= 'Z' ) || ( aDrive >= 'a' && aDrive <= 'z' ) ) && 1004 sURL.EqualsAscii( ":", 2, 1 ) ) 1005 { 1006 sURL.Erase( 0, 1 ); 1007 sURL.SearchAndReplaceAll( '/', '\\' ); 1008 } 1009 1010 m_rWW8Export.pDataStrm->Write( MAGIC_C, sizeof(MAGIC_C) ); 1011 SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, sURL.Len()+1 ); 1012 SwWW8Writer::WriteString8( *m_rWW8Export.pDataStrm, sURL, true, 1013 RTL_TEXTENCODING_MS_1252 ); 1014 m_rWW8Export.pDataStrm->Write( MAGIC_D, sizeof( MAGIC_D ) ); 1015 1016 SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, 2*sURL.Len() + 6 ); 1017 SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, 2*sURL.Len() ); 1018 SwWW8Writer::WriteShort( *m_rWW8Export.pDataStrm, 3 ); 1019 SwWW8Writer::WriteString16( *m_rWW8Export.pDataStrm, sURL, false ); 1020 } 1021 else if ( eProto != INET_PROT_NOT_VALID ) 1022 { 1023 // version 2 (simple url) 1024 // an write some data to the data stream, but dont ask 1025 // what the data mean, except for the URL. 1026 // The First piece is the WW8_PIC structure. 1027 // 1028 static sal_uInt8 __READONLY_DATA MAGIC_B[] = { 1029 0xE0,0xC9,0xEA,0x79,0xF9,0xBA,0xCE,0x11, 1030 0x8C,0x82,0x00,0xAA,0x00,0x4B,0xA9,0x0B 1031 }; 1032 1033 m_rWW8Export.pDataStrm->Write( MAGIC_B, sizeof(MAGIC_B) ); 1034 SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, 2 * ( sURL.Len() + 1 ) ); 1035 SwWW8Writer::WriteString16( *m_rWW8Export.pDataStrm, sURL, true ); 1036 } 1037 1038 if ( sMark.Len() ) 1039 { 1040 SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, sMark.Len()+1 ); 1041 SwWW8Writer::WriteString16( *m_rWW8Export.pDataStrm, sMark, true ); 1042 } 1043 SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, nDataStt, 1044 m_rWW8Export.pDataStrm->Tell() - nDataStt ); 1045 1046 return true; 1047 } 1048 1049 bool WW8AttributeOutput::EndURL() 1050 { 1051 // hyperlinks only in WW8 1052 if ( !m_rWW8Export.bWrtWW8 ) 1053 return false; 1054 1055 m_rWW8Export.OutputField( 0, ww::eHYPERLINK, aEmptyStr, WRITEFIELD_CLOSE ); 1056 1057 return true; 1058 } 1059 1060 String BookmarkToWord(const String &rBookmark) 1061 { 1062 String sRet(INetURLObject::encode(rBookmark, 1063 INetURLObject::PART_REL_SEGMENT_EXTRA, '%', 1064 INetURLObject::ENCODE_ALL, RTL_TEXTENCODING_ASCII_US)); 1065 return TruncateBookmark(sRet); 1066 } 1067 1068 String BookmarkToWriter(const String &rBookmark) 1069 { 1070 return INetURLObject::decode(rBookmark, '%', 1071 INetURLObject::DECODE_UNAMBIGUOUS, RTL_TEXTENCODING_ASCII_US); 1072 } 1073 1074 void WW8SwAttrIter::OutSwFmtRefMark(const SwFmtRefMark& rAttr, bool) 1075 { 1076 if ( m_rExport.HasRefToObject( REF_SETREFATTR, &rAttr.GetRefName(), 0 ) ) 1077 m_rExport.AppendBookmark( m_rExport.GetBookmarkName( REF_SETREFATTR, 1078 &rAttr.GetRefName(), 0 )); 1079 } 1080 1081 void WW8AttributeOutput::FieldVanish( const String& rTxt, ww::eField /*eType*/ ) 1082 { 1083 WW8Bytes aItems; 1084 m_rWW8Export.GetCurrentItems( aItems ); 1085 1086 // sprmCFFldVanish 1087 if ( m_rWW8Export.bWrtWW8 ) 1088 SwWW8Writer::InsUInt16( aItems, NS_sprm::LN_CFFldVanish ); 1089 else 1090 aItems.Insert( 67, aItems.Count() ); 1091 aItems.Insert( 1, aItems.Count() ); 1092 1093 sal_uInt16 nStt_sprmCFSpec = aItems.Count(); 1094 1095 // sprmCFSpec -- fSpec-Attribut true 1096 if ( m_rWW8Export.bWrtWW8 ) 1097 SwWW8Writer::InsUInt16( aItems, 0x855 ); 1098 else 1099 aItems.Insert( 117, aItems.Count() ); 1100 aItems.Insert( 1, aItems.Count() ); 1101 1102 m_rWW8Export.WriteChar( '\x13' ); 1103 m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), aItems.Count(), 1104 aItems.GetData() ); 1105 m_rWW8Export.OutSwString( rTxt, 0, rTxt.Len(), m_rWW8Export.IsUnicode(), 1106 RTL_TEXTENCODING_MS_1252 ); 1107 m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), nStt_sprmCFSpec, 1108 aItems.GetData() ); 1109 m_rWW8Export.WriteChar( '\x15' ); 1110 m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), aItems.Count(), 1111 aItems.GetData() ); 1112 } 1113 1114 void AttributeOutputBase::TOXMark( const SwTxtNode& rNode, const SwTOXMark& rAttr ) 1115 { 1116 // its a field; so get the Text form the Node and build the field 1117 String sTxt; 1118 ww::eField eType = ww::eNONE; 1119 1120 const SwTxtTOXMark& rTxtTOXMark = *rAttr.GetTxtTOXMark(); 1121 const xub_StrLen* pTxtEnd = rTxtTOXMark.GetEnd(); 1122 if ( pTxtEnd ) // has range? 1123 { 1124 sTxt = rNode.GetExpandTxt( *rTxtTOXMark.GetStart(), 1125 *pTxtEnd - *rTxtTOXMark.GetStart() ); 1126 } 1127 else 1128 sTxt = rAttr.GetAlternativeText(); 1129 1130 switch ( rAttr.GetTOXType()->GetType() ) 1131 { 1132 case TOX_INDEX: 1133 eType = ww::eXE; 1134 if ( rAttr.GetPrimaryKey().Len() ) 1135 { 1136 if ( rAttr.GetSecondaryKey().Len() ) 1137 { 1138 sTxt.Insert( ':', 0 ); 1139 sTxt.Insert( rAttr.GetSecondaryKey(), 0 ); 1140 } 1141 1142 sTxt.Insert( ':', 0 ); 1143 sTxt.Insert( rAttr.GetPrimaryKey(), 0 ); 1144 } 1145 sTxt.InsertAscii( " XE \"", 0 ); 1146 sTxt.InsertAscii( "\" " ); 1147 break; 1148 1149 case TOX_USER: 1150 ( sTxt.APPEND_CONST_ASC( "\" \\f \"" ) ) 1151 += (sal_Char)( 'A' + GetExport( ).GetId( *rAttr.GetTOXType() ) ); 1152 // fall through - no break; 1153 case TOX_CONTENT: 1154 { 1155 eType = ww::eTC; 1156 sTxt.InsertAscii( " TC \"", 0 ); 1157 sal_uInt16 nLvl = rAttr.GetLevel(); 1158 if (nLvl > WW8ListManager::nMaxLevel) 1159 nLvl = WW8ListManager::nMaxLevel; 1160 1161 ((sTxt.APPEND_CONST_ASC( "\" \\l " )) 1162 += String::CreateFromInt32( nLvl )) += ' '; 1163 } 1164 break; 1165 default: 1166 ASSERT( !this, "Unhandled option for toc export" ); 1167 break; 1168 } 1169 1170 if ( sTxt.Len() ) 1171 FieldVanish( sTxt, eType ); 1172 } 1173 1174 int WW8SwAttrIter::OutAttrWithRange(xub_StrLen nPos) 1175 { 1176 int nRet = 0; 1177 if ( const SwpHints* pTxtAttrs = rNd.GetpSwpHints() ) 1178 { 1179 m_rExport.m_aCurrentCharPropStarts.push( nPos ); 1180 const xub_StrLen* pEnd; 1181 for ( sal_uInt16 i = 0; i < pTxtAttrs->Count(); ++i ) 1182 { 1183 const SwTxtAttr* pHt = (*pTxtAttrs)[i]; 1184 const SfxPoolItem* pItem = &pHt->GetAttr(); 1185 switch ( pItem->Which() ) 1186 { 1187 case RES_TXTATR_INETFMT: 1188 if ( nPos == *pHt->GetStart() ) 1189 { 1190 const SwFmtINetFmt *rINet = static_cast< const SwFmtINetFmt* >( pItem ); 1191 if ( m_rExport.AttrOutput().StartURL( rINet->GetValue(), rINet->GetTargetFrame() ) ) 1192 ++nRet; 1193 } 1194 if ( 0 != ( pEnd = pHt->GetEnd() ) && nPos == *pEnd ) 1195 { 1196 if ( m_rExport.AttrOutput().EndURL() ) 1197 --nRet; 1198 } 1199 break; 1200 case RES_TXTATR_REFMARK: 1201 if ( nPos == *pHt->GetStart() ) 1202 { 1203 OutSwFmtRefMark( *static_cast< const SwFmtRefMark* >( pItem ), true ); 1204 ++nRet; 1205 } 1206 if ( 0 != ( pEnd = pHt->GetEnd() ) && nPos == *pEnd ) 1207 { 1208 OutSwFmtRefMark( *static_cast< const SwFmtRefMark* >( pItem ), false ); 1209 --nRet; 1210 } 1211 break; 1212 case RES_TXTATR_TOXMARK: 1213 if ( nPos == *pHt->GetStart() ) 1214 m_rExport.AttrOutput().TOXMark( rNd, *static_cast< const SwTOXMark* >( pItem ) ); 1215 break; 1216 case RES_TXTATR_CJK_RUBY: 1217 if ( nPos == *pHt->GetStart() ) 1218 { 1219 m_rExport.AttrOutput().StartRuby( rNd, *static_cast< const SwFmtRuby* >( pItem ) ); 1220 ++nRet; 1221 } 1222 if ( 0 != ( pEnd = pHt->GetEnd() ) && nPos == *pEnd ) 1223 { 1224 m_rExport.AttrOutput().EndRuby(); 1225 --nRet; 1226 } 1227 break; 1228 } 1229 } 1230 m_rExport.m_aCurrentCharPropStarts.pop(); // HasTextItem nur in dem obigen Bereich erlaubt 1231 } 1232 return nRet; 1233 } 1234 1235 bool WW8SwAttrIter::IsRedlineAtEnd( xub_StrLen nEnd ) const 1236 { 1237 bool bRet = false; 1238 // search next Redline 1239 for( sal_uInt16 nPos = nCurRedlinePos; 1240 nPos < m_rExport.pDoc->GetRedlineTbl().Count(); ++nPos ) 1241 { 1242 const SwPosition* pEnd = m_rExport.pDoc->GetRedlineTbl()[ nPos ]->End(); 1243 if( pEnd->nNode == rNd ) 1244 { 1245 if( pEnd->nContent.GetIndex() == nEnd ) 1246 { 1247 bRet = true; 1248 break; 1249 } 1250 } 1251 else 1252 break; 1253 } 1254 return bRet; 1255 } 1256 1257 const SwRedlineData* WW8SwAttrIter::GetRedline( xub_StrLen nPos ) 1258 { 1259 if( pCurRedline ) 1260 { 1261 const SwPosition* pEnd = pCurRedline->End(); 1262 if( pEnd->nNode == rNd && 1263 pEnd->nContent.GetIndex() <= nPos ) 1264 { 1265 pCurRedline = 0; 1266 ++nCurRedlinePos; 1267 } 1268 else 1269 { 1270 // write data of current redline 1271 return &( pCurRedline->GetRedlineData() ); 1272 } 1273 } 1274 1275 if( !pCurRedline ) 1276 { 1277 // search next Redline 1278 for( ; nCurRedlinePos < m_rExport.pDoc->GetRedlineTbl().Count(); 1279 ++nCurRedlinePos ) 1280 { 1281 const SwRedline* pRedl = m_rExport.pDoc->GetRedlineTbl()[ nCurRedlinePos ]; 1282 1283 const SwPosition* pStt = pRedl->Start(); 1284 const SwPosition* pEnd = pStt == pRedl->GetPoint() 1285 ? pRedl->GetMark() 1286 : pRedl->GetPoint(); 1287 1288 if( pStt->nNode == rNd ) 1289 { 1290 if( pStt->nContent.GetIndex() >= nPos ) 1291 { 1292 if( pStt->nContent.GetIndex() == nPos ) 1293 { 1294 // write data of this redline 1295 pCurRedline = pRedl; 1296 return &( pCurRedline->GetRedlineData() ); 1297 } 1298 break; 1299 } 1300 } 1301 else 1302 break; 1303 1304 if( pEnd->nNode == rNd && 1305 pEnd->nContent.GetIndex() < nPos ) 1306 { 1307 pCurRedline = pRedl; 1308 break; 1309 } 1310 } 1311 } 1312 return NULL; 1313 } 1314 1315 /* */ 1316 1317 short MSWordExportBase::GetCurrentPageDirection() const 1318 { 1319 const SwFrmFmt &rFmt = pAktPageDesc 1320 ? pAktPageDesc->GetMaster() 1321 : const_cast<const SwDoc *>( pDoc )->GetPageDesc( 0 ).GetMaster(); 1322 return rFmt.GetFrmDir().GetValue(); 1323 } 1324 1325 short MSWordExportBase::GetDefaultFrameDirection( ) const 1326 { 1327 short nDir = FRMDIR_ENVIRONMENT; 1328 1329 if ( bOutPageDescs ) 1330 nDir = GetCurrentPageDirection( ); 1331 else if ( pOutFmtNode ) 1332 { 1333 if ( bOutFlyFrmAttrs ) //frame 1334 { 1335 nDir = TrueFrameDirection( *( const SwFrmFmt * ) pOutFmtNode ); 1336 } 1337 else if ( pOutFmtNode->ISA( SwCntntNode ) ) //pagagraph 1338 { 1339 const SwCntntNode *pNd = ( const SwCntntNode * ) pOutFmtNode; 1340 SwPosition aPos( *pNd ); 1341 nDir = pDoc->GetTextDirection( aPos ); 1342 } 1343 else if ( pOutFmtNode->ISA( SwTxtFmtColl ) ) 1344 nDir = FRMDIR_HORI_LEFT_TOP; //what else can we do :-( 1345 } 1346 1347 if ( nDir == FRMDIR_ENVIRONMENT ) 1348 nDir = FRMDIR_HORI_LEFT_TOP; //Set something 1349 1350 return nDir; 1351 } 1352 1353 short MSWordExportBase::TrueFrameDirection( const SwFrmFmt &rFlyFmt ) const 1354 { 1355 const SwFrmFmt *pFlyFmt = &rFlyFmt; 1356 const SvxFrameDirectionItem* pItem = 0; 1357 while ( pFlyFmt ) 1358 { 1359 pItem = &pFlyFmt->GetFrmDir(); 1360 if ( FRMDIR_ENVIRONMENT == pItem->GetValue() ) 1361 { 1362 pItem = 0; 1363 const SwFmtAnchor* pAnchor = &pFlyFmt->GetAnchor(); 1364 if ((FLY_AT_PAGE != pAnchor->GetAnchorId()) && 1365 pAnchor->GetCntntAnchor() ) 1366 { 1367 pFlyFmt = pAnchor->GetCntntAnchor()->nNode.GetNode().GetFlyFmt(); 1368 } 1369 else 1370 pFlyFmt = 0; 1371 } 1372 else 1373 pFlyFmt = 0; 1374 } 1375 1376 short nRet; 1377 if ( pItem ) 1378 nRet = pItem->GetValue(); 1379 else 1380 nRet = GetCurrentPageDirection(); 1381 1382 ASSERT( nRet != FRMDIR_ENVIRONMENT, "leaving with environment direction" ); 1383 return nRet; 1384 } 1385 1386 const SvxBrushItem* WW8Export::GetCurrentPageBgBrush() const 1387 { 1388 const SwFrmFmt &rFmt = pAktPageDesc 1389 ? pAktPageDesc->GetMaster() 1390 : const_cast<const SwDoc *>(pDoc)->GetPageDesc(0).GetMaster(); 1391 1392 const SfxPoolItem* pItem = 0; 1393 //If not set, or "no fill", get real bg 1394 SfxItemState eState = rFmt.GetItemState(RES_BACKGROUND, true, &pItem); 1395 1396 const SvxBrushItem* pRet = (const SvxBrushItem*)pItem; 1397 if (SFX_ITEM_SET != eState || (!pRet->GetGraphic() && 1398 pRet->GetColor() == COL_TRANSPARENT)) 1399 { 1400 pRet = &(DefaultItemGet<SvxBrushItem>(*pDoc,RES_BACKGROUND)); 1401 } 1402 return pRet; 1403 } 1404 1405 SvxBrushItem WW8Export::TrueFrameBgBrush(const SwFrmFmt &rFlyFmt) const 1406 { 1407 const SwFrmFmt *pFlyFmt = &rFlyFmt; 1408 const SvxBrushItem* pRet = 0; 1409 1410 while (pFlyFmt) 1411 { 1412 //If not set, or "no fill", get real bg 1413 const SfxPoolItem* pItem = 0; 1414 SfxItemState eState = 1415 pFlyFmt->GetItemState(RES_BACKGROUND, true, &pItem); 1416 pRet = (const SvxBrushItem*)pItem; 1417 if (SFX_ITEM_SET != eState || (!pRet->GetGraphic() && 1418 pRet->GetColor() == COL_TRANSPARENT)) 1419 { 1420 pRet = 0; 1421 const SwFmtAnchor* pAnchor = &pFlyFmt->GetAnchor(); 1422 if ((FLY_AT_PAGE != pAnchor->GetAnchorId()) && 1423 pAnchor->GetCntntAnchor()) 1424 { 1425 pFlyFmt = 1426 pAnchor->GetCntntAnchor()->nNode.GetNode().GetFlyFmt(); 1427 } 1428 else 1429 pFlyFmt = 0; 1430 } 1431 else 1432 pFlyFmt = 0; 1433 } 1434 1435 if (!pRet) 1436 pRet = GetCurrentPageBgBrush(); 1437 1438 const Color aTmpColor( COL_WHITE ); 1439 SvxBrushItem aRet( aTmpColor, RES_BACKGROUND ); 1440 if (pRet && (pRet->GetGraphic() ||( pRet->GetColor() != COL_TRANSPARENT))) 1441 aRet = *pRet; 1442 1443 return aRet; 1444 } 1445 1446 1447 /* 1448 Convert characters that need to be converted, the basic replacements and the 1449 ridicously complicated title case attribute mapping to hardcoded upper case 1450 because word doesn't have the feature 1451 */ 1452 String WW8SwAttrIter::GetSnippet(const String &rStr, xub_StrLen nAktPos, 1453 xub_StrLen nLen) const 1454 { 1455 String aSnippet(rStr, nAktPos, nLen); 1456 if (!nLen) 1457 return aSnippet; 1458 1459 // 0x0a ( Hard Line Break ) -> 0x0b 1460 // 0xad ( soft hyphen ) -> 0x1f 1461 // 0x2011 ( hard hyphen ) -> 0x1e 1462 aSnippet.SearchAndReplaceAll(0x0A, 0x0B); 1463 aSnippet.SearchAndReplaceAll(CHAR_HARDHYPHEN, 0x1e); 1464 aSnippet.SearchAndReplaceAll(CHAR_SOFTHYPHEN, 0x1f); 1465 1466 m_rExport.m_aCurrentCharPropStarts.push( nAktPos ); 1467 const SfxPoolItem &rItem = GetItem(RES_CHRATR_CASEMAP); 1468 1469 if (SVX_CASEMAP_TITEL == ((const SvxCaseMapItem&)rItem).GetValue()) 1470 { 1471 sal_uInt16 nScriptType = i18n::ScriptType::LATIN; 1472 if (pBreakIt->GetBreakIter().is()) 1473 nScriptType = pBreakIt->GetBreakIter()->getScriptType(aSnippet, 0); 1474 1475 LanguageType nLanguage; 1476 switch (nScriptType) 1477 { 1478 case i18n::ScriptType::ASIAN: 1479 nLanguage = ((const SvxLanguageItem&)GetItem(RES_CHRATR_CJK_LANGUAGE)).GetLanguage(); 1480 break; 1481 case i18n::ScriptType::COMPLEX: 1482 nLanguage = ((const SvxLanguageItem&)GetItem(RES_CHRATR_CTL_LANGUAGE)).GetLanguage(); 1483 break; 1484 case i18n::ScriptType::LATIN: 1485 default: 1486 nLanguage = ((const SvxLanguageItem&)GetItem(RES_CHRATR_LANGUAGE)).GetLanguage(); 1487 break; 1488 } 1489 1490 SvxFont aFontHelper; 1491 aFontHelper.SetCaseMap(SVX_CASEMAP_TITEL); 1492 aFontHelper.SetLanguage(nLanguage); 1493 aSnippet = aFontHelper.CalcCaseMap(aSnippet); 1494 1495 //If we weren't at the begin of a word undo the case change. 1496 //not done before doing the casemap because the sequence might start 1497 //with whitespace 1498 if (pBreakIt->GetBreakIter().is() && !pBreakIt->GetBreakIter()->isBeginWord( 1499 rStr, nAktPos, pBreakIt->GetLocale(nLanguage), 1500 i18n::WordType::ANYWORD_IGNOREWHITESPACES ) ) 1501 { 1502 aSnippet.SetChar(0, rStr.GetChar(nAktPos)); 1503 } 1504 } 1505 m_rExport.m_aCurrentCharPropStarts.pop(); 1506 1507 return aSnippet; 1508 } 1509 1510 /** Delivers the right paragraph style 1511 1512 Because of the different style handling for delete operations, 1513 the track changes have to be analysed. A deletion, starting in paragraph A 1514 with style A, ending in paragraph B with style B, needs a hack. 1515 */ 1516 static SwTxtFmtColl& lcl_getFormatCollection( MSWordExportBase& rExport, const SwTxtNode* pTxtNode ) 1517 { 1518 sal_uInt16 nPos = 0; 1519 sal_uInt16 nMax = rExport.pDoc->GetRedlineTbl().Count(); 1520 while( nPos < nMax ) 1521 { 1522 const SwRedline* pRedl = rExport.pDoc->GetRedlineTbl()[ nPos++ ]; 1523 const SwPosition* pStt = pRedl->Start(); 1524 const SwPosition* pEnd = pStt == pRedl->GetPoint() 1525 ? pRedl->GetMark() 1526 : pRedl->GetPoint(); 1527 // Looking for deletions, which ends in current pTxtNode 1528 if( nsRedlineType_t::REDLINE_DELETE == pRedl->GetRedlineData().GetType() && 1529 pEnd->nNode == *pTxtNode && pStt->nNode != *pTxtNode && 1530 pStt->nNode.GetNode().IsTxtNode() ) 1531 { 1532 pTxtNode = pStt->nNode.GetNode().GetTxtNode(); 1533 nMax = nPos; 1534 nPos = 0; 1535 } 1536 } 1537 return static_cast<SwTxtFmtColl&>( pTxtNode->GetAnyFmtColl() ); 1538 } 1539 1540 void WW8AttributeOutput::FormatDrop( const SwTxtNode& rNode, const SwFmtDrop &rSwFmtDrop, sal_uInt16 nStyle, 1541 ww8::WW8TableNodeInfo::Pointer_t pTextNodeInfo, ww8::WW8TableNodeInfoInner::Pointer_t pTextNodeInfoInner ) 1542 { 1543 short nDropLines = rSwFmtDrop.GetLines(); 1544 short nDistance = rSwFmtDrop.GetDistance(); 1545 int rFontHeight, rDropHeight, rDropDescent; 1546 1547 SVBT16 nSty; 1548 ShortToSVBT16( nStyle, nSty ); 1549 m_rWW8Export.pO->Insert( (sal_uInt8*)&nSty, 2, m_rWW8Export.pO->Count() ); // Style # 1550 1551 if ( m_rWW8Export.bWrtWW8 ) 1552 { 1553 m_rWW8Export.InsUInt16( NS_sprm::LN_PPc ); // Alignment (sprmPPc) 1554 m_rWW8Export.pO->Insert( 0x20, m_rWW8Export.pO->Count() ); 1555 1556 m_rWW8Export.InsUInt16( NS_sprm::LN_PWr ); // Wrapping (sprmPWr) 1557 m_rWW8Export.pO->Insert( 0x02, m_rWW8Export.pO->Count() ); 1558 1559 m_rWW8Export.InsUInt16( NS_sprm::LN_PDcs ); // Dropcap (sprmPDcs) 1560 int nDCS = ( nDropLines << 3 ) | 0x01; 1561 m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( nDCS ) ); 1562 1563 m_rWW8Export.InsUInt16( NS_sprm::LN_PDxaFromText ); // Distance from text (sprmPDxaFromText) 1564 m_rWW8Export.InsUInt16( nDistance ); 1565 1566 if ( rNode.GetDropSize( rFontHeight, rDropHeight, rDropDescent ) ) 1567 { 1568 m_rWW8Export.InsUInt16( NS_sprm::LN_PDyaLine ); // Line spacing 1569 m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( -rDropHeight ) ); 1570 m_rWW8Export.InsUInt16( 0 ); 1571 } 1572 } 1573 else 1574 { 1575 m_rWW8Export.pO->Insert( 29, m_rWW8Export.pO->Count() ); // Alignment (sprmPPc) 1576 m_rWW8Export.pO->Insert( 0x20, m_rWW8Export.pO->Count() ); 1577 1578 m_rWW8Export.pO->Insert( 37, m_rWW8Export.pO->Count() ); // Wrapping (sprmPWr) 1579 m_rWW8Export.pO->Insert( 0x02, m_rWW8Export.pO->Count() ); 1580 1581 m_rWW8Export.pO->Insert( 46, m_rWW8Export.pO->Count() ); // Dropcap (sprmPDcs) 1582 int nDCS = ( nDropLines << 3 ) | 0x01; 1583 m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( nDCS ) ); 1584 1585 m_rWW8Export.pO->Insert( 49, m_rWW8Export.pO->Count() ); // Distance from text (sprmPDxaFromText) 1586 m_rWW8Export.InsUInt16( nDistance ); 1587 1588 if (rNode.GetDropSize(rFontHeight, rDropHeight, rDropDescent)) 1589 { 1590 m_rWW8Export.pO->Insert( 20, m_rWW8Export.pO->Count() ); // Line spacing 1591 m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( -rDropHeight ) ); 1592 m_rWW8Export.InsUInt16( 0 ); 1593 } 1594 } 1595 1596 m_rWW8Export.WriteCR( pTextNodeInfoInner ); 1597 1598 if ( pTextNodeInfo.get() != NULL ) 1599 { 1600 #ifdef DEBUG 1601 ::std::clog << pTextNodeInfo->toString() << ::std::endl; 1602 #endif 1603 1604 TableInfoCell( pTextNodeInfoInner ); 1605 } 1606 1607 m_rWW8Export.pPapPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), m_rWW8Export.pO->Count(), m_rWW8Export.pO->GetData() ); 1608 m_rWW8Export.pO->Remove( 0, m_rWW8Export.pO->Count() ); 1609 1610 if ( rNode.GetDropSize( rFontHeight, rDropHeight, rDropDescent ) ) 1611 { 1612 if ( m_rWW8Export.bWrtWW8 ) 1613 { 1614 const SwCharFmt *pSwCharFmt = rSwFmtDrop.GetCharFmt(); 1615 if ( pSwCharFmt ) 1616 { 1617 m_rWW8Export.InsUInt16( NS_sprm::LN_CIstd ); 1618 m_rWW8Export.InsUInt16( m_rWW8Export.GetId( *pSwCharFmt ) ); 1619 } 1620 1621 m_rWW8Export.InsUInt16( NS_sprm::LN_CHpsPos ); // Lower the chars 1622 m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( -((nDropLines - 1)*rDropDescent) / 10 ) ); 1623 1624 m_rWW8Export.InsUInt16( NS_sprm::LN_CHps ); // Font Size 1625 m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( rFontHeight / 10 ) ); 1626 } 1627 else 1628 { 1629 const SwCharFmt *pSwCharFmt = rSwFmtDrop.GetCharFmt(); 1630 if ( pSwCharFmt ) 1631 { 1632 m_rWW8Export.InsUInt16( 80 ); 1633 m_rWW8Export.InsUInt16( m_rWW8Export.GetId( *pSwCharFmt ) ); 1634 } 1635 1636 m_rWW8Export.pO->Insert( 101, m_rWW8Export.pO->Count() ); // Lower the chars 1637 m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( -((nDropLines - 1)*rDropDescent) / 10 ) ); 1638 1639 m_rWW8Export.pO->Insert( 99, m_rWW8Export.pO->Count() ); // Font Size 1640 m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( rFontHeight / 10 ) ); 1641 } 1642 } 1643 1644 m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), m_rWW8Export.pO->Count(), m_rWW8Export.pO->GetData() ); 1645 m_rWW8Export.pO->Remove( 0, m_rWW8Export.pO->Count() ); 1646 } 1647 1648 xub_StrLen MSWordExportBase::GetNextPos( WW8SwAttrIter* aAttrIter, const SwTxtNode& rNode, xub_StrLen nAktPos ) 1649 { 1650 // Get the bookmarks for the normal run 1651 xub_StrLen nNextPos = aAttrIter->WhereNext(); 1652 xub_StrLen nNextBookmark = nNextPos; 1653 1654 if( nNextBookmark > nAktPos )//no need to search for bookmarks otherwise 1655 { 1656 GetSortedBookmarks( rNode, nAktPos, nNextBookmark - nAktPos ); 1657 NearestBookmark( nNextBookmark, nAktPos, false ); 1658 } 1659 return std::min( nNextPos, nNextBookmark ); 1660 } 1661 1662 void MSWordExportBase::UpdatePosition( WW8SwAttrIter* aAttrIter, xub_StrLen nAktPos, xub_StrLen /*nEnd*/ ) 1663 { 1664 xub_StrLen nNextPos; 1665 1666 // go to next attribute if no bookmark is found and if the next attribute position if at the current position 1667 bool bNextBookmark = NearestBookmark( nNextPos, nAktPos, true ); 1668 if( !bNextBookmark && nAktPos >= aAttrIter->WhereNext() ) 1669 aAttrIter->NextPos(); 1670 } 1671 1672 bool MSWordExportBase::GetBookmarks( const SwTxtNode& rNd, xub_StrLen nStt, 1673 xub_StrLen nEnd, IMarkVector& rArr ) 1674 { 1675 IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess(); 1676 sal_uLong nNd = rNd.GetIndex( ); 1677 1678 const sal_Int32 nMarks = pMarkAccess->getMarksCount(); 1679 for ( sal_Int32 i = 0; i < nMarks; i++ ) 1680 { 1681 IMark* pMark = ( pMarkAccess->getMarksBegin() + i )->get(); 1682 1683 // Only keep the bookmarks starting or ending in this node 1684 if ( pMark->GetMarkStart().nNode == nNd || 1685 pMark->GetMarkEnd().nNode == nNd ) 1686 { 1687 xub_StrLen nBStart = pMark->GetMarkStart().nContent.GetIndex(); 1688 xub_StrLen nBEnd = pMark->GetMarkEnd().nContent.GetIndex(); 1689 1690 // Keep only the bookmars starting or ending in the snippet 1691 bool bIsStartOk = ( nBStart >= nStt ) && ( nBStart <= nEnd ); 1692 bool bIsEndOk = ( nBEnd >= nStt ) && ( nBEnd <= nEnd ); 1693 1694 if ( bIsStartOk || bIsEndOk ) 1695 rArr.push_back( pMark ); 1696 } 1697 } 1698 return ( rArr.size() > 0 ); 1699 } 1700 1701 class CompareMarksEnd : public std::binary_function < const IMark *, const IMark *, bool > 1702 { 1703 public: 1704 inline bool operator() ( const IMark * pOneB, const IMark * pTwoB ) const 1705 { 1706 xub_StrLen nOEnd = pOneB->GetMarkEnd().nContent.GetIndex(); 1707 xub_StrLen nTEnd = pTwoB->GetMarkEnd().nContent.GetIndex(); 1708 1709 return nOEnd < nTEnd; 1710 } 1711 }; 1712 1713 bool MSWordExportBase::NearestBookmark( xub_StrLen& rNearest, const xub_StrLen nAktPos, bool bNextPositionOnly ) 1714 { 1715 bool bHasBookmark = false; 1716 1717 if ( m_rSortedMarksStart.size( ) > 0 ) 1718 { 1719 IMark* pMarkStart = m_rSortedMarksStart.front(); 1720 xub_StrLen nNext = pMarkStart->GetMarkStart().nContent.GetIndex(); 1721 if( !bNextPositionOnly || (nNext > nAktPos )) 1722 { 1723 rNearest = nNext; 1724 bHasBookmark = true; 1725 } 1726 } 1727 1728 if ( m_rSortedMarksEnd.size( ) > 0 ) 1729 { 1730 IMark* pMarkEnd = m_rSortedMarksEnd[0]; 1731 xub_StrLen nNext = pMarkEnd->GetMarkEnd().nContent.GetIndex(); 1732 if( !bNextPositionOnly || nNext > nAktPos ) 1733 { 1734 if ( !bHasBookmark ) 1735 rNearest = nNext; 1736 else 1737 rNearest = std::min( rNearest, nNext ); 1738 bHasBookmark = true; 1739 } 1740 } 1741 1742 return bHasBookmark; 1743 } 1744 1745 void MSWordExportBase::GetSortedBookmarks( const SwTxtNode& rNode, xub_StrLen nAktPos, xub_StrLen nLen ) 1746 { 1747 IMarkVector aMarksStart; 1748 if ( GetBookmarks( rNode, nAktPos, nAktPos + nLen, aMarksStart ) ) 1749 { 1750 IMarkVector aSortedEnd; 1751 IMarkVector aSortedStart; 1752 for ( IMarkVector::const_iterator it = aMarksStart.begin(), end = aMarksStart.end(); 1753 it < end; ++it ) 1754 { 1755 IMark* pMark = (*it); 1756 1757 // Remove the positions egals to the current pos 1758 xub_StrLen nStart = pMark->GetMarkStart().nContent.GetIndex(); 1759 xub_StrLen nEnd = pMark->GetMarkEnd().nContent.GetIndex(); 1760 1761 if ( nStart > nAktPos && ( pMark->GetMarkStart().nNode == rNode.GetIndex()) ) 1762 aSortedStart.push_back( pMark ); 1763 1764 if ( nEnd > nAktPos && nEnd <= ( nAktPos + nLen ) && (pMark->GetMarkEnd().nNode == rNode.GetIndex()) ) 1765 aSortedEnd.push_back( pMark ); 1766 } 1767 1768 // Sort the bookmarks by end position 1769 std::sort( aSortedEnd.begin(), aSortedEnd.end(), CompareMarksEnd() ); 1770 1771 m_rSortedMarksStart.swap( aSortedStart ); 1772 m_rSortedMarksEnd.swap( aSortedEnd ); 1773 } 1774 else 1775 { 1776 m_rSortedMarksStart.clear( ); 1777 m_rSortedMarksEnd.clear( ); 1778 } 1779 } 1780 1781 void MSWordExportBase::OutputTextNode( const SwTxtNode& rNode ) 1782 { 1783 #ifdef DEBUG 1784 ::std::clog << "<OutWW8_SwTxtNode>" << ::std::endl; 1785 #endif 1786 1787 ww8::WW8TableNodeInfo::Pointer_t pTextNodeInfo( mpTableInfo->getTableNodeInfo( &rNode ) ); 1788 1789 AttrOutput().StartParagraph( pTextNodeInfo ); 1790 1791 bool bFlyInTable = mpParentFrame && IsInTable(); 1792 1793 if ( !bFlyInTable ) 1794 nStyleBeforeFly = GetId( lcl_getFormatCollection( *this, &rNode ) ); 1795 1796 // nStyleBeforeFly may change when we recurse into another node, so we 1797 // have to remember it in nStyle 1798 sal_uInt16 nStyle = nStyleBeforeFly; 1799 1800 WW8SwAttrIter aAttrIter( *this, rNode ); 1801 rtl_TextEncoding eChrSet = aAttrIter.GetCharSet(); 1802 1803 if ( bStartTOX ) 1804 { 1805 // ignore TOX header section 1806 const SwSectionNode* pSectNd = rNode.FindSectionNode(); 1807 if ( pSectNd && TOX_CONTENT_SECTION == pSectNd->GetSection().GetType() ) 1808 { 1809 AttrOutput().StartTOX( pSectNd->GetSection() ); 1810 m_aCurrentCharPropStarts.push( 0 ); 1811 } 1812 } 1813 1814 const SwSection* pTOXSect = 0; 1815 if( bInWriteTOX ) 1816 { 1817 // check for end of TOX 1818 SwNodeIndex aIdx( rNode, 1 ); 1819 if( !aIdx.GetNode().IsTxtNode() ) 1820 { 1821 const SwSectionNode* pTOXSectNd = rNode.FindSectionNode(); 1822 pTOXSect = &pTOXSectNd->GetSection(); 1823 1824 const SwNode* pNxt = rNode.GetNodes().GoNext( &aIdx ); 1825 if( pNxt && pNxt->FindSectionNode() == pTOXSectNd ) 1826 pTOXSect = 0; 1827 } 1828 } 1829 1830 if ( aAttrIter.RequiresImplicitBookmark() ) 1831 { 1832 String sBkmkName = String( RTL_CONSTASCII_STRINGPARAM( "_toc" ) ); 1833 sBkmkName += String::CreateFromInt32( rNode.GetIndex() ); 1834 AppendWordBookmark( sBkmkName ); 1835 } 1836 1837 //Would need to move into WW8Export, probably not worth it 1838 //ASSERT( pO->Count(), " pO ist am Zeilenanfang nicht leer" ); 1839 1840 String aStr( rNode.GetTxt() ); 1841 1842 xub_StrLen nAktPos = 0; 1843 xub_StrLen const nEnd = aStr.Len(); 1844 bool bRedlineAtEnd = false; 1845 int nOpenAttrWithRange = 0; 1846 1847 ww8::WW8TableNodeInfoInner::Pointer_t pTextNodeInfoInner; 1848 if ( pTextNodeInfo.get() != NULL ) 1849 pTextNodeInfoInner = pTextNodeInfo->getFirstInner(); 1850 1851 do { 1852 const SwRedlineData* pRedlineData = aAttrIter.GetRedline( nAktPos ); 1853 1854 AttrOutput().StartRun( pRedlineData ); 1855 1856 xub_StrLen nNextAttr = GetNextPos( &aAttrIter, rNode, nAktPos ); 1857 1858 if( nNextAttr > nEnd ) 1859 nNextAttr = nEnd; 1860 1861 aAttrIter.OutFlys( nAktPos ); 1862 //Append bookmarks in this range after flys, exclusive of final 1863 //position of this range 1864 AppendBookmarks( rNode, nAktPos, nNextAttr - nAktPos ); 1865 bool bTxtAtr = aAttrIter.IsTxtAttr( nAktPos ); 1866 nOpenAttrWithRange += aAttrIter.OutAttrWithRange(nAktPos); 1867 1868 xub_StrLen nLen = nNextAttr - nAktPos; 1869 if ( !bTxtAtr && nLen ) 1870 { 1871 sal_Unicode ch = aStr.GetChar( nAktPos ); 1872 int ofs = ( ch == CH_TXT_ATR_FIELDSTART || ch == CH_TXT_ATR_FIELDEND || ch == CH_TXT_ATR_FORMELEMENT? 1: 0 ); 1873 1874 IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess(); 1875 if ( ch == CH_TXT_ATR_FIELDSTART ) 1876 { 1877 SwPosition aPosition( rNode, SwIndex( const_cast< SwTxtNode* >( &rNode ), nAktPos + 1 ) ); 1878 ::sw::mark::IFieldmark const * const pFieldmark = pMarkAccess->getFieldmarkFor( aPosition ); 1879 OSL_ENSURE( pFieldmark, "Looks like this doc is broken...; where is the Fieldmark for the FIELDSTART??" ); 1880 1881 if ( pFieldmark->GetFieldname().equalsAscii( ODF_FORMTEXT ) ) 1882 AppendBookmark( pFieldmark->GetName(), false ); 1883 OutputField( NULL, lcl_getFieldId( pFieldmark ), lcl_getFieldCode( pFieldmark ), WRITEFIELD_START | WRITEFIELD_CMD_START ); 1884 if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMTEXT ) ) 1885 WriteFormData( *pFieldmark ); 1886 else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_HYPERLINK ) ) 1887 WriteHyperlinkData( *pFieldmark ); 1888 OutputField( NULL, lcl_getFieldId( pFieldmark ), String(), WRITEFIELD_CMD_END ); 1889 } 1890 else if ( ch == CH_TXT_ATR_FIELDEND ) 1891 { 1892 SwPosition aPosition( rNode, SwIndex( const_cast< SwTxtNode* >( &rNode ), nAktPos ) ); 1893 ::sw::mark::IFieldmark const * const pFieldmark = pMarkAccess->getFieldmarkFor( aPosition ); 1894 OSL_ENSURE( pFieldmark, "Looks like this doc is broken...; where is the Fieldmark for the FIELDSTART??" ); 1895 1896 OutputField( NULL, lcl_getFieldId( pFieldmark ), String(), WRITEFIELD_CLOSE ); 1897 if ( pFieldmark->GetFieldname().equalsAscii( ODF_FORMTEXT ) ) 1898 AppendBookmark( pFieldmark->GetName(), false ); 1899 } 1900 else if ( ch == CH_TXT_ATR_FORMELEMENT ) 1901 { 1902 SwPosition aPosition( rNode, SwIndex( const_cast< SwTxtNode* >( &rNode ), nAktPos ) ); 1903 ::sw::mark::IFieldmark const * const pFieldmark = pMarkAccess->getFieldmarkFor( aPosition ); 1904 OSL_ENSURE( pFieldmark, "Looks like this doc is broken...; where is the Fieldmark for the FIELDSTART??" ); 1905 1906 bool isDropdownOrCheckbox = pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMDROPDOWN ) || 1907 pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMCHECKBOX ); 1908 1909 if ( isDropdownOrCheckbox ) 1910 AppendBookmark( pFieldmark->GetName(), 0 ); 1911 OutputField( NULL, lcl_getFieldId( pFieldmark ), 1912 lcl_getFieldCode( pFieldmark ), 1913 WRITEFIELD_START | WRITEFIELD_CMD_START ); 1914 if ( isDropdownOrCheckbox ) 1915 WriteFormData( *pFieldmark ); 1916 OutputField( NULL, lcl_getFieldId( pFieldmark ), String(), WRITEFIELD_CLOSE ); 1917 if ( isDropdownOrCheckbox ) 1918 AppendBookmark( pFieldmark->GetName(), false ); 1919 } 1920 nLen -= static_cast< sal_uInt16 >( ofs ); 1921 1922 String aSnippet( aAttrIter.GetSnippet( aStr, nAktPos + static_cast< sal_uInt16 >( ofs ), nLen ) ); 1923 if ( ( nTxtTyp == TXT_EDN || nTxtTyp == TXT_FTN ) && nAktPos == 0 && nLen > 0 ) 1924 { 1925 // Insert tab for aesthetic puposes #i24762# 1926 if ( aSnippet.GetChar( 0 ) != 0x09 ) 1927 aSnippet.Insert( 0x09, 0 ); 1928 } 1929 AttrOutput().RunText( aSnippet, eChrSet ); 1930 } 1931 1932 if ( aAttrIter.IsDropCap( nNextAttr ) ) 1933 AttrOutput().FormatDrop( rNode, aAttrIter.GetSwFmtDrop(), nStyle, pTextNodeInfo, pTextNodeInfoInner ); 1934 1935 if (0 != nEnd) 1936 { 1937 // Output the character attributes 1938 // #i51277# do this before writing flys at end of paragraph 1939 AttrOutput().StartRunProperties(); 1940 aAttrIter.OutAttr( nAktPos ); 1941 AttrOutput().EndRunProperties( pRedlineData ); 1942 } 1943 1944 // At the end of line, output the attributes until the CR. 1945 // Exception: footnotes at the end of line 1946 if ( nNextAttr == nEnd ) 1947 { 1948 ASSERT( nOpenAttrWithRange >= 0, "odd to see this happening, expected >= 0" ); 1949 if ( !bTxtAtr && nOpenAttrWithRange <= 0 ) 1950 { 1951 if ( aAttrIter.IsRedlineAtEnd( nEnd ) ) 1952 bRedlineAtEnd = true; 1953 else 1954 { 1955 // insert final graphic anchors if any before CR 1956 aAttrIter.OutFlys( nEnd ); 1957 // insert final bookmarks if any before CR and after flys 1958 AppendBookmarks( rNode, nEnd, 1 ); 1959 if ( pTOXSect ) 1960 { 1961 m_aCurrentCharPropStarts.pop(); 1962 AttrOutput().EndTOX( *pTOXSect ); 1963 } 1964 WriteCR( pTextNodeInfoInner ); 1965 } 1966 } 1967 } 1968 1969 if (0 == nEnd) 1970 { 1971 // Output the character attributes 1972 // do it after WriteCR for an empty paragraph (otherwise 1973 // WW8_WrFkp::Append throws SPRMs away...) 1974 AttrOutput().StartRunProperties(); 1975 aAttrIter.OutAttr( nAktPos ); 1976 AttrOutput().EndRunProperties( pRedlineData ); 1977 } 1978 1979 // Exception: footnotes at the end of line 1980 if ( nNextAttr == nEnd ) 1981 { 1982 ASSERT(nOpenAttrWithRange >= 0, 1983 "odd to see this happening, expected >= 0"); 1984 bool bAttrWithRange = (nOpenAttrWithRange > 0); 1985 if ( nAktPos != nEnd ) 1986 { 1987 nOpenAttrWithRange += aAttrIter.OutAttrWithRange(nEnd); 1988 ASSERT(nOpenAttrWithRange == 0, 1989 "odd to see this happening, expected 0"); 1990 } 1991 1992 AttrOutput().OutputFKP(); 1993 1994 if ( bTxtAtr || bAttrWithRange || bRedlineAtEnd ) 1995 { 1996 // insert final graphic anchors if any before CR 1997 aAttrIter.OutFlys( nEnd ); 1998 // insert final bookmarks if any before CR and after flys 1999 AppendBookmarks( rNode, nEnd, 1 ); 2000 2001 if ( pTOXSect ) 2002 { 2003 m_aCurrentCharPropStarts.pop(); 2004 AttrOutput().EndTOX( *pTOXSect ); 2005 } 2006 2007 WriteCR( pTextNodeInfoInner ); 2008 2009 if ( bRedlineAtEnd ) 2010 { 2011 AttrOutput().Redline( aAttrIter.GetRedline( nEnd ) ); 2012 AttrOutput().OutputFKP(); 2013 } 2014 } 2015 } 2016 2017 AttrOutput().EndRun(); 2018 2019 nAktPos = nNextAttr; 2020 UpdatePosition( &aAttrIter, nAktPos, nEnd ); 2021 eChrSet = aAttrIter.GetCharSet(); 2022 } 2023 while ( nAktPos < nEnd ); 2024 2025 AttrOutput().StartParagraphProperties( rNode ); 2026 2027 AttrOutput().ParagraphStyle( nStyle ); 2028 2029 if ( mpParentFrame && IsInTable() ) // Fly-Attrs 2030 OutputFormat( mpParentFrame->GetFrmFmt(), false, false, true ); 2031 2032 if ( pTextNodeInfo.get() != NULL ) 2033 { 2034 #ifdef DEBUG 2035 ::std::clog << pTextNodeInfo->toString() << ::std::endl; 2036 #endif 2037 2038 AttrOutput().TableInfoCell( pTextNodeInfoInner ); 2039 if (pTextNodeInfoInner->isFirstInTable()) 2040 { 2041 const SwTable * pTable = pTextNodeInfoInner->getTable(); 2042 2043 const SwTableFmt * pTabFmt = pTable->GetTableFmt(); 2044 if (pTabFmt != NULL) 2045 { 2046 if (pTabFmt->GetBreak().GetBreak() == SVX_BREAK_PAGE_BEFORE) 2047 AttrOutput().PageBreakBefore(true); 2048 } 2049 } 2050 } 2051 2052 if ( !bFlyInTable ) 2053 { 2054 SfxItemSet* pTmpSet = 0; 2055 const sal_uInt8 nPrvNxtNd = rNode.HasPrevNextLayNode(); 2056 2057 if( (ND_HAS_PREV_LAYNODE|ND_HAS_NEXT_LAYNODE ) != nPrvNxtNd ) 2058 { 2059 const SfxPoolItem* pItem; 2060 if( SFX_ITEM_SET == rNode.GetSwAttrSet().GetItemState( 2061 RES_UL_SPACE, true, &pItem ) && 2062 ( ( !( ND_HAS_PREV_LAYNODE & nPrvNxtNd ) && 2063 ((SvxULSpaceItem*)pItem)->GetUpper()) || 2064 ( !( ND_HAS_NEXT_LAYNODE & nPrvNxtNd ) && 2065 ((SvxULSpaceItem*)pItem)->GetLower()) )) 2066 { 2067 pTmpSet = new SfxItemSet( rNode.GetSwAttrSet() ); 2068 SvxULSpaceItem aUL( *(SvxULSpaceItem*)pItem ); 2069 // OD, MMAHER 2004-03-01 #i25901#- consider compatibility option 2070 if (!pDoc->get(IDocumentSettingAccess::PARA_SPACE_MAX_AT_PAGES)) 2071 { 2072 if( !(ND_HAS_PREV_LAYNODE & nPrvNxtNd )) 2073 aUL.SetUpper( 0 ); 2074 } 2075 // OD, MMAHER 2004-03-01 #i25901# - consider compatibility option 2076 if (!pDoc->get(IDocumentSettingAccess::ADD_PARA_SPACING_TO_TABLE_CELLS)) 2077 { 2078 if( !(ND_HAS_NEXT_LAYNODE & nPrvNxtNd )) 2079 aUL.SetLower( 0 ); 2080 } 2081 pTmpSet->Put( aUL ); 2082 } 2083 } 2084 2085 sal_Bool bParaRTL = sal_False; 2086 const SvxFrameDirectionItem* pItem = (const SvxFrameDirectionItem*) 2087 rNode.GetSwAttrSet().GetItem(RES_FRAMEDIR); 2088 if ( aAttrIter.IsParaRTL()) 2089 bParaRTL = sal_True; 2090 2091 if( rNode.IsNumbered()) 2092 { 2093 const SwNumRule* pRule = rNode.GetNumRule(); 2094 sal_uInt8 nLvl = static_cast< sal_uInt8 >( rNode.GetActualListLevel() ); 2095 const SwNumFmt* pFmt = pRule->GetNumFmt( nLvl ); 2096 if( !pFmt ) 2097 pFmt = &pRule->Get( nLvl ); 2098 2099 if( !pTmpSet ) 2100 pTmpSet = new SfxItemSet( rNode.GetSwAttrSet() ); 2101 2102 SvxLRSpaceItem aLR(ItemGet<SvxLRSpaceItem>(*pTmpSet, RES_LR_SPACE)); 2103 // --> OD 2008-06-03 #i86652# 2104 if ( pFmt->GetPositionAndSpaceMode() == 2105 SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) 2106 { 2107 aLR.SetTxtLeft( aLR.GetTxtLeft() + pFmt->GetAbsLSpace() ); 2108 } 2109 // <-- 2110 2111 if( rNode.IsNumbered() && rNode.IsCountedInList() ) 2112 { 2113 // --> OD 2008-06-03 #i86652# 2114 if ( pFmt->GetPositionAndSpaceMode() == 2115 SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) 2116 { 2117 if (bParaRTL) 2118 aLR.SetTxtFirstLineOfstValue(pFmt->GetAbsLSpace() - pFmt->GetFirstLineOffset()); 2119 else 2120 aLR.SetTxtFirstLineOfst(GetWordFirstLineOffset(*pFmt)); 2121 } 2122 // <-- 2123 2124 // --> OD 2009-03-09 #100020# 2125 // correct fix for issue i94187 2126 if (SFX_ITEM_SET != 2127 pTmpSet->GetItemState(RES_PARATR_NUMRULE, false) ) 2128 { 2129 // List style set via paragraph style - then put it into the itemset. 2130 // This is needed to get list level and list id exported for 2131 // the paragraph. 2132 pTmpSet->Put( SwNumRuleItem( pRule->GetName() )); 2133 2134 // Put indent values into the itemset in case that the list 2135 // style is applied via paragraph style and the list level 2136 // indent values are not applicable. 2137 if ( pFmt->GetPositionAndSpaceMode() == 2138 SvxNumberFormat::LABEL_ALIGNMENT && 2139 !rNode.AreListLevelIndentsApplicable() ) 2140 { 2141 pTmpSet->Put( aLR ); 2142 } 2143 } 2144 } 2145 else 2146 pTmpSet->ClearItem(RES_PARATR_NUMRULE); 2147 2148 // --> OD 2008-06-03 #i86652# 2149 if ( pFmt->GetPositionAndSpaceMode() == 2150 SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) 2151 { 2152 pTmpSet->Put(aLR); 2153 2154 //#i21847# 2155 SvxTabStopItem aItem( 2156 ItemGet<SvxTabStopItem>(*pTmpSet, RES_PARATR_TABSTOP)); 2157 SvxTabStop aTabStop(pFmt->GetAbsLSpace()); 2158 aItem.Insert(aTabStop); 2159 pTmpSet->Put(aItem); 2160 2161 MSWordExportBase::CorrectTabStopInSet(*pTmpSet, pFmt->GetAbsLSpace()); 2162 } 2163 } 2164 2165 /* 2166 If a given para is using the FRMDIR_ENVIRONMENT direction we 2167 cannot export that, its its ltr then that's ok as thats word's 2168 default. Otherwise we must add a RTL attribute to our export list 2169 */ 2170 pItem = (const SvxFrameDirectionItem*) 2171 rNode.GetSwAttrSet().GetItem(RES_FRAMEDIR); 2172 if ( 2173 (!pItem || pItem->GetValue() == FRMDIR_ENVIRONMENT) && 2174 aAttrIter.IsParaRTL() 2175 ) 2176 { 2177 if ( !pTmpSet ) 2178 pTmpSet = new SfxItemSet(rNode.GetSwAttrSet()); 2179 2180 pTmpSet->Put(SvxFrameDirectionItem(FRMDIR_HORI_RIGHT_TOP, RES_FRAMEDIR)); 2181 } 2182 // --> OD 2005-10-18 #126238# - move code for handling of numbered, 2183 // but not counted paragraphs to this place. Otherwise, the paragraph 2184 // isn't exported as numbered, but not counted, if no other attribute 2185 // is found in <pTmpSet> 2186 // #i44815# adjust numbering/indents for numbered paragraphs 2187 // without number (NO_NUMLEVEL) 2188 // #i47013# need to check rNode.GetNumRule()!=NULL as well. 2189 if ( ! rNode.IsCountedInList() && rNode.GetNumRule()!=NULL ) 2190 { 2191 // WW8 does not know numbered paragraphs without number 2192 // (NO_NUMLEVEL). In WW8AttributeOutput::ParaNumRule(), we will export 2193 // the RES_PARATR_NUMRULE as list-id 0, which in WW8 means 2194 // no numbering. Here, we will adjust the indents to match 2195 // visually. 2196 2197 if ( !pTmpSet ) 2198 pTmpSet = new SfxItemSet(rNode.GetSwAttrSet()); 2199 2200 // create new LRSpace item, based on the current (if present) 2201 const SfxPoolItem* pPoolItem = NULL; 2202 pTmpSet->GetItemState(RES_LR_SPACE, sal_True, &pPoolItem); 2203 SvxLRSpaceItem aLRSpace( 2204 ( pPoolItem == NULL ) 2205 ? SvxLRSpaceItem(0, 0, 0, 0, RES_LR_SPACE) 2206 : *static_cast<const SvxLRSpaceItem*>( pPoolItem ) ); 2207 2208 // new left margin = old left + label space 2209 const SwNumRule* pRule = rNode.GetNumRule(); 2210 const SwNumFmt& rNumFmt = pRule->Get( static_cast< sal_uInt16 >(rNode.GetActualListLevel()) ); 2211 // --> OD 2008-06-03 #i86652# 2212 if ( rNumFmt.GetPositionAndSpaceMode() == 2213 SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) 2214 { 2215 aLRSpace.SetTxtLeft( aLRSpace.GetLeft() + rNumFmt.GetAbsLSpace() ); 2216 2217 // new first line indent = 0 2218 // (first line indent is ignored for NO_NUMLEVEL) 2219 if (!bParaRTL) 2220 aLRSpace.SetTxtFirstLineOfst( 0 ); 2221 2222 // put back the new item 2223 pTmpSet->Put( aLRSpace ); 2224 } 2225 // <-- 2226 2227 // assure that numbering rule is in <pTmpSet> 2228 if (SFX_ITEM_SET != pTmpSet->GetItemState(RES_PARATR_NUMRULE, false) ) 2229 { 2230 pTmpSet->Put( SwNumRuleItem( pRule->GetName() )); 2231 } 2232 } 2233 2234 // --> OD 2007-04-24 #i75457# 2235 // Export page break after attribute from paragraph style. 2236 // If page break attribute at the text node exist, an existing page 2237 // break after at the paragraph style hasn't got to be considered. 2238 if ( !rNode.GetpSwAttrSet() || 2239 SFX_ITEM_SET != rNode.GetpSwAttrSet()->GetItemState(RES_BREAK, false) ) 2240 { 2241 const SvxFmtBreakItem* pBreakAtParaStyle = 2242 &(ItemGet<SvxFmtBreakItem>(rNode.GetSwAttrSet(), RES_BREAK)); 2243 if ( pBreakAtParaStyle && 2244 pBreakAtParaStyle->GetBreak() == SVX_BREAK_PAGE_AFTER ) 2245 { 2246 if ( !pTmpSet ) 2247 { 2248 pTmpSet = new SfxItemSet(rNode.GetSwAttrSet()); 2249 } 2250 pTmpSet->Put( *pBreakAtParaStyle ); 2251 } 2252 else if( pTmpSet ) 2253 { // Even a pagedesc item is set, the break item can be set 'NONE', 2254 // this has to be overruled. 2255 const SwFmtPageDesc& rPageDescAtParaStyle = 2256 ItemGet<SwFmtPageDesc>( rNode, RES_PAGEDESC ); 2257 if( rPageDescAtParaStyle.KnowsPageDesc() ) 2258 pTmpSet->ClearItem( RES_BREAK ); 2259 } 2260 } 2261 2262 // --> FME 2007-05-30 #i76520# Emulate non-splitting tables 2263 if ( bOutTable ) 2264 { 2265 const SwTableNode* pTableNode = rNode.FindTableNode(); 2266 2267 if ( pTableNode ) 2268 { 2269 const SwTable& rTable = pTableNode->GetTable(); 2270 const SvxFmtKeepItem& rKeep = rTable.GetFrmFmt()->GetKeep(); 2271 const bool bKeep = rKeep.GetValue(); 2272 const bool bDontSplit = !bKeep ? 2273 !rTable.GetFrmFmt()->GetLayoutSplit().GetValue() : 2274 false; 2275 2276 if ( bKeep || bDontSplit ) 2277 { 2278 // bKeep: set keep at first paragraphs in all lines 2279 // bDontSplit : set keep at first paragraphs in all lines except from last line 2280 // but only for non-complex tables 2281 const SwTableBox* pBox = rNode.GetTblBox(); 2282 const SwTableLine* pLine = pBox ? pBox->GetUpper() : 0; 2283 2284 if ( pLine && !pLine->GetUpper() ) 2285 { 2286 // check if box is first in that line: 2287 if ( 0 == pLine->GetTabBoxes().GetPos( pBox ) && pBox->GetSttNd() ) 2288 { 2289 // check if paragraph is first in that line: 2290 if ( 1 == ( rNode.GetIndex() - pBox->GetSttNd()->GetIndex() ) ) 2291 { 2292 bool bSetAtPara = false; 2293 if ( bKeep ) 2294 bSetAtPara = true; 2295 else if ( bDontSplit ) 2296 { 2297 // check if pLine isn't last line in table 2298 if ( rTable.GetTabLines().Count() - rTable.GetTabLines().GetPos( pLine ) != 1 ) 2299 bSetAtPara = true; 2300 } 2301 2302 if ( bSetAtPara ) 2303 { 2304 if ( !pTmpSet ) 2305 pTmpSet = new SfxItemSet(rNode.GetSwAttrSet()); 2306 2307 const SvxFmtKeepItem aKeepItem( sal_True, RES_KEEP ); 2308 pTmpSet->Put( aKeepItem ); 2309 } 2310 } 2311 } 2312 } 2313 } 2314 } 2315 } 2316 // <-- 2317 2318 const SfxItemSet* pNewSet = pTmpSet ? pTmpSet : rNode.GetpSwAttrSet(); 2319 if( pNewSet ) 2320 { // Para-Attrs 2321 pStyAttr = &rNode.GetAnyFmtColl().GetAttrSet(); 2322 2323 const SwModify* pOldMod = pOutFmtNode; 2324 pOutFmtNode = &rNode; 2325 2326 // Pap-Attrs, so script is not necessary 2327 OutputItemSet( *pNewSet, true, false, i18n::ScriptType::LATIN, false); 2328 2329 pStyAttr = 0; 2330 pOutFmtNode = pOldMod; 2331 2332 if( pNewSet != rNode.GetpSwAttrSet() ) 2333 delete pNewSet; 2334 } 2335 } 2336 2337 AttrOutput().EndParagraphProperties(); 2338 2339 AttrOutput().EndParagraph( pTextNodeInfoInner ); 2340 2341 #ifdef DEBUG 2342 ::std::clog << "</OutWW8_SwTxtNode>" << ::std::endl; 2343 #endif 2344 } 2345 2346 void WW8AttributeOutput::TableNodeInfo( ww8::WW8TableNodeInfo::Pointer_t pNodeInfo ) 2347 { 2348 SVBT16 nSty; 2349 ShortToSVBT16( GetExport().nStyleBeforeFly, nSty ); 2350 2351 ww8::WW8TableNodeInfo::Inners_t::const_iterator aIt( pNodeInfo->getInners().begin() ); 2352 ww8::WW8TableNodeInfo::Inners_t::const_iterator aItEnd( pNodeInfo->getInners().end() ); 2353 2354 while (aIt != aItEnd) 2355 { 2356 ww8::WW8TableNodeInfoInner::Pointer_t pInner = aIt->second; 2357 if ( pInner->isEndOfCell() ) 2358 { 2359 TableRowEnd( pInner->getDepth() ); 2360 2361 m_rWW8Export.pO->Insert( (sal_uInt8*)&nSty, 2, m_rWW8Export.pO->Count() ); // Style # 2362 TableInfoRow( pInner ); 2363 m_rWW8Export.pPapPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), m_rWW8Export.pO->Count(), 2364 m_rWW8Export.pO->GetData() ); 2365 m_rWW8Export.pO->Remove( 0, m_rWW8Export.pO->Count() ); // leeren 2366 } 2367 2368 if ( pInner->isEndOfLine() ) 2369 { 2370 } 2371 2372 aIt++; 2373 } 2374 } 2375 2376 #if 0 2377 /* */ 2378 2379 sal_uInt16 WW8Export::StartTableFromFrmFmt( WW8Bytes &rAt, const SwFrmFmt *pFmt ) 2380 { 2381 // Tell the undocumented table hack that everything between here and 2382 // the last table position is nontable text 2383 if ( WW8_CP nPos = Fc2Cp( Strm().Tell() ) ) 2384 pMagicTable->Append(nPos,0); 2385 2386 // sprmPDxaFromText10 2387 if( bWrtWW8 ) 2388 { 2389 static sal_uInt8 __READONLY_DATA aTabLineAttr[] = { 2390 0, 0, // Sty # 0 2391 0x16, 0x24, 1, // sprmPFInTable 2392 0x17, 0x24, 1 }; // sprmPFTtp 2393 rAt.Insert( aTabLineAttr, sizeof( aTabLineAttr ), rAt.Count() ); 2394 } 2395 else 2396 { 2397 static sal_uInt8 __READONLY_DATA aTabLineAttr[] = { 2398 0, 0, // Sty # 0 2399 24, 1, // sprmPFInTable 2400 25, 1 }; // sprmPFTtp 2401 rAt.Insert( aTabLineAttr, sizeof( aTabLineAttr ), rAt.Count() ); 2402 } 2403 2404 ASSERT( pFmt, "No pFmt!" ); 2405 if ( pFmt ) 2406 { 2407 const SwFmtHoriOrient &rHori = pFmt->GetHoriOrient(); 2408 const SwFmtVertOrient &rVert = pFmt->GetVertOrient(); 2409 if ( 2410 (text::RelOrientation::PRINT_AREA == rHori.GetRelationOrient() || 2411 text::RelOrientation::FRAME == rHori.GetRelationOrient()) 2412 && 2413 (text::RelOrientation::PRINT_AREA == rVert.GetRelationOrient() || 2414 text::RelOrientation::FRAME == rVert.GetRelationOrient()) 2415 ) 2416 { 2417 sal_Int16 eHOri = rHori.GetHoriOrient(); 2418 switch (eHOri) 2419 { 2420 case text::HoriOrientation::CENTER: 2421 case text::HoriOrientation::RIGHT: 2422 if( bWrtWW8 ) 2423 SwWW8Writer::InsUInt16( rAt, NS_sprm::LN_TJc ); 2424 else 2425 rAt.Insert( 182, rAt.Count() ); 2426 SwWW8Writer::InsUInt16( rAt, (text::HoriOrientation::RIGHT == eHOri ? 2 : 1 )); 2427 break; 2428 default: 2429 break; 2430 } 2431 } 2432 } 2433 return rAt.Count(); 2434 } 2435 2436 //See #i19484# for why we need this 2437 static bool CellContainsProblematicGraphic( const SwWriteTableCell *pCell, 2438 const MSWordExportBase &rExport ) 2439 { 2440 const SwNode *pStart = pCell ? pCell->GetBox()->GetSttNd() : 0; 2441 const SwNode *pEnd = pStart ? pStart->EndOfSectionNode() : 0; 2442 ASSERT( pStart && pEnd, "No start or end?" ); 2443 if ( !pStart || !pEnd ) 2444 return false; 2445 2446 bool bHasGraphic = false; 2447 2448 sw::Frames aFrames( GetFramesBetweenNodes( rExport.maFrames, *pStart, *pEnd ) ); 2449 sw::FrameIter aEnd = aFrames.end(); 2450 for ( sw::FrameIter aIter = aFrames.begin(); aIter != aEnd; ++aIter ) 2451 { 2452 const SwFrmFmt &rEntry = aIter->GetFrmFmt(); 2453 if ( rEntry.GetSurround().GetSurround() == SURROUND_THROUGHT ) 2454 { 2455 bHasGraphic = true; 2456 break; 2457 } 2458 } 2459 return bHasGraphic; 2460 } 2461 2462 static bool RowContainsProblematicGraphic( const SwWriteTableCellPtr *pRow, 2463 sal_uInt16 nCols, const MSWordExportBase &rExport ) 2464 { 2465 bool bHasGraphic = false; 2466 for ( sal_uInt16 nI = 0; nI < nCols; ++nI ) 2467 { 2468 if ( CellContainsProblematicGraphic( pRow[nI], rExport ) ) 2469 { 2470 bHasGraphic = true; 2471 break; 2472 } 2473 } 2474 return bHasGraphic; 2475 } 2476 #endif 2477 //--------------------------------------------------------------------------- 2478 // Tabellen 2479 //--------------------------------------------------------------------------- 2480 2481 void WW8AttributeOutput::EmptyParagraph() 2482 { 2483 m_rWW8Export.WriteStringAsPara( aEmptyStr ); 2484 } 2485 2486 bool MSWordExportBase::NoPageBreakSection( const SfxItemSet* pSet ) 2487 { 2488 bool bRet = false; 2489 const SfxPoolItem* pI; 2490 if( pSet) 2491 { 2492 bool bNoPageBreak = false; 2493 if ( SFX_ITEM_ON != pSet->GetItemState(RES_PAGEDESC, true, &pI) 2494 || 0 == ((SwFmtPageDesc*)pI)->GetPageDesc() ) 2495 { 2496 bNoPageBreak = true; 2497 } 2498 2499 if (bNoPageBreak) 2500 { 2501 if (SFX_ITEM_ON != pSet->GetItemState(RES_BREAK, true, &pI)) 2502 bNoPageBreak = true; 2503 else 2504 { 2505 SvxBreak eBreak = ((const SvxFmtBreakItem*)pI)->GetBreak(); 2506 switch (eBreak) 2507 { 2508 case SVX_BREAK_PAGE_BEFORE: 2509 case SVX_BREAK_PAGE_AFTER: 2510 bNoPageBreak = false; 2511 break; 2512 default: 2513 break; 2514 } 2515 } 2516 } 2517 bRet = bNoPageBreak; 2518 } 2519 return bRet; 2520 } 2521 2522 /* */ 2523 2524 void MSWordExportBase::OutputSectionNode( const SwSectionNode& rSectionNode ) 2525 { 2526 const SwSection& rSection = rSectionNode.GetSection(); 2527 2528 SwNodeIndex aIdx( rSectionNode, 1 ); 2529 const SwNode& rNd = aIdx.GetNode(); 2530 if ( !rNd.IsSectionNode() && !IsInTable() ) //No sections in table 2531 { 2532 // Bug 74245 - if the first Node inside the section has an own 2533 // PageDesc or PageBreak attribut, then dont write 2534 // here the section break 2535 sal_uLong nRstLnNum = 0; 2536 const SfxItemSet* pSet; 2537 if ( rNd.IsTableNode() ) 2538 pSet = &rNd.GetTableNode()->GetTable().GetFrmFmt()->GetAttrSet(); 2539 else if ( rNd.IsCntntNode() ) 2540 { 2541 pSet = &rNd.GetCntntNode()->GetSwAttrSet(); 2542 nRstLnNum = ((SwFmtLineNumber&)pSet->Get( 2543 RES_LINENUMBER )).GetStartValue(); 2544 } 2545 else 2546 pSet = 0; 2547 2548 if ( pSet && NoPageBreakSection( pSet ) ) 2549 pSet = 0; 2550 2551 if ( !pSet ) 2552 { 2553 // new Section with no own PageDesc/-Break 2554 // -> write follow section break; 2555 const SwSectionFmt& rFmt = *rSection.GetFmt(); 2556 ReplaceCr( msword::PageBreak ); // Indikator fuer Page/Section-Break 2557 2558 //Get the page in use at the top of this section 2559 SwNodeIndex aIdxTmp(rSectionNode, 1); 2560 const SwPageDesc *pCurrent = 2561 SwPageDesc::GetPageDescOfNode(aIdxTmp.GetNode()); 2562 if (!pCurrent) 2563 pCurrent = pAktPageDesc; 2564 2565 AppendSection( pCurrent, &rFmt, nRstLnNum ); 2566 } 2567 } 2568 if ( TOX_CONTENT_SECTION == rSection.GetType() ) 2569 bStartTOX = true; 2570 } 2571 2572 2573 void WW8Export::AppendSection( const SwPageDesc *pPageDesc, const SwSectionFmt* pFmt, sal_uLong nLnNum ) 2574 { 2575 pSepx->AppendSep(Fc2Cp(Strm().Tell()), pPageDesc, pFmt, nLnNum); 2576 } 2577 2578 /* */ 2579 2580 //--------------------------------------------------------------------------- 2581 // Flys 2582 //--------------------------------------------------------------------------- 2583 2584 void WW8Export::OutWW6FlyFrmsInCntnt( const SwTxtNode& rNd ) 2585 { 2586 ASSERT(!bWrtWW8, "I shouldn't be needed for Word >=8"); 2587 if ( bWrtWW8 ) 2588 return; 2589 2590 if (const SwpHints* pTxtAttrs = rNd.GetpSwpHints()) 2591 { 2592 for( sal_uInt16 n=0; n < pTxtAttrs->Count(); ++n ) 2593 { 2594 const SwTxtAttr* pAttr = (*pTxtAttrs)[ n ]; 2595 if( RES_TXTATR_FLYCNT == pAttr->Which() ) 2596 { 2597 // zeichengebundenes Attribut 2598 const SwFmtFlyCnt& rFlyCntnt = pAttr->GetFlyCnt(); 2599 const SwFlyFrmFmt& rFlyFrmFmt = *(SwFlyFrmFmt*)rFlyCntnt.GetFrmFmt(); 2600 const SwNodeIndex* pNodeIndex = rFlyFrmFmt.GetCntnt().GetCntntIdx(); 2601 2602 if( pNodeIndex ) 2603 { 2604 sal_uLong nStt = pNodeIndex->GetIndex()+1, 2605 nEnd = pNodeIndex->GetNode().EndOfSectionIndex(); 2606 2607 if( (nStt < nEnd) && !pDoc->GetNodes()[ nStt ]->IsNoTxtNode() ) 2608 { 2609 Point aOffset; 2610 // Rechtecke des Flys und des Absatzes besorgen 2611 SwRect aParentRect(rNd.FindLayoutRect(false, &aOffset)), 2612 aFlyRect(rFlyFrmFmt.FindLayoutRect(false, &aOffset ) ); 2613 2614 aOffset = aFlyRect.Pos() - aParentRect.Pos(); 2615 2616 // PaM umsetzen: auf Inhalt des Fly-Frameformats 2617 SaveData( nStt, nEnd ); 2618 2619 // wird in OutputFormat() ausgewertet 2620 pFlyOffset = &aOffset; 2621 eNewAnchorType = rFlyFrmFmt.GetAnchor().GetAnchorId(); 2622 sw::Frame aFrm(rFlyFrmFmt, SwPosition(rNd)); 2623 mpParentFrame = &aFrm; 2624 // Ok, rausschreiben: 2625 WriteText(); 2626 2627 RestoreData(); 2628 } 2629 } 2630 } 2631 } 2632 } 2633 } 2634 2635 void WW8AttributeOutput::OutputFlyFrame_Impl( const sw::Frame& rFmt, const Point& rNdTopLeft ) 2636 { 2637 const SwFrmFmt &rFrmFmt = rFmt.GetFrmFmt(); 2638 const SwFmtAnchor& rAnch = rFrmFmt.GetAnchor(); 2639 2640 bool bUseEscher = m_rWW8Export.bWrtWW8; 2641 2642 if ( m_rWW8Export.bWrtWW8 && rFmt.IsInline() ) 2643 { 2644 sw::Frame::WriterSource eType = rFmt.GetWriterType(); 2645 if ((eType == sw::Frame::eGraphic) || (eType == sw::Frame::eOle)) 2646 bUseEscher = false; 2647 else 2648 bUseEscher = true; 2649 2650 /* 2651 #110185# 2652 A special case for converting some inline form controls to form fields 2653 when in winword 8+ mode 2654 */ 2655 if ((bUseEscher == true) && (eType == sw::Frame::eFormControl)) 2656 { 2657 if ( m_rWW8Export.MiserableFormFieldExportHack( rFrmFmt ) ) 2658 return ; 2659 } 2660 } 2661 2662 if (bUseEscher) 2663 { 2664 ASSERT( m_rWW8Export.bWrtWW8, "this has gone horribly wrong" ); 2665 // write as escher 2666 m_rWW8Export.AppendFlyInFlys(rFmt, rNdTopLeft); 2667 } 2668 else 2669 { 2670 bool bDone = false; 2671 2672 // Hole vom Node und vom letzten Node die Position in der Section 2673 const SwNodeIndex* pNodeIndex = rFrmFmt.GetCntnt().GetCntntIdx(); 2674 2675 sal_uLong nStt = pNodeIndex ? pNodeIndex->GetIndex()+1 : 0; 2676 sal_uLong nEnd = pNodeIndex ? pNodeIndex->GetNode().EndOfSectionIndex() : 0; 2677 2678 if( nStt >= nEnd ) // kein Bereich, also kein gueltiger Node 2679 return; 2680 2681 if ( !m_rWW8Export.IsInTable() && rFmt.IsInline() ) 2682 { 2683 //Test to see if this textbox contains only a single graphic/ole 2684 SwTxtNode* pParTxtNode = rAnch.GetCntntAnchor()->nNode.GetNode().GetTxtNode(); 2685 if ( pParTxtNode && !m_rWW8Export.pDoc->GetNodes()[ nStt ]->IsNoTxtNode() ) 2686 bDone = true; 2687 } 2688 if( !bDone ) 2689 { 2690 // ein NICHT zeichengebundener Rahmen liegt vor 2691 2692 // --> OD 2007-04-19 #i43447# - removed 2693 // const SwFmtFrmSize& rS = rFrmFmt.GetFrmSize(); 2694 // nFlyWidth = rS.GetWidth(); // Fuer Anpassung Graphic-Groesse 2695 // nFlyHeight = rS.GetHeight(); 2696 // <-- 2697 2698 m_rWW8Export.SaveData( nStt, nEnd ); 2699 2700 Point aOffset; 2701 if ( m_rWW8Export.mpParentFrame ) 2702 { 2703 /* 2704 #90804# 2705 Munge flys in fly into absolutely positioned elements for 2706 word 6 2707 */ 2708 const SwTxtNode* pParTxtNode = rAnch.GetCntntAnchor()->nNode.GetNode().GetTxtNode(); 2709 const SwRect aPageRect = pParTxtNode->FindPageFrmRect( sal_False, 0, sal_False ); 2710 2711 aOffset = rFrmFmt.FindLayoutRect().Pos(); 2712 aOffset -= aPageRect.Pos(); 2713 2714 m_rWW8Export.pFlyOffset = &aOffset; 2715 m_rWW8Export.eNewAnchorType = FLY_AT_PAGE; 2716 } 2717 2718 m_rWW8Export.mpParentFrame = &rFmt; 2719 if ( 2720 m_rWW8Export.IsInTable() && 2721 (FLY_AT_PAGE != rAnch.GetAnchorId()) && 2722 !m_rWW8Export.pDoc->GetNodes()[ nStt ]->IsNoTxtNode() 2723 ) 2724 { 2725 // Beachten: Flag bOutTable wieder setzen, 2726 // denn wir geben ja ganz normalen Content der 2727 // Tabelenzelle aus und keinen Rahmen 2728 // (Flag wurde oben in aSaveData() geloescht) 2729 m_rWW8Export.bOutTable = true; 2730 const String& rName = rFrmFmt.GetName(); 2731 m_rWW8Export.StartCommentOutput(rName); 2732 m_rWW8Export.WriteText(); 2733 m_rWW8Export.EndCommentOutput(rName); 2734 } 2735 else 2736 m_rWW8Export.WriteText(); 2737 2738 m_rWW8Export.RestoreData(); 2739 } 2740 } 2741 } 2742 2743 void AttributeOutputBase::OutputFlyFrame( const sw::Frame& rFmt ) 2744 { 2745 if ( !rFmt.GetCntntNode() ) 2746 return; 2747 2748 const SwCntntNode &rNode = *rFmt.GetCntntNode(); 2749 Point aNdPos, aPgPos; 2750 Point* pLayPos; 2751 bool bValidNdPos = false, bValidPgPos = false; 2752 2753 if (FLY_AT_PAGE == rFmt.GetFrmFmt().GetAnchor().GetAnchorId()) 2754 { 2755 // get the Layout Node-Position. 2756 if ( !bValidPgPos ) 2757 { 2758 aPgPos = rNode.FindPageFrmRect(false, &aPgPos).Pos(); 2759 bValidPgPos = true; 2760 } 2761 pLayPos = &aPgPos; 2762 } 2763 else 2764 { 2765 // get the Layout Node-Position. 2766 if ( !bValidNdPos ) 2767 { 2768 aNdPos = rNode.FindLayoutRect(false, &aNdPos).Pos(); 2769 bValidNdPos = true; 2770 } 2771 pLayPos = &aNdPos; 2772 } 2773 2774 OutputFlyFrame_Impl( rFmt, *pLayPos ); 2775 } 2776 2777 // write data of any redline 2778 void WW8AttributeOutput::Redline( const SwRedlineData* pRedline ) 2779 { 2780 if ( !pRedline ) 2781 return; 2782 2783 if ( pRedline->Next() ) 2784 Redline( pRedline->Next() ); 2785 2786 static sal_uInt16 __READONLY_DATA aSprmIds[ 2 * 2 * 3 ] = 2787 { 2788 // Ids for insert 2789 NS_sprm::LN_CFRMark, NS_sprm::LN_CIbstRMark, NS_sprm::LN_CDttmRMark, // for WW8 2790 0x0042, 0x0045, 0x0046, // for WW6 2791 // Ids for delete 2792 NS_sprm::LN_CFRMarkDel, NS_sprm::LN_CIbstRMarkDel, NS_sprm::LN_CDttmRMarkDel, // for WW8 2793 0x0041, 0x0045, 0x0046 // for WW6 2794 }; 2795 2796 const sal_uInt16* pSprmIds = 0; 2797 switch( pRedline->GetType() ) 2798 { 2799 case nsRedlineType_t::REDLINE_INSERT: 2800 pSprmIds = aSprmIds; 2801 break; 2802 2803 case nsRedlineType_t::REDLINE_DELETE: 2804 pSprmIds = aSprmIds + (2 * 3); 2805 break; 2806 2807 case nsRedlineType_t::REDLINE_FORMAT: 2808 if( m_rWW8Export.bWrtWW8 ) 2809 { 2810 m_rWW8Export.InsUInt16( NS_sprm::LN_CPropRMark ); 2811 m_rWW8Export.pO->Insert( 7, m_rWW8Export.pO->Count() ); // len 2812 m_rWW8Export.pO->Insert( 1, m_rWW8Export.pO->Count() ); 2813 m_rWW8Export.InsUInt16( m_rWW8Export.AddRedlineAuthor( pRedline->GetAuthor() ) ); 2814 m_rWW8Export.InsUInt32( sw::ms::DateTime2DTTM( pRedline->GetTimeStamp() )); 2815 } 2816 break; 2817 default: 2818 ASSERT(!this, "Unhandled redline type for export"); 2819 break; 2820 } 2821 2822 if ( pSprmIds ) 2823 { 2824 if ( !m_rWW8Export.bWrtWW8 ) 2825 pSprmIds += 3; 2826 2827 if ( m_rWW8Export.bWrtWW8 ) 2828 m_rWW8Export.InsUInt16( pSprmIds[0] ); 2829 else 2830 m_rWW8Export.pO->Insert( msword_cast<sal_uInt8>(pSprmIds[0]), m_rWW8Export.pO->Count() ); 2831 m_rWW8Export.pO->Insert( 1, m_rWW8Export.pO->Count() ); 2832 2833 if ( m_rWW8Export.bWrtWW8 ) 2834 m_rWW8Export.InsUInt16( pSprmIds[1] ); 2835 else 2836 m_rWW8Export.pO->Insert( msword_cast<sal_uInt8>(pSprmIds[1]), m_rWW8Export.pO->Count() ); 2837 m_rWW8Export.InsUInt16( m_rWW8Export.AddRedlineAuthor( pRedline->GetAuthor() ) ); 2838 2839 if ( m_rWW8Export.bWrtWW8 ) 2840 m_rWW8Export.InsUInt16( pSprmIds[2] ); 2841 else 2842 m_rWW8Export.pO->Insert( msword_cast<sal_uInt8>(pSprmIds[2]), m_rWW8Export.pO->Count() ); 2843 m_rWW8Export.InsUInt32( sw::ms::DateTime2DTTM( pRedline->GetTimeStamp() )); 2844 } 2845 } 2846 2847 /* */ 2848 2849 void MSWordExportBase::OutputContentNode( const SwCntntNode& rNode ) 2850 { 2851 switch ( rNode.GetNodeType() ) 2852 { 2853 case ND_TEXTNODE: 2854 { 2855 const SwTxtNode& rTextNode = *rNode.GetTxtNode(); 2856 if( !mbOutOutlineOnly || rTextNode.IsOutline() ) 2857 OutputTextNode( rTextNode ); 2858 } 2859 break; 2860 case ND_GRFNODE: 2861 OutputGrfNode( *rNode.GetGrfNode() ); 2862 break; 2863 case ND_OLENODE: 2864 OutputOLENode( *rNode.GetOLENode() ); 2865 break; 2866 default: 2867 #if OSL_DEBUG_LEVEL > 0 2868 OSL_TRACE("Unhandled node, type == %d\n", rNode.GetNodeType() ); 2869 #endif 2870 break; 2871 } 2872 } 2873 2874 /* vi:set tabstop=4 shiftwidth=4 expandtab: */ 2875