1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <boost/scoped_ptr.hpp>
21 #include <comphelper/string.hxx>
22 #include <tools/solar.h>
23 #include <vcl/vclenum.hxx>
24 #include <vcl/font.hxx>
25 #include <hintids.hxx>
26 #include <editeng/colritem.hxx>
27 #include <editeng/orphitem.hxx>
28 #include <editeng/widwitem.hxx>
29 #include <editeng/brushitem.hxx>
30 #include <editeng/boxitem.hxx>
31 #include <editeng/lrspitem.hxx>
32 #include <editeng/fhgtitem.hxx>
33 #include <editeng/hyphenzoneitem.hxx>
34 #include <editeng/frmdiritem.hxx>
35 #include <editeng/langitem.hxx>
36 #include <editeng/charrotateitem.hxx>
37 #include <editeng/pgrditem.hxx>
38 #include <msfilter.hxx>
39 #include <pam.hxx> // fuer SwPam
42 #include <ndtxt.hxx> // class SwTxtNode
43 #include <paratr.hxx> // SwNumRuleItem
44 #include <poolfmt.hxx> // RES_POOLCOLL_STANDARD
45 #include <swtable.hxx> // class SwTableLines, ...
46 #include <tblsel.hxx> // class _SwSelBox
48 #include <fmtpdsc.hxx>
53 #include <charfmt.hxx>
54 #include <SwStyleNameMapper.hxx>
55 #include <fltshell.hxx> // for the attribute stack
56 #include <fmtanchr.hxx>
57 #include <fmtrowsplt.hxx>
58 #include <fmtfollowtextflow.hxx> // #i33818#
59 #include <numrule.hxx>
60 #include "../inc/wwstyles.hxx"
61 #include "writerhelper.hxx"
62 #include "ww8struc.hxx" // struct TC
64 #include "ww8par2.hxx"
70 using namespace ::com::sun::star
;
74 : public std::vector
<SwTableBox
*>
77 WW8SelBoxInfo(const WW8SelBoxInfo
&);
78 WW8SelBoxInfo
& operator=(const WW8SelBoxInfo
&);
84 WW8SelBoxInfo(short nXCenter
, short nWidth
)
85 : nGroupXStart( nXCenter
), nGroupWidth( nWidth
), bGroupLocked(false)
89 typedef boost::ptr_vector
<WW8SelBoxInfo
> WW8MergeGroups
;
91 WW8TabBandDesc::WW8TabBandDesc()
93 memset(this, 0, sizeof(*this));
94 for (size_t i
= 0; i
< sizeof(maDirections
)/sizeof(sal_uInt16
); ++i
)
98 WW8TabBandDesc::~WW8TabBandDesc()
107 std::vector
<String
> aNumRuleNames
;
108 sw::util::RedlineStack
*mpOldRedlineStack
;
110 SwWW8ImplReader
* pIo
;
112 WW8TabBandDesc
* pFirstBand
;
113 WW8TabBandDesc
* pActBand
;
117 SwTableNode
* pTblNd
; // table node
118 const SwTableLines
* pTabLines
; // row array of node
119 SwTableLine
* pTabLine
; // current row
120 SwTableBoxes
* pTabBoxes
; // boxes array in current row
121 SwTableBox
* pTabBox
; // current cell
123 WW8MergeGroups aMergeGroups
; // list of all cells to be merged
125 WW8_TCell
* pAktWWCell
;
128 short nDefaultSwCols
;
131 short nConvertedLeft
;
134 short nPreferredWidth
;
141 // 2. common admin info
143 short nAktBandRow
; // SW: row of current band
144 // 3. admin info for writer
147 sal_uInt16 nRowsToRepeat
;
151 sal_uInt16
GetLogicalWWCol() const;
152 void SetTabBorders( SwTableBox
* pBox
, short nIdx
);
153 void SetTabShades( SwTableBox
* pBox
, short nWwIdx
);
154 void SetTabVertAlign( SwTableBox
* pBox
, short nWwIdx
);
155 void SetTabDirection( SwTableBox
* pBox
, short nWwIdx
);
157 bool SetPamInCell(short nWwCol
, bool bPam
);
158 void InsertCells( short nIns
);
159 void AdjustNewBand();
161 WW8SelBoxInfo
* FindMergeGroup(short nX1
, short nWidth
, bool bExact
);
163 // single box - maybe used in a merge group
164 // (the merge groups are processed later at once)
165 SwTableBox
* UpdateTableMergeGroup(WW8_TCell
& rCell
,
166 WW8SelBoxInfo
* pActGroup
, SwTableBox
* pActBox
, sal_uInt16 nCol
);
167 void StartMiserableHackForUnsupportedDirection(short nWwCol
);
168 void EndMiserableHackForUnsupportedDirection(short nWwCol
);
170 WW8TabDesc(const WW8TabDesc
&);
171 WW8TabDesc
&operator=(const WW8TabDesc
&);
173 const SwTable
* pTable
; // table
174 SwPosition
* pParentPos
;
175 SwFlyFrmFmt
* pFlyFmt
;
177 bool IsValidCell(short nCol
) const;
178 bool InFirstParaInCell() const;
180 WW8TabDesc( SwWW8ImplReader
* pIoClass
, WW8_CP nStartCp
);
181 bool Ok() const { return bOk
; }
182 void CreateSwTable();
184 void SetSizePosition(SwFrmFmt
* pFrmFmt
);
186 void MoveOutsideTable();
188 void FinishSwTable();
190 short GetMinLeft() const { return nConvertedLeft
; }
192 SwPosition
*GetPos() { return pTmpPos
; }
194 const WW8_TCell
* GetAktWWCell() const { return pAktWWCell
; }
195 short GetAktCol() const { return nAktCol
; }
196 // find name of numrule valid for current WW-COL
197 const String
& GetNumRuleName() const;
198 void SetNumRuleName( const String
& rName
);
200 sw::util::RedlineStack
* getOldRedlineStack(){ return mpOldRedlineStack
; }
203 void sw::util::RedlineStack::close( const SwPosition
& rPos
,
204 RedlineType_t eType
, WW8TabDesc
* pTabDesc
)
206 // If the redline type is not found in the redline stack, we have to check if there has been
207 // a tabledesc and to check its saved redline stack, too. (#136939, #i68139)
208 if( !close( rPos
, eType
) )
210 if( pTabDesc
&& pTabDesc
->getOldRedlineStack() )
213 pTabDesc
->getOldRedlineStack()->close(rPos
, eType
);
214 OSL_ENSURE( bResult
, "close without open!");
215 (void) bResult
; // unused in non-debug
221 void wwSectionManager::SetCurrentSectionHasFootnote()
223 OSL_ENSURE(!maSegments
.empty(),
224 "should not be possible, must be at least one segment");
225 if (!maSegments
.empty())
226 maSegments
.back().mbHasFootnote
= true;
229 bool wwSectionManager::CurrentSectionIsVertical() const
231 OSL_ENSURE(!maSegments
.empty(),
232 "should not be possible, must be at least one segment");
233 if (!maSegments
.empty())
234 return maSegments
.back().IsVertical();
238 bool wwSectionManager::CurrentSectionIsProtected() const
240 OSL_ENSURE(!maSegments
.empty(),
241 "should not be possible, must be at least one segment");
242 if (!maSegments
.empty())
243 return SectionIsProtected(maSegments
.back());
247 sal_uInt32
wwSectionManager::GetPageLeft() const
249 return !maSegments
.empty() ? maSegments
.back().nPgLeft
: 0;
252 sal_uInt32
wwSectionManager::GetPageRight() const
254 return !maSegments
.empty() ? maSegments
.back().nPgRight
: 0;
257 sal_uInt32
wwSectionManager::GetPageWidth() const
259 return !maSegments
.empty() ? maSegments
.back().GetPageWidth() : 0;
262 sal_uInt32
wwSectionManager::GetTextAreaWidth() const
264 return !maSegments
.empty() ? maSegments
.back().GetTextAreaWidth() : 0;
267 sal_uInt32
wwSectionManager::GetWWPageTopMargin() const
269 return !maSegments
.empty() ? maSegments
.back().maSep
.dyaTop
: 0;
272 sal_uInt16
SwWW8ImplReader::End_Ftn()
275 Ignoring Footnote outside of the normal Text. People will put footnotes
276 into field results and field commands.
279 pPaM
->GetPoint()->nNode
< rDoc
.GetNodes().GetEndOfExtras().GetIndex())
284 OSL_ENSURE(!maFtnStack
.empty(), "footnote end without start");
285 if (maFtnStack
.empty())
288 bool bFtEdOk
= false;
289 const FtnDescriptor
&rDesc
= maFtnStack
.back();
291 //Get the footnote character and remove it from the txtnode. We'll
292 //replace it with the footnote
293 SwTxtNode
* pTxt
= pPaM
->GetNode()->GetTxtNode();
294 xub_StrLen nPos
= pPaM
->GetPoint()->nContent
.GetIndex();
298 //There should have been a footnote char, we will replace this.
301 sChar
.Append(pTxt
->GetTxt()[--nPos
]);
303 pPaM
->GetMark()->nContent
--;
304 rDoc
.DeleteRange( *pPaM
);
306 SwFmtFtn
aFtn(rDesc
.meType
== MAN_EDN
);
307 pFN
= pTxt
->InsertItem(aFtn
, nPos
, nPos
);
309 OSL_ENSURE(pFN
, "Probleme beim Anlegen des Fussnoten-Textes");
313 SwPosition
aTmpPos( *pPaM
->GetPoint() ); // remember old cursor position
314 WW8PLCFxSaveAll aSave
;
315 pPlcxMan
->SaveAllPLCFx( aSave
);
316 WW8PLCFMan
* pOldPlcxMan
= pPlcxMan
;
318 const SwNodeIndex
* pSttIdx
= ((SwTxtFtn
*)pFN
)->GetStartNode();
319 OSL_ENSURE(pSttIdx
, "Probleme beim Anlegen des Fussnoten-Textes");
321 ((SwTxtFtn
*)pFN
)->SetSeqNo( rDoc
.GetFtnIdxs().size() );
326 // read content of Ft-/End-Note
327 Read_HdFtFtnText( pSttIdx
, rDesc
.mnStartCp
, rDesc
.mnLen
, rDesc
.meType
);
331 OSL_ENSURE(sChar
.Len()==1 && ((rDesc
.mbAutoNum
== (sChar
.GetChar(0) == 2))),
332 "footnote autonumbering must be 0x02, and everthing else must not be");
334 // If no automatic numbering use the following char from the main text
335 // as the footnote number
336 if (!rDesc
.mbAutoNum
)
337 ((SwTxtFtn
*)pFN
)->SetNumber(0, &sChar
);
340 Delete the footnote char from the footnote if its at the beginning
341 as usual. Might not be if the user has already deleted it, e.g.
344 SwNodeIndex
& rNIdx
= pPaM
->GetPoint()->nNode
;
345 rNIdx
= pSttIdx
->GetIndex() + 1;
346 SwTxtNode
* pTNd
= rNIdx
.GetNode().GetTxtNode();
347 if (pTNd
&& !pTNd
->GetTxt().isEmpty() && sChar
.Len())
349 if (pTNd
->GetTxt()[0] == sChar
.GetChar(0))
351 pPaM
->GetPoint()->nContent
.Assign( pTNd
, 0 );
353 // Strip out tabs we may have inserted on export #i24762#
354 if (pTNd
->GetTxt()[1] == 0x09)
355 pPaM
->GetMark()->nContent
++;
356 pPaM
->GetMark()->nContent
++;
357 pReffingStck
->Delete(*pPaM
);
358 rDoc
.DeleteRange( *pPaM
);
363 *pPaM
->GetPoint() = aTmpPos
; // restore Cursor
365 pPlcxMan
= pOldPlcxMan
; // Restore attributes
366 pPlcxMan
->RestoreAllPLCFx( aSave
);
370 maSectionManager
.SetCurrentSectionHasFootnote();
372 maFtnStack
.pop_back();
376 long SwWW8ImplReader::Read_Ftn(WW8PLCFManResult
* pRes
)
379 Ignoring Footnote outside of the normal Text. People will put footnotes
380 into field results and field commands.
383 pPaM
->GetPoint()->nNode
< rDoc
.GetNodes().GetEndOfExtras().GetIndex())
389 aDesc
.mbAutoNum
= true;
390 if (eEDN
== pRes
->nSprmId
)
392 aDesc
.meType
= MAN_EDN
;
393 if (pPlcxMan
->GetEdn())
394 aDesc
.mbAutoNum
= 0 != *(short*)pPlcxMan
->GetEdn()->GetData();
398 aDesc
.meType
= MAN_FTN
;
399 if (pPlcxMan
->GetFtn())
400 aDesc
.mbAutoNum
= 0 != *(short*)pPlcxMan
->GetFtn()->GetData();
403 aDesc
.mnStartCp
= pRes
->nCp2OrIdx
;
404 aDesc
.mnLen
= pRes
->nMemLen
;
406 maFtnStack
.push_back(aDesc
);
411 bool SwWW8ImplReader::SearchRowEnd(WW8PLCFx_Cp_FKP
* pPap
, WW8_CP
&rStartCp
,
416 aRes
.nEndPos
= rStartCp
;
418 while (pPap
->HasFkp() && rStartCp
!= WW8_CP_MAX
)
420 if (pPap
->Where() != WW8_CP_MAX
)
422 const sal_uInt8
* pB
= pPap
->HasSprm(TabRowSprm(nLevel
));
425 const sal_uInt8
*pLevel
= 0;
426 if (0 != (pLevel
= pPap
->HasSprm(0x6649)))
428 if (nLevel
+ 1 == *pLevel
)
433 OSL_ENSURE(!nLevel
|| pLevel
, "sublevel without level sprm");
434 return true; // RowEnd found
439 aRes
.nStartPos
= aRes
.nEndPos
;
441 //Seek to our next block of properties
442 if (!(pPap
->SeekPos(aRes
.nStartPos
)))
444 aRes
.nEndPos
= WW8_CP_MAX
;
445 pPap
->SetDirty(true);
447 pPap
->GetSprms(&aRes
);
448 pPap
->SetDirty(false);
449 //Update our aRes to get the new starting point of the next properties
450 rStartCp
= aRes
.nEndPos
;
456 ApoTestResults
SwWW8ImplReader::TestApo(int nCellLevel
, bool bTableRowEnd
,
457 const WW8_TablePos
*pTabPos
)
459 const WW8_TablePos
*pTopLevelTable
= nCellLevel
<= 1 ? pTabPos
: 0;
461 // Frame in Style Definition (word appears to ignore them if inside an
463 if (!bTxbxFlySection
&& nAktColl
< vColl
.size())
464 aRet
.mpStyleApo
= StyleExists(nAktColl
) ? vColl
[nAktColl
].pWWFly
: 0;
468 If I have a table and apply a style to one of its frames that should cause
469 a paragraph that its applied to it to only exist as a separate floating
470 frame, then the behavour depends on which cell that it has been applied
471 to. If its the first cell of a row then the whole table row jumps into the
472 new frame, if its not then then the paragraph attributes are applied
473 "except" for the floating frame stuff. i.e. its ignored. So if theres a
474 table, and we're not in the first cell then we ignore the fact that the
475 paragraph style wants to be in a different frame.
477 This sort of mindbending inconsistency is surely why frames are deprecated
478 in word 97 onwards and hidden away from the user
482 If we are already a table in a frame then we must grab the para properties
483 to see if we are still in that frame.
486 aRet
.m_bHasSprm37
= pPlcxMan
->HasParaSprm( bVer67
? 37 : 0x2423 );
487 const sal_uInt8
*pSrpm29
= pPlcxMan
->HasParaSprm( bVer67
? 29 : 0x261B );
488 aRet
.m_bHasSprm29
= pSrpm29
!= NULL
;
489 aRet
.m_nSprm29
= pSrpm29
? *pSrpm29
: 0;
491 // Is there some frame data here
492 bool bNowApo
= aRet
.HasFrame() || pTopLevelTable
;
495 if (WW8FlyPara
*pTest
= ConstructApo(aRet
, pTabPos
))
501 bool bTestAllowed
= !bTxbxFlySection
&& !bTableRowEnd
;
504 //Test is allowed if there is no table.
505 //Otherwise only allowed if we are in the
506 //first paragraph of the first cell of a row.
507 //(And only if the row we are inside is at the
508 //same level as the previous row, think tables
510 if (nCellLevel
== nInTable
)
519 OSL_ENSURE(pTableDesc
, "What!");
520 bTestAllowed
= false;
525 // If current cell isn't valid, the test is allowed.
526 // The cell isn't valid, if e.g. there is a new row
527 // <pTableDesc->nAktRow> >= <pTableDesc->pTabLines->Count()>
529 pTableDesc
->GetAktCol() == 0 &&
530 ( !pTableDesc
->IsValidCell( pTableDesc
->GetAktCol() ) ||
531 pTableDesc
->InFirstParaInCell() );
540 aRet
.mbStartApo
= bNowApo
&& !InAnyApo(); // APO-start
541 aRet
.mbStopApo
= InEqualOrHigherApo(nCellLevel
) && !bNowApo
; // APO-end
543 //If it happens that we are in a table, then if its not the first cell
544 //then any attributes that might otherwise cause the contents to jump
545 //into another frame don't matter, a table row sticks together as one
546 //unit no matter what else happens. So if we are not in a table at
547 //all, or if we are in the first cell then test that the last frame
548 //data is the same as the current one
549 if (bNowApo
&& InEqualApo(nCellLevel
))
551 // two bordering eachother
552 if (!TestSameApo(aRet
, pTabPos
))
553 aRet
.mbStopApo
= aRet
.mbStartApo
= true;
558 //---------------------------------------------------------------------
559 // helper methods for outline, numbering and bullets
560 //---------------------------------------------------------------------
562 static void SetBaseAnlv(SwNumFmt
&rNum
, WW8_ANLV
&rAV
, sal_uInt8 nSwLevel
)
564 static SvxExtNumType eNumA
[8] = { SVX_NUM_ARABIC
, SVX_NUM_ROMAN_UPPER
, SVX_NUM_ROMAN_LOWER
,
565 SVX_NUM_CHARS_UPPER_LETTER_N
, SVX_NUM_CHARS_LOWER_LETTER_N
, SVX_NUM_ARABIC
,
566 SVX_NUM_ARABIC
, SVX_NUM_ARABIC
};
568 static SvxAdjust eAdjA
[4] = { SVX_ADJUST_LEFT
,
569 SVX_ADJUST_RIGHT
, SVX_ADJUST_LEFT
, SVX_ADJUST_LEFT
};
570 // in fact the following 2, but writer UI does not provide
571 // SVX_ADJUST_CENTER, SVX_ADJUST_BLOCKLINE };
573 rNum
.SetNumberingType( static_cast< sal_Int16
>(( SVBT8ToByte( rAV
.nfc
) < 8 ) ?
574 eNumA
[SVBT8ToByte( rAV
.nfc
) ] : SVX_NUM_NUMBER_NONE
) );
575 if ((SVBT8ToByte(rAV
.aBits1
) & 0x4) >> 2)
576 rNum
.SetIncludeUpperLevels(nSwLevel
+ 1);
577 rNum
.SetStart( SVBT16ToShort( rAV
.iStartAt
) );
578 rNum
.SetNumAdjust( eAdjA
[SVBT8ToByte( rAV
.aBits1
) & 0x3] );
580 rNum
.SetCharTextDistance( SVBT16ToShort( rAV
.dxaSpace
) );
581 sal_Int16 nIndent
= std::abs((sal_Int16
)SVBT16ToShort( rAV
.dxaIndent
));
582 if( SVBT8ToByte( rAV
.aBits1
) & 0x08 ) //fHang
584 rNum
.SetFirstLineOffset( -nIndent
);
585 rNum
.SetLSpace( nIndent
);
586 rNum
.SetAbsLSpace( nIndent
);
589 rNum
.SetCharTextDistance( nIndent
); // width of number is missing
591 if( SVBT8ToByte( rAV
.nfc
) == 5 || SVBT8ToByte( rAV
.nfc
) == 7 )
593 String
sP( rNum
.GetSuffix() );
595 rNum
.SetSuffix( sP
); // ordinal number
599 void SwWW8ImplReader::SetAnlvStrings(SwNumFmt
&rNum
, WW8_ANLV
&rAV
,
600 const sal_uInt8
* pTxt
, bool bOutline
)
602 bool bInsert
= false; // Default
603 CharSet eCharSet
= eStructCharSet
;
605 const WW8_FFN
* pF
= pFonts
->GetFont(SVBT16ToShort(rAV
.ftc
)); // FontInfo
606 bool bListSymbol
= pF
&& ( pF
->chs
== 2 ); // Symbol/WingDings/...
611 sTxt
= String( (sal_Char
*)pTxt
, SVBT8ToByte( rAV
.cbTextBefore
)
612 + SVBT8ToByte( rAV
.cbTextAfter
), eCharSet
);
616 for(xub_StrLen i
= SVBT8ToByte(rAV
.cbTextBefore
);
617 i
< SVBT8ToByte(rAV
.cbTextAfter
); ++i
, pTxt
+= 2)
619 sTxt
.Append(SVBT16ToShort(*(SVBT16
*)pTxt
));
625 if( !rNum
.GetIncludeUpperLevels() // there are <= 1 number to show
626 || rNum
.GetNumberingType() == SVX_NUM_NUMBER_NONE
) // or this level has none
628 // if self defined digits
629 bInsert
= true; // then apply character
631 // replace by simple Bullet ?
634 // use cBulletChar for correct mapping on MAC
636 comphelper::string::padToLength(aBuf
, SVBT8ToByte(rAV
.cbTextBefore
)
637 + SVBT8ToByte(rAV
.cbTextAfter
), cBulletChar
);
638 sTxt
= aBuf
.makeStringAndClear();
643 { // numbering / bullets
651 if( GetFontParams( SVBT16ToShort( rAV
.ftc
), eFamily
, aName
,
652 ePitch
, eCharSet
) ){
655 aFont
.SetName( aName
);
656 aFont
.SetFamily( eFamily
);
658 aFont
.SetCharSet( eCharSet
);
659 rNum
.SetNumberingType(SVX_NUM_CHAR_SPECIAL
);
661 rNum
.SetBulletFont( &aFont
);
663 // take only the very first character
664 if( rAV
.cbTextBefore
|| rAV
.cbTextAfter
)
665 rNum
.SetBulletChar( sTxt
.GetChar( 0 ) );
667 rNum
.SetBulletChar( 0x2190 );
673 if( rAV
.cbTextBefore
)
675 String
sP( sTxt
.Copy( 0, SVBT8ToByte( rAV
.cbTextBefore
) ) );
676 rNum
.SetPrefix( sP
);
678 if( SVBT8ToByte( rAV
.cbTextAfter
) )
680 String
sP( rNum
.GetSuffix() );
681 sP
.Insert( sTxt
.Copy( SVBT8ToByte( rAV
.cbTextBefore
),
682 SVBT8ToByte( rAV
.cbTextAfter
) ) );
683 rNum
.SetSuffix( sP
);
685 // The characters before and after multipe digits do not apply because
686 // those are handled different by the writer and the result is in most
687 // cases worse than without.
691 // SetAnld gets a WW-ANLD-Descriptor and a Level and modifies the NumRules
692 // which are provided by pNumR. This is used for everything beside
693 // outline inside the text.
694 void SwWW8ImplReader::SetAnld(SwNumRule
* pNumR
, WW8_ANLD
* pAD
, sal_uInt8 nSwLevel
,
699 { // there is a Anld-Sprm
700 bAktAND_fNumberAcross
= 0 != SVBT8ToByte( pAD
->fNumberAcross
);
701 WW8_ANLV
&rAV
= pAD
->eAnlv
;
702 SetBaseAnlv(aNF
, rAV
, nSwLevel
); // set the base format
703 SetAnlvStrings(aNF
, rAV
, pAD
->rgchAnld
, bOutLine
); // set the rest
705 pNumR
->Set(nSwLevel
, aNF
);
708 //-------------------------------------------------------
709 // chapter numbering and bullets
710 //-------------------------------------------------------
711 // Chapter numbering happens in the style definition.
712 // Sprm 13 provides the level, Sprm 12 the content.
714 SwNumRule
* SwWW8ImplReader::GetStyRule()
716 if( pStyles
->pStyRule
) // Bullet-Style already present
717 return pStyles
->pStyRule
;
719 const String
aBaseName(OUString("WW8StyleNum"));
720 const String
aName( rDoc
.GetUniqueNumRuleName( &aBaseName
, false) );
723 sal_uInt16 nRul
= rDoc
.MakeNumRule( aName
, 0, false,
724 SvxNumberFormat::LABEL_ALIGNMENT
);
725 pStyles
->pStyRule
= rDoc
.GetNumRuleTbl()[nRul
];
726 // Auto == false-> Nummerierungsvorlage
727 pStyles
->pStyRule
->SetAutoRule(false);
729 return pStyles
->pStyRule
;
733 void SwWW8ImplReader::Read_ANLevelNo( sal_uInt16
, const sal_uInt8
* pData
, short nLen
)
735 nSwNumLevel
= 0xff; // Default: invalid
743 // only for SwTxtFmtColl, not CharFmt
744 // WW: 0 = no Numbering
745 SwWW8StyInf
* pColl
= GetStyle(nAktColl
);
746 if (pColl
!= NULL
&& pColl
->bColl
&& *pData
)
748 // Range WW:1..9 -> SW:0..8 no bullets / numbering
750 if (*pData
<= MAXLEVEL
&& *pData
<= 9)
752 nSwNumLevel
= *pData
- 1;
754 ((SwTxtFmtColl
*)pAktColl
)->AssignToListLevelOfOutlineStyle( nSwNumLevel
); //<-end,zhaojianwei
755 // For WW-NoNumbering also NO_NUMBERING could be used.
756 // ( For normal numberierung NO_NUM has to be used:
757 // NO_NUM : pauses numbering,
758 // NO_NUMBERING : no numbering at all )
761 else if( *pData
== 10 || *pData
== 11 )
763 // remember type, the rest happens at Sprm 12
764 pStyles
->nWwNumLevel
= *pData
;
772 StartAnl(pData
); // begin of outline / bullets
777 void SwWW8ImplReader::Read_ANLevelDesc( sal_uInt16
, const sal_uInt8
* pData
, short nLen
) // Sprm 12
779 SwWW8StyInf
* pStyInf
= GetStyle(nAktColl
);
780 if( !pAktColl
|| nLen
<= 0 // only for Styledef
781 || (pStyInf
&& !pStyInf
->bColl
) // ignore CharFmt ->
782 || ( nIniFlags
& WW8FL_NO_OUTLINE
) )
789 if( nSwNumLevel
<= MAXLEVEL
// Value range mapping WW:1..9 -> SW:0..8
790 && nSwNumLevel
<= 9 ){ // No Bullets or Numbering
792 // If NumRuleItems were set, either directly or through inheritance, disable them now
793 pAktColl
->SetFmtAttr( SwNumRuleItem() );
795 String
aName(OUString("Outline"));
796 SwNumRule
aNR( rDoc
.GetUniqueNumRuleName( &aName
),
797 SvxNumberFormat::LABEL_WIDTH_AND_POSITION
,
799 aNR
= *rDoc
.GetOutlineNumRule();
801 SetAnld(&aNR
, (WW8_ANLD
*)pData
, nSwNumLevel
, true);
803 // Missing Levels need not be replenished
804 rDoc
.SetOutlineNumRule( aNR
);
805 }else if( pStyles
->nWwNumLevel
== 10 || pStyles
->nWwNumLevel
== 11 ){
806 SwNumRule
* pNR
= GetStyRule();
807 SetAnld(pNR
, (WW8_ANLD
*)pData
, 0, false);
808 pAktColl
->SetFmtAttr( SwNumRuleItem( pNR
->GetName() ) );
810 pStyInf
= GetStyle(nAktColl
);
812 pStyInf
->bHasStyNumRule
= true;
816 //-----------------------------------------
817 // Numbering / Bullets
818 //-----------------------------------------
820 // SetNumOlst() carries the Numrules for this cell to SwNumFmt.
821 // For this the info is fetched from OLST and not from ANLD ( see later )
822 // ( only for outline inside text; Bullets / numbering use ANLDs )
823 void SwWW8ImplReader::SetNumOlst(SwNumRule
* pNumR
, WW8_OLST
* pO
, sal_uInt8 nSwLevel
)
826 WW8_ANLV
&rAV
= pO
->rganlv
[nSwLevel
];
827 SetBaseAnlv(aNF
, rAV
, nSwLevel
);
828 // ... and then the Strings
831 WW8_ANLV
* pAV1
; // search String-Positions
832 for (i
= 0, pAV1
= pO
->rganlv
; i
< nSwLevel
; ++i
, ++pAV1
)
834 nTxtOfs
+= SVBT8ToByte(pAV1
->cbTextBefore
)
835 + SVBT8ToByte(pAV1
->cbTextAfter
);
840 SetAnlvStrings(aNF
, rAV
, pO
->rgch
+ nTxtOfs
, true); // and apply
841 pNumR
->Set(nSwLevel
, aNF
);
844 // The OLST is at the beginning of each section that contains outlines.
845 // The ANLDs that are connected to each outline-line contain only nonsense,
846 // so the OLSTs are remembered for the section to have usable information
847 // when outline-paragraphs occur.
848 void SwWW8ImplReader::Read_OLST( sal_uInt16
, const sal_uInt8
* pData
, short nLen
)
856 pNumOlst
= new WW8_OLST
;
857 if( nLen
< sal::static_int_cast
< sal_Int32
>(sizeof( WW8_OLST
)) ) // fill if to short
858 memset( pNumOlst
, 0, sizeof( *pNumOlst
) );
859 *pNumOlst
= *(WW8_OLST
*)pData
;
862 WW8LvlType
GetNumType(sal_uInt8 nWwLevelNo
)
864 WW8LvlType nRet
= WW8_None
;
865 if( nWwLevelNo
== 12 )
867 else if( nWwLevelNo
== 10 )
868 nRet
= WW8_Numbering
;
869 else if( nWwLevelNo
== 11 )
871 else if( nWwLevelNo
> 0 && nWwLevelNo
<= 9 )
876 SwNumRule
*ANLDRuleMap::GetNumRule(sal_uInt8 nNumType
)
878 return (WW8_Numbering
== nNumType
? mpNumberingNumRule
: mpOutlineNumRule
);
881 void ANLDRuleMap::SetNumRule(SwNumRule
*pRule
, sal_uInt8 nNumType
)
883 if (WW8_Numbering
== nNumType
)
884 mpNumberingNumRule
= pRule
;
886 mpOutlineNumRule
= pRule
;
890 // StartAnl is called at the beginning of a row area that contains
891 // outline / numbering / bullets
892 void SwWW8ImplReader::StartAnl(const sal_uInt8
* pSprm13
)
894 bAktAND_fNumberAcross
= false;
896 sal_uInt8 nT
= static_cast< sal_uInt8
>(GetNumType(*pSprm13
));
897 if (nT
== WW8_Pause
|| nT
== WW8_None
)
901 SwNumRule
*pNumRule
= maANLDRules
.GetNumRule(nWwNumType
);
903 // check for COL numbering:
904 const sal_uInt8
* pS12
= 0;// sprmAnld
909 sNumRule
= pTableDesc
->GetNumRuleName();
912 pNumRule
= rDoc
.FindNumRulePtr(sNumRule
);
917 // this is ROW numbering ?
918 pS12
= pPlcxMan
->HasParaSprm(bVer67
? 12 : 0xC63E); // sprmAnld
919 if (pS12
&& 0 != SVBT8ToByte(((WW8_ANLD
*)pS12
)->fNumberAcross
))
925 SwWW8StyInf
* pStyInf
= GetStyle(nAktColl
);
926 if (!sNumRule
.Len() && pStyInf
!= NULL
&& pStyInf
->bHasStyNumRule
)
928 sNumRule
= pStyInf
->pFmt
->GetNumRule().GetValue();
929 pNumRule
= rDoc
.FindNumRulePtr(sNumRule
);
939 pNumRule
= rDoc
.GetNumRuleTbl()[
940 rDoc
.MakeNumRule( sNumRule
, 0, false,
941 SvxNumberFormat::LABEL_ALIGNMENT
) ];
946 pS12
= pPlcxMan
->HasParaSprm(bVer67
? 12 : 0xC63E); // sprmAnld
947 if (!pS12
|| !SVBT8ToByte( ((WW8_ANLD
*)pS12
)->fNumberAcross
))
948 pTableDesc
->SetNumRuleName(pNumRule
->GetName());
954 // set NumRules via stack
955 pCtrlStck
->NewAttr(*pPaM
->GetPoint(),
956 SfxStringItem(RES_FLTR_NUMRULE
, pNumRule
->GetName()));
958 maANLDRules
.SetNumRule(pNumRule
, nWwNumType
);
961 // NextAnlLine() is called once for every row of a
962 // outline / numbering / bullet
963 void SwWW8ImplReader::NextAnlLine(const sal_uInt8
* pSprm13
)
968 SwNumRule
*pNumRule
= maANLDRules
.GetNumRule(nWwNumType
);
970 // pNd->UpdateNum ohne Regelwerk gibt GPF spaetestens beim Speichern als
973 // WW:10 = numberierung -> SW:0 & WW:11 = bullets -> SW:0
974 if (*pSprm13
== 10 || *pSprm13
== 11)
977 if (!pNumRule
->GetNumFmt(nSwNumLevel
))
981 const sal_uInt8
* pS12
= pPlcxMan
->HasParaSprm(bVer67
? 12 : 0xC63E);
982 SetAnld(pNumRule
, (WW8_ANLD
*)pS12
, nSwNumLevel
, false);
985 else if( *pSprm13
> 0 && *pSprm13
<= MAXLEVEL
) // range WW:1..9 -> SW:0..8
987 nSwNumLevel
= *pSprm13
- 1; // outline
989 if (!pNumRule
->GetNumFmt(nSwNumLevel
))
991 if (pNumOlst
) // there was a OLST
993 //Assure upper levels are set, #i9556#
994 for (sal_uInt8 nI
= 0; nI
< nSwNumLevel
; ++nI
)
996 if (!pNumRule
->GetNumFmt(nI
))
997 SetNumOlst(pNumRule
, pNumOlst
, nI
);
1000 SetNumOlst(pNumRule
, pNumOlst
, nSwNumLevel
);
1002 else // no Olst -> use Anld
1005 const sal_uInt8
* pS12
= pPlcxMan
->HasParaSprm(bVer67
? 12 : 0xC63E);
1006 SetAnld(pNumRule
, (WW8_ANLD
*)pS12
, nSwNumLevel
, false);
1011 nSwNumLevel
= 0xff; // no number
1013 SwTxtNode
* pNd
= pPaM
->GetNode()->GetTxtNode();
1014 if (nSwNumLevel
< MAXLEVEL
)
1015 pNd
->SetAttrListLevel( nSwNumLevel
);
1018 pNd
->SetAttrListLevel(0);
1019 pNd
->SetCountedInList( false );
1023 void SwWW8ImplReader::StopAllAnl(bool bGoBack
)
1025 //Of course we're not restarting, but we'll make use of our knowledge
1026 //of the implementation to do it.
1027 StopAnlToRestart(WW8_None
, bGoBack
);
1030 void SwWW8ImplReader::StopAnlToRestart(sal_uInt8 nNewType
, bool bGoBack
)
1034 SwPosition
aTmpPos(*pPaM
->GetPoint());
1035 pPaM
->Move(fnMoveBackward
, fnGoCntnt
);
1036 pCtrlStck
->SetAttr(*pPaM
->GetPoint(), RES_FLTR_NUMRULE
);
1037 *pPaM
->GetPoint() = aTmpPos
;
1040 pCtrlStck
->SetAttr(*pPaM
->GetPoint(), RES_FLTR_NUMRULE
);
1042 maANLDRules
.mpNumberingNumRule
= 0;
1045 my take on this problem is that moving either way from an outline to a
1046 numbering doesn't halt the outline, while the numbering is always halted
1048 bool bNumberingNotStopOutline
=
1049 (((nWwNumType
== WW8_Outline
) && (nNewType
== WW8_Numbering
)) ||
1050 ((nWwNumType
== WW8_Numbering
) && (nNewType
== WW8_Outline
)));
1051 if (!bNumberingNotStopOutline
)
1052 maANLDRules
.mpOutlineNumRule
= 0;
1055 nWwNumType
= WW8_None
;
1059 WW8TabBandDesc::WW8TabBandDesc( WW8TabBandDesc
& rBand
)
1064 pTCs
= new WW8_TCell
[nWwCols
];
1065 memcpy( pTCs
, rBand
.pTCs
, nWwCols
* sizeof( WW8_TCell
) );
1069 pSHDs
= new WW8_SHD
[nWwCols
];
1070 memcpy( pSHDs
, rBand
.pSHDs
, nWwCols
* sizeof( WW8_SHD
) );
1072 if( rBand
.pNewSHDs
)
1074 pNewSHDs
= new sal_uInt32
[nWwCols
];
1075 memcpy(pNewSHDs
, rBand
.pNewSHDs
, nWwCols
* sizeof(sal_uInt32
));
1077 memcpy(aDefBrcs
, rBand
.aDefBrcs
, sizeof(aDefBrcs
));
1080 // ReadDef reads the cell position and the borders of a band
1081 void WW8TabBandDesc::ReadDef(bool bVer67
, const sal_uInt8
* pS
)
1086 short nLen
= (sal_Int16
)SVBT16ToShort( pS
- 2 ); // not beautiful
1088 sal_uInt8 nCols
= *pS
; // number of cells
1089 short nOldCols
= nWwCols
;
1091 if( nCols
> MAX_COL
)
1096 const sal_uInt8
* pT
= &pS
[1];
1099 for(i
=0; i
<=nCols
; i
++, pT
+=2 )
1100 nCenter
[i
] = (sal_Int16
)SVBT16ToShort( pT
); // X-borders
1101 nLen
-= 2 * ( nCols
+ 1 );
1102 if( nCols
!= nOldCols
) // different column count
1104 delete[] pTCs
, pTCs
= 0;
1105 delete[] pSHDs
, pSHDs
= 0;
1106 delete[] pNewSHDs
, pNewSHDs
= 0;
1109 short nFileCols
= nLen
/ ( bVer67
? 10 : 20 ); // realy saved
1114 pTCs
= new WW8_TCell
[nCols
];
1115 setcelldefaults(pTCs
,nCols
);
1118 short nColsToRead
= nFileCols
;
1119 if (nColsToRead
> nCols
)
1120 nColsToRead
= nCols
;
1127 Attention: Beginning with Ver8 there is an extra ushort per TC
1128 added and the size of the border code is doubled.
1129 Because of this a simple copy (pTCs[i] = *pTc;)
1132 Advantage: The work structure suits better.
1134 WW8_TCell
* pAktTC
= pTCs
;
1137 WW8_TCellVer6
* pTc
= (WW8_TCellVer6
*)pT
;
1138 for(i
=0; i
<nColsToRead
; i
++, ++pAktTC
,++pTc
)
1140 if( i
< nColsToRead
)
1142 sal_uInt8 aBits1
= SVBT8ToByte( pTc
->aBits1Ver6
);
1143 pAktTC
->bFirstMerged
= ( ( aBits1
& 0x01 ) != 0 );
1144 pAktTC
->bMerged
= ( ( aBits1
& 0x02 ) != 0 );
1145 memcpy( pAktTC
->rgbrc
[ WW8_TOP
].aBits1
,
1146 pTc
->rgbrcVer6
[ WW8_TOP
].aBits1
, sizeof( SVBT16
) );
1147 memcpy( pAktTC
->rgbrc
[ WW8_LEFT
].aBits1
,
1148 pTc
->rgbrcVer6
[ WW8_LEFT
].aBits1
, sizeof( SVBT16
) );
1149 memcpy( pAktTC
->rgbrc
[ WW8_BOT
].aBits1
,
1150 pTc
->rgbrcVer6
[ WW8_BOT
].aBits1
, sizeof( SVBT16
) );
1151 memcpy( pAktTC
->rgbrc
[ WW8_RIGHT
].aBits1
,
1152 pTc
->rgbrcVer6
[ WW8_RIGHT
].aBits1
, sizeof( SVBT16
) );
1153 if( ( pAktTC
->bMerged
)
1156 // Cell merged -> remember
1157 //bWWMergedVer6[i] = true;
1158 memcpy( pTCs
[i
-1].rgbrc
[ WW8_RIGHT
].aBits1
,
1159 pTc
->rgbrcVer6
[ WW8_RIGHT
].aBits1
, sizeof( SVBT16
) );
1160 // apply right border to previous cell
1161 // bExist must not be set to false, because WW
1162 // does not count this cells in text boxes....
1169 WW8_TCellVer8
* pTc
= (WW8_TCellVer8
*)pT
;
1170 for (int k
= 0; k
< nColsToRead
; ++k
, ++pAktTC
, ++pTc
)
1172 sal_uInt16 aBits1
= SVBT16ToShort( pTc
->aBits1Ver8
);
1173 pAktTC
->bFirstMerged
= ( ( aBits1
& 0x0001 ) != 0 );
1174 pAktTC
->bMerged
= ( ( aBits1
& 0x0002 ) != 0 );
1175 pAktTC
->bVertical
= ( ( aBits1
& 0x0004 ) != 0 );
1176 pAktTC
->bBackward
= ( ( aBits1
& 0x0008 ) != 0 );
1177 pAktTC
->bRotateFont
= ( ( aBits1
& 0x0010 ) != 0 );
1178 pAktTC
->bVertMerge
= ( ( aBits1
& 0x0020 ) != 0 );
1179 pAktTC
->bVertRestart
= ( ( aBits1
& 0x0040 ) != 0 );
1180 pAktTC
->nVertAlign
= ( ( aBits1
& 0x0180 ) >> 7 );
1181 // note: in aBits1 there are 7 bits unused,
1182 // followed by another 16 unused bits
1184 // In Version 8 koennen we can copy all border codes at once!
1185 memcpy( pAktTC
->rgbrc
, pTc
->rgbrcVer8
, 4 * sizeof( WW8_BRC
) );
1189 // #i25071 In '97 text direction appears to be only set using TC properties
1190 // not with sprmTTextFlow so we need to cycle through the maDirections and
1191 // double check any non-default directions
1192 for (int k
= 0; k
< nCols
; ++k
)
1194 if(maDirections
[k
] == 4)
1196 if(pTCs
[k
].bVertical
)
1198 if(pTCs
[k
].bBackward
)
1199 maDirections
[k
] = 3;
1201 maDirections
[k
] = 1;
1210 void WW8TabBandDesc::ProcessSprmTSetBRC(bool bVer67
, const sal_uInt8
* pParamsTSetBRC
)
1212 if( pParamsTSetBRC
&& pTCs
) // set one or more cell border(s)
1214 sal_uInt8 nitcFirst
= pParamsTSetBRC
[0];// first col to be changed
1215 sal_uInt8 nitcLim
= pParamsTSetBRC
[1];// (last col to be changed)+1
1216 sal_uInt8 nFlag
= *(pParamsTSetBRC
+2);
1218 if (nitcFirst
>= nWwCols
)
1221 if (nitcLim
> nWwCols
)
1224 bool bChangeRight
= (nFlag
& 0x08) ? true : false;
1225 bool bChangeBottom
= (nFlag
& 0x04) ? true : false;
1226 bool bChangeLeft
= (nFlag
& 0x02) ? true : false;
1227 bool bChangeTop
= (nFlag
& 0x01) ? true : false;
1229 WW8_TCell
* pAktTC
= pTCs
+ nitcFirst
;
1232 WW8_BRCVer6
* pBRC
= (WW8_BRCVer6
*)(pParamsTSetBRC
+3);
1234 for( int i
= nitcFirst
; i
< nitcLim
; ++i
, ++pAktTC
)
1238 memcpy( pAktTC
->rgbrc
[ WW8_TOP
].aBits1
,
1244 memcpy( pAktTC
->rgbrc
[ WW8_LEFT
].aBits1
,
1250 memcpy( pAktTC
->rgbrc
[ WW8_BOT
].aBits1
,
1256 memcpy( pAktTC
->rgbrc
[ WW8_RIGHT
].aBits1
,
1264 WW8_BRC
* pBRC
= (WW8_BRC
*)(pParamsTSetBRC
+3);
1266 for( int i
= nitcFirst
; i
< nitcLim
; ++i
, ++pAktTC
)
1270 memcpy( pAktTC
->rgbrc
[ WW8_TOP
].aBits1
,
1273 memcpy( pAktTC
->rgbrc
[ WW8_TOP
].aBits2
,
1279 memcpy( pAktTC
->rgbrc
[ WW8_LEFT
].aBits1
,
1282 memcpy( pAktTC
->rgbrc
[ WW8_LEFT
].aBits2
,
1288 memcpy( pAktTC
->rgbrc
[ WW8_BOT
].aBits1
,
1291 memcpy( pAktTC
->rgbrc
[ WW8_BOT
].aBits2
,
1297 memcpy( pAktTC
->rgbrc
[ WW8_RIGHT
].aBits1
,
1300 memcpy( pAktTC
->rgbrc
[ WW8_RIGHT
].aBits2
,
1309 void WW8TabBandDesc::ProcessSprmTTableBorders(bool bVer67
, const sal_uInt8
* pParams
)
1311 // sprmTTableBorders
1314 for( int i
= 0; i
< 6; ++i
)
1316 aDefBrcs
[i
].aBits1
[0] = pParams
[ 2*i
];
1317 aDefBrcs
[i
].aBits1
[1] = pParams
[ 1+2*i
];
1320 else // aDefBrcs = *(BRC(*)[6])pS;
1321 memcpy( aDefBrcs
, pParams
, 24 );
1324 void WW8TabBandDesc::ProcessSprmTDxaCol(const sal_uInt8
* pParamsTDxaCol
)
1326 // sprmTDxaCol (opcode 0x7623) changes the width of cells
1327 // whose index is within a certain range to be a certain value.
1329 if( nWwCols
&& pParamsTDxaCol
) // set one or more cell length(s)
1331 sal_uInt8 nitcFirst
= pParamsTDxaCol
[0]; // first col to be changed
1332 sal_uInt8 nitcLim
= pParamsTDxaCol
[1]; // (last col to be changed)+1
1333 short nDxaCol
= (sal_Int16
)SVBT16ToShort( pParamsTDxaCol
+ 2 );
1337 for( int i
= nitcFirst
; (i
< nitcLim
) && (i
< nWwCols
); i
++ )
1339 nOrgWidth
= nCenter
[i
+1] - nCenter
[i
];
1340 nDelta
= nDxaCol
- nOrgWidth
;
1341 for( int j
= i
+1; j
<= nWwCols
; j
++ )
1343 nCenter
[j
] = nCenter
[j
] + nDelta
;
1349 void WW8TabBandDesc::ProcessSprmTInsert(const sal_uInt8
* pParamsTInsert
)
1351 if( nWwCols
&& pParamsTInsert
) // set one or more cell length(s)
1353 sal_uInt8 nitcInsert
= pParamsTInsert
[0]; // position at which to insert
1354 if (nitcInsert
>= MAX_COL
) // cannot insert into cell outside max possible index
1356 sal_uInt8 nctc
= pParamsTInsert
[1]; // number of cells
1357 sal_uInt16 ndxaCol
= SVBT16ToShort( pParamsTInsert
+2 );
1360 if (nitcInsert
> nWwCols
)
1362 nNewWwCols
= nitcInsert
+nctc
;
1363 //if new count would be outside max possible count, clip it, and calc a new replacement
1365 if (nNewWwCols
> MAX_COL
)
1367 nNewWwCols
= MAX_COL
;
1368 nctc
= ::sal::static_int_cast
<sal_uInt8
>(nNewWwCols
-nitcInsert
);
1373 nNewWwCols
= nWwCols
+nctc
;
1374 //if new count would be outside max possible count, clip it, and calc a new replacement
1376 if (nNewWwCols
> MAX_COL
)
1378 nNewWwCols
= MAX_COL
;
1379 nctc
= ::sal::static_int_cast
<sal_uInt8
>(nNewWwCols
-nWwCols
);
1383 WW8_TCell
*pTC2s
= new WW8_TCell
[nNewWwCols
];
1384 setcelldefaults(pTC2s
, nNewWwCols
);
1388 memcpy( pTC2s
, pTCs
, nWwCols
* sizeof( WW8_TCell
) );
1393 //If we have to move some cells
1394 if (nitcInsert
<= nWwCols
)
1396 // adjust the left x-position of the dummy at the very end
1397 nCenter
[nWwCols
+ nctc
] = nCenter
[nWwCols
]+nctc
*ndxaCol
;
1398 for( int i
= nWwCols
-1; i
>= nitcInsert
; i
--)
1400 // adjust the left x-position
1401 nCenter
[i
+ nctc
] = nCenter
[i
]+nctc
*ndxaCol
;
1403 // adjust the cell's borders
1404 pTCs
[i
+ nctc
] = pTCs
[i
];
1408 //if itcMac is larger than full size, fill in missing ones first
1409 for( int i
= nWwCols
; i
> nitcInsert
+nWwCols
; i
--)
1410 nCenter
[i
] = i
? (nCenter
[i
- 1]+ndxaCol
) : 0;
1412 //now add in our new cells
1413 for( int j
= 0;j
< nctc
; j
++)
1414 nCenter
[j
+ nitcInsert
] = (j
+ nitcInsert
) ? (nCenter
[j
+ nitcInsert
-1]+ndxaCol
) : 0;
1416 nWwCols
= nNewWwCols
;
1420 void WW8TabBandDesc::ProcessDirection(const sal_uInt8
* pParams
)
1422 sal_uInt8 nStartCell
= *pParams
++;
1423 sal_uInt8 nEndCell
= *pParams
++;
1424 sal_uInt16 nCode
= SVBT16ToShort(pParams
);
1426 OSL_ENSURE(nStartCell
< nEndCell
, "not as I thought");
1427 OSL_ENSURE(nEndCell
< MAX_COL
+ 1, "not as I thought");
1428 if (nStartCell
> MAX_COL
)
1430 if (nEndCell
> MAX_COL
+ 1)
1431 nEndCell
= MAX_COL
+ 1;
1433 for (;nStartCell
< nEndCell
; ++nStartCell
)
1434 maDirections
[nStartCell
] = nCode
;
1437 void WW8TabBandDesc::ProcessSpacing(const sal_uInt8
* pParams
)
1439 sal_uInt8 nLen
= pParams
? *(pParams
- 1) : 0;
1440 OSL_ENSURE(nLen
== 6, "Unexpected spacing len");
1444 #if OSL_DEBUG_LEVEL > 0
1445 sal_uInt8 nWhichCell
= *pParams
;
1446 OSL_ENSURE(nWhichCell
== 0, "Expected cell to be 0!");
1448 ++pParams
; //Skip which cell
1449 ++pParams
; //unknown byte
1451 sal_uInt8 nSideBits
= *pParams
++;
1452 OSL_ENSURE(nSideBits
< 0x10, "Unexpected value for nSideBits");
1453 ++pParams
; //unknown byte
1454 sal_uInt16 nValue
= SVBT16ToShort( pParams
);
1455 for (int i
= wwTOP
; i
<= wwRIGHT
; i
++)
1457 switch (nSideBits
& (1 << i
))
1460 mnDefaultTop
= nValue
;
1463 mnDefaultLeft
= nValue
;
1466 mnDefaultBottom
= nValue
;
1469 mnDefaultRight
= nValue
;
1474 OSL_ENSURE(!this, "Impossible");
1480 void WW8TabBandDesc::ProcessSpecificSpacing(const sal_uInt8
* pParams
)
1482 sal_uInt8 nLen
= pParams
? *(pParams
- 1) : 0;
1483 OSL_ENSURE(nLen
== 6, "Unexpected spacing len");
1486 sal_uInt8 nWhichCell
= *pParams
++;
1487 OSL_ENSURE(nWhichCell
< MAX_COL
+ 1, "Cell out of range in spacings");
1488 if (nWhichCell
>= MAX_COL
+ 1)
1491 ++pParams
; //unknown byte
1492 sal_uInt8 nSideBits
= *pParams
++;
1493 OSL_ENSURE(nSideBits
< 0x10, "Unexpected value for nSideBits");
1494 nOverrideSpacing
[nWhichCell
] |= nSideBits
;
1496 OSL_ENSURE(nOverrideSpacing
[nWhichCell
] < 0x10,
1497 "Unexpected value for nSideBits");
1498 #if OSL_DEBUG_LEVEL > 0
1499 sal_uInt8 nUnknown2
= *pParams
;
1500 OSL_ENSURE(nUnknown2
== 0x3, "Unexpected value for spacing2");
1503 sal_uInt16 nValue
= SVBT16ToShort( pParams
);
1505 for (int i
=0; i
< 4; i
++)
1507 if (nSideBits
& (1 << i
))
1508 nOverrideValues
[nWhichCell
][i
] = nValue
;
1512 void WW8TabBandDesc::ProcessSprmTDelete(const sal_uInt8
* pParamsTDelete
)
1514 if( nWwCols
&& pParamsTDelete
) // set one or more cell length(s)
1516 sal_uInt8 nitcFirst
= pParamsTDelete
[0]; // first col to be deleted
1517 if (nitcFirst
>= nWwCols
) // first index to delete from doesn't exist
1519 sal_uInt8 nitcLim
= pParamsTDelete
[1]; // (last col to be deleted)+1
1520 if (nitcLim
<= nitcFirst
) // second index to delete to is not greater than first index
1524 * sprmTDelete causes any rgdxaCenter and rgtc entries whose index is
1525 * greater than or equal to itcLim to be moved
1527 int nShlCnt
= nWwCols
- nitcLim
; // count of cells to be shifted
1529 if (nShlCnt
>= 0) //There exist entries whose index is greater than or equal to itcLim
1531 WW8_TCell
* pAktTC
= pTCs
+ nitcFirst
;
1533 while( i
< nShlCnt
)
1535 // adjust the left x-position
1536 nCenter
[nitcFirst
+ i
] = nCenter
[nitcLim
+ i
];
1538 // adjust the cell's borders
1539 *pAktTC
= pTCs
[ nitcLim
+ i
];
1544 // adjust the left x-position of the dummy at the very end
1545 nCenter
[nitcFirst
+ i
] = nCenter
[nitcLim
+ i
];
1548 short nCellsDeleted
= nitcLim
- nitcFirst
;
1549 //clip delete request to available number of cells
1550 if (nCellsDeleted
> nWwCols
)
1551 nCellsDeleted
= nWwCols
;
1552 nWwCols
-= nCellsDeleted
;
1556 // ReadShd reads the background color of a cell
1557 // ReadDef must be called before
1558 void WW8TabBandDesc::ReadShd(const sal_uInt8
* pS
)
1560 sal_uInt8 nLen
= pS
? *(pS
- 1) : 0;
1566 pSHDs
= new WW8_SHD
[nWwCols
];
1567 memset( pSHDs
, 0, nWwCols
* sizeof( WW8_SHD
) );
1570 short nAnz
= nLen
>> 1;
1576 for(i
=0, pShd
= (SVBT16
*)pS
; i
<nAnz
; i
++, pShd
++ )
1577 pSHDs
[i
].SetWWValue( *pShd
);
1580 void WW8TabBandDesc::ReadNewShd(const sal_uInt8
* pS
, bool bVer67
)
1582 sal_uInt8 nLen
= pS
? *(pS
- 1) : 0;
1587 pNewSHDs
= new sal_uInt32
[nWwCols
];
1589 short nAnz
= nLen
/ 10; //10 bytes each
1595 pNewSHDs
[i
++] = SwWW8ImplReader::ExtractColour(pS
, bVer67
);
1598 pNewSHDs
[i
++] = COL_AUTO
;
1601 void WW8TabBandDesc::setcelldefaults(WW8_TCell
*pCells
, short nCols
)
1603 memset( pCells
, 0, nCols
* sizeof( WW8_TCell
) );
1606 const sal_uInt8
*HasTabCellSprm(WW8PLCFx_Cp_FKP
* pPap
, bool bVer67
)
1608 const sal_uInt8
*pParams
;
1610 pParams
= pPap
->HasSprm(24);
1613 if (0 == (pParams
= pPap
->HasSprm(0x244B)))
1614 pParams
= pPap
->HasSprm(0x2416);
1623 sprmTTableWidth
,sprmTTextFlow
, sprmTFCantSplit
, sprmTFCantSplit90
,sprmTJc
, sprmTFBiDi
, sprmTDefTable
,
1624 sprmTDyaRowHeight
, sprmTDefTableShd
, sprmTDxaLeft
, sprmTSetBrc
,
1625 sprmTDxaCol
, sprmTInsert
, sprmTDelete
, sprmTTableHeader
,
1626 sprmTDxaGapHalf
, sprmTTableBorders
,
1628 sprmTDefTableNewShd
, sprmTSpacing
, sprmTNewSpacing
1631 wwTableSprm
GetTableSprm(sal_uInt16 nId
, ww::WordVersion eVer
)
1639 return sprmTTableWidth
;
1641 return sprmTTextFlow
;
1643 return sprmTFCantSplit
;
1645 return sprmTTableHeader
;
1647 return sprmTFCantSplit90
;
1659 return sprmTDyaRowHeight
;
1661 return sprmTDxaLeft
;
1663 return sprmTDxaGapHalf
;
1665 return sprmTTableBorders
;
1667 return sprmTDefTable
;
1669 return sprmTDefTableShd
;
1671 return sprmTDefTableNewShd
;
1675 return sprmTSpacing
;
1677 return sprmTNewSpacing
;
1687 return sprmTDxaLeft
;
1689 return sprmTDxaGapHalf
;
1691 return sprmTTableHeader
;
1693 return sprmTTableBorders
;
1695 return sprmTDyaRowHeight
;
1697 return sprmTDefTable
;
1699 return sprmTDefTableShd
;
1716 return sprmTDxaLeft
;
1718 return sprmTDxaGapHalf
;
1720 return sprmTDyaRowHeight
;
1722 return sprmTDefTable
;
1724 return sprmTDefTableShd
;
1739 WW8TabDesc::WW8TabDesc(SwWW8ImplReader
* pIoClass
, WW8_CP nStartCp
) :
1740 mpOldRedlineStack(0),
1761 bClaimLineFmt(false),
1762 eOri(text::HoriOrientation::NONE
),
1771 aItemSet(pIo
->rDoc
.GetAttrPool(),RES_FRMATR_BEGIN
,RES_FRMATR_END
-1)
1773 pIo
->bAktAND_fNumberAcross
= false;
1775 static const sal_Int16 aOriArr
[] =
1777 text::HoriOrientation::LEFT
, text::HoriOrientation::CENTER
, text::HoriOrientation::RIGHT
, text::HoriOrientation::CENTER
1780 bool bOldVer
= ww::IsSevenMinus(pIo
->GetFib().GetFIBVersion());
1781 WW8_TablePos aTabPos
;
1783 WW8PLCFxSave1 aSave
;
1784 pIo
->pPlcxMan
->GetPap()->Save( aSave
);
1786 WW8PLCFx_Cp_FKP
* pPap
= pIo
->pPlcxMan
->GetPapPLCF();
1788 eOri
= text::HoriOrientation::LEFT
;
1790 WW8TabBandDesc
* pNewBand
= new WW8TabBandDesc
;
1792 wwSprmParser
aSprmParser(pIo
->GetFib().GetFIBVersion());
1794 // process pPap until end of table found
1797 short nTabeDxaNew
= SHRT_MAX
;
1798 bool bTabRowJustRead
= false;
1799 const sal_uInt8
* pShadeSprm
= 0;
1800 const sal_uInt8
* pNewShadeSprm
= 0;
1801 WW8_TablePos
*pTabPos
= 0;
1803 // search end of a tab row
1804 if(!(pIo
->SearchRowEnd(pPap
, nStartCp
, pIo
->nInTable
)))
1810 // Get the SPRM chains:
1811 // first from PAP and then from PCD (of the Piece Table)
1813 pPap
->GetSprms( &aDesc
);
1814 WW8SprmIter
aSprmIter(aDesc
.pMemPos
, aDesc
.nSprmsLen
, aSprmParser
);
1816 const sal_uInt8
* pParams
= aSprmIter
.GetAktParams();
1817 for (int nLoop
= 0; nLoop
< 2; ++nLoop
)
1819 bool bRepeatedSprm
= false;
1820 while (aSprmIter
.GetSprms() && 0 != (pParams
= aSprmIter
.GetAktParams()))
1822 sal_uInt16 nId
= aSprmIter
.GetAktId();
1823 wwTableSprm eSprm
= GetTableSprm(nId
, pIo
->GetFib().GetFIBVersion());
1826 case sprmTTableWidth
:
1828 const sal_uInt8 b0
= pParams
[0];
1829 const sal_uInt8 b1
= pParams
[1];
1830 const sal_uInt8 b2
= pParams
[2];
1831 if (b0
== 3) // Twips
1832 nPreferredWidth
= b2
* 0x100 + b1
;
1836 pNewBand
->ProcessDirection(pParams
);
1838 case sprmTFCantSplit
:
1839 pNewBand
->bCantSplit
= *pParams
;
1840 bClaimLineFmt
= true;
1842 case sprmTFCantSplit90
:
1843 pNewBand
->bCantSplit90
= *pParams
;
1844 bClaimLineFmt
= true;
1846 case sprmTTableBorders
:
1847 pNewBand
->ProcessSprmTTableBorders(bOldVer
, pParams
);
1849 case sprmTTableHeader
:
1853 bRepeatedSprm
= true;
1857 // sprmTJc - Justification Code
1859 eOri
= aOriArr
[*pParams
& 0x3];
1862 bIsBiDi
= SVBT16ToShort(pParams
) ? true : false;
1864 case sprmTDxaGapHalf
:
1865 pNewBand
->nGapHalf
= (sal_Int16
)SVBT16ToShort( pParams
);
1867 case sprmTDyaRowHeight
:
1868 pNewBand
->nLineHeight
= (sal_Int16
)SVBT16ToShort( pParams
);
1869 bClaimLineFmt
= true;
1872 pNewBand
->ReadDef(bOldVer
, pParams
);
1873 bTabRowJustRead
= true;
1875 case sprmTDefTableShd
:
1876 pShadeSprm
= pParams
;
1878 case sprmTDefTableNewShd
:
1879 pNewShadeSprm
= pParams
;
1882 // our Writer cannot shift single table lines
1883 // horizontally so we have to find the smallest
1884 // parameter (meaning the left-most position) and then
1885 // shift the whole table to that margin (see below)
1887 short nDxaNew
= (sal_Int16
)SVBT16ToShort( pParams
);
1888 nOrgDxaLeft
= nDxaNew
;
1889 if( nDxaNew
< nTabeDxaNew
)
1890 nTabeDxaNew
= nDxaNew
;
1894 pNewBand
->ProcessSprmTSetBRC(bOldVer
, pParams
);
1897 pNewBand
->ProcessSprmTDxaCol(pParams
);
1900 pNewBand
->ProcessSprmTInsert(pParams
);
1903 pNewBand
->ProcessSprmTDelete(pParams
);
1905 case sprmTNewSpacing
:
1906 pNewBand
->ProcessSpacing(pParams
);
1909 pNewBand
->ProcessSpecificSpacing(pParams
);
1914 aSprmIter
.advance();
1919 pPap
->GetPCDSprms( aDesc
);
1920 aSprmIter
.SetSprms( aDesc
.pMemPos
, aDesc
.nSprmsLen
);
1924 // WW-Tables can contain Fly-changes. For this abort tables here
1925 // and start again. *pPap is still before TabRowEnd, so TestApo()
1926 // can be called with the last parameter set to false and therefore
1929 if (bTabRowJustRead
)
1932 pNewBand
->ReadShd(pShadeSprm
);
1934 pNewBand
->ReadNewShd(pNewShadeSprm
, bOldVer
);
1937 if( nTabeDxaNew
< SHRT_MAX
)
1939 short* pCenter
= pNewBand
->nCenter
;
1940 short firstDxaCenter
= *pCenter
;
1941 for( int i
= 0; i
< pNewBand
->nWwCols
; i
++, ++pCenter
)
1943 // #i30298# Use sprmTDxaLeft to adjust the left indent
1944 // #i40461# Use dxaGapHalf during calculation
1946 (nTabeDxaNew
- (firstDxaCenter
+ pNewBand
->nGapHalf
));
1951 pActBand
= pFirstBand
= pNewBand
;
1954 pActBand
->pNextBand
= pNewBand
;
1955 pActBand
= pNewBand
;
1959 pNewBand
= new WW8TabBandDesc
;
1964 //Seek our pap to its next block of properties
1967 aRes
.nStartPos
= nStartCp
;
1969 if (!(pPap
->SeekPos(aRes
.nStartPos
)))
1971 aRes
.nEndPos
= WW8_CP_MAX
;
1972 pPap
->SetDirty(true);
1974 pPap
->GetSprms(&aRes
);
1975 pPap
->SetDirty(false);
1977 //Are we at the end of available properties
1979 !pPap
->HasFkp() || pPap
->Where() == WW8_CP_MAX
||
1980 aRes
.nStartPos
== WW8_CP_MAX
1987 //Are we still in a table cell
1988 pParams
= HasTabCellSprm(pPap
, bOldVer
);
1989 const sal_uInt8
*pLevel
= pPap
->HasSprm(0x6649);
1991 if (!pParams
|| (1 != *pParams
) ||
1992 (pLevel
&& (*pLevel
<= pIo
->nInTable
)))
1997 //Get the end of row new table positioning data
1998 WW8_CP nMyStartCp
=nStartCp
;
1999 if (pIo
->SearchRowEnd(pPap
, nMyStartCp
, pIo
->nInTable
))
2000 if (pIo
->ParseTabPos(&aTabPos
, pPap
))
2003 //Move back to this cell
2005 aRes
.nStartPos
= nStartCp
;
2007 // PlcxMan currently points too far ahead so we need to bring
2008 // it back to where we are trying to make a table
2009 pIo
->pPlcxMan
->GetPap()->nOrigStartPos
= aRes
.nStartPos
;
2010 if (!(pPap
->SeekPos(aRes
.nStartPos
)))
2012 aRes
.nEndPos
= WW8_CP_MAX
;
2013 pPap
->SetDirty(true);
2015 pPap
->GetSprms(&aRes
);
2016 pPap
->SetDirty(false);
2018 //Does this row match up with the last row closely enough to be
2019 //considered part of the same table
2020 ApoTestResults aApo
= pIo
->TestApo(pIo
->nInTable
+ 1, false, pTabPos
);
2023 ##513##, #79474# If this is not sufficent, then we should look at
2024 sprmPD{y|x}aAbs as our indicator that the following set of rows is not
2025 part of this table, but instead is an absolutely positioned table
2030 if (aApo
.mbStartApo
)
2032 //if there really is a fly here, and not a "null" fly then break.
2033 WW8FlyPara
*pNewFly
= pIo
->ConstructApo(aApo
, pTabPos
);
2040 nStartCp
= aRes
.nEndPos
;
2046 if( pActBand
->nRows
> 1 )
2048 // last band has more than 1 cell
2050 pNewBand
= new WW8TabBandDesc( *pActBand
); // create new
2051 pActBand
->nRows
--; // wegen Sonderbehandlung Raender-Defaults
2052 pNewBand
->nRows
= 1;
2053 pActBand
->pNextBand
= pNewBand
; // am Ende einschleifen
2055 pNewBand
= 0; // do not delete
2061 pIo
->pPlcxMan
->GetPap()->Restore( aSave
);
2064 WW8TabDesc::~WW8TabDesc()
2066 WW8TabBandDesc
* pR
= pFirstBand
;
2069 WW8TabBandDesc
* pR2
= pR
->pNextBand
;
2077 void WW8TabDesc::CalcDefaults()
2079 short nMinCols
= SHRT_MAX
;
2082 nMinLeft
= SHRT_MAX
;
2083 nMaxRight
= SHRT_MIN
;
2086 If we are an honestly inline centered table, then the normal rules of
2087 engagement for left and right margins do not apply. The multiple rows are
2088 centered regardless of the actual placement of rows, so we cannot have
2089 mismatched rows as is possible in other configurations.
2091 e.g. change the example bugdoc in word from text wrapping of none (inline)
2092 to around (in frame (bApo)) and the table splits into two very disjoint
2093 rows as the beginning point of each row are very different
2095 if ((!pIo
->InLocalApo()) && (eOri
== text::HoriOrientation::CENTER
))
2097 for (pR
= pFirstBand
; pR
; pR
= pR
->pNextBand
)
2098 for( short i
= pR
->nWwCols
; i
>= 0; --i
)
2099 pR
->nCenter
[i
] = pR
->nCenter
[i
] - pR
->nCenter
[0];
2102 // 1. Durchlauf: aeusserste L- und R-Grenzen finden
2103 for( pR
= pFirstBand
; pR
; pR
= pR
->pNextBand
)
2105 if( pR
->nCenter
[0] < nMinLeft
)
2106 nMinLeft
= pR
->nCenter
[0];
2108 for( short i
= 0; i
< pR
->nWwCols
; i
++ )
2111 If the margins are so large as to make the displayable
2112 area inside them smaller than the minimum allowed then adjust the
2113 width to fit. But only do it if the two cells are not the exact
2114 same value, if they are then the cell does not really exist and will
2115 be blended together into the same cell through the use of the
2117 #i28333# If the nGapHalf is greater than the cell width best to ignore it
2119 int nCellWidth
= pR
->nCenter
[i
+1] - pR
->nCenter
[i
];
2120 if (nCellWidth
&& ((nCellWidth
- pR
->nGapHalf
*2) < MINLAY
) && pR
->nGapHalf
< nCellWidth
)
2122 pR
->nCenter
[i
+1] = pR
->nCenter
[i
]+MINLAY
+pR
->nGapHalf
* 2;
2126 if( pR
->nCenter
[pR
->nWwCols
] > nMaxRight
)
2127 nMaxRight
= pR
->nCenter
[pR
->nWwCols
];
2129 nSwWidth
= nMaxRight
- nMinLeft
;
2131 // If the table is right aligned we need to align all rows to the
2132 // row that has the furthest right point
2134 if(eOri
== text::HoriOrientation::RIGHT
)
2136 for( pR
= pFirstBand
; pR
; pR
= pR
->pNextBand
)
2138 int adjust
= nMaxRight
- pR
->nCenter
[pR
->nWwCols
];
2139 for( short i
= 0; i
< pR
->nWwCols
+ 1; i
++ )
2141 pR
->nCenter
[i
] = static_cast< short >(pR
->nCenter
[i
] + adjust
);
2147 // 2. pass: Detect number of writer columns. This can exceed the count
2148 // of columns in WW by 2, because SW in constrast to WW does not provide
2149 // fringed left and right borders and has to fill with empty boxes.
2150 // Non exisitent cells can reduce the number of columns.
2152 // 3. pass: Replace border with defaults if needed
2153 nConvertedLeft
= nMinLeft
;
2155 short nLeftMaxThickness
= 0, nRightMaxThickness
=0;
2156 for( pR
= pFirstBand
; pR
; pR
= pR
->pNextBand
)
2160 pR
->pTCs
= new WW8_TCell
[ pR
->nWwCols
];
2161 memset( pR
->pTCs
, 0, pR
->nWwCols
* sizeof( WW8_TCell
) );
2163 for (int k
= 0; k
< pR
->nWwCols
; ++k
)
2165 WW8_TCell
* pT
= &pR
->pTCs
[k
];
2167 for( i
= 0; i
< 4; i
++ )
2169 if (pT
->rgbrc
[i
].IsZeroed(pIo
->bVer67
))
2171 // if shadow is set, its invalid
2176 // outer top / horizontally inside
2177 j
= (pR
== pFirstBand
) ? 0 : 4;
2180 // outer left / vertically inside
2184 // outer bottom / horizontally inside
2185 j
= pR
->pNextBand
? 4 : 2;
2188 // outer right / vertically inside
2189 j
= (k
== pR
->nWwCols
- 1) ? 3 : 5;
2192 // mangel mit Defaults ueber
2193 pT
->rgbrc
[i
] = pR
->aDefBrcs
[j
];
2200 Similiar to graphics and other elements word does not totally
2201 factor the width of the border into its calculations of size, we
2202 do so we must adjust out widths and other dimensions to fit. It
2203 appears that what occurs is that the last cell's right margin if
2204 the margin width that is not calculated into winwords table
2205 dimensions, so in that case increase the table to include the
2206 extra width of the right margin.
2209 !(SVBT16ToShort(pR
->pTCs
[pR
->nWwCols
-1].rgbrc
[3].aBits1
) & 0x20)
2210 : !(SVBT16ToShort(pR
->pTCs
[pR
->nWwCols
-1].rgbrc
[3].aBits2
) & 0x2000))
2212 short nThickness
= pR
->pTCs
[pR
->nWwCols
-1].rgbrc
[3].
2213 DetermineBorderProperties(pIo
->bVer67
);
2214 pR
->nCenter
[pR
->nWwCols
] = pR
->nCenter
[pR
->nWwCols
] + nThickness
;
2215 if (nThickness
> nRightMaxThickness
)
2216 nRightMaxThickness
= nThickness
;
2220 The left space of the table is in nMinLeft, but again this
2221 does not consider the margin thickness to its left in the
2222 placement value, so get the thickness of the left border,
2223 half is placed to the left of the nominal left side, and
2227 !(SVBT16ToShort(pR
->pTCs
[0].rgbrc
[1].aBits1
) & 0x20)
2228 : !(SVBT16ToShort(pR
->pTCs
[0].rgbrc
[1].aBits2
) & 0x2000))
2230 short nThickness
= pR
->pTCs
[0].rgbrc
[1].
2231 DetermineBorderProperties(pIo
->bVer67
);
2232 if (nThickness
> nLeftMaxThickness
)
2233 nLeftMaxThickness
= nThickness
;
2237 nSwWidth
= nSwWidth
+ nRightMaxThickness
;
2238 nMaxRight
= nMaxRight
+ nRightMaxThickness
;
2239 nConvertedLeft
= nMinLeft
-(nLeftMaxThickness
/2);
2241 for( pR
= pFirstBand
; pR
; pR
= pR
->pNextBand
)
2243 pR
->nSwCols
= pR
->nWwCols
;
2244 pR
->bLEmptyCol
= pR
->nCenter
[0] - nMinLeft
>= MINLAY
;
2245 pR
->bREmptyCol
= (nMaxRight
- pR
->nCenter
[pR
->nWwCols
] - nRightMaxThickness
) >= MINLAY
;
2247 short nAddCols
= pR
->bLEmptyCol
+ pR
->bREmptyCol
;
2249 sal_uInt16 j
= ( pR
->bLEmptyCol
) ? 1 : 0;
2250 for (i
= 0; i
< pR
->nWwCols
; ++i
)
2252 pR
->nTransCell
[i
] = (sal_Int8
)j
;
2253 if ( pR
->nCenter
[i
] < pR
->nCenter
[i
+1] )
2255 pR
->bExist
[i
] = true;
2260 pR
->bExist
[i
] = false;
2265 OSL_ENSURE(i
,"no columns in row ?");
2268 If the last cell was "false" then there is no valid cell following it,
2269 so the default mapping forward wont't work. So map it (and
2270 contigious invalid cells backwards to the last valid cell instead.
2272 if (i
&& pR
->bExist
[i
-1] == false)
2275 while (k
&& pR
->bExist
[k
] == false)
2277 for (sal_uInt16 n
=k
+1;n
<i
;n
++)
2278 pR
->nTransCell
[n
] = pR
->nTransCell
[k
];
2281 pR
->nTransCell
[i
++] = (sal_Int8
)(j
++); // Can exceed by 2 among other
2282 pR
->nTransCell
[i
] = (sal_Int8
)j
; // things because of bREmptyCol
2284 pR
->nSwCols
= pR
->nSwCols
+ nAddCols
;
2285 if( pR
->nSwCols
< nMinCols
)
2286 nMinCols
= pR
->nSwCols
;
2291 Find the largest of the borders on cells that adjoin top bottom and remove
2292 the val from the top and put in on the bottom cell. I can't seem to make
2293 disjoint upper and lowers to see what happens there.
2296 if ((nMinLeft
&& !bIsBiDi
&& text::HoriOrientation::LEFT
== eOri
) ||
2297 (nMinLeft
!= -108 && bIsBiDi
&& text::HoriOrientation::RIGHT
== eOri
)) // Word sets the first nCenter value to -108 when no indent is used
2298 eOri
= text::HoriOrientation::LEFT_AND_WIDTH
; // absolutely positioned
2300 nDefaultSwCols
= nMinCols
; // because inserting cells is cheaper than merging
2301 if( nDefaultSwCols
== 0 )
2303 pActBand
= pFirstBand
;
2305 OSL_ENSURE( pActBand
, "pActBand ist 0" );
2308 void WW8TabDesc::SetSizePosition(SwFrmFmt
* pFrmFmt
)
2310 SwFrmFmt
* pApply
= pFrmFmt
;
2312 pApply
= pTable
->GetFrmFmt();
2313 OSL_ENSURE(pApply
,"No frame");
2314 pApply
->SetFmtAttr(aItemSet
);
2317 SwFmtFrmSize aSize
= pFrmFmt
->GetFrmSize();
2318 aSize
.SetHeightSizeType(ATT_MIN_SIZE
);
2319 aSize
.SetHeight(MINLAY
);
2320 pFrmFmt
->SetFmtAttr(aSize
);
2321 pTable
->GetFrmFmt()->SetFmtAttr(SwFmtHoriOrient(0,text::HoriOrientation::FULL
));
2325 void wwSectionManager::PrependedInlineNode(const SwPosition
&rPos
,
2326 const SwNode
&rNode
)
2328 OSL_ENSURE(!maSegments
.empty(),
2329 "should not be possible, must be at least one segment");
2330 if ((!maSegments
.empty()) && (maSegments
.back().maStart
== rPos
.nNode
))
2331 maSegments
.back().maStart
= SwNodeIndex(rNode
);
2334 void WW8TabDesc::CreateSwTable()
2336 ::SetProgressState(pIo
->nProgress
, pIo
->mpDocShell
); // Update
2338 // if there is already some content on the Node append new node to ensure
2339 // that this content remains ABOVE the table
2340 SwPosition
* pPoint
= pIo
->pPaM
->GetPoint();
2341 bool bInsNode
= pPoint
->nContent
.GetIndex() ? true : false;
2342 bool bSetMinHeight
= false;
2346 Set fly anchor to its anchor pos, so that if a table starts immediately
2347 at this position a new node will be inserted before inserting the table.
2349 if (!bInsNode
&& pIo
->pFmtOfJustInsertedApo
)
2351 const SwPosition
* pAPos
=
2352 pIo
->pFmtOfJustInsertedApo
->GetAnchor().GetCntntAnchor();
2353 if (pAPos
&& &pAPos
->nNode
.GetNode() == &pPoint
->nNode
.GetNode())
2356 bSetMinHeight
= true;
2358 SwFmtSurround
aSur(pIo
->pFmtOfJustInsertedApo
->GetSurround());
2359 aSur
.SetAnchorOnly(true);
2360 pIo
->pFmtOfJustInsertedApo
->SetFmtAttr(aSur
);
2364 if (bSetMinHeight
== true)
2366 // minimize Fontsize to minimize height growth of the header/footer
2367 // set font size to 1 point to minimize y-growth of Hd/Ft
2368 SvxFontHeightItem
aSz(20, 100, RES_CHRATR_FONTSIZE
);
2369 pIo
->NewAttr( aSz
);
2370 pIo
->pCtrlStck
->SetAttr(*pPoint
, RES_CHRATR_FONTSIZE
);
2374 pIo
->AppendTxtNode(*pPoint
);
2376 pTmpPos
= new SwPosition( *pIo
->pPaM
->GetPoint() );
2378 // The table is small: The number of columns is the lowest count of
2379 // columns of the origin, because inserting is faster than deleting.
2380 // The number of rows is the count of bands because (identically)
2381 // rows of a band can be duplicated easy.
2382 pTable
= pIo
->rDoc
.InsertTable(
2383 SwInsertTableOptions( tabopts::HEADLINE_NO_BORDER
, 0 ),
2384 *pTmpPos
, nBands
, nDefaultSwCols
, eOri
, 0, 0, sal_False
, sal_True
);
2386 OSL_ENSURE(pTable
&& pTable
->GetFrmFmt(), "insert table failed");
2387 if (!pTable
|| !pTable
->GetFrmFmt())
2390 SwTableNode
* pTableNode
= pTable
->GetTableNode();
2391 OSL_ENSURE(pTableNode
, "no table node!");
2394 pIo
->maSectionManager
.PrependedInlineNode(*pIo
->pPaM
->GetPoint(),
2398 // Check if the node into which the table should be inserted already
2399 // contains a Pagedesc. If so that Pagedesc would be moved to the
2400 // row after the table, whats wrong. So delete and
2401 // set later to the table format.
2402 if (SwTxtNode
*const pNd
= pTmpPos
->nNode
.GetNode().GetTxtNode())
2404 if (const SfxItemSet
* pSet
= pNd
->GetpSwAttrSet())
2406 SfxPoolItem
*pSetAttr
= 0;
2407 const SfxPoolItem
* pItem
;
2408 if (SFX_ITEM_SET
== pSet
->GetItemState(RES_BREAK
, false, &pItem
))
2410 pSetAttr
= new SvxFmtBreakItem( *(SvxFmtBreakItem
*)pItem
);
2411 pNd
->ResetAttr( RES_BREAK
);
2414 // eventually set the PageDesc/Break now to the table
2417 aItemSet
.Put(*pSetAttr
);
2423 // total width of table
2424 if( nMaxRight
- nMinLeft
> MINLAY
* nDefaultSwCols
)
2426 pTable
->GetFrmFmt()->SetFmtAttr(SwFmtFrmSize(ATT_FIX_SIZE
, nSwWidth
));
2427 aItemSet
.Put(SwFmtFrmSize(ATT_FIX_SIZE
, nSwWidth
));
2430 SvxFrameDirectionItem
aDirection(
2431 bIsBiDi
? FRMDIR_HORI_RIGHT_TOP
: FRMDIR_HORI_LEFT_TOP
, RES_FRAMEDIR
);
2432 pTable
->GetFrmFmt()->SetFmtAttr(aDirection
);
2434 if (text::HoriOrientation::LEFT_AND_WIDTH
== eOri
)
2436 if (!pIo
->nInTable
&& pIo
->InLocalApo() && pIo
->pSFlyPara
->pFlyFmt
&&
2439 //If we are inside a frame and we have a border, the frames
2440 //placement does not consider the tables border, which word
2441 //displays outside the frame, so adjust here.
2442 SwFmtHoriOrient
aHori(pIo
->pSFlyPara
->pFlyFmt
->GetHoriOrient());
2443 sal_Int16 eHori
= aHori
.GetHoriOrient();
2444 if ((eHori
== text::HoriOrientation::NONE
) || (eHori
== text::HoriOrientation::LEFT
) ||
2445 (eHori
== text::HoriOrientation::LEFT_AND_WIDTH
))
2447 //With multiple table, use last table settings. Perhaps
2448 //the maximum is what word does ?
2449 aHori
.SetPos(pIo
->pSFlyPara
->nXPos
+ GetMinLeft());
2450 aHori
.SetHoriOrient(text::HoriOrientation::NONE
);
2451 pIo
->pSFlyPara
->pFlyFmt
->SetFmtAttr(aHori
);
2456 //If bApo is set, then this table is being placed in a floating
2457 //frame, and the frame matches the left and right *lines* of the
2458 //table, so the space to the left of the table isn't to be used
2459 //inside the frame, in word the dialog involved greys out the
2460 //ability to set the margin.
2461 SvxLRSpaceItem
aL( RES_LR_SPACE
);
2462 // set right to original DxaLeft (i28656)
2466 nLeft
= GetMinLeft();
2469 if (nPreferredWidth
)
2471 nLeft
= pIo
->maSectionManager
.GetTextAreaWidth();
2472 nLeft
= nLeft
- nPreferredWidth
- nOrgDxaLeft
;
2475 nLeft
= -GetMinLeft();
2484 mpOldRedlineStack
= pIo
->mpRedlineStack
;
2485 pIo
->mpRedlineStack
= new sw::util::RedlineStack(pIo
->rDoc
);
2488 void WW8TabDesc::UseSwTable()
2491 pTabLines
= &pTable
->GetTabLines();
2492 nAktRow
= nAktCol
= nAktBandRow
= 0;
2494 pTblNd
= (SwTableNode
*)(*pTabLines
)[0]->GetTabBoxes()[0]->
2495 GetSttNd()->FindTableNode();
2496 OSL_ENSURE( pTblNd
, "wo ist mein TabellenNode" );
2498 // #i69519# - Restrict rows to repeat to a decent value
2499 if ( nRowsToRepeat
== static_cast<sal_uInt16
>(nRows
) )
2502 pTblNd
->GetTable().SetRowsToRepeat( nRowsToRepeat
);
2503 // insert extra cells if needed and something like this
2506 WW8DupProperties
aDup(pIo
->rDoc
,pIo
->pCtrlStck
);
2507 pIo
->pCtrlStck
->SetAttr(*pIo
->pPaM
->GetPoint(), 0, false);
2509 // now set the correct PaM and prepare first merger group if any
2510 SetPamInCell(nAktCol
, true);
2511 aDup
.Insert(*pIo
->pPaM
->GetPoint());
2513 pIo
->bWasTabRowEnd
= false;
2514 pIo
->bWasTabCellEnd
= false;
2517 void WW8TabDesc::MergeCells()
2521 for (pActBand
=pFirstBand
, nRow
=0; pActBand
; pActBand
=pActBand
->pNextBand
)
2523 // insert current box into merge group if appropriate
2524 if( pActBand
->pTCs
)
2526 for( short j
= 0; j
< pActBand
->nRows
; j
++, nRow
++ )
2527 for( short i
= 0; i
< pActBand
->nWwCols
; i
++ )
2529 WW8SelBoxInfo
* pActMGroup
= 0;
2531 // start a new merge group if appropriate
2533 OSL_ENSURE(nRow
< (sal_uInt16
)pTabLines
->size(),
2534 "Too few lines, table ended early");
2535 if (nRow
>= (sal_uInt16
)pTabLines
->size())
2537 pTabLine
= (*pTabLines
)[ nRow
];
2538 pTabBoxes
= &pTabLine
->GetTabBoxes();
2540 sal_uInt16 nCol
= pActBand
->nTransCell
[ i
];
2541 if (!pActBand
->bExist
[i
])
2543 OSL_ENSURE(nCol
< pTabBoxes
->size(),
2544 "Too few columns, table ended early");
2545 if (nCol
>= pTabBoxes
->size())
2547 pTabBox
= (*pTabBoxes
)[nCol
];
2548 WW8_TCell
& rCell
= pActBand
->pTCs
[ i
];
2549 // is this the left upper cell of a merge group ?
2551 bool bMerge
= false;
2552 if ( rCell
.bVertRestart
&& !rCell
.bMerged
)
2554 else if (rCell
.bFirstMerged
&& pActBand
->bExist
[i
])
2556 // Some tests to avoid merging cells which previously were
2557 // declared invalid because of sharing the exact same dimensions
2558 // as their previous cell
2560 //If theres anything underneath/above we're ok.
2561 if (rCell
.bVertMerge
|| rCell
.bVertRestart
)
2565 //If its a hori merge only, and the only things in
2566 //it are invalid cells then its already taken care
2567 //of, so don't merge.
2568 for (sal_uInt16 i2
= i
+1; i2
< pActBand
->nWwCols
; i2
++ )
2569 if (pActBand
->pTCs
[ i2
].bMerged
&&
2570 !pActBand
->pTCs
[ i2
].bFirstMerged
)
2572 if (pActBand
->bExist
[i2
])
2586 short nX1
= pActBand
->nCenter
[ i
];
2587 short nWidth
= pActBand
->nWidth
[ i
];
2589 // 2. create current merge group
2590 pActMGroup
= new WW8SelBoxInfo( nX1
, nWidth
);
2592 // determine size of new merge group
2593 // before inserted the new merge group.
2594 // Needed to correctly locked previously created merge groups.
2595 // Calculate total width and set
2596 short nSizCell
= pActBand
->nWidth
[ i
];
2597 for (sal_uInt16 i2
= i
+1; i2
< pActBand
->nWwCols
; i2
++ )
2598 if (pActBand
->pTCs
[ i2
].bMerged
&&
2599 !pActBand
->pTCs
[ i2
].bFirstMerged
)
2601 nSizCell
= nSizCell
+ pActBand
->nWidth
[ i2
];
2605 pActMGroup
->nGroupWidth
= nSizCell
;
2607 // locked previously created merge groups,
2608 // after determining the size for the new merge group.
2609 // 1. If necessary close old merge group(s) that overlap
2610 // the X-area of the new group
2613 WW8SelBoxInfo
* p
= FindMergeGroup(
2614 nX1
, pActMGroup
->nGroupWidth
, false );
2619 p
->bGroupLocked
= true;
2622 // 3. push to group array
2623 aMergeGroups
.push_back(pActMGroup
);
2626 // if necessary add the current box to a merge group
2627 // (that can be a newly created or another group)
2628 UpdateTableMergeGroup( rCell
, pActMGroup
, pTabBox
, i
);
2634 //There is a limbo area in word at the end of the row marker
2635 //where properties can live in word, there is no location in
2636 //writer equivalent, so try and park the cursor in the best
2637 //match, see #i23022#/#i18644#
2638 void WW8TabDesc::ParkPaM()
2640 SwTableBox
*pTabBox2
= 0;
2641 short nRow
= nAktRow
+ 1;
2642 if (nRow
< (sal_uInt16
)pTabLines
->size())
2644 if (SwTableLine
*pLine
= (*pTabLines
)[nRow
])
2646 SwTableBoxes
&rBoxes
= pLine
->GetTabBoxes();
2647 pTabBox2
= rBoxes
.empty() ? 0 : rBoxes
.front();
2651 if (!pTabBox2
|| !pTabBox2
->GetSttNd())
2657 if (pIo
->pPaM
->GetPoint()->nNode
!= pTabBox2
->GetSttIdx() + 1)
2659 pIo
->pPaM
->GetPoint()->nNode
= pTabBox2
->GetSttIdx() + 1;
2660 pIo
->pPaM
->GetPoint()->nContent
.Assign(pIo
->pPaM
->GetCntntNode(), 0);
2661 pIo
->rDoc
.SetTxtFmtColl(*pIo
->pPaM
, (SwTxtFmtColl
*)pIo
->pDfltTxtFmtColl
);
2665 void WW8TabDesc::MoveOutsideTable()
2667 OSL_ENSURE(pTmpPos
&& pIo
, "I've forgotten where the table is anchored");
2669 *pIo
->pPaM
->GetPoint() = *pTmpPos
;
2672 void WW8TabDesc::FinishSwTable()
2674 pIo
->mpRedlineStack
->closeall(*pIo
->pPaM
->GetPoint());
2675 delete pIo
->mpRedlineStack
;
2676 pIo
->mpRedlineStack
= mpOldRedlineStack
;
2677 mpOldRedlineStack
= 0;
2679 WW8DupProperties
aDup(pIo
->rDoc
,pIo
->pCtrlStck
);
2680 pIo
->pCtrlStck
->SetAttr( *pIo
->pPaM
->GetPoint(), 0, false);
2683 delete pTmpPos
, pTmpPos
= 0;
2685 aDup
.Insert(*pIo
->pPaM
->GetPoint());
2687 pIo
->bWasTabRowEnd
= false;
2688 pIo
->bWasTabCellEnd
= false;
2690 pIo
->maInsertedTables
.InsertTable(*pTblNd
, *pIo
->pPaM
);
2694 // if needed group cells together that should be merged
2695 if( !aMergeGroups
.empty() )
2697 // process all merge groups one by one
2699 WW8MergeGroups::iterator groupIt
= aMergeGroups
.begin();
2700 groupIt
!= aMergeGroups
.end();
2703 sal_uInt16 nActBoxCount
= groupIt
->size();
2705 if( ( 1 < nActBoxCount
) && (*groupIt
)[0] )
2707 const sal_uInt16 nRowSpan
= groupIt
->size();
2708 for (sal_uInt16 n
= 0; n
< nRowSpan
; ++n
)
2710 SwTableBox
* pCurrentBox
= (*groupIt
)[n
];
2711 const long nRowSpanSet
= n
== 0 ?
2713 ((-1) * (nRowSpan
- n
));
2714 pCurrentBox
->setRowSpan( nRowSpanSet
);
2718 pIo
->pFmtOfJustInsertedApo
= 0;
2719 aMergeGroups
.clear();
2724 // browse aMergeGroups, detect the index of the first fitting group or -1 otherwise
2726 // Parameter: nXcenter = center position of asking box
2727 // nWidth = width of asking box
2728 // bExact = flag, if box has to fit into group
2729 // or only has to touch
2731 WW8SelBoxInfo
* WW8TabDesc::FindMergeGroup(short nX1
, short nWidth
, bool bExact
)
2733 if( !aMergeGroups
.empty() )
2735 // still valid area near the boundery
2736 const short nToleranz
= 4;
2738 short nX2
= nX1
+ nWidth
;
2739 // approximate group boundery
2743 // improvement: search backwards
2744 for ( short iGr
= aMergeGroups
.size() - 1; iGr
>= 0; --iGr
)
2746 // the currently inspected group
2747 WW8SelBoxInfo
& rActGroup
= aMergeGroups
[ iGr
];
2748 if (!rActGroup
.bGroupLocked
)
2750 // approximate group boundery with room (tolerance) to the *outside*
2751 nGrX1
= rActGroup
.nGroupXStart
- nToleranz
;
2752 nGrX2
= rActGroup
.nGroupXStart
2753 +rActGroup
.nGroupWidth
+ nToleranz
;
2755 // If box fits report success
2757 if( ( nX1
> nGrX1
) && ( nX2
< nGrX2
) )
2762 // does the box share areas with the group?
2766 // successful if nX1 *or* nX2 are inside the group
2767 if( ( ( nX1
> nGrX1
)
2768 && ( nX1
< nGrX2
- 2*nToleranz
) )
2769 || ( ( nX2
> nGrX1
+ 2*nToleranz
)
2770 && ( nX2
< nGrX2
) )
2771 // or nX1 and nX2 surround the group
2772 || ( ( nX1
<=nGrX1
)
2773 && ( nX2
>=nGrX2
) ) )
2784 bool WW8TabDesc::IsValidCell(short nCol
) const
2786 return (static_cast<size_t>(nCol
) < SAL_N_ELEMENTS(pActBand
->bExist
)) &&
2787 pActBand
->bExist
[nCol
] &&
2788 (sal_uInt16
)nAktRow
< pTabLines
->size();
2791 bool WW8TabDesc::InFirstParaInCell() const
2794 if (!pTabBox
|| !pTabBox
->GetSttNd())
2796 OSL_FAIL("Problem with table");
2800 if (!IsValidCell(GetAktCol()))
2803 if (pIo
->pPaM
->GetPoint()->nNode
== pTabBox
->GetSttIdx() + 1)
2809 void WW8TabDesc::StartMiserableHackForUnsupportedDirection(short nWwCol
)
2811 OSL_ENSURE(pActBand
, "Impossible");
2812 if (pActBand
&& pActBand
->maDirections
[nWwCol
] == 3)
2814 pIo
->pCtrlStck
->NewAttr(*pIo
->pPaM
->GetPoint(),
2815 SvxCharRotateItem(900, false, RES_CHRATR_ROTATE
));
2819 void WW8TabDesc::EndMiserableHackForUnsupportedDirection(short nWwCol
)
2821 OSL_ENSURE(pActBand
, "Impossible");
2822 if (pActBand
&& pActBand
->maDirections
[nWwCol
] == 3)
2823 pIo
->pCtrlStck
->SetAttr(*pIo
->pPaM
->GetPoint(), RES_CHRATR_ROTATE
);
2826 bool WW8TabDesc::SetPamInCell(short nWwCol
, bool bPam
)
2828 OSL_ENSURE( pActBand
, "pActBand ist 0" );
2830 sal_uInt16 nCol
= pActBand
->transCell(nWwCol
);
2832 if ((sal_uInt16
)nAktRow
>= pTabLines
->size())
2834 OSL_ENSURE(!this, "Actual row bigger than expected." );
2840 pTabLine
= (*pTabLines
)[nAktRow
];
2841 pTabBoxes
= &pTabLine
->GetTabBoxes();
2843 if (nCol
>= pTabBoxes
->size())
2847 // The first paragraph in a cell with upper autospacing has upper
2850 pIo
->bParaAutoBefore
&& pIo
->bFirstPara
&&
2851 !pIo
->pWDop
->fDontUseHTMLAutoSpacing
2854 pIo
->SetUpperSpacing(*pIo
->pPaM
, 0);
2857 // The last paragraph in a cell with lower autospacing has lower
2859 if (pIo
->bParaAutoAfter
&& !pIo
->pWDop
->fDontUseHTMLAutoSpacing
)
2860 pIo
->SetLowerSpacing(*pIo
->pPaM
, 0);
2866 pTabBox
= (*pTabBoxes
)[nCol
];
2867 if( !pTabBox
->GetSttNd() )
2869 OSL_ENSURE(pTabBox
->GetSttNd(), "Probleme beim Aufbau der Tabelle");
2876 pAktWWCell
= &pActBand
->pTCs
[ nWwCol
];
2878 // The first paragraph in a cell with upper autospacing has upper spacing set to 0
2879 if(pIo
->bParaAutoBefore
&& pIo
->bFirstPara
&& !pIo
->pWDop
->fDontUseHTMLAutoSpacing
)
2880 pIo
->SetUpperSpacing(*pIo
->pPaM
, 0);
2882 // The last paragraph in a cell with lower autospacing has lower spacing set to 0
2883 if(pIo
->bParaAutoAfter
&& !pIo
->pWDop
->fDontUseHTMLAutoSpacing
)
2884 pIo
->SetLowerSpacing(*pIo
->pPaM
, 0);
2886 //We need to set the pPaM on the first cell, invalid
2887 //or not so that we can collect paragraph proproties over
2888 //all the cells, but in that case on the valid cell we do not
2889 //want to reset the fmt properties
2890 if (pIo
->pPaM
->GetPoint()->nNode
!= pTabBox
->GetSttIdx() + 1)
2892 pIo
->pPaM
->GetPoint()->nNode
= pTabBox
->GetSttIdx() + 1;
2893 pIo
->pPaM
->GetPoint()->nContent
.Assign(pIo
->pPaM
->GetCntntNode(), 0);
2894 // Precautionally set now, otherwise the style is not set for cells
2895 // that are inserted for margin balancing.
2896 pIo
->rDoc
.SetTxtFmtColl(*pIo
->pPaM
, (SwTxtFmtColl
*)pIo
->pDfltTxtFmtColl
);
2897 // because this cells are invisible helper constructions only to simulate
2898 // the frayed view of WW-tables we do NOT need SetTxtFmtCollAndListLevel()
2901 // Better to turn Snap to Grid off for all paragraphs in tables
2902 if(SwTxtNode
*pNd
= pIo
->pPaM
->GetNode()->GetTxtNode())
2904 const SfxPoolItem
&rItm
= pNd
->SwCntntNode::GetAttr(RES_PARATR_SNAPTOGRID
);
2905 SvxParaGridItem
&rSnapToGrid
= (SvxParaGridItem
&)(rItm
);
2907 if(rSnapToGrid
.GetValue())
2909 SvxParaGridItem
aGridItem( rSnapToGrid
);
2910 aGridItem
.SetValue(false);
2912 SwPosition
* pGridPos
= pIo
->pPaM
->GetPoint();
2914 xub_StrLen nEnd
= pGridPos
->nContent
.GetIndex();
2915 pGridPos
->nContent
.Assign(pIo
->pPaM
->GetCntntNode(), 0);
2916 pIo
->pCtrlStck
->NewAttr(*pGridPos
, aGridItem
);
2917 pGridPos
->nContent
.Assign(pIo
->pPaM
->GetCntntNode(), nEnd
);
2918 pIo
->pCtrlStck
->SetAttr(*pGridPos
, RES_PARATR_SNAPTOGRID
);
2922 StartMiserableHackForUnsupportedDirection(nWwCol
);
2927 void WW8TabDesc::InsertCells( short nIns
)
2929 pTabLine
= (*pTabLines
)[nAktRow
];
2930 pTabBoxes
= &pTabLine
->GetTabBoxes();
2931 pTabBox
= (*pTabBoxes
)[0];
2933 pIo
->rDoc
.GetNodes().InsBoxen( pTblNd
, pTabLine
, (SwTableBoxFmt
*)pTabBox
->GetFrmFmt(),
2934 (SwTxtFmtColl
*)pIo
->pDfltTxtFmtColl
, 0, pTabBoxes
->size(), nIns
);
2935 // The third parameter contains the FrmFmt of the boxes.
2936 // Here it is possible to optimize to save (reduce) FrmFmts.
2939 void WW8TabDesc::SetTabBorders(SwTableBox
* pBox
, short nWwIdx
)
2941 if( nWwIdx
< 0 || nWwIdx
>= pActBand
->nWwCols
)
2942 return; // faked cells -> no border
2945 SvxBoxItem
aFmtBox( RES_BOX
);
2946 if (pActBand
->pTCs
) // neither Cell Border nor Default Border defined ?
2948 WW8_TCell
* pT
= &pActBand
->pTCs
[nWwIdx
];
2949 if (pIo
->IsBorder(pT
->rgbrc
))
2950 pIo
->SetBorder(aFmtBox
, pT
->rgbrc
);
2953 if (pActBand
->nOverrideSpacing
[nWwIdx
] & (1 << WW8TabBandDesc::wwTOP
))
2955 aFmtBox
.SetDistance(
2956 pActBand
->nOverrideValues
[nWwIdx
][WW8TabBandDesc::wwTOP
],
2960 aFmtBox
.SetDistance(pActBand
->mnDefaultTop
, BOX_LINE_TOP
);
2961 if (pActBand
->nOverrideSpacing
[nWwIdx
] & (1 << WW8TabBandDesc::wwBOTTOM
))
2963 aFmtBox
.SetDistance(
2964 pActBand
->nOverrideValues
[nWwIdx
][WW8TabBandDesc::wwBOTTOM
],
2968 aFmtBox
.SetDistance(pActBand
->mnDefaultBottom
,BOX_LINE_BOTTOM
);
2970 // nGapHalf for WW is a *horizontal* gap between table cell and content.
2972 pActBand
->mbHasSpacing
? pActBand
->mnDefaultLeft
: pActBand
->nGapHalf
;
2974 pActBand
->mbHasSpacing
? pActBand
->mnDefaultRight
: pActBand
->nGapHalf
;
2975 if (pActBand
->nOverrideSpacing
[nWwIdx
] & (1 << WW8TabBandDesc::wwLEFT
))
2977 aFmtBox
.SetDistance(
2978 pActBand
->nOverrideValues
[nWwIdx
][WW8TabBandDesc::wwLEFT
],
2982 aFmtBox
.SetDistance(nLeftDist
, BOX_LINE_LEFT
);
2983 if (pActBand
->nOverrideSpacing
[nWwIdx
] & (1 << WW8TabBandDesc::wwRIGHT
))
2985 aFmtBox
.SetDistance(
2986 pActBand
->nOverrideValues
[nWwIdx
][WW8TabBandDesc::wwRIGHT
],
2990 aFmtBox
.SetDistance(nRightDist
,BOX_LINE_RIGHT
);
2992 pBox
->GetFrmFmt()->SetFmtAttr(aFmtBox
);
2995 void WW8TabDesc::SetTabShades( SwTableBox
* pBox
, short nWwIdx
)
2997 if( nWwIdx
< 0 || nWwIdx
>= pActBand
->nWwCols
)
2998 return; // faked cells -> no color
3001 if (pActBand
->pNewSHDs
&& pActBand
->pNewSHDs
[nWwIdx
] != COL_AUTO
)
3003 Color
aColor(pActBand
->pNewSHDs
[nWwIdx
]);
3004 pBox
->GetFrmFmt()->SetFmtAttr(SvxBrushItem(aColor
, RES_BACKGROUND
));
3008 //If there was no new shades, or no new shade setting
3009 if (pActBand
->pSHDs
&& !bFound
)
3011 WW8_SHD
& rSHD
= pActBand
->pSHDs
[nWwIdx
];
3012 if (!rSHD
.GetValue()) // auto
3015 SwWW8Shade
aSh( pIo
->bVer67
, rSHD
);
3016 pBox
->GetFrmFmt()->SetFmtAttr(SvxBrushItem(aSh
.aColor
, RES_BACKGROUND
));
3020 SvxFrameDirection
MakeDirection(sal_uInt16 nCode
, bool bIsBiDi
)
3022 SvxFrameDirection eDir
= FRMDIR_ENVIRONMENT
;
3023 // 1: Asian layout with rotated CJK characters
3025 // 3: Western layout rotated by 90 degrees
3026 // 4: Western layout
3030 OSL_ENSURE(eDir
== 4, "unknown direction code, maybe its a bitfield");
3032 eDir
= bIsBiDi
? FRMDIR_HORI_RIGHT_TOP
: FRMDIR_HORI_LEFT_TOP
; // #i38158# - Consider RTL tables
3035 eDir
= FRMDIR_VERT_TOP_RIGHT
;
3038 eDir
= FRMDIR_VERT_TOP_RIGHT
;
3041 eDir
= bIsBiDi
? FRMDIR_HORI_RIGHT_TOP
: FRMDIR_HORI_LEFT_TOP
; // #i38158# - Consider RTL tables
3047 void WW8TabDesc::SetTabDirection(SwTableBox
* pBox
, short nWwIdx
)
3049 if (nWwIdx
< 0 || nWwIdx
>= pActBand
->nWwCols
)
3051 SvxFrameDirectionItem
aItem(MakeDirection(pActBand
->maDirections
[nWwIdx
], bIsBiDi
), RES_FRAMEDIR
);
3052 pBox
->GetFrmFmt()->SetFmtAttr(aItem
);
3055 void WW8TabDesc::SetTabVertAlign( SwTableBox
* pBox
, short nWwIdx
)
3057 if( nWwIdx
< 0 || nWwIdx
>= pActBand
->nWwCols
)
3060 sal_Int16 eVertOri
=text::VertOrientation::TOP
;
3062 if( pActBand
->pTCs
)
3064 WW8_TCell
* pT
= &pActBand
->pTCs
[nWwIdx
];
3065 switch (pT
->nVertAlign
)
3069 eVertOri
= text::VertOrientation::TOP
;
3072 eVertOri
= text::VertOrientation::CENTER
;
3075 eVertOri
= text::VertOrientation::BOTTOM
;
3080 pBox
->GetFrmFmt()->SetFmtAttr( SwFmtVertOrient(0,eVertOri
) );
3083 void WW8TabDesc::AdjustNewBand()
3085 if( pActBand
->nSwCols
> nDefaultSwCols
) // split cells
3086 InsertCells( pActBand
->nSwCols
- nDefaultSwCols
);
3088 SetPamInCell( 0, false);
3089 OSL_ENSURE( pTabBoxes
&& pTabBoxes
->size() == (sal_uInt16
)pActBand
->nSwCols
,
3090 "Falsche Spaltenzahl in Tabelle" );
3094 pTabLine
->ClaimFrmFmt(); // necessary because of cell height
3095 SwFmtFrmSize
aF( ATT_MIN_SIZE
, 0, 0 ); // default
3097 if (pActBand
->nLineHeight
== 0) // 0 = Auto
3098 aF
.SetHeightSizeType( ATT_VAR_SIZE
);
3101 if (pActBand
->nLineHeight
< 0) // positive = min, negative = exact
3103 aF
.SetHeightSizeType(ATT_FIX_SIZE
);
3104 pActBand
->nLineHeight
= -pActBand
->nLineHeight
;
3106 if (pActBand
->nLineHeight
< MINLAY
) // invalid cell height
3107 pActBand
->nLineHeight
= MINLAY
;
3109 aF
.SetHeight(pActBand
->nLineHeight
);// set min/exact height
3111 pTabLine
->GetFrmFmt()->SetFmtAttr(aF
);
3114 //Word stores 1 for bCantSplit if the row cannot be split, we set true if
3115 //we can split the row
3116 // bCantSplit: Always true for rows containing merged cells (Word <= 2000 crashes otherwise)
3117 // So in case bCantSplit is true, we check for bCantSplit90, which has been introduced for
3118 // Word versions >= 2002.
3119 bool bSetCantSplit
= pActBand
->bCantSplit
;
3121 bSetCantSplit
= pActBand
->bCantSplit90
;
3123 pTabLine
->GetFrmFmt()->SetFmtAttr(SwFmtRowSplit(!bSetCantSplit
));
3125 short i
; // SW-Index
3126 short j
; // WW-Index
3128 SwFmtFrmSize
aFS( ATT_FIX_SIZE
);
3129 j
= pActBand
->bLEmptyCol
? -1 : 0;
3131 for( i
= 0; i
< pActBand
->nSwCols
; i
++ )
3135 nW
= pActBand
->nCenter
[0] - nMinLeft
;
3138 //Set j to first non invalid cell
3139 while ((j
< pActBand
->nWwCols
) && (!pActBand
->bExist
[j
]))
3142 if( j
< pActBand
->nWwCols
)
3143 nW
= pActBand
->nCenter
[j
+1] - pActBand
->nCenter
[j
];
3145 nW
= nMaxRight
- pActBand
->nCenter
[j
];
3146 pActBand
->nWidth
[ j
] = nW
;
3149 SwTableBox
* pBox
= (*pTabBoxes
)[i
];
3150 // could be reduced further by intelligent moving of FrmFmts
3151 pBox
->ClaimFrmFmt();
3153 SetTabBorders(pBox
, j
);
3155 // #i18128# word has only one line between adjoining vertical cells
3156 // we have to mimick this in the filter by picking the larger of the
3157 // sides and using that one on one side of the line (right)
3158 SvxBoxItem
aCurrentBox(sw::util::ItemGet
<SvxBoxItem
>(*(pBox
->GetFrmFmt()), RES_BOX
));
3159 const ::editeng::SvxBorderLine
*pLeftLine
= aCurrentBox
.GetLine(BOX_LINE_LEFT
);
3160 int nCurrentRightLineWidth
= 0;
3162 nCurrentRightLineWidth
= pLeftLine
->GetScaledWidth();
3166 SwTableBox
* pBox2
= (*pTabBoxes
)[i
-1];
3167 SvxBoxItem
aOldBox(sw::util::ItemGet
<SvxBoxItem
>(*(pBox2
->GetFrmFmt()), RES_BOX
));
3168 const ::editeng::SvxBorderLine
*pRightLine
= aOldBox
.GetLine(BOX_LINE_RIGHT
);
3169 int nOldBoxRightLineWidth
= 0;
3171 nOldBoxRightLineWidth
= pRightLine
->GetScaledWidth();
3173 if(nOldBoxRightLineWidth
>nCurrentRightLineWidth
)
3174 aCurrentBox
.SetLine(aOldBox
.GetLine(BOX_LINE_RIGHT
), BOX_LINE_LEFT
);
3176 aOldBox
.SetLine(0, BOX_LINE_RIGHT
);
3177 pBox2
->GetFrmFmt()->SetFmtAttr(aOldBox
);
3180 pBox
->GetFrmFmt()->SetFmtAttr(aCurrentBox
);
3182 SetTabVertAlign(pBox
, j
);
3183 SetTabDirection(pBox
, j
);
3184 if( pActBand
->pSHDs
|| pActBand
->pNewSHDs
)
3185 SetTabShades(pBox
, j
);
3189 pBox
->GetFrmFmt()->SetFmtAttr( aFS
);
3191 // skip non existing cells
3192 while( ( j
< pActBand
->nWwCols
) && !pActBand
->bExist
[j
] )
3194 pActBand
->nWidth
[j
] = pActBand
->nCenter
[j
+1] - pActBand
->nCenter
[j
];
3200 void WW8TabDesc::TableCellEnd()
3202 ::SetProgressState(pIo
->nProgress
, pIo
->mpDocShell
); // Update
3204 EndMiserableHackForUnsupportedDirection(nAktCol
);
3207 if( pIo
->bWasTabRowEnd
)
3209 // bWasTabRowEnd will be deactivated in
3210 // SwWW8ImplReader::ProcessSpecial()
3212 sal_uInt16 iCol
= GetLogicalWWCol();
3213 if (iCol
< aNumRuleNames
.size())
3215 aNumRuleNames
.erase(aNumRuleNames
.begin() + iCol
,
3216 aNumRuleNames
.end());
3222 OSL_ENSURE( pActBand
, "pActBand ist 0" );
3225 if( nAktRow
>= nRows
) // nothing to at end of table
3228 bool bNewBand
= nAktBandRow
>= pActBand
->nRows
;
3230 { // new band needed ?
3231 pActBand
= pActBand
->pNextBand
;
3233 OSL_ENSURE( pActBand
, "pActBand ist 0" );
3238 SwTableBox
* pBox
= (*pTabBoxes
)[0];
3240 pIo
->rDoc
.InsertRow( pTable
->SelLineFromBox( pBox
, aBoxes
) );
3245 { // new column ( cell )
3248 SetPamInCell(nAktCol
, true);
3250 // finish Annotated Level Numbering ?
3251 if (pIo
->bAnl
&& !pIo
->bAktAND_fNumberAcross
)
3252 pIo
->StopAllAnl(IsValidCell(nAktCol
));
3255 // if necessary register the box for the merge group for this column
3256 SwTableBox
* WW8TabDesc::UpdateTableMergeGroup( WW8_TCell
& rCell
,
3257 WW8SelBoxInfo
* pActGroup
,
3258 SwTableBox
* pActBox
,
3261 // set default for return
3262 SwTableBox
* pResult
= 0;
3264 // check if the box has to be merged
3265 // If cell is the first one to be merged, a new merge group has to be provided.
3266 // E.g., it could be that a cell is the first one to be merged, but no
3267 // new merge group is provided, because the potential other cell to be merged
3268 // doesn't exist - see method <WW8TabDesc::MergeCells>.
3269 if ( pActBand
->bExist
[ nCol
] &&
3270 ( ( rCell
.bFirstMerged
&& pActGroup
) ||
3273 rCell
.bVertRestart
) )
3275 // detect appropriate merge group
3276 WW8SelBoxInfo
* pTheMergeGroup
= 0;
3279 pTheMergeGroup
= pActGroup
;
3283 pTheMergeGroup
= FindMergeGroup(
3284 pActBand
->nCenter
[ nCol
], pActBand
->nWidth
[ nCol
], true );
3286 if( pTheMergeGroup
)
3288 // add current box to merge group
3289 pTheMergeGroup
->push_back(pActBox
);
3290 // return target box
3291 pResult
= (*pTheMergeGroup
)[ 0 ];
3298 sal_uInt16
WW8TabDesc::GetLogicalWWCol() const // returns number of col as INDICATED within WW6 UI status line -1
3300 sal_uInt16 nCol
= 0;
3301 if( pActBand
&& pActBand
->pTCs
)
3303 for( sal_uInt16 iCol
= 1; iCol
<= nAktCol
&& iCol
<= pActBand
->nWwCols
; ++iCol
)
3305 if( !pActBand
->pTCs
[ iCol
-1 ].bMerged
)
3312 // find name of numrule valid for current WW-COL
3313 const String
& WW8TabDesc::GetNumRuleName() const
3315 sal_uInt16 nCol
= GetLogicalWWCol();
3316 if (nCol
< aNumRuleNames
.size())
3317 return aNumRuleNames
[nCol
];
3322 void WW8TabDesc::SetNumRuleName( const String
& rName
)
3324 sal_uInt16 nCol
= GetLogicalWWCol();
3325 for (sal_uInt16 nSize
= static_cast< sal_uInt16
>(aNumRuleNames
.size()); nSize
<= nCol
; ++nSize
)
3326 aNumRuleNames
.push_back(aEmptyStr
);
3327 aNumRuleNames
[nCol
] = rName
;
3330 bool SwWW8ImplReader::StartTable(WW8_CP nStartCp
)
3332 // Entering a table so make sure the FirstPara flag gets set
3334 // keine rekursiven Tabellen Nicht bei EinfuegenDatei in Tabelle oder
3340 maTableStack
.push(pTableDesc
);
3342 // #i33818# - determine absolute position object attributes,
3343 // if possible. It's needed for nested tables.
3344 WW8FlyPara
* pTableWFlyPara( 0L );
3345 WW8SwFlyPara
* pTableSFlyPara( 0L );
3346 // #i45301# - anchor nested table inside Writer fly frame
3347 // only at-character, if absolute position object attributes are available.
3348 // Thus, default anchor type is as-character anchored.
3349 RndStdIds
eAnchor( FLY_AS_CHAR
);
3352 WW8_TablePos
* pNestedTabPos( 0L );
3353 WW8_TablePos aNestedTabPos
;
3354 WW8PLCFxSave1 aSave
;
3355 pPlcxMan
->GetPap()->Save( aSave
);
3356 WW8PLCFx_Cp_FKP
* pPap
= pPlcxMan
->GetPapPLCF();
3357 WW8_CP nMyStartCp
= nStartCp
;
3358 if ( SearchRowEnd( pPap
, nMyStartCp
, nInTable
) &&
3359 ParseTabPos( &aNestedTabPos
, pPap
) )
3361 pNestedTabPos
= &aNestedTabPos
;
3363 pPlcxMan
->GetPap()->Restore( aSave
);
3364 if ( pNestedTabPos
)
3366 ApoTestResults aApo
= TestApo( nInTable
+ 1, false, pNestedTabPos
);
3367 pTableWFlyPara
= ConstructApo( aApo
, pNestedTabPos
);
3368 if ( pTableWFlyPara
)
3370 // <WW8SwFlyPara> constructor has changed - new 4th parameter
3371 // containing WW8 page top margin.
3372 pTableSFlyPara
= new WW8SwFlyPara(*pPaM
, *this, *pTableWFlyPara
,
3373 maSectionManager
.GetWWPageTopMargin(),
3374 maSectionManager
.GetPageLeft(), maSectionManager
.GetTextAreaWidth(),
3375 nIniFlyDx
, nIniFlyDy
);
3377 // #i45301# - anchor nested table Writer fly frame at-character
3378 eAnchor
= FLY_AT_CHAR
;
3383 pTableDesc
= new WW8TabDesc( this, nStartCp
);
3385 if( pTableDesc
->Ok() )
3387 int nNewInTable
= nInTable
+ 1;
3388 if (InEqualApo(nNewInTable
))
3390 OSL_ENSURE(pSFlyPara
->pFlyFmt
,
3391 "how could we be in a local apo and have no apo");
3394 if ((eAnchor
== FLY_AT_CHAR
)
3395 && !maTableStack
.empty() && !InEqualApo(nNewInTable
) )
3397 pTableDesc
->pParentPos
= new SwPosition(*pPaM
->GetPoint());
3398 SfxItemSet
aItemSet(rDoc
.GetAttrPool(),
3399 RES_FRMATR_BEGIN
, RES_FRMATR_END
-1);
3400 // #i33818# - anchor the Writer fly frame for the nested table at-character.
3402 SwFmtAnchor
aAnchor( eAnchor
);
3403 aAnchor
.SetAnchor( pTableDesc
->pParentPos
);
3404 aItemSet
.Put( aAnchor
);
3405 pTableDesc
->pFlyFmt
= rDoc
.MakeFlySection( eAnchor
,
3406 pTableDesc
->pParentPos
, &aItemSet
);
3407 OSL_ENSURE( pTableDesc
->pFlyFmt
->GetAnchor().GetAnchorId() == eAnchor
,
3408 "Not the anchor type requested!" );
3409 MoveInsideFly(pTableDesc
->pFlyFmt
);
3411 pTableDesc
->CreateSwTable();
3412 if (pTableDesc
->pFlyFmt
)
3414 pTableDesc
->SetSizePosition(pTableDesc
->pFlyFmt
);
3415 // #i33818# - Use absolute position object attributes,
3416 // if existing, and apply them to the created Writer fly frame.
3417 if ( pTableWFlyPara
&& pTableSFlyPara
)
3419 WW8FlySet
aFlySet( *this, pTableWFlyPara
, pTableSFlyPara
, false );
3420 SwFmtAnchor
aAnchor( FLY_AT_CHAR
);
3421 aAnchor
.SetAnchor( pTableDesc
->pParentPos
);
3422 aFlySet
.Put( aAnchor
);
3423 pTableDesc
->pFlyFmt
->SetFmtAttr( aFlySet
);
3427 SwFmtHoriOrient aHori
=
3428 pTableDesc
->pTable
->GetFrmFmt()->GetHoriOrient();
3429 pTableDesc
->pFlyFmt
->SetFmtAttr(aHori
);
3430 pTableDesc
->pFlyFmt
->SetFmtAttr( SwFmtSurround( SURROUND_NONE
) );
3432 // #i33818# - The nested table doesn't have to leave
3433 // the table cell. Thus, the Writer fly frame has to follow the text flow.
3434 pTableDesc
->pFlyFmt
->SetFmtAttr( SwFmtFollowTextFlow( sal_True
) );
3437 pTableDesc
->SetSizePosition(0);
3438 pTableDesc
->UseSwTable();
3444 delete pTableWFlyPara
;
3445 delete pTableSFlyPara
;
3447 return 0 != pTableDesc
;
3450 void SwWW8ImplReader::TabCellEnd()
3452 if (nInTable
&& pTableDesc
)
3453 pTableDesc
->TableCellEnd();
3455 bFirstPara
= true; // We have come to the end of a cell so FirstPara flag
3457 mpTableEndPaM
.reset();
3460 void SwWW8ImplReader::Read_TabCellEnd( sal_uInt16
, const sal_uInt8
* pData
, short nLen
)
3462 if( ( nLen
> 0 ) && ( *pData
== 1 ) )
3463 bWasTabCellEnd
= true;
3466 void SwWW8ImplReader::Read_TabRowEnd( sal_uInt16
, const sal_uInt8
* pData
, short nLen
) // Sprm25
3468 if( ( nLen
> 0 ) && ( *pData
== 1 ) )
3469 bWasTabRowEnd
= true;
3472 void SwWW8ImplReader::PopTableDesc()
3474 if (pTableDesc
&& pTableDesc
->pFlyFmt
)
3476 MoveOutsideFly(pTableDesc
->pFlyFmt
,*pTableDesc
->pParentPos
);
3480 if (maTableStack
.empty())
3484 pTableDesc
= maTableStack
.top();
3489 void SwWW8ImplReader::StopTable()
3491 OSL_ENSURE(pTableDesc
, "Panic, stop table with no table!");
3495 // We are leaving a table so make sure the next paragraph doesn't think
3496 // it's the first paragraph
3499 pTableDesc
->FinishSwTable();
3503 // #i101116# - Keep PaM on table end only for nested tables
3506 mpTableEndPaM
.reset(new SwPaM(*pPaM
));
3510 // GetTableLeft() is needed for graphic objects bound to paragraphs in tables.
3511 // For indented tables the base for WW is the margin that would be used without
3512 // the table; SW uses the left table margin.
3513 short SwWW8ImplReader::GetTableLeft()
3515 return (pTableDesc
) ? pTableDesc
->GetMinLeft() : 0;
3518 bool SwWW8ImplReader::IsInvalidOrToBeMergedTabCell() const
3523 const WW8_TCell
* pCell
= pTableDesc
->GetAktWWCell();
3525 return !pTableDesc
->IsValidCell( pTableDesc
->GetAktCol() )
3527 && ( !pCell
->bFirstMerged
3529 || ( pCell
->bVertMerge
3530 && !pCell
->bVertRestart
3537 sal_uInt16
SwWW8ImplReader::StyleUsingLFO( sal_uInt16 nLFOIndex
) const
3539 sal_uInt16 nRes
= USHRT_MAX
;
3540 if( !vColl
.empty() )
3542 for(sal_uInt16 nI
= 0; nI
< pStyles
->GetCount(); nI
++ )
3543 if( vColl
[ nI
].bValid
3544 && (nLFOIndex
== vColl
[ nI
].nLFOIndex
) )
3550 const SwFmt
* SwWW8ImplReader::GetStyleWithOrgWWName( String
& rName
) const
3553 if( !vColl
.empty() )
3555 for(sal_uInt16 nI
= 0; nI
< pStyles
->GetCount(); nI
++ )
3556 if( vColl
[ nI
].bValid
3557 && (rName
.Equals( vColl
[ nI
].GetOrgWWName())) )
3559 pRet
= vColl
[ nI
].pFmt
;
3566 //-----------------------------------------
3568 //-----------------------------------------
3570 const sal_uInt8
* WW8RStyle::HasParaSprm( sal_uInt16 nId
) const
3572 if( !pParaSprms
|| !nSprmsLen
)
3575 return maSprmParser
.findSprmData(nId
, pParaSprms
, nSprmsLen
);
3578 void WW8RStyle::ImportSprms(sal_uInt8
*pSprms
, short nLen
, bool bPap
)
3585 pParaSprms
= pSprms
; // for HasParaSprms()
3589 WW8SprmIter
aSprmIter(pSprms
, nLen
, maSprmParser
);
3590 while (const sal_uInt8
* pSprm
= aSprmIter
.GetSprms())
3592 pIo
->ImportSprm(pSprm
);
3593 aSprmIter
.advance();
3600 void WW8RStyle::ImportSprms(sal_Size nPosFc
, short nLen
, bool bPap
)
3605 if (checkSeek(*pStStrm
, nPosFc
))
3607 sal_uInt8
*pSprms
= new sal_uInt8
[nLen
];
3608 nLen
= pStStrm
->Read(pSprms
, nLen
);
3609 ImportSprms(pSprms
, nLen
, bPap
);
3614 static inline short WW8SkipOdd(SvStream
* pSt
)
3616 if ( pSt
->Tell() & 0x1 )
3619 return pSt
->Read( &c
, 1 );
3624 static inline short WW8SkipEven(SvStream
* pSt
)
3626 if (!(pSt
->Tell() & 0x1))
3629 return pSt
->Read( &c
, 1 );
3634 short WW8RStyle::ImportUPX(short nLen
, bool bPAP
, bool bOdd
)
3636 if( 0 < nLen
) // Empty ?
3639 nLen
= nLen
- WW8SkipEven( pStStrm
);
3641 nLen
= nLen
- WW8SkipOdd( pStStrm
);
3649 cbUPX
= nLen
; // shrink cbUPX to nLen
3651 if( (1 < cbUPX
) || ( (0 < cbUPX
) && !bPAP
) )
3664 sal_Size nPos
= pStStrm
->Tell(); // if something is interpreted wrong,
3665 // this should make it work again
3666 ImportSprms( nPos
, cbUPX
, bPAP
);
3668 if ( pStStrm
->Tell() != nPos
+ cbUPX
)
3669 pStStrm
->Seek( nPos
+cbUPX
);
3671 nLen
= nLen
- cbUPX
;
3678 void WW8RStyle::ImportGrupx(short nLen
, bool bPara
, bool bOdd
)
3683 nLen
= nLen
- WW8SkipEven( pStStrm
);
3685 nLen
= nLen
- WW8SkipOdd( pStStrm
);
3687 if( bPara
) // Grupx.Papx
3688 nLen
= ImportUPX(nLen
, true, bOdd
);
3689 ImportUPX(nLen
, false, bOdd
); // Grupx.Chpx
3692 WW8RStyle::WW8RStyle(WW8Fib
& _rFib
, SwWW8ImplReader
* pI
)
3693 : WW8Style(*pI
->pTableStream
, _rFib
), maSprmParser(_rFib
.GetFIBVersion()),
3694 pIo(pI
), pStStrm(pI
->pTableStream
), pStyRule(0), nWwNumLevel(0)
3696 pIo
->vColl
.resize(cstd
);
3699 void WW8RStyle::Set1StyleDefaults()
3701 // see #i25247#, #i25561#, #i48064#, #i92341# for default font
3702 if (!bCJKFontChanged
) // Style no CJK Font? set the default
3703 pIo
->SetNewFontAttr(ftcFE
, true, RES_CHRATR_CJK_FONT
);
3705 if (!bCTLFontChanged
) // Style no CTL Font? set the default
3706 pIo
->SetNewFontAttr(ftcBi
, true, RES_CHRATR_CTL_FONT
);
3708 // western 2nd to make western charset conversion the default
3709 if (!bFontChanged
) // Style has no Font? set the default,
3710 pIo
->SetNewFontAttr(ftcAsci
, true, RES_CHRATR_FONT
);
3712 if( !pIo
->bNoAttrImport
)
3714 // Style has no text color set, winword default is auto
3715 if ( !bTxtColChanged
)
3716 pIo
->pAktColl
->SetFmtAttr(SvxColorItem(Color(COL_AUTO
), RES_CHRATR_COLOR
));
3718 // Style has no FontSize ? WinWord Default is 10pt for western and asian
3719 if( !bFSizeChanged
)
3721 SvxFontHeightItem
aAttr(200, 100, RES_CHRATR_FONTSIZE
);
3722 pIo
->pAktColl
->SetFmtAttr(aAttr
);
3723 aAttr
.SetWhich(RES_CHRATR_CJK_FONTSIZE
);
3724 pIo
->pAktColl
->SetFmtAttr(aAttr
);
3727 // Style has no FontSize ? WinWord Default is 10pt for western and asian
3728 if( !bFCTLSizeChanged
)
3730 SvxFontHeightItem
aAttr(200, 100, RES_CHRATR_FONTSIZE
);
3731 aAttr
.SetWhich(RES_CHRATR_CTL_FONTSIZE
);
3732 pIo
->pAktColl
->SetFmtAttr(aAttr
);
3735 if( pIo
->pWDop
->fWidowControl
&& !bWidowsChanged
) // Widows ?
3737 pIo
->pAktColl
->SetFmtAttr( SvxWidowsItem( 2, RES_PARATR_WIDOWS
) );
3738 pIo
->pAktColl
->SetFmtAttr( SvxOrphansItem( 2, RES_PARATR_ORPHANS
) );
3743 bool WW8RStyle::PrepareStyle(SwWW8StyInf
&rSI
, ww::sti eSti
, sal_uInt16 nThisStyle
, sal_uInt16 nNextStyle
)
3751 sw::util::ParaStyleMapper::StyleResult aResult
=
3752 pIo
->maParaStyleMapper
.GetStyle(rSI
.GetOrgWWName(), eSti
);
3753 pColl
= aResult
.first
;
3754 bStyExist
= aResult
.second
;
3759 sw::util::CharStyleMapper::StyleResult aResult
=
3760 pIo
->maCharStyleMapper
.GetStyle(rSI
.GetOrgWWName(), eSti
);
3761 pColl
= aResult
.first
;
3762 bStyExist
= aResult
.second
;
3765 bool bImport
= !bStyExist
|| pIo
->mbNewDoc
; // import content ?
3767 // Do not override character styles the list import code created earlier.
3768 if (bImport
&& bStyExist
&& rSI
.GetOrgWWName().SearchAscii("WW8Num") == 0)
3771 bool bOldNoImp
= pIo
->bNoAttrImport
;
3772 rSI
.bImportSkipped
= !bImport
;
3775 pIo
->bNoAttrImport
= true;
3780 pColl
->ResetAllFmtAttr(); // #i73790# - method renamed
3782 pColl
->SetAuto(false); // suggested by JP
3783 } // but changes the UI
3784 pIo
->pAktColl
= pColl
;
3785 rSI
.pFmt
= pColl
; // remember translation WW->SW
3786 rSI
.bImportSkipped
= !bImport
;
3788 // Set Based on style
3789 sal_uInt16 j
= rSI
.nBase
;
3790 if (j
!= nThisStyle
&& j
< cstd
)
3792 SwWW8StyInf
* pj
= &pIo
->vColl
[j
];
3793 if (rSI
.pFmt
&& pj
->pFmt
&& rSI
.bColl
== pj
->bColl
)
3795 rSI
.pFmt
->SetDerivedFrom( pj
->pFmt
); // ok, set Based on
3796 rSI
.eLTRFontSrcCharSet
= pj
->eLTRFontSrcCharSet
;
3797 rSI
.eRTLFontSrcCharSet
= pj
->eRTLFontSrcCharSet
;
3798 rSI
.eCJKFontSrcCharSet
= pj
->eCJKFontSrcCharSet
;
3799 rSI
.n81Flags
= pj
->n81Flags
;
3800 rSI
.n81BiDiFlags
= pj
->n81BiDiFlags
;
3801 rSI
.nOutlineLevel
= pj
->nOutlineLevel
;
3802 rSI
.bParaAutoBefore
= pj
->bParaAutoBefore
;
3803 rSI
.bParaAutoAfter
= pj
->bParaAutoAfter
;
3806 rSI
.pWWFly
= new WW8FlyPara(pIo
->bVer67
, pj
->pWWFly
);
3809 else if( pIo
->mbNewDoc
&& bStyExist
)
3810 rSI
.pFmt
->SetDerivedFrom(0);
3812 rSI
.nFollow
= nNextStyle
; // remember Follow
3814 pStyRule
= 0; // recreate if necessary
3815 bTxtColChanged
= bFontChanged
= bCJKFontChanged
= bCTLFontChanged
=
3816 bFSizeChanged
= bFCTLSizeChanged
= bWidowsChanged
= false;
3817 pIo
->SetNAktColl( nThisStyle
);
3818 pIo
->bStyNormal
= nThisStyle
== 0;
3822 void WW8RStyle::PostStyle(SwWW8StyInf
&rSI
, bool bOldNoImp
)
3824 // Reset attribute flags, because there are no style-ends.
3826 pIo
->bHasBorder
= pIo
->bShdTxtCol
= pIo
->bCharShdTxtCol
3827 = pIo
->bSpec
= pIo
->bObj
= pIo
->bSymbol
= false;
3830 // If Style basiert auf Nichts oder Basis ignoriert
3831 if ((rSI
.nBase
>= cstd
|| pIo
->vColl
[rSI
.nBase
].bImportSkipped
) && rSI
.bColl
)
3833 // If Char-Styles does not work
3834 // -> set hard WW-Defaults
3835 Set1StyleDefaults();
3838 pStyRule
= 0; // to be on the safe side
3839 pIo
->bStyNormal
= false;
3840 pIo
->SetNAktColl( 0 );
3841 pIo
->bNoAttrImport
= bOldNoImp
;
3842 // reset the list-remember-fields, if used when reading styles
3843 pIo
->nLFOPosition
= USHRT_MAX
;
3844 pIo
->nListLevel
= WW8ListManager::nMaxLevel
;
3847 void WW8RStyle::Import1Style( sal_uInt16 nNr
)
3849 if (nNr
>= pIo
->vColl
.size())
3852 SwWW8StyInf
&rSI
= pIo
->vColl
[nNr
];
3854 if( rSI
.bImported
|| !rSI
.bValid
)
3857 rSI
.bImported
= true; // set flag now to avoid endless loops
3859 // valid and not NUL and not yet imported
3861 if( rSI
.nBase
< cstd
&& !pIo
->vColl
[rSI
.nBase
].bImported
)
3862 Import1Style( rSI
.nBase
);
3864 pStStrm
->Seek( rSI
.nFilePos
);
3869 boost::scoped_ptr
<WW8_STD
> xStd(Read1Style(nSkip
, &sName
, &cbStd
));// read Style
3872 rSI
.SetOrgWWIdent( sName
, xStd
->sti
);
3874 // either no Name or unused Slot or unknown Style
3876 if ( !xStd
|| (0 == sName
.Len()) || ((1 != xStd
->sgc
) && (2 != xStd
->sgc
)) )
3878 pStStrm
->SeekRel( nSkip
);
3882 bool bOldNoImp
= PrepareStyle(rSI
, static_cast<ww::sti
>(xStd
->sti
), nNr
, xStd
->istdNext
);
3884 // if something is interpreted wrong, this should make it work again
3885 long nPos
= pStStrm
->Tell();
3887 //Variable parts of the STD start at even byte offsets, but "inside
3888 //the STD", which I take to meaning even in relation to the starting
3889 //position of the STD, which matches findings in #89439#, generally it
3890 //doesn't matter as the STSHI starts off nearly always on an even
3893 //Import of the Style Contents
3894 ImportGrupx(nSkip
, xStd
->sgc
== 1, rSI
.nFilePos
& 1);
3896 PostStyle(rSI
, bOldNoImp
);
3898 pStStrm
->Seek( nPos
+nSkip
);
3901 void WW8RStyle::RecursiveReg(sal_uInt16 nNr
)
3903 if (nNr
>= pIo
->vColl
.size())
3906 SwWW8StyInf
&rSI
= pIo
->vColl
[nNr
];
3907 if( rSI
.bImported
|| !rSI
.bValid
)
3910 rSI
.bImported
= true;
3912 if( rSI
.nBase
< cstd
&& !pIo
->vColl
[rSI
.nBase
].bImported
)
3913 RecursiveReg(rSI
.nBase
);
3915 pIo
->RegisterNumFmtOnStyle(nNr
);
3920 After all styles are imported then we can recursively apply numbering
3921 styles to them, and change their tab stop settings if they turned out
3922 to have special first line indentation.
3924 void WW8RStyle::PostProcessStyles()
3928 Clear all imported flags so that we can recursively apply numbering
3929 formats and use it to mark handled ones
3931 for (i
=0; i
< cstd
; ++i
)
3932 pIo
->vColl
[i
].bImported
= false;
3935 Register the num formats and tabstop changes on the styles recursively.
3939 In the same loop apply the tabstop changes required because we need to
3940 change their location if theres a special indentation for the first line,
3941 By avoiding making use of each styles margins during reading of their
3942 tabstops we don't get problems with doubly adjusting tabstops that
3945 for (i
=0; i
< cstd
; ++i
)
3947 if (pIo
->vColl
[i
].bValid
)
3954 void WW8RStyle::ScanStyles() // investigate style dependencies
3955 { // and detect Filepos for each Style
3956 for (sal_uInt16 i
= 0; i
< cstd
; ++i
)
3959 SwWW8StyInf
&rSI
= pIo
->vColl
[i
];
3961 rSI
.nFilePos
= pStStrm
->Tell(); // remember FilePos
3962 WW8_STD
* pStd
= Read1Style( nSkip
, 0, 0 ); // read STD
3963 rSI
.bValid
= (0 != pStd
);
3966 rSI
.nBase
= pStd
->istdBase
; // remember Basis
3967 rSI
.bColl
= ( pStd
->sgc
== 1 ); // Para-Style
3970 rSI
= SwWW8StyInf();
3973 pStStrm
->SeekRel( nSkip
); // skip Names and Sprms
3977 std::vector
<sal_uInt8
> ChpxToSprms(const Word2CHPX
&rChpx
)
3979 std::vector
<sal_uInt8
> aRet
;
3982 aRet
.push_back( static_cast< sal_uInt8
>(128 + rChpx
.fBold
) );
3985 aRet
.push_back( static_cast< sal_uInt8
>(128 + rChpx
.fItalic
) );
3988 aRet
.push_back( static_cast< sal_uInt8
>(128 + rChpx
.fStrike
) );
3991 aRet
.push_back( static_cast< sal_uInt8
>(128 + rChpx
.fOutline
) );
3994 aRet
.push_back( static_cast< sal_uInt8
>(128 + rChpx
.fSmallCaps
) );
3997 aRet
.push_back( static_cast< sal_uInt8
>(128 + rChpx
.fCaps
) );
4000 aRet
.push_back( static_cast< sal_uInt8
>(128 + rChpx
.fVanish
) );
4006 ShortToSVBT16(rChpx
.ftc
, a
);
4007 aRet
.push_back(a
[1]);
4008 aRet
.push_back(a
[0]);
4014 aRet
.push_back(rChpx
.kul
);
4021 ShortToSVBT16(rChpx
.lid
, a
);
4022 aRet
.push_back(a
[1]);
4023 aRet
.push_back(a
[0]);
4029 aRet
.push_back(rChpx
.ico
);
4037 ShortToSVBT16(rChpx
.hps
, a
);
4038 aRet
.push_back(a
[0]);
4044 aRet
.push_back(rChpx
.hpsPos
);
4048 aRet
.push_back( static_cast< sal_uInt8
>(128 + rChpx
.fBoldBi
) );
4051 aRet
.push_back( static_cast< sal_uInt8
>(128 + rChpx
.fItalicBi
) );
4057 ShortToSVBT16(rChpx
.fsFtcBi
, a
);
4058 aRet
.push_back(a
[1]);
4059 aRet
.push_back(a
[0]);
4066 ShortToSVBT16(rChpx
.lidBi
, a
);
4067 aRet
.push_back(a
[1]);
4068 aRet
.push_back(a
[0]);
4074 aRet
.push_back(rChpx
.icoBi
);
4081 ShortToSVBT16(rChpx
.hpsBi
, a
);
4082 aRet
.push_back(a
[1]);
4083 aRet
.push_back(a
[0]);
4089 Word2CHPX
ReadWord2Chpx(SvStream
&rSt
, sal_Size nOffset
, sal_uInt8 nSize
)
4106 aChpx
.fBold
= nFlags8
& 0x01;
4107 aChpx
.fItalic
= (nFlags8
& 0x02) >> 1;
4108 aChpx
.fRMarkDel
= (nFlags8
& 0x04) >> 2;
4109 aChpx
.fOutline
= (nFlags8
& 0x08) >> 3;
4110 aChpx
.fFldVanish
= (nFlags8
& 0x10) >> 4;
4111 aChpx
.fSmallCaps
= (nFlags8
& 0x20) >> 5;
4112 aChpx
.fCaps
= (nFlags8
& 0x40) >> 6;
4113 aChpx
.fVanish
= (nFlags8
& 0x80) >> 7;
4115 if (nCount
>= nSize
) break;
4119 aChpx
.fRMark
= nFlags8
& 0x01;
4120 aChpx
.fSpec
= (nFlags8
& 0x02) >> 1;
4121 aChpx
.fStrike
= (nFlags8
& 0x04) >> 2;
4122 aChpx
.fObj
= (nFlags8
& 0x08) >> 3;
4123 aChpx
.fBoldBi
= (nFlags8
& 0x10) >> 4;
4124 aChpx
.fItalicBi
= (nFlags8
& 0x20) >> 5;
4125 aChpx
.fBiDi
= (nFlags8
& 0x40) >> 6;
4126 aChpx
.fDiacUSico
= (nFlags8
& 0x80) >> 7;
4128 if (nCount
>= nSize
) break;
4132 aChpx
.fsIco
= nFlags8
& 0x01;
4133 aChpx
.fsFtc
= (nFlags8
& 0x02) >> 1;
4134 aChpx
.fsHps
= (nFlags8
& 0x04) >> 2;
4135 aChpx
.fsKul
= (nFlags8
& 0x08) >> 3;
4136 aChpx
.fsPos
= (nFlags8
& 0x10) >> 4;
4137 aChpx
.fsSpace
= (nFlags8
& 0x20) >> 5;
4138 aChpx
.fsLid
= (nFlags8
& 0x40) >> 6;
4139 aChpx
.fsIcoBi
= (nFlags8
& 0x80) >> 7;
4141 if (nCount
>= nSize
) break;
4145 aChpx
.fsFtcBi
= nFlags8
& 0x01;
4146 aChpx
.fsHpsBi
= (nFlags8
& 0x02) >> 1;
4147 aChpx
.fsLidBi
= (nFlags8
& 0x04) >> 2;
4149 if (nCount
>= nSize
) break;
4153 if (nCount
>= nSize
) break;
4157 if (nCount
>= nSize
) break;
4161 aChpx
.qpsSpace
= nFlags8
& 0x3F;
4162 aChpx
.fSysVanish
= (nFlags8
& 0x40) >> 6;
4163 aChpx
.fNumRun
= (nFlags8
& 0x80) >> 7;
4165 if (nCount
>= nSize
) break;
4169 aChpx
.ico
= nFlags8
& 0x1F;
4170 aChpx
.kul
= (nFlags8
& 0xE0) >> 5;
4172 if (nCount
>= nSize
) break;
4173 rSt
>> aChpx
.hpsPos
;
4176 if (nCount
>= nSize
) break;
4180 if (nCount
>= nSize
) break;
4184 if (nCount
>= nSize
) break;
4188 if (nCount
>= nSize
) break;
4192 if (nCount
>= nSize
) break;
4196 if (nCount
>= nSize
) break;
4203 rSt
.SeekRel(nSize
-nCount
);
4209 struct pxoffset
{ sal_Size mnOffset
; sal_uInt8 mnSize
; };
4212 void WW8RStyle::ImportOldFormatStyles()
4214 for (sal_uInt16 i
=0; i
< cstd
; ++i
)
4216 pIo
->vColl
[i
].bColl
= true;
4217 //every chain must end eventually at the null style (style code 222)
4218 pIo
->vColl
[i
].nBase
= 222;
4221 rtl_TextEncoding eStructChrSet
= WW8Fib::GetFIBCharset(
4222 pIo
->pWwFib
->chseTables
);
4229 sal_uInt16 nByteCount
= 2;
4231 while (nByteCount
< cbName
)
4237 sal_uInt8 stc
= static_cast< sal_uInt8
>((stcp
- cstcStd
) & 255);
4238 if (stc
>=pIo
->vColl
.size())
4241 SwWW8StyInf
&rSI
= pIo
->vColl
[stc
];
4242 if (nCount
!= 0xFF) // undefined style
4245 if (nCount
== 0) // inbuilt style
4247 ww::sti eSti
= ww::GetCanonicalStiFromStc(stc
);
4248 if (const sal_Char
*pStr
= GetEnglishNameFromSti(eSti
))
4249 sName
= String(pStr
, RTL_TEXTENCODING_ASCII_US
);
4251 sName
= OUString("Unknown");
4255 OString aTmp
= read_uInt8s_ToOString(rSt
, nCount
);
4256 nByteCount
+= aTmp
.getLength();
4257 sName
= OStringToOUString(aTmp
, eStructChrSet
);
4259 rSI
.SetOrgWWIdent(sName
, stc
);
4260 rSI
.bImported
= true;
4264 ww::sti eSti
= ww::GetCanonicalStiFromStc(stc
);
4265 if (const sal_Char
*pStr
= GetEnglishNameFromSti(eSti
))
4267 String sName
= String(pStr
, RTL_TEXTENCODING_ASCII_US
);
4268 rSI
.SetOrgWWIdent(sName
, stc
);
4274 sal_uInt16 nStyles
=stcp
;
4276 std::vector
<pxoffset
> aCHPXOffsets(stcp
);
4281 std::vector
< std::vector
<sal_uInt8
> > aConvertedChpx
;
4282 while (nByteCount
< cbChpx
)
4288 aCHPXOffsets
[stcp
].mnSize
= 0;
4292 sal_uInt8 nRemainder
= cb
;
4294 aCHPXOffsets
[stcp
].mnOffset
= rSt
.Tell();
4295 aCHPXOffsets
[stcp
].mnSize
= nRemainder
;
4297 Word2CHPX aChpx
= ReadWord2Chpx(rSt
, aCHPXOffsets
[stcp
].mnOffset
,
4298 aCHPXOffsets
[stcp
].mnSize
);
4299 aConvertedChpx
.push_back( ChpxToSprms(aChpx
) );
4301 nByteCount
+= nRemainder
;
4304 aConvertedChpx
.push_back( std::vector
<sal_uInt8
>() );
4307 if (stcp
== nStyles
)
4309 rSt
.SeekRel(cbChpx
-nByteCount
);
4310 nByteCount
+= cbChpx
-nByteCount
;
4314 std::vector
<pxoffset
> aPAPXOffsets(stcp
);
4319 while (nByteCount
< cbPapx
)
4325 aPAPXOffsets
[stcp
].mnSize
= 0;
4333 sal_uInt8 nRemainder
= cb
-7;
4335 aPAPXOffsets
[stcp
].mnOffset
= rSt
.Tell();
4336 aPAPXOffsets
[stcp
].mnSize
= nRemainder
;
4338 rSt
.SeekRel(nRemainder
);
4339 nByteCount
+= nRemainder
;
4344 if (stcp
== nStyles
)
4346 rSt
.SeekRel(cbPapx
-nByteCount
);
4347 nByteCount
+= cbPapx
-nByteCount
;
4354 if (iMac
> nStyles
) iMac
= nStyles
;
4356 for (stcp
= 0; stcp
< iMac
; ++stcp
)
4358 sal_uInt8 stcNext
, stcBase
;
4362 sal_uInt8 stc
= static_cast< sal_uInt8
>((stcp
- cstcStd
) & 255);
4365 #i64557# style based on itself
4366 every chain must end eventually at the null style (style code 222)
4371 SwWW8StyInf
&rSI
= pIo
->vColl
[stc
];
4372 rSI
.nBase
= stcBase
;
4374 ww::sti eSti
= ww::GetCanonicalStiFromStc(stc
);
4376 if (eSti
== ww::stiNil
)
4381 if (ww::StandardStiIsCharStyle(eSti
) && !aPAPXOffsets
[stcp
].mnSize
)
4382 pIo
->vColl
[stc
].bColl
= false;
4384 bool bOldNoImp
= PrepareStyle(rSI
, eSti
, stc
, stcNext
);
4386 ImportSprms(aPAPXOffsets
[stcp
].mnOffset
, aPAPXOffsets
[stcp
].mnSize
,
4389 if (aConvertedChpx
[stcp
].size() > 0)
4390 ImportSprms(&(aConvertedChpx
[stcp
][0]),
4391 static_cast< short >(aConvertedChpx
[stcp
].size()),
4394 PostStyle(rSI
, bOldNoImp
);
4398 void WW8RStyle::ImportNewFormatStyles()
4400 ScanStyles(); // Scan Based On
4402 for (sal_uInt16 i
= 0; i
< cstd
; ++i
) // import Styles
4403 if (pIo
->vColl
[i
].bValid
)
4407 void WW8RStyle::ImportStyles()
4409 if (ww::eWW2
== pIo
->pWwFib
->GetFIBVersion())
4410 ImportOldFormatStyles();
4412 ImportNewFormatStyles();
4415 void WW8RStyle::Import()
4417 pIo
->pDfltTxtFmtColl
= pIo
->rDoc
.GetDfltTxtFmtColl();
4418 pIo
->pStandardFmtColl
=
4419 pIo
->rDoc
.GetTxtCollFromPool(RES_POOLCOLL_STANDARD
, false);
4421 if( pIo
->nIniFlags
& WW8FL_NO_STYLES
)
4426 for (sal_uInt16 i
= 0; i
< cstd
; ++i
)
4429 SwWW8StyInf
* pi
= &pIo
->vColl
[i
];
4430 sal_uInt16 j
= pi
->nFollow
;
4433 SwWW8StyInf
* pj
= &pIo
->vColl
[j
];
4434 if ( j
!= i
// rational Index ?
4435 && pi
->pFmt
// Format ok ?
4436 && pj
->pFmt
// Derived-Format ok ?
4437 && pi
->bColl
// only possible for paragraph templates (WW)
4438 && pj
->bColl
){ // identical Typ ?
4439 ( (SwTxtFmtColl
*)pi
->pFmt
)->SetNextTxtFmtColl(
4440 *(SwTxtFmtColl
*)pj
->pFmt
); // ok, register
4445 // Missing special handling for default character template
4446 // "Absatz-Standardschriftart" ( Style-ID 65 ).
4447 // That is empty by default ( WW6 dt and US ) and not changeable
4448 // via WW-UI so this does not matter.
4449 // This could be done by:
4450 // if( bNew ) rDoc.SetDefault( pDefCharFmt->GetAttrSet() );
4452 // for e.g. tables an always valid Std-Style is necessary
4454 if( pIo
->StyleExists(0) && !pIo
->vColl
.empty() &&
4455 pIo
->vColl
[0].pFmt
&& pIo
->vColl
[0].bColl
&& pIo
->vColl
[0].bValid
)
4456 pIo
->pDfltTxtFmtColl
= (SwTxtFmtColl
*)pIo
->vColl
[0].pFmt
;
4458 pIo
->pDfltTxtFmtColl
= pIo
->rDoc
.GetDfltTxtFmtColl();
4461 // set Hyphenation flag on BASIC para-style
4462 if (pIo
->mbNewDoc
&& pIo
->pStandardFmtColl
)
4464 if (pIo
->pWDop
->fAutoHyphen
4465 && SFX_ITEM_SET
!= pIo
->pStandardFmtColl
->GetItemState(
4466 RES_PARATR_HYPHENZONE
, false) )
4468 SvxHyphenZoneItem
aAttr(true, RES_PARATR_HYPHENZONE
);
4469 aAttr
.GetMinLead() = 2;
4470 aAttr
.GetMinTrail() = 2;
4471 aAttr
.GetMaxHyphens() = 0;
4473 pIo
->pStandardFmtColl
->SetFmtAttr( aAttr
);
4477 Word defaults to ltr not from environment like writer. Regardless of
4478 the page/sections rtl setting the standard style lack of rtl still
4481 if (SFX_ITEM_SET
!= pIo
->pStandardFmtColl
->GetItemState(RES_FRAMEDIR
,
4484 pIo
->pStandardFmtColl
->SetFmtAttr(
4485 SvxFrameDirectionItem(FRMDIR_HORI_LEFT_TOP
, RES_FRAMEDIR
));
4489 // we do not read styles anymore:
4493 CharSet
SwWW8StyInf::GetCharSet() const
4495 if ((pFmt
) && (pFmt
->GetFrmDir().GetValue() == FRMDIR_HORI_RIGHT_TOP
))
4496 return eRTLFontSrcCharSet
;
4497 return eLTRFontSrcCharSet
;
4500 CharSet
SwWW8StyInf::GetCJKCharSet() const
4502 if ((pFmt
) && (pFmt
->GetFrmDir().GetValue() == FRMDIR_HORI_RIGHT_TOP
))
4503 return eRTLFontSrcCharSet
;
4504 return eCJKFontSrcCharSet
;
4507 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */