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