update dev300-m58
[ooovba.git] / sw / source / filter / ww8 / ww8par2.cxx
blob0a65d9f52ccf51eaa2dc6f5dd0ade2bf95ac4f1f
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ww8par2.cxx,v $
10 * $Revision: 1.145.76.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
33 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
35 #include <tools/solar.h>
36 #include <vcl/vclenum.hxx>
37 #include <vcl/font.hxx>
38 #include <hintids.hxx>
39 #include <svx/colritem.hxx>
40 #include <svx/orphitem.hxx>
41 #include <svx/widwitem.hxx>
42 #include <svx/brshitem.hxx>
43 #include <svx/boxitem.hxx>
44 #include <svx/lrspitem.hxx>
45 #include <svx/fhgtitem.hxx>
46 #include <svx/fhgtitem.hxx>
47 #include <svx/hyznitem.hxx>
48 #include <svx/frmdiritem.hxx>
49 #include <svx/langitem.hxx>
50 #include <svx/charrotateitem.hxx>
51 #include <svx/pgrditem.hxx>
52 #include <msfilter.hxx>
53 #include <pam.hxx> // fuer SwPam
54 #include <doc.hxx>
55 #include <docary.hxx>
56 #include <ndtxt.hxx> // class SwTxtNode
57 #include <paratr.hxx> // SwNumRuleItem
58 #include <poolfmt.hxx> // RES_POOLCOLL_STANDARD
59 #include <swtable.hxx> // class SwTableLines, ...
60 #include <tblsel.hxx> // class _SwSelBox
61 #include <mdiexp.hxx>
62 #include <fmtpdsc.hxx>
63 #include <txtftn.hxx>
64 #include <frmfmt.hxx>
65 #include <ftnidx.hxx>
66 #include <fmtftn.hxx>
67 #include <charfmt.hxx>
68 #include <SwStyleNameMapper.hxx>
69 #include <fltshell.hxx> // fuer den Attribut Stack
70 #include <fmtanchr.hxx>
71 #include <fmtrowsplt.hxx>
72 // --> OD 2005-01-27 #i33818#
73 #include <fmtfollowtextflow.hxx>
74 // <--
75 #include <numrule.hxx>
76 # include "../inc/wwstyles.hxx"
77 # include "writerhelper.hxx"
78 #include "ww8struc.hxx" // struct TC
79 #include "ww8par.hxx"
80 #include "ww8par2.hxx"
82 #include <frmatr.hxx>
84 #include <iostream>
86 #define MAX_COL 64 // WW6-Beschreibung: 32, WW6-UI: 31 & WW8-UI: 63!
88 using namespace ::com::sun::star;
91 class WW8SelBoxInfo: public SwSelBoxes_SAR
93 private:
94 WW8SelBoxInfo(const WW8SelBoxInfo&);
95 WW8SelBoxInfo& operator=(const WW8SelBoxInfo&);
96 public:
97 short nGroupXStart;
98 short nGroupWidth;
99 bool bGroupLocked;
101 WW8SelBoxInfo(short nXCenter, short nWidth)
102 : nGroupXStart( nXCenter ), nGroupWidth( nWidth ), bGroupLocked(false)
106 typedef WW8SelBoxInfo* WW8SelBoxInfoPtr;
108 SV_DECL_PTRARR_DEL(WW8MergeGroups, WW8SelBoxInfoPtr, 16,16)
109 SV_IMPL_PTRARR(WW8MergeGroups, WW8SelBoxInfoPtr)
111 struct WW8TabBandDesc
113 WW8TabBandDesc* pNextBand;
114 short nGapHalf;
115 short mnDefaultLeft;
116 short mnDefaultTop;
117 short mnDefaultRight;
118 short mnDefaultBottom;
119 bool mbHasSpacing;
120 short nLineHeight;
121 short nRows;
122 sal_uInt16 maDirections[MAX_COL + 1];
123 short nCenter[MAX_COL + 1]; // X-Rand aller Zellen dieses Bandes
124 short nWidth[MAX_COL + 1]; // Laenge aller Zellen dieses Bandes
125 short nWwCols; // BYTE wuerde reichen, alignment -> short
126 short nSwCols; // SW: so viele Spalten fuer den Writer
127 bool bLEmptyCol; // SW: Links eine leere Zusatz-Spalte
128 bool bREmptyCol; // SW: dito rechts
129 bool bCantSplit;
130 bool bCantSplit90;
131 WW8_TCell* pTCs;
132 BYTE nOverrideSpacing[MAX_COL + 1];
133 short nOverrideValues[MAX_COL + 1][4];
134 WW8_SHD* pSHDs;
135 sal_uInt32* pNewSHDs;
136 WW8_BRC aDefBrcs[6];
139 // nur fuer WW6-7: diese Zelle hat WW-Flag bMerged (horizontal) gesetzt
140 //bool bWWMergedVer6[MAX_COL];
143 bool bExist[MAX_COL]; // Existiert diese Zelle ?
144 UINT8 nTransCell[MAX_COL + 2]; // UEbersetzung WW-Index -> SW-Index
146 WW8TabBandDesc();
147 WW8TabBandDesc(WW8TabBandDesc& rBand); // tief kopieren
148 ~WW8TabBandDesc();
149 static void setcelldefaults(WW8_TCell *pCells, short nCells);
150 void ReadDef(bool bVer67, const BYTE* pS);
151 void ProcessDirection(const BYTE* pParams);
152 void ProcessSprmTSetBRC(bool bVer67, const BYTE* pParamsTSetBRC);
153 void ProcessSprmTTableBorders(bool bVer67, const BYTE* pParams);
154 void ProcessSprmTDxaCol(const BYTE* pParamsTDxaCol);
155 void ProcessSprmTDelete(const BYTE* pParamsTDelete);
156 void ProcessSprmTInsert(const BYTE* pParamsTInsert);
157 void ProcessSpacing(const BYTE* pParamsTInsert);
158 void ProcessSpecificSpacing(const BYTE* pParamsTInsert);
159 void ReadShd(const BYTE* pS );
160 void ReadNewShd(const BYTE* pS, bool bVer67);
162 enum wwDIR {wwTOP = 0, wwLEFT = 1, wwBOTTOM = 2, wwRIGHT = 3};
165 WW8TabBandDesc::WW8TabBandDesc()
167 memset(this, 0, sizeof(*this));
168 for (size_t i = 0; i < sizeof(maDirections)/sizeof(sal_uInt16); ++i)
169 maDirections[i] = 4;
172 WW8TabBandDesc::~WW8TabBandDesc()
174 delete[] pTCs;
175 delete[] pSHDs;
176 delete[] pNewSHDs;
179 class WW8TabDesc
181 std::vector<String> aNumRuleNames;
182 sw::util::RedlineStack *mpOldRedlineStack;
184 SwWW8ImplReader* pIo;
186 WW8TabBandDesc* pFirstBand;
187 WW8TabBandDesc* pActBand;
189 SwPosition* pTmpPos;
191 SwTableNode* pTblNd; // Tabellen-Node
192 const SwTableLines* pTabLines; // Zeilen-Array davon
193 SwTableLine* pTabLine; // akt. Zeile
194 SwTableBoxes* pTabBoxes; // Boxen-Array in akt. Zeile
195 SwTableBox* pTabBox; // akt. Zelle
197 WW8MergeGroups* pMergeGroups; // Listen aller zu verknuepfenden Zellen
199 WW8_TCell* pAktWWCell;
201 short nRows;
202 short nDefaultSwCols;
203 short nBands;
204 short nMinLeft;
205 short nConvertedLeft;
206 short nMaxRight;
207 short nSwWidth;
208 short nPreferredWidth;
209 short nOrgDxaLeft;
211 bool bOk;
212 bool bClaimLineFmt;
213 sal_Int16 eOri;
214 bool bIsBiDi;
215 // 2. allgemeine Verwaltungsinfo
216 short nAktRow;
217 short nAktBandRow; // SW: in dieser Zeile des akt. Bandes bin ich
218 // 3. Verwaltungsinfo fuer Writer
219 short nAktCol;
221 USHORT nRowsToRepeat;
223 // 4. Methoden
225 USHORT GetLogicalWWCol() const;
226 void SetTabBorders( SwTableBox* pBox, short nIdx );
227 void SetTabShades( SwTableBox* pBox, short nWwIdx );
228 void SetTabVertAlign( SwTableBox* pBox, short nWwIdx );
229 void SetTabDirection( SwTableBox* pBox, short nWwIdx );
230 void CalcDefaults();
231 bool SetPamInCell(short nWwCol, bool bPam);
232 void InsertCells( short nIns );
233 void AdjustNewBand();
235 // durchsucht pMergeGroups, meldet Index der ersten, passenden Gruppe bzw.
236 // -1 Details siehe bei der Implementierung
237 bool FindMergeGroup(short nX1, short nWidth, bool bExact, short& nMGrIdx);
239 // einzelne Box ggfs. in eine Merge-Gruppe aufnehmen
240 // (die Merge-Gruppen werden dann spaeter auf einen Schlag abgearbeitet)
241 SwTableBox* UpdateTableMergeGroup(WW8_TCell& rCell,
242 WW8SelBoxInfo* pActGroup, SwTableBox* pActBox, USHORT nCol );
243 void StartMiserableHackForUnsupportedDirection(short nWwCol);
244 void EndMiserableHackForUnsupportedDirection(short nWwCol);
245 //No copying
246 WW8TabDesc(const WW8TabDesc&);
247 WW8TabDesc &operator=(const WW8TabDesc&);
248 public:
249 const SwTable* pTable; // Tabelle
250 SwPosition* pParentPos;
251 SwFlyFrmFmt* pFlyFmt;
252 SfxItemSet aItemSet;
253 bool IsValidCell(short nCol) const;
254 bool InFirstParaInCell() const;
256 WW8TabDesc( SwWW8ImplReader* pIoClass, WW8_CP nStartCp );
257 bool Ok() const { return bOk; }
258 void CreateSwTable();
259 void UseSwTable();
260 void SetSizePosition(SwFrmFmt* pFrmFmt);
261 void TableCellEnd();
262 void MoveOutsideTable();
263 void ParkPaM();
264 void FinishSwTable();
265 void MergeCells();
266 short GetMinLeft() const { return nConvertedLeft; }
267 ~WW8TabDesc();
268 SwPosition *GetPos() { return pTmpPos; }
270 const WW8_TCell* GetAktWWCell() const { return pAktWWCell; }
271 short GetAktCol() const { return nAktCol; }
272 // find name of numrule valid for current WW-COL
273 const String& GetNumRuleName() const;
274 void SetNumRuleName( const String& rName );
276 sw::util::RedlineStack* getOldRedlineStack(){ return mpOldRedlineStack; }
279 void sw::util::RedlineStack::close( const SwPosition& rPos,
280 RedlineType_t eType, WW8TabDesc* pTabDesc )
282 // If the redline type is not found in the redline stack, we have to check if there has been
283 // a tabledesc and to check its saved redline stack, too. (#136939, #i68139)
284 if( !close( rPos, eType ) )
286 if( pTabDesc && pTabDesc->getOldRedlineStack() )
288 #ifndef PRODUCT
289 ASSERT( pTabDesc->getOldRedlineStack()->close(rPos, eType), "close without open!");
290 #else
291 pTabDesc->getOldRedlineStack()->close( rPos, eType );
292 #endif
298 void wwSectionManager::SetCurrentSectionHasFootnote()
300 ASSERT(!maSegments.empty(),
301 "should not be possible, must be at least one segment");
302 if (!maSegments.empty())
303 maSegments.back().mbHasFootnote = true;
306 bool wwSectionManager::CurrentSectionIsVertical() const
308 ASSERT(!maSegments.empty(),
309 "should not be possible, must be at least one segment");
310 if (!maSegments.empty())
311 return maSegments.back().IsVertical();
312 return false;
315 bool wwSectionManager::CurrentSectionIsProtected() const
317 ASSERT(!maSegments.empty(),
318 "should not be possible, must be at least one segment");
319 if (!maSegments.empty())
320 return SectionIsProtected(maSegments.back());
321 return false;
324 sal_uInt32 wwSectionManager::GetPageLeft() const
326 return !maSegments.empty() ? maSegments.back().nPgLeft : 0;
329 sal_uInt32 wwSectionManager::GetPageRight() const
331 return !maSegments.empty() ? maSegments.back().nPgRight : 0;
334 sal_uInt32 wwSectionManager::GetPageWidth() const
336 return !maSegments.empty() ? maSegments.back().GetPageWidth() : 0;
339 sal_uInt32 wwSectionManager::GetTextAreaWidth() const
341 return !maSegments.empty() ? maSegments.back().GetTextAreaWidth() : 0;
344 // --> OD 2007-07-03 #148498#
345 sal_uInt32 wwSectionManager::GetWWPageTopMargin() const
347 return !maSegments.empty() ? maSegments.back().maSep.dyaTop : 0;
349 // <--
351 sal_uInt16 SwWW8ImplReader::End_Ftn()
354 #84095#
355 Ignoring Footnote outside of the normal Text. People will put footnotes
356 into field results and field commands.
358 if (bIgnoreText ||
359 pPaM->GetPoint()->nNode < rDoc.GetNodes().GetEndOfExtras().GetIndex())
361 return 0;
364 ASSERT(!maFtnStack.empty(), "footnote end without start");
365 if (maFtnStack.empty())
366 return 0;
368 bool bFtEdOk = false;
369 const FtnDescriptor &rDesc = maFtnStack.back();
371 //Get the footnote character and remove it from the txtnode. We'll
372 //replace it with the footnote
373 SwTxtNode* pTxt = pPaM->GetNode()->GetTxtNode();
374 xub_StrLen nPos = pPaM->GetPoint()->nContent.GetIndex();
376 String sChar;
377 SwTxtAttr* pFN = 0;
378 //There should have been a footnote char, we will replace this.
379 if (pTxt && nPos)
381 sChar.Append(pTxt->GetTxt().GetChar(--nPos));
382 pPaM->SetMark();
383 pPaM->GetMark()->nContent--;
384 rDoc.Delete( *pPaM );
385 pPaM->DeleteMark();
386 SwFmtFtn aFtn(rDesc.meType == MAN_EDN);
387 pFN = pTxt->InsertItem(aFtn, nPos, nPos);
389 ASSERT(pFN, "Probleme beim Anlegen des Fussnoten-Textes");
390 if (pFN)
393 SwPosition aTmpPos( *pPaM->GetPoint() ); // merke alte Cursorposition
394 WW8PLCFxSaveAll aSave;
395 pPlcxMan->SaveAllPLCFx( aSave );
396 WW8PLCFMan* pOldPlcxMan = pPlcxMan;
398 const SwNodeIndex* pSttIdx = ((SwTxtFtn*)pFN)->GetStartNode();
399 ASSERT(pSttIdx, "Probleme beim Anlegen des Fussnoten-Textes");
401 ((SwTxtFtn*)pFN)->SetSeqNo( rDoc.GetFtnIdxs().Count() );
403 bool bOld = bFtnEdn;
404 bFtnEdn = true;
406 // read content of Ft-/End-Note
407 Read_HdFtFtnText( pSttIdx, rDesc.mnStartCp, rDesc.mnLen, rDesc.meType);
408 bFtEdOk = true;
409 bFtnEdn = bOld;
411 ASSERT(sChar.Len()==1 && ((rDesc.mbAutoNum == (sChar.GetChar(0) == 2))),
412 "footnote autonumbering must be 0x02, and everthing else must not be");
414 // If no automatic numbering use the following char from the main text
415 // as the footnote number
416 if (!rDesc.mbAutoNum)
417 ((SwTxtFtn*)pFN)->SetNumber(0, &sChar);
420 Delete the footnote char from the footnote if its at the beginning
421 as usual. Might not be if the user has already deleted it, e.g.
422 #i14737#
424 SwNodeIndex& rNIdx = pPaM->GetPoint()->nNode;
425 rNIdx = pSttIdx->GetIndex() + 1;
426 SwTxtNode* pTNd = rNIdx.GetNode().GetTxtNode();
427 if (pTNd && pTNd->GetTxt().Len() && sChar.Len())
429 if (pTNd->GetTxt().GetChar(0) == sChar.GetChar(0))
431 pPaM->GetPoint()->nContent.Assign( pTNd, 0 );
432 pPaM->SetMark();
433 // Strip out tabs we may have inserted on export #i24762#
434 if (pTNd->GetTxt().GetChar(1) == 0x09)
435 pPaM->GetMark()->nContent++;
436 pPaM->GetMark()->nContent++;
437 pReffingStck->Delete(*pPaM);
438 rDoc.Delete( *pPaM );
439 pPaM->DeleteMark();
443 *pPaM->GetPoint() = aTmpPos; // restore Cursor
445 pPlcxMan = pOldPlcxMan; // Restore attributes
446 pPlcxMan->RestoreAllPLCFx( aSave );
449 if (bFtEdOk)
450 maSectionManager.SetCurrentSectionHasFootnote();
452 maFtnStack.pop_back();
453 return 0;
456 long SwWW8ImplReader::Read_Ftn(WW8PLCFManResult* pRes)
459 #84095#
460 Ignoring Footnote outside of the normal Text. People will put footnotes
461 into field results and field commands.
463 if (bIgnoreText ||
464 pPaM->GetPoint()->nNode < rDoc.GetNodes().GetEndOfExtras().GetIndex())
466 return 0;
469 FtnDescriptor aDesc;
470 aDesc.mbAutoNum = true;
471 if (eEDN == pRes->nSprmId)
473 aDesc.meType = MAN_EDN;
474 if (pPlcxMan->GetEdn())
475 aDesc.mbAutoNum = 0 != *(short*)pPlcxMan->GetEdn()->GetData();
477 else
479 aDesc.meType = MAN_FTN;
480 if (pPlcxMan->GetFtn())
481 aDesc.mbAutoNum = 0 != *(short*)pPlcxMan->GetFtn()->GetData();
484 aDesc.mnStartCp = pRes->nCp2OrIdx;
485 aDesc.mnLen = pRes->nMemLen;
487 maFtnStack.push_back(aDesc);
489 return 0;
492 bool SwWW8ImplReader::SearchRowEnd(WW8PLCFx_Cp_FKP* pPap, WW8_CP &rStartCp,
493 int nLevel) const
495 WW8PLCFxDesc aRes;
496 aRes.pMemPos = 0;
497 aRes.nEndPos = rStartCp;
499 while (pPap->HasFkp() && rStartCp != WW8_CP_MAX)
501 if (pPap->Where() != WW8_CP_MAX)
503 const BYTE* pB = pPap->HasSprm(TabRowSprm(nLevel));
504 if (pB && *pB == 1)
506 const BYTE *pLevel = 0;
507 if (0 != (pLevel = pPap->HasSprm(0x6649)))
509 if (nLevel + 1 == *pLevel)
510 return true;
512 else
514 ASSERT(!nLevel || pLevel, "sublevel without level sprm");
515 return true; // RowEnd found
520 aRes.nStartPos = aRes.nEndPos;
521 aRes.pMemPos = 0;
522 //Seek to our next block of properties
523 if (!(pPap->SeekPos(aRes.nStartPos)))
525 aRes.nEndPos = WW8_CP_MAX;
526 pPap->SetDirty(true);
528 pPap->GetSprms(&aRes);
529 pPap->SetDirty(false);
530 //Update our aRes to get the new starting point of the next properties
531 rStartCp = aRes.nEndPos;
534 return false;
537 ApoTestResults SwWW8ImplReader::TestApo(int nCellLevel, bool bTableRowEnd,
538 const WW8_TablePos *pTabPos)
540 const WW8_TablePos *pTopLevelTable = nCellLevel <= 1 ? pTabPos : 0;
541 ApoTestResults aRet;
542 // Frame in Style Definition (word appears to ignore them if inside an
543 // text autoshape, e.g. #94418#)
544 if (!bTxbxFlySection)
545 aRet.mpStyleApo = StyleExists(nAktColl) ? pCollA[nAktColl].pWWFly : 0;
548 #i1140#
549 If I have a table and apply a style to one of its frames that should cause
550 a paragraph that its applied to it to only exist as a seperate floating
551 frame, then the behavour depends on which cell that it has been applied
552 to. If its the first cell of a row then the whole table row jumps into the
553 new frame, if its not then then the paragraph attributes are applied
554 "except" for the floating frame stuff. i.e. its ignored. So if theres a
555 table, and we're not in the first cell then we ignore the fact that the
556 paragraph style wants to be in a different frame.
558 This sort of mindbending inconsistency is surely why frames are deprecated
559 in word 97 onwards and hidden away from the user
562 #i1532# & #i5379#
563 If we are already a table in a frame then we must grab the para properties
564 to see if we are still in that frame.
567 aRet.mpSprm37 = pPlcxMan->HasParaSprm( bVer67 ? 37 : 0x2423 );
568 aRet.mpSprm29 = pPlcxMan->HasParaSprm( bVer67 ? 29 : 0x261B );
570 // Is there some frame data here
571 bool bNowApo = aRet.HasFrame() || pTopLevelTable;
572 if (bNowApo)
574 if (WW8FlyPara *pTest = ConstructApo(aRet, pTabPos))
575 delete pTest;
576 else
577 bNowApo = false;
580 bool bTestAllowed = !bTxbxFlySection && !bTableRowEnd;
581 if (bTestAllowed)
583 //Test is allowed if there is no table.
584 //Otherwise only allowed if we are in the
585 //first paragraph of the first cell of a row.
586 //(And only if the row we are inside is at the
587 //same level as the previous row, think tables
588 //in tables)
589 if (nCellLevel == nInTable)
592 if (!nInTable)
593 bTestAllowed = true;
594 else
596 if (!pTableDesc)
598 ASSERT(pTableDesc, "What!");
599 bTestAllowed = false;
601 else
603 // --> OD 2005-02-01 #i39468#
604 // If current cell isn't valid, the test is allowed.
605 // The cell isn't valid, if e.g. there is a new row
606 // <pTableDesc->nAktRow> >= <pTableDesc->pTabLines->Count()>
607 bTestAllowed =
608 pTableDesc->GetAktCol() == 0 &&
609 ( !pTableDesc->IsValidCell( pTableDesc->GetAktCol() ) ||
610 pTableDesc->InFirstParaInCell() );
611 // <--
617 if (!bTestAllowed)
618 return aRet;
620 aRet.mbStartApo = bNowApo && !InAnyApo(); // APO-start
621 aRet.mbStopApo = InEqualOrHigherApo(nCellLevel) && !bNowApo; // APO-end
623 //If it happens that we are in a table, then if its not the first cell
624 //then any attributes that might otherwise cause the contents to jump
625 //into another frame don't matter, a table row sticks together as one
626 //unit no matter what else happens. So if we are not in a table at
627 //all, or if we are in the first cell then test that the last frame
628 //data is the same as the current one
629 if (bNowApo && InEqualApo(nCellLevel))
631 // two bordering eachother
632 if (!TestSameApo(aRet, pTabPos))
633 aRet.mbStopApo = aRet.mbStartApo = true;
636 return aRet;
638 //---------------------------------------------------------------------
639 // Hilfroutinen fuer Kapitelnummerierung und Aufzaehlung / Gliederung
640 //---------------------------------------------------------------------
642 static void SetBaseAnlv(SwNumFmt &rNum, WW8_ANLV &rAV, BYTE nSwLevel )
644 static SvxExtNumType eNumA[8] = { SVX_NUM_ARABIC, SVX_NUM_ROMAN_UPPER, SVX_NUM_ROMAN_LOWER,
645 SVX_NUM_CHARS_UPPER_LETTER_N, SVX_NUM_CHARS_LOWER_LETTER_N, SVX_NUM_ARABIC,
646 SVX_NUM_ARABIC, SVX_NUM_ARABIC };
648 static SvxAdjust eAdjA[4] = { SVX_ADJUST_LEFT,
649 SVX_ADJUST_RIGHT, SVX_ADJUST_LEFT, SVX_ADJUST_LEFT };
650 // eigentlich folgende 2, aber Writer-UI bietet es nicht an
651 // SVX_ADJUST_CENTER, SVX_ADJUST_BLOCKLINE };
653 rNum.SetNumberingType( static_cast< sal_Int16 >(( SVBT8ToByte( rAV.nfc ) < 8 ) ?
654 eNumA[SVBT8ToByte( rAV.nfc ) ] : SVX_NUM_NUMBER_NONE) );
655 if ((SVBT8ToByte(rAV.aBits1 ) & 0x4) >> 2)
656 rNum.SetIncludeUpperLevels(nSwLevel + 1);
657 rNum.SetStart( SVBT16ToShort( rAV.iStartAt ) );
658 // rNum.eNumAdjust = eAdjA[rAV.jc];
659 rNum.SetNumAdjust( eAdjA[SVBT8ToByte( rAV.aBits1 ) & 0x3] );
661 rNum.SetCharTextDistance( SVBT16ToShort( rAV.dxaSpace ) );
662 INT16 nIndent = Abs((INT16)SVBT16ToShort( rAV.dxaIndent ));
663 if( SVBT8ToByte( rAV.aBits1 ) & 0x08 ) //fHang
665 rNum.SetFirstLineOffset( -nIndent );
666 rNum.SetLSpace( nIndent );
667 rNum.SetAbsLSpace( nIndent );
669 else
670 rNum.SetCharTextDistance( nIndent ); // Breite der Nummer fehlt
672 if( SVBT8ToByte( rAV.nfc ) == 5 || SVBT8ToByte( rAV.nfc ) == 7 )
674 String sP( rNum.GetSuffix() );
675 sP.Insert( '.', 0 );
676 rNum.SetSuffix( sP ); // Ordinalzahlen
680 void SwWW8ImplReader::SetAnlvStrings(SwNumFmt &rNum, WW8_ANLV &rAV,
681 const BYTE* pTxt, bool bOutline)
683 bool bInsert = false; // Default
684 CharSet eCharSet = eStructCharSet;
686 const WW8_FFN* pF = pFonts->GetFont(SVBT16ToShort(rAV.ftc)); // FontInfo
687 bool bListSymbol = pF && ( pF->chs == 2 ); // Symbol/WingDings/...
689 String sTxt;
690 if (bVer67)
692 sTxt = String( (sal_Char*)pTxt, SVBT8ToByte( rAV.cbTextBefore )
693 + SVBT8ToByte( rAV.cbTextAfter ), eCharSet );
695 else
697 for(xub_StrLen i = SVBT8ToByte(rAV.cbTextBefore);
698 i < SVBT8ToByte(rAV.cbTextAfter); ++i, pTxt += 2)
700 sTxt.Append(SVBT16ToShort(*(SVBT16*)pTxt));
704 if( bOutline )
705 { // Gliederung
706 if( !rNum.GetIncludeUpperLevels() // es sind <= 1 Nummern anzuzeigen
707 || rNum.GetNumberingType() == SVX_NUM_NUMBER_NONE ){ // oder dieser Level hat keine
708 // eigenen Ziffern
709 bInsert = true; // -> dann uebernehme Zeichen
711 // replace by simple Bullet ?
712 if( bListSymbol )
713 //JP 14.08.96: cBulletChar benutzen, damit auf dem MAC
714 // richtig gemappt wird
715 sTxt.Fill( SVBT8ToByte( rAV.cbTextBefore )
716 + SVBT8ToByte( rAV.cbTextAfter ), cBulletChar );
719 else
720 { // Nummerierung / Aufzaehlung
721 bInsert = true;
722 // if( SVBT16ToShort( rAV.ftc ) == 1
723 // || SVBT16ToShort( rAV.ftc ) == 3 ){ // Symbol / WingDings
724 if( bListSymbol )
726 FontFamily eFamily;
727 String aName;
728 FontPitch ePitch;
730 if( GetFontParams( SVBT16ToShort( rAV.ftc ), eFamily, aName,
731 ePitch, eCharSet ) ){
732 // USHORT nSiz = ( SVBT16ToShort( rAV.hps ) ) ?
733 // SVBT16ToShort( rAV.hps ) : 24; // Groesse in 1/2 Pt
734 // darf nach JP nicht gesetzt werden, da immer die Size
735 // genommen wird, die am ZeilenAnfang benutzt wird
736 Font aFont;
737 aFont.SetName( aName );
738 aFont.SetFamily( eFamily );
739 // aFont.SetPitch( ePitch ); // darf nach JP nicht
740 aFont.SetCharSet( eCharSet );
741 rNum.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
742 // if( rAV.ico ) // geht in UI und SWG-Writer/Reader nicht
743 // aFont.SetColor( Color( GetCol( rAV.ico ) ) );
744 rNum.SetBulletFont( &aFont );
746 // take only the very first character
747 if( rAV.cbTextBefore || rAV.cbTextAfter)
748 rNum.SetBulletChar( sTxt.GetChar( 0 ) );
749 else
750 rNum.SetBulletChar( 0x2190 );
754 if( bInsert )
756 if( rAV.cbTextBefore )
758 String sP( sTxt.Copy( 0, SVBT8ToByte( rAV.cbTextBefore ) ) );
759 rNum.SetPrefix( sP );
761 if( SVBT8ToByte( rAV.cbTextAfter ) )
763 String sP( rNum.GetSuffix() );
764 sP.Insert( sTxt.Copy( SVBT8ToByte( rAV.cbTextBefore ),
765 SVBT8ToByte( rAV.cbTextAfter ) ) );
766 rNum.SetSuffix( sP );
768 // Die Zeichen vor und hinter mehreren Ziffern koennen leider nicht uebernommen
769 // werden, da sie der Writer ganz anders behandelt und das Ergebnis i.A.
770 // schlechter als ohne waere.
774 // SetAnld bekommt einen WW-ANLD-Descriptor und einen Level und modifiziert
775 // die durch pNumR anggebeben NumRules. Wird benutzt fuer alles ausser
776 // Gliederung im Text
777 void SwWW8ImplReader::SetAnld(SwNumRule* pNumR, WW8_ANLD* pAD, BYTE nSwLevel,
778 bool bOutLine)
780 SwNumFmt aNF;
781 if (pAD)
782 { // Es gibt einen Anld-Sprm
783 bAktAND_fNumberAcross = 0 != SVBT8ToByte( pAD->fNumberAcross );
784 WW8_ANLV &rAV = pAD->eAnlv;
785 SetBaseAnlv(aNF, rAV, nSwLevel); // Setze Basis-Format
786 SetAnlvStrings(aNF, rAV, pAD->rgchAnld, bOutLine );// und Rest
788 pNumR->Set(nSwLevel, aNF);
791 //-------------------------------------------------------
792 // Kapitelnummerierung und Kapitelbullets
793 //-------------------------------------------------------
794 // Kapitelnummerierung findet in Styledefinionen statt. Sprm 13 gibt den Level
795 // an, Sprm 12 den Inhalt
797 SwNumRule* SwWW8ImplReader::GetStyRule()
799 if( pStyles->pStyRule ) // Bullet-Style bereits vorhanden
800 return pStyles->pStyRule;
802 const String aBaseName(CREATE_CONST_ASC( "WW8StyleNum" ));
803 const String aName( rDoc.GetUniqueNumRuleName( &aBaseName, false) );
805 // --> OD 2008-06-04 #i86652#
806 // USHORT nRul = rDoc.MakeNumRule( aName );
807 USHORT nRul = rDoc.MakeNumRule( aName, 0, FALSE,
808 SvxNumberFormat::LABEL_ALIGNMENT );
809 // <--
810 pStyles->pStyRule = rDoc.GetNumRuleTbl()[nRul];
811 // Auto == false-> Nummerierungsvorlage
812 pStyles->pStyRule->SetAutoRule(false);
814 return pStyles->pStyRule;
817 // Sprm 13
818 void SwWW8ImplReader::Read_ANLevelNo( USHORT, const BYTE* pData, short nLen )
820 nSwNumLevel = 0xff; // Default: ungueltig
822 if( nLen <= 0 )
823 return;
825 // StyleDef ?
826 if( pAktColl )
828 // nur fuer SwTxtFmtColl, nicht CharFmt
829 // WW: 0 = no Numbering
830 if (pCollA[nAktColl].bColl && *pData)
832 // Bereich WW:1..9 -> SW:0..8 keine Aufzaehlung / Nummerierung
834 if (*pData <= MAXLEVEL && *pData <= 9)
836 nSwNumLevel = *pData - 1;
837 if (!bNoAttrImport)
838 //((SwTxtFmtColl*)pAktColl)->SetOutlineLevel( nSwNumLevel ); //#outline level,zhaojianwei
839 ((SwTxtFmtColl*)pAktColl)->AssignToListLevelOfOutlineStyle( nSwNumLevel ); //<-end,zhaojianwei
840 // Bei WW-NoNumbering koennte auch NO_NUMBERING gesetzt
841 // werden. ( Bei normaler Nummerierung muss NO_NUM gesetzt
842 // werden: NO_NUM : Nummerierungs-Pause,
843 // NO_NUMBERING : ueberhaupt keine Nummerierung )
846 else if( *pData == 10 || *pData == 11 )
848 // Typ merken, der Rest geschieht bei Sprm 12
849 pStyles->nWwNumLevel = *pData;
853 else
855 //Not StyleDef
856 if (!bAnl)
857 StartAnl(pData); // Anfang der Gliederung / Aufzaehlung
858 NextAnlLine(pData);
862 void SwWW8ImplReader::Read_ANLevelDesc( USHORT, const BYTE* pData, short nLen ) // Sprm 12
864 if( !pAktColl || nLen <= 0 // nur bei Styledef
865 || !pCollA[nAktColl].bColl // CharFmt -> ignorieren
866 || ( nIniFlags & WW8FL_NO_OUTLINE ) ){
867 nSwNumLevel = 0xff;
868 return;
870 if( nSwNumLevel <= MAXLEVEL // Bereich WW:1..9 -> SW:0..8
871 && nSwNumLevel <= 9 ){ // keine Aufzaehlung / Nummerierung
873 // Falls bereits direkt oder durch
874 // Vererbung NumruleItems gesetzt sind,
875 // dann jetzt ausschalten #56163
876 pAktColl->SetFmtAttr( SwNumRuleItem() );
878 String aName(CREATE_CONST_ASC( "Outline" ));
879 // --> OD 2008-02-11 #newlistlevelattrs#
880 SwNumRule aNR( rDoc.GetUniqueNumRuleName( &aName ),
881 SvxNumberFormat::LABEL_WIDTH_AND_POSITION,
882 OUTLINE_RULE );
883 // <--
884 aNR = *rDoc.GetOutlineNumRule();
886 SetAnld(&aNR, (WW8_ANLD*)pData, nSwNumLevel, true);
888 // fehlende Level muessen nicht aufgefuellt werden
890 rDoc.SetOutlineNumRule( aNR );
891 }else if( pStyles->nWwNumLevel == 10 || pStyles->nWwNumLevel == 11 ){
892 SwNumRule* pNR = GetStyRule();
893 SetAnld(pNR, (WW8_ANLD*)pData, 0, false);
894 pAktColl->SetFmtAttr( SwNumRuleItem( pNR->GetName() ) );
895 pCollA[nAktColl].bHasStyNumRule = true;
899 //-----------------------------------------
900 // Nummerierung / Aufzaehlung
901 //-----------------------------------------
903 // SetNumOlst() traegt die Numrules fuer diese Zeile ins SwNumFmt ein
904 // ( nur fuer Gliederungen im Text; Aufzaehlungen / Nummerierungen laufen
905 // ueber ANLDs )
906 // dabei wird die Info aus dem OLST geholt und nicht aus dem ANLD ( s.u. )
907 void SwWW8ImplReader::SetNumOlst(SwNumRule* pNumR, WW8_OLST* pO, BYTE nSwLevel)
909 SwNumFmt aNF;
910 WW8_ANLV &rAV = pO->rganlv[nSwLevel];
911 SetBaseAnlv(aNF, rAV, nSwLevel);
912 // ... und then the Strings
913 int nTxtOfs = 0;
914 BYTE i;
915 WW8_ANLV* pAV1; // search String-Positions
916 for (i = 0, pAV1 = pO->rganlv; i < nSwLevel; ++i, ++pAV1)
918 nTxtOfs += SVBT8ToByte(pAV1->cbTextBefore)
919 + SVBT8ToByte(pAV1->cbTextAfter);
922 if (!bVer67)
923 nTxtOfs *= 2;
924 SetAnlvStrings(aNF, rAV, pO->rgch + nTxtOfs, true); // und rein
925 pNumR->Set(nSwLevel, aNF);
928 // der OLST kommt am Anfang jeder Section, die Gliederungen enthaelt. Die ANLDs,
929 // die an jeder Gliederungszeile haengen, enthalten nur Stuss, also werden die
930 // OLSTs waehrend der Section gemerkt, damit die Informationen beim Auftreten
931 // von Gliederungsabsaetzen zugreifbar ist.
932 void SwWW8ImplReader::Read_OLST( USHORT, const BYTE* pData, short nLen )
934 if (nLen <= 0)
936 delete pNumOlst, pNumOlst = 0;
937 return;
939 if (pNumOlst)
940 delete pNumOlst; // nur sicherheitshalber
941 pNumOlst = new WW8_OLST;
942 if( nLen < sal::static_int_cast< sal_Int32 >(sizeof( WW8_OLST )) ) // auffuellen, falls zu kurz
943 memset( pNumOlst, 0, sizeof( *pNumOlst ) );
944 *pNumOlst = *(WW8_OLST*)pData;
947 WW8LvlType GetNumType(BYTE nWwLevelNo)
949 WW8LvlType nRet = WW8_None;
950 if( nWwLevelNo == 12 )
951 nRet = WW8_Pause;
952 else if( nWwLevelNo == 10 )
953 nRet = WW8_Numbering;
954 else if( nWwLevelNo == 11 )
955 nRet = WW8_Sequence;
956 else if( nWwLevelNo > 0 && nWwLevelNo <= 9 )
957 nRet = WW8_Outline;
958 return nRet;
961 SwNumRule *ANLDRuleMap::GetNumRule(BYTE nNumType)
963 return (WW8_Numbering == nNumType ? mpNumberingNumRule : mpOutlineNumRule);
966 void ANLDRuleMap::SetNumRule(SwNumRule *pRule, BYTE nNumType)
968 if (WW8_Numbering == nNumType)
969 mpNumberingNumRule = pRule;
970 else
971 mpOutlineNumRule = pRule;
975 // StartAnl wird am Anfang eines Zeilenbereichs gerufen,
976 // der Gliederung / Nummerierung / Aufzaehlung enthaelt
977 void SwWW8ImplReader::StartAnl(const BYTE* pSprm13)
979 bAktAND_fNumberAcross = false;
981 BYTE nT = static_cast< BYTE >(GetNumType(*pSprm13));
982 if (nT == WW8_Pause || nT == WW8_None)
983 return;
985 nWwNumType = nT;
986 SwNumRule *pNumRule = maANLDRules.GetNumRule(nWwNumType);
988 // check for COL numbering:
989 const BYTE* pS12 = 0;// sprmAnld
990 String sNumRule;
992 if (pTableDesc)
994 sNumRule = pTableDesc->GetNumRuleName();
995 if (sNumRule.Len())
997 pNumRule = rDoc.FindNumRulePtr(sNumRule);
998 if (!pNumRule)
999 sNumRule.Erase();
1000 else
1002 // this is ROW numbering ?
1003 pS12 = pPlcxMan->HasParaSprm(bVer67 ? 12 : 0xC63E); // sprmAnld
1004 if (pS12 && 0 != SVBT8ToByte(((WW8_ANLD*)pS12)->fNumberAcross))
1005 sNumRule.Erase();
1010 if (!sNumRule.Len() && pCollA[nAktColl].bHasStyNumRule)
1012 sNumRule = pCollA[nAktColl].pFmt->GetNumRule().GetValue();
1013 pNumRule = rDoc.FindNumRulePtr(sNumRule);
1014 if (!pNumRule)
1015 sNumRule.Erase();
1018 if (!sNumRule.Len())
1020 if (!pNumRule)
1022 // --> OD 2008-06-04 #i86652#
1023 // pNumRule = rDoc.GetNumRuleTbl()[rDoc.MakeNumRule(sNumRule)];
1024 pNumRule = rDoc.GetNumRuleTbl()[
1025 rDoc.MakeNumRule( sNumRule, 0, FALSE,
1026 SvxNumberFormat::LABEL_ALIGNMENT ) ];
1027 // <--
1029 if (pTableDesc)
1031 if (!pS12)
1032 pS12 = pPlcxMan->HasParaSprm(bVer67 ? 12 : 0xC63E); // sprmAnld
1033 if (!pS12 || !SVBT8ToByte( ((WW8_ANLD*)pS12)->fNumberAcross))
1034 pTableDesc->SetNumRuleName(pNumRule->GetName());
1038 bAnl = true;
1040 // NumRules ueber Stack setzen
1041 pCtrlStck->NewAttr(*pPaM->GetPoint(),
1042 SfxStringItem(RES_FLTR_NUMRULE, pNumRule->GetName()));
1044 maANLDRules.SetNumRule(pNumRule, nWwNumType);
1047 // NextAnlLine() wird fuer jede Zeile einer
1048 // Gliederung / Nummerierung / Aufzaehlung einmal gerufen
1049 void SwWW8ImplReader::NextAnlLine(const BYTE* pSprm13)
1051 if (!bAnl)
1052 return;
1054 SwNumRule *pNumRule = maANLDRules.GetNumRule(nWwNumType);
1056 // pNd->UpdateNum ohne Regelwerk gibt GPF spaetestens beim Speichern als
1057 // sdw3
1059 // WW:10 = Nummerierung -> SW:0 & WW:11 = Auffzaehlung -> SW:0
1060 if (*pSprm13 == 10 || *pSprm13 == 11)
1062 nSwNumLevel = 0;
1063 if (!pNumRule->GetNumFmt(nSwNumLevel))
1065 // noch nicht definiert
1066 // sprmAnld o. 0
1067 const BYTE* pS12 = pPlcxMan->HasParaSprm(bVer67 ? 12 : 0xC63E);
1068 SetAnld(pNumRule, (WW8_ANLD*)pS12, nSwNumLevel, false);
1071 else if( *pSprm13 > 0 && *pSprm13 <= MAXLEVEL ) // Bereich WW:1..9 -> SW:0..8
1073 nSwNumLevel = *pSprm13 - 1; // Gliederung
1074 // noch nicht definiert
1075 if (!pNumRule->GetNumFmt(nSwNumLevel))
1077 if (pNumOlst) // es gab ein OLST
1079 //Assure upper levels are set, #i9556#
1080 for (BYTE nI = 0; nI < nSwNumLevel; ++nI)
1082 if (!pNumRule->GetNumFmt(nI))
1083 SetNumOlst(pNumRule, pNumOlst, nI);
1086 SetNumOlst(pNumRule, pNumOlst , nSwNumLevel);
1088 else // kein Olst, nimm Anld
1090 // sprmAnld
1091 const BYTE* pS12 = pPlcxMan->HasParaSprm(bVer67 ? 12 : 0xC63E);
1092 SetAnld(pNumRule, (WW8_ANLD*)pS12, nSwNumLevel, false);
1096 else
1097 nSwNumLevel = 0xff; // keine Nummer
1099 SwTxtNode* pNd = pPaM->GetNode()->GetTxtNode();
1100 if (nSwNumLevel < MAXLEVEL)
1101 pNd->SetAttrListLevel( nSwNumLevel );
1102 else
1104 pNd->SetAttrListLevel(0);
1105 pNd->SetCountedInList( false );
1109 void SwWW8ImplReader::StopAllAnl(bool bGoBack)
1111 //Of course we're not restarting, but we'll make use of our knowledge
1112 //of the implementation to do it.
1113 StopAnlToRestart(WW8_None, bGoBack);
1116 void SwWW8ImplReader::StopAnlToRestart(BYTE nNewType, bool bGoBack)
1118 if (bGoBack)
1120 SwPosition aTmpPos(*pPaM->GetPoint());
1121 pPaM->Move(fnMoveBackward, fnGoCntnt);
1122 pCtrlStck->SetAttr(*pPaM->GetPoint(), RES_FLTR_NUMRULE);
1123 *pPaM->GetPoint() = aTmpPos;
1125 else
1126 pCtrlStck->SetAttr(*pPaM->GetPoint(), RES_FLTR_NUMRULE);
1128 maANLDRules.mpNumberingNumRule = 0;
1130 #i18816#
1131 my take on this problem is that moving either way from an outline to a
1132 numbering doesn't halt the outline, while the numbering is always halted
1134 bool bNumberingNotStopOutline =
1135 (((nWwNumType == WW8_Outline) && (nNewType == WW8_Numbering)) ||
1136 ((nWwNumType == WW8_Numbering) && (nNewType == WW8_Outline)));
1137 if (!bNumberingNotStopOutline)
1138 maANLDRules.mpOutlineNumRule = 0;
1140 nSwNumLevel = 0xff;
1141 nWwNumType = WW8_None;
1142 bAnl = false;
1145 WW8TabBandDesc::WW8TabBandDesc( WW8TabBandDesc& rBand )
1147 *this = rBand;
1148 if( rBand.pTCs )
1150 pTCs = new WW8_TCell[nWwCols];
1151 memcpy( pTCs, rBand.pTCs, nWwCols * sizeof( WW8_TCell ) );
1153 if( rBand.pSHDs )
1155 pSHDs = new WW8_SHD[nWwCols];
1156 memcpy( pSHDs, rBand.pSHDs, nWwCols * sizeof( WW8_SHD ) );
1158 if( rBand.pNewSHDs )
1160 pNewSHDs = new sal_uInt32[nWwCols];
1161 memcpy(pNewSHDs, rBand.pNewSHDs, nWwCols * sizeof(sal_uInt32));
1163 memcpy(aDefBrcs, rBand.aDefBrcs, sizeof(aDefBrcs));
1166 // ReadDef liest die Zellenpositionen und ggfs die Umrandungen eines Bandes ein
1167 void WW8TabBandDesc::ReadDef(bool bVer67, const BYTE* pS)
1169 if (!bVer67)
1170 pS++;
1172 short nLen = (INT16)SVBT16ToShort( pS - 2 ); // nicht schoen
1173 BYTE nCols = *pS; // Anzahl der Zellen
1174 short nOldCols = nWwCols;
1176 if( nCols > MAX_COL )
1177 return;
1179 nWwCols = nCols;
1181 const BYTE* pT = &pS[1];
1182 nLen --;
1183 int i;
1184 for(i=0; i<=nCols; i++, pT+=2 )
1185 nCenter[i] = (INT16)SVBT16ToShort( pT ); // X-Raender
1186 nLen -= 2 * ( nCols + 1 );
1187 if( nCols != nOldCols ) // andere Spaltenzahl
1189 delete[] pTCs, pTCs = 0;
1190 delete[] pSHDs, pSHDs = 0;
1191 delete[] pNewSHDs, pNewSHDs = 0;
1194 short nFileCols = nLen / ( bVer67 ? 10 : 20 ); // wirklich abgespeichert
1196 if (!pTCs && nCols)
1198 // lege leere TCs an
1199 pTCs = new WW8_TCell[nCols];
1200 setcelldefaults(pTCs,nCols);
1203 if( nFileCols )
1205 // lies TCs ein
1208 Achtung: ab Ver8 ist ein reserve-ushort je TC eingefuegt und auch
1209 der Border-Code ist doppelt so gross, daher ist hier
1210 kein simples kopieren moeglich,
1211 d.h.: pTCs[i] = *pTc; geht leider nicht.
1213 Vorteil: Arbeitstruktur ist jetzt viel bequemer zu handhaben!
1215 WW8_TCell* pAktTC = pTCs;
1216 if( bVer67 )
1218 WW8_TCellVer6* pTc = (WW8_TCellVer6*)pT;
1219 for(i=0; i<nFileCols; i++, ++pAktTC,++pTc)
1221 if( i < nFileCols )
1222 { // TC aus File ?
1223 BYTE aBits1 = SVBT8ToByte( pTc->aBits1Ver6 );
1224 pAktTC->bFirstMerged = ( ( aBits1 & 0x01 ) != 0 );
1225 pAktTC->bMerged = ( ( aBits1 & 0x02 ) != 0 );
1226 memcpy( pAktTC->rgbrc[ WW8_TOP ].aBits1,
1227 pTc->rgbrcVer6[ WW8_TOP ].aBits1, sizeof( SVBT16 ) );
1228 memcpy( pAktTC->rgbrc[ WW8_LEFT ].aBits1,
1229 pTc->rgbrcVer6[ WW8_LEFT ].aBits1, sizeof( SVBT16 ) );
1230 memcpy( pAktTC->rgbrc[ WW8_BOT ].aBits1,
1231 pTc->rgbrcVer6[ WW8_BOT ].aBits1, sizeof( SVBT16 ) );
1232 memcpy( pAktTC->rgbrc[ WW8_RIGHT ].aBits1,
1233 pTc->rgbrcVer6[ WW8_RIGHT ].aBits1, sizeof( SVBT16 ) );
1234 if( ( pAktTC->bMerged )
1235 && ( i > 0 ) )
1237 // Cell gemerged -> merken
1238 //bWWMergedVer6[i] = true;
1239 memcpy( pTCs[i-1].rgbrc[ WW8_RIGHT ].aBits1,
1240 pTc->rgbrcVer6[ WW8_RIGHT ].aBits1, sizeof( SVBT16 ) );
1241 // right Border in vorige Zelle uebernehmen
1242 // Hier darf bExist nicht auf false gesetzt werden, da WW
1243 // in den Textboxen diese Zellen nicht mitzaehlt....
1248 else
1250 WW8_TCellVer8* pTc = (WW8_TCellVer8*)pT;
1251 for (int k = 0; k < nFileCols; ++k, ++pAktTC, ++pTc )
1253 UINT16 aBits1 = SVBT16ToShort( pTc->aBits1Ver8 );
1254 pAktTC->bFirstMerged = ( ( aBits1 & 0x0001 ) != 0 );
1255 pAktTC->bMerged = ( ( aBits1 & 0x0002 ) != 0 );
1256 pAktTC->bVertical = ( ( aBits1 & 0x0004 ) != 0 );
1257 pAktTC->bBackward = ( ( aBits1 & 0x0008 ) != 0 );
1258 pAktTC->bRotateFont = ( ( aBits1 & 0x0010 ) != 0 );
1259 pAktTC->bVertMerge = ( ( aBits1 & 0x0020 ) != 0 );
1260 pAktTC->bVertRestart = ( ( aBits1 & 0x0040 ) != 0 );
1261 pAktTC->nVertAlign = ( ( aBits1 & 0x0180 ) >> 7 );
1262 // am Rande: im aBits1 verstecken sich noch 7 Reserve-Bits,
1263 // anschliessend folgen noch 16 weitere Reserve-Bits
1265 // In Version 8 koennen wir alle Bordercodes auf einmal kopieren!
1266 memcpy( pAktTC->rgbrc, pTc->rgbrcVer8, 4 * sizeof( WW8_BRC ) );
1270 // #i25071 In '97 text direction appears to be only set using TC properties
1271 // not with sprmTTextFlow so we need to cycle through the maDirections and
1272 // double check any non-default directions
1273 for (int k = 0; k < nCols; ++k)
1275 if(maDirections[k] == 4)
1277 if(pTCs[k].bVertical)
1279 if(pTCs[k].bBackward)
1280 maDirections[k] = 3;
1281 else
1282 maDirections[k] = 1;
1291 void WW8TabBandDesc::ProcessSprmTSetBRC(bool bVer67, const BYTE* pParamsTSetBRC)
1293 if( pParamsTSetBRC && pTCs ) // set one or more cell border(s)
1295 BYTE nitcFirst= pParamsTSetBRC[0];// first col to be changed
1296 BYTE nitcLim = pParamsTSetBRC[1];// (last col to be changed)+1
1297 BYTE nFlag = *(pParamsTSetBRC+2);
1299 bool bChangeRight = (nFlag & 0x08) ? true : false;
1300 bool bChangeBottom = (nFlag & 0x04) ? true : false;
1301 bool bChangeLeft = (nFlag & 0x02) ? true : false;
1302 bool bChangeTop = (nFlag & 0x01) ? true : false;
1304 WW8_TCell* pAktTC = pTCs + nitcFirst;
1305 if( bVer67 )
1307 WW8_BRCVer6* pBRC = (WW8_BRCVer6*)(pParamsTSetBRC+3);
1309 for( int i = nitcFirst; i < nitcLim; i++, ++pAktTC )
1311 if( bChangeTop )
1312 memcpy( pAktTC->rgbrc[ WW8_TOP ].aBits1,
1313 pBRC->aBits1,
1314 sizeof( SVBT16 ) );
1315 if( bChangeLeft )
1316 memcpy( pAktTC->rgbrc[ WW8_LEFT ].aBits1,
1317 pBRC->aBits1,
1318 sizeof( SVBT16 ) );
1319 if( bChangeBottom )
1320 memcpy( pAktTC->rgbrc[ WW8_BOT ].aBits1,
1321 pBRC->aBits1,
1322 sizeof( SVBT16 ) );
1323 if( bChangeRight )
1324 memcpy( pAktTC->rgbrc[ WW8_RIGHT].aBits1,
1325 pBRC->aBits1,
1326 sizeof( SVBT16 ) );
1329 else
1331 WW8_BRC* pBRC = (WW8_BRC*)(pParamsTSetBRC+3);
1333 for( int i = nitcFirst; i < nitcLim; i++, ++pAktTC )
1335 if( bChangeTop )
1336 memcpy( pAktTC->rgbrc[ WW8_TOP ].aBits1,
1337 pBRC->aBits1,
1338 sizeof( WW8_BRC ) );
1339 if( bChangeLeft )
1340 memcpy( pAktTC->rgbrc[ WW8_LEFT ].aBits1,
1341 pBRC->aBits1,
1342 sizeof( WW8_BRC ) );
1343 if( bChangeBottom )
1344 memcpy( pAktTC->rgbrc[ WW8_BOT ].aBits1,
1345 pBRC->aBits1,
1346 sizeof( WW8_BRC ) );
1347 if( bChangeRight )
1348 memcpy( pAktTC->rgbrc[ WW8_RIGHT].aBits1,
1349 pBRC->aBits1,
1350 sizeof( WW8_BRC ) );
1359 void WW8TabBandDesc::ProcessSprmTTableBorders(bool bVer67, const BYTE* pParams)
1361 // sprmTTableBorders
1362 if( bVer67 )
1364 for( int i = 0; i < 6; ++i )
1366 aDefBrcs[i].aBits1[0] = pParams[ 2*i ];
1367 aDefBrcs[i].aBits1[1] = pParams[ 1+2*i ];
1370 else // aDefBrcs = *(BRC(*)[6])pS;
1371 memcpy( aDefBrcs, pParams, 24 );
1374 void WW8TabBandDesc::ProcessSprmTDxaCol(const BYTE* pParamsTDxaCol)
1376 // sprmTDxaCol (opcode 0x7623) changes the width of cells
1377 // whose index is within a certain range to be a certain value.
1379 if( nWwCols && pParamsTDxaCol ) // set one or more cell length(s)
1381 BYTE nitcFirst= pParamsTDxaCol[0]; // first col to be changed
1382 BYTE nitcLim = pParamsTDxaCol[1]; // (last col to be changed)+1
1383 short nDxaCol = (INT16)SVBT16ToShort( pParamsTDxaCol + 2 );
1384 short nOrgWidth;
1385 short nDelta;
1387 for( int i = nitcFirst; (i < nitcLim) && (i < nWwCols); i++ )
1389 nOrgWidth = nCenter[i+1] - nCenter[i];
1390 nDelta = nDxaCol - nOrgWidth;
1391 for( int j = i+1; j <= nWwCols; j++ )
1393 nCenter[j] = nCenter[j] + nDelta;
1399 void WW8TabBandDesc::ProcessSprmTInsert(const BYTE* pParamsTInsert)
1401 if( nWwCols && pParamsTInsert ) // set one or more cell length(s)
1403 BYTE nitcInsert = pParamsTInsert[0]; // position at which to insert
1404 if (nitcInsert >= MAX_COL) // cannot insert into cell outside max possible index
1405 return;
1406 BYTE nctc = pParamsTInsert[1]; // number of cells
1407 USHORT ndxaCol = SVBT16ToShort( pParamsTInsert+2 );
1409 short nNewWwCols;
1410 if (nitcInsert > nWwCols)
1412 nNewWwCols = nitcInsert+nctc;
1413 //if new count would be outside max possible count, clip it, and calc a new replacement
1414 //legal nctc
1415 if (nNewWwCols > MAX_COL)
1417 nNewWwCols = MAX_COL;
1418 nctc = ::sal::static_int_cast<BYTE>(nNewWwCols-nitcInsert);
1421 else
1423 nNewWwCols = nWwCols+nctc;
1424 //if new count would be outside max possible count, clip it, and calc a new replacement
1425 //legal nctc
1426 if (nNewWwCols > MAX_COL)
1428 nNewWwCols = MAX_COL;
1429 nctc = ::sal::static_int_cast<BYTE>(nNewWwCols-nWwCols);
1433 WW8_TCell *pTC2s = new WW8_TCell[nNewWwCols];
1434 setcelldefaults(pTC2s, nNewWwCols);
1436 if (pTCs)
1438 memcpy( pTC2s, pTCs, nWwCols * sizeof( WW8_TCell ) );
1439 delete[] pTCs;
1441 pTCs = pTC2s;
1443 //If we have to move some cells
1444 if (nitcInsert <= nWwCols)
1446 // adjust the left x-position of the dummy at the very end
1447 nCenter[nWwCols + nctc] = nCenter[nWwCols]+nctc*ndxaCol;
1448 for( int i = nWwCols-1; i >= nitcInsert; i--)
1450 // adjust the left x-position
1451 nCenter[i + nctc] = nCenter[i]+nctc*ndxaCol;
1453 // adjust the cell's borders
1454 pTCs[i + nctc] = pTCs[i];
1458 //if itcMac is larger than full size, fill in missing ones first
1459 for( int i = nWwCols; i > nitcInsert+nWwCols; i--)
1460 nCenter[i] = i ? (nCenter[i - 1]+ndxaCol) : 0;
1462 //now add in our new cells
1463 for( int j = 0;j < nctc; j++)
1464 nCenter[j + nitcInsert] = (j + nitcInsert) ? (nCenter[j + nitcInsert -1]+ndxaCol) : 0;
1466 nWwCols = nNewWwCols;
1470 void WW8TabBandDesc::ProcessDirection(const BYTE* pParams)
1472 sal_uInt8 nStartCell = *pParams++;
1473 sal_uInt8 nEndCell = *pParams++;
1474 sal_uInt16 nCode = SVBT16ToShort(pParams);
1476 ASSERT(nStartCell < nEndCell, "not as I thought");
1477 ASSERT(nEndCell < MAX_COL + 1, "not as I thought");
1478 if (nStartCell > MAX_COL)
1479 return;
1480 if (nEndCell > MAX_COL + 1)
1481 nEndCell = MAX_COL + 1;
1483 for (;nStartCell < nEndCell; ++nStartCell)
1484 maDirections[nStartCell] = nCode;
1487 void WW8TabBandDesc::ProcessSpacing(const BYTE* pParams)
1489 BYTE nLen = pParams ? *(pParams - 1) : 0;
1490 ASSERT(nLen == 6, "Unexpected spacing len");
1491 if (nLen != 6)
1492 return;
1493 mbHasSpacing=true;
1494 #ifndef PRODUCT
1495 BYTE nWhichCell =
1496 #endif
1497 *pParams++;
1498 ASSERT(nWhichCell == 0, "Expected cell to be 0!");
1499 *pParams++; //unknown byte
1501 BYTE nSideBits = *pParams++;
1502 ASSERT(nSideBits < 0x10, "Unexpected value for nSideBits");
1503 *pParams++; //unknown byte
1504 USHORT nValue = SVBT16ToShort( pParams );
1505 for (int i = wwTOP; i <= wwRIGHT; i++)
1507 switch (nSideBits & (1 << i))
1509 case 1 << wwTOP:
1510 mnDefaultTop = nValue;
1511 break;
1512 case 1 << wwLEFT:
1513 mnDefaultLeft = nValue;
1514 break;
1515 case 1 << wwBOTTOM:
1516 mnDefaultBottom = nValue;
1517 break;
1518 case 1 << wwRIGHT:
1519 mnDefaultRight = nValue;
1520 break;
1521 case 0:
1522 break;
1523 default:
1524 ASSERT(!this, "Impossible");
1525 break;
1530 void WW8TabBandDesc::ProcessSpecificSpacing(const BYTE* pParams)
1532 BYTE nLen = pParams ? *(pParams - 1) : 0;
1533 ASSERT(nLen == 6, "Unexpected spacing len");
1534 if (nLen != 6)
1535 return;
1536 BYTE nWhichCell = *pParams++;
1537 ASSERT(nWhichCell < MAX_COL + 1, "Cell out of range in spacings");
1538 if (nWhichCell >= MAX_COL + 1)
1539 return;
1541 *pParams++; //unknown byte
1542 BYTE nSideBits = *pParams++;
1543 ASSERT(nSideBits < 0x10, "Unexpected value for nSideBits");
1544 nOverrideSpacing[nWhichCell] |= nSideBits;
1546 ASSERT(nOverrideSpacing[nWhichCell] < 0x10,
1547 "Unexpected value for nSideBits");
1548 #ifndef PRODUCT
1549 BYTE nUnknown2 =
1550 #endif
1551 *pParams++;
1552 ASSERT(nUnknown2 == 0x3, "Unexpected value for spacing2");
1553 USHORT nValue = SVBT16ToShort( pParams );
1555 for (int i=0; i < 4; i++)
1557 if (nSideBits & (1 << i))
1558 nOverrideValues[nWhichCell][i] = nValue;
1562 void WW8TabBandDesc::ProcessSprmTDelete(const BYTE* pParamsTDelete)
1564 if( nWwCols && pParamsTDelete ) // set one or more cell length(s)
1566 BYTE nitcFirst= pParamsTDelete[0]; // first col to be deleted
1567 if (nitcFirst >= nWwCols) // first index to delete from doesn't exist
1568 return;
1569 BYTE nitcLim = pParamsTDelete[1]; // (last col to be deleted)+1
1570 if (nitcLim <= nitcFirst) // second index to delete to is not greater than first index
1571 return;
1574 * sprmTDelete causes any rgdxaCenter and rgtc entries whose index is
1575 * greater than or equal to itcLim to be moved
1577 int nShlCnt = nWwCols - nitcLim; // count of cells to be shifted
1579 if (nShlCnt >= 0) //There exist entries whose index is greater than or equal to itcLim
1581 WW8_TCell* pAktTC = pTCs + nitcFirst;
1582 int i = 0;
1583 while( i < nShlCnt )
1585 // adjust the left x-position
1586 nCenter[nitcFirst + i] = nCenter[nitcLim + i];
1588 // adjust the cell's borders
1589 *pAktTC = pTCs[ nitcLim + i];
1591 ++i;
1592 ++pAktTC;
1594 // adjust the left x-position of the dummy at the very end
1595 nCenter[nitcFirst + i] = nCenter[nitcLim + i];
1598 short nCellsDeleted = nitcLim - nitcFirst;
1599 //clip delete request to available number of cells
1600 if (nCellsDeleted > nWwCols)
1601 nCellsDeleted = nWwCols;
1602 nWwCols -= nCellsDeleted;
1606 // ReadShd liest ggfs die Hintergrundfarben einer Zeile ein.
1607 // Es muss vorher ReadDef aufgerufen worden sein
1608 void WW8TabBandDesc::ReadShd(const BYTE* pS )
1610 BYTE nLen = pS ? *(pS - 1) : 0;
1611 if( !nLen )
1612 return;
1614 if( !pSHDs )
1616 pSHDs = new WW8_SHD[nWwCols];
1617 memset( pSHDs, 0, nWwCols * sizeof( WW8_SHD ) );
1620 short nAnz = nLen >> 1;
1621 if (nAnz > nWwCols)
1622 nAnz = nWwCols;
1624 SVBT16* pShd;
1625 int i;
1626 for(i=0, pShd = (SVBT16*)pS; i<nAnz; i++, pShd++ )
1627 pSHDs[i].SetWWValue( *pShd );
1630 void WW8TabBandDesc::ReadNewShd(const BYTE* pS, bool bVer67)
1632 BYTE nLen = pS ? *(pS - 1) : 0;
1633 if (!nLen)
1634 return;
1636 if (!pNewSHDs)
1637 pNewSHDs = new sal_uInt32[nWwCols];
1639 short nAnz = nLen / 10; //10 bytes each
1640 if (nAnz > nWwCols)
1641 nAnz = nWwCols;
1643 int i=0;
1644 while (i < nAnz)
1645 pNewSHDs[i++] = SwWW8ImplReader::ExtractColour(pS, bVer67);
1647 while (i < nWwCols)
1648 pNewSHDs[i++] = COL_AUTO;
1651 void WW8TabBandDesc::setcelldefaults(WW8_TCell *pCells, short nCols)
1653 memset( pCells, 0, nCols * sizeof( WW8_TCell ) );
1656 const BYTE *HasTabCellSprm(WW8PLCFx_Cp_FKP* pPap, bool bVer67)
1658 const BYTE *pParams;
1659 if (bVer67)
1660 pParams = pPap->HasSprm(24);
1661 else
1663 if (0 == (pParams = pPap->HasSprm(0x244B)))
1664 pParams = pPap->HasSprm(0x2416);
1666 return pParams;
1669 enum wwTableSprm
1671 sprmNil,
1673 sprmTTableWidth,sprmTTextFlow, sprmTFCantSplit, sprmTFCantSplit90,sprmTJc, sprmTFBiDi, sprmTDefTable,
1674 sprmTDyaRowHeight, sprmTDefTableShd, sprmTDxaLeft, sprmTSetBrc,
1675 sprmTDxaCol, sprmTInsert, sprmTDelete, sprmTTableHeader,
1676 sprmTDxaGapHalf, sprmTTableBorders,
1678 sprmTDefTableNewShd, sprmTSpacing, sprmTNewSpacing
1681 wwTableSprm GetTableSprm(sal_uInt16 nId, ww::WordVersion eVer)
1683 switch (eVer)
1685 case ww::eWW8:
1686 switch (nId)
1688 case 0xF614:
1689 return sprmTTableWidth;
1690 case 0x7629:
1691 return sprmTTextFlow;
1692 case 0x3403:
1693 return sprmTFCantSplit;
1694 case 0x3404:
1695 return sprmTTableHeader;
1696 case 0x3466:
1697 return sprmTFCantSplit90;
1698 case 0x5400:
1699 return sprmTJc;
1700 case 0x560B:
1701 return sprmTFBiDi;
1702 case 0x5622:
1703 return sprmTDelete;
1704 case 0x7621:
1705 return sprmTInsert;
1706 case 0x7623:
1707 return sprmTDxaCol;
1708 case 0x9407:
1709 return sprmTDyaRowHeight;
1710 case 0x9601:
1711 return sprmTDxaLeft;
1712 case 0x9602:
1713 return sprmTDxaGapHalf;
1714 case 0xD605:
1715 return sprmTTableBorders;
1716 case 0xD608:
1717 return sprmTDefTable;
1718 case 0xD609:
1719 return sprmTDefTableShd;
1720 case 0xD612:
1721 return sprmTDefTableNewShd;
1722 case 0xD620:
1723 return sprmTSetBrc;
1724 case 0xD632:
1725 return sprmTSpacing;
1726 case 0xD634:
1727 return sprmTNewSpacing;
1729 break;
1730 case ww::eWW7:
1731 case ww::eWW6:
1732 switch (nId)
1734 case 182:
1735 return sprmTJc;
1736 case 183:
1737 return sprmTDxaLeft;
1738 case 184:
1739 return sprmTDxaGapHalf;
1740 case 186:
1741 return sprmTTableHeader;
1742 case 187:
1743 return sprmTTableBorders;
1744 case 189:
1745 return sprmTDyaRowHeight;
1746 case 190:
1747 return sprmTDefTable;
1748 case 191:
1749 return sprmTDefTableShd;
1750 case 193:
1751 return sprmTSetBrc;
1752 case 194:
1753 return sprmTInsert;
1754 case 195:
1755 return sprmTDelete;
1756 case 196:
1757 return sprmTDxaCol;
1759 break;
1760 case ww::eWW2:
1761 switch (nId)
1763 case 146:
1764 return sprmTJc;
1765 case 147:
1766 return sprmTDxaLeft;
1767 case 148:
1768 return sprmTDxaGapHalf;
1769 case 153:
1770 return sprmTDyaRowHeight;
1771 case 154:
1772 return sprmTDefTable;
1773 case 155:
1774 return sprmTDefTableShd;
1775 case 157:
1776 return sprmTSetBrc;
1777 case 158:
1778 return sprmTInsert;
1779 case 159:
1780 return sprmTDelete;
1781 case 160:
1782 return sprmTDxaCol;
1784 break;
1786 return sprmNil;
1789 WW8TabDesc::WW8TabDesc(SwWW8ImplReader* pIoClass, WW8_CP nStartCp) :
1790 mpOldRedlineStack(0),
1791 pIo(pIoClass),
1792 pFirstBand(0),
1793 pActBand(0),
1794 pTmpPos(0),
1795 pTblNd(0),
1796 pTabLines(0),
1797 pTabLine(0),
1798 pTabBoxes(0),
1799 pTabBox(0),
1800 pMergeGroups(0),
1801 pAktWWCell(0),
1802 nRows(0),
1803 nDefaultSwCols(0),
1804 nBands(0),
1805 nMinLeft(0),
1806 nConvertedLeft(0),
1807 nMaxRight(0),
1808 nSwWidth(0),
1809 nPreferredWidth(0),
1810 nOrgDxaLeft(0),
1811 bOk(true),
1812 bClaimLineFmt(false),
1813 eOri(text::HoriOrientation::NONE),
1814 bIsBiDi(false),
1815 nAktRow(0),
1816 nAktBandRow(0),
1817 nAktCol(0),
1818 nRowsToRepeat(0),
1819 pTable(0),
1820 pParentPos(0),
1821 pFlyFmt(0),
1822 aItemSet(pIo->rDoc.GetAttrPool(),RES_FRMATR_BEGIN,RES_FRMATR_END-1)
1824 pIo->bAktAND_fNumberAcross = false;
1826 static const sal_Int16 aOriArr[] =
1828 text::HoriOrientation::LEFT, text::HoriOrientation::CENTER, text::HoriOrientation::RIGHT, text::HoriOrientation::CENTER
1831 bool bOldVer = ww::IsSevenMinus(pIo->GetFib().GetFIBVersion());
1832 WW8_TablePos aTabPos;
1834 WW8PLCFxSave1 aSave;
1835 pIo->pPlcxMan->GetPap()->Save( aSave );
1837 WW8PLCFx_Cp_FKP* pPap = pIo->pPlcxMan->GetPapPLCF();
1839 eOri = text::HoriOrientation::LEFT;
1841 WW8TabBandDesc* pNewBand = new WW8TabBandDesc;
1843 wwSprmParser aSprmParser(pIo->GetFib().GetFIBVersion());
1845 // process pPap until end of table found
1848 short nTabeDxaNew = SHRT_MAX;
1849 bool bTabRowJustRead = false;
1850 const BYTE* pShadeSprm = 0;
1851 const BYTE* pNewShadeSprm = 0;
1852 WW8_TablePos *pTabPos = 0;
1854 // Suche Ende einer TabZeile
1855 if(!(pIo->SearchRowEnd(pPap, nStartCp, pIo->nInTable)))
1857 bOk = false;
1858 break;
1861 // Get the SPRM chains:
1862 // first from PAP and then from PCD (of the Piece Table)
1863 WW8PLCFxDesc aDesc;
1864 pPap->GetSprms( &aDesc );
1865 WW8SprmIter aSprmIter(aDesc.pMemPos, aDesc.nSprmsLen, aSprmParser);
1867 const BYTE* pParams = aSprmIter.GetAktParams();
1868 for (int nLoop = 0; nLoop < 2; ++nLoop)
1870 bool bRepeatedSprm = false;
1871 while (aSprmIter.GetSprms() && 0 != (pParams = aSprmIter.GetAktParams()))
1873 sal_uInt16 nId = aSprmIter.GetAktId();
1874 wwTableSprm eSprm = GetTableSprm(nId, pIo->GetFib().GetFIBVersion());
1875 switch (eSprm)
1877 case sprmTTableWidth:
1879 const BYTE b0 = pParams[0];
1880 const BYTE b1 = pParams[1];
1881 const BYTE b2 = pParams[2];
1882 if (b0 == 3) // Twips
1883 nPreferredWidth = b2 * 0x100 + b1;
1885 break;
1886 case sprmTTextFlow:
1887 pNewBand->ProcessDirection(pParams);
1888 break;
1889 case sprmTFCantSplit:
1890 pNewBand->bCantSplit = *pParams;
1891 bClaimLineFmt = true;
1892 break;
1893 case sprmTFCantSplit90:
1894 pNewBand->bCantSplit90 = *pParams;
1895 bClaimLineFmt = true;
1896 break;
1897 case sprmTTableBorders:
1898 pNewBand->ProcessSprmTTableBorders(bOldVer, pParams);
1899 break;
1900 case sprmTTableHeader:
1901 if (!bRepeatedSprm)
1903 nRowsToRepeat++;
1904 bRepeatedSprm = true;
1906 break;
1907 case sprmTJc:
1908 // sprmTJc - Justification Code
1909 if (nRows == 0)
1910 eOri = aOriArr[*pParams & 0x3];
1911 break;
1912 case sprmTFBiDi:
1913 bIsBiDi = SVBT16ToShort(pParams) ? true : false;
1914 break;
1915 case sprmTDxaGapHalf:
1916 pNewBand->nGapHalf = (INT16)SVBT16ToShort( pParams );
1917 break;
1918 case sprmTDyaRowHeight:
1919 pNewBand->nLineHeight = (INT16)SVBT16ToShort( pParams );
1920 bClaimLineFmt = true;
1921 break;
1922 case sprmTDefTable:
1923 pNewBand->ReadDef(bOldVer, pParams);
1924 bTabRowJustRead = true;
1925 break;
1926 case sprmTDefTableShd:
1927 pShadeSprm = pParams;
1928 break;
1929 case sprmTDefTableNewShd:
1930 pNewShadeSprm = pParams;
1931 break;
1932 case sprmTDxaLeft:
1933 // our Writer cannot shift single table lines
1934 // horizontally so we have to find the smallest
1935 // parameter (meaning the left-most position) and then
1936 // shift the whole table to that margin (see below)
1938 short nDxaNew = (INT16)SVBT16ToShort( pParams );
1939 nOrgDxaLeft = nDxaNew;
1940 if( nDxaNew < nTabeDxaNew )
1941 nTabeDxaNew = nDxaNew;
1943 break;
1944 case sprmTSetBrc:
1945 pNewBand->ProcessSprmTSetBRC(bOldVer, pParams);
1946 break;
1947 case sprmTDxaCol:
1948 pNewBand->ProcessSprmTDxaCol(pParams);
1949 break;
1950 case sprmTInsert:
1951 pNewBand->ProcessSprmTInsert(pParams);
1952 break;
1953 case sprmTDelete:
1954 pNewBand->ProcessSprmTDelete(pParams);
1955 break;
1956 case sprmTNewSpacing:
1957 pNewBand->ProcessSpacing(pParams);
1958 break;
1959 case sprmTSpacing:
1960 pNewBand->ProcessSpecificSpacing(pParams);
1961 break;
1962 default:
1965 aSprmIter++;
1968 if( !nLoop )
1970 pPap->GetPCDSprms( aDesc );
1971 aSprmIter.SetSprms( aDesc.pMemPos, aDesc.nSprmsLen );
1975 // #55171: WW-Tabellen koennen Fly-Wechsel beinhalten daher hier
1976 // Tabellen abbrechen und neu beginnen noch steht *pPap noch vor
1977 // TabRowEnd, daher kann TestApo() mit letztem Parameter false und
1978 // damit wirksam gerufen werden.
1980 if (bTabRowJustRead)
1982 if (pShadeSprm)
1983 pNewBand->ReadShd(pShadeSprm);
1984 if (pNewShadeSprm)
1985 pNewBand->ReadNewShd(pNewShadeSprm, bOldVer);
1988 if( nTabeDxaNew < SHRT_MAX )
1990 short* pCenter = pNewBand->nCenter;
1991 short firstDxaCenter = *pCenter;
1992 for( int i = 0; i < pNewBand->nWwCols; i++, ++pCenter )
1994 // #i30298# Use sprmTDxaLeft to adjust the left indent
1995 // #i40461# Use dxaGapHalf during calculation
1996 *pCenter +=
1997 (nTabeDxaNew - (firstDxaCenter + pNewBand->nGapHalf));
2001 if (!pActBand)
2002 pActBand = pFirstBand = pNewBand;
2003 else
2005 pActBand->pNextBand = pNewBand;
2006 pActBand = pNewBand;
2008 nBands++;
2010 pNewBand = new WW8TabBandDesc;
2012 nRows++;
2013 pActBand->nRows++;
2015 //Seek our pap to its next block of properties
2016 WW8PLCFxDesc aRes;
2017 aRes.pMemPos = 0;
2018 aRes.nStartPos = nStartCp;
2020 if (!(pPap->SeekPos(aRes.nStartPos)))
2022 aRes.nEndPos = WW8_CP_MAX;
2023 pPap->SetDirty(true);
2025 pPap->GetSprms(&aRes);
2026 pPap->SetDirty(false);
2028 //Are we at the end of available properties
2029 if (
2030 !pPap->HasFkp() || pPap->Where() == WW8_CP_MAX ||
2031 aRes.nStartPos == WW8_CP_MAX
2034 bOk = false;
2035 break;
2038 //Are we still in a table cell
2039 pParams = HasTabCellSprm(pPap, bOldVer);
2040 const BYTE *pLevel = pPap->HasSprm(0x6649);
2041 // InTable
2042 if (!pParams || (1 != *pParams) ||
2043 (pLevel && (*pLevel <= pIo->nInTable)))
2045 break;
2048 //Get the end of row new table positioning data
2049 WW8_CP nMyStartCp=nStartCp;
2050 if (pIo->SearchRowEnd(pPap, nMyStartCp, pIo->nInTable))
2051 if (SwWW8ImplReader::ParseTabPos(&aTabPos, pPap))
2052 pTabPos = &aTabPos;
2054 //Move back to this cell
2055 aRes.pMemPos = 0;
2056 aRes.nStartPos = nStartCp;
2058 // #114237 PlcxMan currently points too far ahead so we need to bring
2059 // it back to where we are trying to make a table
2060 pIo->pPlcxMan->GetPap()->nOrigStartPos = aRes.nStartPos;
2061 if (!(pPap->SeekPos(aRes.nStartPos)))
2063 aRes.nEndPos = WW8_CP_MAX;
2064 pPap->SetDirty(true);
2066 pPap->GetSprms(&aRes);
2067 pPap->SetDirty(false);
2069 //Does this row match up with the last row closely enough to be
2070 //considered part of the same table
2071 ApoTestResults aApo = pIo->TestApo(pIo->nInTable + 1, false, pTabPos);
2074 ##513##, #79474# If this is not sufficent, then we should look at
2075 sprmPD{y|x}aAbs as our indicator that the following set of rows is not
2076 part of this table, but instead is an absolutely positioned table
2077 outside of this one
2079 if (aApo.mbStopApo)
2080 break;
2081 if (aApo.mbStartApo)
2083 //if there really is a fly here, and not a "null" fly then break.
2084 WW8FlyPara *pNewFly = pIo->ConstructApo(aApo, pTabPos);
2085 if (pNewFly)
2086 delete pNewFly;
2087 else
2088 break;
2091 nStartCp = aRes.nEndPos;
2093 while( 1 );
2095 if( bOk )
2097 if( pActBand->nRows > 1 )
2099 // Letztes Band hat mehr als 1 Zeile
2100 delete pNewBand;
2101 pNewBand = new WW8TabBandDesc( *pActBand ); // neues machen
2102 pActBand->nRows--; // wegen Sonderbehandlung Raender-Defaults
2103 pNewBand->nRows = 1;
2104 pActBand->pNextBand = pNewBand; // am Ende einschleifen
2105 nBands++;
2106 pNewBand = 0; // nicht loeschen
2108 CalcDefaults();
2110 delete pNewBand;
2112 pIo->pPlcxMan->GetPap()->Restore( aSave );
2115 WW8TabDesc::~WW8TabDesc()
2117 WW8TabBandDesc* pR = pFirstBand;
2118 while(pR)
2120 WW8TabBandDesc* pR2 = pR->pNextBand;
2121 delete pR;
2122 pR = pR2;
2125 delete pParentPos;
2126 delete pMergeGroups;
2129 void WW8TabDesc::CalcDefaults()
2131 short nMinCols = SHRT_MAX;
2132 WW8TabBandDesc* pR;
2134 nMinLeft = SHRT_MAX;
2135 nMaxRight = SHRT_MIN;
2138 #101175#
2139 If we are an honestly inline centered table, then the normal rules of
2140 engagement for left and right margins do not apply. The multiple rows are
2141 centered regardless of the actual placement of rows, so we cannot have
2142 mismatched rows as is possible in other configurations.
2144 e.g. change the example bugdoc in word from text wrapping of none (inline)
2145 to around (in frame (bApo)) and the table splits into two very disjoint
2146 rows as the beginning point of each row are very different
2148 if ((!pIo->InLocalApo()) && (eOri == text::HoriOrientation::CENTER))
2150 for (pR = pFirstBand; pR; pR = pR->pNextBand)
2151 for( short i = pR->nWwCols; i >= 0; --i)
2152 pR->nCenter[i] = pR->nCenter[i] - pR->nCenter[0];
2155 // 1. Durchlauf: aeusserste L- und R-Grenzen finden
2156 for( pR = pFirstBand; pR; pR = pR->pNextBand )
2158 if( pR->nCenter[0] < nMinLeft )
2159 nMinLeft = pR->nCenter[0];
2161 for( short i = 0; i < pR->nWwCols; i++ )
2164 #74387# If the margins are so large as to make the displayable
2165 area inside them smaller than the minimum allowed then adjust the
2166 width to fit. But only do it if the two cells are not the exact
2167 same value, if they are then the cell does not really exist and will
2168 be blended together into the same cell through the use of the
2169 nTrans(late) array.
2170 #i28333# If the nGapHalf is greater than the cell width best to ignore it
2172 int nCellWidth = pR->nCenter[i+1] - pR->nCenter[i];
2173 if (nCellWidth && ((nCellWidth - pR->nGapHalf*2) < MINLAY) && pR->nGapHalf < nCellWidth)
2175 pR->nCenter[i+1] = pR->nCenter[i]+MINLAY+pR->nGapHalf * 2;
2179 if( pR->nCenter[pR->nWwCols] > nMaxRight )
2180 nMaxRight = pR->nCenter[pR->nWwCols];
2182 nSwWidth = nMaxRight - nMinLeft;
2184 // #109830# If the table is right aligned we need to align all rows to the
2185 // row that has the furthest right point
2187 if(eOri == text::HoriOrientation::RIGHT)
2189 for( pR = pFirstBand; pR; pR = pR->pNextBand )
2191 int adjust = nMaxRight - pR->nCenter[pR->nWwCols];
2192 for( short i = 0; i < pR->nWwCols + 1; i++ )
2194 pR->nCenter[i] = static_cast< short >(pR->nCenter[i] + adjust);
2200 // 2. Durchlauf: Zahl der Writer-Spalten feststellen Die Zahl der Writer
2201 // Spalten kann um bis zu 2 hoeher sein als im WW, da der SW im Gegensatz
2202 // zu WW keine ausgefransten linken und rechten Raender kann und diese
2203 // durch leere Boxen aufgefuellt werden. Durch nichtexistente Zellen
2204 // koennen auch Zellen wegfallen
2206 // 3. Durchlauf: Wo noetig die Umrandungen durch die Defaults ersetzen
2207 nConvertedLeft = nMinLeft;
2209 short nLeftMaxThickness = 0, nRightMaxThickness=0;
2210 for( pR = pFirstBand ; pR; pR = pR->pNextBand )
2212 if( !pR->pTCs )
2214 pR->pTCs = new WW8_TCell[ pR->nWwCols ];
2215 memset( pR->pTCs, 0, pR->nWwCols * sizeof( WW8_TCell ) );
2217 for (int k = 0; k < pR->nWwCols; ++k)
2219 WW8_TCell* pT = &pR->pTCs[k];
2220 int i, j;
2221 for( i = 0; i < 4; i ++ )
2223 if (pT->rgbrc[i].IsZeroed(pIo->bVer67))
2225 // if shadow is set, its invalid
2226 j = i;
2227 switch( i )
2229 case 0:
2230 // Aussen oben / Innen waagerecht
2231 j = (pR == pFirstBand) ? 0 : 4;
2232 break;
2233 case 1:
2234 // Aussen links / Innen senkrecht
2235 j = k ? 5 : 1;
2236 break;
2237 case 2:
2238 // Aussen unten / Innen waagerecht
2239 j = pR->pNextBand ? 4 : 2;
2240 break;
2241 case 3:
2242 // Aussen rechts/ Innen senkrecht
2243 j = (k == pR->nWwCols - 1) ? 3 : 5;
2244 break;
2246 // mangel mit Defaults ueber
2247 pT->rgbrc[i] = pR->aDefBrcs[j];
2252 Similiar to graphics and other elements word does not totally
2253 factor the width of the border into its calculations of size, we
2254 do so we must adjust out widths and other dimensions to fit. It
2255 appears that what occurs is that the last cell's right margin if
2256 the margin width that is not calculated into winwords table
2257 dimensions, so in that case increase the table to include the
2258 extra width of the right margin.
2260 if ( pIo->bVer67 ?
2261 !(SVBT16ToShort(pR->pTCs[pR->nWwCols-1].rgbrc[3].aBits1) & 0x20)
2262 : !(SVBT16ToShort(pR->pTCs[pR->nWwCols-1].rgbrc[3].aBits2) & 0x2000))
2264 short nThickness = pR->pTCs[pR->nWwCols-1].rgbrc[3].
2265 DetermineBorderProperties(pIo->bVer67);
2266 pR->nCenter[pR->nWwCols] = pR->nCenter[pR->nWwCols] + nThickness;
2267 if (nThickness > nRightMaxThickness)
2268 nRightMaxThickness = nThickness;
2272 The left space of the table is in nMinLeft, but again this
2273 does not consider the margin thickness to its left in the
2274 placement value, so get the thickness of the left border,
2275 half is placed to the left of the nominal left side, and
2276 half to the right.
2278 if ( pIo->bVer67 ?
2279 !(SVBT16ToShort(pR->pTCs[0].rgbrc[1].aBits1) & 0x20)
2280 : !(SVBT16ToShort(pR->pTCs[0].rgbrc[1].aBits2) & 0x2000))
2282 short nThickness = pR->pTCs[0].rgbrc[1].
2283 DetermineBorderProperties(pIo->bVer67);
2284 if (nThickness > nLeftMaxThickness)
2285 nLeftMaxThickness = nThickness;
2288 nSwWidth = nSwWidth + nRightMaxThickness;
2289 nMaxRight = nMaxRight + nRightMaxThickness;
2290 nConvertedLeft = nMinLeft-(nLeftMaxThickness/2);
2292 for( pR = pFirstBand; pR; pR = pR->pNextBand )
2294 pR->nSwCols = pR->nWwCols;
2295 pR->bLEmptyCol = pR->nCenter[0] - nMinLeft >= MINLAY;
2296 pR->bREmptyCol = (nMaxRight - pR->nCenter[pR->nWwCols] - nRightMaxThickness) >= MINLAY;
2298 short nAddCols = pR->bLEmptyCol + pR->bREmptyCol;
2299 USHORT i;
2300 USHORT j = ( pR->bLEmptyCol ) ? 1 : 0;
2301 for (i = 0; i < pR->nWwCols; ++i)
2303 pR->nTransCell[i] = (INT8)j;
2304 if ( pR->nCenter[i] < pR->nCenter[i+1] )
2306 pR->bExist[i] = true;
2307 j++;
2309 else
2311 pR->bExist[i] = false;
2312 nAddCols--;
2316 ASSERT(i,"no columns in row ?");
2319 #96345#
2320 If the last cell was "false" then there is no valid cell following it,
2321 so the default mapping forward wont't work. So map it (and
2322 contigious invalid cells backwards to the last valid cell instead.
2324 if (i && pR->bExist[i-1] == false)
2326 USHORT k=i-1;
2327 while (k && pR->bExist[k] == false)
2328 k--;
2329 for (USHORT n=k+1;n<i;n++)
2330 pR->nTransCell[n] = pR->nTransCell[k];
2333 pR->nTransCell[i++] = (INT8)(j++); // Wird u.a. wegen bREmptyCol um
2334 pR->nTransCell[i] = (INT8)j; // max. 2 ueberindiziert
2336 pR->nSwCols = pR->nSwCols + nAddCols;
2337 if( pR->nSwCols < nMinCols )
2338 nMinCols = pR->nSwCols;
2342 #i9718#
2343 Find the largest of the borders on cells that adjoin top bottom and remove
2344 the val from the top and put in on the bottom cell. I can't seem to make
2345 disjoint upper and lowers to see what happens there.
2348 /* #i29550# FME 2004-06-02 Removed this code because of the implementation
2349 of the collapsing table borders model. So this should not be necessary
2350 anymore. */
2352 /* for (pR = pFirstBand; pR; pR = pR->pNextBand)
2354 WW8TabBandDesc *pNext = pR->pNextBand;
2355 if (!pNext)
2356 break;
2358 for (int k = 0; k < pR->nWwCols; ++k)
2360 WW8_BRC &rAbove = pR->pTCs[k].rgbrc[WW8_BOT];
2361 short nAboveThick = rAbove.IsEmpty(pIo->bVer67) ?
2362 0 : rAbove.DetermineBorderProperties(pIo->bVer67);
2363 short nUpperLeft = pR->nCenter[k];
2364 short nUpperRight = pR->nCenter[k+1];
2366 for (int l = 0; l < pNext->nWwCols; ++l)
2368 short nLowerLeft = pNext->nCenter[l];
2369 short nLowerRight = pNext->nCenter[l+1];
2371 if ((nLowerLeft < nUpperLeft) || (nLowerRight > nUpperRight))
2372 continue;
2374 WW8_BRC &rBelow = pNext->pTCs[l].rgbrc[WW8_TOP];
2375 short nBelowThick = rBelow.IsEmpty(pIo->bVer67) ?
2376 0 : rBelow.DetermineBorderProperties(pIo->bVer67);
2377 if (nAboveThick > nBelowThick)
2378 rBelow = rAbove;
2381 rAbove = WW8_BRC();
2383 } */
2385 if ((nMinLeft && !bIsBiDi && text::HoriOrientation::LEFT == eOri) ||
2386 (nMinLeft != -108 && bIsBiDi && text::HoriOrientation::RIGHT == eOri)) // Word sets the first nCenter value to -108 when no indent is used
2387 eOri = text::HoriOrientation::LEFT_AND_WIDTH; // absolutely positioned
2389 nDefaultSwCols = nMinCols; // da Zellen einfuegen billiger ist als Mergen
2390 if( nDefaultSwCols == 0 )
2391 bOk = false;
2392 pActBand = pFirstBand;
2393 nAktBandRow = 0;
2394 ASSERT( pActBand, "pActBand ist 0" );
2397 void WW8TabDesc::SetSizePosition(SwFrmFmt* pFrmFmt)
2399 SwFrmFmt* pApply = pFrmFmt;
2400 if (!pApply )
2401 pApply = pTable->GetFrmFmt();
2402 ASSERT(pApply,"No frame");
2403 pApply->SetFmtAttr(aItemSet);
2404 if (pFrmFmt)
2406 SwFmtFrmSize aSize = pFrmFmt->GetFrmSize();
2407 aSize.SetHeightSizeType(ATT_MIN_SIZE);
2408 aSize.SetHeight(MINLAY);
2409 pFrmFmt->SetFmtAttr(aSize);
2410 pTable->GetFrmFmt()->SetFmtAttr(SwFmtHoriOrient(0,text::HoriOrientation::FULL));
2414 void wwSectionManager::PrependedInlineNode(const SwPosition &rPos,
2415 const SwNode &rNode)
2417 ASSERT(!maSegments.empty(),
2418 "should not be possible, must be at least one segment");
2419 if ((!maSegments.empty()) && (maSegments.back().maStart == rPos.nNode))
2420 maSegments.back().maStart = SwNodeIndex(rNode);
2423 void WW8TabDesc::CreateSwTable()
2425 ::SetProgressState(pIo->nProgress, pIo->mpDocShell); // Update
2427 // if there is already some content on the Node append new node to ensure
2428 // that this content remains ABOVE the table
2429 SwPosition* pPoint = pIo->pPaM->GetPoint();
2430 bool bInsNode = pPoint->nContent.GetIndex() ? true : false;
2431 bool bSetMinHeight = false;
2434 #i8062#
2435 Set fly anchor to its anchor pos, so that if a table starts immediately
2436 at this position a new node will be inserted before inserting the table.
2438 if (!bInsNode && pIo->pFmtOfJustInsertedApo)
2440 const SwPosition* pAPos =
2441 pIo->pFmtOfJustInsertedApo->GetAnchor().GetCntntAnchor();
2442 if (pAPos && &pAPos->nNode.GetNode() == &pPoint->nNode.GetNode())
2444 bInsNode = true;
2445 bSetMinHeight = true;
2447 SwFmtSurround aSur(pIo->pFmtOfJustInsertedApo->GetSurround());
2448 aSur.SetAnchorOnly(true);
2449 pIo->pFmtOfJustInsertedApo->SetFmtAttr(aSur);
2453 if (bSetMinHeight == true)
2455 // minimize Fontsize to minimize height growth of the header/footer
2456 // set font size to 1 point to minimize y-growth of Hd/Ft
2457 SvxFontHeightItem aSz(20, 100, RES_CHRATR_FONTSIZE);
2458 pIo->NewAttr( aSz );
2459 pIo->pCtrlStck->SetAttr(*pPoint, RES_CHRATR_FONTSIZE);
2462 if (bInsNode)
2463 pIo->AppendTxtNode(*pPoint);
2465 pTmpPos = new SwPosition( *pIo->pPaM->GetPoint() );
2467 // Die Tabelle ist beim Einfuegen noch recht klein: Zahl der Spalten ist
2468 // die kleinste Spaltenanzahl des Originals, da Spalten einfuegen
2469 // schneller geht als Loeschen Zahl der Zeilen ist die Zahl der Baender,
2470 // da sich die (identischen) Zeilen eines Bandes prima duplizieren lassen
2471 pTable = pIo->rDoc.InsertTable(
2472 SwInsertTableOptions( tabopts::HEADLINE_NO_BORDER, 0 ),
2473 *pTmpPos, nBands, nDefaultSwCols, eOri, 0, 0, FALSE, TRUE );
2475 ASSERT(pTable && pTable->GetFrmFmt(), "insert table failed");
2476 if (!pTable || !pTable->GetFrmFmt())
2477 return;
2479 SwTableNode* pTableNode = pTable->GetTableNode();
2480 ASSERT(pTableNode, "no table node!");
2481 if (pTableNode)
2483 pIo->maSectionManager.PrependedInlineNode(*pIo->pPaM->GetPoint(),
2484 *pTableNode);
2487 // Abfrage, ob im Node, in dem die Tabelle eingefuegt werden soll, bereits
2488 // ein Pagedesc steht. Dann wuerde der PageDesc in die naechste Zeile
2489 // hinter der Tabelle rutschen, wo er nichts zu suchen hat. -> loeschen
2490 // und spaeter an das Tabellenformat setzen
2491 if (SwTxtNode* pNd = pIo->rDoc.GetNodes()[pTmpPos->nNode]->GetTxtNode())
2493 if (const SfxItemSet* pSet = pNd->GetpSwAttrSet())
2495 SfxPoolItem *pSetAttr = 0;
2496 const SfxPoolItem* pItem;
2497 if (SFX_ITEM_SET == pSet->GetItemState(RES_BREAK, false, &pItem))
2499 pSetAttr = new SvxFmtBreakItem( *(SvxFmtBreakItem*)pItem );
2500 pNd->ResetAttr( RES_BREAK );
2503 // evtl den PageDesc/Break jetzt an der Tabelle setzen
2504 if (pSetAttr)
2506 aItemSet.Put(*pSetAttr);
2507 delete pSetAttr;
2512 // Gesamtbreite der Tabelle
2513 if( nMaxRight - nMinLeft > MINLAY * nDefaultSwCols )
2515 pTable->GetFrmFmt()->SetFmtAttr(SwFmtFrmSize(ATT_FIX_SIZE, nSwWidth));
2516 aItemSet.Put(SwFmtFrmSize(ATT_FIX_SIZE, nSwWidth));
2519 SvxFrameDirectionItem aDirection(
2520 bIsBiDi ? FRMDIR_HORI_RIGHT_TOP : FRMDIR_HORI_LEFT_TOP, RES_FRAMEDIR );
2521 pTable->GetFrmFmt()->SetFmtAttr(aDirection);
2523 if (text::HoriOrientation::LEFT_AND_WIDTH == eOri)
2525 if (!pIo->nInTable && pIo->InLocalApo() && pIo->pSFlyPara->pFlyFmt &&
2526 GetMinLeft())
2528 //If we are inside a frame and we have a border, the frames
2529 //placement does not consider the tables border, which word
2530 //displays outside the frame, so adjust here.
2531 SwFmtHoriOrient aHori(pIo->pSFlyPara->pFlyFmt->GetHoriOrient());
2532 sal_Int16 eHori = aHori.GetHoriOrient();
2533 if ((eHori == text::HoriOrientation::NONE) || (eHori == text::HoriOrientation::LEFT) ||
2534 (eHori == text::HoriOrientation::LEFT_AND_WIDTH))
2536 //With multiple table, use last table settings. Perhaps
2537 //the maximum is what word does ?
2538 aHori.SetPos(pIo->pSFlyPara->nXPos + GetMinLeft());
2539 aHori.SetHoriOrient(text::HoriOrientation::NONE);
2540 pIo->pSFlyPara->pFlyFmt->SetFmtAttr(aHori);
2543 else
2545 //If bApo is set, then this table is being placed in a floating
2546 //frame, and the frame matches the left and right *lines* of the
2547 //table, so the space to the left of the table isn't to be used
2548 //inside the frame, in word the dialog involved greys out the
2549 //ability to set the margin.
2550 SvxLRSpaceItem aL( RES_LR_SPACE );
2551 // set right to original DxaLeft (i28656)
2553 long nLeft = 0;
2554 if (!bIsBiDi)
2555 nLeft = GetMinLeft();
2556 else
2558 if (nPreferredWidth)
2559 nLeft = pIo->maSectionManager.GetTextAreaWidth() - nPreferredWidth - nOrgDxaLeft;
2560 else
2561 nLeft = -GetMinLeft();
2564 aL.SetLeft(nLeft);
2566 aItemSet.Put(aL);
2570 mpOldRedlineStack = pIo->mpRedlineStack;
2571 pIo->mpRedlineStack = new sw::util::RedlineStack(pIo->rDoc);
2574 void WW8TabDesc::UseSwTable()
2576 // globale Varis initialisieren
2577 pTabLines = &pTable->GetTabLines();
2578 nAktRow = nAktCol = nAktBandRow = 0;
2580 pTblNd = (SwTableNode*)(*pTabLines)[0]->GetTabBoxes()[0]->
2581 GetSttNd()->FindTableNode();
2582 ASSERT( pTblNd, "wo ist mein TabellenNode" );
2584 // --> mloiseleur 2007-10-10 #i69519# Restrict rows to repeat to a decent value
2585 if ( nRowsToRepeat == static_cast<USHORT>(nRows) )
2586 nRowsToRepeat = 1;
2587 // <--
2589 pTblNd->GetTable().SetRowsToRepeat( nRowsToRepeat );
2590 // ggfs. Zusatz-Zellen einfuegen u.dgl.
2591 AdjustNewBand();
2593 WW8DupProperties aDup(pIo->rDoc,pIo->pCtrlStck);
2594 pIo->pCtrlStck->SetAttr(*pIo->pPaM->GetPoint(), 0, false);
2596 // jetzt den PaM korrekt setzen und ggfs. erste Mergegruppe vorbereiten...
2597 SetPamInCell(nAktCol, true);
2598 aDup.Insert(*pIo->pPaM->GetPoint());
2600 pIo->bWasTabRowEnd = false;
2601 pIo->bWasTabCellEnd = false;
2604 void WW8TabDesc::MergeCells()
2606 short nRow;
2608 for (pActBand=pFirstBand, nRow=0; pActBand; pActBand=pActBand->pNextBand)
2611 // ggfs. aktuelle Box in entsprechende Merge-Gruppe eintragen
2613 if( pActBand->pTCs )
2615 for( short j = 0; j < pActBand->nRows; j++, nRow++ )
2616 for( short i = 0; i < pActBand->nWwCols; i++ )
2618 WW8SelBoxInfoPtr pActMGroup = 0;
2620 // ggfs. eine neue Merge-Gruppe beginnen
2622 ASSERT(nRow < pTabLines->Count(),
2623 "Too few lines, table ended early");
2624 if (nRow >= pTabLines->Count())
2625 return;
2626 pTabLine = (*pTabLines)[ nRow ];
2627 pTabBoxes = &pTabLine->GetTabBoxes();
2629 USHORT nCol = pActBand->nTransCell[ i ];
2630 if (!pActBand->bExist[i]) //#113434#
2631 continue;
2632 ASSERT(nCol < pTabBoxes->Count(),
2633 "Too few columns, table ended early");
2634 if (nCol >= pTabBoxes->Count())
2635 return;
2636 pTabBox = (*pTabBoxes)[nCol];
2637 WW8_TCell& rCell = pActBand->pTCs[ i ];
2638 // ist dies die obere, linke-Zelle einer Merge-Gruppe ?
2640 bool bMerge = false;
2641 if ( rCell.bVertRestart && !rCell.bMerged )
2642 bMerge = true;
2643 else if (rCell.bFirstMerged && pActBand->bExist[i])
2645 //#91211# Some tests to avoid merging cells
2646 //which previously were declared invalid because
2647 //of sharing the exact same dimensions as their
2648 //previous cell
2650 //If theres anything underneath/above we're ok.
2651 if (rCell.bVertMerge || rCell.bVertRestart)
2652 bMerge = true;
2653 else
2655 //If its a hori merge only, and the only things in
2656 //it are invalid cells then its already taken care
2657 //of, so don't merge.
2658 for (USHORT i2 = i+1; i2 < pActBand->nWwCols; i2++ )
2659 if (pActBand->pTCs[ i2 ].bMerged &&
2660 !pActBand->pTCs[ i2 ].bFirstMerged )
2662 if (pActBand->bExist[i2])
2664 bMerge = true;
2665 break;
2668 else
2669 break;
2674 if (bMerge)
2676 short nX1 = pActBand->nCenter[ i ];
2677 short nWidth = pActBand->nWidth[ i ];
2679 // 0. falls noetig das Array fuer die Merge-Gruppen
2680 // anlegen
2681 if( !pMergeGroups )
2682 pMergeGroups = new WW8MergeGroups;
2684 // 2. aktuelle Merge-Gruppe anlegen
2685 pActMGroup = new WW8SelBoxInfo( nX1, nWidth );
2687 // --> OD 2005-02-04 #118544# - determine size of new
2688 // merge group before inserted the new merge group.
2689 // Needed to correctly locked previously created merge groups.
2690 // Gesamtbreite ermitteln und zuweisen
2691 short nSizCell = pActBand->nWidth[ i ];
2692 for (USHORT i2 = i+1; i2 < pActBand->nWwCols; i2++ )
2693 if (pActBand->pTCs[ i2 ].bMerged &&
2694 !pActBand->pTCs[ i2 ].bFirstMerged )
2696 nSizCell = nSizCell + pActBand->nWidth[ i2 ];
2698 else
2699 break;
2700 pActMGroup->nGroupWidth = nSizCell;
2701 // <--
2703 // --> OD 2005-02-03 #118544# - locked previously
2704 // created merge groups, after determining the size
2705 // for the new merge group.
2706 // 1. ggfs. alte Mergegruppe(n) schliessen, die
2707 // den von unserer neuen Gruppe betroffenen
2708 // X-Bereich ueberdecken
2709 short nMGrIdx;
2710 while ( FindMergeGroup( nX1, pActMGroup->nGroupWidth,
2711 false, nMGrIdx ) )
2713 (*pMergeGroups)[ nMGrIdx ]->bGroupLocked = true;
2715 // <--
2717 // 3. und in Gruppen-Array eintragen
2718 pMergeGroups->Insert(pActMGroup, pMergeGroups->Count());
2721 // ggfs. akt. Box zu einer Merge-Gruppe hinzufuegen (dies
2722 // kann eine soeben angelegte, oder eine andere Gruppe
2723 // sein)
2724 UpdateTableMergeGroup( rCell, pActMGroup, pTabBox, i );
2730 //There is a limbo area in word at the end of the row marker
2731 //where properties can live in word, there is no location in
2732 //writer equivalent, so try and park the cursor in the best
2733 //match, see #i23022#/#i18644#
2734 void WW8TabDesc::ParkPaM()
2736 SwTableBox *pTabBox2 = 0;
2737 short nRow = nAktRow + 1;
2738 if (nRow < pTabLines->Count())
2740 if (SwTableLine *pLine = (*pTabLines)[nRow])
2742 SwTableBoxes &rBoxes = pLine->GetTabBoxes();
2743 pTabBox2 = rBoxes.Count() ? rBoxes[0] : 0;
2747 if (!pTabBox2 || !pTabBox2->GetSttNd())
2749 MoveOutsideTable();
2750 return;
2753 if (pIo->pPaM->GetPoint()->nNode != pTabBox2->GetSttIdx() + 1)
2755 pIo->pPaM->GetPoint()->nNode = pTabBox2->GetSttIdx() + 1;
2756 pIo->pPaM->GetPoint()->nContent.Assign(pIo->pPaM->GetCntntNode(), 0);
2757 pIo->rDoc.SetTxtFmtColl(*pIo->pPaM, (SwTxtFmtColl*)pIo->pDfltTxtFmtColl);
2761 void WW8TabDesc::MoveOutsideTable()
2763 ASSERT(pTmpPos && pIo, "I've forgotten where the table is anchored");
2764 if (pTmpPos && pIo)
2765 *pIo->pPaM->GetPoint() = *pTmpPos;
2768 void WW8TabDesc::FinishSwTable()
2770 pIo->mpRedlineStack->closeall(*pIo->pPaM->GetPoint());
2771 delete pIo->mpRedlineStack;
2772 pIo->mpRedlineStack = mpOldRedlineStack;
2773 mpOldRedlineStack = 0;
2775 WW8DupProperties aDup(pIo->rDoc,pIo->pCtrlStck);
2776 pIo->pCtrlStck->SetAttr( *pIo->pPaM->GetPoint(), 0, false);
2778 MoveOutsideTable();
2779 delete pTmpPos, pTmpPos = 0;
2781 aDup.Insert(*pIo->pPaM->GetPoint());
2783 pIo->bWasTabRowEnd = false;
2784 pIo->bWasTabCellEnd = false;
2786 pIo->maInsertedTables.InsertTable(*pTblNd, *pIo->pPaM);
2788 MergeCells();
2790 // falls noetig, zu mergende Zellen gruppenweise zusammenfassen
2791 if( pMergeGroups )
2793 // bearbeite alle Merge-Gruppen nacheinander
2794 WW8SelBoxInfo* pActMGroup;
2795 USHORT nActBoxCount;
2797 for (USHORT iGr = 0; iGr < pMergeGroups->Count(); ++iGr)
2799 pActMGroup = (*pMergeGroups)[ iGr ];
2800 nActBoxCount = pActMGroup->Count();
2802 if( ( 1 < nActBoxCount ) && pActMGroup && (*pActMGroup)[ 0 ] )
2804 const USHORT nRowSpan = pActMGroup->Count();
2805 for (USHORT n = 0; n < nRowSpan; ++n)
2807 SwTableBox* pCurrentBox = (*pActMGroup)[n];
2808 const long nRowSpanSet = n == 0 ?
2809 nRowSpan :
2810 ((-1) * (nRowSpan - n));
2811 pCurrentBox->setRowSpan( nRowSpanSet );
2815 pIo->pFmtOfJustInsertedApo = 0;
2816 DELETEZ( pMergeGroups );
2821 // durchsucht pMergeGroups, meldet Index der ersten, passenden Gruppe bzw. -1
2823 // Parameter: nXcenter = Mittenposition der anfragenden Box
2824 // nWidth = Breite der anfragenden Box
2825 // bExact = Flag, ob Box in dieser Gruppe passen muss,
2826 // oder diese nur zu tangieren braucht
2828 bool WW8TabDesc::FindMergeGroup(short nX1, short nWidth, bool bExact,
2829 short& nMGrIdx)
2831 nMGrIdx = -1;
2832 if( pMergeGroups )
2834 // noch als gueltig angesehener Bereich in der Naehe der Grenzen
2835 const short nToleranz = 4;
2836 // die aktuell untersuchte Gruppe
2837 WW8SelBoxInfoPtr pActGroup;
2838 // Boxgrenzen
2839 short nX2 = nX1 + nWidth;
2840 // ungefaehre Gruppengrenzen
2841 short nGrX1;
2842 short nGrX2;
2844 // --> OD 2005-02-04 #118544# - improvement: search backwards
2845 //for ( USHORT iGr = 0; iGr < pMergeGroups->Count(); iGr++ )
2846 for ( short iGr = pMergeGroups->Count() - 1; iGr >= 0; --iGr )
2848 // die aktuell untersuchte Gruppe
2849 pActGroup = (*pMergeGroups)[ iGr ];
2850 if (!pActGroup->bGroupLocked)
2852 // ungefaehre Gruppengrenzen mit Toleranz nach *aussen* hin
2853 nGrX1 = pActGroup->nGroupXStart - nToleranz;
2854 nGrX2 = pActGroup->nGroupXStart
2855 +pActGroup->nGroupWidth + nToleranz;
2857 // Falls Box reinpasst, melde auf jeden Fall den Erfolg
2859 if( ( nX1 > nGrX1 ) && ( nX2 < nGrX2 ) )
2861 nMGrIdx = iGr; break;
2864 // hat die Box Bereiche mit der Gruppe gemeinsam?
2866 if( !bExact )
2868 // melde Erfolg, wenn nX1 *oder* nX2 innerhalb der Gruppe liegen
2869 if( ( ( nX1 > nGrX1 )
2870 && ( nX1 < nGrX2 - 2*nToleranz ) )
2871 || ( ( nX2 > nGrX1 + 2*nToleranz )
2872 && ( nX2 < nGrX2 ) )
2873 // oder nX1 und nX2 die Gruppe umfassen
2874 || ( ( nX1 <=nGrX1 )
2875 && ( nX2 >=nGrX2 ) ) )
2877 nMGrIdx = iGr; break;
2883 return ( -1 < nMGrIdx );
2886 bool WW8TabDesc::IsValidCell(short nCol) const
2888 return pActBand->bExist[nCol] && (USHORT)nAktRow < pTabLines->Count();
2891 bool WW8TabDesc::InFirstParaInCell() const
2893 //e.g. #i19718#
2894 if (!pTabBox || !pTabBox->GetSttNd())
2896 ASSERT(false, "Problem with table");
2897 return false;
2900 if (!IsValidCell(GetAktCol()))
2901 return false;
2903 if (pIo->pPaM->GetPoint()->nNode == pTabBox->GetSttIdx() + 1)
2904 return true;
2906 return false;
2909 void WW8TabDesc::StartMiserableHackForUnsupportedDirection(short nWwCol)
2911 ASSERT(pActBand, "Impossible");
2912 if (pActBand && pActBand->maDirections[nWwCol] == 3)
2914 pIo->pCtrlStck->NewAttr(*pIo->pPaM->GetPoint(),
2915 SvxCharRotateItem(900, false, RES_CHRATR_ROTATE));
2919 void WW8TabDesc::EndMiserableHackForUnsupportedDirection(short nWwCol)
2921 ASSERT(pActBand, "Impossible");
2922 if (pActBand && pActBand->maDirections[nWwCol] == 3)
2923 pIo->pCtrlStck->SetAttr(*pIo->pPaM->GetPoint(), RES_CHRATR_ROTATE);
2926 bool WW8TabDesc::SetPamInCell(short nWwCol, bool bPam)
2928 ASSERT( pActBand, "pActBand ist 0" );
2930 USHORT nCol = pActBand->nTransCell[nWwCol];
2932 if ((USHORT)nAktRow >= pTabLines->Count())
2934 ASSERT(!this, "Actual row bigger than expected." );
2935 if (bPam)
2936 MoveOutsideTable();
2937 return false;
2940 pTabLine = (*pTabLines)[nAktRow];
2941 pTabBoxes = &pTabLine->GetTabBoxes();
2943 if (nCol >= pTabBoxes->Count())
2945 if (bPam)
2947 // The first paragraph in a cell with upper autospacing has upper
2948 // spacing set to 0
2949 if (
2950 pIo->bParaAutoBefore && pIo->bFirstPara &&
2951 !pIo->pWDop->fDontUseHTMLAutoSpacing
2954 pIo->SetUpperSpacing(*pIo->pPaM, 0);
2957 // The last paragraph in a cell with lower autospacing has lower
2958 // spacing set to 0
2959 if (pIo->bParaAutoAfter && !pIo->pWDop->fDontUseHTMLAutoSpacing)
2960 pIo->SetLowerSpacing(*pIo->pPaM, 0);
2962 ParkPaM();
2964 return false;
2966 pTabBox = (*pTabBoxes)[nCol];
2967 if( !pTabBox->GetSttNd() )
2969 ASSERT(pTabBox->GetSttNd(), "Probleme beim Aufbau der Tabelle");
2970 if (bPam)
2971 MoveOutsideTable();
2972 return false;
2974 if (bPam)
2976 pAktWWCell = &pActBand->pTCs[ nWwCol ];
2978 // The first paragraph in a cell with upper autospacing has upper spacing set to 0
2979 if(pIo->bParaAutoBefore && pIo->bFirstPara && !pIo->pWDop->fDontUseHTMLAutoSpacing)
2980 pIo->SetUpperSpacing(*pIo->pPaM, 0);
2982 // The last paragraph in a cell with lower autospacing has lower spacing set to 0
2983 if(pIo->bParaAutoAfter && !pIo->pWDop->fDontUseHTMLAutoSpacing)
2984 pIo->SetLowerSpacing(*pIo->pPaM, 0);
2986 //We need to set the pPaM on the first cell, invalid
2987 //or not so that we can collect paragraph proproties over
2988 //all the cells, but in that case on the valid cell we do not
2989 //want to reset the fmt properties
2990 if (pIo->pPaM->GetPoint()->nNode != pTabBox->GetSttIdx() + 1)
2992 pIo->pPaM->GetPoint()->nNode = pTabBox->GetSttIdx() + 1;
2993 pIo->pPaM->GetPoint()->nContent.Assign(pIo->pPaM->GetCntntNode(), 0);
2994 // Zur Sicherheit schon jetzt setzen, da bei den Zellen, die
2995 // zum Randausgleich eingefuegt werden, sonst der Style
2996 // nicht gesetzt wird.
2997 pIo->rDoc.SetTxtFmtColl(*pIo->pPaM, (SwTxtFmtColl*)pIo->pDfltTxtFmtColl);
2998 // uebrigens: da diese Zellen unsichtbare Hilfskonstruktionen sind,
2999 // und nur dazu dienen, zerfranste Aussehen der WW-Tabelle
3000 // nachzuahmen, braucht NICHT SetTxtFmtCollAndListLevel()
3001 // verwendet zu werden.
3004 // Better to turn Snap to Grid off for all paragraphs in tables
3005 if(SwTxtNode *pNd = pIo->pPaM->GetNode()->GetTxtNode())
3007 const SfxPoolItem &rItm = pNd->SwCntntNode::GetAttr(RES_PARATR_SNAPTOGRID);
3008 SvxParaGridItem &rSnapToGrid = (SvxParaGridItem&)(rItm);
3010 if(rSnapToGrid.GetValue())
3012 SvxParaGridItem aGridItem( rSnapToGrid );
3013 aGridItem.SetValue(false);
3015 SwPosition* pGridPos = pIo->pPaM->GetPoint();
3017 xub_StrLen nEnd = pGridPos->nContent.GetIndex();
3018 pGridPos->nContent.Assign(pIo->pPaM->GetCntntNode(), 0);
3019 pIo->pCtrlStck->NewAttr(*pGridPos, aGridItem);
3020 pGridPos->nContent.Assign(pIo->pPaM->GetCntntNode(), nEnd);
3021 pIo->pCtrlStck->SetAttr(*pGridPos, RES_PARATR_SNAPTOGRID);
3025 StartMiserableHackForUnsupportedDirection(nWwCol);
3027 return true;
3030 void WW8TabDesc::InsertCells( short nIns )
3032 pTabLine = (*pTabLines)[nAktRow];
3033 pTabBoxes = &pTabLine->GetTabBoxes();
3034 pTabBox = (*pTabBoxes)[0];
3036 pIo->rDoc.GetNodes().InsBoxen( pTblNd, pTabLine, (SwTableBoxFmt*)pTabBox->GetFrmFmt(),
3037 (SwTxtFmtColl*)pIo->pDfltTxtFmtColl, 0, pTabBoxes->Count(), nIns );
3038 // mit dem Dritten Parameter wird das FrmFmt der Boxen angegeben.
3039 // hier kann man auch noch optimieren, um FrmFmts zu sparen
3042 void WW8TabDesc::SetTabBorders(SwTableBox* pBox, short nWwIdx)
3044 if( nWwIdx < 0 || nWwIdx >= pActBand->nWwCols )
3045 return; // kuenstlich erzeugte Zellen -> Kein Rand
3048 SvxBoxItem aFmtBox( RES_BOX );
3049 if (pActBand->pTCs) // neither Cell Border nor Default Border defined ?
3051 WW8_TCell* pT = &pActBand->pTCs[nWwIdx];
3052 if (pIo->IsBorder(pT->rgbrc))
3053 pIo->SetBorder(aFmtBox, pT->rgbrc);
3056 if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwTOP))
3058 aFmtBox.SetDistance(
3059 pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwTOP],
3060 BOX_LINE_TOP);
3062 else
3063 aFmtBox.SetDistance(pActBand->mnDefaultTop, BOX_LINE_TOP);
3064 if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwBOTTOM))
3066 aFmtBox.SetDistance(
3067 pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwBOTTOM],
3068 BOX_LINE_BOTTOM);
3070 else
3071 aFmtBox.SetDistance(pActBand->mnDefaultBottom,BOX_LINE_BOTTOM);
3073 // nGapHalf bedeutet bei WW ein *horizontaler* Abstand zwischen
3074 // Tabellenzelle und -Inhalt
3075 short nLeftDist =
3076 pActBand->mbHasSpacing ? pActBand->mnDefaultLeft : pActBand->nGapHalf;
3077 short nRightDist =
3078 pActBand->mbHasSpacing ? pActBand->mnDefaultRight : pActBand->nGapHalf;
3079 if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwLEFT))
3081 aFmtBox.SetDistance(
3082 pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwLEFT],
3083 BOX_LINE_LEFT);
3085 else
3086 aFmtBox.SetDistance(nLeftDist, BOX_LINE_LEFT);
3087 if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwRIGHT))
3089 aFmtBox.SetDistance(
3090 pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwRIGHT],
3091 BOX_LINE_RIGHT);
3093 else
3094 aFmtBox.SetDistance(nRightDist,BOX_LINE_RIGHT);
3096 pBox->GetFrmFmt()->SetFmtAttr(aFmtBox);
3099 void WW8TabDesc::SetTabShades( SwTableBox* pBox, short nWwIdx )
3101 if( nWwIdx < 0 || nWwIdx >= pActBand->nWwCols )
3102 return; // kuenstlich erzeugte Zellen -> Keine Farbe
3104 bool bFound=false;
3105 if (pActBand->pNewSHDs && pActBand->pNewSHDs[nWwIdx] != COL_AUTO)
3107 Color aColor(pActBand->pNewSHDs[nWwIdx]);
3108 if (aColor.GetColor() == 0x00333333)
3109 pIo->maTracer.Log(sw::log::eAutoColorBg);
3110 pBox->GetFrmFmt()->SetFmtAttr(SvxBrushItem(aColor, RES_BACKGROUND));
3111 bFound = true;
3114 //If there was no new shades, or no new shade setting
3115 if (pActBand->pSHDs && !bFound)
3117 WW8_SHD& rSHD = pActBand->pSHDs[nWwIdx];
3118 if (!rSHD.GetValue()) // auto
3119 return;
3121 SwWW8Shade aSh( pIo->bVer67, rSHD );
3122 pBox->GetFrmFmt()->SetFmtAttr(SvxBrushItem(aSh.aColor, RES_BACKGROUND));
3126 SvxFrameDirection MakeDirection(sal_uInt16 nCode, BOOL bIsBiDi)
3128 SvxFrameDirection eDir = FRMDIR_ENVIRONMENT;
3129 // 1: Asian layout with rotated CJK characters
3130 // 5: Asian layout
3131 // 3: Western layout rotated by 90 degrees
3132 // 4: Western layout
3133 switch (nCode)
3135 default:
3136 ASSERT(eDir == 4, "unknown direction code, maybe its a bitfield");
3137 case 3:
3138 // --> FME/Alan Yaniger: 2006-09-15 #i38158# Consider RTL tables:
3139 eDir = bIsBiDi ? FRMDIR_HORI_RIGHT_TOP : FRMDIR_HORI_LEFT_TOP;
3140 // <--
3141 break;
3142 case 5:
3143 eDir = FRMDIR_VERT_TOP_RIGHT;
3144 break;
3145 case 1:
3146 eDir = FRMDIR_VERT_TOP_RIGHT;
3147 break;
3148 case 4:
3149 // --> FME/Alan Yaniger: 2006-09-15 #i38158# Consider RTL tables:
3150 eDir = bIsBiDi ? FRMDIR_HORI_RIGHT_TOP : FRMDIR_HORI_LEFT_TOP;
3151 // <--
3152 break;
3154 return eDir;
3157 void WW8TabDesc::SetTabDirection(SwTableBox* pBox, short nWwIdx)
3159 if (nWwIdx < 0 || nWwIdx >= pActBand->nWwCols)
3160 return;
3161 SvxFrameDirectionItem aItem(MakeDirection(pActBand->maDirections[nWwIdx], bIsBiDi), RES_FRAMEDIR);
3162 pBox->GetFrmFmt()->SetFmtAttr(aItem);
3165 void WW8TabDesc::SetTabVertAlign( SwTableBox* pBox, short nWwIdx )
3167 if( nWwIdx < 0 || nWwIdx >= pActBand->nWwCols )
3168 return;
3170 sal_Int16 eVertOri=text::VertOrientation::TOP;
3172 if( pActBand->pTCs )
3174 WW8_TCell* pT = &pActBand->pTCs[nWwIdx];
3175 switch (pT->nVertAlign)
3177 case 0:
3178 default:
3179 eVertOri = text::VertOrientation::TOP;
3180 break;
3181 case 1:
3182 eVertOri = text::VertOrientation::CENTER;
3183 break;
3184 case 2:
3185 eVertOri = text::VertOrientation::BOTTOM;
3186 break;
3190 pBox->GetFrmFmt()->SetFmtAttr( SwFmtVertOrient(0,eVertOri) );
3193 void WW8TabDesc::AdjustNewBand()
3195 if( pActBand->nSwCols > nDefaultSwCols ) // Zellen splitten
3196 InsertCells( pActBand->nSwCols - nDefaultSwCols );
3198 SetPamInCell( 0, false);
3199 ASSERT( pTabBoxes && pTabBoxes->Count() == (USHORT)pActBand->nSwCols,
3200 "Falsche Spaltenzahl in Tabelle" )
3202 if( bClaimLineFmt )
3204 pTabLine->ClaimFrmFmt(); // noetig wg. Zeilenhoehe
3205 SwFmtFrmSize aF( ATT_MIN_SIZE, 0, 0 ); // default
3207 if (pActBand->nLineHeight == 0) // 0 = Auto
3208 aF.SetHeightSizeType( ATT_VAR_SIZE );
3209 else
3211 if (pActBand->nLineHeight < 0) // Pos = min, Neg = exakt
3213 aF.SetHeightSizeType(ATT_FIX_SIZE);
3214 pActBand->nLineHeight = -pActBand->nLineHeight;
3216 if (pActBand->nLineHeight < MINLAY) // nicht erlaubte Zeilenhoehe
3217 pActBand->nLineHeight = MINLAY;
3219 aF.SetHeight(pActBand->nLineHeight);// Min- / Exakt-Hoehe setzen
3221 pTabLine->GetFrmFmt()->SetFmtAttr(aF);
3224 //Word stores 1 for bCantSplit if the row cannot be split, we set true if
3225 //we can split the row
3226 // bCantSplit: Always true for rows containing merged cells (Word <= 2000 crashes otherwise)
3227 // So in case bCantSplit is true, we check for bCantSplit90, which has been introduced for
3228 // Word versions >= 2002.
3229 bool bSetCantSplit = pActBand->bCantSplit;
3230 if(bSetCantSplit)
3231 bSetCantSplit = pActBand->bCantSplit90;
3233 pTabLine->GetFrmFmt()->SetFmtAttr(SwFmtRowSplit(!bSetCantSplit));
3235 short i; // SW-Index
3236 short j; // WW-Index
3237 short nW; // Breite
3238 SwFmtFrmSize aFS( ATT_FIX_SIZE );
3239 j = pActBand->bLEmptyCol ? -1 : 0;
3241 for( i = 0; i < pActBand->nSwCols; i++ )
3243 // setze Zellenbreite
3244 if( j < 0 )
3245 nW = pActBand->nCenter[0] - nMinLeft;
3246 else
3248 //Set j to first non invalid cell
3249 while ((j < pActBand->nWwCols) && (!pActBand->bExist[j]))
3250 j++;
3252 if( j < pActBand->nWwCols )
3253 nW = pActBand->nCenter[j+1] - pActBand->nCenter[j];
3254 else
3255 nW = nMaxRight - pActBand->nCenter[j];
3256 pActBand->nWidth[ j ] = nW;
3259 SwTableBox* pBox = (*pTabBoxes)[i];
3260 // liesse sich durch intelligentes Umhaengen der FrmFmts noch weiter
3261 // verringern
3262 pBox->ClaimFrmFmt();
3264 SetTabBorders(pBox, j);
3266 // #i18128# word has only one line between adjoining vertical cells
3267 // we have to mimick this in the filter by picking the larger of the
3268 // sides and using that one on one side of the line (right)
3269 SvxBoxItem aCurrentBox(sw::util::ItemGet<SvxBoxItem>(*(pBox->GetFrmFmt()), RES_BOX));
3270 const SvxBorderLine *pLeftLine = aCurrentBox.GetLine(BOX_LINE_LEFT);
3271 int nCurrentRightLineWidth = 0;
3272 if(pLeftLine)
3273 nCurrentRightLineWidth = pLeftLine->GetInWidth() + pLeftLine->GetOutWidth() + pLeftLine->GetDistance();
3275 if (i != 0)
3277 SwTableBox* pBox2 = (*pTabBoxes)[i-1];
3278 SvxBoxItem aOldBox(sw::util::ItemGet<SvxBoxItem>(*(pBox2->GetFrmFmt()), RES_BOX));
3279 const SvxBorderLine *pRightLine = aOldBox.GetLine(BOX_LINE_RIGHT);
3280 int nOldBoxRightLineWidth = 0;
3281 if(pRightLine)
3282 nOldBoxRightLineWidth = pRightLine->GetInWidth() + pRightLine->GetOutWidth() + pRightLine->GetDistance();
3284 if(nOldBoxRightLineWidth>nCurrentRightLineWidth)
3285 aCurrentBox.SetLine(aOldBox.GetLine(BOX_LINE_RIGHT), BOX_LINE_LEFT);
3287 aOldBox.SetLine(0, BOX_LINE_RIGHT);
3288 pBox2->GetFrmFmt()->SetFmtAttr(aOldBox);
3291 pBox->GetFrmFmt()->SetFmtAttr(aCurrentBox);
3293 SetTabVertAlign(pBox, j);
3294 SetTabDirection(pBox, j);
3295 if( pActBand->pSHDs || pActBand->pNewSHDs)
3296 SetTabShades(pBox, j);
3297 j++;
3299 aFS.SetWidth( nW );
3300 pBox->GetFrmFmt()->SetFmtAttr( aFS );
3302 // ueberspringe nicht existente Zellen
3303 while( ( j < pActBand->nWwCols ) && !pActBand->bExist[j] )
3305 pActBand->nWidth[j] = pActBand->nCenter[j+1] - pActBand->nCenter[j];
3306 j++;
3311 void WW8TabDesc::TableCellEnd()
3313 ::SetProgressState(pIo->nProgress, pIo->mpDocShell); // Update
3315 EndMiserableHackForUnsupportedDirection(nAktCol);
3317 // neue Zeile
3318 if( pIo->bWasTabRowEnd )
3320 // bWasTabRowEnd will be deactivated in
3321 // SwWW8ImplReader::ProcessSpecial()
3323 USHORT iCol = GetLogicalWWCol();
3324 if (iCol < aNumRuleNames.size())
3326 aNumRuleNames.erase(aNumRuleNames.begin() + iCol,
3327 aNumRuleNames.end());
3330 nAktCol = 0;
3331 nAktRow++;
3332 nAktBandRow++;
3333 ASSERT( pActBand , "pActBand ist 0" );
3334 if( pActBand )
3336 if( nAktRow >= nRows ) // am Tabellenende gibt's nichts sinnvolles
3337 return; // mehr zu tun
3339 bool bNewBand = nAktBandRow >= pActBand->nRows;
3340 if( bNewBand )
3341 { // neues Band noetig ?
3342 pActBand = pActBand->pNextBand; //
3343 nAktBandRow = 0;
3344 ASSERT( pActBand, "pActBand ist 0" );
3345 AdjustNewBand();
3347 else
3349 SwTableBox* pBox = (*pTabBoxes)[0];
3350 SwSelBoxes aBoxes;
3351 pIo->rDoc.InsertRow( pTable->SelLineFromBox( pBox, aBoxes ) );
3355 else
3356 { // neue Spalte ( Zelle )
3357 nAktCol++;
3359 SetPamInCell(nAktCol, true);
3361 // finish Annotated Level Numbering ?
3362 if (pIo->bAnl && !pIo->bAktAND_fNumberAcross)
3363 pIo->StopAllAnl(IsValidCell(nAktCol));
3366 // ggfs. die Box in fuer diese Col offene Merge-Gruppe eintragen
3367 SwTableBox* WW8TabDesc::UpdateTableMergeGroup( WW8_TCell& rCell,
3368 WW8SelBoxInfo* pActGroup,
3369 SwTableBox* pActBox,
3370 USHORT nCol )
3372 // Rueckgabewert defaulten
3373 SwTableBox* pResult = 0;
3375 // pruefen, ob die Box zu mergen ist
3376 // --> OD 2005-02-04 #118544# - If cell is the first one to be merged,
3377 // a new merge group has to be provided.
3378 // E.g., it could be that a cell is the first one to be merged, but no
3379 // new merge group is provided, because the potential other cell to be merged
3380 // doesn't exist - see method <WW8TabDesc::MergeCells>.
3381 if ( pActBand->bExist[ nCol ] &&
3382 ( ( rCell.bFirstMerged && pActGroup ) ||
3383 rCell.bMerged ||
3384 rCell.bVertMerge ||
3385 rCell.bVertRestart ) )
3386 // <--
3388 // passende Merge-Gruppe ermitteln
3389 WW8SelBoxInfo* pTheMergeGroup = 0;
3390 if( pActGroup )
3391 // Gruppe uebernehmen
3392 pTheMergeGroup = pActGroup;
3393 else
3395 // Gruppe finden
3396 short nMGrIdx;
3397 if( FindMergeGroup( pActBand->nCenter[ nCol ],
3398 pActBand->nWidth[ nCol ], true, nMGrIdx ) )
3399 pTheMergeGroup = (*pMergeGroups)[ nMGrIdx ];
3401 if( pTheMergeGroup )
3403 // aktuelle Box der Merge-Gruppe hinzufuegen
3404 pTheMergeGroup->Insert( pActBox, pTheMergeGroup->Count() );
3406 // Target-Box zurueckmelden
3407 pResult = (*pTheMergeGroup)[ 0 ];
3410 return pResult;
3414 USHORT WW8TabDesc::GetLogicalWWCol() const // returns number of col as INDICATED within WW6 UI status line -1
3416 USHORT nCol = 0;
3417 if( pActBand && pActBand->pTCs)
3419 for( USHORT iCol = 1; iCol <= nAktCol; ++iCol )
3421 if( !pActBand->pTCs[ iCol-1 ].bMerged )
3422 ++nCol;
3425 return nCol;
3428 // find name of numrule valid for current WW-COL
3429 const String& WW8TabDesc::GetNumRuleName() const
3431 USHORT nCol = GetLogicalWWCol();
3432 if (nCol < aNumRuleNames.size())
3433 return aNumRuleNames[nCol];
3434 else
3435 return aEmptyStr;
3438 void WW8TabDesc::SetNumRuleName( const String& rName )
3440 USHORT nCol = GetLogicalWWCol();
3441 for (USHORT nSize = static_cast< USHORT >(aNumRuleNames.size()); nSize <= nCol; ++nSize)
3442 aNumRuleNames.push_back(aEmptyStr);
3443 aNumRuleNames[nCol] = rName;
3446 bool SwWW8ImplReader::StartTable(WW8_CP nStartCp)
3448 // Entering a table so make sure the the FirstPara flag gets set
3449 bFirstPara = true;
3450 // keine rekursiven Tabellen Nicht bei EinfuegenDatei in Tabelle oder
3451 // Fussnote
3452 if (bReadNoTbl)
3453 return false;
3455 if (pTableDesc)
3456 maTableStack.push(pTableDesc);
3458 // --> OD 2005-01-27 #i33818# - determine absolute position object attributes,
3459 // if possible. It's needed for nested tables.
3460 WW8FlyPara* pTableWFlyPara( 0L );
3461 WW8SwFlyPara* pTableSFlyPara( 0L );
3462 // --> OD 2005-03-21 #i45301# - anchor nested table inside Writer fly frame
3463 // only at-character, if absolute position object attributes are available.
3464 // Thus, default anchor type is as-character anchored.
3465 RndStdIds eAnchor( FLY_IN_CNTNT );
3466 // <--
3467 if ( nInTable )
3469 WW8_TablePos* pNestedTabPos( 0L );
3470 WW8_TablePos aNestedTabPos;
3471 WW8PLCFxSave1 aSave;
3472 pPlcxMan->GetPap()->Save( aSave );
3473 WW8PLCFx_Cp_FKP* pPap = pPlcxMan->GetPapPLCF();
3474 WW8_CP nMyStartCp = nStartCp;
3475 if ( SearchRowEnd( pPap, nMyStartCp, nInTable ) &&
3476 ParseTabPos( &aNestedTabPos, pPap ) )
3478 pNestedTabPos = &aNestedTabPos;
3480 pPlcxMan->GetPap()->Restore( aSave );
3481 if ( pNestedTabPos )
3483 ApoTestResults aApo = TestApo( nInTable + 1, false, pNestedTabPos );
3484 pTableWFlyPara = ConstructApo( aApo, pNestedTabPos );
3485 if ( pTableWFlyPara )
3487 // --> OD 2007-07-03 #148498#
3488 // <WW8SwFlyPara> constructor has changed - new 4th parameter
3489 // containing WW8 page top margin.
3490 pTableSFlyPara = new WW8SwFlyPara(*pPaM, *this, *pTableWFlyPara,
3491 maSectionManager.GetWWPageTopMargin(),
3492 maSectionManager.GetPageLeft(), maSectionManager.GetTextAreaWidth(),
3493 nIniFlyDx, nIniFlyDy);
3494 // <--
3495 // --> OD 2005-03-21 #i45301# - anchor nested table Writer fly
3496 // frame at-character
3497 eAnchor = FLY_AUTO_CNTNT;
3498 // <--
3502 // <--
3504 pTableDesc = new WW8TabDesc( this, nStartCp );
3506 if( pTableDesc->Ok() )
3508 int nNewInTable = nInTable + 1;
3509 if (InEqualApo(nNewInTable))
3511 ASSERT(pSFlyPara->pFlyFmt,
3512 "how could we be in a local apo and have no apo");
3515 if ( eAnchor == FLY_AUTO_CNTNT && !maTableStack.empty() && !InEqualApo(nNewInTable) )
3517 pTableDesc->pParentPos = new SwPosition(*pPaM->GetPoint());
3518 SfxItemSet aItemSet(rDoc.GetAttrPool(),
3519 RES_FRMATR_BEGIN, RES_FRMATR_END-1);
3520 // --> OD 2005-01-26 #i33818# - anchor the Writer fly frame for
3521 // the nested table at-character.
3522 // --> OD 2005-03-21 #i45301#
3523 SwFmtAnchor aAnchor( eAnchor );
3524 aAnchor.SetAnchor( pTableDesc->pParentPos );
3525 aItemSet.Put( aAnchor );
3526 pTableDesc->pFlyFmt = rDoc.MakeFlySection( eAnchor,
3527 pTableDesc->pParentPos, &aItemSet);
3528 ASSERT( pTableDesc->pFlyFmt->GetAnchor().GetAnchorId() == eAnchor,
3529 "Not the anchor type requested!" );
3530 // <--
3531 MoveInsideFly(pTableDesc->pFlyFmt);
3533 pTableDesc->CreateSwTable();
3534 if (pTableDesc->pFlyFmt)
3536 pTableDesc->SetSizePosition(pTableDesc->pFlyFmt);
3537 // --> OD 2005-01-26 #i33818# - Use absolute position object
3538 // attributes, if existing, and apply them to the created Writer fly
3539 // frame.
3540 if ( pTableWFlyPara && pTableSFlyPara )
3542 WW8FlySet aFlySet( *this, pTableWFlyPara, pTableSFlyPara, false );
3543 SwFmtAnchor aAnchor( FLY_AUTO_CNTNT );
3544 aAnchor.SetAnchor( pTableDesc->pParentPos );
3545 aFlySet.Put( aAnchor );
3546 pTableDesc->pFlyFmt->SetFmtAttr( aFlySet );
3548 else
3550 SwFmtHoriOrient aHori =
3551 pTableDesc->pTable->GetFrmFmt()->GetHoriOrient();
3552 pTableDesc->pFlyFmt->SetFmtAttr(aHori);
3553 pTableDesc->pFlyFmt->SetFmtAttr( SwFmtSurround( SURROUND_NONE ) );
3555 // <--
3556 // --> OD 2005-01-27 #i33818# - The nested table doesn't have to leave
3557 // the table cell. Thus, the Writer fly frame has to follow the text flow.
3558 pTableDesc->pFlyFmt->SetFmtAttr( SwFmtFollowTextFlow( TRUE ) );
3559 // <--
3561 else
3562 pTableDesc->SetSizePosition(0);
3563 pTableDesc->UseSwTable();
3565 else
3566 PopTableDesc();
3568 // --> OD 2005-01-28 #i33818#
3569 delete pTableWFlyPara;
3570 delete pTableSFlyPara;
3571 // <--
3573 bool bSuccess = (0 != pTableDesc);
3574 if (bSuccess)
3576 maTracer.EnterEnvironment(sw::log::eTable, rtl::OUString::valueOf(
3577 static_cast<sal_Int32>(maTableStack.size())));
3579 return bSuccess;
3582 bool lcl_PamContainsFly(SwPaM & rPam)
3584 bool bResult = false;
3585 SwNodeRange aRg( rPam.Start()->nNode, rPam.End()->nNode );
3586 SwDoc * pDoc = rPam.GetDoc();
3588 sal_uInt16 n = 0;
3589 SwSpzFrmFmts * pSpzFmts = pDoc->GetSpzFrmFmts();
3590 sal_uInt16 nCount = pSpzFmts->Count();
3591 while (!bResult && n < nCount)
3593 SwFrmFmt* pFly = (*pSpzFmts)[n];
3594 const SwFmtAnchor* pAnchor = &pFly->GetAnchor();
3596 switch (pAnchor->GetAnchorId())
3598 case FLY_AT_CNTNT:
3599 case FLY_AUTO_CNTNT:
3601 const SwPosition* pAPos = pAnchor->GetCntntAnchor();
3603 if (pAPos != NULL &&
3604 aRg.aStart <= pAPos->nNode &&
3605 pAPos->nNode <= aRg.aEnd)
3607 bResult = true;
3610 break;
3611 default:
3612 break;
3615 ++n;
3618 return bResult;
3621 void SwWW8ImplReader::TabCellEnd()
3623 if (nInTable && pTableDesc)
3625 pTableDesc->TableCellEnd();
3627 if (bReadTable
3628 && pWFlyPara == NULL
3629 && mpTableEndPaM.get() != NULL
3630 && (! SwPaM::Overlap(*pPaM, *mpTableEndPaM))
3631 && SwPaM::LessThan(*mpTableEndPaM, *pPaM)
3632 && mpTableEndPaM->GetPoint()->nNode.GetNode().IsTxtNode()
3633 && !lcl_PamContainsFly(*mpTableEndPaM)
3636 rDoc.DelFullPara(*mpTableEndPaM);
3640 bFirstPara = true; // We have come to the end of a cell so FirstPara flag
3641 bReadTable = false;
3642 mpTableEndPaM.reset();
3645 void SwWW8ImplReader::Read_TabCellEnd( USHORT, const BYTE* pData, short nLen)
3647 if( ( nLen > 0 ) && ( *pData == 1 ) )
3648 bWasTabCellEnd = true;
3651 void SwWW8ImplReader::Read_TabRowEnd( USHORT, const BYTE* pData, short nLen ) // Sprm25
3653 if( ( nLen > 0 ) && ( *pData == 1 ) )
3654 bWasTabRowEnd = true;
3657 void SwWW8ImplReader::PopTableDesc()
3659 if (pTableDesc && pTableDesc->pFlyFmt)
3661 MoveOutsideFly(pTableDesc->pFlyFmt,*pTableDesc->pParentPos);
3664 delete pTableDesc;
3665 if (maTableStack.empty())
3666 pTableDesc = 0;
3667 else
3669 pTableDesc = maTableStack.top();
3670 maTableStack.pop();
3674 void SwWW8ImplReader::StopTable()
3676 maTracer.LeaveEnvironment(sw::log::eTable);
3678 ASSERT(pTableDesc, "Panic, stop table with no table!");
3679 if (!pTableDesc)
3680 return;
3682 // We are leaving a table so make sure the next paragraph doesn't think
3683 // it's the first paragraph
3684 bFirstPara = false;
3686 pTableDesc->FinishSwTable();
3687 PopTableDesc();
3689 if (!maTableStack.empty())
3691 maTracer.EnterEnvironment(sw::log::eTable, rtl::OUString::valueOf(
3692 static_cast<sal_Int32>(maTableStack.size())));
3695 bReadTable = true;
3696 // --> OD 2009-04-16 #i101116#
3697 // Keep PaM on table end only for nested tables
3698 if ( nInTable > 1 )
3700 mpTableEndPaM.reset(new SwPaM(*pPaM));
3702 // <--
3705 // GetTableLeft() wird fuer absatzgebundene Grafikobjekte in Tabellen
3706 // gebraucht.
3707 // WW nimmt bei eingerueckten Tabellen den Absatzrand, der ohne Tabelle
3708 // gueltig waere, als Basis; SW benutzt den linken Tabellenrand.
3709 short SwWW8ImplReader::GetTableLeft()
3711 return (pTableDesc) ? pTableDesc->GetMinLeft() : 0;
3714 bool SwWW8ImplReader::IsInvalidOrToBeMergedTabCell() const
3716 if( !pTableDesc )
3717 return false;
3719 const WW8_TCell* pCell = pTableDesc->GetAktWWCell();
3721 return !pTableDesc->IsValidCell( pTableDesc->GetAktCol() )
3722 || ( pCell
3723 && ( !pCell->bFirstMerged
3724 && ( pCell->bMerged
3725 || ( pCell->bVertMerge
3726 && !pCell->bVertRestart
3733 USHORT SwWW8ImplReader::StyleUsingLFO( USHORT nLFOIndex ) const
3735 USHORT nRes = USHRT_MAX;
3736 if( pCollA )
3738 for(USHORT nI = 0; nI < pStyles->GetCount(); nI++ )
3739 if( pCollA[ nI ].bValid
3740 && (nLFOIndex == pCollA[ nI ].nLFOIndex) )
3741 nRes = nI;
3743 return nRes;
3746 const SwFmt* SwWW8ImplReader::GetStyleWithOrgWWName( String& rName ) const
3748 SwFmt* pRet = 0;
3749 if( pCollA )
3751 for(USHORT nI = 0; nI < pStyles->GetCount(); nI++ )
3752 if( pCollA[ nI ].bValid
3753 && (rName.Equals( pCollA[ nI ].GetOrgWWName())) )
3755 pRet = pCollA[ nI ].pFmt;
3756 break;
3759 return pRet;
3762 //-----------------------------------------
3763 // class WW8RStyle
3764 //-----------------------------------------
3766 const BYTE* WW8RStyle::HasParaSprm( USHORT nId ) const
3768 if( !pParaSprms || !nSprmsLen )
3769 return 0;
3771 const BYTE* pSprms = pParaSprms;
3772 USHORT i, x;
3774 for( i=0; i < nSprmsLen; )
3776 USHORT nAktId = maSprmParser.GetSprmId(pSprms);
3777 // Sprm found ?
3778 if( nAktId == nId )
3779 return pSprms + maSprmParser.DistanceToData(nId);
3781 x = maSprmParser.GetSprmSize(nAktId, pSprms);
3782 i = i + x;
3783 pSprms += x;
3785 return 0; // Sprm not found
3788 void WW8RStyle::ImportSprms(BYTE *pSprms, short nLen, bool bPap)
3790 if (!nLen)
3791 return;
3793 if( bPap )
3795 pParaSprms = pSprms; // fuer HasParaSprms()
3796 nSprmsLen = nLen;
3799 while ( nLen > 0 )
3801 USHORT nL1 = pIo->ImportSprm(pSprms);
3802 nLen = nLen - nL1;
3803 pSprms += nL1;
3806 pParaSprms = 0;
3807 nSprmsLen = 0;
3810 void WW8RStyle::ImportSprms(sal_Size nPosFc, short nLen, bool bPap)
3812 if (!nLen)
3813 return;
3815 BYTE *pSprms = new BYTE[nLen];
3817 pStStrm->Seek(nPosFc);
3818 pStStrm->Read(pSprms, nLen);
3820 ImportSprms(pSprms, nLen, bPap);
3822 delete[] pSprms;
3825 static inline short WW8SkipOdd(SvStream* pSt )
3827 if ( pSt->Tell() & 0x1 )
3829 UINT8 c;
3830 pSt->Read( &c, 1 );
3831 return 1;
3833 return 0;
3836 static inline short WW8SkipEven(SvStream* pSt )
3838 if (!(pSt->Tell() & 0x1))
3840 UINT8 c;
3841 pSt->Read( &c, 1 );
3842 return 1;
3844 return 0;
3847 short WW8RStyle::ImportUPX(short nLen, bool bPAP, bool bOdd)
3849 INT16 cbUPX;
3851 if( 0 < nLen ) // Empty ?
3853 if (bOdd)
3854 nLen = nLen - WW8SkipEven( pStStrm );
3855 else
3856 nLen = nLen - WW8SkipOdd( pStStrm );
3858 *pStStrm >> cbUPX;
3860 nLen-=2;
3862 if ( cbUPX > nLen )
3863 cbUPX = nLen; // !cbUPX auf nLen verkleinert!
3865 if( (1 < cbUPX) || ( (0 < cbUPX) && !bPAP ) )
3867 if( bPAP )
3869 UINT16 id;
3870 *pStStrm >> id;
3872 cbUPX-= 2;
3873 nLen-= 2;
3876 if( 0 < cbUPX )
3878 sal_Size nPos = pStStrm->Tell(); // falls etwas falsch interpretiert
3879 // wird, gehts danach wieder richtig
3880 ImportSprms( nPos, cbUPX, bPAP );
3882 if ( pStStrm->Tell() != nPos + cbUPX )
3883 pStStrm->Seek( nPos+cbUPX );
3885 nLen = nLen - cbUPX;
3889 return nLen;
3892 void WW8RStyle::ImportGrupx(short nLen, bool bPara, bool bOdd)
3894 if( nLen <= 0 )
3895 return;
3896 if (bOdd)
3897 nLen = nLen - WW8SkipEven( pStStrm );
3898 else
3899 nLen = nLen - WW8SkipOdd( pStStrm );
3901 if( bPara ) // Grupx.Papx
3902 nLen = ImportUPX(nLen, true, bOdd);
3903 ImportUPX(nLen, false, bOdd); // Grupx.Chpx
3906 WW8RStyle::WW8RStyle(WW8Fib& _rFib, SwWW8ImplReader* pI)
3907 : WW8Style(*pI->pTableStream, _rFib), maSprmParser(_rFib.GetFIBVersion()),
3908 pIo(pI), pStStrm(pI->pTableStream), pStyRule(0), nWwNumLevel(0)
3910 pIo->pCollA = new SwWW8StyInf[ cstd ]; // Style-UEbersetzung WW->SW
3911 pIo->nColls = cstd;
3914 void WW8RStyle::Set1StyleDefaults()
3916 if (!bCJKFontChanged) // Style no CJK Font? set the default
3917 pIo->SetNewFontAttr(ftcStandardChpCJKStsh, true, RES_CHRATR_CJK_FONT);
3919 // see i25247
3920 const WW8_FFN* pF = pIo->pFonts->GetFont(3);
3921 if (pF)
3923 rtl_TextEncoding eEnc = WW8Fib::GetFIBCharset(pF->chs);
3924 if ((ftcStandardChpCTLStsh == 0) && (eEnc == RTL_TEXTENCODING_MS_1255))
3925 ftcStandardChpCTLStsh = 3;
3928 if (ftcStandardChpCJKStsh == 0)
3929 ftcStandardChpCJKStsh = 2;
3931 if (!bCTLFontChanged) // Style no CTL Font? set the default
3932 pIo->SetNewFontAttr(ftcStandardChpCTLStsh, true, RES_CHRATR_CTL_FONT);
3934 //#88976# western 2nd to make western charset conversion the default
3935 if (!bFontChanged) // Style has no Font? set the default,
3937 pIo->SetNewFontAttr(ftcStandardChpStsh, true, RES_CHRATR_FONT);
3938 /* removed by a patch from cmc for #i52786#
3939 if (pIo->bVer67)
3940 SetStyleCharSet(pIo->pCollA[pIo->nAktColl]);
3944 if( !pIo->bNoAttrImport )
3946 // Style has no text color set, winword default is auto
3947 if ( !bTxtColChanged )
3948 pIo->pAktColl->SetFmtAttr(SvxColorItem(Color(COL_AUTO), RES_CHRATR_COLOR));
3950 // Style has no FontSize ? WinWord Default is 10pt for western and asian
3951 if( !bFSizeChanged )
3953 SvxFontHeightItem aAttr(200, 100, RES_CHRATR_FONTSIZE);
3954 pIo->pAktColl->SetFmtAttr(aAttr);
3955 aAttr.SetWhich(RES_CHRATR_CJK_FONTSIZE);
3956 pIo->pAktColl->SetFmtAttr(aAttr);
3959 // Style has no FontSize ? WinWord Default is 10pt for western and asian
3960 if( !bFCTLSizeChanged )
3962 SvxFontHeightItem aAttr(200, 100, RES_CHRATR_FONTSIZE);
3963 aAttr.SetWhich(RES_CHRATR_CTL_FONTSIZE);
3964 pIo->pAktColl->SetFmtAttr(aAttr);
3967 if( pIo->pWDop->fWidowControl && !bWidowsChanged ) // Widows ?
3969 pIo->pAktColl->SetFmtAttr( SvxWidowsItem( 2, RES_PARATR_WIDOWS ) );
3970 pIo->pAktColl->SetFmtAttr( SvxOrphansItem( 2, RES_PARATR_ORPHANS ) );
3975 bool WW8RStyle::PrepareStyle(SwWW8StyInf &rSI, ww::sti eSti, sal_uInt16 nThisStyle, sal_uInt16 nNextStyle)
3977 SwFmt* pColl;
3978 bool bStyExist;
3979 if (rSI.bColl)
3981 // Para-Style
3982 sw::util::ParaStyleMapper::StyleResult aResult =
3983 pIo->maParaStyleMapper.GetStyle(rSI.GetOrgWWName(), eSti);
3984 pColl = aResult.first;
3985 bStyExist = aResult.second;
3987 else
3989 // Char-Style
3990 sw::util::CharStyleMapper::StyleResult aResult =
3991 pIo->maCharStyleMapper.GetStyle(rSI.GetOrgWWName(), eSti);
3992 pColl = aResult.first;
3993 bStyExist = aResult.second;
3996 bool bImport = !bStyExist || pIo->mbNewDoc; // Inhalte Importieren ?
3997 bool bOldNoImp = pIo->bNoAttrImport;
3998 rSI.bImportSkipped = !bImport;
4000 if( !bImport )
4001 pIo->bNoAttrImport = true;
4002 else
4004 if (bStyExist)
4006 // --> OD 2007-01-25 #i73790# - method renamed
4007 pColl->ResetAllFmtAttr();
4008 // <--
4010 pColl->SetAuto(false); // nach Empfehlung JP
4011 } // macht die UI aber anders
4012 pIo->pAktColl = pColl;
4013 rSI.pFmt = pColl; // UEbersetzung WW->SW merken
4014 rSI.bImportSkipped = !bImport;
4016 // Set Based on style
4017 USHORT j = rSI.nBase;
4018 if (j != nThisStyle && j < cstd )
4020 SwWW8StyInf* pj = &pIo->pCollA[j];
4021 if (rSI.pFmt && pj->pFmt && rSI.bColl == pj->bColl)
4023 rSI.pFmt->SetDerivedFrom( pj->pFmt ); // ok, Based on eintragen
4024 rSI.eLTRFontSrcCharSet = pj->eLTRFontSrcCharSet;
4025 rSI.eRTLFontSrcCharSet = pj->eRTLFontSrcCharSet;
4026 rSI.eCJKFontSrcCharSet = pj->eCJKFontSrcCharSet;
4027 rSI.n81Flags = pj->n81Flags;
4028 rSI.n81BiDiFlags = pj->n81BiDiFlags;
4029 rSI.nOutlineLevel = pj->nOutlineLevel;
4030 rSI.bParaAutoBefore = pj->bParaAutoBefore;
4031 rSI.bParaAutoAfter = pj->bParaAutoAfter;
4033 if (pj->pWWFly)
4034 rSI.pWWFly = new WW8FlyPara(pIo->bVer67, pj->pWWFly);
4037 else if( pIo->mbNewDoc && bStyExist )
4038 rSI.pFmt->SetDerivedFrom(0);
4040 rSI.nFollow = nNextStyle; // Follow merken
4042 pStyRule = 0; // falls noetig, neu anlegen
4043 bTxtColChanged = bFontChanged = bCJKFontChanged = bCTLFontChanged =
4044 bFSizeChanged = bFCTLSizeChanged = bWidowsChanged = false;
4045 pIo->SetNAktColl( nThisStyle );
4046 pIo->bStyNormal = nThisStyle == 0;
4047 return bOldNoImp;
4050 void WW8RStyle::PostStyle(SwWW8StyInf &rSI, bool bOldNoImp)
4052 // Alle moeglichen Attribut-Flags zuruecksetzen,
4053 // da es in Styles keine Attr-Enden gibt
4055 pIo->bHasBorder = pIo->bShdTxtCol = pIo->bCharShdTxtCol
4056 = pIo->bSpec = pIo->bObj = pIo->bSymbol = false;
4057 pIo->nCharFmt = -1;
4059 // If Style basiert auf Nichts oder Basis ignoriert
4060 if ((rSI.nBase >= cstd || pIo->pCollA[rSI.nBase].bImportSkipped) && rSI.bColl)
4062 //! Char-Styles funktionieren aus
4063 // unerfindlichen Gruenden nicht
4064 // -> dann evtl. harte WW-Defaults
4065 // reinsetzen
4066 Set1StyleDefaults();
4069 pStyRule = 0; // zur Sicherheit
4070 pIo->bStyNormal = false;
4071 pIo->SetNAktColl( 0 );
4072 pIo->bNoAttrImport = bOldNoImp;
4073 // rasch nochmal die Listen-Merk-Felder zuruecksetzen,
4074 // fuer den Fall dass sie beim einlesen des Styles verwendet wurden
4075 pIo->nLFOPosition = USHRT_MAX;
4076 pIo->nListLevel = WW8ListManager::nMaxLevel;
4079 void WW8RStyle::Import1Style( USHORT nNr )
4081 SwWW8StyInf &rSI = pIo->pCollA[nNr];
4083 if( rSI.bImported || !rSI.bValid )
4084 return;
4086 rSI.bImported = true; // jetzt schon Flag setzen
4087 // verhindert endlose Rekursion
4089 // gueltig und nicht NIL und noch nicht Importiert
4091 if( rSI.nBase < cstd && !pIo->pCollA[rSI.nBase].bImported )
4092 Import1Style( rSI.nBase );
4094 pStStrm->Seek( rSI.nFilePos );
4096 short nSkip, cbStd;
4097 String sName;
4099 WW8_STD* pStd = Read1Style( nSkip, &sName, &cbStd );// lies Style
4101 if (pStd)
4102 rSI.SetOrgWWIdent( sName, pStd->sti );
4104 // either no Name or unused Slot or unknown Style
4106 if ( !pStd || (0 == sName.Len()) || ((1 != pStd->sgc) && (2 != pStd->sgc)) )
4108 pStStrm->SeekRel( nSkip );
4109 return;
4112 bool bOldNoImp = PrepareStyle(rSI, static_cast<ww::sti>(pStd->sti), nNr, pStd->istdNext);
4114 // falls etwas falsch interpretiert wird, gehts danach wieder richtig
4115 long nPos = pStStrm->Tell();
4117 //Variable parts of the STD start at even byte offsets, but "inside
4118 //the STD", which I take to meaning even in relation to the starting
4119 //position of the STD, which matches findings in #89439#, generally it
4120 //doesn't matter as the STSHI starts off nearly always on an even
4121 //offset
4123 //Import of the Style Contents
4124 ImportGrupx(nSkip, pStd->sgc == 1, rSI.nFilePos & 1);
4126 PostStyle(rSI, bOldNoImp);
4128 pStStrm->Seek( nPos+nSkip );
4129 delete pStd;
4132 void WW8RStyle::RecursiveReg(USHORT nNr)
4134 SwWW8StyInf &rSI = pIo->pCollA[nNr];
4135 if( rSI.bImported || !rSI.bValid )
4136 return;
4138 rSI.bImported = true;
4140 if( rSI.nBase < cstd && !pIo->pCollA[rSI.nBase].bImported )
4141 RecursiveReg(rSI.nBase);
4143 pIo->RegisterNumFmtOnStyle(nNr);
4148 After all styles are imported then we can recursively apply numbering
4149 styles to them, and change their tab stop settings if they turned out
4150 to have special first line indentation.
4152 void WW8RStyle::PostProcessStyles()
4154 USHORT i;
4156 Clear all imported flags so that we can recursively apply numbering
4157 formats and use it to mark handled ones
4159 for (i=0; i < cstd; ++i)
4160 pIo->pCollA[i].bImported = false;
4163 Register the num formats and tabstop changes on the styles recursively.
4167 In the same loop apply the tabstop changes required because we need to
4168 change their location if theres a special indentation for the first line,
4169 By avoiding making use of each styles margins during reading of their
4170 tabstops we don't get problems with doubly adjusting tabstops that
4171 are inheritied.
4173 for (i=0; i < cstd; ++i)
4175 if (pIo->pCollA[i].bValid)
4177 RecursiveReg(i);
4182 void WW8RStyle::ScanStyles() // untersucht Style-Abhaengigkeiten
4183 { // und ermittelt die Filepos fuer jeden Style
4185 WW8_FC nStyleStart = rFib.fcStshf;
4186 pStStrm->Seek( nStyleStart );
4188 for (USHORT i = 0; i < cstd; ++i)
4190 short nSkip;
4191 SwWW8StyInf &rSI = pIo->pCollA[i];
4193 rSI.nFilePos = pStStrm->Tell(); // merke FilePos
4194 WW8_STD* pStd = Read1Style( nSkip, 0, 0 ); // read STD
4195 rSI.bValid = (0 != pStd);
4196 if (rSI.bValid)
4198 rSI.nBase = pStd->istdBase; // merke Basis
4199 rSI.bColl = ( pStd->sgc == 1 ); // Para-Style
4201 else
4202 rSI = SwWW8StyInf();
4204 delete pStd;
4205 pStStrm->SeekRel( nSkip ); // ueberlese Namen und Sprms
4209 std::vector<BYTE> ChpxToSprms(const Word2CHPX &rChpx)
4211 std::vector<BYTE> aRet;
4213 aRet.push_back(60);
4214 aRet.push_back( static_cast< BYTE >(128 + rChpx.fBold) );
4216 aRet.push_back(61);
4217 aRet.push_back( static_cast< BYTE >(128 + rChpx.fItalic) );
4219 aRet.push_back(62);
4220 aRet.push_back( static_cast< BYTE >(128 + rChpx.fStrike) );
4222 aRet.push_back(63);
4223 aRet.push_back( static_cast< BYTE >(128 + rChpx.fOutline) );
4225 aRet.push_back(65);
4226 aRet.push_back( static_cast< BYTE >(128 + rChpx.fSmallCaps) );
4228 aRet.push_back(66);
4229 aRet.push_back( static_cast< BYTE >(128 + rChpx.fCaps) );
4231 aRet.push_back(67);
4232 aRet.push_back( static_cast< BYTE >(128 + rChpx.fVanish) );
4234 if (rChpx.fsFtc)
4236 aRet.push_back(68);
4237 SVBT16 a;
4238 ShortToSVBT16(rChpx.ftc, a);
4239 aRet.push_back(a[1]);
4240 aRet.push_back(a[0]);
4243 if (rChpx.fsKul)
4245 aRet.push_back(69);
4246 aRet.push_back(rChpx.kul);
4249 if (rChpx.fsLid)
4251 aRet.push_back(72);
4252 SVBT16 a;
4253 ShortToSVBT16(rChpx.lid, a);
4254 aRet.push_back(a[1]);
4255 aRet.push_back(a[0]);
4258 if (rChpx.fsIco)
4260 aRet.push_back(73);
4261 aRet.push_back(rChpx.ico);
4264 if (rChpx.fsHps)
4266 aRet.push_back(74);
4268 SVBT16 a;
4269 ShortToSVBT16(rChpx.hps, a);
4270 aRet.push_back(a[0]);
4271 // aRet.push_back(a[1]);
4274 if (rChpx.fsPos)
4276 aRet.push_back(76);
4277 aRet.push_back(rChpx.hpsPos);
4280 aRet.push_back(80);
4281 aRet.push_back( static_cast< BYTE >(128 + rChpx.fBoldBi) );
4283 aRet.push_back(81);
4284 aRet.push_back( static_cast< BYTE >(128 + rChpx.fItalicBi) );
4286 if (rChpx.fsFtcBi)
4288 aRet.push_back(82);
4289 SVBT16 a;
4290 ShortToSVBT16(rChpx.fsFtcBi, a);
4291 aRet.push_back(a[1]);
4292 aRet.push_back(a[0]);
4295 if (rChpx.fsLidBi)
4297 aRet.push_back(83);
4298 SVBT16 a;
4299 ShortToSVBT16(rChpx.lidBi, a);
4300 aRet.push_back(a[1]);
4301 aRet.push_back(a[0]);
4304 if (rChpx.fsIcoBi)
4306 aRet.push_back(84);
4307 aRet.push_back(rChpx.icoBi);
4310 if (rChpx.fsHpsBi)
4312 aRet.push_back(85);
4313 SVBT16 a;
4314 ShortToSVBT16(rChpx.hpsBi, a);
4315 aRet.push_back(a[1]);
4316 aRet.push_back(a[0]);
4319 return aRet;
4322 Word2CHPX ReadWord2Chpx(SvStream &rSt, sal_Size nOffset, sal_uInt8 nSize)
4324 Word2CHPX aChpx;
4326 if (!nSize)
4327 return aChpx;
4329 rSt.Seek(nOffset);
4331 sal_uInt8 nCount=0;
4333 while (1)
4335 sal_uInt8 nFlags8;
4336 rSt >> nFlags8;
4337 nCount++;
4339 aChpx.fBold = nFlags8 & 0x01;
4340 aChpx.fItalic = (nFlags8 & 0x02) >> 1;
4341 aChpx.fRMarkDel = (nFlags8 & 0x04) >> 2;
4342 aChpx.fOutline = (nFlags8 & 0x08) >> 3;
4343 aChpx.fFldVanish = (nFlags8 & 0x10) >> 4;
4344 aChpx.fSmallCaps = (nFlags8 & 0x20) >> 5;
4345 aChpx.fCaps = (nFlags8 & 0x40) >> 6;
4346 aChpx.fVanish = (nFlags8 & 0x80) >> 7;
4348 if (nCount >= nSize) break;
4349 rSt >> nFlags8;
4350 nCount++;
4352 aChpx.fRMark = nFlags8 & 0x01;
4353 aChpx.fSpec = (nFlags8 & 0x02) >> 1;
4354 aChpx.fStrike = (nFlags8 & 0x04) >> 2;
4355 aChpx.fObj = (nFlags8 & 0x08) >> 3;
4356 aChpx.fBoldBi = (nFlags8 & 0x10) >> 4;
4357 aChpx.fItalicBi = (nFlags8 & 0x20) >> 5;
4358 aChpx.fBiDi = (nFlags8 & 0x40) >> 6;
4359 aChpx.fDiacUSico = (nFlags8 & 0x80) >> 7;
4361 if (nCount >= nSize) break;
4362 rSt >> nFlags8;
4363 nCount++;
4365 aChpx.fsIco = nFlags8 & 0x01;
4366 aChpx.fsFtc = (nFlags8 & 0x02) >> 1;
4367 aChpx.fsHps = (nFlags8 & 0x04) >> 2;
4368 aChpx.fsKul = (nFlags8 & 0x08) >> 3;
4369 aChpx.fsPos = (nFlags8 & 0x10) >> 4;
4370 aChpx.fsSpace = (nFlags8 & 0x20) >> 5;
4371 aChpx.fsLid = (nFlags8 & 0x40) >> 6;
4372 aChpx.fsIcoBi = (nFlags8 & 0x80) >> 7;
4374 if (nCount >= nSize) break;
4375 rSt >> nFlags8;
4376 nCount++;
4378 aChpx.fsFtcBi = nFlags8 & 0x01;
4379 aChpx.fsHpsBi = (nFlags8 & 0x02) >> 1;
4380 aChpx.fsLidBi = (nFlags8 & 0x04) >> 2;
4382 if (nCount >= nSize) break;
4383 rSt >> aChpx.ftc;
4384 nCount+=2;
4386 if (nCount >= nSize) break;
4387 rSt >> aChpx.hps;
4388 nCount+=2;
4390 if (nCount >= nSize) break;
4391 rSt >> nFlags8;
4392 nCount++;
4394 aChpx.qpsSpace = nFlags8 & 0x3F;
4395 aChpx.fSysVanish = (nFlags8 & 0x40) >> 6;
4396 aChpx.fNumRun = (nFlags8 & 0x80) >> 7;
4398 if (nCount >= nSize) break;
4399 rSt >> nFlags8;
4400 nCount++;
4402 aChpx.ico = nFlags8 & 0x1F;
4403 aChpx.kul = (nFlags8 & 0xE0) >> 5;
4405 if (nCount >= nSize) break;
4406 rSt >> aChpx.hpsPos;
4407 nCount++;
4409 if (nCount >= nSize) break;
4410 rSt >> aChpx.icoBi;
4411 nCount++;
4413 if (nCount >= nSize) break;
4414 rSt >> aChpx.lid;
4415 nCount+=2;
4417 if (nCount >= nSize) break;
4418 rSt >> aChpx.ftcBi;
4419 nCount+=2;
4421 if (nCount >= nSize) break;
4422 rSt >> aChpx.hpsBi;
4423 nCount+=2;
4425 if (nCount >= nSize) break;
4426 rSt >> aChpx.lidBi;
4427 nCount+=2;
4429 if (nCount >= nSize) break;
4430 rSt >> aChpx.fcPic;
4431 nCount+=4;
4433 break;
4436 rSt.SeekRel(nSize-nCount);
4437 return aChpx;
4440 namespace
4442 struct pxoffset { sal_Size mnOffset; sal_uInt8 mnSize; };
4445 void WW8RStyle::ImportOldFormatStyles()
4447 for (sal_uInt16 i=0; i < cstd; ++i)
4449 pIo->pCollA[i].bColl = true;
4450 //every chain must end eventually at the null style (style code 222)
4451 pIo->pCollA[i].nBase = 222;
4454 rtl_TextEncoding eStructChrSet = WW8Fib::GetFIBCharset(
4455 pIo->pWwFib->chseTables);
4457 sal_uInt16 cstcStd;
4458 rSt >> cstcStd;
4460 sal_uInt16 cbName;
4461 rSt >> cbName;
4462 sal_uInt16 nByteCount = 2;
4463 USHORT stcp=0;
4464 while (nByteCount < cbName)
4466 sal_uInt8 nCount;
4467 rSt >> nCount;
4468 nByteCount++;
4470 sal_uInt8 stc = static_cast< sal_uInt8 >((stcp - cstcStd) & 255);
4471 SwWW8StyInf &rSI = pIo->pCollA[stc];
4472 if (nCount != 0xFF) // undefined style
4474 String sName;
4475 if (nCount == 0) // inbuilt style
4477 ww::sti eSti = ww::GetCanonicalStiFromStc(stc);
4478 if (const sal_Char *pStr = GetEnglishNameFromSti(eSti))
4479 sName = String(pStr, RTL_TEXTENCODING_ASCII_US);
4480 else
4481 sName = String(CREATE_CONST_ASC("Unknown"));
4483 else // user style
4485 ByteString aTmp;
4486 nByteCount = static_cast< sal_uInt16 >(nByteCount + SafeReadString(aTmp, nCount, rSt));
4487 sName = String(aTmp, eStructChrSet);
4489 rSI.SetOrgWWIdent(sName, stc);
4490 rSI.bImported = true;
4492 else
4494 ww::sti eSti = ww::GetCanonicalStiFromStc(stc);
4495 if (const sal_Char *pStr = GetEnglishNameFromSti(eSti))
4497 String sName = String(pStr, RTL_TEXTENCODING_ASCII_US);
4498 rSI.SetOrgWWIdent(sName, stc);
4501 stcp++;
4504 USHORT nStyles=stcp;
4506 std::vector<pxoffset> aCHPXOffsets(stcp);
4507 sal_uInt16 cbChpx;
4508 rSt >> cbChpx;
4509 nByteCount = 2;
4510 stcp=0;
4511 std::vector< std::vector<BYTE> > aConvertedChpx;
4512 while (nByteCount < cbChpx)
4514 sal_uInt8 cb;
4515 rSt >> cb;
4516 nByteCount++;
4518 aCHPXOffsets[stcp].mnSize = 0;
4520 if (cb != 0xFF)
4522 sal_uInt8 nRemainder = cb;
4524 aCHPXOffsets[stcp].mnOffset = rSt.Tell();
4525 aCHPXOffsets[stcp].mnSize = nRemainder;
4527 Word2CHPX aChpx = ReadWord2Chpx(rSt, aCHPXOffsets[stcp].mnOffset,
4528 aCHPXOffsets[stcp].mnSize);
4529 aConvertedChpx.push_back( ChpxToSprms(aChpx) );
4531 nByteCount += nRemainder;
4533 else
4534 aConvertedChpx.push_back( std::vector<BYTE>() );
4536 stcp++;
4537 if (stcp == nStyles)
4539 rSt.SeekRel(cbChpx-nByteCount);
4540 nByteCount += cbChpx-nByteCount;
4544 std::vector<pxoffset> aPAPXOffsets(stcp);
4545 sal_uInt16 cbPapx;
4546 rSt >> cbPapx;
4547 nByteCount = 2;
4548 stcp=0;
4549 while (nByteCount < cbPapx)
4551 sal_uInt8 cb;
4552 rSt >> cb;
4553 nByteCount++;
4555 aPAPXOffsets[stcp].mnSize = 0;
4557 if (cb != 0xFF)
4559 sal_uInt8 stc2;
4560 rSt >> stc2;
4561 rSt.SeekRel(6);
4562 nByteCount+=7;
4563 sal_uInt8 nRemainder = cb-7;
4565 aPAPXOffsets[stcp].mnOffset = rSt.Tell();
4566 aPAPXOffsets[stcp].mnSize = nRemainder;
4568 rSt.SeekRel(nRemainder);
4569 nByteCount += nRemainder;
4572 stcp++;
4574 if (stcp == nStyles)
4576 rSt.SeekRel(cbPapx-nByteCount);
4577 nByteCount += cbPapx-nByteCount;
4581 sal_uInt16 iMac;
4582 rSt >> iMac;
4584 if (iMac > nStyles) iMac = nStyles;
4586 for (stcp = 0; stcp < iMac; ++stcp)
4588 sal_uInt8 stcNext, stcBase;
4589 rSt >> stcNext;
4590 rSt >> stcBase;
4592 sal_uInt8 stc = static_cast< sal_uInt8 >((stcp - cstcStd) & 255);
4595 #i64557# style based on itself
4596 every chain must end eventually at the null style (style code 222)
4598 if (stc == stcBase)
4599 stcBase = 222;
4601 SwWW8StyInf &rSI = pIo->pCollA[stc];
4602 rSI.nBase = stcBase;
4604 ww::sti eSti = ww::GetCanonicalStiFromStc(stc);
4606 if (eSti == ww::stiNil)
4607 continue;
4609 rSI.bValid = true;
4611 if (ww::StandardStiIsCharStyle(eSti) && !aPAPXOffsets[stcp].mnSize)
4612 pIo->pCollA[stc].bColl = false;
4614 bool bOldNoImp = PrepareStyle(rSI, eSti, stc, stcNext);
4616 ImportSprms(aPAPXOffsets[stcp].mnOffset, aPAPXOffsets[stcp].mnSize,
4617 true);
4619 if (aConvertedChpx[stcp].size() > 0)
4620 ImportSprms(&(aConvertedChpx[stcp][0]),
4621 static_cast< short >(aConvertedChpx[stcp].size()),
4622 false);
4624 PostStyle(rSI, bOldNoImp);
4628 void WW8RStyle::ImportNewFormatStyles()
4630 ScanStyles(); // Scanne Based On
4632 for (USHORT i = 0; i < cstd; ++i) // import Styles
4633 if (pIo->pCollA[i].bValid)
4634 Import1Style( i );
4637 void WW8RStyle::ImportStyles()
4639 if (ww::eWW2 == pIo->pWwFib->GetFIBVersion())
4640 ImportOldFormatStyles();
4641 else
4642 ImportNewFormatStyles();
4645 void WW8RStyle::Import()
4647 pIo->pDfltTxtFmtColl = pIo->rDoc.GetDfltTxtFmtColl();
4648 pIo->pStandardFmtColl =
4649 pIo->rDoc.GetTxtCollFromPool(RES_POOLCOLL_STANDARD, false);
4651 if( pIo->nIniFlags & WW8FL_NO_STYLES )
4652 return;
4654 ImportStyles();
4656 for (USHORT i = 0; i < cstd; ++i)
4658 // Follow chain
4659 SwWW8StyInf* pi = &pIo->pCollA[i];
4660 USHORT j = pi->nFollow;
4661 if( j < cstd )
4663 SwWW8StyInf* pj = &pIo->pCollA[j];
4664 if ( j != i // sinnvoller Index ?
4665 && pi->pFmt // Format ok ?
4666 && pj->pFmt // Derived-Format ok ?
4667 && pi->bColl // geht nur bei Absatz-Vorlagen (WW)
4668 && pj->bColl ){ // beides gleicher Typ ?
4669 ( (SwTxtFmtColl*)pi->pFmt )->SetNextTxtFmtColl(
4670 *(SwTxtFmtColl*)pj->pFmt ); // ok, eintragen
4674 // Die Sonderbehandlung zur Setzen der
4675 // Default-Zeichenvorlage "Absatz-Standardschriftart" ( Style-ID 65 ) fehlt
4676 // Sie ist aber defaultmaessig leer ( WW6 dt und US ) und von der
4677 // WW-UI nicht zu veraendern, so dass das nicht stoert.
4678 // Der Mechanismus waere folgender:
4679 // if( bNew ) rDoc.SetDefault( pDefCharFmt->GetAttrSet() );
4681 // fuer z.B. Tabellen wird ein immer gueltiger Std-Style gebraucht
4683 if( pIo->pCollA[0].pFmt && pIo->pCollA[0].bColl && pIo->pCollA[0].bValid )
4684 pIo->pDfltTxtFmtColl = (SwTxtFmtColl*)pIo->pCollA[0].pFmt;
4685 else
4686 pIo->pDfltTxtFmtColl = pIo->rDoc.GetDfltTxtFmtColl();
4689 // set Hyphenation flag on BASIC para-style
4690 if (pIo->mbNewDoc && pIo->pStandardFmtColl)
4692 if (pIo->pWDop->fAutoHyphen
4693 && SFX_ITEM_SET != pIo->pStandardFmtColl->GetItemState(
4694 RES_PARATR_HYPHENZONE, false) )
4696 SvxHyphenZoneItem aAttr(true, RES_PARATR_HYPHENZONE);
4697 aAttr.GetMinLead() = 2;
4698 aAttr.GetMinTrail() = 2;
4699 aAttr.GetMaxHyphens() = 0;
4701 pIo->pStandardFmtColl->SetFmtAttr( aAttr );
4705 Word defaults to ltr not from environment like writer. Regardless of
4706 the page/sections rtl setting the standard style lack of rtl still
4707 means ltr
4709 if (SFX_ITEM_SET != pIo->pStandardFmtColl->GetItemState(RES_FRAMEDIR,
4710 false))
4712 pIo->pStandardFmtColl->SetFmtAttr(
4713 SvxFrameDirectionItem(FRMDIR_HORI_LEFT_TOP, RES_FRAMEDIR));
4717 // wir sind jetzt nicht mehr beim Style einlesen:
4718 pIo->pAktColl = 0;
4721 CharSet SwWW8StyInf::GetCharSet() const
4723 if ((pFmt) && (pFmt->GetFrmDir().GetValue() == FRMDIR_HORI_RIGHT_TOP))
4724 return eRTLFontSrcCharSet;
4725 return eLTRFontSrcCharSet;
4728 /* vi:set tabstop=4 shiftwidth=4 expandtab: */