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