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