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 <tools/solar.h> 29 #include <vcl/vclenum.hxx> 30 #include <vcl/font.hxx> 31 #include <hintids.hxx> 32 #include <editeng/colritem.hxx> 33 #include <editeng/orphitem.hxx> 34 #include <editeng/widwitem.hxx> 35 #include <editeng/brshitem.hxx> 36 #include <editeng/boxitem.hxx> 37 #include <editeng/lrspitem.hxx> 38 #include <editeng/fhgtitem.hxx> 39 #include <editeng/fhgtitem.hxx> 40 #include <editeng/hyznitem.hxx> 41 #include <editeng/frmdiritem.hxx> 42 #include <editeng/langitem.hxx> 43 #include <editeng/charrotateitem.hxx> 44 #include <editeng/pgrditem.hxx> 45 #include <msfilter.hxx> 46 #include <pam.hxx> // fuer SwPam 47 #include <doc.hxx> 48 #include <docary.hxx> 49 #include <ndtxt.hxx> // class SwTxtNode 50 #include <paratr.hxx> // SwNumRuleItem 51 #include <poolfmt.hxx> // RES_POOLCOLL_STANDARD 52 #include <swtable.hxx> // class SwTableLines, ... 53 #include <tblsel.hxx> // class _SwSelBox 54 #include <mdiexp.hxx> 55 #include <fmtpdsc.hxx> 56 #include <txtftn.hxx> 57 #include <frmfmt.hxx> 58 #include <ftnidx.hxx> 59 #include <fmtftn.hxx> 60 #include <charfmt.hxx> 61 #include <SwStyleNameMapper.hxx> 62 #include <fltshell.hxx> // fuer den Attribut Stack 63 #include <fmtanchr.hxx> 64 #include <fmtrowsplt.hxx> 65 // --> OD 2005-01-27 #i33818# 66 #include <fmtfollowtextflow.hxx> 67 // <-- 68 #include <numrule.hxx> 69 # include "../inc/wwstyles.hxx" 70 # include "writerhelper.hxx" 71 #include "ww8struc.hxx" // struct TC 72 #include "ww8par.hxx" 73 #include "ww8par2.hxx" 74 75 #include <frmatr.hxx> 76 77 #include <iostream> 78 79 #define MAX_COL 64 // WW6-Beschreibung: 32, WW6-UI: 31 & WW8-UI: 63! 80 81 using namespace ::com::sun::star; 82 83 84 class WW8SelBoxInfo: public SwSelBoxes_SAR 85 { 86 private: 87 WW8SelBoxInfo(const WW8SelBoxInfo&); 88 WW8SelBoxInfo& operator=(const WW8SelBoxInfo&); 89 public: 90 short nGroupXStart; 91 short nGroupWidth; 92 bool bGroupLocked; 93 94 WW8SelBoxInfo(short nXCenter, short nWidth) 95 : nGroupXStart( nXCenter ), nGroupWidth( nWidth ), bGroupLocked(false) 96 {} 97 }; 98 99 typedef WW8SelBoxInfo* WW8SelBoxInfoPtr; 100 101 SV_DECL_PTRARR_DEL(WW8MergeGroups, WW8SelBoxInfoPtr, 16,16) 102 SV_IMPL_PTRARR(WW8MergeGroups, WW8SelBoxInfoPtr) 103 104 struct WW8TabBandDesc 105 { 106 WW8TabBandDesc* pNextBand; 107 short nGapHalf; 108 short mnDefaultLeft; 109 short mnDefaultTop; 110 short mnDefaultRight; 111 short mnDefaultBottom; 112 bool mbHasSpacing; 113 short nLineHeight; 114 short nRows; 115 sal_uInt16 maDirections[MAX_COL + 1]; 116 short nCenter[MAX_COL + 1]; // X-Rand aller Zellen dieses Bandes 117 short nWidth[MAX_COL + 1]; // Laenge aller Zellen dieses Bandes 118 short nWwCols; // sal_uInt8 wuerde reichen, alignment -> short 119 short nSwCols; // SW: so viele Spalten fuer den Writer 120 bool bLEmptyCol; // SW: Links eine leere Zusatz-Spalte 121 bool bREmptyCol; // SW: dito rechts 122 bool bCantSplit; 123 bool bCantSplit90; 124 WW8_TCell* pTCs; 125 sal_uInt8 nOverrideSpacing[MAX_COL + 1]; 126 short nOverrideValues[MAX_COL + 1][4]; 127 WW8_SHD* pSHDs; 128 sal_uInt32* pNewSHDs; 129 WW8_BRC aDefBrcs[6]; 130 131 132 // nur fuer WW6-7: diese Zelle hat WW-Flag bMerged (horizontal) gesetzt 133 //bool bWWMergedVer6[MAX_COL]; 134 135 136 bool bExist[MAX_COL]; // Existiert diese Zelle ? 137 sal_uInt8 nTransCell[MAX_COL + 2]; // UEbersetzung WW-Index -> SW-Index 138 139 WW8TabBandDesc(); 140 WW8TabBandDesc(WW8TabBandDesc& rBand); // tief kopieren 141 ~WW8TabBandDesc(); 142 static void setcelldefaults(WW8_TCell *pCells, short nCells); 143 void ReadDef(bool bVer67, const sal_uInt8* pS); 144 void ProcessDirection(const sal_uInt8* pParams); 145 void ProcessSprmTSetBRC(bool bVer67, const sal_uInt8* pParamsTSetBRC); 146 void ProcessSprmTTableBorders(bool bVer67, const sal_uInt8* pParams); 147 void ProcessSprmTDxaCol(const sal_uInt8* pParamsTDxaCol); 148 void ProcessSprmTDelete(const sal_uInt8* pParamsTDelete); 149 void ProcessSprmTInsert(const sal_uInt8* pParamsTInsert); 150 void ProcessSpacing(const sal_uInt8* pParamsTInsert); 151 void ProcessSpecificSpacing(const sal_uInt8* pParamsTInsert); 152 void ReadShd(const sal_uInt8* pS ); 153 void ReadNewShd(const sal_uInt8* pS, bool bVer67); 154 155 enum wwDIR {wwTOP = 0, wwLEFT = 1, wwBOTTOM = 2, wwRIGHT = 3}; 156 }; 157 158 WW8TabBandDesc::WW8TabBandDesc() 159 { 160 memset(this, 0, sizeof(*this)); 161 for (size_t i = 0; i < sizeof(maDirections)/sizeof(sal_uInt16); ++i) 162 maDirections[i] = 4; 163 } 164 165 WW8TabBandDesc::~WW8TabBandDesc() 166 { 167 delete[] pTCs; 168 delete[] pSHDs; 169 delete[] pNewSHDs; 170 } 171 172 class WW8TabDesc 173 { 174 std::vector<String> aNumRuleNames; 175 sw::util::RedlineStack *mpOldRedlineStack; 176 177 SwWW8ImplReader* pIo; 178 179 WW8TabBandDesc* pFirstBand; 180 WW8TabBandDesc* pActBand; 181 182 SwPosition* pTmpPos; 183 184 SwTableNode* pTblNd; // Tabellen-Node 185 const SwTableLines* pTabLines; // Zeilen-Array davon 186 SwTableLine* pTabLine; // akt. Zeile 187 SwTableBoxes* pTabBoxes; // Boxen-Array in akt. Zeile 188 SwTableBox* pTabBox; // akt. Zelle 189 190 WW8MergeGroups* pMergeGroups; // Listen aller zu verknuepfenden Zellen 191 192 WW8_TCell* pAktWWCell; 193 194 short nRows; 195 short nDefaultSwCols; 196 short nBands; 197 short nMinLeft; 198 short nConvertedLeft; 199 short nMaxRight; 200 short nSwWidth; 201 short nPreferredWidth; 202 short nOrgDxaLeft; 203 204 bool bOk; 205 bool bClaimLineFmt; 206 sal_Int16 eOri; 207 bool bIsBiDi; 208 // 2. allgemeine Verwaltungsinfo 209 short nAktRow; 210 short nAktBandRow; // SW: in dieser Zeile des akt. Bandes bin ich 211 // 3. Verwaltungsinfo fuer Writer 212 short nAktCol; 213 214 sal_uInt16 nRowsToRepeat; 215 216 // 4. Methoden 217 218 sal_uInt16 GetLogicalWWCol() const; 219 void SetTabBorders( SwTableBox* pBox, short nIdx ); 220 void SetTabShades( SwTableBox* pBox, short nWwIdx ); 221 void SetTabVertAlign( SwTableBox* pBox, short nWwIdx ); 222 void SetTabDirection( SwTableBox* pBox, short nWwIdx ); 223 void CalcDefaults(); 224 bool SetPamInCell(short nWwCol, bool bPam); 225 void InsertCells( short nIns ); 226 void AdjustNewBand(); 227 228 // durchsucht pMergeGroups, meldet Index der ersten, passenden Gruppe bzw. 229 // -1 Details siehe bei der Implementierung 230 bool FindMergeGroup(short nX1, short nWidth, bool bExact, short& nMGrIdx); 231 232 // einzelne Box ggfs. in eine Merge-Gruppe aufnehmen 233 // (die Merge-Gruppen werden dann spaeter auf einen Schlag abgearbeitet) 234 SwTableBox* UpdateTableMergeGroup(WW8_TCell& rCell, 235 WW8SelBoxInfo* pActGroup, SwTableBox* pActBox, sal_uInt16 nCol ); 236 void StartMiserableHackForUnsupportedDirection(short nWwCol); 237 void EndMiserableHackForUnsupportedDirection(short nWwCol); 238 //No copying 239 WW8TabDesc(const WW8TabDesc&); 240 WW8TabDesc &operator=(const WW8TabDesc&); 241 public: 242 const SwTable* pTable; // Tabelle 243 SwPosition* pParentPos; 244 SwFlyFrmFmt* pFlyFmt; 245 SfxItemSet aItemSet; 246 bool IsValidCell(short nCol) const; 247 bool InFirstParaInCell() const; 248 249 WW8TabDesc( SwWW8ImplReader* pIoClass, WW8_CP nStartCp ); 250 bool Ok() const { return bOk; } 251 void CreateSwTable(); 252 void UseSwTable(); 253 void SetSizePosition(SwFrmFmt* pFrmFmt); 254 void TableCellEnd(); 255 void MoveOutsideTable(); 256 void ParkPaM(); 257 void FinishSwTable(); 258 void MergeCells(); 259 short GetMinLeft() const { return nConvertedLeft; } 260 ~WW8TabDesc(); 261 SwPosition *GetPos() { return pTmpPos; } 262 263 const WW8_TCell* GetAktWWCell() const { return pAktWWCell; } 264 short GetAktCol() const { return nAktCol; } 265 // find name of numrule valid for current WW-COL 266 const String& GetNumRuleName() const; 267 void SetNumRuleName( const String& rName ); 268 269 sw::util::RedlineStack* getOldRedlineStack(){ return mpOldRedlineStack; } 270 }; 271 272 void sw::util::RedlineStack::close( const SwPosition& rPos, 273 RedlineType_t eType, WW8TabDesc* pTabDesc ) 274 { 275 // If the redline type is not found in the redline stack, we have to check if there has been 276 // a tabledesc and to check its saved redline stack, too. (#136939, #i68139) 277 if( !close( rPos, eType ) ) 278 { 279 if( pTabDesc && pTabDesc->getOldRedlineStack() ) 280 { 281 #ifdef DBG_UTIL 282 ASSERT( pTabDesc->getOldRedlineStack()->close(rPos, eType), "close without open!"); 283 #else 284 pTabDesc->getOldRedlineStack()->close( rPos, eType ); 285 #endif 286 } 287 } 288 } 289 290 291 void wwSectionManager::SetCurrentSectionHasFootnote() 292 { 293 ASSERT(!maSegments.empty(), 294 "should not be possible, must be at least one segment"); 295 if (!maSegments.empty()) 296 maSegments.back().mbHasFootnote = true; 297 } 298 299 bool wwSectionManager::CurrentSectionIsVertical() const 300 { 301 ASSERT(!maSegments.empty(), 302 "should not be possible, must be at least one segment"); 303 if (!maSegments.empty()) 304 return maSegments.back().IsVertical(); 305 return false; 306 } 307 308 bool wwSectionManager::CurrentSectionIsProtected() const 309 { 310 ASSERT(!maSegments.empty(), 311 "should not be possible, must be at least one segment"); 312 if (!maSegments.empty()) 313 return SectionIsProtected(maSegments.back()); 314 return false; 315 } 316 317 sal_uInt32 wwSectionManager::GetPageLeft() const 318 { 319 return !maSegments.empty() ? maSegments.back().nPgLeft : 0; 320 } 321 322 sal_uInt32 wwSectionManager::GetPageRight() const 323 { 324 return !maSegments.empty() ? maSegments.back().nPgRight : 0; 325 } 326 327 sal_uInt32 wwSectionManager::GetPageWidth() const 328 { 329 return !maSegments.empty() ? maSegments.back().GetPageWidth() : 0; 330 } 331 332 sal_uInt32 wwSectionManager::GetTextAreaWidth() const 333 { 334 return !maSegments.empty() ? maSegments.back().GetTextAreaWidth() : 0; 335 } 336 337 // --> OD 2007-07-03 #148498# 338 sal_uInt32 wwSectionManager::GetWWPageTopMargin() const 339 { 340 return !maSegments.empty() ? maSegments.back().maSep.dyaTop : 0; 341 } 342 // <-- 343 344 sal_uInt16 SwWW8ImplReader::End_Ftn() 345 { 346 /* 347 #84095# 348 Ignoring Footnote outside of the normal Text. People will put footnotes 349 into field results and field commands. 350 */ 351 if (bIgnoreText || 352 pPaM->GetPoint()->nNode < rDoc.GetNodes().GetEndOfExtras().GetIndex()) 353 { 354 return 0; 355 } 356 357 ASSERT(!maFtnStack.empty(), "footnote end without start"); 358 if (maFtnStack.empty()) 359 return 0; 360 361 bool bFtEdOk = false; 362 const FtnDescriptor &rDesc = maFtnStack.back(); 363 364 //Get the footnote character and remove it from the txtnode. We'll 365 //replace it with the footnote 366 SwTxtNode* pTxt = pPaM->GetNode()->GetTxtNode(); 367 xub_StrLen nPos = pPaM->GetPoint()->nContent.GetIndex(); 368 369 String sChar; 370 SwTxtAttr* pFN = 0; 371 //There should have been a footnote char, we will replace this. 372 if (pTxt && nPos) 373 { 374 sChar.Append(pTxt->GetTxt().GetChar(--nPos)); 375 pPaM->SetMark(); 376 pPaM->GetMark()->nContent--; 377 rDoc.DeleteRange( *pPaM ); 378 pPaM->DeleteMark(); 379 SwFmtFtn aFtn(rDesc.meType == MAN_EDN); 380 pFN = pTxt->InsertItem(aFtn, nPos, nPos); 381 } 382 ASSERT(pFN, "Probleme beim Anlegen des Fussnoten-Textes"); 383 if (pFN) 384 { 385 386 SwPosition aTmpPos( *pPaM->GetPoint() ); // merke alte Cursorposition 387 WW8PLCFxSaveAll aSave; 388 pPlcxMan->SaveAllPLCFx( aSave ); 389 WW8PLCFMan* pOldPlcxMan = pPlcxMan; 390 391 const SwNodeIndex* pSttIdx = ((SwTxtFtn*)pFN)->GetStartNode(); 392 ASSERT(pSttIdx, "Probleme beim Anlegen des Fussnoten-Textes"); 393 394 ((SwTxtFtn*)pFN)->SetSeqNo( rDoc.GetFtnIdxs().Count() ); 395 396 bool bOld = bFtnEdn; 397 bFtnEdn = true; 398 399 // read content of Ft-/End-Note 400 Read_HdFtFtnText( pSttIdx, rDesc.mnStartCp, rDesc.mnLen, rDesc.meType); 401 bFtEdOk = true; 402 bFtnEdn = bOld; 403 404 ASSERT(sChar.Len()==1 && ((rDesc.mbAutoNum == (sChar.GetChar(0) == 2))), 405 "footnote autonumbering must be 0x02, and everthing else must not be"); 406 407 // If no automatic numbering use the following char from the main text 408 // as the footnote number 409 if (!rDesc.mbAutoNum) 410 ((SwTxtFtn*)pFN)->SetNumber(0, &sChar); 411 412 /* 413 Delete the footnote char from the footnote if its at the beginning 414 as usual. Might not be if the user has already deleted it, e.g. 415 #i14737# 416 */ 417 SwNodeIndex& rNIdx = pPaM->GetPoint()->nNode; 418 rNIdx = pSttIdx->GetIndex() + 1; 419 SwTxtNode* pTNd = rNIdx.GetNode().GetTxtNode(); 420 if (pTNd && pTNd->GetTxt().Len() && sChar.Len()) 421 { 422 if (pTNd->GetTxt().GetChar(0) == sChar.GetChar(0)) 423 { 424 pPaM->GetPoint()->nContent.Assign( pTNd, 0 ); 425 pPaM->SetMark(); 426 // Strip out tabs we may have inserted on export #i24762# 427 if (pTNd->GetTxt().GetChar(1) == 0x09) 428 pPaM->GetMark()->nContent++; 429 pPaM->GetMark()->nContent++; 430 pReffingStck->Delete(*pPaM); 431 rDoc.DeleteRange( *pPaM ); 432 pPaM->DeleteMark(); 433 } 434 } 435 436 *pPaM->GetPoint() = aTmpPos; // restore Cursor 437 438 pPlcxMan = pOldPlcxMan; // Restore attributes 439 pPlcxMan->RestoreAllPLCFx( aSave ); 440 } 441 442 if (bFtEdOk) 443 maSectionManager.SetCurrentSectionHasFootnote(); 444 445 maFtnStack.pop_back(); 446 return 0; 447 } 448 449 long SwWW8ImplReader::Read_Ftn(WW8PLCFManResult* pRes) 450 { 451 /* 452 #84095# 453 Ignoring Footnote outside of the normal Text. People will put footnotes 454 into field results and field commands. 455 */ 456 if (bIgnoreText || 457 pPaM->GetPoint()->nNode < rDoc.GetNodes().GetEndOfExtras().GetIndex()) 458 { 459 return 0; 460 } 461 462 FtnDescriptor aDesc; 463 aDesc.mbAutoNum = true; 464 if (eEDN == pRes->nSprmId) 465 { 466 aDesc.meType = MAN_EDN; 467 if (pPlcxMan->GetEdn()) 468 aDesc.mbAutoNum = 0 != *(short*)pPlcxMan->GetEdn()->GetData(); 469 } 470 else 471 { 472 aDesc.meType = MAN_FTN; 473 if (pPlcxMan->GetFtn()) 474 aDesc.mbAutoNum = 0 != *(short*)pPlcxMan->GetFtn()->GetData(); 475 } 476 477 aDesc.mnStartCp = pRes->nCp2OrIdx; 478 aDesc.mnLen = pRes->nMemLen; 479 480 maFtnStack.push_back(aDesc); 481 482 return 0; 483 } 484 485 bool SwWW8ImplReader::SearchRowEnd(WW8PLCFx_Cp_FKP* pPap, WW8_CP &rStartCp, 486 int nLevel) const 487 { 488 WW8PLCFxDesc aRes; 489 aRes.pMemPos = 0; 490 aRes.nEndPos = rStartCp; 491 492 while (pPap->HasFkp() && rStartCp != WW8_CP_MAX) 493 { 494 if (pPap->Where() != WW8_CP_MAX) 495 { 496 const sal_uInt8* pB = pPap->HasSprm(TabRowSprm(nLevel)); 497 if (pB && *pB == 1) 498 { 499 const sal_uInt8 *pLevel = 0; 500 if (0 != (pLevel = pPap->HasSprm(0x6649))) 501 { 502 if (nLevel + 1 == *pLevel) 503 return true; 504 } 505 else 506 { 507 ASSERT(!nLevel || pLevel, "sublevel without level sprm"); 508 return true; // RowEnd found 509 } 510 } 511 } 512 513 aRes.nStartPos = aRes.nEndPos; 514 aRes.pMemPos = 0; 515 //Seek to our next block of properties 516 if (!(pPap->SeekPos(aRes.nStartPos))) 517 { 518 aRes.nEndPos = WW8_CP_MAX; 519 pPap->SetDirty(true); 520 } 521 pPap->GetSprms(&aRes); 522 pPap->SetDirty(false); 523 //Update our aRes to get the new starting point of the next properties 524 rStartCp = aRes.nEndPos; 525 } 526 527 return false; 528 } 529 530 ApoTestResults SwWW8ImplReader::TestApo(int nCellLevel, bool bTableRowEnd, 531 const WW8_TablePos *pTabPos, bool bReadTablePos) 532 { 533 const WW8_TablePos *pTopLevelTable = nCellLevel <= 1 ? pTabPos : 0; 534 ApoTestResults aRet; 535 // Frame in Style Definition (word appears to ignore them if inside an 536 // text autoshape, e.g. #94418#) 537 if (!bTxbxFlySection) 538 aRet.mpStyleApo = StyleExists(nAktColl) ? pCollA[nAktColl].pWWFly : 0; 539 540 /* 541 #i1140# 542 If I have a table and apply a style to one of its frames that should cause 543 a paragraph that its applied to it to only exist as a seperate floating 544 frame, then the behavour depends on which cell that it has been applied 545 to. If its the first cell of a row then the whole table row jumps into the 546 new frame, if its not then then the paragraph attributes are applied 547 "except" for the floating frame stuff. i.e. its ignored. So if theres a 548 table, and we're not in the first cell then we ignore the fact that the 549 paragraph style wants to be in a different frame. 550 551 This sort of mindbending inconsistency is surely why frames are deprecated 552 in word 97 onwards and hidden away from the user 553 554 555 #i1532# & #i5379# 556 If we are already a table in a frame then we must grab the para properties 557 to see if we are still in that frame. 558 */ 559 // If table front don't have some content and it is doc first table, ignore table text wrapping property 560 if ( bReadTablePos ) 561 { 562 aRet.mpSprm37 = pPlcxMan->HasParaSprm( bVer67 ? 37 : 0x2423 ); 563 aRet.mpSprm29 = pPlcxMan->HasParaSprm( bVer67 ? 29 : 0x261B ); 564 } 565 566 567 // Is there some frame data here 568 bool bNowApo = aRet.HasFrame() || pTopLevelTable; 569 if (bNowApo) 570 { 571 if (WW8FlyPara *pTest = ConstructApo(aRet, pTabPos)) 572 delete pTest; 573 else 574 bNowApo = false; 575 } 576 577 bool bTestAllowed = !bTxbxFlySection && !bTableRowEnd; 578 if (bTestAllowed) 579 { 580 //Test is allowed if there is no table. 581 //Otherwise only allowed if we are in the 582 //first paragraph of the first cell of a row. 583 //(And only if the row we are inside is at the 584 //same level as the previous row, think tables 585 //in tables) 586 if (nCellLevel == nInTable) 587 { 588 589 if (!nInTable) 590 bTestAllowed = true; 591 else 592 { 593 if (!pTableDesc) 594 { 595 ASSERT(pTableDesc, "What!"); 596 bTestAllowed = false; 597 } 598 else 599 { 600 // --> OD 2005-02-01 #i39468# 601 // If current cell isn't valid, the test is allowed. 602 // The cell isn't valid, if e.g. there is a new row 603 // <pTableDesc->nAktRow> >= <pTableDesc->pTabLines->Count()> 604 bTestAllowed = 605 pTableDesc->GetAktCol() == 0 && 606 ( !pTableDesc->IsValidCell( pTableDesc->GetAktCol() ) || 607 pTableDesc->InFirstParaInCell() ); 608 // <-- 609 } 610 } 611 } 612 } 613 614 if (!bTestAllowed) 615 return aRet; 616 617 aRet.mbStartApo = bNowApo && !InAnyApo(); // APO-start 618 aRet.mbStopApo = InEqualOrHigherApo(nCellLevel) && !bNowApo; // APO-end 619 620 //If it happens that we are in a table, then if its not the first cell 621 //then any attributes that might otherwise cause the contents to jump 622 //into another frame don't matter, a table row sticks together as one 623 //unit no matter what else happens. So if we are not in a table at 624 //all, or if we are in the first cell then test that the last frame 625 //data is the same as the current one 626 if (bNowApo && InEqualApo(nCellLevel)) 627 { 628 // two bordering eachother 629 if (!TestSameApo(aRet, pTabPos)) 630 aRet.mbStopApo = aRet.mbStartApo = true; 631 } 632 633 return aRet; 634 } 635 //--------------------------------------------------------------------- 636 // Hilfroutinen fuer Kapitelnummerierung und Aufzaehlung / Gliederung 637 //--------------------------------------------------------------------- 638 639 static void SetBaseAnlv(SwNumFmt &rNum, WW8_ANLV &rAV, sal_uInt8 nSwLevel ) 640 { 641 static SvxExtNumType eNumA[8] = { SVX_NUM_ARABIC, SVX_NUM_ROMAN_UPPER, SVX_NUM_ROMAN_LOWER, 642 SVX_NUM_CHARS_UPPER_LETTER_N, SVX_NUM_CHARS_LOWER_LETTER_N, SVX_NUM_ARABIC, 643 SVX_NUM_ARABIC, SVX_NUM_ARABIC }; 644 645 static SvxAdjust eAdjA[4] = { SVX_ADJUST_LEFT, 646 SVX_ADJUST_RIGHT, SVX_ADJUST_LEFT, SVX_ADJUST_LEFT }; 647 // eigentlich folgende 2, aber Writer-UI bietet es nicht an 648 // SVX_ADJUST_CENTER, SVX_ADJUST_BLOCKLINE }; 649 650 rNum.SetNumberingType( static_cast< sal_Int16 >(( SVBT8ToByte( rAV.nfc ) < 8 ) ? 651 eNumA[SVBT8ToByte( rAV.nfc ) ] : SVX_NUM_NUMBER_NONE) ); 652 if ((SVBT8ToByte(rAV.aBits1 ) & 0x4) >> 2) 653 rNum.SetIncludeUpperLevels(nSwLevel + 1); 654 rNum.SetStart( SVBT16ToShort( rAV.iStartAt ) ); 655 // rNum.eNumAdjust = eAdjA[rAV.jc]; 656 rNum.SetNumAdjust( eAdjA[SVBT8ToByte( rAV.aBits1 ) & 0x3] ); 657 658 rNum.SetCharTextDistance( SVBT16ToShort( rAV.dxaSpace ) ); 659 sal_Int16 nIndent = Abs((sal_Int16)SVBT16ToShort( rAV.dxaIndent )); 660 if( SVBT8ToByte( rAV.aBits1 ) & 0x08 ) //fHang 661 { 662 rNum.SetFirstLineOffset( -nIndent ); 663 rNum.SetLSpace( nIndent ); 664 rNum.SetAbsLSpace( nIndent ); 665 } 666 else 667 rNum.SetCharTextDistance( nIndent ); // Breite der Nummer fehlt 668 669 if( SVBT8ToByte( rAV.nfc ) == 5 || SVBT8ToByte( rAV.nfc ) == 7 ) 670 { 671 String sP( rNum.GetSuffix() ); 672 sP.Insert( '.', 0 ); 673 rNum.SetSuffix( sP ); // Ordinalzahlen 674 } 675 } 676 677 void SwWW8ImplReader::SetAnlvStrings(SwNumFmt &rNum, WW8_ANLV &rAV, 678 const sal_uInt8* pTxt, bool bOutline) 679 { 680 bool bInsert = false; // Default 681 CharSet eCharSet = eStructCharSet; 682 683 const WW8_FFN* pF = pFonts->GetFont(SVBT16ToShort(rAV.ftc)); // FontInfo 684 bool bListSymbol = pF && ( pF->chs == 2 ); // Symbol/WingDings/... 685 686 String sTxt; 687 if (bVer67) 688 { 689 sTxt = String( (sal_Char*)pTxt, SVBT8ToByte( rAV.cbTextBefore ) 690 + SVBT8ToByte( rAV.cbTextAfter ), eCharSet ); 691 } 692 else 693 { 694 for(xub_StrLen i = SVBT8ToByte(rAV.cbTextBefore); 695 i < SVBT8ToByte(rAV.cbTextAfter); ++i, pTxt += 2) 696 { 697 sTxt.Append(SVBT16ToShort(*(SVBT16*)pTxt)); 698 } 699 } 700 701 if( bOutline ) 702 { // Gliederung 703 if( !rNum.GetIncludeUpperLevels() // es sind <= 1 Nummern anzuzeigen 704 || rNum.GetNumberingType() == SVX_NUM_NUMBER_NONE ){ // oder dieser Level hat keine 705 // eigenen Ziffern 706 bInsert = true; // -> dann uebernehme Zeichen 707 708 // replace by simple Bullet ? 709 if( bListSymbol ) 710 //JP 14.08.96: cBulletChar benutzen, damit auf dem MAC 711 // richtig gemappt wird 712 sTxt.Fill( SVBT8ToByte( rAV.cbTextBefore ) 713 + SVBT8ToByte( rAV.cbTextAfter ), cBulletChar ); 714 } 715 } 716 else 717 { // Nummerierung / Aufzaehlung 718 bInsert = true; 719 // if( SVBT16ToShort( rAV.ftc ) == 1 720 // || SVBT16ToShort( rAV.ftc ) == 3 ){ // Symbol / WingDings 721 if( bListSymbol ) 722 { 723 FontFamily eFamily; 724 String aName; 725 FontPitch ePitch; 726 727 if( GetFontParams( SVBT16ToShort( rAV.ftc ), eFamily, aName, 728 ePitch, eCharSet ) ){ 729 // sal_uInt16 nSiz = ( SVBT16ToShort( rAV.hps ) ) ? 730 // SVBT16ToShort( rAV.hps ) : 24; // Groesse in 1/2 Pt 731 // darf nach JP nicht gesetzt werden, da immer die Size 732 // genommen wird, die am ZeilenAnfang benutzt wird 733 Font aFont; 734 aFont.SetName( aName ); 735 aFont.SetFamily( eFamily ); 736 // aFont.SetPitch( ePitch ); // darf nach JP nicht 737 aFont.SetCharSet( eCharSet ); 738 rNum.SetNumberingType(SVX_NUM_CHAR_SPECIAL); 739 // if( rAV.ico ) // geht in UI und SWG-Writer/Reader nicht 740 // aFont.SetColor( Color( GetCol( rAV.ico ) ) ); 741 rNum.SetBulletFont( &aFont ); 742 743 // take only the very first character 744 if( rAV.cbTextBefore || rAV.cbTextAfter) 745 rNum.SetBulletChar( sTxt.GetChar( 0 ) ); 746 else 747 rNum.SetBulletChar( 0x2190 ); 748 } 749 } 750 } 751 if( bInsert ) 752 { 753 if( rAV.cbTextBefore ) 754 { 755 String sP( sTxt.Copy( 0, SVBT8ToByte( rAV.cbTextBefore ) ) ); 756 rNum.SetPrefix( sP ); 757 } 758 if( SVBT8ToByte( rAV.cbTextAfter ) ) 759 { 760 String sP( rNum.GetSuffix() ); 761 sP.Insert( sTxt.Copy( SVBT8ToByte( rAV.cbTextBefore ), 762 SVBT8ToByte( rAV.cbTextAfter ) ) ); 763 rNum.SetSuffix( sP ); 764 } 765 // Die Zeichen vor und hinter mehreren Ziffern koennen leider nicht uebernommen 766 // werden, da sie der Writer ganz anders behandelt und das Ergebnis i.A. 767 // schlechter als ohne waere. 768 } 769 } 770 771 // SetAnld bekommt einen WW-ANLD-Descriptor und einen Level und modifiziert 772 // die durch pNumR anggebeben NumRules. Wird benutzt fuer alles ausser 773 // Gliederung im Text 774 void SwWW8ImplReader::SetAnld(SwNumRule* pNumR, WW8_ANLD* pAD, sal_uInt8 nSwLevel, 775 bool bOutLine) 776 { 777 SwNumFmt aNF; 778 if (pAD) 779 { // Es gibt einen Anld-Sprm 780 bAktAND_fNumberAcross = 0 != SVBT8ToByte( pAD->fNumberAcross ); 781 WW8_ANLV &rAV = pAD->eAnlv; 782 SetBaseAnlv(aNF, rAV, nSwLevel); // Setze Basis-Format 783 SetAnlvStrings(aNF, rAV, pAD->rgchAnld, bOutLine );// und Rest 784 } 785 pNumR->Set(nSwLevel, aNF); 786 } 787 788 //------------------------------------------------------- 789 // Kapitelnummerierung und Kapitelbullets 790 //------------------------------------------------------- 791 // Kapitelnummerierung findet in Styledefinionen statt. Sprm 13 gibt den Level 792 // an, Sprm 12 den Inhalt 793 794 SwNumRule* SwWW8ImplReader::GetStyRule() 795 { 796 if( pStyles->pStyRule ) // Bullet-Style bereits vorhanden 797 return pStyles->pStyRule; 798 799 const String aBaseName(CREATE_CONST_ASC( "WW8StyleNum" )); 800 const String aName( rDoc.GetUniqueNumRuleName( &aBaseName, false) ); 801 802 // --> OD 2008-06-04 #i86652# 803 // sal_uInt16 nRul = rDoc.MakeNumRule( aName ); 804 sal_uInt16 nRul = rDoc.MakeNumRule( aName, 0, sal_False, 805 SvxNumberFormat::LABEL_ALIGNMENT ); 806 // <-- 807 pStyles->pStyRule = rDoc.GetNumRuleTbl()[nRul]; 808 // Auto == false-> Nummerierungsvorlage 809 pStyles->pStyRule->SetAutoRule(false); 810 811 return pStyles->pStyRule; 812 } 813 814 // Sprm 13 815 void SwWW8ImplReader::Read_ANLevelNo( sal_uInt16, const sal_uInt8* pData, short nLen ) 816 { 817 nSwNumLevel = 0xff; // Default: ungueltig 818 819 if( nLen <= 0 ) 820 return; 821 822 // StyleDef ? 823 if( pAktColl ) 824 { 825 // nur fuer SwTxtFmtColl, nicht CharFmt 826 // WW: 0 = no Numbering 827 SwWW8StyInf * pColl = GetStyle(nAktColl); 828 if (pColl != NULL && pColl->bColl && *pData) 829 { 830 // Bereich WW:1..9 -> SW:0..8 keine Aufzaehlung / Nummerierung 831 832 if (*pData <= MAXLEVEL && *pData <= 9) 833 { 834 nSwNumLevel = *pData - 1; 835 if (!bNoAttrImport) 836 ( (SwTxtFmtColl*) pAktColl )->AssignToListLevelOfOutlineStyle( nSwNumLevel ); 837 // Bei WW-NoNumbering koennte auch NO_NUMBERING gesetzt 838 // werden. ( Bei normaler Nummerierung muss NO_NUM gesetzt 839 // werden: NO_NUM : Nummerierungs-Pause, 840 // NO_NUMBERING : ueberhaupt keine Nummerierung ) 841 842 } 843 else if( *pData == 10 || *pData == 11 ) 844 { 845 // Typ merken, der Rest geschieht bei Sprm 12 846 pStyles->nWwNumLevel = *pData; 847 } 848 } 849 } 850 else 851 { 852 //Not StyleDef 853 if (!bAnl) 854 StartAnl(pData); // Anfang der Gliederung / Aufzaehlung 855 NextAnlLine(pData); 856 } 857 } 858 859 void SwWW8ImplReader::Read_ANLevelDesc( sal_uInt16, const sal_uInt8* pData, short nLen ) // Sprm 12 860 { 861 { 862 SwWW8StyInf * pStyInf = GetStyle(nAktColl); 863 if( !pAktColl || nLen <= 0 // nur bei Styledef 864 || (pStyInf && !pStyInf->bColl) // CharFmt -> ignorieren 865 || ( nIniFlags & WW8FL_NO_OUTLINE ) ){ 866 nSwNumLevel = 0xff; 867 return; 868 } 869 } 870 871 if( nSwNumLevel <= MAXLEVEL // Bereich WW:1..9 -> SW:0..8 872 && nSwNumLevel <= 9 ){ // keine Aufzaehlung / Nummerierung 873 874 // Falls bereits direkt oder durch 875 // Vererbung NumruleItems gesetzt sind, 876 // dann jetzt ausschalten #56163 877 pAktColl->SetFmtAttr( SwNumRuleItem() ); 878 879 String aName(CREATE_CONST_ASC( "Outline" )); 880 // --> OD 2008-02-11 #newlistlevelattrs# 881 SwNumRule aNR( rDoc.GetUniqueNumRuleName( &aName ), 882 SvxNumberFormat::LABEL_WIDTH_AND_POSITION, 883 OUTLINE_RULE ); 884 // <-- 885 aNR = *rDoc.GetOutlineNumRule(); 886 887 SetAnld(&aNR, (WW8_ANLD*)pData, nSwNumLevel, true); 888 889 // fehlende Level muessen nicht aufgefuellt werden 890 891 rDoc.SetOutlineNumRule( aNR ); 892 }else if( pStyles->nWwNumLevel == 10 || pStyles->nWwNumLevel == 11 ){ 893 SwNumRule* pNR = GetStyRule(); 894 SetAnld(pNR, (WW8_ANLD*)pData, 0, false); 895 pAktColl->SetFmtAttr( SwNumRuleItem( pNR->GetName() ) ); 896 897 SwWW8StyInf * pStyInf = GetStyle(nAktColl); 898 if (pStyInf != NULL) 899 pStyInf->bHasStyNumRule = true; 900 } 901 } 902 903 //----------------------------------------- 904 // Nummerierung / Aufzaehlung 905 //----------------------------------------- 906 907 // SetNumOlst() traegt die Numrules fuer diese Zeile ins SwNumFmt ein 908 // ( nur fuer Gliederungen im Text; Aufzaehlungen / Nummerierungen laufen 909 // ueber ANLDs ) 910 // dabei wird die Info aus dem OLST geholt und nicht aus dem ANLD ( s.u. ) 911 void SwWW8ImplReader::SetNumOlst(SwNumRule* pNumR, WW8_OLST* pO, sal_uInt8 nSwLevel) 912 { 913 SwNumFmt aNF; 914 WW8_ANLV &rAV = pO->rganlv[nSwLevel]; 915 SetBaseAnlv(aNF, rAV, nSwLevel); 916 // ... und then the Strings 917 int nTxtOfs = 0; 918 sal_uInt8 i; 919 WW8_ANLV* pAV1; // search String-Positions 920 for (i = 0, pAV1 = pO->rganlv; i < nSwLevel; ++i, ++pAV1) 921 { 922 nTxtOfs += SVBT8ToByte(pAV1->cbTextBefore) 923 + SVBT8ToByte(pAV1->cbTextAfter); 924 } 925 926 if (!bVer67) 927 nTxtOfs *= 2; 928 SetAnlvStrings(aNF, rAV, pO->rgch + nTxtOfs, true); // und rein 929 pNumR->Set(nSwLevel, aNF); 930 } 931 932 // der OLST kommt am Anfang jeder Section, die Gliederungen enthaelt. Die ANLDs, 933 // die an jeder Gliederungszeile haengen, enthalten nur Stuss, also werden die 934 // OLSTs waehrend der Section gemerkt, damit die Informationen beim Auftreten 935 // von Gliederungsabsaetzen zugreifbar ist. 936 void SwWW8ImplReader::Read_OLST( sal_uInt16, const sal_uInt8* pData, short nLen ) 937 { 938 if (nLen <= 0) 939 { 940 delete pNumOlst, pNumOlst = 0; 941 return; 942 } 943 if (pNumOlst) 944 delete pNumOlst; // nur sicherheitshalber 945 pNumOlst = new WW8_OLST; 946 if( nLen < sal::static_int_cast< sal_Int32 >(sizeof( WW8_OLST )) ) // auffuellen, falls zu kurz 947 memset( pNumOlst, 0, sizeof( *pNumOlst ) ); 948 *pNumOlst = *(WW8_OLST*)pData; 949 } 950 951 WW8LvlType GetNumType(sal_uInt8 nWwLevelNo) 952 { 953 WW8LvlType nRet = WW8_None; 954 if( nWwLevelNo == 12 ) 955 nRet = WW8_Pause; 956 else if( nWwLevelNo == 10 ) 957 nRet = WW8_Numbering; 958 else if( nWwLevelNo == 11 ) 959 nRet = WW8_Sequence; 960 else if( nWwLevelNo > 0 && nWwLevelNo <= 9 ) 961 nRet = WW8_Outline; 962 return nRet; 963 } 964 965 SwNumRule *ANLDRuleMap::GetNumRule(sal_uInt8 nNumType) 966 { 967 return (WW8_Numbering == nNumType ? mpNumberingNumRule : mpOutlineNumRule); 968 } 969 970 void ANLDRuleMap::SetNumRule(SwNumRule *pRule, sal_uInt8 nNumType) 971 { 972 if (WW8_Numbering == nNumType) 973 mpNumberingNumRule = pRule; 974 else 975 mpOutlineNumRule = pRule; 976 } 977 978 979 // StartAnl wird am Anfang eines Zeilenbereichs gerufen, 980 // der Gliederung / Nummerierung / Aufzaehlung enthaelt 981 void SwWW8ImplReader::StartAnl(const sal_uInt8* pSprm13) 982 { 983 bAktAND_fNumberAcross = false; 984 985 sal_uInt8 nT = static_cast< sal_uInt8 >(GetNumType(*pSprm13)); 986 if (nT == WW8_Pause || nT == WW8_None) 987 return; 988 989 nWwNumType = nT; 990 SwNumRule *pNumRule = maANLDRules.GetNumRule(nWwNumType); 991 992 // check for COL numbering: 993 const sal_uInt8* pS12 = 0;// sprmAnld 994 String sNumRule; 995 996 if (pTableDesc) 997 { 998 sNumRule = pTableDesc->GetNumRuleName(); 999 if (sNumRule.Len()) 1000 { 1001 pNumRule = rDoc.FindNumRulePtr(sNumRule); 1002 if (!pNumRule) 1003 sNumRule.Erase(); 1004 else 1005 { 1006 // this is ROW numbering ? 1007 pS12 = pPlcxMan->HasParaSprm(bVer67 ? 12 : 0xC63E); // sprmAnld 1008 if (pS12 && 0 != SVBT8ToByte(((WW8_ANLD*)pS12)->fNumberAcross)) 1009 sNumRule.Erase(); 1010 } 1011 } 1012 } 1013 1014 SwWW8StyInf * pStyInf = GetStyle(nAktColl); 1015 if (!sNumRule.Len() && pStyInf->bHasStyNumRule) 1016 { 1017 sNumRule = pStyInf->pFmt->GetNumRule().GetValue(); 1018 pNumRule = rDoc.FindNumRulePtr(sNumRule); 1019 if (!pNumRule) 1020 sNumRule.Erase(); 1021 } 1022 1023 if (!sNumRule.Len()) 1024 { 1025 if (!pNumRule) 1026 { 1027 // --> OD 2008-06-04 #i86652# 1028 // pNumRule = rDoc.GetNumRuleTbl()[rDoc.MakeNumRule(sNumRule)]; 1029 pNumRule = rDoc.GetNumRuleTbl()[ 1030 rDoc.MakeNumRule( sNumRule, 0, sal_False, 1031 SvxNumberFormat::LABEL_ALIGNMENT ) ]; 1032 // <-- 1033 } 1034 if (pTableDesc) 1035 { 1036 if (!pS12) 1037 pS12 = pPlcxMan->HasParaSprm(bVer67 ? 12 : 0xC63E); // sprmAnld 1038 if (!pS12 || !SVBT8ToByte( ((WW8_ANLD*)pS12)->fNumberAcross)) 1039 pTableDesc->SetNumRuleName(pNumRule->GetName()); 1040 } 1041 } 1042 1043 bAnl = true; 1044 1045 // NumRules ueber Stack setzen 1046 pCtrlStck->NewAttr(*pPaM->GetPoint(), 1047 SfxStringItem(RES_FLTR_NUMRULE, pNumRule->GetName())); 1048 1049 maANLDRules.SetNumRule(pNumRule, nWwNumType); 1050 } 1051 1052 // NextAnlLine() wird fuer jede Zeile einer 1053 // Gliederung / Nummerierung / Aufzaehlung einmal gerufen 1054 void SwWW8ImplReader::NextAnlLine(const sal_uInt8* pSprm13) 1055 { 1056 if (!bAnl) 1057 return; 1058 1059 SwNumRule *pNumRule = maANLDRules.GetNumRule(nWwNumType); 1060 1061 // pNd->UpdateNum ohne Regelwerk gibt GPF spaetestens beim Speichern als 1062 // sdw3 1063 1064 // WW:10 = Nummerierung -> SW:0 & WW:11 = Auffzaehlung -> SW:0 1065 if (*pSprm13 == 10 || *pSprm13 == 11) 1066 { 1067 nSwNumLevel = 0; 1068 if (!pNumRule->GetNumFmt(nSwNumLevel)) 1069 { 1070 // noch nicht definiert 1071 // sprmAnld o. 0 1072 const sal_uInt8* pS12 = pPlcxMan->HasParaSprm(bVer67 ? 12 : 0xC63E); 1073 SetAnld(pNumRule, (WW8_ANLD*)pS12, nSwNumLevel, false); 1074 } 1075 } 1076 else if( *pSprm13 > 0 && *pSprm13 <= MAXLEVEL ) // Bereich WW:1..9 -> SW:0..8 1077 { 1078 nSwNumLevel = *pSprm13 - 1; // Gliederung 1079 // noch nicht definiert 1080 if (!pNumRule->GetNumFmt(nSwNumLevel)) 1081 { 1082 if (pNumOlst) // es gab ein OLST 1083 { 1084 //Assure upper levels are set, #i9556# 1085 for (sal_uInt8 nI = 0; nI < nSwNumLevel; ++nI) 1086 { 1087 if (!pNumRule->GetNumFmt(nI)) 1088 SetNumOlst(pNumRule, pNumOlst, nI); 1089 } 1090 1091 SetNumOlst(pNumRule, pNumOlst , nSwNumLevel); 1092 } 1093 else // kein Olst, nimm Anld 1094 { 1095 // sprmAnld 1096 const sal_uInt8* pS12 = pPlcxMan->HasParaSprm(bVer67 ? 12 : 0xC63E); 1097 SetAnld(pNumRule, (WW8_ANLD*)pS12, nSwNumLevel, false); 1098 } 1099 } 1100 } 1101 else 1102 nSwNumLevel = 0xff; // keine Nummer 1103 1104 SwTxtNode* pNd = pPaM->GetNode()->GetTxtNode(); 1105 if (nSwNumLevel < MAXLEVEL) 1106 pNd->SetAttrListLevel( nSwNumLevel ); 1107 else 1108 { 1109 pNd->SetAttrListLevel(0); 1110 pNd->SetCountedInList( false ); 1111 } 1112 } 1113 1114 void SwWW8ImplReader::StopAllAnl(bool bGoBack) 1115 { 1116 //Of course we're not restarting, but we'll make use of our knowledge 1117 //of the implementation to do it. 1118 StopAnlToRestart(WW8_None, bGoBack); 1119 } 1120 1121 void SwWW8ImplReader::StopAnlToRestart(sal_uInt8 nNewType, bool bGoBack) 1122 { 1123 if (bGoBack) 1124 { 1125 SwPosition aTmpPos(*pPaM->GetPoint()); 1126 pPaM->Move(fnMoveBackward, fnGoCntnt); 1127 pCtrlStck->SetAttr(*pPaM->GetPoint(), RES_FLTR_NUMRULE); 1128 *pPaM->GetPoint() = aTmpPos; 1129 } 1130 else 1131 pCtrlStck->SetAttr(*pPaM->GetPoint(), RES_FLTR_NUMRULE); 1132 1133 maANLDRules.mpNumberingNumRule = 0; 1134 /* 1135 #i18816# 1136 my take on this problem is that moving either way from an outline to a 1137 numbering doesn't halt the outline, while the numbering is always halted 1138 */ 1139 bool bNumberingNotStopOutline = 1140 (((nWwNumType == WW8_Outline) && (nNewType == WW8_Numbering)) || 1141 ((nWwNumType == WW8_Numbering) && (nNewType == WW8_Outline))); 1142 if (!bNumberingNotStopOutline) 1143 maANLDRules.mpOutlineNumRule = 0; 1144 1145 nSwNumLevel = 0xff; 1146 nWwNumType = WW8_None; 1147 bAnl = false; 1148 } 1149 1150 WW8TabBandDesc::WW8TabBandDesc( WW8TabBandDesc& rBand ) 1151 { 1152 *this = rBand; 1153 if( rBand.pTCs ) 1154 { 1155 pTCs = new WW8_TCell[nWwCols]; 1156 memcpy( pTCs, rBand.pTCs, nWwCols * sizeof( WW8_TCell ) ); 1157 } 1158 if( rBand.pSHDs ) 1159 { 1160 pSHDs = new WW8_SHD[nWwCols]; 1161 memcpy( pSHDs, rBand.pSHDs, nWwCols * sizeof( WW8_SHD ) ); 1162 } 1163 if( rBand.pNewSHDs ) 1164 { 1165 pNewSHDs = new sal_uInt32[nWwCols]; 1166 memcpy(pNewSHDs, rBand.pNewSHDs, nWwCols * sizeof(sal_uInt32)); 1167 } 1168 memcpy(aDefBrcs, rBand.aDefBrcs, sizeof(aDefBrcs)); 1169 } 1170 1171 // ReadDef liest die Zellenpositionen und ggfs die Umrandungen eines Bandes ein 1172 void WW8TabBandDesc::ReadDef(bool bVer67, const sal_uInt8* pS) 1173 { 1174 if (!bVer67) 1175 pS++; 1176 1177 short nLen = (sal_Int16)SVBT16ToShort( pS - 2 ); // nicht schoen 1178 1179 sal_uInt8 nCols = *pS; // Anzahl der Zellen 1180 short nOldCols = nWwCols; 1181 1182 if( nCols > MAX_COL ) 1183 return; 1184 1185 nWwCols = nCols; 1186 1187 const sal_uInt8* pT = &pS[1]; 1188 nLen --; 1189 int i; 1190 for(i=0; i<=nCols; i++, pT+=2 ) 1191 nCenter[i] = (sal_Int16)SVBT16ToShort( pT ); // X-Raender 1192 nLen -= 2 * ( nCols + 1 ); 1193 if( nCols != nOldCols ) // andere Spaltenzahl 1194 { 1195 delete[] pTCs, pTCs = 0; 1196 delete[] pSHDs, pSHDs = 0; 1197 delete[] pNewSHDs, pNewSHDs = 0; 1198 } 1199 1200 short nFileCols = nLen / ( bVer67 ? 10 : 20 ); // wirklich abgespeichert 1201 1202 if (!pTCs && nCols) 1203 { 1204 // lege leere TCs an 1205 pTCs = new WW8_TCell[nCols]; 1206 setcelldefaults(pTCs,nCols); 1207 } 1208 1209 short nColsToRead = nFileCols; 1210 if (nColsToRead > nCols) 1211 nColsToRead = nCols; 1212 1213 if( nColsToRead ) 1214 { 1215 // lies TCs ein 1216 1217 /* 1218 Achtung: ab Ver8 ist ein reserve-ushort je TC eingefuegt und auch 1219 der Border-Code ist doppelt so gross, daher ist hier 1220 kein simples kopieren moeglich, 1221 d.h.: pTCs[i] = *pTc; geht leider nicht. 1222 --- 1223 Vorteil: Arbeitstruktur ist jetzt viel bequemer zu handhaben! 1224 */ 1225 WW8_TCell* pAktTC = pTCs; 1226 if( bVer67 ) 1227 { 1228 WW8_TCellVer6* pTc = (WW8_TCellVer6*)pT; 1229 for(i=0; i<nColsToRead; i++, ++pAktTC,++pTc) 1230 { 1231 if( i < nColsToRead ) 1232 { // TC aus File ? 1233 sal_uInt8 aBits1 = SVBT8ToByte( pTc->aBits1Ver6 ); 1234 pAktTC->bFirstMerged = ( ( aBits1 & 0x01 ) != 0 ); 1235 pAktTC->bMerged = ( ( aBits1 & 0x02 ) != 0 ); 1236 memcpy( pAktTC->rgbrc[ WW8_TOP ].aBits1, 1237 pTc->rgbrcVer6[ WW8_TOP ].aBits1, sizeof( SVBT16 ) ); 1238 memcpy( pAktTC->rgbrc[ WW8_LEFT ].aBits1, 1239 pTc->rgbrcVer6[ WW8_LEFT ].aBits1, sizeof( SVBT16 ) ); 1240 memcpy( pAktTC->rgbrc[ WW8_BOT ].aBits1, 1241 pTc->rgbrcVer6[ WW8_BOT ].aBits1, sizeof( SVBT16 ) ); 1242 memcpy( pAktTC->rgbrc[ WW8_RIGHT ].aBits1, 1243 pTc->rgbrcVer6[ WW8_RIGHT ].aBits1, sizeof( SVBT16 ) ); 1244 if( ( pAktTC->bMerged ) 1245 && ( i > 0 ) ) 1246 { 1247 // Cell gemerged -> merken 1248 //bWWMergedVer6[i] = true; 1249 memcpy( pTCs[i-1].rgbrc[ WW8_RIGHT ].aBits1, 1250 pTc->rgbrcVer6[ WW8_RIGHT ].aBits1, sizeof( SVBT16 ) ); 1251 // right Border in vorige Zelle uebernehmen 1252 // Hier darf bExist nicht auf false gesetzt werden, da WW 1253 // in den Textboxen diese Zellen nicht mitzaehlt.... 1254 } 1255 } 1256 } 1257 } 1258 else 1259 { 1260 WW8_TCellVer8* pTc = (WW8_TCellVer8*)pT; 1261 for (int k = 0; k < nColsToRead; ++k, ++pAktTC, ++pTc ) 1262 { 1263 sal_uInt16 aBits1 = SVBT16ToShort( pTc->aBits1Ver8 ); 1264 pAktTC->bFirstMerged = ( ( aBits1 & 0x0001 ) != 0 ); 1265 pAktTC->bMerged = ( ( aBits1 & 0x0002 ) != 0 ); 1266 pAktTC->bVertical = ( ( aBits1 & 0x0004 ) != 0 ); 1267 pAktTC->bBackward = ( ( aBits1 & 0x0008 ) != 0 ); 1268 pAktTC->bRotateFont = ( ( aBits1 & 0x0010 ) != 0 ); 1269 pAktTC->bVertMerge = ( ( aBits1 & 0x0020 ) != 0 ); 1270 pAktTC->bVertRestart = ( ( aBits1 & 0x0040 ) != 0 ); 1271 pAktTC->nVertAlign = ( ( aBits1 & 0x0180 ) >> 7 ); 1272 // am Rande: im aBits1 verstecken sich noch 7 Reserve-Bits, 1273 // anschliessend folgen noch 16 weitere Reserve-Bits 1274 1275 // In Version 8 koennen wir alle Bordercodes auf einmal kopieren! 1276 memcpy( pAktTC->rgbrc, pTc->rgbrcVer8, 4 * sizeof( WW8_BRC ) ); 1277 } 1278 } 1279 1280 // #i25071 In '97 text direction appears to be only set using TC properties 1281 // not with sprmTTextFlow so we need to cycle through the maDirections and 1282 // double check any non-default directions 1283 for (int k = 0; k < nCols; ++k) 1284 { 1285 if(maDirections[k] == 4) 1286 { 1287 if(pTCs[k].bVertical) 1288 { 1289 if(pTCs[k].bBackward) 1290 maDirections[k] = 3; 1291 else 1292 maDirections[k] = 1; 1293 } 1294 } 1295 } 1296 1297 1298 } 1299 } 1300 1301 void WW8TabBandDesc::ProcessSprmTSetBRC(bool bVer67, const sal_uInt8* pParamsTSetBRC) 1302 { 1303 if( pParamsTSetBRC && pTCs ) // set one or more cell border(s) 1304 { 1305 sal_uInt8 nitcFirst= pParamsTSetBRC[0];// first col to be changed 1306 sal_uInt8 nitcLim = pParamsTSetBRC[1];// (last col to be changed)+1 1307 sal_uInt8 nFlag = *(pParamsTSetBRC+2); 1308 1309 if (nitcFirst >= nWwCols) 1310 return; 1311 1312 if (nitcLim > nWwCols) 1313 nitcLim = nWwCols; 1314 1315 bool bChangeRight = (nFlag & 0x08) ? true : false; 1316 bool bChangeBottom = (nFlag & 0x04) ? true : false; 1317 bool bChangeLeft = (nFlag & 0x02) ? true : false; 1318 bool bChangeTop = (nFlag & 0x01) ? true : false; 1319 1320 WW8_TCell* pAktTC = pTCs + nitcFirst; 1321 if( bVer67 ) 1322 { 1323 WW8_BRCVer6* pBRC = (WW8_BRCVer6*)(pParamsTSetBRC+3); 1324 1325 for( int i = nitcFirst; i < nitcLim; i++, ++pAktTC ) 1326 { 1327 if( bChangeTop ) 1328 memcpy( pAktTC->rgbrc[ WW8_TOP ].aBits1, 1329 pBRC->aBits1, 1330 sizeof( SVBT16 ) ); 1331 if( bChangeLeft ) 1332 memcpy( pAktTC->rgbrc[ WW8_LEFT ].aBits1, 1333 pBRC->aBits1, 1334 sizeof( SVBT16 ) ); 1335 if( bChangeBottom ) 1336 memcpy( pAktTC->rgbrc[ WW8_BOT ].aBits1, 1337 pBRC->aBits1, 1338 sizeof( SVBT16 ) ); 1339 if( bChangeRight ) 1340 memcpy( pAktTC->rgbrc[ WW8_RIGHT].aBits1, 1341 pBRC->aBits1, 1342 sizeof( SVBT16 ) ); 1343 } 1344 } 1345 else 1346 { 1347 WW8_BRC* pBRC = (WW8_BRC*)(pParamsTSetBRC+3); 1348 1349 for( int i = nitcFirst; i < nitcLim; i++, ++pAktTC ) 1350 { 1351 if( bChangeTop ) 1352 memcpy( pAktTC->rgbrc[ WW8_TOP ].aBits1, 1353 pBRC->aBits1, 1354 sizeof( WW8_BRC ) ); 1355 if( bChangeLeft ) 1356 memcpy( pAktTC->rgbrc[ WW8_LEFT ].aBits1, 1357 pBRC->aBits1, 1358 sizeof( WW8_BRC ) ); 1359 if( bChangeBottom ) 1360 memcpy( pAktTC->rgbrc[ WW8_BOT ].aBits1, 1361 pBRC->aBits1, 1362 sizeof( WW8_BRC ) ); 1363 if( bChangeRight ) 1364 memcpy( pAktTC->rgbrc[ WW8_RIGHT].aBits1, 1365 pBRC->aBits1, 1366 sizeof( WW8_BRC ) ); 1367 } 1368 1369 1370 1371 } 1372 } 1373 } 1374 1375 void WW8TabBandDesc::ProcessSprmTTableBorders(bool bVer67, const sal_uInt8* pParams) 1376 { 1377 // sprmTTableBorders 1378 if( bVer67 ) 1379 { 1380 for( int i = 0; i < 6; ++i ) 1381 { 1382 aDefBrcs[i].aBits1[0] = pParams[ 2*i ]; 1383 aDefBrcs[i].aBits1[1] = pParams[ 1+2*i ]; 1384 } 1385 } 1386 else // aDefBrcs = *(BRC(*)[6])pS; 1387 memcpy( aDefBrcs, pParams, 24 ); 1388 } 1389 1390 void WW8TabBandDesc::ProcessSprmTDxaCol(const sal_uInt8* pParamsTDxaCol) 1391 { 1392 // sprmTDxaCol (opcode 0x7623) changes the width of cells 1393 // whose index is within a certain range to be a certain value. 1394 1395 if( nWwCols && pParamsTDxaCol ) // set one or more cell length(s) 1396 { 1397 sal_uInt8 nitcFirst= pParamsTDxaCol[0]; // first col to be changed 1398 sal_uInt8 nitcLim = pParamsTDxaCol[1]; // (last col to be changed)+1 1399 short nDxaCol = (sal_Int16)SVBT16ToShort( pParamsTDxaCol + 2 ); 1400 short nOrgWidth; 1401 short nDelta; 1402 1403 for( int i = nitcFirst; (i < nitcLim) && (i < nWwCols); i++ ) 1404 { 1405 nOrgWidth = nCenter[i+1] - nCenter[i]; 1406 nDelta = nDxaCol - nOrgWidth; 1407 for( int j = i+1; j <= nWwCols; j++ ) 1408 { 1409 nCenter[j] = nCenter[j] + nDelta; 1410 } 1411 } 1412 } 1413 } 1414 1415 void WW8TabBandDesc::ProcessSprmTInsert(const sal_uInt8* pParamsTInsert) 1416 { 1417 if( nWwCols && pParamsTInsert ) // set one or more cell length(s) 1418 { 1419 sal_uInt8 nitcInsert = pParamsTInsert[0]; // position at which to insert 1420 if (nitcInsert >= MAX_COL) // cannot insert into cell outside max possible index 1421 return; 1422 sal_uInt8 nctc = pParamsTInsert[1]; // number of cells 1423 sal_uInt16 ndxaCol = SVBT16ToShort( pParamsTInsert+2 ); 1424 1425 short nNewWwCols; 1426 if (nitcInsert > nWwCols) 1427 { 1428 nNewWwCols = nitcInsert+nctc; 1429 //if new count would be outside max possible count, clip it, and calc a new replacement 1430 //legal nctc 1431 if (nNewWwCols > MAX_COL) 1432 { 1433 nNewWwCols = MAX_COL; 1434 nctc = ::sal::static_int_cast<sal_uInt8>(nNewWwCols-nitcInsert); 1435 } 1436 } 1437 else 1438 { 1439 nNewWwCols = nWwCols+nctc; 1440 //if new count would be outside max possible count, clip it, and calc a new replacement 1441 //legal nctc 1442 if (nNewWwCols > MAX_COL) 1443 { 1444 nNewWwCols = MAX_COL; 1445 nctc = ::sal::static_int_cast<sal_uInt8>(nNewWwCols-nWwCols); 1446 } 1447 } 1448 1449 WW8_TCell *pTC2s = new WW8_TCell[nNewWwCols]; 1450 setcelldefaults(pTC2s, nNewWwCols); 1451 1452 if (pTCs) 1453 { 1454 memcpy( pTC2s, pTCs, nWwCols * sizeof( WW8_TCell ) ); 1455 delete[] pTCs; 1456 } 1457 pTCs = pTC2s; 1458 1459 //If we have to move some cells 1460 if (nitcInsert <= nWwCols) 1461 { 1462 // adjust the left x-position of the dummy at the very end 1463 nCenter[nWwCols + nctc] = nCenter[nWwCols]+nctc*ndxaCol; 1464 for( int i = nWwCols-1; i >= nitcInsert; i--) 1465 { 1466 // adjust the left x-position 1467 nCenter[i + nctc] = nCenter[i]+nctc*ndxaCol; 1468 1469 // adjust the cell's borders 1470 pTCs[i + nctc] = pTCs[i]; 1471 } 1472 } 1473 1474 //if itcMac is larger than full size, fill in missing ones first 1475 for( int i = nWwCols; i > nitcInsert+nWwCols; i--) 1476 nCenter[i] = i ? (nCenter[i - 1]+ndxaCol) : 0; 1477 1478 //now add in our new cells 1479 for( int j = 0;j < nctc; j++) 1480 nCenter[j + nitcInsert] = (j + nitcInsert) ? (nCenter[j + nitcInsert -1]+ndxaCol) : 0; 1481 1482 nWwCols = nNewWwCols; 1483 } 1484 } 1485 1486 void WW8TabBandDesc::ProcessDirection(const sal_uInt8* pParams) 1487 { 1488 sal_uInt8 nStartCell = *pParams++; 1489 sal_uInt8 nEndCell = *pParams++; 1490 sal_uInt16 nCode = SVBT16ToShort(pParams); 1491 1492 ASSERT(nStartCell < nEndCell, "not as I thought"); 1493 ASSERT(nEndCell < MAX_COL + 1, "not as I thought"); 1494 if (nStartCell > MAX_COL) 1495 return; 1496 if (nEndCell > MAX_COL + 1) 1497 nEndCell = MAX_COL + 1; 1498 1499 for (;nStartCell < nEndCell; ++nStartCell) 1500 maDirections[nStartCell] = nCode; 1501 } 1502 1503 void WW8TabBandDesc::ProcessSpacing(const sal_uInt8* pParams) 1504 { 1505 sal_uInt8 nLen = pParams ? *(pParams - 1) : 0; 1506 ASSERT(nLen == 6, "Unexpected spacing len"); 1507 if (nLen != 6) 1508 return; 1509 mbHasSpacing=true; 1510 #ifdef DBG_UTIL 1511 sal_uInt8 nWhichCell = *pParams; 1512 ASSERT(nWhichCell == 0, "Expected cell to be 0!"); 1513 #endif 1514 ++pParams; //Skip which cell 1515 ++pParams; //unknown byte 1516 1517 sal_uInt8 nSideBits = *pParams++; 1518 ASSERT(nSideBits < 0x10, "Unexpected value for nSideBits"); 1519 ++pParams; //unknown byte 1520 sal_uInt16 nValue = SVBT16ToShort( pParams ); 1521 for (int i = wwTOP; i <= wwRIGHT; i++) 1522 { 1523 switch (nSideBits & (1 << i)) 1524 { 1525 case 1 << wwTOP: 1526 mnDefaultTop = nValue; 1527 break; 1528 case 1 << wwLEFT: 1529 mnDefaultLeft = nValue; 1530 break; 1531 case 1 << wwBOTTOM: 1532 mnDefaultBottom = nValue; 1533 break; 1534 case 1 << wwRIGHT: 1535 mnDefaultRight = nValue; 1536 break; 1537 case 0: 1538 break; 1539 default: 1540 ASSERT(!this, "Impossible"); 1541 break; 1542 } 1543 } 1544 } 1545 1546 void WW8TabBandDesc::ProcessSpecificSpacing(const sal_uInt8* pParams) 1547 { 1548 sal_uInt8 nLen = pParams ? *(pParams - 1) : 0; 1549 ASSERT(nLen == 6, "Unexpected spacing len"); 1550 if (nLen != 6) 1551 return; 1552 sal_uInt8 nWhichCell = *pParams++; 1553 ASSERT(nWhichCell < MAX_COL + 1, "Cell out of range in spacings"); 1554 if (nWhichCell >= MAX_COL + 1) 1555 return; 1556 1557 ++pParams; //unknown byte 1558 sal_uInt8 nSideBits = *pParams++; 1559 ASSERT(nSideBits < 0x10, "Unexpected value for nSideBits"); 1560 nOverrideSpacing[nWhichCell] |= nSideBits; 1561 1562 ASSERT(nOverrideSpacing[nWhichCell] < 0x10, 1563 "Unexpected value for nSideBits"); 1564 #ifdef DBG_UTIL 1565 sal_uInt8 nUnknown2 = *pParams; 1566 ASSERT(nUnknown2 == 0x3, "Unexpected value for spacing2"); 1567 #endif 1568 ++pParams; 1569 sal_uInt16 nValue = SVBT16ToShort( pParams ); 1570 1571 for (int i=0; i < 4; i++) 1572 { 1573 if (nSideBits & (1 << i)) 1574 nOverrideValues[nWhichCell][i] = nValue; 1575 } 1576 } 1577 1578 void WW8TabBandDesc::ProcessSprmTDelete(const sal_uInt8* pParamsTDelete) 1579 { 1580 if( nWwCols && pParamsTDelete ) // set one or more cell length(s) 1581 { 1582 sal_uInt8 nitcFirst= pParamsTDelete[0]; // first col to be deleted 1583 if (nitcFirst >= nWwCols) // first index to delete from doesn't exist 1584 return; 1585 sal_uInt8 nitcLim = pParamsTDelete[1]; // (last col to be deleted)+1 1586 if (nitcLim <= nitcFirst) // second index to delete to is not greater than first index 1587 return; 1588 1589 /* 1590 * sprmTDelete causes any rgdxaCenter and rgtc entries whose index is 1591 * greater than or equal to itcLim to be moved 1592 */ 1593 int nShlCnt = nWwCols - nitcLim; // count of cells to be shifted 1594 1595 if (nShlCnt >= 0) //There exist entries whose index is greater than or equal to itcLim 1596 { 1597 WW8_TCell* pAktTC = pTCs + nitcFirst; 1598 int i = 0; 1599 while( i < nShlCnt ) 1600 { 1601 // adjust the left x-position 1602 nCenter[nitcFirst + i] = nCenter[nitcLim + i]; 1603 1604 // adjust the cell's borders 1605 *pAktTC = pTCs[ nitcLim + i]; 1606 1607 ++i; 1608 ++pAktTC; 1609 } 1610 // adjust the left x-position of the dummy at the very end 1611 nCenter[nitcFirst + i] = nCenter[nitcLim + i]; 1612 } 1613 1614 short nCellsDeleted = nitcLim - nitcFirst; 1615 //clip delete request to available number of cells 1616 if (nCellsDeleted > nWwCols) 1617 nCellsDeleted = nWwCols; 1618 nWwCols -= nCellsDeleted; 1619 } 1620 } 1621 1622 // ReadShd liest ggfs die Hintergrundfarben einer Zeile ein. 1623 // Es muss vorher ReadDef aufgerufen worden sein 1624 void WW8TabBandDesc::ReadShd(const sal_uInt8* pS ) 1625 { 1626 sal_uInt8 nLen = pS ? *(pS - 1) : 0; 1627 if( !nLen ) 1628 return; 1629 1630 if( !pSHDs ) 1631 { 1632 pSHDs = new WW8_SHD[nWwCols]; 1633 memset( pSHDs, 0, nWwCols * sizeof( WW8_SHD ) ); 1634 } 1635 1636 short nAnz = nLen >> 1; 1637 if (nAnz > nWwCols) 1638 nAnz = nWwCols; 1639 1640 SVBT16* pShd; 1641 int i; 1642 for(i=0, pShd = (SVBT16*)pS; i<nAnz; i++, pShd++ ) 1643 pSHDs[i].SetWWValue( *pShd ); 1644 } 1645 1646 void WW8TabBandDesc::ReadNewShd(const sal_uInt8* pS, bool bVer67) 1647 { 1648 sal_uInt8 nLen = pS ? *(pS - 1) : 0; 1649 if (!nLen) 1650 return; 1651 1652 if (!pNewSHDs) 1653 pNewSHDs = new sal_uInt32[nWwCols]; 1654 1655 short nAnz = nLen / 10; //10 bytes each 1656 if (nAnz > nWwCols) 1657 nAnz = nWwCols; 1658 1659 int i=0; 1660 while (i < nAnz) 1661 pNewSHDs[i++] = SwWW8ImplReader::ExtractColour(pS, bVer67); 1662 1663 while (i < nWwCols) 1664 pNewSHDs[i++] = COL_AUTO; 1665 } 1666 1667 void WW8TabBandDesc::setcelldefaults(WW8_TCell *pCells, short nCols) 1668 { 1669 memset( pCells, 0, nCols * sizeof( WW8_TCell ) ); 1670 } 1671 1672 const sal_uInt8 *HasTabCellSprm(WW8PLCFx_Cp_FKP* pPap, bool bVer67) 1673 { 1674 const sal_uInt8 *pParams; 1675 if (bVer67) 1676 pParams = pPap->HasSprm(24); 1677 else 1678 { 1679 if (0 == (pParams = pPap->HasSprm(0x244B))) 1680 pParams = pPap->HasSprm(0x2416); 1681 } 1682 return pParams; 1683 } 1684 1685 enum wwTableSprm 1686 { 1687 sprmNil, 1688 1689 sprmTTableWidth,sprmTTextFlow, sprmTFCantSplit, sprmTFCantSplit90,sprmTJc, sprmTFBiDi, sprmTDefTable, 1690 sprmTDyaRowHeight, sprmTDefTableShd, sprmTDxaLeft, sprmTSetBrc, 1691 sprmTDxaCol, sprmTInsert, sprmTDelete, sprmTTableHeader, 1692 sprmTDxaGapHalf, sprmTTableBorders, 1693 1694 sprmTDefTableNewShd, sprmTSpacing, sprmTNewSpacing 1695 }; 1696 1697 wwTableSprm GetTableSprm(sal_uInt16 nId, ww::WordVersion eVer) 1698 { 1699 switch (eVer) 1700 { 1701 case ww::eWW8: 1702 switch (nId) 1703 { 1704 case 0xF614: 1705 return sprmTTableWidth; 1706 case 0x7629: 1707 return sprmTTextFlow; 1708 case 0x3403: 1709 return sprmTFCantSplit; 1710 case 0x3404: 1711 return sprmTTableHeader; 1712 case 0x3466: 1713 return sprmTFCantSplit90; 1714 case 0x5400: 1715 return sprmTJc; 1716 case 0x560B: 1717 return sprmTFBiDi; 1718 case 0x5622: 1719 return sprmTDelete; 1720 case 0x7621: 1721 return sprmTInsert; 1722 case 0x7623: 1723 return sprmTDxaCol; 1724 case 0x9407: 1725 return sprmTDyaRowHeight; 1726 case 0x9601: 1727 return sprmTDxaLeft; 1728 case 0x9602: 1729 return sprmTDxaGapHalf; 1730 case 0xD605: 1731 return sprmTTableBorders; 1732 case 0xD608: 1733 return sprmTDefTable; 1734 case 0xD609: 1735 return sprmTDefTableShd; 1736 case 0xD612: 1737 return sprmTDefTableNewShd; 1738 case 0xD620: 1739 return sprmTSetBrc; 1740 case 0xD632: 1741 return sprmTSpacing; 1742 case 0xD634: 1743 return sprmTNewSpacing; 1744 } 1745 break; 1746 case ww::eWW7: 1747 case ww::eWW6: 1748 switch (nId) 1749 { 1750 case 182: 1751 return sprmTJc; 1752 case 183: 1753 return sprmTDxaLeft; 1754 case 184: 1755 return sprmTDxaGapHalf; 1756 case 186: 1757 return sprmTTableHeader; 1758 case 187: 1759 return sprmTTableBorders; 1760 case 189: 1761 return sprmTDyaRowHeight; 1762 case 190: 1763 return sprmTDefTable; 1764 case 191: 1765 return sprmTDefTableShd; 1766 case 193: 1767 return sprmTSetBrc; 1768 case 194: 1769 return sprmTInsert; 1770 case 195: 1771 return sprmTDelete; 1772 case 196: 1773 return sprmTDxaCol; 1774 } 1775 break; 1776 case ww::eWW2: 1777 switch (nId) 1778 { 1779 case 146: 1780 return sprmTJc; 1781 case 147: 1782 return sprmTDxaLeft; 1783 case 148: 1784 return sprmTDxaGapHalf; 1785 case 153: 1786 return sprmTDyaRowHeight; 1787 case 154: 1788 return sprmTDefTable; 1789 case 155: 1790 return sprmTDefTableShd; 1791 case 157: 1792 return sprmTSetBrc; 1793 case 158: 1794 return sprmTInsert; 1795 case 159: 1796 return sprmTDelete; 1797 case 160: 1798 return sprmTDxaCol; 1799 } 1800 break; 1801 } 1802 return sprmNil; 1803 } 1804 1805 WW8TabDesc::WW8TabDesc(SwWW8ImplReader* pIoClass, WW8_CP nStartCp) : 1806 mpOldRedlineStack(0), 1807 pIo(pIoClass), 1808 pFirstBand(0), 1809 pActBand(0), 1810 pTmpPos(0), 1811 pTblNd(0), 1812 pTabLines(0), 1813 pTabLine(0), 1814 pTabBoxes(0), 1815 pTabBox(0), 1816 pMergeGroups(0), 1817 pAktWWCell(0), 1818 nRows(0), 1819 nDefaultSwCols(0), 1820 nBands(0), 1821 nMinLeft(0), 1822 nConvertedLeft(0), 1823 nMaxRight(0), 1824 nSwWidth(0), 1825 nPreferredWidth(0), 1826 nOrgDxaLeft(0), 1827 bOk(true), 1828 bClaimLineFmt(false), 1829 eOri(text::HoriOrientation::NONE), 1830 bIsBiDi(false), 1831 nAktRow(0), 1832 nAktBandRow(0), 1833 nAktCol(0), 1834 nRowsToRepeat(0), 1835 pTable(0), 1836 pParentPos(0), 1837 pFlyFmt(0), 1838 aItemSet(pIo->rDoc.GetAttrPool(),RES_FRMATR_BEGIN,RES_FRMATR_END-1) 1839 { 1840 pIo->bAktAND_fNumberAcross = false; 1841 1842 static const sal_Int16 aOriArr[] = 1843 { 1844 text::HoriOrientation::LEFT, text::HoriOrientation::CENTER, text::HoriOrientation::RIGHT, text::HoriOrientation::CENTER 1845 }; 1846 1847 bool bOldVer = ww::IsSevenMinus(pIo->GetFib().GetFIBVersion()); 1848 WW8_TablePos aTabPos; 1849 1850 WW8PLCFxSave1 aSave; 1851 pIo->pPlcxMan->GetPap()->Save( aSave ); 1852 1853 WW8PLCFx_Cp_FKP* pPap = pIo->pPlcxMan->GetPapPLCF(); 1854 1855 eOri = text::HoriOrientation::LEFT; 1856 1857 WW8TabBandDesc* pNewBand = new WW8TabBandDesc; 1858 1859 wwSprmParser aSprmParser(pIo->GetFib().GetFIBVersion()); 1860 1861 // process pPap until end of table found 1862 do 1863 { 1864 short nTabeDxaNew = SHRT_MAX; 1865 bool bTabRowJustRead = false; 1866 const sal_uInt8* pShadeSprm = 0; 1867 const sal_uInt8* pNewShadeSprm = 0; 1868 WW8_TablePos *pTabPos = 0; 1869 1870 // Suche Ende einer TabZeile 1871 if(!(pIo->SearchRowEnd(pPap, nStartCp, pIo->nInTable))) 1872 { 1873 bOk = false; 1874 break; 1875 } 1876 1877 // Get the SPRM chains: 1878 // first from PAP and then from PCD (of the Piece Table) 1879 WW8PLCFxDesc aDesc; 1880 pPap->GetSprms( &aDesc ); 1881 WW8SprmIter aSprmIter(aDesc.pMemPos, aDesc.nSprmsLen, aSprmParser); 1882 1883 const sal_uInt8* pParams = aSprmIter.GetAktParams(); 1884 for (int nLoop = 0; nLoop < 2; ++nLoop) 1885 { 1886 bool bRepeatedSprm = false; 1887 while (aSprmIter.GetSprms() && 0 != (pParams = aSprmIter.GetAktParams())) 1888 { 1889 sal_uInt16 nId = aSprmIter.GetAktId(); 1890 wwTableSprm eSprm = GetTableSprm(nId, pIo->GetFib().GetFIBVersion()); 1891 switch (eSprm) 1892 { 1893 case sprmTTableWidth: 1894 { 1895 const sal_uInt8 b0 = pParams[0]; 1896 const sal_uInt8 b1 = pParams[1]; 1897 const sal_uInt8 b2 = pParams[2]; 1898 if (b0 == 3) // Twips 1899 nPreferredWidth = b2 * 0x100 + b1; 1900 } 1901 break; 1902 case sprmTTextFlow: 1903 pNewBand->ProcessDirection(pParams); 1904 break; 1905 case sprmTFCantSplit: 1906 pNewBand->bCantSplit = *pParams; 1907 bClaimLineFmt = true; 1908 break; 1909 case sprmTFCantSplit90: 1910 pNewBand->bCantSplit90 = *pParams; 1911 bClaimLineFmt = true; 1912 break; 1913 case sprmTTableBorders: 1914 pNewBand->ProcessSprmTTableBorders(bOldVer, pParams); 1915 break; 1916 case sprmTTableHeader: 1917 if (!bRepeatedSprm) 1918 { 1919 nRowsToRepeat++; 1920 bRepeatedSprm = true; 1921 } 1922 break; 1923 case sprmTJc: 1924 // sprmTJc - Justification Code 1925 if (nRows == 0) 1926 eOri = aOriArr[*pParams & 0x3]; 1927 break; 1928 case sprmTFBiDi: 1929 bIsBiDi = SVBT16ToShort(pParams) ? true : false; 1930 break; 1931 case sprmTDxaGapHalf: 1932 pNewBand->nGapHalf = (sal_Int16)SVBT16ToShort( pParams ); 1933 break; 1934 case sprmTDyaRowHeight: 1935 pNewBand->nLineHeight = (sal_Int16)SVBT16ToShort( pParams ); 1936 bClaimLineFmt = true; 1937 break; 1938 case sprmTDefTable: 1939 pNewBand->ReadDef(bOldVer, pParams); 1940 bTabRowJustRead = true; 1941 break; 1942 case sprmTDefTableShd: 1943 pShadeSprm = pParams; 1944 break; 1945 case sprmTDefTableNewShd: 1946 pNewShadeSprm = pParams; 1947 break; 1948 case sprmTDxaLeft: 1949 // our Writer cannot shift single table lines 1950 // horizontally so we have to find the smallest 1951 // parameter (meaning the left-most position) and then 1952 // shift the whole table to that margin (see below) 1953 { 1954 short nDxaNew = (sal_Int16)SVBT16ToShort( pParams ); 1955 nOrgDxaLeft = nDxaNew; 1956 if( nDxaNew < nTabeDxaNew ) 1957 nTabeDxaNew = nDxaNew; 1958 } 1959 break; 1960 case sprmTSetBrc: 1961 pNewBand->ProcessSprmTSetBRC(bOldVer, pParams); 1962 break; 1963 case sprmTDxaCol: 1964 pNewBand->ProcessSprmTDxaCol(pParams); 1965 break; 1966 case sprmTInsert: 1967 pNewBand->ProcessSprmTInsert(pParams); 1968 break; 1969 case sprmTDelete: 1970 pNewBand->ProcessSprmTDelete(pParams); 1971 break; 1972 case sprmTNewSpacing: 1973 pNewBand->ProcessSpacing(pParams); 1974 break; 1975 case sprmTSpacing: 1976 pNewBand->ProcessSpecificSpacing(pParams); 1977 break; 1978 default: 1979 ; 1980 } 1981 aSprmIter++; 1982 } 1983 1984 if( !nLoop ) 1985 { 1986 pPap->GetPCDSprms( aDesc ); 1987 aSprmIter.SetSprms( aDesc.pMemPos, aDesc.nSprmsLen ); 1988 } 1989 } 1990 1991 // #55171: WW-Tabellen koennen Fly-Wechsel beinhalten daher hier 1992 // Tabellen abbrechen und neu beginnen noch steht *pPap noch vor 1993 // TabRowEnd, daher kann TestApo() mit letztem Parameter false und 1994 // damit wirksam gerufen werden. 1995 1996 if (bTabRowJustRead) 1997 { 1998 if (pShadeSprm) 1999 pNewBand->ReadShd(pShadeSprm); 2000 if (pNewShadeSprm) 2001 pNewBand->ReadNewShd(pNewShadeSprm, bOldVer); 2002 } 2003 2004 if( nTabeDxaNew < SHRT_MAX ) 2005 { 2006 short* pCenter = pNewBand->nCenter; 2007 short firstDxaCenter = *pCenter; 2008 for( int i = 0; i < pNewBand->nWwCols; i++, ++pCenter ) 2009 { 2010 // #i30298# Use sprmTDxaLeft to adjust the left indent 2011 // #i40461# Use dxaGapHalf during calculation 2012 *pCenter += 2013 (nTabeDxaNew - (firstDxaCenter + pNewBand->nGapHalf)); 2014 } 2015 } 2016 2017 if (!pActBand) 2018 pActBand = pFirstBand = pNewBand; 2019 else 2020 { 2021 pActBand->pNextBand = pNewBand; 2022 pActBand = pNewBand; 2023 } 2024 nBands++; 2025 2026 pNewBand = new WW8TabBandDesc; 2027 2028 nRows++; 2029 pActBand->nRows++; 2030 2031 //Seek our pap to its next block of properties 2032 WW8PLCFxDesc aRes; 2033 aRes.pMemPos = 0; 2034 aRes.nStartPos = nStartCp; 2035 2036 if (!(pPap->SeekPos(aRes.nStartPos))) 2037 { 2038 aRes.nEndPos = WW8_CP_MAX; 2039 pPap->SetDirty(true); 2040 } 2041 pPap->GetSprms(&aRes); 2042 pPap->SetDirty(false); 2043 2044 //Are we at the end of available properties 2045 if ( 2046 !pPap->HasFkp() || pPap->Where() == WW8_CP_MAX || 2047 aRes.nStartPos == WW8_CP_MAX 2048 ) 2049 { 2050 bOk = false; 2051 break; 2052 } 2053 2054 //Are we still in a table cell 2055 pParams = HasTabCellSprm(pPap, bOldVer); 2056 const sal_uInt8 *pLevel = pPap->HasSprm(0x6649); 2057 // InTable 2058 if (!pParams || (1 != *pParams) || 2059 (pLevel && (*pLevel <= pIo->nInTable))) 2060 { 2061 break; 2062 } 2063 2064 //Get the end of row new table positioning data 2065 WW8_CP nMyStartCp=nStartCp; 2066 if (pIo->SearchRowEnd(pPap, nMyStartCp, pIo->nInTable)) 2067 if (SwWW8ImplReader::ParseTabPos(&aTabPos, pPap)) 2068 pTabPos = &aTabPos; 2069 2070 //Move back to this cell 2071 aRes.pMemPos = 0; 2072 aRes.nStartPos = nStartCp; 2073 2074 // #114237 PlcxMan currently points too far ahead so we need to bring 2075 // it back to where we are trying to make a table 2076 pIo->pPlcxMan->GetPap()->nOrigStartPos = aRes.nStartPos; 2077 if (!(pPap->SeekPos(aRes.nStartPos))) 2078 { 2079 aRes.nEndPos = WW8_CP_MAX; 2080 pPap->SetDirty(true); 2081 } 2082 pPap->GetSprms(&aRes); 2083 pPap->SetDirty(false); 2084 2085 //Does this row match up with the last row closely enough to be 2086 //considered part of the same table 2087 ApoTestResults aApo = pIo->TestApo(pIo->nInTable + 1, false, pTabPos); 2088 2089 /* 2090 ##513##, #79474# If this is not sufficent, then we should look at 2091 sprmPD{y|x}aAbs as our indicator that the following set of rows is not 2092 part of this table, but instead is an absolutely positioned table 2093 outside of this one 2094 */ 2095 if (aApo.mbStopApo) 2096 break; 2097 if (aApo.mbStartApo) 2098 { 2099 //if there really is a fly here, and not a "null" fly then break. 2100 WW8FlyPara *pNewFly = pIo->ConstructApo(aApo, pTabPos); 2101 if (pNewFly) 2102 delete pNewFly; 2103 else 2104 break; 2105 } 2106 2107 nStartCp = aRes.nEndPos; 2108 } 2109 while( 1 ); 2110 2111 if( bOk ) 2112 { 2113 if( pActBand->nRows > 1 ) 2114 { 2115 // Letztes Band hat mehr als 1 Zeile 2116 delete pNewBand; 2117 pNewBand = new WW8TabBandDesc( *pActBand ); // neues machen 2118 pActBand->nRows--; // wegen Sonderbehandlung Raender-Defaults 2119 pNewBand->nRows = 1; 2120 pActBand->pNextBand = pNewBand; // am Ende einschleifen 2121 nBands++; 2122 pNewBand = 0; // nicht loeschen 2123 } 2124 CalcDefaults(); 2125 } 2126 delete pNewBand; 2127 2128 pIo->pPlcxMan->GetPap()->Restore( aSave ); 2129 } 2130 2131 WW8TabDesc::~WW8TabDesc() 2132 { 2133 WW8TabBandDesc* pR = pFirstBand; 2134 while(pR) 2135 { 2136 WW8TabBandDesc* pR2 = pR->pNextBand; 2137 delete pR; 2138 pR = pR2; 2139 } 2140 2141 delete pParentPos; 2142 delete pMergeGroups; 2143 } 2144 2145 void WW8TabDesc::CalcDefaults() 2146 { 2147 short nMinCols = SHRT_MAX; 2148 WW8TabBandDesc* pR; 2149 2150 nMinLeft = SHRT_MAX; 2151 nMaxRight = SHRT_MIN; 2152 2153 /* 2154 #101175# 2155 If we are an honestly inline centered table, then the normal rules of 2156 engagement for left and right margins do not apply. The multiple rows are 2157 centered regardless of the actual placement of rows, so we cannot have 2158 mismatched rows as is possible in other configurations. 2159 2160 e.g. change the example bugdoc in word from text wrapping of none (inline) 2161 to around (in frame (bApo)) and the table splits into two very disjoint 2162 rows as the beginning point of each row are very different 2163 */ 2164 if ((!pIo->InLocalApo()) && (eOri == text::HoriOrientation::CENTER)) 2165 { 2166 for (pR = pFirstBand; pR; pR = pR->pNextBand) 2167 for( short i = pR->nWwCols; i >= 0; --i) 2168 pR->nCenter[i] = pR->nCenter[i] - pR->nCenter[0]; 2169 } 2170 2171 // 1. Durchlauf: aeusserste L- und R-Grenzen finden 2172 for( pR = pFirstBand; pR; pR = pR->pNextBand ) 2173 { 2174 if( pR->nCenter[0] < nMinLeft ) 2175 nMinLeft = pR->nCenter[0]; 2176 2177 for( short i = 0; i < pR->nWwCols; i++ ) 2178 { 2179 /* 2180 #74387# If the margins are so large as to make the displayable 2181 area inside them smaller than the minimum allowed then adjust the 2182 width to fit. But only do it if the two cells are not the exact 2183 same value, if they are then the cell does not really exist and will 2184 be blended together into the same cell through the use of the 2185 nTrans(late) array. 2186 #i28333# If the nGapHalf is greater than the cell width best to ignore it 2187 */ 2188 int nCellWidth = pR->nCenter[i+1] - pR->nCenter[i]; 2189 if (nCellWidth && ((nCellWidth - pR->nGapHalf*2) < MINLAY) && pR->nGapHalf < nCellWidth) 2190 { 2191 pR->nCenter[i+1] = pR->nCenter[i]+MINLAY+pR->nGapHalf * 2; 2192 } 2193 } 2194 2195 if( pR->nCenter[pR->nWwCols] > nMaxRight ) 2196 nMaxRight = pR->nCenter[pR->nWwCols]; 2197 } 2198 nSwWidth = nMaxRight - nMinLeft; 2199 2200 // #109830# If the table is right aligned we need to align all rows to the 2201 // row that has the furthest right point 2202 2203 if(eOri == text::HoriOrientation::RIGHT) 2204 { 2205 for( pR = pFirstBand; pR; pR = pR->pNextBand ) 2206 { 2207 int adjust = nMaxRight - pR->nCenter[pR->nWwCols]; 2208 for( short i = 0; i < pR->nWwCols + 1; i++ ) 2209 { 2210 pR->nCenter[i] = static_cast< short >(pR->nCenter[i] + adjust); 2211 } 2212 2213 } 2214 } 2215 2216 // 2. Durchlauf: Zahl der Writer-Spalten feststellen Die Zahl der Writer 2217 // Spalten kann um bis zu 2 hoeher sein als im WW, da der SW im Gegensatz 2218 // zu WW keine ausgefransten linken und rechten Raender kann und diese 2219 // durch leere Boxen aufgefuellt werden. Durch nichtexistente Zellen 2220 // koennen auch Zellen wegfallen 2221 2222 // 3. Durchlauf: Wo noetig die Umrandungen durch die Defaults ersetzen 2223 nConvertedLeft = nMinLeft; 2224 2225 short nLeftMaxThickness = 0, nRightMaxThickness=0; 2226 for( pR = pFirstBand ; pR; pR = pR->pNextBand ) 2227 { 2228 if( !pR->pTCs ) 2229 { 2230 pR->pTCs = new WW8_TCell[ pR->nWwCols ]; 2231 memset( pR->pTCs, 0, pR->nWwCols * sizeof( WW8_TCell ) ); 2232 } 2233 for (int k = 0; k < pR->nWwCols; ++k) 2234 { 2235 WW8_TCell* pT = &pR->pTCs[k]; 2236 int i, j; 2237 for( i = 0; i < 4; i ++ ) 2238 { 2239 if (pT->rgbrc[i].IsZeroed(pIo->bVer67)) 2240 { 2241 // if shadow is set, its invalid 2242 j = i; 2243 switch( i ) 2244 { 2245 case 0: 2246 // Aussen oben / Innen waagerecht 2247 j = (pR == pFirstBand) ? 0 : 4; 2248 break; 2249 case 1: 2250 // Aussen links / Innen senkrecht 2251 j = k ? 5 : 1; 2252 break; 2253 case 2: 2254 // Aussen unten / Innen waagerecht 2255 j = pR->pNextBand ? 4 : 2; 2256 break; 2257 case 3: 2258 // Aussen rechts/ Innen senkrecht 2259 j = (k == pR->nWwCols - 1) ? 3 : 5; 2260 break; 2261 } 2262 // mangel mit Defaults ueber 2263 pT->rgbrc[i] = pR->aDefBrcs[j]; 2264 } 2265 } 2266 } 2267 /* 2268 Similiar to graphics and other elements word does not totally 2269 factor the width of the border into its calculations of size, we 2270 do so we must adjust out widths and other dimensions to fit. It 2271 appears that what occurs is that the last cell's right margin if 2272 the margin width that is not calculated into winwords table 2273 dimensions, so in that case increase the table to include the 2274 extra width of the right margin. 2275 */ 2276 if ( pIo->bVer67 ? 2277 !(SVBT16ToShort(pR->pTCs[pR->nWwCols-1].rgbrc[3].aBits1) & 0x20) 2278 : !(SVBT16ToShort(pR->pTCs[pR->nWwCols-1].rgbrc[3].aBits2) & 0x2000)) 2279 { 2280 short nThickness = pR->pTCs[pR->nWwCols-1].rgbrc[3]. 2281 DetermineBorderProperties(pIo->bVer67); 2282 pR->nCenter[pR->nWwCols] = pR->nCenter[pR->nWwCols] + nThickness; 2283 if (nThickness > nRightMaxThickness) 2284 nRightMaxThickness = nThickness; 2285 } 2286 2287 /* 2288 The left space of the table is in nMinLeft, but again this 2289 does not consider the margin thickness to its left in the 2290 placement value, so get the thickness of the left border, 2291 half is placed to the left of the nominal left side, and 2292 half to the right. 2293 */ 2294 if ( pIo->bVer67 ? 2295 !(SVBT16ToShort(pR->pTCs[0].rgbrc[1].aBits1) & 0x20) 2296 : !(SVBT16ToShort(pR->pTCs[0].rgbrc[1].aBits2) & 0x2000)) 2297 { 2298 short nThickness = pR->pTCs[0].rgbrc[1]. 2299 DetermineBorderProperties(pIo->bVer67); 2300 if (nThickness > nLeftMaxThickness) 2301 nLeftMaxThickness = nThickness; 2302 } 2303 } 2304 nSwWidth = nSwWidth + nRightMaxThickness; 2305 nMaxRight = nMaxRight + nRightMaxThickness; 2306 nConvertedLeft = nMinLeft-(nLeftMaxThickness/2); 2307 2308 for( pR = pFirstBand; pR; pR = pR->pNextBand ) 2309 { 2310 pR->nSwCols = pR->nWwCols; 2311 pR->bLEmptyCol = pR->nCenter[0] - nMinLeft >= MINLAY; 2312 pR->bREmptyCol = (nMaxRight - pR->nCenter[pR->nWwCols] - nRightMaxThickness) >= MINLAY; 2313 2314 short nAddCols = pR->bLEmptyCol + pR->bREmptyCol; 2315 sal_uInt16 i; 2316 sal_uInt16 j = ( pR->bLEmptyCol ) ? 1 : 0; 2317 for (i = 0; i < pR->nWwCols; ++i) 2318 { 2319 pR->nTransCell[i] = (sal_Int8)j; 2320 if ( pR->nCenter[i] < pR->nCenter[i+1] ) 2321 { 2322 pR->bExist[i] = true; 2323 j++; 2324 } 2325 else 2326 { 2327 pR->bExist[i] = false; 2328 nAddCols--; 2329 } 2330 } 2331 2332 ASSERT(i,"no columns in row ?"); 2333 2334 /* 2335 #96345# 2336 If the last cell was "false" then there is no valid cell following it, 2337 so the default mapping forward wont't work. So map it (and 2338 contigious invalid cells backwards to the last valid cell instead. 2339 */ 2340 if (i && pR->bExist[i-1] == false) 2341 { 2342 sal_uInt16 k=i-1; 2343 while (k && pR->bExist[k] == false) 2344 k--; 2345 for (sal_uInt16 n=k+1;n<i;n++) 2346 pR->nTransCell[n] = pR->nTransCell[k]; 2347 } 2348 2349 pR->nTransCell[i++] = (sal_Int8)(j++); // Wird u.a. wegen bREmptyCol um 2350 pR->nTransCell[i] = (sal_Int8)j; // max. 2 ueberindiziert 2351 2352 pR->nSwCols = pR->nSwCols + nAddCols; 2353 if( pR->nSwCols < nMinCols ) 2354 nMinCols = pR->nSwCols; 2355 } 2356 2357 /* 2358 #i9718# 2359 Find the largest of the borders on cells that adjoin top bottom and remove 2360 the val from the top and put in on the bottom cell. I can't seem to make 2361 disjoint upper and lowers to see what happens there. 2362 */ 2363 2364 /* #i29550# FME 2004-06-02 Removed this code because of the implementation 2365 of the collapsing table borders model. So this should not be necessary 2366 anymore. */ 2367 2368 /* for (pR = pFirstBand; pR; pR = pR->pNextBand) 2369 { 2370 WW8TabBandDesc *pNext = pR->pNextBand; 2371 if (!pNext) 2372 break; 2373 2374 for (int k = 0; k < pR->nWwCols; ++k) 2375 { 2376 WW8_BRC &rAbove = pR->pTCs[k].rgbrc[WW8_BOT]; 2377 short nAboveThick = rAbove.IsEmpty(pIo->bVer67) ? 2378 0 : rAbove.DetermineBorderProperties(pIo->bVer67); 2379 short nUpperLeft = pR->nCenter[k]; 2380 short nUpperRight = pR->nCenter[k+1]; 2381 2382 for (int l = 0; l < pNext->nWwCols; ++l) 2383 { 2384 short nLowerLeft = pNext->nCenter[l]; 2385 short nLowerRight = pNext->nCenter[l+1]; 2386 2387 if ((nLowerLeft < nUpperLeft) || (nLowerRight > nUpperRight)) 2388 continue; 2389 2390 WW8_BRC &rBelow = pNext->pTCs[l].rgbrc[WW8_TOP]; 2391 short nBelowThick = rBelow.IsEmpty(pIo->bVer67) ? 2392 0 : rBelow.DetermineBorderProperties(pIo->bVer67); 2393 if (nAboveThick > nBelowThick) 2394 rBelow = rAbove; 2395 } 2396 2397 rAbove = WW8_BRC(); 2398 } 2399 } */ 2400 2401 if ((nMinLeft && !bIsBiDi && text::HoriOrientation::LEFT == eOri) || 2402 (nMinLeft != -108 && bIsBiDi && text::HoriOrientation::RIGHT == eOri)) // Word sets the first nCenter value to -108 when no indent is used 2403 eOri = text::HoriOrientation::LEFT_AND_WIDTH; // absolutely positioned 2404 2405 nDefaultSwCols = nMinCols; // da Zellen einfuegen billiger ist als Mergen 2406 if( nDefaultSwCols == 0 ) 2407 bOk = false; 2408 pActBand = pFirstBand; 2409 nAktBandRow = 0; 2410 ASSERT( pActBand, "pActBand ist 0" ); 2411 } 2412 2413 void WW8TabDesc::SetSizePosition(SwFrmFmt* pFrmFmt) 2414 { 2415 SwFrmFmt* pApply = pFrmFmt; 2416 if (!pApply ) 2417 pApply = pTable->GetFrmFmt(); 2418 ASSERT(pApply,"No frame"); 2419 pApply->SetFmtAttr(aItemSet); 2420 if (pFrmFmt) 2421 { 2422 SwFmtFrmSize aSize = pFrmFmt->GetFrmSize(); 2423 aSize.SetHeightSizeType(ATT_MIN_SIZE); 2424 aSize.SetHeight(MINLAY); 2425 pFrmFmt->SetFmtAttr(aSize); 2426 pTable->GetFrmFmt()->SetFmtAttr(SwFmtHoriOrient(0,text::HoriOrientation::FULL)); 2427 } 2428 } 2429 2430 void wwSectionManager::PrependedInlineNode(const SwPosition &rPos, 2431 const SwNode &rNode) 2432 { 2433 ASSERT(!maSegments.empty(), 2434 "should not be possible, must be at least one segment"); 2435 if ((!maSegments.empty()) && (maSegments.back().maStart == rPos.nNode)) 2436 maSegments.back().maStart = SwNodeIndex(rNode); 2437 } 2438 2439 void WW8TabDesc::CreateSwTable() 2440 { 2441 ::SetProgressState(pIo->nProgress, pIo->mpDocShell); // Update 2442 2443 // if there is already some content on the Node append new node to ensure 2444 // that this content remains ABOVE the table 2445 SwPosition* pPoint = pIo->pPaM->GetPoint(); 2446 bool bInsNode = pPoint->nContent.GetIndex() ? true : false; 2447 bool bSetMinHeight = false; 2448 2449 /* 2450 #i8062# 2451 Set fly anchor to its anchor pos, so that if a table starts immediately 2452 at this position a new node will be inserted before inserting the table. 2453 */ 2454 if (!bInsNode && pIo->pFmtOfJustInsertedApo) 2455 { 2456 const SwPosition* pAPos = 2457 pIo->pFmtOfJustInsertedApo->GetAnchor().GetCntntAnchor(); 2458 if (pAPos && &pAPos->nNode.GetNode() == &pPoint->nNode.GetNode()) 2459 { 2460 bInsNode = true; 2461 bSetMinHeight = true; 2462 2463 SwFmtSurround aSur(pIo->pFmtOfJustInsertedApo->GetSurround()); 2464 aSur.SetAnchorOnly(true); 2465 pIo->pFmtOfJustInsertedApo->SetFmtAttr(aSur); 2466 } 2467 } 2468 2469 if (bSetMinHeight == true) 2470 { 2471 // minimize Fontsize to minimize height growth of the header/footer 2472 // set font size to 1 point to minimize y-growth of Hd/Ft 2473 SvxFontHeightItem aSz(20, 100, RES_CHRATR_FONTSIZE); 2474 pIo->NewAttr( aSz ); 2475 pIo->pCtrlStck->SetAttr(*pPoint, RES_CHRATR_FONTSIZE); 2476 } 2477 2478 if (bInsNode) 2479 pIo->AppendTxtNode(*pPoint); 2480 2481 pTmpPos = new SwPosition( *pIo->pPaM->GetPoint() ); 2482 2483 // Die Tabelle ist beim Einfuegen noch recht klein: Zahl der Spalten ist 2484 // die kleinste Spaltenanzahl des Originals, da Spalten einfuegen 2485 // schneller geht als Loeschen Zahl der Zeilen ist die Zahl der Baender, 2486 // da sich die (identischen) Zeilen eines Bandes prima duplizieren lassen 2487 pTable = pIo->rDoc.InsertTable( 2488 SwInsertTableOptions( tabopts::HEADLINE_NO_BORDER, 0 ), 2489 *pTmpPos, nBands, nDefaultSwCols, eOri, 0, 0, sal_False, sal_True ); 2490 2491 ASSERT(pTable && pTable->GetFrmFmt(), "insert table failed"); 2492 if (!pTable || !pTable->GetFrmFmt()) 2493 return; 2494 2495 SwTableNode* pTableNode = pTable->GetTableNode(); 2496 ASSERT(pTableNode, "no table node!"); 2497 if (pTableNode) 2498 { 2499 pIo->maSectionManager.PrependedInlineNode(*pIo->pPaM->GetPoint(), 2500 *pTableNode); 2501 } 2502 2503 // Abfrage, ob im Node, in dem die Tabelle eingefuegt werden soll, bereits 2504 // ein Pagedesc steht. Dann wuerde der PageDesc in die naechste Zeile 2505 // hinter der Tabelle rutschen, wo er nichts zu suchen hat. -> loeschen 2506 // und spaeter an das Tabellenformat setzen 2507 if (SwTxtNode *const pNd = pTmpPos->nNode.GetNode().GetTxtNode()) 2508 { 2509 if (const SfxItemSet* pSet = pNd->GetpSwAttrSet()) 2510 { 2511 SfxPoolItem *pSetAttr = 0; 2512 const SfxPoolItem* pItem; 2513 if (SFX_ITEM_SET == pSet->GetItemState(RES_BREAK, false, &pItem)) 2514 { 2515 pSetAttr = new SvxFmtBreakItem( *(SvxFmtBreakItem*)pItem ); 2516 pNd->ResetAttr( RES_BREAK ); 2517 } 2518 2519 // evtl den PageDesc/Break jetzt an der Tabelle setzen 2520 if (pSetAttr) 2521 { 2522 aItemSet.Put(*pSetAttr); 2523 delete pSetAttr; 2524 } 2525 } 2526 } 2527 2528 // Gesamtbreite der Tabelle 2529 if( nMaxRight - nMinLeft > MINLAY * nDefaultSwCols ) 2530 { 2531 pTable->GetFrmFmt()->SetFmtAttr(SwFmtFrmSize(ATT_FIX_SIZE, nSwWidth)); 2532 aItemSet.Put(SwFmtFrmSize(ATT_FIX_SIZE, nSwWidth)); 2533 } 2534 2535 SvxFrameDirectionItem aDirection( 2536 bIsBiDi ? FRMDIR_HORI_RIGHT_TOP : FRMDIR_HORI_LEFT_TOP, RES_FRAMEDIR ); 2537 pTable->GetFrmFmt()->SetFmtAttr(aDirection); 2538 2539 if (text::HoriOrientation::LEFT_AND_WIDTH == eOri) 2540 { 2541 if (!pIo->nInTable && pIo->InLocalApo() && pIo->pSFlyPara->pFlyFmt && 2542 GetMinLeft()) 2543 { 2544 //If we are inside a frame and we have a border, the frames 2545 //placement does not consider the tables border, which word 2546 //displays outside the frame, so adjust here. 2547 SwFmtHoriOrient aHori(pIo->pSFlyPara->pFlyFmt->GetHoriOrient()); 2548 sal_Int16 eHori = aHori.GetHoriOrient(); 2549 if ((eHori == text::HoriOrientation::NONE) || (eHori == text::HoriOrientation::LEFT) || 2550 (eHori == text::HoriOrientation::LEFT_AND_WIDTH)) 2551 { 2552 //With multiple table, use last table settings. Perhaps 2553 //the maximum is what word does ? 2554 aHori.SetPos(pIo->pSFlyPara->nXPos + GetMinLeft()); 2555 aHori.SetHoriOrient(text::HoriOrientation::NONE); 2556 pIo->pSFlyPara->pFlyFmt->SetFmtAttr(aHori); 2557 } 2558 } 2559 else 2560 { 2561 //If bApo is set, then this table is being placed in a floating 2562 //frame, and the frame matches the left and right *lines* of the 2563 //table, so the space to the left of the table isn't to be used 2564 //inside the frame, in word the dialog involved greys out the 2565 //ability to set the margin. 2566 SvxLRSpaceItem aL( RES_LR_SPACE ); 2567 // set right to original DxaLeft (i28656) 2568 2569 long nLeft = 0; 2570 if (!bIsBiDi) 2571 nLeft = GetMinLeft(); 2572 else 2573 { 2574 if (nPreferredWidth) 2575 { 2576 nLeft = pIo->maSectionManager.GetTextAreaWidth(); 2577 nLeft = nLeft - nPreferredWidth - nOrgDxaLeft; 2578 } 2579 else 2580 nLeft = -GetMinLeft(); 2581 } 2582 2583 aL.SetLeft(nLeft); 2584 2585 aItemSet.Put(aL); 2586 } 2587 } 2588 2589 mpOldRedlineStack = pIo->mpRedlineStack; 2590 pIo->mpRedlineStack = new sw::util::RedlineStack(pIo->rDoc); 2591 } 2592 2593 void WW8TabDesc::UseSwTable() 2594 { 2595 // globale Varis initialisieren 2596 pTabLines = &pTable->GetTabLines(); 2597 nAktRow = nAktCol = nAktBandRow = 0; 2598 2599 pTblNd = (SwTableNode*)(*pTabLines)[0]->GetTabBoxes()[0]-> 2600 GetSttNd()->FindTableNode(); 2601 ASSERT( pTblNd, "wo ist mein TabellenNode" ); 2602 2603 // --> mloiseleur 2007-10-10 #i69519# Restrict rows to repeat to a decent value 2604 if ( nRowsToRepeat == static_cast<sal_uInt16>(nRows) ) 2605 nRowsToRepeat = 1; 2606 // <-- 2607 2608 pTblNd->GetTable().SetRowsToRepeat( nRowsToRepeat ); 2609 // ggfs. Zusatz-Zellen einfuegen u.dgl. 2610 AdjustNewBand(); 2611 2612 WW8DupProperties aDup(pIo->rDoc,pIo->pCtrlStck); 2613 pIo->pCtrlStck->SetAttr(*pIo->pPaM->GetPoint(), 0, false); 2614 2615 // jetzt den PaM korrekt setzen und ggfs. erste Mergegruppe vorbereiten... 2616 SetPamInCell(nAktCol, true); 2617 aDup.Insert(*pIo->pPaM->GetPoint()); 2618 2619 pIo->bWasTabRowEnd = false; 2620 pIo->bWasTabCellEnd = false; 2621 } 2622 2623 void WW8TabDesc::MergeCells() 2624 { 2625 short nRow; 2626 2627 for (pActBand=pFirstBand, nRow=0; pActBand; pActBand=pActBand->pNextBand) 2628 { 2629 // 2630 // ggfs. aktuelle Box in entsprechende Merge-Gruppe eintragen 2631 // 2632 if( pActBand->pTCs ) 2633 { 2634 for( short j = 0; j < pActBand->nRows; j++, nRow++ ) 2635 for( short i = 0; i < pActBand->nWwCols; i++ ) 2636 { 2637 WW8SelBoxInfoPtr pActMGroup = 0; 2638 // 2639 // ggfs. eine neue Merge-Gruppe beginnen 2640 // 2641 ASSERT(nRow < pTabLines->Count(), 2642 "Too few lines, table ended early"); 2643 if (nRow >= pTabLines->Count()) 2644 return; 2645 pTabLine = (*pTabLines)[ nRow ]; 2646 pTabBoxes = &pTabLine->GetTabBoxes(); 2647 2648 sal_uInt16 nCol = pActBand->nTransCell[ i ]; 2649 if (!pActBand->bExist[i]) //#113434# 2650 continue; 2651 ASSERT(nCol < pTabBoxes->Count(), 2652 "Too few columns, table ended early"); 2653 if (nCol >= pTabBoxes->Count()) 2654 return; 2655 pTabBox = (*pTabBoxes)[nCol]; 2656 WW8_TCell& rCell = pActBand->pTCs[ i ]; 2657 // ist dies die obere, linke-Zelle einer Merge-Gruppe ? 2658 2659 bool bMerge = false; 2660 if ( rCell.bVertRestart && !rCell.bMerged ) 2661 bMerge = true; 2662 else if (rCell.bFirstMerged && pActBand->bExist[i]) 2663 { 2664 //#91211# Some tests to avoid merging cells 2665 //which previously were declared invalid because 2666 //of sharing the exact same dimensions as their 2667 //previous cell 2668 2669 //If theres anything underneath/above we're ok. 2670 if (rCell.bVertMerge || rCell.bVertRestart) 2671 bMerge = true; 2672 else 2673 { 2674 //If its a hori merge only, and the only things in 2675 //it are invalid cells then its already taken care 2676 //of, so don't merge. 2677 for (sal_uInt16 i2 = i+1; i2 < pActBand->nWwCols; i2++ ) 2678 if (pActBand->pTCs[ i2 ].bMerged && 2679 !pActBand->pTCs[ i2 ].bFirstMerged ) 2680 { 2681 if (pActBand->bExist[i2]) 2682 { 2683 bMerge = true; 2684 break; 2685 } 2686 } 2687 else 2688 break; 2689 } 2690 } 2691 2692 2693 if (bMerge) 2694 { 2695 short nX1 = pActBand->nCenter[ i ]; 2696 short nWidth = pActBand->nWidth[ i ]; 2697 2698 // 0. falls noetig das Array fuer die Merge-Gruppen 2699 // anlegen 2700 if( !pMergeGroups ) 2701 pMergeGroups = new WW8MergeGroups; 2702 2703 // 2. aktuelle Merge-Gruppe anlegen 2704 pActMGroup = new WW8SelBoxInfo( nX1, nWidth ); 2705 2706 // --> OD 2005-02-04 #118544# - determine size of new 2707 // merge group before inserted the new merge group. 2708 // Needed to correctly locked previously created merge groups. 2709 // Gesamtbreite ermitteln und zuweisen 2710 short nSizCell = pActBand->nWidth[ i ]; 2711 for (sal_uInt16 i2 = i+1; i2 < pActBand->nWwCols; i2++ ) 2712 if (pActBand->pTCs[ i2 ].bMerged && 2713 !pActBand->pTCs[ i2 ].bFirstMerged ) 2714 { 2715 nSizCell = nSizCell + pActBand->nWidth[ i2 ]; 2716 } 2717 else 2718 break; 2719 pActMGroup->nGroupWidth = nSizCell; 2720 // <-- 2721 2722 // --> OD 2005-02-03 #118544# - locked previously 2723 // created merge groups, after determining the size 2724 // for the new merge group. 2725 // 1. ggfs. alte Mergegruppe(n) schliessen, die 2726 // den von unserer neuen Gruppe betroffenen 2727 // X-Bereich ueberdecken 2728 short nMGrIdx; 2729 while ( FindMergeGroup( nX1, pActMGroup->nGroupWidth, 2730 false, nMGrIdx ) ) 2731 { 2732 (*pMergeGroups)[ nMGrIdx ]->bGroupLocked = true; 2733 } 2734 // <-- 2735 2736 // 3. und in Gruppen-Array eintragen 2737 pMergeGroups->Insert(pActMGroup, pMergeGroups->Count()); 2738 } 2739 2740 // ggfs. akt. Box zu einer Merge-Gruppe hinzufuegen (dies 2741 // kann eine soeben angelegte, oder eine andere Gruppe 2742 // sein) 2743 UpdateTableMergeGroup( rCell, pActMGroup, pTabBox, i ); 2744 } 2745 } 2746 } 2747 } 2748 2749 //There is a limbo area in word at the end of the row marker 2750 //where properties can live in word, there is no location in 2751 //writer equivalent, so try and park the cursor in the best 2752 //match, see #i23022#/#i18644# 2753 void WW8TabDesc::ParkPaM() 2754 { 2755 SwTableBox *pTabBox2 = 0; 2756 short nRow = nAktRow + 1; 2757 if (nRow < pTabLines->Count()) 2758 { 2759 if (SwTableLine *pLine = (*pTabLines)[nRow]) 2760 { 2761 SwTableBoxes &rBoxes = pLine->GetTabBoxes(); 2762 pTabBox2 = rBoxes.Count() ? rBoxes[0] : 0; 2763 } 2764 } 2765 2766 if (!pTabBox2 || !pTabBox2->GetSttNd()) 2767 { 2768 MoveOutsideTable(); 2769 return; 2770 } 2771 2772 if (pIo->pPaM->GetPoint()->nNode != pTabBox2->GetSttIdx() + 1) 2773 { 2774 pIo->pPaM->GetPoint()->nNode = pTabBox2->GetSttIdx() + 1; 2775 pIo->pPaM->GetPoint()->nContent.Assign(pIo->pPaM->GetCntntNode(), 0); 2776 pIo->rDoc.SetTxtFmtColl(*pIo->pPaM, (SwTxtFmtColl*)pIo->pDfltTxtFmtColl); 2777 } 2778 } 2779 2780 void WW8TabDesc::MoveOutsideTable() 2781 { 2782 ASSERT(pTmpPos && pIo, "I've forgotten where the table is anchored"); 2783 if (pTmpPos && pIo) 2784 *pIo->pPaM->GetPoint() = *pTmpPos; 2785 } 2786 2787 void WW8TabDesc::FinishSwTable() 2788 { 2789 pIo->mpRedlineStack->closeall(*pIo->pPaM->GetPoint()); 2790 delete pIo->mpRedlineStack; 2791 pIo->mpRedlineStack = mpOldRedlineStack; 2792 mpOldRedlineStack = 0; 2793 2794 WW8DupProperties aDup(pIo->rDoc,pIo->pCtrlStck); 2795 pIo->pCtrlStck->SetAttr( *pIo->pPaM->GetPoint(), 0, false); 2796 2797 MoveOutsideTable(); 2798 delete pTmpPos, pTmpPos = 0; 2799 2800 aDup.Insert(*pIo->pPaM->GetPoint()); 2801 2802 pIo->bWasTabRowEnd = false; 2803 pIo->bWasTabCellEnd = false; 2804 2805 pIo->maInsertedTables.InsertTable(*pTblNd, *pIo->pPaM); 2806 2807 MergeCells(); 2808 2809 // falls noetig, zu mergende Zellen gruppenweise zusammenfassen 2810 if( pMergeGroups ) 2811 { 2812 // bearbeite alle Merge-Gruppen nacheinander 2813 WW8SelBoxInfo* pActMGroup; 2814 sal_uInt16 nActBoxCount; 2815 2816 for (sal_uInt16 iGr = 0; iGr < pMergeGroups->Count(); ++iGr) 2817 { 2818 pActMGroup = (*pMergeGroups)[ iGr ]; 2819 nActBoxCount = pActMGroup->Count(); 2820 2821 if( ( 1 < nActBoxCount ) && pActMGroup && (*pActMGroup)[ 0 ] ) 2822 { 2823 const sal_uInt16 nRowSpan = pActMGroup->Count(); 2824 for (sal_uInt16 n = 0; n < nRowSpan; ++n) 2825 { 2826 SwTableBox* pCurrentBox = (*pActMGroup)[n]; 2827 const long nRowSpanSet = n == 0 ? 2828 nRowSpan : 2829 ((-1) * (nRowSpan - n)); 2830 pCurrentBox->setRowSpan( nRowSpanSet ); 2831 } 2832 } 2833 } 2834 pIo->pFmtOfJustInsertedApo = 0; 2835 DELETEZ( pMergeGroups ); 2836 } 2837 } 2838 2839 2840 // durchsucht pMergeGroups, meldet Index der ersten, passenden Gruppe bzw. -1 2841 // 2842 // Parameter: nXcenter = Mittenposition der anfragenden Box 2843 // nWidth = Breite der anfragenden Box 2844 // bExact = Flag, ob Box in dieser Gruppe passen muss, 2845 // oder diese nur zu tangieren braucht 2846 // 2847 bool WW8TabDesc::FindMergeGroup(short nX1, short nWidth, bool bExact, 2848 short& nMGrIdx) 2849 { 2850 nMGrIdx = -1; 2851 if( pMergeGroups ) 2852 { 2853 // noch als gueltig angesehener Bereich in der Naehe der Grenzen 2854 const short nToleranz = 4; 2855 // die aktuell untersuchte Gruppe 2856 WW8SelBoxInfoPtr pActGroup; 2857 // Boxgrenzen 2858 short nX2 = nX1 + nWidth; 2859 // ungefaehre Gruppengrenzen 2860 short nGrX1; 2861 short nGrX2; 2862 2863 // --> OD 2005-02-04 #118544# - improvement: search backwards 2864 //for ( sal_uInt16 iGr = 0; iGr < pMergeGroups->Count(); iGr++ ) 2865 for ( short iGr = pMergeGroups->Count() - 1; iGr >= 0; --iGr ) 2866 { 2867 // die aktuell untersuchte Gruppe 2868 pActGroup = (*pMergeGroups)[ iGr ]; 2869 if (!pActGroup->bGroupLocked) 2870 { 2871 // ungefaehre Gruppengrenzen mit Toleranz nach *aussen* hin 2872 nGrX1 = pActGroup->nGroupXStart - nToleranz; 2873 nGrX2 = pActGroup->nGroupXStart 2874 +pActGroup->nGroupWidth + nToleranz; 2875 // 2876 // Falls Box reinpasst, melde auf jeden Fall den Erfolg 2877 // 2878 if( ( nX1 > nGrX1 ) && ( nX2 < nGrX2 ) ) 2879 { 2880 nMGrIdx = iGr; break; 2881 } 2882 // 2883 // hat die Box Bereiche mit der Gruppe gemeinsam? 2884 // 2885 if( !bExact ) 2886 { 2887 // melde Erfolg, wenn nX1 *oder* nX2 innerhalb der Gruppe liegen 2888 if( ( ( nX1 > nGrX1 ) 2889 && ( nX1 < nGrX2 - 2*nToleranz ) ) 2890 || ( ( nX2 > nGrX1 + 2*nToleranz ) 2891 && ( nX2 < nGrX2 ) ) 2892 // oder nX1 und nX2 die Gruppe umfassen 2893 || ( ( nX1 <=nGrX1 ) 2894 && ( nX2 >=nGrX2 ) ) ) 2895 { 2896 nMGrIdx = iGr; break; 2897 } 2898 } 2899 } 2900 } 2901 } 2902 return ( -1 < nMGrIdx ); 2903 } 2904 2905 bool WW8TabDesc::IsValidCell(short nCol) const 2906 { 2907 return pActBand->bExist[nCol] && (sal_uInt16)nAktRow < pTabLines->Count(); 2908 } 2909 2910 bool WW8TabDesc::InFirstParaInCell() const 2911 { 2912 //e.g. #i19718# 2913 if (!pTabBox || !pTabBox->GetSttNd()) 2914 { 2915 ASSERT(false, "Problem with table"); 2916 return false; 2917 } 2918 2919 if (!IsValidCell(GetAktCol())) 2920 return false; 2921 2922 if (pIo->pPaM->GetPoint()->nNode == pTabBox->GetSttIdx() + 1) 2923 return true; 2924 2925 return false; 2926 } 2927 2928 void WW8TabDesc::StartMiserableHackForUnsupportedDirection(short nWwCol) 2929 { 2930 ASSERT(pActBand, "Impossible"); 2931 if (pActBand && pActBand->maDirections[nWwCol] == 3) 2932 { 2933 pIo->pCtrlStck->NewAttr(*pIo->pPaM->GetPoint(), 2934 SvxCharRotateItem(900, false, RES_CHRATR_ROTATE)); 2935 } 2936 } 2937 2938 void WW8TabDesc::EndMiserableHackForUnsupportedDirection(short nWwCol) 2939 { 2940 ASSERT(pActBand, "Impossible"); 2941 if (pActBand && pActBand->maDirections[nWwCol] == 3) 2942 pIo->pCtrlStck->SetAttr(*pIo->pPaM->GetPoint(), RES_CHRATR_ROTATE); 2943 } 2944 2945 bool WW8TabDesc::SetPamInCell(short nWwCol, bool bPam) 2946 { 2947 ASSERT( pActBand, "pActBand ist 0" ); 2948 2949 sal_uInt16 nCol = pActBand->nTransCell[nWwCol]; 2950 2951 if ((sal_uInt16)nAktRow >= pTabLines->Count()) 2952 { 2953 ASSERT(!this, "Actual row bigger than expected." ); 2954 if (bPam) 2955 MoveOutsideTable(); 2956 return false; 2957 } 2958 2959 pTabLine = (*pTabLines)[nAktRow]; 2960 pTabBoxes = &pTabLine->GetTabBoxes(); 2961 2962 if (nCol >= pTabBoxes->Count()) 2963 { 2964 if (bPam) 2965 { 2966 // The first paragraph in a cell with upper autospacing has upper 2967 // spacing set to 0 2968 if ( 2969 pIo->bParaAutoBefore && pIo->bFirstPara && 2970 !pIo->pWDop->fDontUseHTMLAutoSpacing 2971 ) 2972 { 2973 pIo->SetUpperSpacing(*pIo->pPaM, 0); 2974 } 2975 2976 // The last paragraph in a cell with lower autospacing has lower 2977 // spacing set to 0 2978 if (pIo->bParaAutoAfter && !pIo->pWDop->fDontUseHTMLAutoSpacing) 2979 pIo->SetLowerSpacing(*pIo->pPaM, 0); 2980 2981 ParkPaM(); 2982 } 2983 return false; 2984 } 2985 pTabBox = (*pTabBoxes)[nCol]; 2986 if( !pTabBox->GetSttNd() ) 2987 { 2988 ASSERT(pTabBox->GetSttNd(), "Probleme beim Aufbau der Tabelle"); 2989 if (bPam) 2990 MoveOutsideTable(); 2991 return false; 2992 } 2993 if (bPam) 2994 { 2995 pAktWWCell = &pActBand->pTCs[ nWwCol ]; 2996 2997 // The first paragraph in a cell with upper autospacing has upper spacing set to 0 2998 if(pIo->bParaAutoBefore && pIo->bFirstPara && !pIo->pWDop->fDontUseHTMLAutoSpacing) 2999 pIo->SetUpperSpacing(*pIo->pPaM, 0); 3000 3001 // The last paragraph in a cell with lower autospacing has lower spacing set to 0 3002 if(pIo->bParaAutoAfter && !pIo->pWDop->fDontUseHTMLAutoSpacing) 3003 pIo->SetLowerSpacing(*pIo->pPaM, 0); 3004 3005 //We need to set the pPaM on the first cell, invalid 3006 //or not so that we can collect paragraph proproties over 3007 //all the cells, but in that case on the valid cell we do not 3008 //want to reset the fmt properties 3009 if (pIo->pPaM->GetPoint()->nNode != pTabBox->GetSttIdx() + 1) 3010 { 3011 pIo->pPaM->GetPoint()->nNode = pTabBox->GetSttIdx() + 1; 3012 pIo->pPaM->GetPoint()->nContent.Assign(pIo->pPaM->GetCntntNode(), 0); 3013 // Zur Sicherheit schon jetzt setzen, da bei den Zellen, die 3014 // zum Randausgleich eingefuegt werden, sonst der Style 3015 // nicht gesetzt wird. 3016 pIo->rDoc.SetTxtFmtColl(*pIo->pPaM, (SwTxtFmtColl*)pIo->pDfltTxtFmtColl); 3017 // uebrigens: da diese Zellen unsichtbare Hilfskonstruktionen sind, 3018 // und nur dazu dienen, zerfranste Aussehen der WW-Tabelle 3019 // nachzuahmen, braucht NICHT SetTxtFmtCollAndListLevel() 3020 // verwendet zu werden. 3021 } 3022 3023 // Better to turn Snap to Grid off for all paragraphs in tables 3024 if(SwTxtNode *pNd = pIo->pPaM->GetNode()->GetTxtNode()) 3025 { 3026 const SfxPoolItem &rItm = pNd->SwCntntNode::GetAttr(RES_PARATR_SNAPTOGRID); 3027 SvxParaGridItem &rSnapToGrid = (SvxParaGridItem&)(rItm); 3028 3029 if(rSnapToGrid.GetValue()) 3030 { 3031 SvxParaGridItem aGridItem( rSnapToGrid ); 3032 aGridItem.SetValue(false); 3033 3034 SwPosition* pGridPos = pIo->pPaM->GetPoint(); 3035 3036 xub_StrLen nEnd = pGridPos->nContent.GetIndex(); 3037 pGridPos->nContent.Assign(pIo->pPaM->GetCntntNode(), 0); 3038 pIo->pCtrlStck->NewAttr(*pGridPos, aGridItem); 3039 pGridPos->nContent.Assign(pIo->pPaM->GetCntntNode(), nEnd); 3040 pIo->pCtrlStck->SetAttr(*pGridPos, RES_PARATR_SNAPTOGRID); 3041 } 3042 } 3043 3044 StartMiserableHackForUnsupportedDirection(nWwCol); 3045 } 3046 return true; 3047 } 3048 3049 void WW8TabDesc::InsertCells( short nIns ) 3050 { 3051 pTabLine = (*pTabLines)[nAktRow]; 3052 pTabBoxes = &pTabLine->GetTabBoxes(); 3053 pTabBox = (*pTabBoxes)[0]; 3054 3055 pIo->rDoc.GetNodes().InsBoxen( pTblNd, pTabLine, (SwTableBoxFmt*)pTabBox->GetFrmFmt(), 3056 (SwTxtFmtColl*)pIo->pDfltTxtFmtColl, 0, pTabBoxes->Count(), nIns ); 3057 // mit dem Dritten Parameter wird das FrmFmt der Boxen angegeben. 3058 // hier kann man auch noch optimieren, um FrmFmts zu sparen 3059 } 3060 3061 void WW8TabDesc::SetTabBorders(SwTableBox* pBox, short nWwIdx) 3062 { 3063 if( nWwIdx < 0 || nWwIdx >= pActBand->nWwCols ) 3064 return; // kuenstlich erzeugte Zellen -> Kein Rand 3065 3066 3067 SvxBoxItem aFmtBox( RES_BOX ); 3068 if (pActBand->pTCs) // neither Cell Border nor Default Border defined ? 3069 { 3070 WW8_TCell* pT = &pActBand->pTCs[nWwIdx]; 3071 if (pIo->IsBorder(pT->rgbrc)) 3072 pIo->SetBorder(aFmtBox, pT->rgbrc); 3073 } 3074 3075 if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwTOP)) 3076 { 3077 aFmtBox.SetDistance( 3078 pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwTOP], 3079 BOX_LINE_TOP); 3080 } 3081 else 3082 aFmtBox.SetDistance(pActBand->mnDefaultTop, BOX_LINE_TOP); 3083 if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwBOTTOM)) 3084 { 3085 aFmtBox.SetDistance( 3086 pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwBOTTOM], 3087 BOX_LINE_BOTTOM); 3088 } 3089 else 3090 aFmtBox.SetDistance(pActBand->mnDefaultBottom,BOX_LINE_BOTTOM); 3091 3092 // nGapHalf bedeutet bei WW ein *horizontaler* Abstand zwischen 3093 // Tabellenzelle und -Inhalt 3094 short nLeftDist = 3095 pActBand->mbHasSpacing ? pActBand->mnDefaultLeft : pActBand->nGapHalf; 3096 short nRightDist = 3097 pActBand->mbHasSpacing ? pActBand->mnDefaultRight : pActBand->nGapHalf; 3098 if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwLEFT)) 3099 { 3100 aFmtBox.SetDistance( 3101 pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwLEFT], 3102 BOX_LINE_LEFT); 3103 } 3104 else 3105 aFmtBox.SetDistance(nLeftDist, BOX_LINE_LEFT); 3106 if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwRIGHT)) 3107 { 3108 aFmtBox.SetDistance( 3109 pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwRIGHT], 3110 BOX_LINE_RIGHT); 3111 } 3112 else 3113 aFmtBox.SetDistance(nRightDist,BOX_LINE_RIGHT); 3114 3115 pBox->GetFrmFmt()->SetFmtAttr(aFmtBox); 3116 } 3117 3118 void WW8TabDesc::SetTabShades( SwTableBox* pBox, short nWwIdx ) 3119 { 3120 if( nWwIdx < 0 || nWwIdx >= pActBand->nWwCols ) 3121 return; // kuenstlich erzeugte Zellen -> Keine Farbe 3122 3123 bool bFound=false; 3124 if (pActBand->pNewSHDs && pActBand->pNewSHDs[nWwIdx] != COL_AUTO) 3125 { 3126 Color aColor(pActBand->pNewSHDs[nWwIdx]); 3127 if (aColor.GetColor() == 0x00333333) 3128 pIo->maTracer.Log(sw::log::eAutoColorBg); 3129 pBox->GetFrmFmt()->SetFmtAttr(SvxBrushItem(aColor, RES_BACKGROUND)); 3130 bFound = true; 3131 } 3132 3133 //If there was no new shades, or no new shade setting 3134 if (pActBand->pSHDs && !bFound) 3135 { 3136 WW8_SHD& rSHD = pActBand->pSHDs[nWwIdx]; 3137 if (!rSHD.GetValue()) // auto 3138 return; 3139 3140 SwWW8Shade aSh( pIo->bVer67, rSHD ); 3141 pBox->GetFrmFmt()->SetFmtAttr(SvxBrushItem(aSh.aColor, RES_BACKGROUND)); 3142 } 3143 } 3144 3145 SvxFrameDirection MakeDirection(sal_uInt16 nCode, sal_Bool bIsBiDi) 3146 { 3147 SvxFrameDirection eDir = FRMDIR_ENVIRONMENT; 3148 // 1: Asian layout with rotated CJK characters 3149 // 5: Asian layout 3150 // 3: Western layout rotated by 90 degrees 3151 // 4: Western layout 3152 switch (nCode) 3153 { 3154 default: 3155 ASSERT(eDir == 4, "unknown direction code, maybe its a bitfield"); 3156 case 3: 3157 // --> FME/Alan Yaniger: 2006-09-15 #i38158# Consider RTL tables: 3158 eDir = bIsBiDi ? FRMDIR_HORI_RIGHT_TOP : FRMDIR_HORI_LEFT_TOP; 3159 // <-- 3160 break; 3161 case 5: 3162 eDir = FRMDIR_VERT_TOP_RIGHT; 3163 break; 3164 case 1: 3165 eDir = FRMDIR_VERT_TOP_RIGHT; 3166 break; 3167 case 4: 3168 // --> FME/Alan Yaniger: 2006-09-15 #i38158# Consider RTL tables: 3169 eDir = bIsBiDi ? FRMDIR_HORI_RIGHT_TOP : FRMDIR_HORI_LEFT_TOP; 3170 // <-- 3171 break; 3172 } 3173 return eDir; 3174 } 3175 3176 void WW8TabDesc::SetTabDirection(SwTableBox* pBox, short nWwIdx) 3177 { 3178 if (nWwIdx < 0 || nWwIdx >= pActBand->nWwCols) 3179 return; 3180 SvxFrameDirectionItem aItem(MakeDirection(pActBand->maDirections[nWwIdx], bIsBiDi), RES_FRAMEDIR); 3181 pBox->GetFrmFmt()->SetFmtAttr(aItem); 3182 } 3183 3184 void WW8TabDesc::SetTabVertAlign( SwTableBox* pBox, short nWwIdx ) 3185 { 3186 if( nWwIdx < 0 || nWwIdx >= pActBand->nWwCols ) 3187 return; 3188 3189 sal_Int16 eVertOri=text::VertOrientation::TOP; 3190 3191 if( pActBand->pTCs ) 3192 { 3193 WW8_TCell* pT = &pActBand->pTCs[nWwIdx]; 3194 switch (pT->nVertAlign) 3195 { 3196 case 0: 3197 default: 3198 eVertOri = text::VertOrientation::TOP; 3199 break; 3200 case 1: 3201 eVertOri = text::VertOrientation::CENTER; 3202 break; 3203 case 2: 3204 eVertOri = text::VertOrientation::BOTTOM; 3205 break; 3206 } 3207 } 3208 3209 pBox->GetFrmFmt()->SetFmtAttr( SwFmtVertOrient(0,eVertOri) ); 3210 } 3211 3212 void WW8TabDesc::AdjustNewBand() 3213 { 3214 if( pActBand->nSwCols > nDefaultSwCols ) // Zellen splitten 3215 InsertCells( pActBand->nSwCols - nDefaultSwCols ); 3216 3217 SetPamInCell( 0, false); 3218 ASSERT( pTabBoxes && pTabBoxes->Count() == (sal_uInt16)pActBand->nSwCols, 3219 "Falsche Spaltenzahl in Tabelle" ) 3220 3221 if( bClaimLineFmt ) 3222 { 3223 pTabLine->ClaimFrmFmt(); // noetig wg. Zeilenhoehe 3224 SwFmtFrmSize aF( ATT_MIN_SIZE, 0, 0 ); // default 3225 3226 if (pActBand->nLineHeight == 0) // 0 = Auto 3227 aF.SetHeightSizeType( ATT_VAR_SIZE ); 3228 else 3229 { 3230 if (pActBand->nLineHeight < 0) // Pos = min, Neg = exakt 3231 { 3232 aF.SetHeightSizeType(ATT_FIX_SIZE); 3233 pActBand->nLineHeight = -pActBand->nLineHeight; 3234 } 3235 if (pActBand->nLineHeight < MINLAY) // nicht erlaubte Zeilenhoehe 3236 pActBand->nLineHeight = MINLAY; 3237 3238 aF.SetHeight(pActBand->nLineHeight);// Min- / Exakt-Hoehe setzen 3239 } 3240 pTabLine->GetFrmFmt()->SetFmtAttr(aF); 3241 } 3242 3243 //Word stores 1 for bCantSplit if the row cannot be split, we set true if 3244 //we can split the row 3245 // bCantSplit: Always true for rows containing merged cells (Word <= 2000 crashes otherwise) 3246 // So in case bCantSplit is true, we check for bCantSplit90, which has been introduced for 3247 // Word versions >= 2002. 3248 bool bSetCantSplit = pActBand->bCantSplit; 3249 if(bSetCantSplit) 3250 bSetCantSplit = pActBand->bCantSplit90; 3251 3252 pTabLine->GetFrmFmt()->SetFmtAttr(SwFmtRowSplit(!bSetCantSplit)); 3253 3254 short i; // SW-Index 3255 short j; // WW-Index 3256 short nW; // Breite 3257 SwFmtFrmSize aFS( ATT_FIX_SIZE ); 3258 j = pActBand->bLEmptyCol ? -1 : 0; 3259 3260 for( i = 0; i < pActBand->nSwCols; i++ ) 3261 { 3262 // setze Zellenbreite 3263 if( j < 0 ) 3264 nW = pActBand->nCenter[0] - nMinLeft; 3265 else 3266 { 3267 //Set j to first non invalid cell 3268 while ((j < pActBand->nWwCols) && (!pActBand->bExist[j])) 3269 j++; 3270 3271 if( j < pActBand->nWwCols ) 3272 nW = pActBand->nCenter[j+1] - pActBand->nCenter[j]; 3273 else 3274 nW = nMaxRight - pActBand->nCenter[j]; 3275 pActBand->nWidth[ j ] = nW; 3276 } 3277 3278 SwTableBox* pBox = (*pTabBoxes)[i]; 3279 // liesse sich durch intelligentes Umhaengen der FrmFmts noch weiter 3280 // verringern 3281 pBox->ClaimFrmFmt(); 3282 3283 SetTabBorders(pBox, j); 3284 3285 // #i18128# word has only one line between adjoining vertical cells 3286 // we have to mimick this in the filter by picking the larger of the 3287 // sides and using that one on one side of the line (right) 3288 SvxBoxItem aCurrentBox(sw::util::ItemGet<SvxBoxItem>(*(pBox->GetFrmFmt()), RES_BOX)); 3289 const SvxBorderLine *pLeftLine = aCurrentBox.GetLine(BOX_LINE_LEFT); 3290 int nCurrentRightLineWidth = 0; 3291 if(pLeftLine) 3292 nCurrentRightLineWidth = pLeftLine->GetInWidth() + pLeftLine->GetOutWidth() + pLeftLine->GetDistance(); 3293 3294 if (i != 0) 3295 { 3296 SwTableBox* pBox2 = (*pTabBoxes)[i-1]; 3297 SvxBoxItem aOldBox(sw::util::ItemGet<SvxBoxItem>(*(pBox2->GetFrmFmt()), RES_BOX)); 3298 const SvxBorderLine *pRightLine = aOldBox.GetLine(BOX_LINE_RIGHT); 3299 int nOldBoxRightLineWidth = 0; 3300 if(pRightLine) 3301 nOldBoxRightLineWidth = pRightLine->GetInWidth() + pRightLine->GetOutWidth() + pRightLine->GetDistance(); 3302 3303 if(nOldBoxRightLineWidth>nCurrentRightLineWidth) 3304 aCurrentBox.SetLine(aOldBox.GetLine(BOX_LINE_RIGHT), BOX_LINE_LEFT); 3305 3306 aOldBox.SetLine(0, BOX_LINE_RIGHT); 3307 pBox2->GetFrmFmt()->SetFmtAttr(aOldBox); 3308 } 3309 3310 pBox->GetFrmFmt()->SetFmtAttr(aCurrentBox); 3311 3312 SetTabVertAlign(pBox, j); 3313 SetTabDirection(pBox, j); 3314 if( pActBand->pSHDs || pActBand->pNewSHDs) 3315 SetTabShades(pBox, j); 3316 j++; 3317 3318 aFS.SetWidth( nW ); 3319 pBox->GetFrmFmt()->SetFmtAttr( aFS ); 3320 3321 // ueberspringe nicht existente Zellen 3322 while( ( j < pActBand->nWwCols ) && !pActBand->bExist[j] ) 3323 { 3324 pActBand->nWidth[j] = pActBand->nCenter[j+1] - pActBand->nCenter[j]; 3325 j++; 3326 } 3327 } 3328 } 3329 3330 void WW8TabDesc::TableCellEnd() 3331 { 3332 ::SetProgressState(pIo->nProgress, pIo->mpDocShell); // Update 3333 3334 EndMiserableHackForUnsupportedDirection(nAktCol); 3335 3336 // neue Zeile 3337 if( pIo->bWasTabRowEnd ) 3338 { 3339 // bWasTabRowEnd will be deactivated in 3340 // SwWW8ImplReader::ProcessSpecial() 3341 3342 sal_uInt16 iCol = GetLogicalWWCol(); 3343 if (iCol < aNumRuleNames.size()) 3344 { 3345 aNumRuleNames.erase(aNumRuleNames.begin() + iCol, 3346 aNumRuleNames.end()); 3347 } 3348 3349 nAktCol = 0; 3350 nAktRow++; 3351 nAktBandRow++; 3352 ASSERT( pActBand , "pActBand ist 0" ); 3353 if( pActBand ) 3354 { 3355 if( nAktRow >= nRows ) // am Tabellenende gibt's nichts sinnvolles 3356 return; // mehr zu tun 3357 3358 bool bNewBand = nAktBandRow >= pActBand->nRows; 3359 if( bNewBand ) 3360 { // neues Band noetig ? 3361 pActBand = pActBand->pNextBand; // 3362 nAktBandRow = 0; 3363 ASSERT( pActBand, "pActBand ist 0" ); 3364 AdjustNewBand(); 3365 } 3366 else 3367 { 3368 SwTableBox* pBox = (*pTabBoxes)[0]; 3369 SwSelBoxes aBoxes; 3370 pIo->rDoc.InsertRow( pTable->SelLineFromBox( pBox, aBoxes ) ); 3371 } 3372 } 3373 } 3374 else 3375 { // neue Spalte ( Zelle ) 3376 nAktCol++; 3377 } 3378 SetPamInCell(nAktCol, true); 3379 3380 // finish Annotated Level Numbering ? 3381 if (pIo->bAnl && !pIo->bAktAND_fNumberAcross) 3382 pIo->StopAllAnl(IsValidCell(nAktCol)); 3383 } 3384 3385 // ggfs. die Box in fuer diese Col offene Merge-Gruppe eintragen 3386 SwTableBox* WW8TabDesc::UpdateTableMergeGroup( WW8_TCell& rCell, 3387 WW8SelBoxInfo* pActGroup, 3388 SwTableBox* pActBox, 3389 sal_uInt16 nCol ) 3390 { 3391 // Rueckgabewert defaulten 3392 SwTableBox* pResult = 0; 3393 3394 // pruefen, ob die Box zu mergen ist 3395 // --> OD 2005-02-04 #118544# - If cell is the first one to be merged, 3396 // a new merge group has to be provided. 3397 // E.g., it could be that a cell is the first one to be merged, but no 3398 // new merge group is provided, because the potential other cell to be merged 3399 // doesn't exist - see method <WW8TabDesc::MergeCells>. 3400 if ( pActBand->bExist[ nCol ] && 3401 ( ( rCell.bFirstMerged && pActGroup ) || 3402 rCell.bMerged || 3403 rCell.bVertMerge || 3404 rCell.bVertRestart ) ) 3405 // <-- 3406 { 3407 // passende Merge-Gruppe ermitteln 3408 WW8SelBoxInfo* pTheMergeGroup = 0; 3409 if( pActGroup ) 3410 // Gruppe uebernehmen 3411 pTheMergeGroup = pActGroup; 3412 else 3413 { 3414 // Gruppe finden 3415 short nMGrIdx; 3416 if( FindMergeGroup( pActBand->nCenter[ nCol ], 3417 pActBand->nWidth[ nCol ], true, nMGrIdx ) ) 3418 pTheMergeGroup = (*pMergeGroups)[ nMGrIdx ]; 3419 } 3420 if( pTheMergeGroup ) 3421 { 3422 // aktuelle Box der Merge-Gruppe hinzufuegen 3423 pTheMergeGroup->Insert( pActBox, pTheMergeGroup->Count() ); 3424 3425 // Target-Box zurueckmelden 3426 pResult = (*pTheMergeGroup)[ 0 ]; 3427 } 3428 } 3429 return pResult; 3430 } 3431 3432 3433 sal_uInt16 WW8TabDesc::GetLogicalWWCol() const // returns number of col as INDICATED within WW6 UI status line -1 3434 { 3435 sal_uInt16 nCol = 0; 3436 if( pActBand && pActBand->pTCs) 3437 { 3438 for( sal_uInt16 iCol = 1; iCol <= nAktCol; ++iCol ) 3439 { 3440 if( !pActBand->pTCs[ iCol-1 ].bMerged ) 3441 ++nCol; 3442 } 3443 } 3444 return nCol; 3445 } 3446 3447 // find name of numrule valid for current WW-COL 3448 const String& WW8TabDesc::GetNumRuleName() const 3449 { 3450 sal_uInt16 nCol = GetLogicalWWCol(); 3451 if (nCol < aNumRuleNames.size()) 3452 return aNumRuleNames[nCol]; 3453 else 3454 return aEmptyStr; 3455 } 3456 3457 void WW8TabDesc::SetNumRuleName( const String& rName ) 3458 { 3459 sal_uInt16 nCol = GetLogicalWWCol(); 3460 for (sal_uInt16 nSize = static_cast< sal_uInt16 >(aNumRuleNames.size()); nSize <= nCol; ++nSize) 3461 aNumRuleNames.push_back(aEmptyStr); 3462 aNumRuleNames[nCol] = rName; 3463 } 3464 3465 bool SwWW8ImplReader::StartTable(WW8_CP nStartCp) 3466 { 3467 // Entering a table so make sure the the FirstPara flag gets set 3468 bFirstPara = true; 3469 // keine rekursiven Tabellen Nicht bei EinfuegenDatei in Tabelle oder 3470 // Fussnote 3471 if (bReadNoTbl) 3472 return false; 3473 3474 if (pTableDesc) 3475 maTableStack.push(pTableDesc); 3476 3477 // --> OD 2005-01-27 #i33818# - determine absolute position object attributes, 3478 // if possible. It's needed for nested tables. 3479 WW8FlyPara* pTableWFlyPara( 0L ); 3480 WW8SwFlyPara* pTableSFlyPara( 0L ); 3481 // --> OD 2005-03-21 #i45301# - anchor nested table inside Writer fly frame 3482 // only at-character, if absolute position object attributes are available. 3483 // Thus, default anchor type is as-character anchored. 3484 RndStdIds eAnchor( FLY_AS_CHAR ); 3485 // <-- 3486 if ( nInTable ) 3487 { 3488 WW8_TablePos* pNestedTabPos( 0L ); 3489 WW8_TablePos aNestedTabPos; 3490 WW8PLCFxSave1 aSave; 3491 pPlcxMan->GetPap()->Save( aSave ); 3492 WW8PLCFx_Cp_FKP* pPap = pPlcxMan->GetPapPLCF(); 3493 WW8_CP nMyStartCp = nStartCp; 3494 if ( SearchRowEnd( pPap, nMyStartCp, nInTable ) && 3495 ParseTabPos( &aNestedTabPos, pPap ) ) 3496 { 3497 pNestedTabPos = &aNestedTabPos; 3498 } 3499 pPlcxMan->GetPap()->Restore( aSave ); 3500 if ( pNestedTabPos ) 3501 { 3502 ApoTestResults aApo = TestApo( nInTable + 1, false, pNestedTabPos ); 3503 pTableWFlyPara = ConstructApo( aApo, pNestedTabPos ); 3504 if ( pTableWFlyPara ) 3505 { 3506 // --> OD 2007-07-03 #148498# 3507 // <WW8SwFlyPara> constructor has changed - new 4th parameter 3508 // containing WW8 page top margin. 3509 pTableSFlyPara = new WW8SwFlyPara(*pPaM, *this, *pTableWFlyPara, 3510 maSectionManager.GetWWPageTopMargin(), 3511 maSectionManager.GetPageLeft(), maSectionManager.GetTextAreaWidth(), 3512 nIniFlyDx, nIniFlyDy); 3513 // <-- 3514 // --> OD 2005-03-21 #i45301# - anchor nested table Writer fly 3515 // frame at-character 3516 eAnchor = FLY_AT_CHAR; 3517 // <-- 3518 } 3519 } 3520 } 3521 // <-- 3522 3523 pTableDesc = new WW8TabDesc( this, nStartCp ); 3524 3525 if( pTableDesc->Ok() ) 3526 { 3527 int nNewInTable = nInTable + 1; 3528 if (InEqualApo(nNewInTable)) 3529 { 3530 ASSERT(pSFlyPara->pFlyFmt, 3531 "how could we be in a local apo and have no apo"); 3532 } 3533 3534 if ((eAnchor == FLY_AT_CHAR) 3535 && !maTableStack.empty() && !InEqualApo(nNewInTable) ) 3536 { 3537 pTableDesc->pParentPos = new SwPosition(*pPaM->GetPoint()); 3538 SfxItemSet aItemSet(rDoc.GetAttrPool(), 3539 RES_FRMATR_BEGIN, RES_FRMATR_END-1); 3540 // --> OD 2005-01-26 #i33818# - anchor the Writer fly frame for 3541 // the nested table at-character. 3542 // --> OD 2005-03-21 #i45301# 3543 SwFmtAnchor aAnchor( eAnchor ); 3544 aAnchor.SetAnchor( pTableDesc->pParentPos ); 3545 aItemSet.Put( aAnchor ); 3546 pTableDesc->pFlyFmt = rDoc.MakeFlySection( eAnchor, 3547 pTableDesc->pParentPos, &aItemSet); 3548 ASSERT( pTableDesc->pFlyFmt->GetAnchor().GetAnchorId() == eAnchor, 3549 "Not the anchor type requested!" ); 3550 // <-- 3551 MoveInsideFly(pTableDesc->pFlyFmt); 3552 } 3553 pTableDesc->CreateSwTable(); 3554 if (pTableDesc->pFlyFmt) 3555 { 3556 pTableDesc->SetSizePosition(pTableDesc->pFlyFmt); 3557 // --> OD 2005-01-26 #i33818# - Use absolute position object 3558 // attributes, if existing, and apply them to the created Writer fly 3559 // frame. 3560 if ( pTableWFlyPara && pTableSFlyPara ) 3561 { 3562 WW8FlySet aFlySet( *this, pTableWFlyPara, pTableSFlyPara, false ); 3563 SwFmtAnchor aAnchor( FLY_AT_CHAR ); 3564 aAnchor.SetAnchor( pTableDesc->pParentPos ); 3565 aFlySet.Put( aAnchor ); 3566 pTableDesc->pFlyFmt->SetFmtAttr( aFlySet ); 3567 } 3568 else 3569 { 3570 SwFmtHoriOrient aHori = 3571 pTableDesc->pTable->GetFrmFmt()->GetHoriOrient(); 3572 pTableDesc->pFlyFmt->SetFmtAttr(aHori); 3573 pTableDesc->pFlyFmt->SetFmtAttr( SwFmtSurround( SURROUND_NONE ) ); 3574 } 3575 // <-- 3576 // --> OD 2005-01-27 #i33818# - The nested table doesn't have to leave 3577 // the table cell. Thus, the Writer fly frame has to follow the text flow. 3578 pTableDesc->pFlyFmt->SetFmtAttr( SwFmtFollowTextFlow( sal_True ) ); 3579 // <-- 3580 } 3581 else 3582 pTableDesc->SetSizePosition(0); 3583 pTableDesc->UseSwTable(); 3584 } 3585 else 3586 PopTableDesc(); 3587 3588 // --> OD 2005-01-28 #i33818# 3589 delete pTableWFlyPara; 3590 delete pTableSFlyPara; 3591 // <-- 3592 3593 bool bSuccess = (0 != pTableDesc); 3594 if (bSuccess) 3595 { 3596 maTracer.EnterEnvironment(sw::log::eTable, rtl::OUString::valueOf( 3597 static_cast<sal_Int32>(maTableStack.size()))); 3598 } 3599 return bSuccess; 3600 } 3601 3602 bool lcl_PamContainsFly(SwPaM & rPam) 3603 { 3604 bool bResult = false; 3605 SwNodeRange aRg( rPam.Start()->nNode, rPam.End()->nNode ); 3606 SwDoc * pDoc = rPam.GetDoc(); 3607 3608 sal_uInt16 n = 0; 3609 SwSpzFrmFmts * pSpzFmts = pDoc->GetSpzFrmFmts(); 3610 sal_uInt16 nCount = pSpzFmts->Count(); 3611 while (!bResult && n < nCount) 3612 { 3613 SwFrmFmt* pFly = (*pSpzFmts)[n]; 3614 const SwFmtAnchor* pAnchor = &pFly->GetAnchor(); 3615 3616 switch (pAnchor->GetAnchorId()) 3617 { 3618 case FLY_AT_PARA: 3619 case FLY_AT_CHAR: 3620 { 3621 const SwPosition* pAPos = pAnchor->GetCntntAnchor(); 3622 3623 if (pAPos != NULL && 3624 aRg.aStart <= pAPos->nNode && 3625 pAPos->nNode <= aRg.aEnd) 3626 { 3627 bResult = true; 3628 } 3629 } 3630 break; 3631 default: 3632 break; 3633 } 3634 3635 ++n; 3636 } 3637 3638 return bResult; 3639 } 3640 3641 void SwWW8ImplReader::TabCellEnd() 3642 { 3643 if (nInTable && pTableDesc) 3644 { 3645 pTableDesc->TableCellEnd(); 3646 3647 if (bReadTable 3648 && pWFlyPara == NULL 3649 && mpTableEndPaM.get() != NULL 3650 && (! SwPaM::Overlap(*pPaM, *mpTableEndPaM)) 3651 && SwPaM::LessThan(*mpTableEndPaM, *pPaM) 3652 && mpTableEndPaM->GetPoint()->nNode.GetNode().IsTxtNode() 3653 && !lcl_PamContainsFly(*mpTableEndPaM) 3654 ) 3655 { 3656 rDoc.DelFullPara(*mpTableEndPaM); 3657 } 3658 } 3659 3660 bFirstPara = true; // We have come to the end of a cell so FirstPara flag 3661 bReadTable = false; 3662 mpTableEndPaM.reset(); 3663 } 3664 3665 void SwWW8ImplReader::Read_TabCellEnd( sal_uInt16, const sal_uInt8* pData, short nLen) 3666 { 3667 if( ( nLen > 0 ) && ( *pData == 1 ) ) 3668 bWasTabCellEnd = true; 3669 } 3670 3671 void SwWW8ImplReader::Read_TabRowEnd( sal_uInt16, const sal_uInt8* pData, short nLen ) // Sprm25 3672 { 3673 if( ( nLen > 0 ) && ( *pData == 1 ) ) 3674 bWasTabRowEnd = true; 3675 } 3676 3677 void SwWW8ImplReader::PopTableDesc() 3678 { 3679 if (pTableDesc && pTableDesc->pFlyFmt) 3680 { 3681 MoveOutsideFly(pTableDesc->pFlyFmt,*pTableDesc->pParentPos); 3682 } 3683 3684 delete pTableDesc; 3685 if (maTableStack.empty()) 3686 pTableDesc = 0; 3687 else 3688 { 3689 pTableDesc = maTableStack.top(); 3690 maTableStack.pop(); 3691 } 3692 } 3693 3694 void SwWW8ImplReader::StopTable() 3695 { 3696 maTracer.LeaveEnvironment(sw::log::eTable); 3697 3698 ASSERT(pTableDesc, "Panic, stop table with no table!"); 3699 if (!pTableDesc) 3700 return; 3701 3702 // We are leaving a table so make sure the next paragraph doesn't think 3703 // it's the first paragraph 3704 bFirstPara = false; 3705 3706 pTableDesc->FinishSwTable(); 3707 PopTableDesc(); 3708 3709 if (!maTableStack.empty()) 3710 { 3711 maTracer.EnterEnvironment(sw::log::eTable, rtl::OUString::valueOf( 3712 static_cast<sal_Int32>(maTableStack.size()))); 3713 } 3714 3715 bReadTable = true; 3716 // --> OD 2009-04-16 #i101116# 3717 // Keep PaM on table end only for nested tables 3718 if ( nInTable > 1 ) 3719 { 3720 mpTableEndPaM.reset(new SwPaM(*pPaM)); 3721 } 3722 // <-- 3723 } 3724 3725 // GetTableLeft() wird fuer absatzgebundene Grafikobjekte in Tabellen 3726 // gebraucht. 3727 // WW nimmt bei eingerueckten Tabellen den Absatzrand, der ohne Tabelle 3728 // gueltig waere, als Basis; SW benutzt den linken Tabellenrand. 3729 short SwWW8ImplReader::GetTableLeft() 3730 { 3731 return (pTableDesc) ? pTableDesc->GetMinLeft() : 0; 3732 } 3733 3734 bool SwWW8ImplReader::IsInvalidOrToBeMergedTabCell() const 3735 { 3736 if( !pTableDesc ) 3737 return false; 3738 3739 const WW8_TCell* pCell = pTableDesc->GetAktWWCell(); 3740 3741 return !pTableDesc->IsValidCell( pTableDesc->GetAktCol() ) 3742 || ( pCell 3743 && ( !pCell->bFirstMerged 3744 && ( pCell->bMerged 3745 || ( pCell->bVertMerge 3746 && !pCell->bVertRestart 3747 ) 3748 ) 3749 ) 3750 ); 3751 } 3752 3753 sal_uInt16 SwWW8ImplReader::StyleUsingLFO( sal_uInt16 nLFOIndex ) const 3754 { 3755 sal_uInt16 nRes = USHRT_MAX; 3756 if( pCollA ) 3757 { 3758 for(sal_uInt16 nI = 0; nI < pStyles->GetCount(); nI++ ) 3759 if( pCollA[ nI ].bValid 3760 && (nLFOIndex == pCollA[ nI ].nLFOIndex) ) 3761 nRes = nI; 3762 } 3763 return nRes; 3764 } 3765 3766 const SwFmt* SwWW8ImplReader::GetStyleWithOrgWWName( String& rName ) const 3767 { 3768 SwFmt* pRet = 0; 3769 if( pCollA ) 3770 { 3771 for(sal_uInt16 nI = 0; nI < pStyles->GetCount(); nI++ ) 3772 if( pCollA[ nI ].bValid 3773 && (rName.Equals( pCollA[ nI ].GetOrgWWName())) ) 3774 { 3775 pRet = pCollA[ nI ].pFmt; 3776 break; 3777 } 3778 } 3779 return pRet; 3780 } 3781 3782 //----------------------------------------- 3783 // class WW8RStyle 3784 //----------------------------------------- 3785 3786 const sal_uInt8* WW8RStyle::HasParaSprm( sal_uInt16 nId ) const 3787 { 3788 if( !pParaSprms || !nSprmsLen ) 3789 return 0; 3790 3791 const sal_uInt8* pSprms = pParaSprms; 3792 sal_uInt16 i, x; 3793 3794 for( i=0; i < nSprmsLen; ) 3795 { 3796 sal_uInt16 nAktId = maSprmParser.GetSprmId(pSprms); 3797 // Sprm found ? 3798 if( nAktId == nId ) 3799 return pSprms + maSprmParser.DistanceToData(nId); 3800 3801 x = maSprmParser.GetSprmSize(nAktId, pSprms); 3802 i = i + x; 3803 pSprms += x; 3804 } 3805 return 0; // Sprm not found 3806 } 3807 3808 void WW8RStyle::ImportSprms(sal_uInt8 *pSprms, short nLen, bool bPap) 3809 { 3810 if (!nLen) 3811 return; 3812 3813 if( bPap ) 3814 { 3815 pParaSprms = pSprms; // fuer HasParaSprms() 3816 nSprmsLen = nLen; 3817 } 3818 3819 while ( nLen > 0 ) 3820 { 3821 sal_uInt16 nL1 = pIo->ImportSprm(pSprms); 3822 nLen = nLen - nL1; 3823 pSprms += nL1; 3824 } 3825 3826 pParaSprms = 0; 3827 nSprmsLen = 0; 3828 } 3829 3830 void WW8RStyle::ImportSprms(sal_Size nPosFc, short nLen, bool bPap) 3831 { 3832 if (!nLen) 3833 return; 3834 3835 sal_uInt8 *pSprms = new sal_uInt8[nLen]; 3836 3837 pStStrm->Seek(nPosFc); 3838 pStStrm->Read(pSprms, nLen); 3839 3840 ImportSprms(pSprms, nLen, bPap); 3841 3842 delete[] pSprms; 3843 } 3844 3845 static inline short WW8SkipOdd(SvStream* pSt ) 3846 { 3847 if ( pSt->Tell() & 0x1 ) 3848 { 3849 sal_uInt8 c; 3850 pSt->Read( &c, 1 ); 3851 return 1; 3852 } 3853 return 0; 3854 } 3855 3856 static inline short WW8SkipEven(SvStream* pSt ) 3857 { 3858 if (!(pSt->Tell() & 0x1)) 3859 { 3860 sal_uInt8 c; 3861 pSt->Read( &c, 1 ); 3862 return 1; 3863 } 3864 return 0; 3865 } 3866 3867 short WW8RStyle::ImportUPX(short nLen, bool bPAP, bool bOdd) 3868 { 3869 sal_Int16 cbUPX; 3870 3871 if( 0 < nLen ) // Empty ? 3872 { 3873 if (bOdd) 3874 nLen = nLen - WW8SkipEven( pStStrm ); 3875 else 3876 nLen = nLen - WW8SkipOdd( pStStrm ); 3877 3878 *pStStrm >> cbUPX; 3879 3880 nLen-=2; 3881 3882 if ( cbUPX > nLen ) 3883 cbUPX = nLen; // !cbUPX auf nLen verkleinert! 3884 3885 if( (1 < cbUPX) || ( (0 < cbUPX) && !bPAP ) ) 3886 { 3887 if( bPAP ) 3888 { 3889 sal_uInt16 id; 3890 *pStStrm >> id; 3891 3892 cbUPX-= 2; 3893 nLen-= 2; 3894 } 3895 3896 if( 0 < cbUPX ) 3897 { 3898 sal_Size nPos = pStStrm->Tell(); // falls etwas falsch interpretiert 3899 // wird, gehts danach wieder richtig 3900 ImportSprms( nPos, cbUPX, bPAP ); 3901 3902 if ( pStStrm->Tell() != nPos + cbUPX ) 3903 pStStrm->Seek( nPos+cbUPX ); 3904 3905 nLen = nLen - cbUPX; 3906 } 3907 } 3908 } 3909 return nLen; 3910 } 3911 3912 void WW8RStyle::ImportGrupx(short nLen, bool bPara, bool bOdd) 3913 { 3914 if( nLen <= 0 ) 3915 return; 3916 if (bOdd) 3917 nLen = nLen - WW8SkipEven( pStStrm ); 3918 else 3919 nLen = nLen - WW8SkipOdd( pStStrm ); 3920 3921 if( bPara ) // Grupx.Papx 3922 nLen = ImportUPX(nLen, true, bOdd); 3923 ImportUPX(nLen, false, bOdd); // Grupx.Chpx 3924 } 3925 3926 WW8RStyle::WW8RStyle(WW8Fib& _rFib, SwWW8ImplReader* pI) 3927 : WW8Style(*pI->pTableStream, _rFib), maSprmParser(_rFib.GetFIBVersion()), 3928 pIo(pI), pStStrm(pI->pTableStream), pStyRule(0), nWwNumLevel(0) 3929 { 3930 pIo->nColls = cstd; 3931 pIo->pCollA = cstd ? new SwWW8StyInf[ cstd ] : NULL; // Style-UEbersetzung WW->SW 3932 } 3933 3934 void WW8RStyle::Set1StyleDefaults() 3935 { 3936 // see #i25247#, #i25561#, #i48064#, #i92341# for default font 3937 if (!bCJKFontChanged) // Style no CJK Font? set the default 3938 pIo->SetNewFontAttr(ftcFE, true, RES_CHRATR_CJK_FONT); 3939 3940 if (!bCTLFontChanged) // Style no CTL Font? set the default 3941 pIo->SetNewFontAttr(ftcBi, true, RES_CHRATR_CTL_FONT); 3942 3943 //#88976# western 2nd to make western charset conversion the default 3944 if (!bFontChanged) // Style has no Font? set the default, 3945 { 3946 pIo->SetNewFontAttr(ftcAsci, true, RES_CHRATR_FONT); 3947 /* removed by a patch from cmc for #i52786# 3948 if (pIo->bVer67) 3949 SetStyleCharSet(pIo->pCollA[pIo->nAktColl]); 3950 */ 3951 } 3952 3953 if( !pIo->bNoAttrImport ) 3954 { 3955 // Style has no text color set, winword default is auto 3956 if ( !bTxtColChanged ) 3957 pIo->pAktColl->SetFmtAttr(SvxColorItem(Color(COL_AUTO), RES_CHRATR_COLOR)); 3958 3959 // Style has no FontSize ? WinWord Default is 10pt for western and asian 3960 if( !bFSizeChanged ) 3961 { 3962 SvxFontHeightItem aAttr(200, 100, RES_CHRATR_FONTSIZE); 3963 pIo->pAktColl->SetFmtAttr(aAttr); 3964 aAttr.SetWhich(RES_CHRATR_CJK_FONTSIZE); 3965 pIo->pAktColl->SetFmtAttr(aAttr); 3966 } 3967 3968 // Style has no FontSize ? WinWord Default is 10pt for western and asian 3969 if( !bFCTLSizeChanged ) 3970 { 3971 SvxFontHeightItem aAttr(200, 100, RES_CHRATR_FONTSIZE); 3972 aAttr.SetWhich(RES_CHRATR_CTL_FONTSIZE); 3973 pIo->pAktColl->SetFmtAttr(aAttr); 3974 } 3975 3976 if( /*pIo->pWDop->fWidowControl &&*/ !bWidowsChanged ) // Widows ? 3977 { 3978 pIo->pAktColl->SetFmtAttr( SvxWidowsItem( 2, RES_PARATR_WIDOWS ) ); 3979 pIo->pAktColl->SetFmtAttr( SvxOrphansItem( 2, RES_PARATR_ORPHANS ) ); 3980 } 3981 } 3982 } 3983 3984 bool WW8RStyle::PrepareStyle(SwWW8StyInf &rSI, ww::sti eSti, sal_uInt16 nThisStyle, sal_uInt16 nNextStyle) 3985 { 3986 SwFmt* pColl; 3987 bool bStyExist; 3988 if (rSI.bColl) 3989 { 3990 // Para-Style 3991 sw::util::ParaStyleMapper::StyleResult aResult = 3992 pIo->maParaStyleMapper.GetStyle(rSI.GetOrgWWName(), eSti); 3993 pColl = aResult.first; 3994 bStyExist = aResult.second; 3995 } 3996 else 3997 { 3998 // Char-Style 3999 sw::util::CharStyleMapper::StyleResult aResult = 4000 pIo->maCharStyleMapper.GetStyle(rSI.GetOrgWWName(), eSti); 4001 pColl = aResult.first; 4002 bStyExist = aResult.second; 4003 } 4004 4005 bool bImport = !bStyExist || pIo->mbNewDoc; // Inhalte Importieren ? 4006 bool bOldNoImp = pIo->bNoAttrImport; 4007 rSI.bImportSkipped = !bImport; 4008 4009 if( !bImport ) 4010 pIo->bNoAttrImport = true; 4011 else 4012 { 4013 if (bStyExist) 4014 { 4015 // --> OD 2007-01-25 #i73790# - method renamed 4016 pColl->ResetAllFmtAttr(); 4017 // <-- 4018 } 4019 pColl->SetAuto(false); // nach Empfehlung JP 4020 } // macht die UI aber anders 4021 pIo->pAktColl = pColl; 4022 rSI.pFmt = pColl; // UEbersetzung WW->SW merken 4023 rSI.bImportSkipped = !bImport; 4024 4025 // Set Based on style 4026 sal_uInt16 j = rSI.nBase; 4027 if (j != nThisStyle && j < cstd ) 4028 { 4029 SwWW8StyInf* pj = &pIo->pCollA[j]; 4030 if (rSI.pFmt && pj->pFmt && rSI.bColl == pj->bColl) 4031 { 4032 rSI.pFmt->SetDerivedFrom( pj->pFmt ); // ok, Based on eintragen 4033 rSI.eLTRFontSrcCharSet = pj->eLTRFontSrcCharSet; 4034 rSI.eRTLFontSrcCharSet = pj->eRTLFontSrcCharSet; 4035 rSI.eCJKFontSrcCharSet = pj->eCJKFontSrcCharSet; 4036 rSI.n81Flags = pj->n81Flags; 4037 rSI.n81BiDiFlags = pj->n81BiDiFlags; 4038 rSI.mnWW8OutlineLevel = pj->mnWW8OutlineLevel; 4039 rSI.bParaAutoBefore = pj->bParaAutoBefore; 4040 rSI.bParaAutoAfter = pj->bParaAutoAfter; 4041 4042 if (pj->pWWFly) 4043 rSI.pWWFly = new WW8FlyPara(pIo->bVer67, pj->pWWFly); 4044 } 4045 } 4046 else if( pIo->mbNewDoc && bStyExist ) 4047 rSI.pFmt->SetDerivedFrom(0); 4048 4049 rSI.nFollow = nNextStyle; // Follow merken 4050 4051 pStyRule = 0; // falls noetig, neu anlegen 4052 bTxtColChanged = bFontChanged = bCJKFontChanged = bCTLFontChanged = 4053 bFSizeChanged = bFCTLSizeChanged = bWidowsChanged = false; 4054 pIo->SetNAktColl( nThisStyle ); 4055 pIo->bStyNormal = nThisStyle == 0; 4056 return bOldNoImp; 4057 } 4058 4059 void WW8RStyle::PostStyle(SwWW8StyInf &rSI, bool bOldNoImp) 4060 { 4061 // Alle moeglichen Attribut-Flags zuruecksetzen, 4062 // da es in Styles keine Attr-Enden gibt 4063 4064 pIo->bHasBorder = pIo->bShdTxtCol = pIo->bCharShdTxtCol 4065 = pIo->bSpec = pIo->bObj = pIo->bSymbol = false; 4066 pIo->nCharFmt = -1; 4067 4068 // If Style basiert auf Nichts oder Basis ignoriert 4069 if ((rSI.nBase >= cstd || pIo->pCollA[rSI.nBase].bImportSkipped) && rSI.bColl) 4070 { 4071 //! Char-Styles funktionieren aus 4072 // unerfindlichen Gruenden nicht 4073 // -> dann evtl. harte WW-Defaults 4074 // reinsetzen 4075 Set1StyleDefaults(); 4076 } 4077 4078 pStyRule = 0; // zur Sicherheit 4079 pIo->bStyNormal = false; 4080 pIo->SetNAktColl( 0 ); 4081 pIo->bNoAttrImport = bOldNoImp; 4082 // rasch nochmal die Listen-Merk-Felder zuruecksetzen, 4083 // fuer den Fall dass sie beim einlesen des Styles verwendet wurden 4084 pIo->nLFOPosition = USHRT_MAX; 4085 pIo->nListLevel = WW8ListManager::nMaxLevel; 4086 } 4087 4088 void WW8RStyle::Import1Style( sal_uInt16 nNr ) 4089 { 4090 SwWW8StyInf &rSI = pIo->pCollA[nNr]; 4091 4092 if( rSI.bImported || !rSI.bValid ) 4093 return; 4094 4095 rSI.bImported = true; // jetzt schon Flag setzen 4096 // verhindert endlose Rekursion 4097 // 4098 // gueltig und nicht NIL und noch nicht Importiert 4099 4100 if( rSI.nBase < cstd && !pIo->pCollA[rSI.nBase].bImported ) 4101 Import1Style( rSI.nBase ); 4102 4103 pStStrm->Seek( rSI.nFilePos ); 4104 4105 short nSkip, cbStd; 4106 String sName; 4107 4108 WW8_STD* pStd = Read1Style( nSkip, &sName, &cbStd );// lies Style 4109 4110 if (pStd) 4111 rSI.SetOrgWWIdent( sName, pStd->sti ); 4112 4113 // either no Name or unused Slot or unknown Style 4114 4115 if ( !pStd || (0 == sName.Len()) || ((1 != pStd->sgc) && (2 != pStd->sgc)) ) 4116 { 4117 pStStrm->SeekRel( nSkip ); 4118 return; 4119 } 4120 4121 bool bOldNoImp = PrepareStyle(rSI, static_cast<ww::sti>(pStd->sti), nNr, pStd->istdNext); 4122 4123 // falls etwas falsch interpretiert wird, gehts danach wieder richtig 4124 long nPos = pStStrm->Tell(); 4125 4126 //Variable parts of the STD start at even byte offsets, but "inside 4127 //the STD", which I take to meaning even in relation to the starting 4128 //position of the STD, which matches findings in #89439#, generally it 4129 //doesn't matter as the STSHI starts off nearly always on an even 4130 //offset 4131 4132 //Import of the Style Contents 4133 ImportGrupx(nSkip, pStd->sgc == 1, rSI.nFilePos & 1); 4134 4135 PostStyle(rSI, bOldNoImp); 4136 4137 pStStrm->Seek( nPos+nSkip ); 4138 delete pStd; 4139 } 4140 4141 void WW8RStyle::RecursiveReg(sal_uInt16 nNr) 4142 { 4143 SwWW8StyInf &rSI = pIo->pCollA[nNr]; 4144 if( rSI.bImported || !rSI.bValid ) 4145 return; 4146 4147 rSI.bImported = true; 4148 4149 if( rSI.nBase < cstd && !pIo->pCollA[rSI.nBase].bImported ) 4150 RecursiveReg(rSI.nBase); 4151 4152 pIo->RegisterNumFmtOnStyle(nNr); 4153 4154 } 4155 4156 /* 4157 After all styles are imported then we can recursively apply numbering 4158 styles to them, and change their tab stop settings if they turned out 4159 to have special first line indentation. 4160 */ 4161 void WW8RStyle::PostProcessStyles() 4162 { 4163 sal_uInt16 i; 4164 /* 4165 Clear all imported flags so that we can recursively apply numbering 4166 formats and use it to mark handled ones 4167 */ 4168 for (i=0; i < cstd; ++i) 4169 pIo->pCollA[i].bImported = false; 4170 4171 /* 4172 Register the num formats and tabstop changes on the styles recursively. 4173 */ 4174 4175 /* 4176 In the same loop apply the tabstop changes required because we need to 4177 change their location if theres a special indentation for the first line, 4178 By avoiding making use of each styles margins during reading of their 4179 tabstops we don't get problems with doubly adjusting tabstops that 4180 are inheritied. 4181 */ 4182 for (i=0; i < cstd; ++i) 4183 { 4184 if (pIo->pCollA[i].bValid) 4185 { 4186 RecursiveReg(i); 4187 } 4188 } 4189 } 4190 4191 void WW8RStyle::ScanStyles() // untersucht Style-Abhaengigkeiten 4192 { // und ermittelt die Filepos fuer jeden Style 4193 /* 4194 WW8_FC nStyleStart = rFib.fcStshf; 4195 pStStrm->Seek( nStyleStart ); 4196 */ 4197 for (sal_uInt16 i = 0; i < cstd; ++i) 4198 { 4199 short nSkip; 4200 SwWW8StyInf &rSI = pIo->pCollA[i]; 4201 4202 rSI.nFilePos = pStStrm->Tell(); // merke FilePos 4203 WW8_STD* pStd = Read1Style( nSkip, 0, 0 ); // read STD 4204 rSI.bValid = (0 != pStd); 4205 if (rSI.bValid) 4206 { 4207 rSI.nBase = pStd->istdBase; // merke Basis 4208 rSI.bColl = ( pStd->sgc == 1 ); // Para-Style 4209 } 4210 else 4211 rSI = SwWW8StyInf(); 4212 4213 delete pStd; 4214 pStStrm->SeekRel( nSkip ); // ueberlese Namen und Sprms 4215 } 4216 } 4217 4218 std::vector<sal_uInt8> ChpxToSprms(const Word2CHPX &rChpx) 4219 { 4220 std::vector<sal_uInt8> aRet; 4221 4222 aRet.push_back(60); 4223 aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fBold) ); 4224 4225 aRet.push_back(61); 4226 aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fItalic) ); 4227 4228 aRet.push_back(62); 4229 aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fStrike) ); 4230 4231 aRet.push_back(63); 4232 aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fOutline) ); 4233 4234 aRet.push_back(65); 4235 aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fSmallCaps) ); 4236 4237 aRet.push_back(66); 4238 aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fCaps) ); 4239 4240 aRet.push_back(67); 4241 aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fVanish) ); 4242 4243 if (rChpx.fsFtc) 4244 { 4245 aRet.push_back(68); 4246 SVBT16 a; 4247 ShortToSVBT16(rChpx.ftc, a); 4248 aRet.push_back(a[1]); 4249 aRet.push_back(a[0]); 4250 } 4251 4252 if (rChpx.fsKul) 4253 { 4254 aRet.push_back(69); 4255 aRet.push_back(rChpx.kul); 4256 } 4257 4258 if (rChpx.fsLid) 4259 { 4260 aRet.push_back(72); 4261 SVBT16 a; 4262 ShortToSVBT16(rChpx.lid, a); 4263 aRet.push_back(a[1]); 4264 aRet.push_back(a[0]); 4265 } 4266 4267 if (rChpx.fsIco) 4268 { 4269 aRet.push_back(73); 4270 aRet.push_back(rChpx.ico); 4271 } 4272 4273 if (rChpx.fsHps) 4274 { 4275 aRet.push_back(74); 4276 4277 SVBT16 a; 4278 ShortToSVBT16(rChpx.hps, a); 4279 aRet.push_back(a[0]); 4280 // aRet.push_back(a[1]); 4281 } 4282 4283 if (rChpx.fsPos) 4284 { 4285 aRet.push_back(76); 4286 aRet.push_back(rChpx.hpsPos); 4287 } 4288 4289 aRet.push_back(80); 4290 aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fBoldBi) ); 4291 4292 aRet.push_back(81); 4293 aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fItalicBi) ); 4294 4295 if (rChpx.fsFtcBi) 4296 { 4297 aRet.push_back(82); 4298 SVBT16 a; 4299 ShortToSVBT16(rChpx.fsFtcBi, a); 4300 aRet.push_back(a[1]); 4301 aRet.push_back(a[0]); 4302 } 4303 4304 if (rChpx.fsLidBi) 4305 { 4306 aRet.push_back(83); 4307 SVBT16 a; 4308 ShortToSVBT16(rChpx.lidBi, a); 4309 aRet.push_back(a[1]); 4310 aRet.push_back(a[0]); 4311 } 4312 4313 if (rChpx.fsIcoBi) 4314 { 4315 aRet.push_back(84); 4316 aRet.push_back(rChpx.icoBi); 4317 } 4318 4319 if (rChpx.fsHpsBi) 4320 { 4321 aRet.push_back(85); 4322 SVBT16 a; 4323 ShortToSVBT16(rChpx.hpsBi, a); 4324 aRet.push_back(a[1]); 4325 aRet.push_back(a[0]); 4326 } 4327 4328 return aRet; 4329 } 4330 4331 Word2CHPX ReadWord2Chpx(SvStream &rSt, sal_Size nOffset, sal_uInt8 nSize) 4332 { 4333 Word2CHPX aChpx; 4334 4335 if (!nSize) 4336 return aChpx; 4337 4338 rSt.Seek(nOffset); 4339 4340 sal_uInt8 nCount=0; 4341 4342 while (1) 4343 { 4344 sal_uInt8 nFlags8; 4345 rSt >> nFlags8; 4346 nCount++; 4347 4348 aChpx.fBold = nFlags8 & 0x01; 4349 aChpx.fItalic = (nFlags8 & 0x02) >> 1; 4350 aChpx.fRMarkDel = (nFlags8 & 0x04) >> 2; 4351 aChpx.fOutline = (nFlags8 & 0x08) >> 3; 4352 aChpx.fFldVanish = (nFlags8 & 0x10) >> 4; 4353 aChpx.fSmallCaps = (nFlags8 & 0x20) >> 5; 4354 aChpx.fCaps = (nFlags8 & 0x40) >> 6; 4355 aChpx.fVanish = (nFlags8 & 0x80) >> 7; 4356 4357 if (nCount >= nSize) break; 4358 rSt >> nFlags8; 4359 nCount++; 4360 4361 aChpx.fRMark = nFlags8 & 0x01; 4362 aChpx.fSpec = (nFlags8 & 0x02) >> 1; 4363 aChpx.fStrike = (nFlags8 & 0x04) >> 2; 4364 aChpx.fObj = (nFlags8 & 0x08) >> 3; 4365 aChpx.fBoldBi = (nFlags8 & 0x10) >> 4; 4366 aChpx.fItalicBi = (nFlags8 & 0x20) >> 5; 4367 aChpx.fBiDi = (nFlags8 & 0x40) >> 6; 4368 aChpx.fDiacUSico = (nFlags8 & 0x80) >> 7; 4369 4370 if (nCount >= nSize) break; 4371 rSt >> nFlags8; 4372 nCount++; 4373 4374 aChpx.fsIco = nFlags8 & 0x01; 4375 aChpx.fsFtc = (nFlags8 & 0x02) >> 1; 4376 aChpx.fsHps = (nFlags8 & 0x04) >> 2; 4377 aChpx.fsKul = (nFlags8 & 0x08) >> 3; 4378 aChpx.fsPos = (nFlags8 & 0x10) >> 4; 4379 aChpx.fsSpace = (nFlags8 & 0x20) >> 5; 4380 aChpx.fsLid = (nFlags8 & 0x40) >> 6; 4381 aChpx.fsIcoBi = (nFlags8 & 0x80) >> 7; 4382 4383 if (nCount >= nSize) break; 4384 rSt >> nFlags8; 4385 nCount++; 4386 4387 aChpx.fsFtcBi = nFlags8 & 0x01; 4388 aChpx.fsHpsBi = (nFlags8 & 0x02) >> 1; 4389 aChpx.fsLidBi = (nFlags8 & 0x04) >> 2; 4390 4391 if (nCount >= nSize) break; 4392 rSt >> aChpx.ftc; 4393 nCount+=2; 4394 4395 if (nCount >= nSize) break; 4396 rSt >> aChpx.hps; 4397 nCount+=2; 4398 4399 if (nCount >= nSize) break; 4400 rSt >> nFlags8; 4401 nCount++; 4402 4403 aChpx.qpsSpace = nFlags8 & 0x3F; 4404 aChpx.fSysVanish = (nFlags8 & 0x40) >> 6; 4405 aChpx.fNumRun = (nFlags8 & 0x80) >> 7; 4406 4407 if (nCount >= nSize) break; 4408 rSt >> nFlags8; 4409 nCount++; 4410 4411 aChpx.ico = nFlags8 & 0x1F; 4412 aChpx.kul = (nFlags8 & 0xE0) >> 5; 4413 4414 if (nCount >= nSize) break; 4415 rSt >> aChpx.hpsPos; 4416 nCount++; 4417 4418 if (nCount >= nSize) break; 4419 rSt >> aChpx.icoBi; 4420 nCount++; 4421 4422 if (nCount >= nSize) break; 4423 rSt >> aChpx.lid; 4424 nCount+=2; 4425 4426 if (nCount >= nSize) break; 4427 rSt >> aChpx.ftcBi; 4428 nCount+=2; 4429 4430 if (nCount >= nSize) break; 4431 rSt >> aChpx.hpsBi; 4432 nCount+=2; 4433 4434 if (nCount >= nSize) break; 4435 rSt >> aChpx.lidBi; 4436 nCount+=2; 4437 4438 if (nCount >= nSize) break; 4439 rSt >> aChpx.fcPic; 4440 nCount+=4; 4441 4442 break; 4443 } 4444 4445 rSt.SeekRel(nSize-nCount); 4446 return aChpx; 4447 } 4448 4449 namespace 4450 { 4451 struct pxoffset { sal_Size mnOffset; sal_uInt8 mnSize; }; 4452 } 4453 4454 void WW8RStyle::ImportOldFormatStyles() 4455 { 4456 for (sal_uInt16 i=0; i < cstd; ++i) 4457 { 4458 pIo->pCollA[i].bColl = true; 4459 //every chain must end eventually at the null style (style code 222) 4460 pIo->pCollA[i].nBase = 222; 4461 } 4462 4463 rtl_TextEncoding eStructChrSet = WW8Fib::GetFIBCharset( 4464 pIo->pWwFib->chseTables); 4465 4466 sal_uInt16 cstcStd; 4467 rSt >> cstcStd; 4468 4469 sal_uInt16 cbName; 4470 rSt >> cbName; 4471 sal_uInt16 nByteCount = 2; 4472 sal_uInt16 stcp=0; 4473 while (nByteCount < cbName) 4474 { 4475 sal_uInt8 nCount; 4476 rSt >> nCount; 4477 nByteCount++; 4478 4479 sal_uInt8 stc = static_cast< sal_uInt8 >((stcp - cstcStd) & 255); 4480 SwWW8StyInf &rSI = pIo->pCollA[stc]; 4481 if (nCount != 0xFF) // undefined style 4482 { 4483 String sName; 4484 if (nCount == 0) // inbuilt style 4485 { 4486 ww::sti eSti = ww::GetCanonicalStiFromStc(stc); 4487 if (const sal_Char *pStr = GetEnglishNameFromSti(eSti)) 4488 sName = String(pStr, RTL_TEXTENCODING_ASCII_US); 4489 else 4490 sName = String(CREATE_CONST_ASC("Unknown")); 4491 } 4492 else // user style 4493 { 4494 ByteString aTmp; 4495 nByteCount = static_cast< sal_uInt16 >(nByteCount + SafeReadString(aTmp, nCount, rSt)); 4496 sName = String(aTmp, eStructChrSet); 4497 } 4498 rSI.SetOrgWWIdent(sName, stc); 4499 rSI.bImported = true; 4500 } 4501 else 4502 { 4503 ww::sti eSti = ww::GetCanonicalStiFromStc(stc); 4504 if (const sal_Char *pStr = GetEnglishNameFromSti(eSti)) 4505 { 4506 String sName = String(pStr, RTL_TEXTENCODING_ASCII_US); 4507 rSI.SetOrgWWIdent(sName, stc); 4508 } 4509 } 4510 stcp++; 4511 } 4512 4513 sal_uInt16 nStyles=stcp; 4514 4515 std::vector<pxoffset> aCHPXOffsets(stcp); 4516 sal_uInt16 cbChpx; 4517 rSt >> cbChpx; 4518 nByteCount = 2; 4519 stcp=0; 4520 std::vector< std::vector<sal_uInt8> > aConvertedChpx; 4521 while (nByteCount < cbChpx) 4522 { 4523 sal_uInt8 cb; 4524 rSt >> cb; 4525 nByteCount++; 4526 4527 aCHPXOffsets[stcp].mnSize = 0; 4528 4529 if (cb != 0xFF) 4530 { 4531 sal_uInt8 nRemainder = cb; 4532 4533 aCHPXOffsets[stcp].mnOffset = rSt.Tell(); 4534 aCHPXOffsets[stcp].mnSize = nRemainder; 4535 4536 Word2CHPX aChpx = ReadWord2Chpx(rSt, aCHPXOffsets[stcp].mnOffset, 4537 aCHPXOffsets[stcp].mnSize); 4538 aConvertedChpx.push_back( ChpxToSprms(aChpx) ); 4539 4540 nByteCount += nRemainder; 4541 } 4542 else 4543 aConvertedChpx.push_back( std::vector<sal_uInt8>() ); 4544 4545 stcp++; 4546 if (stcp == nStyles) 4547 { 4548 rSt.SeekRel(cbChpx-nByteCount); 4549 nByteCount += cbChpx-nByteCount; 4550 } 4551 } 4552 4553 std::vector<pxoffset> aPAPXOffsets(stcp); 4554 sal_uInt16 cbPapx; 4555 rSt >> cbPapx; 4556 nByteCount = 2; 4557 stcp=0; 4558 while (nByteCount < cbPapx) 4559 { 4560 sal_uInt8 cb; 4561 rSt >> cb; 4562 nByteCount++; 4563 4564 aPAPXOffsets[stcp].mnSize = 0; 4565 4566 if (cb != 0xFF) 4567 { 4568 sal_uInt8 stc2; 4569 rSt >> stc2; 4570 rSt.SeekRel(6); 4571 nByteCount+=7; 4572 sal_uInt8 nRemainder = cb-7; 4573 4574 aPAPXOffsets[stcp].mnOffset = rSt.Tell(); 4575 aPAPXOffsets[stcp].mnSize = nRemainder; 4576 4577 rSt.SeekRel(nRemainder); 4578 nByteCount += nRemainder; 4579 } 4580 4581 stcp++; 4582 4583 if (stcp == nStyles) 4584 { 4585 rSt.SeekRel(cbPapx-nByteCount); 4586 nByteCount += cbPapx-nByteCount; 4587 } 4588 } 4589 4590 sal_uInt16 iMac; 4591 rSt >> iMac; 4592 4593 if (iMac > nStyles) iMac = nStyles; 4594 4595 for (stcp = 0; stcp < iMac; ++stcp) 4596 { 4597 sal_uInt8 stcNext, stcBase; 4598 rSt >> stcNext; 4599 rSt >> stcBase; 4600 4601 sal_uInt8 stc = static_cast< sal_uInt8 >((stcp - cstcStd) & 255); 4602 4603 /* 4604 #i64557# style based on itself 4605 every chain must end eventually at the null style (style code 222) 4606 */ 4607 if (stc == stcBase) 4608 stcBase = 222; 4609 4610 SwWW8StyInf &rSI = pIo->pCollA[stc]; 4611 rSI.nBase = stcBase; 4612 4613 ww::sti eSti = ww::GetCanonicalStiFromStc(stc); 4614 4615 if (eSti == ww::stiNil) 4616 continue; 4617 4618 rSI.bValid = true; 4619 4620 if (ww::StandardStiIsCharStyle(eSti) && !aPAPXOffsets[stcp].mnSize) 4621 pIo->pCollA[stc].bColl = false; 4622 4623 bool bOldNoImp = PrepareStyle(rSI, eSti, stc, stcNext); 4624 4625 ImportSprms(aPAPXOffsets[stcp].mnOffset, aPAPXOffsets[stcp].mnSize, 4626 true); 4627 4628 if (aConvertedChpx[stcp].size() > 0) 4629 ImportSprms(&(aConvertedChpx[stcp][0]), 4630 static_cast< short >(aConvertedChpx[stcp].size()), 4631 false); 4632 4633 PostStyle(rSI, bOldNoImp); 4634 } 4635 } 4636 4637 void WW8RStyle::ImportNewFormatStyles() 4638 { 4639 ScanStyles(); // Scanne Based On 4640 4641 for (sal_uInt16 i = 0; i < cstd; ++i) // import Styles 4642 if (pIo->pCollA[i].bValid) 4643 Import1Style( i ); 4644 } 4645 4646 void WW8RStyle::ImportStyles() 4647 { 4648 if (ww::eWW2 == pIo->pWwFib->GetFIBVersion()) 4649 ImportOldFormatStyles(); 4650 else 4651 ImportNewFormatStyles(); 4652 } 4653 4654 void WW8RStyle::Import() 4655 { 4656 pIo->pDfltTxtFmtColl = pIo->rDoc.GetDfltTxtFmtColl(); 4657 pIo->pStandardFmtColl = 4658 pIo->rDoc.GetTxtCollFromPool(RES_POOLCOLL_STANDARD, false); 4659 4660 if( pIo->nIniFlags & WW8FL_NO_STYLES ) 4661 return; 4662 4663 ImportStyles(); 4664 4665 for (sal_uInt16 i = 0; i < cstd; ++i) 4666 { 4667 // Follow chain 4668 SwWW8StyInf* pi = &pIo->pCollA[i]; 4669 sal_uInt16 j = pi->nFollow; 4670 if( j < cstd ) 4671 { 4672 SwWW8StyInf* pj = &pIo->pCollA[j]; 4673 if ( j != i // sinnvoller Index ? 4674 && pi->pFmt // Format ok ? 4675 && pj->pFmt // Derived-Format ok ? 4676 && pi->bColl // geht nur bei Absatz-Vorlagen (WW) 4677 && pj->bColl ){ // beides gleicher Typ ? 4678 ( (SwTxtFmtColl*)pi->pFmt )->SetNextTxtFmtColl( 4679 *(SwTxtFmtColl*)pj->pFmt ); // ok, eintragen 4680 } 4681 } 4682 } 4683 // Die Sonderbehandlung zur Setzen der 4684 // Default-Zeichenvorlage "Absatz-Standardschriftart" ( Style-ID 65 ) fehlt 4685 // Sie ist aber defaultmaessig leer ( WW6 dt und US ) und von der 4686 // WW-UI nicht zu veraendern, so dass das nicht stoert. 4687 // Der Mechanismus waere folgender: 4688 // if( bNew ) rDoc.SetDefault( pDefCharFmt->GetAttrSet() ); 4689 // 4690 // fuer z.B. Tabellen wird ein immer gueltiger Std-Style gebraucht 4691 4692 if( pIo->StyleExists(0) && pIo->pCollA[0].pFmt && pIo->pCollA[0].bColl && pIo->pCollA[0].bValid ) 4693 pIo->pDfltTxtFmtColl = (SwTxtFmtColl*)pIo->pCollA[0].pFmt; 4694 else 4695 pIo->pDfltTxtFmtColl = pIo->rDoc.GetDfltTxtFmtColl(); 4696 4697 4698 // set Hyphenation flag on BASIC para-style 4699 if (pIo->mbNewDoc && pIo->pStandardFmtColl) 4700 { 4701 if (pIo->pWDop->fAutoHyphen 4702 && SFX_ITEM_SET != pIo->pStandardFmtColl->GetItemState( 4703 RES_PARATR_HYPHENZONE, false) ) 4704 { 4705 SvxHyphenZoneItem aAttr(true, RES_PARATR_HYPHENZONE); 4706 aAttr.GetMinLead() = 2; 4707 aAttr.GetMinTrail() = 2; 4708 aAttr.GetMaxHyphens() = 0; 4709 4710 pIo->pStandardFmtColl->SetFmtAttr( aAttr ); 4711 } 4712 4713 /* 4714 Word defaults to ltr not from environment like writer. Regardless of 4715 the page/sections rtl setting the standard style lack of rtl still 4716 means ltr 4717 */ 4718 if (SFX_ITEM_SET != pIo->pStandardFmtColl->GetItemState(RES_FRAMEDIR, 4719 false)) 4720 { 4721 pIo->pStandardFmtColl->SetFmtAttr( 4722 SvxFrameDirectionItem(FRMDIR_HORI_LEFT_TOP, RES_FRAMEDIR)); 4723 } 4724 } 4725 4726 // wir sind jetzt nicht mehr beim Style einlesen: 4727 pIo->pAktColl = 0; 4728 } 4729 4730 CharSet SwWW8StyInf::GetCharSet() const 4731 { 4732 if ((pFmt) && (pFmt->GetFrmDir().GetValue() == FRMDIR_HORI_RIGHT_TOP)) 4733 return eRTLFontSrcCharSet; 4734 return eLTRFontSrcCharSet; 4735 } 4736 4737 CharSet SwWW8StyInf::GetCJKCharSet() const 4738 { 4739 if ((pFmt) && (pFmt->GetFrmDir().GetValue() == FRMDIR_HORI_RIGHT_TOP)) 4740 return eRTLFontSrcCharSet; 4741 return eCJKFontSrcCharSet; 4742 } 4743 4744 /* vi:set tabstop=4 shiftwidth=4 expandtab: */ 4745