1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
32 #include <tools/solar.h>
33 #include <vcl/vclenum.hxx>
34 #include <vcl/font.hxx>
35 #include <hintids.hxx>
36 #include <editeng/colritem.hxx>
37 #include <editeng/orphitem.hxx>
38 #include <editeng/widwitem.hxx>
39 #include <editeng/brshitem.hxx>
40 #include <editeng/boxitem.hxx>
41 #include <editeng/lrspitem.hxx>
42 #include <editeng/fhgtitem.hxx>
43 #include <editeng/fhgtitem.hxx>
44 #include <editeng/hyznitem.hxx>
45 #include <editeng/frmdiritem.hxx>
46 #include <editeng/langitem.hxx>
47 #include <editeng/charrotateitem.hxx>
48 #include <editeng/pgrditem.hxx>
49 #include <msfilter.hxx>
50 #include <pam.hxx> // fuer SwPam
53 #include <ndtxt.hxx> // class SwTxtNode
54 #include <paratr.hxx> // SwNumRuleItem
55 #include <poolfmt.hxx> // RES_POOLCOLL_STANDARD
56 #include <swtable.hxx> // class SwTableLines, ...
57 #include <tblsel.hxx> // class _SwSelBox
59 #include <fmtpdsc.hxx>
64 #include <charfmt.hxx>
65 #include <SwStyleNameMapper.hxx>
66 #include <fltshell.hxx> // fuer den Attribut Stack
67 #include <fmtanchr.hxx>
68 #include <fmtrowsplt.hxx>
69 // --> OD 2005-01-27 #i33818#
70 #include <fmtfollowtextflow.hxx>
72 #include <numrule.hxx>
73 # include "../inc/wwstyles.hxx"
74 # include "writerhelper.hxx"
75 #include "ww8struc.hxx" // struct TC
77 #include "ww8par2.hxx"
83 #define MAX_COL 64 // WW6-Beschreibung: 32, WW6-UI: 31 & WW8-UI: 63!
85 using namespace ::com::sun::star
;
88 class WW8SelBoxInfo
: public SwSelBoxes_SAR
91 WW8SelBoxInfo(const WW8SelBoxInfo
&);
92 WW8SelBoxInfo
& operator=(const WW8SelBoxInfo
&);
98 WW8SelBoxInfo(short nXCenter
, short nWidth
)
99 : nGroupXStart( nXCenter
), nGroupWidth( nWidth
), bGroupLocked(false)
103 typedef WW8SelBoxInfo
* WW8SelBoxInfoPtr
;
105 SV_DECL_PTRARR_DEL(WW8MergeGroups
, WW8SelBoxInfoPtr
, 16,16)
106 SV_IMPL_PTRARR(WW8MergeGroups
, WW8SelBoxInfoPtr
)
108 struct WW8TabBandDesc
110 WW8TabBandDesc
* pNextBand
;
114 short mnDefaultRight
;
115 short mnDefaultBottom
;
119 sal_uInt16 maDirections
[MAX_COL
+ 1];
120 short nCenter
[MAX_COL
+ 1]; // X-Rand aller Zellen dieses Bandes
121 short nWidth
[MAX_COL
+ 1]; // Laenge aller Zellen dieses Bandes
122 short nWwCols
; // BYTE wuerde reichen, alignment -> short
123 short nSwCols
; // SW: so viele Spalten fuer den Writer
124 bool bLEmptyCol
; // SW: Links eine leere Zusatz-Spalte
125 bool bREmptyCol
; // SW: dito rechts
129 BYTE nOverrideSpacing
[MAX_COL
+ 1];
130 short nOverrideValues
[MAX_COL
+ 1][4];
132 sal_uInt32
* pNewSHDs
;
136 // nur fuer WW6-7: diese Zelle hat WW-Flag bMerged (horizontal) gesetzt
137 //bool bWWMergedVer6[MAX_COL];
140 bool bExist
[MAX_COL
]; // Existiert diese Zelle ?
141 UINT8 nTransCell
[MAX_COL
+ 2]; // UEbersetzung WW-Index -> SW-Index
144 WW8TabBandDesc(WW8TabBandDesc
& rBand
); // tief kopieren
146 static void setcelldefaults(WW8_TCell
*pCells
, short nCells
);
147 void ReadDef(bool bVer67
, const BYTE
* pS
);
148 void ProcessDirection(const BYTE
* pParams
);
149 void ProcessSprmTSetBRC(bool bVer67
, const BYTE
* pParamsTSetBRC
);
150 void ProcessSprmTTableBorders(bool bVer67
, const BYTE
* pParams
);
151 void ProcessSprmTDxaCol(const BYTE
* pParamsTDxaCol
);
152 void ProcessSprmTDelete(const BYTE
* pParamsTDelete
);
153 void ProcessSprmTInsert(const BYTE
* pParamsTInsert
);
154 void ProcessSpacing(const BYTE
* pParamsTInsert
);
155 void ProcessSpecificSpacing(const BYTE
* pParamsTInsert
);
156 void ReadShd(const BYTE
* pS
);
157 void ReadNewShd(const BYTE
* pS
, bool bVer67
);
159 enum wwDIR
{wwTOP
= 0, wwLEFT
= 1, wwBOTTOM
= 2, wwRIGHT
= 3};
162 WW8TabBandDesc::WW8TabBandDesc()
164 memset(this, 0, sizeof(*this));
165 for (size_t i
= 0; i
< sizeof(maDirections
)/sizeof(sal_uInt16
); ++i
)
169 WW8TabBandDesc::~WW8TabBandDesc()
178 std::vector
<String
> aNumRuleNames
;
179 sw::util::RedlineStack
*mpOldRedlineStack
;
181 SwWW8ImplReader
* pIo
;
183 WW8TabBandDesc
* pFirstBand
;
184 WW8TabBandDesc
* pActBand
;
188 SwTableNode
* pTblNd
; // Tabellen-Node
189 const SwTableLines
* pTabLines
; // Zeilen-Array davon
190 SwTableLine
* pTabLine
; // akt. Zeile
191 SwTableBoxes
* pTabBoxes
; // Boxen-Array in akt. Zeile
192 SwTableBox
* pTabBox
; // akt. Zelle
194 WW8MergeGroups
* pMergeGroups
; // Listen aller zu verknuepfenden Zellen
196 WW8_TCell
* pAktWWCell
;
199 short nDefaultSwCols
;
202 short nConvertedLeft
;
205 short nPreferredWidth
;
212 // 2. allgemeine Verwaltungsinfo
214 short nAktBandRow
; // SW: in dieser Zeile des akt. Bandes bin ich
215 // 3. Verwaltungsinfo fuer Writer
218 USHORT nRowsToRepeat
;
222 USHORT
GetLogicalWWCol() const;
223 void SetTabBorders( SwTableBox
* pBox
, short nIdx
);
224 void SetTabShades( SwTableBox
* pBox
, short nWwIdx
);
225 void SetTabVertAlign( SwTableBox
* pBox
, short nWwIdx
);
226 void SetTabDirection( SwTableBox
* pBox
, short nWwIdx
);
228 bool SetPamInCell(short nWwCol
, bool bPam
);
229 void InsertCells( short nIns
);
230 void AdjustNewBand();
232 // durchsucht pMergeGroups, meldet Index der ersten, passenden Gruppe bzw.
233 // -1 Details siehe bei der Implementierung
234 bool FindMergeGroup(short nX1
, short nWidth
, bool bExact
, short& nMGrIdx
);
236 // einzelne Box ggfs. in eine Merge-Gruppe aufnehmen
237 // (die Merge-Gruppen werden dann spaeter auf einen Schlag abgearbeitet)
238 SwTableBox
* UpdateTableMergeGroup(WW8_TCell
& rCell
,
239 WW8SelBoxInfo
* pActGroup
, SwTableBox
* pActBox
, USHORT nCol
);
240 void StartMiserableHackForUnsupportedDirection(short nWwCol
);
241 void EndMiserableHackForUnsupportedDirection(short nWwCol
);
243 WW8TabDesc(const WW8TabDesc
&);
244 WW8TabDesc
&operator=(const WW8TabDesc
&);
246 const SwTable
* pTable
; // Tabelle
247 SwPosition
* pParentPos
;
248 SwFlyFrmFmt
* pFlyFmt
;
250 bool IsValidCell(short nCol
) const;
251 bool InFirstParaInCell() const;
253 WW8TabDesc( SwWW8ImplReader
* pIoClass
, WW8_CP nStartCp
);
254 bool Ok() const { return bOk
; }
255 void CreateSwTable();
257 void SetSizePosition(SwFrmFmt
* pFrmFmt
);
259 void MoveOutsideTable();
261 void FinishSwTable();
263 short GetMinLeft() const { return nConvertedLeft
; }
265 SwPosition
*GetPos() { return pTmpPos
; }
267 const WW8_TCell
* GetAktWWCell() const { return pAktWWCell
; }
268 short GetAktCol() const { return nAktCol
; }
269 // find name of numrule valid for current WW-COL
270 const String
& GetNumRuleName() const;
271 void SetNumRuleName( const String
& rName
);
273 sw::util::RedlineStack
* getOldRedlineStack(){ return mpOldRedlineStack
; }
276 void sw::util::RedlineStack::close( const SwPosition
& rPos
,
277 RedlineType_t eType
, WW8TabDesc
* pTabDesc
)
279 // If the redline type is not found in the redline stack, we have to check if there has been
280 // a tabledesc and to check its saved redline stack, too. (#136939, #i68139)
281 if( !close( rPos
, eType
) )
283 if( pTabDesc
&& pTabDesc
->getOldRedlineStack() )
286 ASSERT( pTabDesc
->getOldRedlineStack()->close(rPos
, eType
), "close without open!");
288 pTabDesc
->getOldRedlineStack()->close( rPos
, eType
);
295 void wwSectionManager::SetCurrentSectionHasFootnote()
297 ASSERT(!maSegments
.empty(),
298 "should not be possible, must be at least one segment");
299 if (!maSegments
.empty())
300 maSegments
.back().mbHasFootnote
= true;
303 bool wwSectionManager::CurrentSectionIsVertical() const
305 ASSERT(!maSegments
.empty(),
306 "should not be possible, must be at least one segment");
307 if (!maSegments
.empty())
308 return maSegments
.back().IsVertical();
312 bool wwSectionManager::CurrentSectionIsProtected() const
314 ASSERT(!maSegments
.empty(),
315 "should not be possible, must be at least one segment");
316 if (!maSegments
.empty())
317 return SectionIsProtected(maSegments
.back());
321 sal_uInt32
wwSectionManager::GetPageLeft() const
323 return !maSegments
.empty() ? maSegments
.back().nPgLeft
: 0;
326 sal_uInt32
wwSectionManager::GetPageRight() const
328 return !maSegments
.empty() ? maSegments
.back().nPgRight
: 0;
331 sal_uInt32
wwSectionManager::GetPageWidth() const
333 return !maSegments
.empty() ? maSegments
.back().GetPageWidth() : 0;
336 sal_uInt32
wwSectionManager::GetTextAreaWidth() const
338 return !maSegments
.empty() ? maSegments
.back().GetTextAreaWidth() : 0;
341 // --> OD 2007-07-03 #148498#
342 sal_uInt32
wwSectionManager::GetWWPageTopMargin() const
344 return !maSegments
.empty() ? maSegments
.back().maSep
.dyaTop
: 0;
348 sal_uInt16
SwWW8ImplReader::End_Ftn()
352 Ignoring Footnote outside of the normal Text. People will put footnotes
353 into field results and field commands.
356 pPaM
->GetPoint()->nNode
< rDoc
.GetNodes().GetEndOfExtras().GetIndex())
361 ASSERT(!maFtnStack
.empty(), "footnote end without start");
362 if (maFtnStack
.empty())
365 bool bFtEdOk
= false;
366 const FtnDescriptor
&rDesc
= maFtnStack
.back();
368 //Get the footnote character and remove it from the txtnode. We'll
369 //replace it with the footnote
370 SwTxtNode
* pTxt
= pPaM
->GetNode()->GetTxtNode();
371 xub_StrLen nPos
= pPaM
->GetPoint()->nContent
.GetIndex();
375 //There should have been a footnote char, we will replace this.
378 sChar
.Append(pTxt
->GetTxt().GetChar(--nPos
));
380 pPaM
->GetMark()->nContent
--;
381 rDoc
.DeleteRange( *pPaM
);
383 SwFmtFtn
aFtn(rDesc
.meType
== MAN_EDN
);
384 pFN
= pTxt
->InsertItem(aFtn
, nPos
, nPos
);
386 ASSERT(pFN
, "Probleme beim Anlegen des Fussnoten-Textes");
390 SwPosition
aTmpPos( *pPaM
->GetPoint() ); // merke alte Cursorposition
391 WW8PLCFxSaveAll aSave
;
392 pPlcxMan
->SaveAllPLCFx( aSave
);
393 WW8PLCFMan
* pOldPlcxMan
= pPlcxMan
;
395 const SwNodeIndex
* pSttIdx
= ((SwTxtFtn
*)pFN
)->GetStartNode();
396 ASSERT(pSttIdx
, "Probleme beim Anlegen des Fussnoten-Textes");
398 ((SwTxtFtn
*)pFN
)->SetSeqNo( rDoc
.GetFtnIdxs().Count() );
403 // read content of Ft-/End-Note
404 Read_HdFtFtnText( pSttIdx
, rDesc
.mnStartCp
, rDesc
.mnLen
, rDesc
.meType
);
408 ASSERT(sChar
.Len()==1 && ((rDesc
.mbAutoNum
== (sChar
.GetChar(0) == 2))),
409 "footnote autonumbering must be 0x02, and everthing else must not be");
411 // If no automatic numbering use the following char from the main text
412 // as the footnote number
413 if (!rDesc
.mbAutoNum
)
414 ((SwTxtFtn
*)pFN
)->SetNumber(0, &sChar
);
417 Delete the footnote char from the footnote if its at the beginning
418 as usual. Might not be if the user has already deleted it, e.g.
421 SwNodeIndex
& rNIdx
= pPaM
->GetPoint()->nNode
;
422 rNIdx
= pSttIdx
->GetIndex() + 1;
423 SwTxtNode
* pTNd
= rNIdx
.GetNode().GetTxtNode();
424 if (pTNd
&& pTNd
->GetTxt().Len() && sChar
.Len())
426 if (pTNd
->GetTxt().GetChar(0) == sChar
.GetChar(0))
428 pPaM
->GetPoint()->nContent
.Assign( pTNd
, 0 );
430 // Strip out tabs we may have inserted on export #i24762#
431 if (pTNd
->GetTxt().GetChar(1) == 0x09)
432 pPaM
->GetMark()->nContent
++;
433 pPaM
->GetMark()->nContent
++;
434 pReffingStck
->Delete(*pPaM
);
435 rDoc
.DeleteRange( *pPaM
);
440 *pPaM
->GetPoint() = aTmpPos
; // restore Cursor
442 pPlcxMan
= pOldPlcxMan
; // Restore attributes
443 pPlcxMan
->RestoreAllPLCFx( aSave
);
447 maSectionManager
.SetCurrentSectionHasFootnote();
449 maFtnStack
.pop_back();
453 long SwWW8ImplReader::Read_Ftn(WW8PLCFManResult
* pRes
)
457 Ignoring Footnote outside of the normal Text. People will put footnotes
458 into field results and field commands.
461 pPaM
->GetPoint()->nNode
< rDoc
.GetNodes().GetEndOfExtras().GetIndex())
467 aDesc
.mbAutoNum
= true;
468 if (eEDN
== pRes
->nSprmId
)
470 aDesc
.meType
= MAN_EDN
;
471 if (pPlcxMan
->GetEdn())
472 aDesc
.mbAutoNum
= 0 != *(short*)pPlcxMan
->GetEdn()->GetData();
476 aDesc
.meType
= MAN_FTN
;
477 if (pPlcxMan
->GetFtn())
478 aDesc
.mbAutoNum
= 0 != *(short*)pPlcxMan
->GetFtn()->GetData();
481 aDesc
.mnStartCp
= pRes
->nCp2OrIdx
;
482 aDesc
.mnLen
= pRes
->nMemLen
;
484 maFtnStack
.push_back(aDesc
);
489 bool SwWW8ImplReader::SearchRowEnd(WW8PLCFx_Cp_FKP
* pPap
, WW8_CP
&rStartCp
,
494 aRes
.nEndPos
= rStartCp
;
496 while (pPap
->HasFkp() && rStartCp
!= WW8_CP_MAX
)
498 if (pPap
->Where() != WW8_CP_MAX
)
500 const BYTE
* pB
= pPap
->HasSprm(TabRowSprm(nLevel
));
503 const BYTE
*pLevel
= 0;
504 if (0 != (pLevel
= pPap
->HasSprm(0x6649)))
506 if (nLevel
+ 1 == *pLevel
)
511 ASSERT(!nLevel
|| pLevel
, "sublevel without level sprm");
512 return true; // RowEnd found
517 aRes
.nStartPos
= aRes
.nEndPos
;
519 //Seek to our next block of properties
520 if (!(pPap
->SeekPos(aRes
.nStartPos
)))
522 aRes
.nEndPos
= WW8_CP_MAX
;
523 pPap
->SetDirty(true);
525 pPap
->GetSprms(&aRes
);
526 pPap
->SetDirty(false);
527 //Update our aRes to get the new starting point of the next properties
528 rStartCp
= aRes
.nEndPos
;
534 ApoTestResults
SwWW8ImplReader::TestApo(int nCellLevel
, bool bTableRowEnd
,
535 const WW8_TablePos
*pTabPos
)
537 const WW8_TablePos
*pTopLevelTable
= nCellLevel
<= 1 ? pTabPos
: 0;
539 // Frame in Style Definition (word appears to ignore them if inside an
540 // text autoshape, e.g. #94418#)
541 if (!bTxbxFlySection
)
542 aRet
.mpStyleApo
= StyleExists(nAktColl
) ? pCollA
[nAktColl
].pWWFly
: 0;
546 If I have a table and apply a style to one of its frames that should cause
547 a paragraph that its applied to it to only exist as a seperate floating
548 frame, then the behavour depends on which cell that it has been applied
549 to. If its the first cell of a row then the whole table row jumps into the
550 new frame, if its not then then the paragraph attributes are applied
551 "except" for the floating frame stuff. i.e. its ignored. So if theres a
552 table, and we're not in the first cell then we ignore the fact that the
553 paragraph style wants to be in a different frame.
555 This sort of mindbending inconsistency is surely why frames are deprecated
556 in word 97 onwards and hidden away from the user
560 If we are already a table in a frame then we must grab the para properties
561 to see if we are still in that frame.
564 aRet
.mpSprm37
= pPlcxMan
->HasParaSprm( bVer67
? 37 : 0x2423 );
565 aRet
.mpSprm29
= pPlcxMan
->HasParaSprm( bVer67
? 29 : 0x261B );
567 // Is there some frame data here
568 bool bNowApo
= aRet
.HasFrame() || pTopLevelTable
;
571 if (WW8FlyPara
*pTest
= ConstructApo(aRet
, pTabPos
))
577 bool bTestAllowed
= !bTxbxFlySection
&& !bTableRowEnd
;
580 //Test is allowed if there is no table.
581 //Otherwise only allowed if we are in the
582 //first paragraph of the first cell of a row.
583 //(And only if the row we are inside is at the
584 //same level as the previous row, think tables
586 if (nCellLevel
== nInTable
)
595 ASSERT(pTableDesc
, "What!");
596 bTestAllowed
= false;
600 // --> OD 2005-02-01 #i39468#
601 // If current cell isn't valid, the test is allowed.
602 // The cell isn't valid, if e.g. there is a new row
603 // <pTableDesc->nAktRow> >= <pTableDesc->pTabLines->Count()>
605 pTableDesc
->GetAktCol() == 0 &&
606 ( !pTableDesc
->IsValidCell( pTableDesc
->GetAktCol() ) ||
607 pTableDesc
->InFirstParaInCell() );
617 aRet
.mbStartApo
= bNowApo
&& !InAnyApo(); // APO-start
618 aRet
.mbStopApo
= InEqualOrHigherApo(nCellLevel
) && !bNowApo
; // APO-end
620 //If it happens that we are in a table, then if its not the first cell
621 //then any attributes that might otherwise cause the contents to jump
622 //into another frame don't matter, a table row sticks together as one
623 //unit no matter what else happens. So if we are not in a table at
624 //all, or if we are in the first cell then test that the last frame
625 //data is the same as the current one
626 if (bNowApo
&& InEqualApo(nCellLevel
))
628 // two bordering eachother
629 if (!TestSameApo(aRet
, pTabPos
))
630 aRet
.mbStopApo
= aRet
.mbStartApo
= true;
635 //---------------------------------------------------------------------
636 // Hilfroutinen fuer Kapitelnummerierung und Aufzaehlung / Gliederung
637 //---------------------------------------------------------------------
639 static void SetBaseAnlv(SwNumFmt
&rNum
, WW8_ANLV
&rAV
, BYTE nSwLevel
)
641 static SvxExtNumType eNumA
[8] = { SVX_NUM_ARABIC
, SVX_NUM_ROMAN_UPPER
, SVX_NUM_ROMAN_LOWER
,
642 SVX_NUM_CHARS_UPPER_LETTER_N
, SVX_NUM_CHARS_LOWER_LETTER_N
, SVX_NUM_ARABIC
,
643 SVX_NUM_ARABIC
, SVX_NUM_ARABIC
};
645 static SvxAdjust eAdjA
[4] = { SVX_ADJUST_LEFT
,
646 SVX_ADJUST_RIGHT
, SVX_ADJUST_LEFT
, SVX_ADJUST_LEFT
};
647 // eigentlich folgende 2, aber Writer-UI bietet es nicht an
648 // SVX_ADJUST_CENTER, SVX_ADJUST_BLOCKLINE };
650 rNum
.SetNumberingType( static_cast< sal_Int16
>(( SVBT8ToByte( rAV
.nfc
) < 8 ) ?
651 eNumA
[SVBT8ToByte( rAV
.nfc
) ] : SVX_NUM_NUMBER_NONE
) );
652 if ((SVBT8ToByte(rAV
.aBits1
) & 0x4) >> 2)
653 rNum
.SetIncludeUpperLevels(nSwLevel
+ 1);
654 rNum
.SetStart( SVBT16ToShort( rAV
.iStartAt
) );
655 // rNum.eNumAdjust = eAdjA[rAV.jc];
656 rNum
.SetNumAdjust( eAdjA
[SVBT8ToByte( rAV
.aBits1
) & 0x3] );
658 rNum
.SetCharTextDistance( SVBT16ToShort( rAV
.dxaSpace
) );
659 INT16 nIndent
= Abs((INT16
)SVBT16ToShort( rAV
.dxaIndent
));
660 if( SVBT8ToByte( rAV
.aBits1
) & 0x08 ) //fHang
662 rNum
.SetFirstLineOffset( -nIndent
);
663 rNum
.SetLSpace( nIndent
);
664 rNum
.SetAbsLSpace( nIndent
);
667 rNum
.SetCharTextDistance( nIndent
); // Breite der Nummer fehlt
669 if( SVBT8ToByte( rAV
.nfc
) == 5 || SVBT8ToByte( rAV
.nfc
) == 7 )
671 String
sP( rNum
.GetSuffix() );
673 rNum
.SetSuffix( sP
); // Ordinalzahlen
677 void SwWW8ImplReader::SetAnlvStrings(SwNumFmt
&rNum
, WW8_ANLV
&rAV
,
678 const BYTE
* pTxt
, bool bOutline
)
680 bool bInsert
= false; // Default
681 CharSet eCharSet
= eStructCharSet
;
683 const WW8_FFN
* pF
= pFonts
->GetFont(SVBT16ToShort(rAV
.ftc
)); // FontInfo
684 bool bListSymbol
= pF
&& ( pF
->chs
== 2 ); // Symbol/WingDings/...
689 sTxt
= String( (sal_Char
*)pTxt
, SVBT8ToByte( rAV
.cbTextBefore
)
690 + SVBT8ToByte( rAV
.cbTextAfter
), eCharSet
);
694 for(xub_StrLen i
= SVBT8ToByte(rAV
.cbTextBefore
);
695 i
< SVBT8ToByte(rAV
.cbTextAfter
); ++i
, pTxt
+= 2)
697 sTxt
.Append(SVBT16ToShort(*(SVBT16
*)pTxt
));
703 if( !rNum
.GetIncludeUpperLevels() // es sind <= 1 Nummern anzuzeigen
704 || rNum
.GetNumberingType() == SVX_NUM_NUMBER_NONE
){ // oder dieser Level hat keine
706 bInsert
= true; // -> dann uebernehme Zeichen
708 // replace by simple Bullet ?
710 //JP 14.08.96: cBulletChar benutzen, damit auf dem MAC
711 // richtig gemappt wird
712 sTxt
.Fill( SVBT8ToByte( rAV
.cbTextBefore
)
713 + SVBT8ToByte( rAV
.cbTextAfter
), cBulletChar
);
717 { // Nummerierung / Aufzaehlung
719 // if( SVBT16ToShort( rAV.ftc ) == 1
720 // || SVBT16ToShort( rAV.ftc ) == 3 ){ // Symbol / WingDings
727 if( GetFontParams( SVBT16ToShort( rAV
.ftc
), eFamily
, aName
,
728 ePitch
, eCharSet
) ){
729 // USHORT nSiz = ( SVBT16ToShort( rAV.hps ) ) ?
730 // SVBT16ToShort( rAV.hps ) : 24; // Groesse in 1/2 Pt
731 // darf nach JP nicht gesetzt werden, da immer die Size
732 // genommen wird, die am ZeilenAnfang benutzt wird
734 aFont
.SetName( aName
);
735 aFont
.SetFamily( eFamily
);
736 // aFont.SetPitch( ePitch ); // darf nach JP nicht
737 aFont
.SetCharSet( eCharSet
);
738 rNum
.SetNumberingType(SVX_NUM_CHAR_SPECIAL
);
739 // if( rAV.ico ) // geht in UI und SWG-Writer/Reader nicht
740 // aFont.SetColor( Color( GetCol( rAV.ico ) ) );
741 rNum
.SetBulletFont( &aFont
);
743 // take only the very first character
744 if( rAV
.cbTextBefore
|| rAV
.cbTextAfter
)
745 rNum
.SetBulletChar( sTxt
.GetChar( 0 ) );
747 rNum
.SetBulletChar( 0x2190 );
753 if( rAV
.cbTextBefore
)
755 String
sP( sTxt
.Copy( 0, SVBT8ToByte( rAV
.cbTextBefore
) ) );
756 rNum
.SetPrefix( sP
);
758 if( SVBT8ToByte( rAV
.cbTextAfter
) )
760 String
sP( rNum
.GetSuffix() );
761 sP
.Insert( sTxt
.Copy( SVBT8ToByte( rAV
.cbTextBefore
),
762 SVBT8ToByte( rAV
.cbTextAfter
) ) );
763 rNum
.SetSuffix( sP
);
765 // Die Zeichen vor und hinter mehreren Ziffern koennen leider nicht uebernommen
766 // werden, da sie der Writer ganz anders behandelt und das Ergebnis i.A.
767 // schlechter als ohne waere.
771 // SetAnld bekommt einen WW-ANLD-Descriptor und einen Level und modifiziert
772 // die durch pNumR anggebeben NumRules. Wird benutzt fuer alles ausser
773 // Gliederung im Text
774 void SwWW8ImplReader::SetAnld(SwNumRule
* pNumR
, WW8_ANLD
* pAD
, BYTE nSwLevel
,
779 { // Es gibt einen Anld-Sprm
780 bAktAND_fNumberAcross
= 0 != SVBT8ToByte( pAD
->fNumberAcross
);
781 WW8_ANLV
&rAV
= pAD
->eAnlv
;
782 SetBaseAnlv(aNF
, rAV
, nSwLevel
); // Setze Basis-Format
783 SetAnlvStrings(aNF
, rAV
, pAD
->rgchAnld
, bOutLine
);// und Rest
785 pNumR
->Set(nSwLevel
, aNF
);
788 //-------------------------------------------------------
789 // Kapitelnummerierung und Kapitelbullets
790 //-------------------------------------------------------
791 // Kapitelnummerierung findet in Styledefinionen statt. Sprm 13 gibt den Level
792 // an, Sprm 12 den Inhalt
794 SwNumRule
* SwWW8ImplReader::GetStyRule()
796 if( pStyles
->pStyRule
) // Bullet-Style bereits vorhanden
797 return pStyles
->pStyRule
;
799 const String
aBaseName(CREATE_CONST_ASC( "WW8StyleNum" ));
800 const String
aName( rDoc
.GetUniqueNumRuleName( &aBaseName
, false) );
802 // --> OD 2008-06-04 #i86652#
803 // USHORT nRul = rDoc.MakeNumRule( aName );
804 USHORT nRul
= rDoc
.MakeNumRule( aName
, 0, FALSE
,
805 SvxNumberFormat::LABEL_ALIGNMENT
);
807 pStyles
->pStyRule
= rDoc
.GetNumRuleTbl()[nRul
];
808 // Auto == false-> Nummerierungsvorlage
809 pStyles
->pStyRule
->SetAutoRule(false);
811 return pStyles
->pStyRule
;
815 void SwWW8ImplReader::Read_ANLevelNo( USHORT
, const BYTE
* pData
, short nLen
)
817 nSwNumLevel
= 0xff; // Default: ungueltig
825 // nur fuer SwTxtFmtColl, nicht CharFmt
826 // WW: 0 = no Numbering
827 SwWW8StyInf
* pColl
= GetStyle(nAktColl
);
828 if (pColl
!= NULL
&& pColl
->bColl
&& *pData
)
830 // Bereich WW:1..9 -> SW:0..8 keine Aufzaehlung / Nummerierung
832 if (*pData
<= MAXLEVEL
&& *pData
<= 9)
834 nSwNumLevel
= *pData
- 1;
836 //((SwTxtFmtColl*)pAktColl)->SetOutlineLevel( nSwNumLevel ); //#outline level,zhaojianwei
837 ((SwTxtFmtColl
*)pAktColl
)->AssignToListLevelOfOutlineStyle( nSwNumLevel
); //<-end,zhaojianwei
838 // Bei WW-NoNumbering koennte auch NO_NUMBERING gesetzt
839 // werden. ( Bei normaler Nummerierung muss NO_NUM gesetzt
840 // werden: NO_NUM : Nummerierungs-Pause,
841 // NO_NUMBERING : ueberhaupt keine Nummerierung )
844 else if( *pData
== 10 || *pData
== 11 )
846 // Typ merken, der Rest geschieht bei Sprm 12
847 pStyles
->nWwNumLevel
= *pData
;
855 StartAnl(pData
); // Anfang der Gliederung / Aufzaehlung
860 void SwWW8ImplReader::Read_ANLevelDesc( USHORT
, const BYTE
* pData
, short nLen
) // Sprm 12
863 SwWW8StyInf
* pStyInf
= GetStyle(nAktColl
);
864 if( !pAktColl
|| nLen
<= 0 // nur bei Styledef
865 || (pStyInf
&& !pStyInf
->bColl
) // CharFmt -> ignorieren
866 || ( nIniFlags
& WW8FL_NO_OUTLINE
) ){
872 if( nSwNumLevel
<= MAXLEVEL
// Bereich WW:1..9 -> SW:0..8
873 && nSwNumLevel
<= 9 ){ // keine Aufzaehlung / Nummerierung
875 // Falls bereits direkt oder durch
876 // Vererbung NumruleItems gesetzt sind,
877 // dann jetzt ausschalten #56163
878 pAktColl
->SetFmtAttr( SwNumRuleItem() );
880 String
aName(CREATE_CONST_ASC( "Outline" ));
881 // --> OD 2008-02-11 #newlistlevelattrs#
882 SwNumRule
aNR( rDoc
.GetUniqueNumRuleName( &aName
),
883 SvxNumberFormat::LABEL_WIDTH_AND_POSITION
,
886 aNR
= *rDoc
.GetOutlineNumRule();
888 SetAnld(&aNR
, (WW8_ANLD
*)pData
, nSwNumLevel
, true);
890 // fehlende Level muessen nicht aufgefuellt werden
892 rDoc
.SetOutlineNumRule( aNR
);
893 }else if( pStyles
->nWwNumLevel
== 10 || pStyles
->nWwNumLevel
== 11 ){
894 SwNumRule
* pNR
= GetStyRule();
895 SetAnld(pNR
, (WW8_ANLD
*)pData
, 0, false);
896 pAktColl
->SetFmtAttr( SwNumRuleItem( pNR
->GetName() ) );
898 SwWW8StyInf
* pStyInf
= GetStyle(nAktColl
);
900 pStyInf
->bHasStyNumRule
= true;
904 //-----------------------------------------
905 // Nummerierung / Aufzaehlung
906 //-----------------------------------------
908 // SetNumOlst() traegt die Numrules fuer diese Zeile ins SwNumFmt ein
909 // ( nur fuer Gliederungen im Text; Aufzaehlungen / Nummerierungen laufen
911 // dabei wird die Info aus dem OLST geholt und nicht aus dem ANLD ( s.u. )
912 void SwWW8ImplReader::SetNumOlst(SwNumRule
* pNumR
, WW8_OLST
* pO
, BYTE nSwLevel
)
915 WW8_ANLV
&rAV
= pO
->rganlv
[nSwLevel
];
916 SetBaseAnlv(aNF
, rAV
, nSwLevel
);
917 // ... und then the Strings
920 WW8_ANLV
* pAV1
; // search String-Positions
921 for (i
= 0, pAV1
= pO
->rganlv
; i
< nSwLevel
; ++i
, ++pAV1
)
923 nTxtOfs
+= SVBT8ToByte(pAV1
->cbTextBefore
)
924 + SVBT8ToByte(pAV1
->cbTextAfter
);
929 SetAnlvStrings(aNF
, rAV
, pO
->rgch
+ nTxtOfs
, true); // und rein
930 pNumR
->Set(nSwLevel
, aNF
);
933 // der OLST kommt am Anfang jeder Section, die Gliederungen enthaelt. Die ANLDs,
934 // die an jeder Gliederungszeile haengen, enthalten nur Stuss, also werden die
935 // OLSTs waehrend der Section gemerkt, damit die Informationen beim Auftreten
936 // von Gliederungsabsaetzen zugreifbar ist.
937 void SwWW8ImplReader::Read_OLST( USHORT
, const BYTE
* pData
, short nLen
)
941 delete pNumOlst
, pNumOlst
= 0;
945 delete pNumOlst
; // nur sicherheitshalber
946 pNumOlst
= new WW8_OLST
;
947 if( nLen
< sal::static_int_cast
< sal_Int32
>(sizeof( WW8_OLST
)) ) // auffuellen, falls zu kurz
948 memset( pNumOlst
, 0, sizeof( *pNumOlst
) );
949 *pNumOlst
= *(WW8_OLST
*)pData
;
952 WW8LvlType
GetNumType(BYTE nWwLevelNo
)
954 WW8LvlType nRet
= WW8_None
;
955 if( nWwLevelNo
== 12 )
957 else if( nWwLevelNo
== 10 )
958 nRet
= WW8_Numbering
;
959 else if( nWwLevelNo
== 11 )
961 else if( nWwLevelNo
> 0 && nWwLevelNo
<= 9 )
966 SwNumRule
*ANLDRuleMap::GetNumRule(BYTE nNumType
)
968 return (WW8_Numbering
== nNumType
? mpNumberingNumRule
: mpOutlineNumRule
);
971 void ANLDRuleMap::SetNumRule(SwNumRule
*pRule
, BYTE nNumType
)
973 if (WW8_Numbering
== nNumType
)
974 mpNumberingNumRule
= pRule
;
976 mpOutlineNumRule
= pRule
;
980 // StartAnl wird am Anfang eines Zeilenbereichs gerufen,
981 // der Gliederung / Nummerierung / Aufzaehlung enthaelt
982 void SwWW8ImplReader::StartAnl(const BYTE
* pSprm13
)
984 bAktAND_fNumberAcross
= false;
986 BYTE nT
= static_cast< BYTE
>(GetNumType(*pSprm13
));
987 if (nT
== WW8_Pause
|| nT
== WW8_None
)
991 SwNumRule
*pNumRule
= maANLDRules
.GetNumRule(nWwNumType
);
993 // check for COL numbering:
994 const BYTE
* pS12
= 0;// sprmAnld
999 sNumRule
= pTableDesc
->GetNumRuleName();
1002 pNumRule
= rDoc
.FindNumRulePtr(sNumRule
);
1007 // this is ROW numbering ?
1008 pS12
= pPlcxMan
->HasParaSprm(bVer67
? 12 : 0xC63E); // sprmAnld
1009 if (pS12
&& 0 != SVBT8ToByte(((WW8_ANLD
*)pS12
)->fNumberAcross
))
1015 SwWW8StyInf
* pStyInf
= GetStyle(nAktColl
);
1016 if (!sNumRule
.Len() && pStyInf
->bHasStyNumRule
)
1018 sNumRule
= pStyInf
->pFmt
->GetNumRule().GetValue();
1019 pNumRule
= rDoc
.FindNumRulePtr(sNumRule
);
1024 if (!sNumRule
.Len())
1028 // --> OD 2008-06-04 #i86652#
1029 // pNumRule = rDoc.GetNumRuleTbl()[rDoc.MakeNumRule(sNumRule)];
1030 pNumRule
= rDoc
.GetNumRuleTbl()[
1031 rDoc
.MakeNumRule( sNumRule
, 0, FALSE
,
1032 SvxNumberFormat::LABEL_ALIGNMENT
) ];
1038 pS12
= pPlcxMan
->HasParaSprm(bVer67
? 12 : 0xC63E); // sprmAnld
1039 if (!pS12
|| !SVBT8ToByte( ((WW8_ANLD
*)pS12
)->fNumberAcross
))
1040 pTableDesc
->SetNumRuleName(pNumRule
->GetName());
1046 // NumRules ueber Stack setzen
1047 pCtrlStck
->NewAttr(*pPaM
->GetPoint(),
1048 SfxStringItem(RES_FLTR_NUMRULE
, pNumRule
->GetName()));
1050 maANLDRules
.SetNumRule(pNumRule
, nWwNumType
);
1053 // NextAnlLine() wird fuer jede Zeile einer
1054 // Gliederung / Nummerierung / Aufzaehlung einmal gerufen
1055 void SwWW8ImplReader::NextAnlLine(const BYTE
* pSprm13
)
1060 SwNumRule
*pNumRule
= maANLDRules
.GetNumRule(nWwNumType
);
1062 // pNd->UpdateNum ohne Regelwerk gibt GPF spaetestens beim Speichern als
1065 // WW:10 = Nummerierung -> SW:0 & WW:11 = Auffzaehlung -> SW:0
1066 if (*pSprm13
== 10 || *pSprm13
== 11)
1069 if (!pNumRule
->GetNumFmt(nSwNumLevel
))
1071 // noch nicht definiert
1073 const BYTE
* pS12
= pPlcxMan
->HasParaSprm(bVer67
? 12 : 0xC63E);
1074 SetAnld(pNumRule
, (WW8_ANLD
*)pS12
, nSwNumLevel
, false);
1077 else if( *pSprm13
> 0 && *pSprm13
<= MAXLEVEL
) // Bereich WW:1..9 -> SW:0..8
1079 nSwNumLevel
= *pSprm13
- 1; // Gliederung
1080 // noch nicht definiert
1081 if (!pNumRule
->GetNumFmt(nSwNumLevel
))
1083 if (pNumOlst
) // es gab ein OLST
1085 //Assure upper levels are set, #i9556#
1086 for (BYTE nI
= 0; nI
< nSwNumLevel
; ++nI
)
1088 if (!pNumRule
->GetNumFmt(nI
))
1089 SetNumOlst(pNumRule
, pNumOlst
, nI
);
1092 SetNumOlst(pNumRule
, pNumOlst
, nSwNumLevel
);
1094 else // kein Olst, nimm Anld
1097 const BYTE
* pS12
= pPlcxMan
->HasParaSprm(bVer67
? 12 : 0xC63E);
1098 SetAnld(pNumRule
, (WW8_ANLD
*)pS12
, nSwNumLevel
, false);
1103 nSwNumLevel
= 0xff; // keine Nummer
1105 SwTxtNode
* pNd
= pPaM
->GetNode()->GetTxtNode();
1106 if (nSwNumLevel
< MAXLEVEL
)
1107 pNd
->SetAttrListLevel( nSwNumLevel
);
1110 pNd
->SetAttrListLevel(0);
1111 pNd
->SetCountedInList( false );
1115 void SwWW8ImplReader::StopAllAnl(bool bGoBack
)
1117 //Of course we're not restarting, but we'll make use of our knowledge
1118 //of the implementation to do it.
1119 StopAnlToRestart(WW8_None
, bGoBack
);
1122 void SwWW8ImplReader::StopAnlToRestart(BYTE nNewType
, bool bGoBack
)
1126 SwPosition
aTmpPos(*pPaM
->GetPoint());
1127 pPaM
->Move(fnMoveBackward
, fnGoCntnt
);
1128 pCtrlStck
->SetAttr(*pPaM
->GetPoint(), RES_FLTR_NUMRULE
);
1129 *pPaM
->GetPoint() = aTmpPos
;
1132 pCtrlStck
->SetAttr(*pPaM
->GetPoint(), RES_FLTR_NUMRULE
);
1134 maANLDRules
.mpNumberingNumRule
= 0;
1137 my take on this problem is that moving either way from an outline to a
1138 numbering doesn't halt the outline, while the numbering is always halted
1140 bool bNumberingNotStopOutline
=
1141 (((nWwNumType
== WW8_Outline
) && (nNewType
== WW8_Numbering
)) ||
1142 ((nWwNumType
== WW8_Numbering
) && (nNewType
== WW8_Outline
)));
1143 if (!bNumberingNotStopOutline
)
1144 maANLDRules
.mpOutlineNumRule
= 0;
1147 nWwNumType
= WW8_None
;
1151 WW8TabBandDesc::WW8TabBandDesc( WW8TabBandDesc
& rBand
)
1156 pTCs
= new WW8_TCell
[nWwCols
];
1157 memcpy( pTCs
, rBand
.pTCs
, nWwCols
* sizeof( WW8_TCell
) );
1161 pSHDs
= new WW8_SHD
[nWwCols
];
1162 memcpy( pSHDs
, rBand
.pSHDs
, nWwCols
* sizeof( WW8_SHD
) );
1164 if( rBand
.pNewSHDs
)
1166 pNewSHDs
= new sal_uInt32
[nWwCols
];
1167 memcpy(pNewSHDs
, rBand
.pNewSHDs
, nWwCols
* sizeof(sal_uInt32
));
1169 memcpy(aDefBrcs
, rBand
.aDefBrcs
, sizeof(aDefBrcs
));
1172 // ReadDef liest die Zellenpositionen und ggfs die Umrandungen eines Bandes ein
1173 void WW8TabBandDesc::ReadDef(bool bVer67
, const BYTE
* pS
)
1178 short nLen
= (INT16
)SVBT16ToShort( pS
- 2 ); // nicht schoen
1180 BYTE nCols
= *pS
; // Anzahl der Zellen
1181 short nOldCols
= nWwCols
;
1183 if( nCols
> MAX_COL
)
1188 const BYTE
* pT
= &pS
[1];
1191 for(i
=0; i
<=nCols
; i
++, pT
+=2 )
1192 nCenter
[i
] = (INT16
)SVBT16ToShort( pT
); // X-Raender
1193 nLen
-= 2 * ( nCols
+ 1 );
1194 if( nCols
!= nOldCols
) // andere Spaltenzahl
1196 delete[] pTCs
, pTCs
= 0;
1197 delete[] pSHDs
, pSHDs
= 0;
1198 delete[] pNewSHDs
, pNewSHDs
= 0;
1201 short nFileCols
= nLen
/ ( bVer67
? 10 : 20 ); // wirklich abgespeichert
1205 // lege leere TCs an
1206 pTCs
= new WW8_TCell
[nCols
];
1207 setcelldefaults(pTCs
,nCols
);
1210 short nColsToRead
= nFileCols
;
1211 if (nColsToRead
> nCols
)
1212 nColsToRead
= nCols
;
1219 Achtung: ab Ver8 ist ein reserve-ushort je TC eingefuegt und auch
1220 der Border-Code ist doppelt so gross, daher ist hier
1221 kein simples kopieren moeglich,
1222 d.h.: pTCs[i] = *pTc; geht leider nicht.
1224 Vorteil: Arbeitstruktur ist jetzt viel bequemer zu handhaben!
1226 WW8_TCell
* pAktTC
= pTCs
;
1229 WW8_TCellVer6
* pTc
= (WW8_TCellVer6
*)pT
;
1230 for(i
=0; i
<nColsToRead
; i
++, ++pAktTC
,++pTc
)
1232 if( i
< nColsToRead
)
1234 BYTE aBits1
= SVBT8ToByte( pTc
->aBits1Ver6
);
1235 pAktTC
->bFirstMerged
= ( ( aBits1
& 0x01 ) != 0 );
1236 pAktTC
->bMerged
= ( ( aBits1
& 0x02 ) != 0 );
1237 memcpy( pAktTC
->rgbrc
[ WW8_TOP
].aBits1
,
1238 pTc
->rgbrcVer6
[ WW8_TOP
].aBits1
, sizeof( SVBT16
) );
1239 memcpy( pAktTC
->rgbrc
[ WW8_LEFT
].aBits1
,
1240 pTc
->rgbrcVer6
[ WW8_LEFT
].aBits1
, sizeof( SVBT16
) );
1241 memcpy( pAktTC
->rgbrc
[ WW8_BOT
].aBits1
,
1242 pTc
->rgbrcVer6
[ WW8_BOT
].aBits1
, sizeof( SVBT16
) );
1243 memcpy( pAktTC
->rgbrc
[ WW8_RIGHT
].aBits1
,
1244 pTc
->rgbrcVer6
[ WW8_RIGHT
].aBits1
, sizeof( SVBT16
) );
1245 if( ( pAktTC
->bMerged
)
1248 // Cell gemerged -> merken
1249 //bWWMergedVer6[i] = true;
1250 memcpy( pTCs
[i
-1].rgbrc
[ WW8_RIGHT
].aBits1
,
1251 pTc
->rgbrcVer6
[ WW8_RIGHT
].aBits1
, sizeof( SVBT16
) );
1252 // right Border in vorige Zelle uebernehmen
1253 // Hier darf bExist nicht auf false gesetzt werden, da WW
1254 // in den Textboxen diese Zellen nicht mitzaehlt....
1261 WW8_TCellVer8
* pTc
= (WW8_TCellVer8
*)pT
;
1262 for (int k
= 0; k
< nColsToRead
; ++k
, ++pAktTC
, ++pTc
)
1264 UINT16 aBits1
= SVBT16ToShort( pTc
->aBits1Ver8
);
1265 pAktTC
->bFirstMerged
= ( ( aBits1
& 0x0001 ) != 0 );
1266 pAktTC
->bMerged
= ( ( aBits1
& 0x0002 ) != 0 );
1267 pAktTC
->bVertical
= ( ( aBits1
& 0x0004 ) != 0 );
1268 pAktTC
->bBackward
= ( ( aBits1
& 0x0008 ) != 0 );
1269 pAktTC
->bRotateFont
= ( ( aBits1
& 0x0010 ) != 0 );
1270 pAktTC
->bVertMerge
= ( ( aBits1
& 0x0020 ) != 0 );
1271 pAktTC
->bVertRestart
= ( ( aBits1
& 0x0040 ) != 0 );
1272 pAktTC
->nVertAlign
= ( ( aBits1
& 0x0180 ) >> 7 );
1273 // am Rande: im aBits1 verstecken sich noch 7 Reserve-Bits,
1274 // anschliessend folgen noch 16 weitere Reserve-Bits
1276 // In Version 8 koennen wir alle Bordercodes auf einmal kopieren!
1277 memcpy( pAktTC
->rgbrc
, pTc
->rgbrcVer8
, 4 * sizeof( WW8_BRC
) );
1281 // #i25071 In '97 text direction appears to be only set using TC properties
1282 // not with sprmTTextFlow so we need to cycle through the maDirections and
1283 // double check any non-default directions
1284 for (int k
= 0; k
< nCols
; ++k
)
1286 if(maDirections
[k
] == 4)
1288 if(pTCs
[k
].bVertical
)
1290 if(pTCs
[k
].bBackward
)
1291 maDirections
[k
] = 3;
1293 maDirections
[k
] = 1;
1302 void WW8TabBandDesc::ProcessSprmTSetBRC(bool bVer67
, const BYTE
* pParamsTSetBRC
)
1304 if( pParamsTSetBRC
&& pTCs
) // set one or more cell border(s)
1306 BYTE nitcFirst
= pParamsTSetBRC
[0];// first col to be changed
1307 BYTE nitcLim
= pParamsTSetBRC
[1];// (last col to be changed)+1
1308 BYTE nFlag
= *(pParamsTSetBRC
+2);
1310 if (nitcFirst
>= nWwCols
)
1313 if (nitcLim
> nWwCols
)
1316 bool bChangeRight
= (nFlag
& 0x08) ? true : false;
1317 bool bChangeBottom
= (nFlag
& 0x04) ? true : false;
1318 bool bChangeLeft
= (nFlag
& 0x02) ? true : false;
1319 bool bChangeTop
= (nFlag
& 0x01) ? true : false;
1321 WW8_TCell
* pAktTC
= pTCs
+ nitcFirst
;
1324 WW8_BRCVer6
* pBRC
= (WW8_BRCVer6
*)(pParamsTSetBRC
+3);
1326 for( int i
= nitcFirst
; i
< nitcLim
; i
++, ++pAktTC
)
1329 memcpy( pAktTC
->rgbrc
[ WW8_TOP
].aBits1
,
1333 memcpy( pAktTC
->rgbrc
[ WW8_LEFT
].aBits1
,
1337 memcpy( pAktTC
->rgbrc
[ WW8_BOT
].aBits1
,
1341 memcpy( pAktTC
->rgbrc
[ WW8_RIGHT
].aBits1
,
1348 WW8_BRC
* pBRC
= (WW8_BRC
*)(pParamsTSetBRC
+3);
1350 for( int i
= nitcFirst
; i
< nitcLim
; i
++, ++pAktTC
)
1353 memcpy( pAktTC
->rgbrc
[ WW8_TOP
].aBits1
,
1355 sizeof( WW8_BRC
) );
1357 memcpy( pAktTC
->rgbrc
[ WW8_LEFT
].aBits1
,
1359 sizeof( WW8_BRC
) );
1361 memcpy( pAktTC
->rgbrc
[ WW8_BOT
].aBits1
,
1363 sizeof( WW8_BRC
) );
1365 memcpy( pAktTC
->rgbrc
[ WW8_RIGHT
].aBits1
,
1367 sizeof( WW8_BRC
) );
1376 void WW8TabBandDesc::ProcessSprmTTableBorders(bool bVer67
, const BYTE
* pParams
)
1378 // sprmTTableBorders
1381 for( int i
= 0; i
< 6; ++i
)
1383 aDefBrcs
[i
].aBits1
[0] = pParams
[ 2*i
];
1384 aDefBrcs
[i
].aBits1
[1] = pParams
[ 1+2*i
];
1387 else // aDefBrcs = *(BRC(*)[6])pS;
1388 memcpy( aDefBrcs
, pParams
, 24 );
1391 void WW8TabBandDesc::ProcessSprmTDxaCol(const BYTE
* pParamsTDxaCol
)
1393 // sprmTDxaCol (opcode 0x7623) changes the width of cells
1394 // whose index is within a certain range to be a certain value.
1396 if( nWwCols
&& pParamsTDxaCol
) // set one or more cell length(s)
1398 BYTE nitcFirst
= pParamsTDxaCol
[0]; // first col to be changed
1399 BYTE nitcLim
= pParamsTDxaCol
[1]; // (last col to be changed)+1
1400 short nDxaCol
= (INT16
)SVBT16ToShort( pParamsTDxaCol
+ 2 );
1404 for( int i
= nitcFirst
; (i
< nitcLim
) && (i
< nWwCols
); i
++ )
1406 nOrgWidth
= nCenter
[i
+1] - nCenter
[i
];
1407 nDelta
= nDxaCol
- nOrgWidth
;
1408 for( int j
= i
+1; j
<= nWwCols
; j
++ )
1410 nCenter
[j
] = nCenter
[j
] + nDelta
;
1416 void WW8TabBandDesc::ProcessSprmTInsert(const BYTE
* pParamsTInsert
)
1418 if( nWwCols
&& pParamsTInsert
) // set one or more cell length(s)
1420 BYTE nitcInsert
= pParamsTInsert
[0]; // position at which to insert
1421 if (nitcInsert
>= MAX_COL
) // cannot insert into cell outside max possible index
1423 BYTE nctc
= pParamsTInsert
[1]; // number of cells
1424 USHORT ndxaCol
= SVBT16ToShort( pParamsTInsert
+2 );
1427 if (nitcInsert
> nWwCols
)
1429 nNewWwCols
= nitcInsert
+nctc
;
1430 //if new count would be outside max possible count, clip it, and calc a new replacement
1432 if (nNewWwCols
> MAX_COL
)
1434 nNewWwCols
= MAX_COL
;
1435 nctc
= ::sal::static_int_cast
<BYTE
>(nNewWwCols
-nitcInsert
);
1440 nNewWwCols
= nWwCols
+nctc
;
1441 //if new count would be outside max possible count, clip it, and calc a new replacement
1443 if (nNewWwCols
> MAX_COL
)
1445 nNewWwCols
= MAX_COL
;
1446 nctc
= ::sal::static_int_cast
<BYTE
>(nNewWwCols
-nWwCols
);
1450 WW8_TCell
*pTC2s
= new WW8_TCell
[nNewWwCols
];
1451 setcelldefaults(pTC2s
, nNewWwCols
);
1455 memcpy( pTC2s
, pTCs
, nWwCols
* sizeof( WW8_TCell
) );
1460 //If we have to move some cells
1461 if (nitcInsert
<= nWwCols
)
1463 // adjust the left x-position of the dummy at the very end
1464 nCenter
[nWwCols
+ nctc
] = nCenter
[nWwCols
]+nctc
*ndxaCol
;
1465 for( int i
= nWwCols
-1; i
>= nitcInsert
; i
--)
1467 // adjust the left x-position
1468 nCenter
[i
+ nctc
] = nCenter
[i
]+nctc
*ndxaCol
;
1470 // adjust the cell's borders
1471 pTCs
[i
+ nctc
] = pTCs
[i
];
1475 //if itcMac is larger than full size, fill in missing ones first
1476 for( int i
= nWwCols
; i
> nitcInsert
+nWwCols
; i
--)
1477 nCenter
[i
] = i
? (nCenter
[i
- 1]+ndxaCol
) : 0;
1479 //now add in our new cells
1480 for( int j
= 0;j
< nctc
; j
++)
1481 nCenter
[j
+ nitcInsert
] = (j
+ nitcInsert
) ? (nCenter
[j
+ nitcInsert
-1]+ndxaCol
) : 0;
1483 nWwCols
= nNewWwCols
;
1487 void WW8TabBandDesc::ProcessDirection(const BYTE
* pParams
)
1489 sal_uInt8 nStartCell
= *pParams
++;
1490 sal_uInt8 nEndCell
= *pParams
++;
1491 sal_uInt16 nCode
= SVBT16ToShort(pParams
);
1493 ASSERT(nStartCell
< nEndCell
, "not as I thought");
1494 ASSERT(nEndCell
< MAX_COL
+ 1, "not as I thought");
1495 if (nStartCell
> MAX_COL
)
1497 if (nEndCell
> MAX_COL
+ 1)
1498 nEndCell
= MAX_COL
+ 1;
1500 for (;nStartCell
< nEndCell
; ++nStartCell
)
1501 maDirections
[nStartCell
] = nCode
;
1504 void WW8TabBandDesc::ProcessSpacing(const BYTE
* pParams
)
1506 BYTE nLen
= pParams
? *(pParams
- 1) : 0;
1507 ASSERT(nLen
== 6, "Unexpected spacing len");
1512 BYTE nWhichCell
= *pParams
;
1513 ASSERT(nWhichCell
== 0, "Expected cell to be 0!");
1515 ++pParams
; //Skip which cell
1516 ++pParams
; //unknown byte
1518 BYTE nSideBits
= *pParams
++;
1519 ASSERT(nSideBits
< 0x10, "Unexpected value for nSideBits");
1520 ++pParams
; //unknown byte
1521 USHORT nValue
= SVBT16ToShort( pParams
);
1522 for (int i
= wwTOP
; i
<= wwRIGHT
; i
++)
1524 switch (nSideBits
& (1 << i
))
1527 mnDefaultTop
= nValue
;
1530 mnDefaultLeft
= nValue
;
1533 mnDefaultBottom
= nValue
;
1536 mnDefaultRight
= nValue
;
1541 ASSERT(!this, "Impossible");
1547 void WW8TabBandDesc::ProcessSpecificSpacing(const BYTE
* pParams
)
1549 BYTE nLen
= pParams
? *(pParams
- 1) : 0;
1550 ASSERT(nLen
== 6, "Unexpected spacing len");
1553 BYTE nWhichCell
= *pParams
++;
1554 ASSERT(nWhichCell
< MAX_COL
+ 1, "Cell out of range in spacings");
1555 if (nWhichCell
>= MAX_COL
+ 1)
1558 ++pParams
; //unknown byte
1559 BYTE nSideBits
= *pParams
++;
1560 ASSERT(nSideBits
< 0x10, "Unexpected value for nSideBits");
1561 nOverrideSpacing
[nWhichCell
] |= nSideBits
;
1563 ASSERT(nOverrideSpacing
[nWhichCell
] < 0x10,
1564 "Unexpected value for nSideBits");
1566 BYTE nUnknown2
= *pParams
;
1567 ASSERT(nUnknown2
== 0x3, "Unexpected value for spacing2");
1570 USHORT nValue
= SVBT16ToShort( pParams
);
1572 for (int i
=0; i
< 4; i
++)
1574 if (nSideBits
& (1 << i
))
1575 nOverrideValues
[nWhichCell
][i
] = nValue
;
1579 void WW8TabBandDesc::ProcessSprmTDelete(const BYTE
* pParamsTDelete
)
1581 if( nWwCols
&& pParamsTDelete
) // set one or more cell length(s)
1583 BYTE nitcFirst
= pParamsTDelete
[0]; // first col to be deleted
1584 if (nitcFirst
>= nWwCols
) // first index to delete from doesn't exist
1586 BYTE nitcLim
= pParamsTDelete
[1]; // (last col to be deleted)+1
1587 if (nitcLim
<= nitcFirst
) // second index to delete to is not greater than first index
1591 * sprmTDelete causes any rgdxaCenter and rgtc entries whose index is
1592 * greater than or equal to itcLim to be moved
1594 int nShlCnt
= nWwCols
- nitcLim
; // count of cells to be shifted
1596 if (nShlCnt
>= 0) //There exist entries whose index is greater than or equal to itcLim
1598 WW8_TCell
* pAktTC
= pTCs
+ nitcFirst
;
1600 while( i
< nShlCnt
)
1602 // adjust the left x-position
1603 nCenter
[nitcFirst
+ i
] = nCenter
[nitcLim
+ i
];
1605 // adjust the cell's borders
1606 *pAktTC
= pTCs
[ nitcLim
+ i
];
1611 // adjust the left x-position of the dummy at the very end
1612 nCenter
[nitcFirst
+ i
] = nCenter
[nitcLim
+ i
];
1615 short nCellsDeleted
= nitcLim
- nitcFirst
;
1616 //clip delete request to available number of cells
1617 if (nCellsDeleted
> nWwCols
)
1618 nCellsDeleted
= nWwCols
;
1619 nWwCols
-= nCellsDeleted
;
1623 // ReadShd liest ggfs die Hintergrundfarben einer Zeile ein.
1624 // Es muss vorher ReadDef aufgerufen worden sein
1625 void WW8TabBandDesc::ReadShd(const BYTE
* pS
)
1627 BYTE nLen
= pS
? *(pS
- 1) : 0;
1633 pSHDs
= new WW8_SHD
[nWwCols
];
1634 memset( pSHDs
, 0, nWwCols
* sizeof( WW8_SHD
) );
1637 short nAnz
= nLen
>> 1;
1643 for(i
=0, pShd
= (SVBT16
*)pS
; i
<nAnz
; i
++, pShd
++ )
1644 pSHDs
[i
].SetWWValue( *pShd
);
1647 void WW8TabBandDesc::ReadNewShd(const BYTE
* pS
, bool bVer67
)
1649 BYTE nLen
= pS
? *(pS
- 1) : 0;
1654 pNewSHDs
= new sal_uInt32
[nWwCols
];
1656 short nAnz
= nLen
/ 10; //10 bytes each
1662 pNewSHDs
[i
++] = SwWW8ImplReader::ExtractColour(pS
, bVer67
);
1665 pNewSHDs
[i
++] = COL_AUTO
;
1668 void WW8TabBandDesc::setcelldefaults(WW8_TCell
*pCells
, short nCols
)
1670 memset( pCells
, 0, nCols
* sizeof( WW8_TCell
) );
1673 const BYTE
*HasTabCellSprm(WW8PLCFx_Cp_FKP
* pPap
, bool bVer67
)
1675 const BYTE
*pParams
;
1677 pParams
= pPap
->HasSprm(24);
1680 if (0 == (pParams
= pPap
->HasSprm(0x244B)))
1681 pParams
= pPap
->HasSprm(0x2416);
1690 sprmTTableWidth
,sprmTTextFlow
, sprmTFCantSplit
, sprmTFCantSplit90
,sprmTJc
, sprmTFBiDi
, sprmTDefTable
,
1691 sprmTDyaRowHeight
, sprmTDefTableShd
, sprmTDxaLeft
, sprmTSetBrc
,
1692 sprmTDxaCol
, sprmTInsert
, sprmTDelete
, sprmTTableHeader
,
1693 sprmTDxaGapHalf
, sprmTTableBorders
,
1695 sprmTDefTableNewShd
, sprmTSpacing
, sprmTNewSpacing
1698 wwTableSprm
GetTableSprm(sal_uInt16 nId
, ww::WordVersion eVer
)
1706 return sprmTTableWidth
;
1708 return sprmTTextFlow
;
1710 return sprmTFCantSplit
;
1712 return sprmTTableHeader
;
1714 return sprmTFCantSplit90
;
1726 return sprmTDyaRowHeight
;
1728 return sprmTDxaLeft
;
1730 return sprmTDxaGapHalf
;
1732 return sprmTTableBorders
;
1734 return sprmTDefTable
;
1736 return sprmTDefTableShd
;
1738 return sprmTDefTableNewShd
;
1742 return sprmTSpacing
;
1744 return sprmTNewSpacing
;
1754 return sprmTDxaLeft
;
1756 return sprmTDxaGapHalf
;
1758 return sprmTTableHeader
;
1760 return sprmTTableBorders
;
1762 return sprmTDyaRowHeight
;
1764 return sprmTDefTable
;
1766 return sprmTDefTableShd
;
1783 return sprmTDxaLeft
;
1785 return sprmTDxaGapHalf
;
1787 return sprmTDyaRowHeight
;
1789 return sprmTDefTable
;
1791 return sprmTDefTableShd
;
1806 WW8TabDesc::WW8TabDesc(SwWW8ImplReader
* pIoClass
, WW8_CP nStartCp
) :
1807 mpOldRedlineStack(0),
1829 bClaimLineFmt(false),
1830 eOri(text::HoriOrientation::NONE
),
1839 aItemSet(pIo
->rDoc
.GetAttrPool(),RES_FRMATR_BEGIN
,RES_FRMATR_END
-1)
1841 pIo
->bAktAND_fNumberAcross
= false;
1843 static const sal_Int16 aOriArr
[] =
1845 text::HoriOrientation::LEFT
, text::HoriOrientation::CENTER
, text::HoriOrientation::RIGHT
, text::HoriOrientation::CENTER
1848 bool bOldVer
= ww::IsSevenMinus(pIo
->GetFib().GetFIBVersion());
1849 WW8_TablePos aTabPos
;
1851 WW8PLCFxSave1 aSave
;
1852 pIo
->pPlcxMan
->GetPap()->Save( aSave
);
1854 WW8PLCFx_Cp_FKP
* pPap
= pIo
->pPlcxMan
->GetPapPLCF();
1856 eOri
= text::HoriOrientation::LEFT
;
1858 WW8TabBandDesc
* pNewBand
= new WW8TabBandDesc
;
1860 wwSprmParser
aSprmParser(pIo
->GetFib().GetFIBVersion());
1862 // process pPap until end of table found
1865 short nTabeDxaNew
= SHRT_MAX
;
1866 bool bTabRowJustRead
= false;
1867 const BYTE
* pShadeSprm
= 0;
1868 const BYTE
* pNewShadeSprm
= 0;
1869 WW8_TablePos
*pTabPos
= 0;
1871 // Suche Ende einer TabZeile
1872 if(!(pIo
->SearchRowEnd(pPap
, nStartCp
, pIo
->nInTable
)))
1878 // Get the SPRM chains:
1879 // first from PAP and then from PCD (of the Piece Table)
1881 pPap
->GetSprms( &aDesc
);
1882 WW8SprmIter
aSprmIter(aDesc
.pMemPos
, aDesc
.nSprmsLen
, aSprmParser
);
1884 const BYTE
* pParams
= aSprmIter
.GetAktParams();
1885 for (int nLoop
= 0; nLoop
< 2; ++nLoop
)
1887 bool bRepeatedSprm
= false;
1888 while (aSprmIter
.GetSprms() && 0 != (pParams
= aSprmIter
.GetAktParams()))
1890 sal_uInt16 nId
= aSprmIter
.GetAktId();
1891 wwTableSprm eSprm
= GetTableSprm(nId
, pIo
->GetFib().GetFIBVersion());
1894 case sprmTTableWidth
:
1896 const BYTE b0
= pParams
[0];
1897 const BYTE b1
= pParams
[1];
1898 const BYTE b2
= pParams
[2];
1899 if (b0
== 3) // Twips
1900 nPreferredWidth
= b2
* 0x100 + b1
;
1904 pNewBand
->ProcessDirection(pParams
);
1906 case sprmTFCantSplit
:
1907 pNewBand
->bCantSplit
= *pParams
;
1908 bClaimLineFmt
= true;
1910 case sprmTFCantSplit90
:
1911 pNewBand
->bCantSplit90
= *pParams
;
1912 bClaimLineFmt
= true;
1914 case sprmTTableBorders
:
1915 pNewBand
->ProcessSprmTTableBorders(bOldVer
, pParams
);
1917 case sprmTTableHeader
:
1921 bRepeatedSprm
= true;
1925 // sprmTJc - Justification Code
1927 eOri
= aOriArr
[*pParams
& 0x3];
1930 bIsBiDi
= SVBT16ToShort(pParams
) ? true : false;
1932 case sprmTDxaGapHalf
:
1933 pNewBand
->nGapHalf
= (INT16
)SVBT16ToShort( pParams
);
1935 case sprmTDyaRowHeight
:
1936 pNewBand
->nLineHeight
= (INT16
)SVBT16ToShort( pParams
);
1937 bClaimLineFmt
= true;
1940 pNewBand
->ReadDef(bOldVer
, pParams
);
1941 bTabRowJustRead
= true;
1943 case sprmTDefTableShd
:
1944 pShadeSprm
= pParams
;
1946 case sprmTDefTableNewShd
:
1947 pNewShadeSprm
= pParams
;
1950 // our Writer cannot shift single table lines
1951 // horizontally so we have to find the smallest
1952 // parameter (meaning the left-most position) and then
1953 // shift the whole table to that margin (see below)
1955 short nDxaNew
= (INT16
)SVBT16ToShort( pParams
);
1956 nOrgDxaLeft
= nDxaNew
;
1957 if( nDxaNew
< nTabeDxaNew
)
1958 nTabeDxaNew
= nDxaNew
;
1962 pNewBand
->ProcessSprmTSetBRC(bOldVer
, pParams
);
1965 pNewBand
->ProcessSprmTDxaCol(pParams
);
1968 pNewBand
->ProcessSprmTInsert(pParams
);
1971 pNewBand
->ProcessSprmTDelete(pParams
);
1973 case sprmTNewSpacing
:
1974 pNewBand
->ProcessSpacing(pParams
);
1977 pNewBand
->ProcessSpecificSpacing(pParams
);
1987 pPap
->GetPCDSprms( aDesc
);
1988 aSprmIter
.SetSprms( aDesc
.pMemPos
, aDesc
.nSprmsLen
);
1992 // #55171: WW-Tabellen koennen Fly-Wechsel beinhalten daher hier
1993 // Tabellen abbrechen und neu beginnen noch steht *pPap noch vor
1994 // TabRowEnd, daher kann TestApo() mit letztem Parameter false und
1995 // damit wirksam gerufen werden.
1997 if (bTabRowJustRead
)
2000 pNewBand
->ReadShd(pShadeSprm
);
2002 pNewBand
->ReadNewShd(pNewShadeSprm
, bOldVer
);
2005 if( nTabeDxaNew
< SHRT_MAX
)
2007 short* pCenter
= pNewBand
->nCenter
;
2008 short firstDxaCenter
= *pCenter
;
2009 for( int i
= 0; i
< pNewBand
->nWwCols
; i
++, ++pCenter
)
2011 // #i30298# Use sprmTDxaLeft to adjust the left indent
2012 // #i40461# Use dxaGapHalf during calculation
2014 (nTabeDxaNew
- (firstDxaCenter
+ pNewBand
->nGapHalf
));
2019 pActBand
= pFirstBand
= pNewBand
;
2022 pActBand
->pNextBand
= pNewBand
;
2023 pActBand
= pNewBand
;
2027 pNewBand
= new WW8TabBandDesc
;
2032 //Seek our pap to its next block of properties
2035 aRes
.nStartPos
= nStartCp
;
2037 if (!(pPap
->SeekPos(aRes
.nStartPos
)))
2039 aRes
.nEndPos
= WW8_CP_MAX
;
2040 pPap
->SetDirty(true);
2042 pPap
->GetSprms(&aRes
);
2043 pPap
->SetDirty(false);
2045 //Are we at the end of available properties
2047 !pPap
->HasFkp() || pPap
->Where() == WW8_CP_MAX
||
2048 aRes
.nStartPos
== WW8_CP_MAX
2055 //Are we still in a table cell
2056 pParams
= HasTabCellSprm(pPap
, bOldVer
);
2057 const BYTE
*pLevel
= pPap
->HasSprm(0x6649);
2059 if (!pParams
|| (1 != *pParams
) ||
2060 (pLevel
&& (*pLevel
<= pIo
->nInTable
)))
2065 //Get the end of row new table positioning data
2066 WW8_CP nMyStartCp
=nStartCp
;
2067 if (pIo
->SearchRowEnd(pPap
, nMyStartCp
, pIo
->nInTable
))
2068 if (SwWW8ImplReader::ParseTabPos(&aTabPos
, pPap
))
2071 //Move back to this cell
2073 aRes
.nStartPos
= nStartCp
;
2075 // #114237 PlcxMan currently points too far ahead so we need to bring
2076 // it back to where we are trying to make a table
2077 pIo
->pPlcxMan
->GetPap()->nOrigStartPos
= aRes
.nStartPos
;
2078 if (!(pPap
->SeekPos(aRes
.nStartPos
)))
2080 aRes
.nEndPos
= WW8_CP_MAX
;
2081 pPap
->SetDirty(true);
2083 pPap
->GetSprms(&aRes
);
2084 pPap
->SetDirty(false);
2086 //Does this row match up with the last row closely enough to be
2087 //considered part of the same table
2088 ApoTestResults aApo
= pIo
->TestApo(pIo
->nInTable
+ 1, false, pTabPos
);
2091 ##513##, #79474# If this is not sufficent, then we should look at
2092 sprmPD{y|x}aAbs as our indicator that the following set of rows is not
2093 part of this table, but instead is an absolutely positioned table
2098 if (aApo
.mbStartApo
)
2100 //if there really is a fly here, and not a "null" fly then break.
2101 WW8FlyPara
*pNewFly
= pIo
->ConstructApo(aApo
, pTabPos
);
2108 nStartCp
= aRes
.nEndPos
;
2114 if( pActBand
->nRows
> 1 )
2116 // Letztes Band hat mehr als 1 Zeile
2118 pNewBand
= new WW8TabBandDesc( *pActBand
); // neues machen
2119 pActBand
->nRows
--; // wegen Sonderbehandlung Raender-Defaults
2120 pNewBand
->nRows
= 1;
2121 pActBand
->pNextBand
= pNewBand
; // am Ende einschleifen
2123 pNewBand
= 0; // nicht loeschen
2129 pIo
->pPlcxMan
->GetPap()->Restore( aSave
);
2132 WW8TabDesc::~WW8TabDesc()
2134 WW8TabBandDesc
* pR
= pFirstBand
;
2137 WW8TabBandDesc
* pR2
= pR
->pNextBand
;
2143 delete pMergeGroups
;
2146 void WW8TabDesc::CalcDefaults()
2148 short nMinCols
= SHRT_MAX
;
2151 nMinLeft
= SHRT_MAX
;
2152 nMaxRight
= SHRT_MIN
;
2156 If we are an honestly inline centered table, then the normal rules of
2157 engagement for left and right margins do not apply. The multiple rows are
2158 centered regardless of the actual placement of rows, so we cannot have
2159 mismatched rows as is possible in other configurations.
2161 e.g. change the example bugdoc in word from text wrapping of none (inline)
2162 to around (in frame (bApo)) and the table splits into two very disjoint
2163 rows as the beginning point of each row are very different
2165 if ((!pIo
->InLocalApo()) && (eOri
== text::HoriOrientation::CENTER
))
2167 for (pR
= pFirstBand
; pR
; pR
= pR
->pNextBand
)
2168 for( short i
= pR
->nWwCols
; i
>= 0; --i
)
2169 pR
->nCenter
[i
] = pR
->nCenter
[i
] - pR
->nCenter
[0];
2172 // 1. Durchlauf: aeusserste L- und R-Grenzen finden
2173 for( pR
= pFirstBand
; pR
; pR
= pR
->pNextBand
)
2175 if( pR
->nCenter
[0] < nMinLeft
)
2176 nMinLeft
= pR
->nCenter
[0];
2178 for( short i
= 0; i
< pR
->nWwCols
; i
++ )
2181 #74387# If the margins are so large as to make the displayable
2182 area inside them smaller than the minimum allowed then adjust the
2183 width to fit. But only do it if the two cells are not the exact
2184 same value, if they are then the cell does not really exist and will
2185 be blended together into the same cell through the use of the
2187 #i28333# If the nGapHalf is greater than the cell width best to ignore it
2189 int nCellWidth
= pR
->nCenter
[i
+1] - pR
->nCenter
[i
];
2190 if (nCellWidth
&& ((nCellWidth
- pR
->nGapHalf
*2) < MINLAY
) && pR
->nGapHalf
< nCellWidth
)
2192 pR
->nCenter
[i
+1] = pR
->nCenter
[i
]+MINLAY
+pR
->nGapHalf
* 2;
2196 if( pR
->nCenter
[pR
->nWwCols
] > nMaxRight
)
2197 nMaxRight
= pR
->nCenter
[pR
->nWwCols
];
2199 nSwWidth
= nMaxRight
- nMinLeft
;
2201 // #109830# If the table is right aligned we need to align all rows to the
2202 // row that has the furthest right point
2204 if(eOri
== text::HoriOrientation::RIGHT
)
2206 for( pR
= pFirstBand
; pR
; pR
= pR
->pNextBand
)
2208 int adjust
= nMaxRight
- pR
->nCenter
[pR
->nWwCols
];
2209 for( short i
= 0; i
< pR
->nWwCols
+ 1; i
++ )
2211 pR
->nCenter
[i
] = static_cast< short >(pR
->nCenter
[i
] + adjust
);
2217 // 2. Durchlauf: Zahl der Writer-Spalten feststellen Die Zahl der Writer
2218 // Spalten kann um bis zu 2 hoeher sein als im WW, da der SW im Gegensatz
2219 // zu WW keine ausgefransten linken und rechten Raender kann und diese
2220 // durch leere Boxen aufgefuellt werden. Durch nichtexistente Zellen
2221 // koennen auch Zellen wegfallen
2223 // 3. Durchlauf: Wo noetig die Umrandungen durch die Defaults ersetzen
2224 nConvertedLeft
= nMinLeft
;
2226 short nLeftMaxThickness
= 0, nRightMaxThickness
=0;
2227 for( pR
= pFirstBand
; pR
; pR
= pR
->pNextBand
)
2231 pR
->pTCs
= new WW8_TCell
[ pR
->nWwCols
];
2232 memset( pR
->pTCs
, 0, pR
->nWwCols
* sizeof( WW8_TCell
) );
2234 for (int k
= 0; k
< pR
->nWwCols
; ++k
)
2236 WW8_TCell
* pT
= &pR
->pTCs
[k
];
2238 for( i
= 0; i
< 4; i
++ )
2240 if (pT
->rgbrc
[i
].IsZeroed(pIo
->bVer67
))
2242 // if shadow is set, its invalid
2247 // Aussen oben / Innen waagerecht
2248 j
= (pR
== pFirstBand
) ? 0 : 4;
2251 // Aussen links / Innen senkrecht
2255 // Aussen unten / Innen waagerecht
2256 j
= pR
->pNextBand
? 4 : 2;
2259 // Aussen rechts/ Innen senkrecht
2260 j
= (k
== pR
->nWwCols
- 1) ? 3 : 5;
2263 // mangel mit Defaults ueber
2264 pT
->rgbrc
[i
] = pR
->aDefBrcs
[j
];
2269 Similiar to graphics and other elements word does not totally
2270 factor the width of the border into its calculations of size, we
2271 do so we must adjust out widths and other dimensions to fit. It
2272 appears that what occurs is that the last cell's right margin if
2273 the margin width that is not calculated into winwords table
2274 dimensions, so in that case increase the table to include the
2275 extra width of the right margin.
2278 !(SVBT16ToShort(pR
->pTCs
[pR
->nWwCols
-1].rgbrc
[3].aBits1
) & 0x20)
2279 : !(SVBT16ToShort(pR
->pTCs
[pR
->nWwCols
-1].rgbrc
[3].aBits2
) & 0x2000))
2281 short nThickness
= pR
->pTCs
[pR
->nWwCols
-1].rgbrc
[3].
2282 DetermineBorderProperties(pIo
->bVer67
);
2283 pR
->nCenter
[pR
->nWwCols
] = pR
->nCenter
[pR
->nWwCols
] + nThickness
;
2284 if (nThickness
> nRightMaxThickness
)
2285 nRightMaxThickness
= nThickness
;
2289 The left space of the table is in nMinLeft, but again this
2290 does not consider the margin thickness to its left in the
2291 placement value, so get the thickness of the left border,
2292 half is placed to the left of the nominal left side, and
2296 !(SVBT16ToShort(pR
->pTCs
[0].rgbrc
[1].aBits1
) & 0x20)
2297 : !(SVBT16ToShort(pR
->pTCs
[0].rgbrc
[1].aBits2
) & 0x2000))
2299 short nThickness
= pR
->pTCs
[0].rgbrc
[1].
2300 DetermineBorderProperties(pIo
->bVer67
);
2301 if (nThickness
> nLeftMaxThickness
)
2302 nLeftMaxThickness
= nThickness
;
2305 nSwWidth
= nSwWidth
+ nRightMaxThickness
;
2306 nMaxRight
= nMaxRight
+ nRightMaxThickness
;
2307 nConvertedLeft
= nMinLeft
-(nLeftMaxThickness
/2);
2309 for( pR
= pFirstBand
; pR
; pR
= pR
->pNextBand
)
2311 pR
->nSwCols
= pR
->nWwCols
;
2312 pR
->bLEmptyCol
= pR
->nCenter
[0] - nMinLeft
>= MINLAY
;
2313 pR
->bREmptyCol
= (nMaxRight
- pR
->nCenter
[pR
->nWwCols
] - nRightMaxThickness
) >= MINLAY
;
2315 short nAddCols
= pR
->bLEmptyCol
+ pR
->bREmptyCol
;
2317 USHORT j
= ( pR
->bLEmptyCol
) ? 1 : 0;
2318 for (i
= 0; i
< pR
->nWwCols
; ++i
)
2320 pR
->nTransCell
[i
] = (INT8
)j
;
2321 if ( pR
->nCenter
[i
] < pR
->nCenter
[i
+1] )
2323 pR
->bExist
[i
] = true;
2328 pR
->bExist
[i
] = false;
2333 ASSERT(i
,"no columns in row ?");
2337 If the last cell was "false" then there is no valid cell following it,
2338 so the default mapping forward wont't work. So map it (and
2339 contigious invalid cells backwards to the last valid cell instead.
2341 if (i
&& pR
->bExist
[i
-1] == false)
2344 while (k
&& pR
->bExist
[k
] == false)
2346 for (USHORT n
=k
+1;n
<i
;n
++)
2347 pR
->nTransCell
[n
] = pR
->nTransCell
[k
];
2350 pR
->nTransCell
[i
++] = (INT8
)(j
++); // Wird u.a. wegen bREmptyCol um
2351 pR
->nTransCell
[i
] = (INT8
)j
; // max. 2 ueberindiziert
2353 pR
->nSwCols
= pR
->nSwCols
+ nAddCols
;
2354 if( pR
->nSwCols
< nMinCols
)
2355 nMinCols
= pR
->nSwCols
;
2360 Find the largest of the borders on cells that adjoin top bottom and remove
2361 the val from the top and put in on the bottom cell. I can't seem to make
2362 disjoint upper and lowers to see what happens there.
2365 /* #i29550# FME 2004-06-02 Removed this code because of the implementation
2366 of the collapsing table borders model. So this should not be necessary
2369 /* for (pR = pFirstBand; pR; pR = pR->pNextBand)
2371 WW8TabBandDesc *pNext = pR->pNextBand;
2375 for (int k = 0; k < pR->nWwCols; ++k)
2377 WW8_BRC &rAbove = pR->pTCs[k].rgbrc[WW8_BOT];
2378 short nAboveThick = rAbove.IsEmpty(pIo->bVer67) ?
2379 0 : rAbove.DetermineBorderProperties(pIo->bVer67);
2380 short nUpperLeft = pR->nCenter[k];
2381 short nUpperRight = pR->nCenter[k+1];
2383 for (int l = 0; l < pNext->nWwCols; ++l)
2385 short nLowerLeft = pNext->nCenter[l];
2386 short nLowerRight = pNext->nCenter[l+1];
2388 if ((nLowerLeft < nUpperLeft) || (nLowerRight > nUpperRight))
2391 WW8_BRC &rBelow = pNext->pTCs[l].rgbrc[WW8_TOP];
2392 short nBelowThick = rBelow.IsEmpty(pIo->bVer67) ?
2393 0 : rBelow.DetermineBorderProperties(pIo->bVer67);
2394 if (nAboveThick > nBelowThick)
2402 if ((nMinLeft
&& !bIsBiDi
&& text::HoriOrientation::LEFT
== eOri
) ||
2403 (nMinLeft
!= -108 && bIsBiDi
&& text::HoriOrientation::RIGHT
== eOri
)) // Word sets the first nCenter value to -108 when no indent is used
2404 eOri
= text::HoriOrientation::LEFT_AND_WIDTH
; // absolutely positioned
2406 nDefaultSwCols
= nMinCols
; // da Zellen einfuegen billiger ist als Mergen
2407 if( nDefaultSwCols
== 0 )
2409 pActBand
= pFirstBand
;
2411 ASSERT( pActBand
, "pActBand ist 0" );
2414 void WW8TabDesc::SetSizePosition(SwFrmFmt
* pFrmFmt
)
2416 SwFrmFmt
* pApply
= pFrmFmt
;
2418 pApply
= pTable
->GetFrmFmt();
2419 ASSERT(pApply
,"No frame");
2420 pApply
->SetFmtAttr(aItemSet
);
2423 SwFmtFrmSize aSize
= pFrmFmt
->GetFrmSize();
2424 aSize
.SetHeightSizeType(ATT_MIN_SIZE
);
2425 aSize
.SetHeight(MINLAY
);
2426 pFrmFmt
->SetFmtAttr(aSize
);
2427 pTable
->GetFrmFmt()->SetFmtAttr(SwFmtHoriOrient(0,text::HoriOrientation::FULL
));
2431 void wwSectionManager::PrependedInlineNode(const SwPosition
&rPos
,
2432 const SwNode
&rNode
)
2434 ASSERT(!maSegments
.empty(),
2435 "should not be possible, must be at least one segment");
2436 if ((!maSegments
.empty()) && (maSegments
.back().maStart
== rPos
.nNode
))
2437 maSegments
.back().maStart
= SwNodeIndex(rNode
);
2440 void WW8TabDesc::CreateSwTable()
2442 ::SetProgressState(pIo
->nProgress
, pIo
->mpDocShell
); // Update
2444 // if there is already some content on the Node append new node to ensure
2445 // that this content remains ABOVE the table
2446 SwPosition
* pPoint
= pIo
->pPaM
->GetPoint();
2447 bool bInsNode
= pPoint
->nContent
.GetIndex() ? true : false;
2448 bool bSetMinHeight
= false;
2452 Set fly anchor to its anchor pos, so that if a table starts immediately
2453 at this position a new node will be inserted before inserting the table.
2455 if (!bInsNode
&& pIo
->pFmtOfJustInsertedApo
)
2457 const SwPosition
* pAPos
=
2458 pIo
->pFmtOfJustInsertedApo
->GetAnchor().GetCntntAnchor();
2459 if (pAPos
&& &pAPos
->nNode
.GetNode() == &pPoint
->nNode
.GetNode())
2462 bSetMinHeight
= true;
2464 SwFmtSurround
aSur(pIo
->pFmtOfJustInsertedApo
->GetSurround());
2465 aSur
.SetAnchorOnly(true);
2466 pIo
->pFmtOfJustInsertedApo
->SetFmtAttr(aSur
);
2470 if (bSetMinHeight
== true)
2472 // minimize Fontsize to minimize height growth of the header/footer
2473 // set font size to 1 point to minimize y-growth of Hd/Ft
2474 SvxFontHeightItem
aSz(20, 100, RES_CHRATR_FONTSIZE
);
2475 pIo
->NewAttr( aSz
);
2476 pIo
->pCtrlStck
->SetAttr(*pPoint
, RES_CHRATR_FONTSIZE
);
2480 pIo
->AppendTxtNode(*pPoint
);
2482 pTmpPos
= new SwPosition( *pIo
->pPaM
->GetPoint() );
2484 // Die Tabelle ist beim Einfuegen noch recht klein: Zahl der Spalten ist
2485 // die kleinste Spaltenanzahl des Originals, da Spalten einfuegen
2486 // schneller geht als Loeschen Zahl der Zeilen ist die Zahl der Baender,
2487 // da sich die (identischen) Zeilen eines Bandes prima duplizieren lassen
2488 pTable
= pIo
->rDoc
.InsertTable(
2489 SwInsertTableOptions( tabopts::HEADLINE_NO_BORDER
, 0 ),
2490 *pTmpPos
, nBands
, nDefaultSwCols
, eOri
, 0, 0, FALSE
, TRUE
);
2492 ASSERT(pTable
&& pTable
->GetFrmFmt(), "insert table failed");
2493 if (!pTable
|| !pTable
->GetFrmFmt())
2496 SwTableNode
* pTableNode
= pTable
->GetTableNode();
2497 ASSERT(pTableNode
, "no table node!");
2500 pIo
->maSectionManager
.PrependedInlineNode(*pIo
->pPaM
->GetPoint(),
2504 // Abfrage, ob im Node, in dem die Tabelle eingefuegt werden soll, bereits
2505 // ein Pagedesc steht. Dann wuerde der PageDesc in die naechste Zeile
2506 // hinter der Tabelle rutschen, wo er nichts zu suchen hat. -> loeschen
2507 // und spaeter an das Tabellenformat setzen
2508 if (SwTxtNode
* pNd
= pIo
->rDoc
.GetNodes()[pTmpPos
->nNode
]->GetTxtNode())
2510 if (const SfxItemSet
* pSet
= pNd
->GetpSwAttrSet())
2512 SfxPoolItem
*pSetAttr
= 0;
2513 const SfxPoolItem
* pItem
;
2514 if (SFX_ITEM_SET
== pSet
->GetItemState(RES_BREAK
, false, &pItem
))
2516 pSetAttr
= new SvxFmtBreakItem( *(SvxFmtBreakItem
*)pItem
);
2517 pNd
->ResetAttr( RES_BREAK
);
2520 // evtl den PageDesc/Break jetzt an der Tabelle setzen
2523 aItemSet
.Put(*pSetAttr
);
2529 // Gesamtbreite der Tabelle
2530 if( nMaxRight
- nMinLeft
> MINLAY
* nDefaultSwCols
)
2532 pTable
->GetFrmFmt()->SetFmtAttr(SwFmtFrmSize(ATT_FIX_SIZE
, nSwWidth
));
2533 aItemSet
.Put(SwFmtFrmSize(ATT_FIX_SIZE
, nSwWidth
));
2536 SvxFrameDirectionItem
aDirection(
2537 bIsBiDi
? FRMDIR_HORI_RIGHT_TOP
: FRMDIR_HORI_LEFT_TOP
, RES_FRAMEDIR
);
2538 pTable
->GetFrmFmt()->SetFmtAttr(aDirection
);
2540 if (text::HoriOrientation::LEFT_AND_WIDTH
== eOri
)
2542 if (!pIo
->nInTable
&& pIo
->InLocalApo() && pIo
->pSFlyPara
->pFlyFmt
&&
2545 //If we are inside a frame and we have a border, the frames
2546 //placement does not consider the tables border, which word
2547 //displays outside the frame, so adjust here.
2548 SwFmtHoriOrient
aHori(pIo
->pSFlyPara
->pFlyFmt
->GetHoriOrient());
2549 sal_Int16 eHori
= aHori
.GetHoriOrient();
2550 if ((eHori
== text::HoriOrientation::NONE
) || (eHori
== text::HoriOrientation::LEFT
) ||
2551 (eHori
== text::HoriOrientation::LEFT_AND_WIDTH
))
2553 //With multiple table, use last table settings. Perhaps
2554 //the maximum is what word does ?
2555 aHori
.SetPos(pIo
->pSFlyPara
->nXPos
+ GetMinLeft());
2556 aHori
.SetHoriOrient(text::HoriOrientation::NONE
);
2557 pIo
->pSFlyPara
->pFlyFmt
->SetFmtAttr(aHori
);
2562 //If bApo is set, then this table is being placed in a floating
2563 //frame, and the frame matches the left and right *lines* of the
2564 //table, so the space to the left of the table isn't to be used
2565 //inside the frame, in word the dialog involved greys out the
2566 //ability to set the margin.
2567 SvxLRSpaceItem
aL( RES_LR_SPACE
);
2568 // set right to original DxaLeft (i28656)
2572 nLeft
= GetMinLeft();
2575 if (nPreferredWidth
)
2576 nLeft
= pIo
->maSectionManager
.GetTextAreaWidth() - nPreferredWidth
- nOrgDxaLeft
;
2578 nLeft
= -GetMinLeft();
2587 mpOldRedlineStack
= pIo
->mpRedlineStack
;
2588 pIo
->mpRedlineStack
= new sw::util::RedlineStack(pIo
->rDoc
);
2591 void WW8TabDesc::UseSwTable()
2593 // globale Varis initialisieren
2594 pTabLines
= &pTable
->GetTabLines();
2595 nAktRow
= nAktCol
= nAktBandRow
= 0;
2597 pTblNd
= (SwTableNode
*)(*pTabLines
)[0]->GetTabBoxes()[0]->
2598 GetSttNd()->FindTableNode();
2599 ASSERT( pTblNd
, "wo ist mein TabellenNode" );
2601 // --> mloiseleur 2007-10-10 #i69519# Restrict rows to repeat to a decent value
2602 if ( nRowsToRepeat
== static_cast<USHORT
>(nRows
) )
2606 pTblNd
->GetTable().SetRowsToRepeat( nRowsToRepeat
);
2607 // ggfs. Zusatz-Zellen einfuegen u.dgl.
2610 WW8DupProperties
aDup(pIo
->rDoc
,pIo
->pCtrlStck
);
2611 pIo
->pCtrlStck
->SetAttr(*pIo
->pPaM
->GetPoint(), 0, false);
2613 // jetzt den PaM korrekt setzen und ggfs. erste Mergegruppe vorbereiten...
2614 SetPamInCell(nAktCol
, true);
2615 aDup
.Insert(*pIo
->pPaM
->GetPoint());
2617 pIo
->bWasTabRowEnd
= false;
2618 pIo
->bWasTabCellEnd
= false;
2621 void WW8TabDesc::MergeCells()
2625 for (pActBand
=pFirstBand
, nRow
=0; pActBand
; pActBand
=pActBand
->pNextBand
)
2628 // ggfs. aktuelle Box in entsprechende Merge-Gruppe eintragen
2630 if( pActBand
->pTCs
)
2632 for( short j
= 0; j
< pActBand
->nRows
; j
++, nRow
++ )
2633 for( short i
= 0; i
< pActBand
->nWwCols
; i
++ )
2635 WW8SelBoxInfoPtr pActMGroup
= 0;
2637 // ggfs. eine neue Merge-Gruppe beginnen
2639 ASSERT(nRow
< pTabLines
->Count(),
2640 "Too few lines, table ended early");
2641 if (nRow
>= pTabLines
->Count())
2643 pTabLine
= (*pTabLines
)[ nRow
];
2644 pTabBoxes
= &pTabLine
->GetTabBoxes();
2646 USHORT nCol
= pActBand
->nTransCell
[ i
];
2647 if (!pActBand
->bExist
[i
]) //#113434#
2649 ASSERT(nCol
< pTabBoxes
->Count(),
2650 "Too few columns, table ended early");
2651 if (nCol
>= pTabBoxes
->Count())
2653 pTabBox
= (*pTabBoxes
)[nCol
];
2654 WW8_TCell
& rCell
= pActBand
->pTCs
[ i
];
2655 // ist dies die obere, linke-Zelle einer Merge-Gruppe ?
2657 bool bMerge
= false;
2658 if ( rCell
.bVertRestart
&& !rCell
.bMerged
)
2660 else if (rCell
.bFirstMerged
&& pActBand
->bExist
[i
])
2662 //#91211# Some tests to avoid merging cells
2663 //which previously were declared invalid because
2664 //of sharing the exact same dimensions as their
2667 //If theres anything underneath/above we're ok.
2668 if (rCell
.bVertMerge
|| rCell
.bVertRestart
)
2672 //If its a hori merge only, and the only things in
2673 //it are invalid cells then its already taken care
2674 //of, so don't merge.
2675 for (USHORT i2
= i
+1; i2
< pActBand
->nWwCols
; i2
++ )
2676 if (pActBand
->pTCs
[ i2
].bMerged
&&
2677 !pActBand
->pTCs
[ i2
].bFirstMerged
)
2679 if (pActBand
->bExist
[i2
])
2693 short nX1
= pActBand
->nCenter
[ i
];
2694 short nWidth
= pActBand
->nWidth
[ i
];
2696 // 0. falls noetig das Array fuer die Merge-Gruppen
2699 pMergeGroups
= new WW8MergeGroups
;
2701 // 2. aktuelle Merge-Gruppe anlegen
2702 pActMGroup
= new WW8SelBoxInfo( nX1
, nWidth
);
2704 // --> OD 2005-02-04 #118544# - determine size of new
2705 // merge group before inserted the new merge group.
2706 // Needed to correctly locked previously created merge groups.
2707 // Gesamtbreite ermitteln und zuweisen
2708 short nSizCell
= pActBand
->nWidth
[ i
];
2709 for (USHORT i2
= i
+1; i2
< pActBand
->nWwCols
; i2
++ )
2710 if (pActBand
->pTCs
[ i2
].bMerged
&&
2711 !pActBand
->pTCs
[ i2
].bFirstMerged
)
2713 nSizCell
= nSizCell
+ pActBand
->nWidth
[ i2
];
2717 pActMGroup
->nGroupWidth
= nSizCell
;
2720 // --> OD 2005-02-03 #118544# - locked previously
2721 // created merge groups, after determining the size
2722 // for the new merge group.
2723 // 1. ggfs. alte Mergegruppe(n) schliessen, die
2724 // den von unserer neuen Gruppe betroffenen
2725 // X-Bereich ueberdecken
2727 while ( FindMergeGroup( nX1
, pActMGroup
->nGroupWidth
,
2730 (*pMergeGroups
)[ nMGrIdx
]->bGroupLocked
= true;
2734 // 3. und in Gruppen-Array eintragen
2735 pMergeGroups
->Insert(pActMGroup
, pMergeGroups
->Count());
2738 // ggfs. akt. Box zu einer Merge-Gruppe hinzufuegen (dies
2739 // kann eine soeben angelegte, oder eine andere Gruppe
2741 UpdateTableMergeGroup( rCell
, pActMGroup
, pTabBox
, i
);
2747 //There is a limbo area in word at the end of the row marker
2748 //where properties can live in word, there is no location in
2749 //writer equivalent, so try and park the cursor in the best
2750 //match, see #i23022#/#i18644#
2751 void WW8TabDesc::ParkPaM()
2753 SwTableBox
*pTabBox2
= 0;
2754 short nRow
= nAktRow
+ 1;
2755 if (nRow
< pTabLines
->Count())
2757 if (SwTableLine
*pLine
= (*pTabLines
)[nRow
])
2759 SwTableBoxes
&rBoxes
= pLine
->GetTabBoxes();
2760 pTabBox2
= rBoxes
.Count() ? rBoxes
[0] : 0;
2764 if (!pTabBox2
|| !pTabBox2
->GetSttNd())
2770 if (pIo
->pPaM
->GetPoint()->nNode
!= pTabBox2
->GetSttIdx() + 1)
2772 pIo
->pPaM
->GetPoint()->nNode
= pTabBox2
->GetSttIdx() + 1;
2773 pIo
->pPaM
->GetPoint()->nContent
.Assign(pIo
->pPaM
->GetCntntNode(), 0);
2774 pIo
->rDoc
.SetTxtFmtColl(*pIo
->pPaM
, (SwTxtFmtColl
*)pIo
->pDfltTxtFmtColl
);
2778 void WW8TabDesc::MoveOutsideTable()
2780 ASSERT(pTmpPos
&& pIo
, "I've forgotten where the table is anchored");
2782 *pIo
->pPaM
->GetPoint() = *pTmpPos
;
2785 void WW8TabDesc::FinishSwTable()
2787 pIo
->mpRedlineStack
->closeall(*pIo
->pPaM
->GetPoint());
2788 delete pIo
->mpRedlineStack
;
2789 pIo
->mpRedlineStack
= mpOldRedlineStack
;
2790 mpOldRedlineStack
= 0;
2792 WW8DupProperties
aDup(pIo
->rDoc
,pIo
->pCtrlStck
);
2793 pIo
->pCtrlStck
->SetAttr( *pIo
->pPaM
->GetPoint(), 0, false);
2796 delete pTmpPos
, pTmpPos
= 0;
2798 aDup
.Insert(*pIo
->pPaM
->GetPoint());
2800 pIo
->bWasTabRowEnd
= false;
2801 pIo
->bWasTabCellEnd
= false;
2803 pIo
->maInsertedTables
.InsertTable(*pTblNd
, *pIo
->pPaM
);
2807 // falls noetig, zu mergende Zellen gruppenweise zusammenfassen
2810 // bearbeite alle Merge-Gruppen nacheinander
2811 WW8SelBoxInfo
* pActMGroup
;
2812 USHORT nActBoxCount
;
2814 for (USHORT iGr
= 0; iGr
< pMergeGroups
->Count(); ++iGr
)
2816 pActMGroup
= (*pMergeGroups
)[ iGr
];
2817 nActBoxCount
= pActMGroup
->Count();
2819 if( ( 1 < nActBoxCount
) && pActMGroup
&& (*pActMGroup
)[ 0 ] )
2821 const USHORT nRowSpan
= pActMGroup
->Count();
2822 for (USHORT n
= 0; n
< nRowSpan
; ++n
)
2824 SwTableBox
* pCurrentBox
= (*pActMGroup
)[n
];
2825 const long nRowSpanSet
= n
== 0 ?
2827 ((-1) * (nRowSpan
- n
));
2828 pCurrentBox
->setRowSpan( nRowSpanSet
);
2832 pIo
->pFmtOfJustInsertedApo
= 0;
2833 DELETEZ( pMergeGroups
);
2838 // durchsucht pMergeGroups, meldet Index der ersten, passenden Gruppe bzw. -1
2840 // Parameter: nXcenter = Mittenposition der anfragenden Box
2841 // nWidth = Breite der anfragenden Box
2842 // bExact = Flag, ob Box in dieser Gruppe passen muss,
2843 // oder diese nur zu tangieren braucht
2845 bool WW8TabDesc::FindMergeGroup(short nX1
, short nWidth
, bool bExact
,
2851 // noch als gueltig angesehener Bereich in der Naehe der Grenzen
2852 const short nToleranz
= 4;
2853 // die aktuell untersuchte Gruppe
2854 WW8SelBoxInfoPtr pActGroup
;
2856 short nX2
= nX1
+ nWidth
;
2857 // ungefaehre Gruppengrenzen
2861 // --> OD 2005-02-04 #118544# - improvement: search backwards
2862 //for ( USHORT iGr = 0; iGr < pMergeGroups->Count(); iGr++ )
2863 for ( short iGr
= pMergeGroups
->Count() - 1; iGr
>= 0; --iGr
)
2865 // die aktuell untersuchte Gruppe
2866 pActGroup
= (*pMergeGroups
)[ iGr
];
2867 if (!pActGroup
->bGroupLocked
)
2869 // ungefaehre Gruppengrenzen mit Toleranz nach *aussen* hin
2870 nGrX1
= pActGroup
->nGroupXStart
- nToleranz
;
2871 nGrX2
= pActGroup
->nGroupXStart
2872 +pActGroup
->nGroupWidth
+ nToleranz
;
2874 // Falls Box reinpasst, melde auf jeden Fall den Erfolg
2876 if( ( nX1
> nGrX1
) && ( nX2
< nGrX2
) )
2878 nMGrIdx
= iGr
; break;
2881 // hat die Box Bereiche mit der Gruppe gemeinsam?
2885 // melde Erfolg, wenn nX1 *oder* nX2 innerhalb der Gruppe liegen
2886 if( ( ( nX1
> nGrX1
)
2887 && ( nX1
< nGrX2
- 2*nToleranz
) )
2888 || ( ( nX2
> nGrX1
+ 2*nToleranz
)
2889 && ( nX2
< nGrX2
) )
2890 // oder nX1 und nX2 die Gruppe umfassen
2891 || ( ( nX1
<=nGrX1
)
2892 && ( nX2
>=nGrX2
) ) )
2894 nMGrIdx
= iGr
; break;
2900 return ( -1 < nMGrIdx
);
2903 bool WW8TabDesc::IsValidCell(short nCol
) const
2905 return pActBand
->bExist
[nCol
] && (USHORT
)nAktRow
< pTabLines
->Count();
2908 bool WW8TabDesc::InFirstParaInCell() const
2911 if (!pTabBox
|| !pTabBox
->GetSttNd())
2913 ASSERT(false, "Problem with table");
2917 if (!IsValidCell(GetAktCol()))
2920 if (pIo
->pPaM
->GetPoint()->nNode
== pTabBox
->GetSttIdx() + 1)
2926 void WW8TabDesc::StartMiserableHackForUnsupportedDirection(short nWwCol
)
2928 ASSERT(pActBand
, "Impossible");
2929 if (pActBand
&& pActBand
->maDirections
[nWwCol
] == 3)
2931 pIo
->pCtrlStck
->NewAttr(*pIo
->pPaM
->GetPoint(),
2932 SvxCharRotateItem(900, false, RES_CHRATR_ROTATE
));
2936 void WW8TabDesc::EndMiserableHackForUnsupportedDirection(short nWwCol
)
2938 ASSERT(pActBand
, "Impossible");
2939 if (pActBand
&& pActBand
->maDirections
[nWwCol
] == 3)
2940 pIo
->pCtrlStck
->SetAttr(*pIo
->pPaM
->GetPoint(), RES_CHRATR_ROTATE
);
2943 bool WW8TabDesc::SetPamInCell(short nWwCol
, bool bPam
)
2945 ASSERT( pActBand
, "pActBand ist 0" );
2947 USHORT nCol
= pActBand
->nTransCell
[nWwCol
];
2949 if ((USHORT
)nAktRow
>= pTabLines
->Count())
2951 ASSERT(!this, "Actual row bigger than expected." );
2957 pTabLine
= (*pTabLines
)[nAktRow
];
2958 pTabBoxes
= &pTabLine
->GetTabBoxes();
2960 if (nCol
>= pTabBoxes
->Count())
2964 // The first paragraph in a cell with upper autospacing has upper
2967 pIo
->bParaAutoBefore
&& pIo
->bFirstPara
&&
2968 !pIo
->pWDop
->fDontUseHTMLAutoSpacing
2971 pIo
->SetUpperSpacing(*pIo
->pPaM
, 0);
2974 // The last paragraph in a cell with lower autospacing has lower
2976 if (pIo
->bParaAutoAfter
&& !pIo
->pWDop
->fDontUseHTMLAutoSpacing
)
2977 pIo
->SetLowerSpacing(*pIo
->pPaM
, 0);
2983 pTabBox
= (*pTabBoxes
)[nCol
];
2984 if( !pTabBox
->GetSttNd() )
2986 ASSERT(pTabBox
->GetSttNd(), "Probleme beim Aufbau der Tabelle");
2993 pAktWWCell
= &pActBand
->pTCs
[ nWwCol
];
2995 // The first paragraph in a cell with upper autospacing has upper spacing set to 0
2996 if(pIo
->bParaAutoBefore
&& pIo
->bFirstPara
&& !pIo
->pWDop
->fDontUseHTMLAutoSpacing
)
2997 pIo
->SetUpperSpacing(*pIo
->pPaM
, 0);
2999 // The last paragraph in a cell with lower autospacing has lower spacing set to 0
3000 if(pIo
->bParaAutoAfter
&& !pIo
->pWDop
->fDontUseHTMLAutoSpacing
)
3001 pIo
->SetLowerSpacing(*pIo
->pPaM
, 0);
3003 //We need to set the pPaM on the first cell, invalid
3004 //or not so that we can collect paragraph proproties over
3005 //all the cells, but in that case on the valid cell we do not
3006 //want to reset the fmt properties
3007 if (pIo
->pPaM
->GetPoint()->nNode
!= pTabBox
->GetSttIdx() + 1)
3009 pIo
->pPaM
->GetPoint()->nNode
= pTabBox
->GetSttIdx() + 1;
3010 pIo
->pPaM
->GetPoint()->nContent
.Assign(pIo
->pPaM
->GetCntntNode(), 0);
3011 // Zur Sicherheit schon jetzt setzen, da bei den Zellen, die
3012 // zum Randausgleich eingefuegt werden, sonst der Style
3013 // nicht gesetzt wird.
3014 pIo
->rDoc
.SetTxtFmtColl(*pIo
->pPaM
, (SwTxtFmtColl
*)pIo
->pDfltTxtFmtColl
);
3015 // uebrigens: da diese Zellen unsichtbare Hilfskonstruktionen sind,
3016 // und nur dazu dienen, zerfranste Aussehen der WW-Tabelle
3017 // nachzuahmen, braucht NICHT SetTxtFmtCollAndListLevel()
3018 // verwendet zu werden.
3021 // Better to turn Snap to Grid off for all paragraphs in tables
3022 if(SwTxtNode
*pNd
= pIo
->pPaM
->GetNode()->GetTxtNode())
3024 const SfxPoolItem
&rItm
= pNd
->SwCntntNode::GetAttr(RES_PARATR_SNAPTOGRID
);
3025 SvxParaGridItem
&rSnapToGrid
= (SvxParaGridItem
&)(rItm
);
3027 if(rSnapToGrid
.GetValue())
3029 SvxParaGridItem
aGridItem( rSnapToGrid
);
3030 aGridItem
.SetValue(false);
3032 SwPosition
* pGridPos
= pIo
->pPaM
->GetPoint();
3034 xub_StrLen nEnd
= pGridPos
->nContent
.GetIndex();
3035 pGridPos
->nContent
.Assign(pIo
->pPaM
->GetCntntNode(), 0);
3036 pIo
->pCtrlStck
->NewAttr(*pGridPos
, aGridItem
);
3037 pGridPos
->nContent
.Assign(pIo
->pPaM
->GetCntntNode(), nEnd
);
3038 pIo
->pCtrlStck
->SetAttr(*pGridPos
, RES_PARATR_SNAPTOGRID
);
3042 StartMiserableHackForUnsupportedDirection(nWwCol
);
3047 void WW8TabDesc::InsertCells( short nIns
)
3049 pTabLine
= (*pTabLines
)[nAktRow
];
3050 pTabBoxes
= &pTabLine
->GetTabBoxes();
3051 pTabBox
= (*pTabBoxes
)[0];
3053 pIo
->rDoc
.GetNodes().InsBoxen( pTblNd
, pTabLine
, (SwTableBoxFmt
*)pTabBox
->GetFrmFmt(),
3054 (SwTxtFmtColl
*)pIo
->pDfltTxtFmtColl
, 0, pTabBoxes
->Count(), nIns
);
3055 // mit dem Dritten Parameter wird das FrmFmt der Boxen angegeben.
3056 // hier kann man auch noch optimieren, um FrmFmts zu sparen
3059 void WW8TabDesc::SetTabBorders(SwTableBox
* pBox
, short nWwIdx
)
3061 if( nWwIdx
< 0 || nWwIdx
>= pActBand
->nWwCols
)
3062 return; // kuenstlich erzeugte Zellen -> Kein Rand
3065 SvxBoxItem
aFmtBox( RES_BOX
);
3066 if (pActBand
->pTCs
) // neither Cell Border nor Default Border defined ?
3068 WW8_TCell
* pT
= &pActBand
->pTCs
[nWwIdx
];
3069 if (pIo
->IsBorder(pT
->rgbrc
))
3070 pIo
->SetBorder(aFmtBox
, pT
->rgbrc
);
3073 if (pActBand
->nOverrideSpacing
[nWwIdx
] & (1 << WW8TabBandDesc::wwTOP
))
3075 aFmtBox
.SetDistance(
3076 pActBand
->nOverrideValues
[nWwIdx
][WW8TabBandDesc::wwTOP
],
3080 aFmtBox
.SetDistance(pActBand
->mnDefaultTop
, BOX_LINE_TOP
);
3081 if (pActBand
->nOverrideSpacing
[nWwIdx
] & (1 << WW8TabBandDesc::wwBOTTOM
))
3083 aFmtBox
.SetDistance(
3084 pActBand
->nOverrideValues
[nWwIdx
][WW8TabBandDesc::wwBOTTOM
],
3088 aFmtBox
.SetDistance(pActBand
->mnDefaultBottom
,BOX_LINE_BOTTOM
);
3090 // nGapHalf bedeutet bei WW ein *horizontaler* Abstand zwischen
3091 // Tabellenzelle und -Inhalt
3093 pActBand
->mbHasSpacing
? pActBand
->mnDefaultLeft
: pActBand
->nGapHalf
;
3095 pActBand
->mbHasSpacing
? pActBand
->mnDefaultRight
: pActBand
->nGapHalf
;
3096 if (pActBand
->nOverrideSpacing
[nWwIdx
] & (1 << WW8TabBandDesc::wwLEFT
))
3098 aFmtBox
.SetDistance(
3099 pActBand
->nOverrideValues
[nWwIdx
][WW8TabBandDesc::wwLEFT
],
3103 aFmtBox
.SetDistance(nLeftDist
, BOX_LINE_LEFT
);
3104 if (pActBand
->nOverrideSpacing
[nWwIdx
] & (1 << WW8TabBandDesc::wwRIGHT
))
3106 aFmtBox
.SetDistance(
3107 pActBand
->nOverrideValues
[nWwIdx
][WW8TabBandDesc::wwRIGHT
],
3111 aFmtBox
.SetDistance(nRightDist
,BOX_LINE_RIGHT
);
3113 pBox
->GetFrmFmt()->SetFmtAttr(aFmtBox
);
3116 void WW8TabDesc::SetTabShades( SwTableBox
* pBox
, short nWwIdx
)
3118 if( nWwIdx
< 0 || nWwIdx
>= pActBand
->nWwCols
)
3119 return; // kuenstlich erzeugte Zellen -> Keine Farbe
3122 if (pActBand
->pNewSHDs
&& pActBand
->pNewSHDs
[nWwIdx
] != COL_AUTO
)
3124 Color
aColor(pActBand
->pNewSHDs
[nWwIdx
]);
3125 if (aColor
.GetColor() == 0x00333333)
3126 pIo
->maTracer
.Log(sw::log::eAutoColorBg
);
3127 pBox
->GetFrmFmt()->SetFmtAttr(SvxBrushItem(aColor
, RES_BACKGROUND
));
3131 //If there was no new shades, or no new shade setting
3132 if (pActBand
->pSHDs
&& !bFound
)
3134 WW8_SHD
& rSHD
= pActBand
->pSHDs
[nWwIdx
];
3135 if (!rSHD
.GetValue()) // auto
3138 SwWW8Shade
aSh( pIo
->bVer67
, rSHD
);
3139 pBox
->GetFrmFmt()->SetFmtAttr(SvxBrushItem(aSh
.aColor
, RES_BACKGROUND
));
3143 SvxFrameDirection
MakeDirection(sal_uInt16 nCode
, BOOL bIsBiDi
)
3145 SvxFrameDirection eDir
= FRMDIR_ENVIRONMENT
;
3146 // 1: Asian layout with rotated CJK characters
3148 // 3: Western layout rotated by 90 degrees
3149 // 4: Western layout
3153 ASSERT(eDir
== 4, "unknown direction code, maybe its a bitfield");
3155 // --> FME/Alan Yaniger: 2006-09-15 #i38158# Consider RTL tables:
3156 eDir
= bIsBiDi
? FRMDIR_HORI_RIGHT_TOP
: FRMDIR_HORI_LEFT_TOP
;
3160 eDir
= FRMDIR_VERT_TOP_RIGHT
;
3163 eDir
= FRMDIR_VERT_TOP_RIGHT
;
3166 // --> FME/Alan Yaniger: 2006-09-15 #i38158# Consider RTL tables:
3167 eDir
= bIsBiDi
? FRMDIR_HORI_RIGHT_TOP
: FRMDIR_HORI_LEFT_TOP
;
3174 void WW8TabDesc::SetTabDirection(SwTableBox
* pBox
, short nWwIdx
)
3176 if (nWwIdx
< 0 || nWwIdx
>= pActBand
->nWwCols
)
3178 SvxFrameDirectionItem
aItem(MakeDirection(pActBand
->maDirections
[nWwIdx
], bIsBiDi
), RES_FRAMEDIR
);
3179 pBox
->GetFrmFmt()->SetFmtAttr(aItem
);
3182 void WW8TabDesc::SetTabVertAlign( SwTableBox
* pBox
, short nWwIdx
)
3184 if( nWwIdx
< 0 || nWwIdx
>= pActBand
->nWwCols
)
3187 sal_Int16 eVertOri
=text::VertOrientation::TOP
;
3189 if( pActBand
->pTCs
)
3191 WW8_TCell
* pT
= &pActBand
->pTCs
[nWwIdx
];
3192 switch (pT
->nVertAlign
)
3196 eVertOri
= text::VertOrientation::TOP
;
3199 eVertOri
= text::VertOrientation::CENTER
;
3202 eVertOri
= text::VertOrientation::BOTTOM
;
3207 pBox
->GetFrmFmt()->SetFmtAttr( SwFmtVertOrient(0,eVertOri
) );
3210 void WW8TabDesc::AdjustNewBand()
3212 if( pActBand
->nSwCols
> nDefaultSwCols
) // Zellen splitten
3213 InsertCells( pActBand
->nSwCols
- nDefaultSwCols
);
3215 SetPamInCell( 0, false);
3216 ASSERT( pTabBoxes
&& pTabBoxes
->Count() == (USHORT
)pActBand
->nSwCols
,
3217 "Falsche Spaltenzahl in Tabelle" )
3221 pTabLine
->ClaimFrmFmt(); // noetig wg. Zeilenhoehe
3222 SwFmtFrmSize
aF( ATT_MIN_SIZE
, 0, 0 ); // default
3224 if (pActBand
->nLineHeight
== 0) // 0 = Auto
3225 aF
.SetHeightSizeType( ATT_VAR_SIZE
);
3228 if (pActBand
->nLineHeight
< 0) // Pos = min, Neg = exakt
3230 aF
.SetHeightSizeType(ATT_FIX_SIZE
);
3231 pActBand
->nLineHeight
= -pActBand
->nLineHeight
;
3233 if (pActBand
->nLineHeight
< MINLAY
) // nicht erlaubte Zeilenhoehe
3234 pActBand
->nLineHeight
= MINLAY
;
3236 aF
.SetHeight(pActBand
->nLineHeight
);// Min- / Exakt-Hoehe setzen
3238 pTabLine
->GetFrmFmt()->SetFmtAttr(aF
);
3241 //Word stores 1 for bCantSplit if the row cannot be split, we set true if
3242 //we can split the row
3243 // bCantSplit: Always true for rows containing merged cells (Word <= 2000 crashes otherwise)
3244 // So in case bCantSplit is true, we check for bCantSplit90, which has been introduced for
3245 // Word versions >= 2002.
3246 bool bSetCantSplit
= pActBand
->bCantSplit
;
3248 bSetCantSplit
= pActBand
->bCantSplit90
;
3250 pTabLine
->GetFrmFmt()->SetFmtAttr(SwFmtRowSplit(!bSetCantSplit
));
3252 short i
; // SW-Index
3253 short j
; // WW-Index
3255 SwFmtFrmSize
aFS( ATT_FIX_SIZE
);
3256 j
= pActBand
->bLEmptyCol
? -1 : 0;
3258 for( i
= 0; i
< pActBand
->nSwCols
; i
++ )
3260 // setze Zellenbreite
3262 nW
= pActBand
->nCenter
[0] - nMinLeft
;
3265 //Set j to first non invalid cell
3266 while ((j
< pActBand
->nWwCols
) && (!pActBand
->bExist
[j
]))
3269 if( j
< pActBand
->nWwCols
)
3270 nW
= pActBand
->nCenter
[j
+1] - pActBand
->nCenter
[j
];
3272 nW
= nMaxRight
- pActBand
->nCenter
[j
];
3273 pActBand
->nWidth
[ j
] = nW
;
3276 SwTableBox
* pBox
= (*pTabBoxes
)[i
];
3277 // liesse sich durch intelligentes Umhaengen der FrmFmts noch weiter
3279 pBox
->ClaimFrmFmt();
3281 SetTabBorders(pBox
, j
);
3283 // #i18128# word has only one line between adjoining vertical cells
3284 // we have to mimick this in the filter by picking the larger of the
3285 // sides and using that one on one side of the line (right)
3286 SvxBoxItem
aCurrentBox(sw::util::ItemGet
<SvxBoxItem
>(*(pBox
->GetFrmFmt()), RES_BOX
));
3287 const SvxBorderLine
*pLeftLine
= aCurrentBox
.GetLine(BOX_LINE_LEFT
);
3288 int nCurrentRightLineWidth
= 0;
3290 nCurrentRightLineWidth
= pLeftLine
->GetInWidth() + pLeftLine
->GetOutWidth() + pLeftLine
->GetDistance();
3294 SwTableBox
* pBox2
= (*pTabBoxes
)[i
-1];
3295 SvxBoxItem
aOldBox(sw::util::ItemGet
<SvxBoxItem
>(*(pBox2
->GetFrmFmt()), RES_BOX
));
3296 const SvxBorderLine
*pRightLine
= aOldBox
.GetLine(BOX_LINE_RIGHT
);
3297 int nOldBoxRightLineWidth
= 0;
3299 nOldBoxRightLineWidth
= pRightLine
->GetInWidth() + pRightLine
->GetOutWidth() + pRightLine
->GetDistance();
3301 if(nOldBoxRightLineWidth
>nCurrentRightLineWidth
)
3302 aCurrentBox
.SetLine(aOldBox
.GetLine(BOX_LINE_RIGHT
), BOX_LINE_LEFT
);
3304 aOldBox
.SetLine(0, BOX_LINE_RIGHT
);
3305 pBox2
->GetFrmFmt()->SetFmtAttr(aOldBox
);
3308 pBox
->GetFrmFmt()->SetFmtAttr(aCurrentBox
);
3310 SetTabVertAlign(pBox
, j
);
3311 SetTabDirection(pBox
, j
);
3312 if( pActBand
->pSHDs
|| pActBand
->pNewSHDs
)
3313 SetTabShades(pBox
, j
);
3317 pBox
->GetFrmFmt()->SetFmtAttr( aFS
);
3319 // ueberspringe nicht existente Zellen
3320 while( ( j
< pActBand
->nWwCols
) && !pActBand
->bExist
[j
] )
3322 pActBand
->nWidth
[j
] = pActBand
->nCenter
[j
+1] - pActBand
->nCenter
[j
];
3328 void WW8TabDesc::TableCellEnd()
3330 ::SetProgressState(pIo
->nProgress
, pIo
->mpDocShell
); // Update
3332 EndMiserableHackForUnsupportedDirection(nAktCol
);
3335 if( pIo
->bWasTabRowEnd
)
3337 // bWasTabRowEnd will be deactivated in
3338 // SwWW8ImplReader::ProcessSpecial()
3340 USHORT iCol
= GetLogicalWWCol();
3341 if (iCol
< aNumRuleNames
.size())
3343 aNumRuleNames
.erase(aNumRuleNames
.begin() + iCol
,
3344 aNumRuleNames
.end());
3350 ASSERT( pActBand
, "pActBand ist 0" );
3353 if( nAktRow
>= nRows
) // am Tabellenende gibt's nichts sinnvolles
3354 return; // mehr zu tun
3356 bool bNewBand
= nAktBandRow
>= pActBand
->nRows
;
3358 { // neues Band noetig ?
3359 pActBand
= pActBand
->pNextBand
; //
3361 ASSERT( pActBand
, "pActBand ist 0" );
3366 SwTableBox
* pBox
= (*pTabBoxes
)[0];
3368 pIo
->rDoc
.InsertRow( pTable
->SelLineFromBox( pBox
, aBoxes
) );
3373 { // neue Spalte ( Zelle )
3376 SetPamInCell(nAktCol
, true);
3378 // finish Annotated Level Numbering ?
3379 if (pIo
->bAnl
&& !pIo
->bAktAND_fNumberAcross
)
3380 pIo
->StopAllAnl(IsValidCell(nAktCol
));
3383 // ggfs. die Box in fuer diese Col offene Merge-Gruppe eintragen
3384 SwTableBox
* WW8TabDesc::UpdateTableMergeGroup( WW8_TCell
& rCell
,
3385 WW8SelBoxInfo
* pActGroup
,
3386 SwTableBox
* pActBox
,
3389 // Rueckgabewert defaulten
3390 SwTableBox
* pResult
= 0;
3392 // pruefen, ob die Box zu mergen ist
3393 // --> OD 2005-02-04 #118544# - If cell is the first one to be merged,
3394 // a new merge group has to be provided.
3395 // E.g., it could be that a cell is the first one to be merged, but no
3396 // new merge group is provided, because the potential other cell to be merged
3397 // doesn't exist - see method <WW8TabDesc::MergeCells>.
3398 if ( pActBand
->bExist
[ nCol
] &&
3399 ( ( rCell
.bFirstMerged
&& pActGroup
) ||
3402 rCell
.bVertRestart
) )
3405 // passende Merge-Gruppe ermitteln
3406 WW8SelBoxInfo
* pTheMergeGroup
= 0;
3408 // Gruppe uebernehmen
3409 pTheMergeGroup
= pActGroup
;
3414 if( FindMergeGroup( pActBand
->nCenter
[ nCol
],
3415 pActBand
->nWidth
[ nCol
], true, nMGrIdx
) )
3416 pTheMergeGroup
= (*pMergeGroups
)[ nMGrIdx
];
3418 if( pTheMergeGroup
)
3420 // aktuelle Box der Merge-Gruppe hinzufuegen
3421 pTheMergeGroup
->Insert( pActBox
, pTheMergeGroup
->Count() );
3423 // Target-Box zurueckmelden
3424 pResult
= (*pTheMergeGroup
)[ 0 ];
3431 USHORT
WW8TabDesc::GetLogicalWWCol() const // returns number of col as INDICATED within WW6 UI status line -1
3434 if( pActBand
&& pActBand
->pTCs
)
3436 for( USHORT iCol
= 1; iCol
<= nAktCol
; ++iCol
)
3438 if( !pActBand
->pTCs
[ iCol
-1 ].bMerged
)
3445 // find name of numrule valid for current WW-COL
3446 const String
& WW8TabDesc::GetNumRuleName() const
3448 USHORT nCol
= GetLogicalWWCol();
3449 if (nCol
< aNumRuleNames
.size())
3450 return aNumRuleNames
[nCol
];
3455 void WW8TabDesc::SetNumRuleName( const String
& rName
)
3457 USHORT nCol
= GetLogicalWWCol();
3458 for (USHORT nSize
= static_cast< USHORT
>(aNumRuleNames
.size()); nSize
<= nCol
; ++nSize
)
3459 aNumRuleNames
.push_back(aEmptyStr
);
3460 aNumRuleNames
[nCol
] = rName
;
3463 bool SwWW8ImplReader::StartTable(WW8_CP nStartCp
)
3465 // Entering a table so make sure the the FirstPara flag gets set
3467 // keine rekursiven Tabellen Nicht bei EinfuegenDatei in Tabelle oder
3473 maTableStack
.push(pTableDesc
);
3475 // --> OD 2005-01-27 #i33818# - determine absolute position object attributes,
3476 // if possible. It's needed for nested tables.
3477 WW8FlyPara
* pTableWFlyPara( 0L );
3478 WW8SwFlyPara
* pTableSFlyPara( 0L );
3479 // --> OD 2005-03-21 #i45301# - anchor nested table inside Writer fly frame
3480 // only at-character, if absolute position object attributes are available.
3481 // Thus, default anchor type is as-character anchored.
3482 RndStdIds
eAnchor( FLY_AS_CHAR
);
3486 WW8_TablePos
* pNestedTabPos( 0L );
3487 WW8_TablePos aNestedTabPos
;
3488 WW8PLCFxSave1 aSave
;
3489 pPlcxMan
->GetPap()->Save( aSave
);
3490 WW8PLCFx_Cp_FKP
* pPap
= pPlcxMan
->GetPapPLCF();
3491 WW8_CP nMyStartCp
= nStartCp
;
3492 if ( SearchRowEnd( pPap
, nMyStartCp
, nInTable
) &&
3493 ParseTabPos( &aNestedTabPos
, pPap
) )
3495 pNestedTabPos
= &aNestedTabPos
;
3497 pPlcxMan
->GetPap()->Restore( aSave
);
3498 if ( pNestedTabPos
)
3500 ApoTestResults aApo
= TestApo( nInTable
+ 1, false, pNestedTabPos
);
3501 pTableWFlyPara
= ConstructApo( aApo
, pNestedTabPos
);
3502 if ( pTableWFlyPara
)
3504 // --> OD 2007-07-03 #148498#
3505 // <WW8SwFlyPara> constructor has changed - new 4th parameter
3506 // containing WW8 page top margin.
3507 pTableSFlyPara
= new WW8SwFlyPara(*pPaM
, *this, *pTableWFlyPara
,
3508 maSectionManager
.GetWWPageTopMargin(),
3509 maSectionManager
.GetPageLeft(), maSectionManager
.GetTextAreaWidth(),
3510 nIniFlyDx
, nIniFlyDy
);
3512 // --> OD 2005-03-21 #i45301# - anchor nested table Writer fly
3513 // frame at-character
3514 eAnchor
= FLY_AT_CHAR
;
3521 pTableDesc
= new WW8TabDesc( this, nStartCp
);
3523 if( pTableDesc
->Ok() )
3525 int nNewInTable
= nInTable
+ 1;
3526 if (InEqualApo(nNewInTable
))
3528 ASSERT(pSFlyPara
->pFlyFmt
,
3529 "how could we be in a local apo and have no apo");
3532 if ((eAnchor
== FLY_AT_CHAR
)
3533 && !maTableStack
.empty() && !InEqualApo(nNewInTable
) )
3535 pTableDesc
->pParentPos
= new SwPosition(*pPaM
->GetPoint());
3536 SfxItemSet
aItemSet(rDoc
.GetAttrPool(),
3537 RES_FRMATR_BEGIN
, RES_FRMATR_END
-1);
3538 // --> OD 2005-01-26 #i33818# - anchor the Writer fly frame for
3539 // the nested table at-character.
3540 // --> OD 2005-03-21 #i45301#
3541 SwFmtAnchor
aAnchor( eAnchor
);
3542 aAnchor
.SetAnchor( pTableDesc
->pParentPos
);
3543 aItemSet
.Put( aAnchor
);
3544 pTableDesc
->pFlyFmt
= rDoc
.MakeFlySection( eAnchor
,
3545 pTableDesc
->pParentPos
, &aItemSet
);
3546 ASSERT( pTableDesc
->pFlyFmt
->GetAnchor().GetAnchorId() == eAnchor
,
3547 "Not the anchor type requested!" );
3549 MoveInsideFly(pTableDesc
->pFlyFmt
);
3551 pTableDesc
->CreateSwTable();
3552 if (pTableDesc
->pFlyFmt
)
3554 pTableDesc
->SetSizePosition(pTableDesc
->pFlyFmt
);
3555 // --> OD 2005-01-26 #i33818# - Use absolute position object
3556 // attributes, if existing, and apply them to the created Writer fly
3558 if ( pTableWFlyPara
&& pTableSFlyPara
)
3560 WW8FlySet
aFlySet( *this, pTableWFlyPara
, pTableSFlyPara
, false );
3561 SwFmtAnchor
aAnchor( FLY_AT_CHAR
);
3562 aAnchor
.SetAnchor( pTableDesc
->pParentPos
);
3563 aFlySet
.Put( aAnchor
);
3564 pTableDesc
->pFlyFmt
->SetFmtAttr( aFlySet
);
3568 SwFmtHoriOrient aHori
=
3569 pTableDesc
->pTable
->GetFrmFmt()->GetHoriOrient();
3570 pTableDesc
->pFlyFmt
->SetFmtAttr(aHori
);
3571 pTableDesc
->pFlyFmt
->SetFmtAttr( SwFmtSurround( SURROUND_NONE
) );
3574 // --> OD 2005-01-27 #i33818# - The nested table doesn't have to leave
3575 // the table cell. Thus, the Writer fly frame has to follow the text flow.
3576 pTableDesc
->pFlyFmt
->SetFmtAttr( SwFmtFollowTextFlow( TRUE
) );
3580 pTableDesc
->SetSizePosition(0);
3581 pTableDesc
->UseSwTable();
3586 // --> OD 2005-01-28 #i33818#
3587 delete pTableWFlyPara
;
3588 delete pTableSFlyPara
;
3591 bool bSuccess
= (0 != pTableDesc
);
3594 maTracer
.EnterEnvironment(sw::log::eTable
, rtl::OUString::valueOf(
3595 static_cast<sal_Int32
>(maTableStack
.size())));
3600 bool lcl_PamContainsFly(SwPaM
& rPam
)
3602 bool bResult
= false;
3603 SwNodeRange
aRg( rPam
.Start()->nNode
, rPam
.End()->nNode
);
3604 SwDoc
* pDoc
= rPam
.GetDoc();
3607 SwSpzFrmFmts
* pSpzFmts
= pDoc
->GetSpzFrmFmts();
3608 sal_uInt16 nCount
= pSpzFmts
->Count();
3609 while (!bResult
&& n
< nCount
)
3611 SwFrmFmt
* pFly
= (*pSpzFmts
)[n
];
3612 const SwFmtAnchor
* pAnchor
= &pFly
->GetAnchor();
3614 switch (pAnchor
->GetAnchorId())
3619 const SwPosition
* pAPos
= pAnchor
->GetCntntAnchor();
3621 if (pAPos
!= NULL
&&
3622 aRg
.aStart
<= pAPos
->nNode
&&
3623 pAPos
->nNode
<= aRg
.aEnd
)
3639 void SwWW8ImplReader::TabCellEnd()
3641 if (nInTable
&& pTableDesc
)
3643 pTableDesc
->TableCellEnd();
3646 && pWFlyPara
== NULL
3647 && mpTableEndPaM
.get() != NULL
3648 && (! SwPaM::Overlap(*pPaM
, *mpTableEndPaM
))
3649 && SwPaM::LessThan(*mpTableEndPaM
, *pPaM
)
3650 && mpTableEndPaM
->GetPoint()->nNode
.GetNode().IsTxtNode()
3651 && !lcl_PamContainsFly(*mpTableEndPaM
)
3654 rDoc
.DelFullPara(*mpTableEndPaM
);
3658 bFirstPara
= true; // We have come to the end of a cell so FirstPara flag
3660 mpTableEndPaM
.reset();
3663 void SwWW8ImplReader::Read_TabCellEnd( USHORT
, const BYTE
* pData
, short nLen
)
3665 if( ( nLen
> 0 ) && ( *pData
== 1 ) )
3666 bWasTabCellEnd
= true;
3669 void SwWW8ImplReader::Read_TabRowEnd( USHORT
, const BYTE
* pData
, short nLen
) // Sprm25
3671 if( ( nLen
> 0 ) && ( *pData
== 1 ) )
3672 bWasTabRowEnd
= true;
3675 void SwWW8ImplReader::PopTableDesc()
3677 if (pTableDesc
&& pTableDesc
->pFlyFmt
)
3679 MoveOutsideFly(pTableDesc
->pFlyFmt
,*pTableDesc
->pParentPos
);
3683 if (maTableStack
.empty())
3687 pTableDesc
= maTableStack
.top();
3692 void SwWW8ImplReader::StopTable()
3694 maTracer
.LeaveEnvironment(sw::log::eTable
);
3696 ASSERT(pTableDesc
, "Panic, stop table with no table!");
3700 // We are leaving a table so make sure the next paragraph doesn't think
3701 // it's the first paragraph
3704 pTableDesc
->FinishSwTable();
3707 if (!maTableStack
.empty())
3709 maTracer
.EnterEnvironment(sw::log::eTable
, rtl::OUString::valueOf(
3710 static_cast<sal_Int32
>(maTableStack
.size())));
3714 // --> OD 2009-04-16 #i101116#
3715 // Keep PaM on table end only for nested tables
3718 mpTableEndPaM
.reset(new SwPaM(*pPaM
));
3723 // GetTableLeft() wird fuer absatzgebundene Grafikobjekte in Tabellen
3725 // WW nimmt bei eingerueckten Tabellen den Absatzrand, der ohne Tabelle
3726 // gueltig waere, als Basis; SW benutzt den linken Tabellenrand.
3727 short SwWW8ImplReader::GetTableLeft()
3729 return (pTableDesc
) ? pTableDesc
->GetMinLeft() : 0;
3732 bool SwWW8ImplReader::IsInvalidOrToBeMergedTabCell() const
3737 const WW8_TCell
* pCell
= pTableDesc
->GetAktWWCell();
3739 return !pTableDesc
->IsValidCell( pTableDesc
->GetAktCol() )
3741 && ( !pCell
->bFirstMerged
3743 || ( pCell
->bVertMerge
3744 && !pCell
->bVertRestart
3751 USHORT
SwWW8ImplReader::StyleUsingLFO( USHORT nLFOIndex
) const
3753 USHORT nRes
= USHRT_MAX
;
3756 for(USHORT nI
= 0; nI
< pStyles
->GetCount(); nI
++ )
3757 if( pCollA
[ nI
].bValid
3758 && (nLFOIndex
== pCollA
[ nI
].nLFOIndex
) )
3764 const SwFmt
* SwWW8ImplReader::GetStyleWithOrgWWName( String
& rName
) const
3769 for(USHORT nI
= 0; nI
< pStyles
->GetCount(); nI
++ )
3770 if( pCollA
[ nI
].bValid
3771 && (rName
.Equals( pCollA
[ nI
].GetOrgWWName())) )
3773 pRet
= pCollA
[ nI
].pFmt
;
3780 //-----------------------------------------
3782 //-----------------------------------------
3784 const BYTE
* WW8RStyle::HasParaSprm( USHORT nId
) const
3786 if( !pParaSprms
|| !nSprmsLen
)
3789 const BYTE
* pSprms
= pParaSprms
;
3792 for( i
=0; i
< nSprmsLen
; )
3794 USHORT nAktId
= maSprmParser
.GetSprmId(pSprms
);
3797 return pSprms
+ maSprmParser
.DistanceToData(nId
);
3799 x
= maSprmParser
.GetSprmSize(nAktId
, pSprms
);
3803 return 0; // Sprm not found
3806 void WW8RStyle::ImportSprms(BYTE
*pSprms
, short nLen
, bool bPap
)
3813 pParaSprms
= pSprms
; // fuer HasParaSprms()
3819 USHORT nL1
= pIo
->ImportSprm(pSprms
);
3828 void WW8RStyle::ImportSprms(sal_Size nPosFc
, short nLen
, bool bPap
)
3833 BYTE
*pSprms
= new BYTE
[nLen
];
3835 pStStrm
->Seek(nPosFc
);
3836 pStStrm
->Read(pSprms
, nLen
);
3838 ImportSprms(pSprms
, nLen
, bPap
);
3843 static inline short WW8SkipOdd(SvStream
* pSt
)
3845 if ( pSt
->Tell() & 0x1 )
3854 static inline short WW8SkipEven(SvStream
* pSt
)
3856 if (!(pSt
->Tell() & 0x1))
3865 short WW8RStyle::ImportUPX(short nLen
, bool bPAP
, bool bOdd
)
3869 if( 0 < nLen
) // Empty ?
3872 nLen
= nLen
- WW8SkipEven( pStStrm
);
3874 nLen
= nLen
- WW8SkipOdd( pStStrm
);
3881 cbUPX
= nLen
; // !cbUPX auf nLen verkleinert!
3883 if( (1 < cbUPX
) || ( (0 < cbUPX
) && !bPAP
) )
3896 sal_Size nPos
= pStStrm
->Tell(); // falls etwas falsch interpretiert
3897 // wird, gehts danach wieder richtig
3898 ImportSprms( nPos
, cbUPX
, bPAP
);
3900 if ( pStStrm
->Tell() != nPos
+ cbUPX
)
3901 pStStrm
->Seek( nPos
+cbUPX
);
3903 nLen
= nLen
- cbUPX
;
3910 void WW8RStyle::ImportGrupx(short nLen
, bool bPara
, bool bOdd
)
3915 nLen
= nLen
- WW8SkipEven( pStStrm
);
3917 nLen
= nLen
- WW8SkipOdd( pStStrm
);
3919 if( bPara
) // Grupx.Papx
3920 nLen
= ImportUPX(nLen
, true, bOdd
);
3921 ImportUPX(nLen
, false, bOdd
); // Grupx.Chpx
3924 WW8RStyle::WW8RStyle(WW8Fib
& _rFib
, SwWW8ImplReader
* pI
)
3925 : WW8Style(*pI
->pTableStream
, _rFib
), maSprmParser(_rFib
.GetFIBVersion()),
3926 pIo(pI
), pStStrm(pI
->pTableStream
), pStyRule(0), nWwNumLevel(0)
3929 pIo
->pCollA
= cstd
? new SwWW8StyInf
[ cstd
] : NULL
; // Style-UEbersetzung WW->SW
3932 void WW8RStyle::Set1StyleDefaults()
3934 if (!bCJKFontChanged
) // Style no CJK Font? set the default
3935 pIo
->SetNewFontAttr(ftcStandardChpCJKStsh
, true, RES_CHRATR_CJK_FONT
);
3938 const WW8_FFN
* pF
= pIo
->pFonts
->GetFont(3);
3941 rtl_TextEncoding eEnc
= WW8Fib::GetFIBCharset(pF
->chs
);
3942 if ((ftcStandardChpCTLStsh
== 0) && (eEnc
== RTL_TEXTENCODING_MS_1255
))
3943 ftcStandardChpCTLStsh
= 3;
3946 if (ftcStandardChpCJKStsh
== 0)
3947 ftcStandardChpCJKStsh
= 2;
3949 if (!bCTLFontChanged
) // Style no CTL Font? set the default
3950 pIo
->SetNewFontAttr(ftcStandardChpCTLStsh
, true, RES_CHRATR_CTL_FONT
);
3952 //#88976# western 2nd to make western charset conversion the default
3953 if (!bFontChanged
) // Style has no Font? set the default,
3955 pIo
->SetNewFontAttr(ftcStandardChpStsh
, true, RES_CHRATR_FONT
);
3956 /* removed by a patch from cmc for #i52786#
3958 SetStyleCharSet(pIo->pCollA[pIo->nAktColl]);
3962 if( !pIo
->bNoAttrImport
)
3964 // Style has no text color set, winword default is auto
3965 if ( !bTxtColChanged
)
3966 pIo
->pAktColl
->SetFmtAttr(SvxColorItem(Color(COL_AUTO
), RES_CHRATR_COLOR
));
3968 // Style has no FontSize ? WinWord Default is 10pt for western and asian
3969 if( !bFSizeChanged
)
3971 SvxFontHeightItem
aAttr(200, 100, RES_CHRATR_FONTSIZE
);
3972 pIo
->pAktColl
->SetFmtAttr(aAttr
);
3973 aAttr
.SetWhich(RES_CHRATR_CJK_FONTSIZE
);
3974 pIo
->pAktColl
->SetFmtAttr(aAttr
);
3977 // Style has no FontSize ? WinWord Default is 10pt for western and asian
3978 if( !bFCTLSizeChanged
)
3980 SvxFontHeightItem
aAttr(200, 100, RES_CHRATR_FONTSIZE
);
3981 aAttr
.SetWhich(RES_CHRATR_CTL_FONTSIZE
);
3982 pIo
->pAktColl
->SetFmtAttr(aAttr
);
3985 if( pIo
->pWDop
->fWidowControl
&& !bWidowsChanged
) // Widows ?
3987 pIo
->pAktColl
->SetFmtAttr( SvxWidowsItem( 2, RES_PARATR_WIDOWS
) );
3988 pIo
->pAktColl
->SetFmtAttr( SvxOrphansItem( 2, RES_PARATR_ORPHANS
) );
3993 bool WW8RStyle::PrepareStyle(SwWW8StyInf
&rSI
, ww::sti eSti
, sal_uInt16 nThisStyle
, sal_uInt16 nNextStyle
)
4000 sw::util::ParaStyleMapper::StyleResult aResult
=
4001 pIo
->maParaStyleMapper
.GetStyle(rSI
.GetOrgWWName(), eSti
);
4002 pColl
= aResult
.first
;
4003 bStyExist
= aResult
.second
;
4008 sw::util::CharStyleMapper::StyleResult aResult
=
4009 pIo
->maCharStyleMapper
.GetStyle(rSI
.GetOrgWWName(), eSti
);
4010 pColl
= aResult
.first
;
4011 bStyExist
= aResult
.second
;
4014 bool bImport
= !bStyExist
|| pIo
->mbNewDoc
; // Inhalte Importieren ?
4015 bool bOldNoImp
= pIo
->bNoAttrImport
;
4016 rSI
.bImportSkipped
= !bImport
;
4019 pIo
->bNoAttrImport
= true;
4024 // --> OD 2007-01-25 #i73790# - method renamed
4025 pColl
->ResetAllFmtAttr();
4028 pColl
->SetAuto(false); // nach Empfehlung JP
4029 } // macht die UI aber anders
4030 pIo
->pAktColl
= pColl
;
4031 rSI
.pFmt
= pColl
; // UEbersetzung WW->SW merken
4032 rSI
.bImportSkipped
= !bImport
;
4034 // Set Based on style
4035 USHORT j
= rSI
.nBase
;
4036 if (j
!= nThisStyle
&& j
< cstd
)
4038 SwWW8StyInf
* pj
= &pIo
->pCollA
[j
];
4039 if (rSI
.pFmt
&& pj
->pFmt
&& rSI
.bColl
== pj
->bColl
)
4041 rSI
.pFmt
->SetDerivedFrom( pj
->pFmt
); // ok, Based on eintragen
4042 rSI
.eLTRFontSrcCharSet
= pj
->eLTRFontSrcCharSet
;
4043 rSI
.eRTLFontSrcCharSet
= pj
->eRTLFontSrcCharSet
;
4044 rSI
.eCJKFontSrcCharSet
= pj
->eCJKFontSrcCharSet
;
4045 rSI
.n81Flags
= pj
->n81Flags
;
4046 rSI
.n81BiDiFlags
= pj
->n81BiDiFlags
;
4047 rSI
.nOutlineLevel
= pj
->nOutlineLevel
;
4048 rSI
.bParaAutoBefore
= pj
->bParaAutoBefore
;
4049 rSI
.bParaAutoAfter
= pj
->bParaAutoAfter
;
4052 rSI
.pWWFly
= new WW8FlyPara(pIo
->bVer67
, pj
->pWWFly
);
4055 else if( pIo
->mbNewDoc
&& bStyExist
)
4056 rSI
.pFmt
->SetDerivedFrom(0);
4058 rSI
.nFollow
= nNextStyle
; // Follow merken
4060 pStyRule
= 0; // falls noetig, neu anlegen
4061 bTxtColChanged
= bFontChanged
= bCJKFontChanged
= bCTLFontChanged
=
4062 bFSizeChanged
= bFCTLSizeChanged
= bWidowsChanged
= false;
4063 pIo
->SetNAktColl( nThisStyle
);
4064 pIo
->bStyNormal
= nThisStyle
== 0;
4068 void WW8RStyle::PostStyle(SwWW8StyInf
&rSI
, bool bOldNoImp
)
4070 // Alle moeglichen Attribut-Flags zuruecksetzen,
4071 // da es in Styles keine Attr-Enden gibt
4073 pIo
->bHasBorder
= pIo
->bShdTxtCol
= pIo
->bCharShdTxtCol
4074 = pIo
->bSpec
= pIo
->bObj
= pIo
->bSymbol
= false;
4077 // If Style basiert auf Nichts oder Basis ignoriert
4078 if ((rSI
.nBase
>= cstd
|| pIo
->pCollA
[rSI
.nBase
].bImportSkipped
) && rSI
.bColl
)
4080 //! Char-Styles funktionieren aus
4081 // unerfindlichen Gruenden nicht
4082 // -> dann evtl. harte WW-Defaults
4084 Set1StyleDefaults();
4087 pStyRule
= 0; // zur Sicherheit
4088 pIo
->bStyNormal
= false;
4089 pIo
->SetNAktColl( 0 );
4090 pIo
->bNoAttrImport
= bOldNoImp
;
4091 // rasch nochmal die Listen-Merk-Felder zuruecksetzen,
4092 // fuer den Fall dass sie beim einlesen des Styles verwendet wurden
4093 pIo
->nLFOPosition
= USHRT_MAX
;
4094 pIo
->nListLevel
= WW8ListManager::nMaxLevel
;
4097 void WW8RStyle::Import1Style( USHORT nNr
)
4099 SwWW8StyInf
&rSI
= pIo
->pCollA
[nNr
];
4101 if( rSI
.bImported
|| !rSI
.bValid
)
4104 rSI
.bImported
= true; // jetzt schon Flag setzen
4105 // verhindert endlose Rekursion
4107 // gueltig und nicht NIL und noch nicht Importiert
4109 if( rSI
.nBase
< cstd
&& !pIo
->pCollA
[rSI
.nBase
].bImported
)
4110 Import1Style( rSI
.nBase
);
4112 pStStrm
->Seek( rSI
.nFilePos
);
4117 WW8_STD
* pStd
= Read1Style( nSkip
, &sName
, &cbStd
);// lies Style
4120 rSI
.SetOrgWWIdent( sName
, pStd
->sti
);
4122 // either no Name or unused Slot or unknown Style
4124 if ( !pStd
|| (0 == sName
.Len()) || ((1 != pStd
->sgc
) && (2 != pStd
->sgc
)) )
4126 pStStrm
->SeekRel( nSkip
);
4130 bool bOldNoImp
= PrepareStyle(rSI
, static_cast<ww::sti
>(pStd
->sti
), nNr
, pStd
->istdNext
);
4132 // falls etwas falsch interpretiert wird, gehts danach wieder richtig
4133 long nPos
= pStStrm
->Tell();
4135 //Variable parts of the STD start at even byte offsets, but "inside
4136 //the STD", which I take to meaning even in relation to the starting
4137 //position of the STD, which matches findings in #89439#, generally it
4138 //doesn't matter as the STSHI starts off nearly always on an even
4141 //Import of the Style Contents
4142 ImportGrupx(nSkip
, pStd
->sgc
== 1, rSI
.nFilePos
& 1);
4144 PostStyle(rSI
, bOldNoImp
);
4146 pStStrm
->Seek( nPos
+nSkip
);
4150 void WW8RStyle::RecursiveReg(USHORT nNr
)
4152 SwWW8StyInf
&rSI
= pIo
->pCollA
[nNr
];
4153 if( rSI
.bImported
|| !rSI
.bValid
)
4156 rSI
.bImported
= true;
4158 if( rSI
.nBase
< cstd
&& !pIo
->pCollA
[rSI
.nBase
].bImported
)
4159 RecursiveReg(rSI
.nBase
);
4161 pIo
->RegisterNumFmtOnStyle(nNr
);
4166 After all styles are imported then we can recursively apply numbering
4167 styles to them, and change their tab stop settings if they turned out
4168 to have special first line indentation.
4170 void WW8RStyle::PostProcessStyles()
4174 Clear all imported flags so that we can recursively apply numbering
4175 formats and use it to mark handled ones
4177 for (i
=0; i
< cstd
; ++i
)
4178 pIo
->pCollA
[i
].bImported
= false;
4181 Register the num formats and tabstop changes on the styles recursively.
4185 In the same loop apply the tabstop changes required because we need to
4186 change their location if theres a special indentation for the first line,
4187 By avoiding making use of each styles margins during reading of their
4188 tabstops we don't get problems with doubly adjusting tabstops that
4191 for (i
=0; i
< cstd
; ++i
)
4193 if (pIo
->pCollA
[i
].bValid
)
4200 void WW8RStyle::ScanStyles() // untersucht Style-Abhaengigkeiten
4201 { // und ermittelt die Filepos fuer jeden Style
4203 WW8_FC nStyleStart = rFib.fcStshf;
4204 pStStrm->Seek( nStyleStart );
4206 for (USHORT i
= 0; i
< cstd
; ++i
)
4209 SwWW8StyInf
&rSI
= pIo
->pCollA
[i
];
4211 rSI
.nFilePos
= pStStrm
->Tell(); // merke FilePos
4212 WW8_STD
* pStd
= Read1Style( nSkip
, 0, 0 ); // read STD
4213 rSI
.bValid
= (0 != pStd
);
4216 rSI
.nBase
= pStd
->istdBase
; // merke Basis
4217 rSI
.bColl
= ( pStd
->sgc
== 1 ); // Para-Style
4220 rSI
= SwWW8StyInf();
4223 pStStrm
->SeekRel( nSkip
); // ueberlese Namen und Sprms
4227 std::vector
<BYTE
> ChpxToSprms(const Word2CHPX
&rChpx
)
4229 std::vector
<BYTE
> aRet
;
4232 aRet
.push_back( static_cast< BYTE
>(128 + rChpx
.fBold
) );
4235 aRet
.push_back( static_cast< BYTE
>(128 + rChpx
.fItalic
) );
4238 aRet
.push_back( static_cast< BYTE
>(128 + rChpx
.fStrike
) );
4241 aRet
.push_back( static_cast< BYTE
>(128 + rChpx
.fOutline
) );
4244 aRet
.push_back( static_cast< BYTE
>(128 + rChpx
.fSmallCaps
) );
4247 aRet
.push_back( static_cast< BYTE
>(128 + rChpx
.fCaps
) );
4250 aRet
.push_back( static_cast< BYTE
>(128 + rChpx
.fVanish
) );
4256 ShortToSVBT16(rChpx
.ftc
, a
);
4257 aRet
.push_back(a
[1]);
4258 aRet
.push_back(a
[0]);
4264 aRet
.push_back(rChpx
.kul
);
4271 ShortToSVBT16(rChpx
.lid
, a
);
4272 aRet
.push_back(a
[1]);
4273 aRet
.push_back(a
[0]);
4279 aRet
.push_back(rChpx
.ico
);
4287 ShortToSVBT16(rChpx
.hps
, a
);
4288 aRet
.push_back(a
[0]);
4289 // aRet.push_back(a[1]);
4295 aRet
.push_back(rChpx
.hpsPos
);
4299 aRet
.push_back( static_cast< BYTE
>(128 + rChpx
.fBoldBi
) );
4302 aRet
.push_back( static_cast< BYTE
>(128 + rChpx
.fItalicBi
) );
4308 ShortToSVBT16(rChpx
.fsFtcBi
, a
);
4309 aRet
.push_back(a
[1]);
4310 aRet
.push_back(a
[0]);
4317 ShortToSVBT16(rChpx
.lidBi
, a
);
4318 aRet
.push_back(a
[1]);
4319 aRet
.push_back(a
[0]);
4325 aRet
.push_back(rChpx
.icoBi
);
4332 ShortToSVBT16(rChpx
.hpsBi
, a
);
4333 aRet
.push_back(a
[1]);
4334 aRet
.push_back(a
[0]);
4340 Word2CHPX
ReadWord2Chpx(SvStream
&rSt
, sal_Size nOffset
, sal_uInt8 nSize
)
4357 aChpx
.fBold
= nFlags8
& 0x01;
4358 aChpx
.fItalic
= (nFlags8
& 0x02) >> 1;
4359 aChpx
.fRMarkDel
= (nFlags8
& 0x04) >> 2;
4360 aChpx
.fOutline
= (nFlags8
& 0x08) >> 3;
4361 aChpx
.fFldVanish
= (nFlags8
& 0x10) >> 4;
4362 aChpx
.fSmallCaps
= (nFlags8
& 0x20) >> 5;
4363 aChpx
.fCaps
= (nFlags8
& 0x40) >> 6;
4364 aChpx
.fVanish
= (nFlags8
& 0x80) >> 7;
4366 if (nCount
>= nSize
) break;
4370 aChpx
.fRMark
= nFlags8
& 0x01;
4371 aChpx
.fSpec
= (nFlags8
& 0x02) >> 1;
4372 aChpx
.fStrike
= (nFlags8
& 0x04) >> 2;
4373 aChpx
.fObj
= (nFlags8
& 0x08) >> 3;
4374 aChpx
.fBoldBi
= (nFlags8
& 0x10) >> 4;
4375 aChpx
.fItalicBi
= (nFlags8
& 0x20) >> 5;
4376 aChpx
.fBiDi
= (nFlags8
& 0x40) >> 6;
4377 aChpx
.fDiacUSico
= (nFlags8
& 0x80) >> 7;
4379 if (nCount
>= nSize
) break;
4383 aChpx
.fsIco
= nFlags8
& 0x01;
4384 aChpx
.fsFtc
= (nFlags8
& 0x02) >> 1;
4385 aChpx
.fsHps
= (nFlags8
& 0x04) >> 2;
4386 aChpx
.fsKul
= (nFlags8
& 0x08) >> 3;
4387 aChpx
.fsPos
= (nFlags8
& 0x10) >> 4;
4388 aChpx
.fsSpace
= (nFlags8
& 0x20) >> 5;
4389 aChpx
.fsLid
= (nFlags8
& 0x40) >> 6;
4390 aChpx
.fsIcoBi
= (nFlags8
& 0x80) >> 7;
4392 if (nCount
>= nSize
) break;
4396 aChpx
.fsFtcBi
= nFlags8
& 0x01;
4397 aChpx
.fsHpsBi
= (nFlags8
& 0x02) >> 1;
4398 aChpx
.fsLidBi
= (nFlags8
& 0x04) >> 2;
4400 if (nCount
>= nSize
) break;
4404 if (nCount
>= nSize
) break;
4408 if (nCount
>= nSize
) break;
4412 aChpx
.qpsSpace
= nFlags8
& 0x3F;
4413 aChpx
.fSysVanish
= (nFlags8
& 0x40) >> 6;
4414 aChpx
.fNumRun
= (nFlags8
& 0x80) >> 7;
4416 if (nCount
>= nSize
) break;
4420 aChpx
.ico
= nFlags8
& 0x1F;
4421 aChpx
.kul
= (nFlags8
& 0xE0) >> 5;
4423 if (nCount
>= nSize
) break;
4424 rSt
>> aChpx
.hpsPos
;
4427 if (nCount
>= nSize
) break;
4431 if (nCount
>= nSize
) break;
4435 if (nCount
>= nSize
) break;
4439 if (nCount
>= nSize
) break;
4443 if (nCount
>= nSize
) break;
4447 if (nCount
>= nSize
) break;
4454 rSt
.SeekRel(nSize
-nCount
);
4460 struct pxoffset
{ sal_Size mnOffset
; sal_uInt8 mnSize
; };
4463 void WW8RStyle::ImportOldFormatStyles()
4465 for (sal_uInt16 i
=0; i
< cstd
; ++i
)
4467 pIo
->pCollA
[i
].bColl
= true;
4468 //every chain must end eventually at the null style (style code 222)
4469 pIo
->pCollA
[i
].nBase
= 222;
4472 rtl_TextEncoding eStructChrSet
= WW8Fib::GetFIBCharset(
4473 pIo
->pWwFib
->chseTables
);
4480 sal_uInt16 nByteCount
= 2;
4482 while (nByteCount
< cbName
)
4488 sal_uInt8 stc
= static_cast< sal_uInt8
>((stcp
- cstcStd
) & 255);
4489 SwWW8StyInf
&rSI
= pIo
->pCollA
[stc
];
4490 if (nCount
!= 0xFF) // undefined style
4493 if (nCount
== 0) // inbuilt style
4495 ww::sti eSti
= ww::GetCanonicalStiFromStc(stc
);
4496 if (const sal_Char
*pStr
= GetEnglishNameFromSti(eSti
))
4497 sName
= String(pStr
, RTL_TEXTENCODING_ASCII_US
);
4499 sName
= String(CREATE_CONST_ASC("Unknown"));
4504 nByteCount
= static_cast< sal_uInt16
>(nByteCount
+ SafeReadString(aTmp
, nCount
, rSt
));
4505 sName
= String(aTmp
, eStructChrSet
);
4507 rSI
.SetOrgWWIdent(sName
, stc
);
4508 rSI
.bImported
= true;
4512 ww::sti eSti
= ww::GetCanonicalStiFromStc(stc
);
4513 if (const sal_Char
*pStr
= GetEnglishNameFromSti(eSti
))
4515 String sName
= String(pStr
, RTL_TEXTENCODING_ASCII_US
);
4516 rSI
.SetOrgWWIdent(sName
, stc
);
4522 USHORT nStyles
=stcp
;
4524 std::vector
<pxoffset
> aCHPXOffsets(stcp
);
4529 std::vector
< std::vector
<BYTE
> > aConvertedChpx
;
4530 while (nByteCount
< cbChpx
)
4536 aCHPXOffsets
[stcp
].mnSize
= 0;
4540 sal_uInt8 nRemainder
= cb
;
4542 aCHPXOffsets
[stcp
].mnOffset
= rSt
.Tell();
4543 aCHPXOffsets
[stcp
].mnSize
= nRemainder
;
4545 Word2CHPX aChpx
= ReadWord2Chpx(rSt
, aCHPXOffsets
[stcp
].mnOffset
,
4546 aCHPXOffsets
[stcp
].mnSize
);
4547 aConvertedChpx
.push_back( ChpxToSprms(aChpx
) );
4549 nByteCount
+= nRemainder
;
4552 aConvertedChpx
.push_back( std::vector
<BYTE
>() );
4555 if (stcp
== nStyles
)
4557 rSt
.SeekRel(cbChpx
-nByteCount
);
4558 nByteCount
+= cbChpx
-nByteCount
;
4562 std::vector
<pxoffset
> aPAPXOffsets(stcp
);
4567 while (nByteCount
< cbPapx
)
4573 aPAPXOffsets
[stcp
].mnSize
= 0;
4581 sal_uInt8 nRemainder
= cb
-7;
4583 aPAPXOffsets
[stcp
].mnOffset
= rSt
.Tell();
4584 aPAPXOffsets
[stcp
].mnSize
= nRemainder
;
4586 rSt
.SeekRel(nRemainder
);
4587 nByteCount
+= nRemainder
;
4592 if (stcp
== nStyles
)
4594 rSt
.SeekRel(cbPapx
-nByteCount
);
4595 nByteCount
+= cbPapx
-nByteCount
;
4602 if (iMac
> nStyles
) iMac
= nStyles
;
4604 for (stcp
= 0; stcp
< iMac
; ++stcp
)
4606 sal_uInt8 stcNext
, stcBase
;
4610 sal_uInt8 stc
= static_cast< sal_uInt8
>((stcp
- cstcStd
) & 255);
4613 #i64557# style based on itself
4614 every chain must end eventually at the null style (style code 222)
4619 SwWW8StyInf
&rSI
= pIo
->pCollA
[stc
];
4620 rSI
.nBase
= stcBase
;
4622 ww::sti eSti
= ww::GetCanonicalStiFromStc(stc
);
4624 if (eSti
== ww::stiNil
)
4629 if (ww::StandardStiIsCharStyle(eSti
) && !aPAPXOffsets
[stcp
].mnSize
)
4630 pIo
->pCollA
[stc
].bColl
= false;
4632 bool bOldNoImp
= PrepareStyle(rSI
, eSti
, stc
, stcNext
);
4634 ImportSprms(aPAPXOffsets
[stcp
].mnOffset
, aPAPXOffsets
[stcp
].mnSize
,
4637 if (aConvertedChpx
[stcp
].size() > 0)
4638 ImportSprms(&(aConvertedChpx
[stcp
][0]),
4639 static_cast< short >(aConvertedChpx
[stcp
].size()),
4642 PostStyle(rSI
, bOldNoImp
);
4646 void WW8RStyle::ImportNewFormatStyles()
4648 ScanStyles(); // Scanne Based On
4650 for (USHORT i
= 0; i
< cstd
; ++i
) // import Styles
4651 if (pIo
->pCollA
[i
].bValid
)
4655 void WW8RStyle::ImportStyles()
4657 if (ww::eWW2
== pIo
->pWwFib
->GetFIBVersion())
4658 ImportOldFormatStyles();
4660 ImportNewFormatStyles();
4663 void WW8RStyle::Import()
4665 pIo
->pDfltTxtFmtColl
= pIo
->rDoc
.GetDfltTxtFmtColl();
4666 pIo
->pStandardFmtColl
=
4667 pIo
->rDoc
.GetTxtCollFromPool(RES_POOLCOLL_STANDARD
, false);
4669 if( pIo
->nIniFlags
& WW8FL_NO_STYLES
)
4674 for (USHORT i
= 0; i
< cstd
; ++i
)
4677 SwWW8StyInf
* pi
= &pIo
->pCollA
[i
];
4678 USHORT j
= pi
->nFollow
;
4681 SwWW8StyInf
* pj
= &pIo
->pCollA
[j
];
4682 if ( j
!= i
// sinnvoller Index ?
4683 && pi
->pFmt
// Format ok ?
4684 && pj
->pFmt
// Derived-Format ok ?
4685 && pi
->bColl
// geht nur bei Absatz-Vorlagen (WW)
4686 && pj
->bColl
){ // beides gleicher Typ ?
4687 ( (SwTxtFmtColl
*)pi
->pFmt
)->SetNextTxtFmtColl(
4688 *(SwTxtFmtColl
*)pj
->pFmt
); // ok, eintragen
4692 // Die Sonderbehandlung zur Setzen der
4693 // Default-Zeichenvorlage "Absatz-Standardschriftart" ( Style-ID 65 ) fehlt
4694 // Sie ist aber defaultmaessig leer ( WW6 dt und US ) und von der
4695 // WW-UI nicht zu veraendern, so dass das nicht stoert.
4696 // Der Mechanismus waere folgender:
4697 // if( bNew ) rDoc.SetDefault( pDefCharFmt->GetAttrSet() );
4699 // fuer z.B. Tabellen wird ein immer gueltiger Std-Style gebraucht
4701 if( pIo
->StyleExists(0) && pIo
->pCollA
[0].pFmt
&& pIo
->pCollA
[0].bColl
&& pIo
->pCollA
[0].bValid
)
4702 pIo
->pDfltTxtFmtColl
= (SwTxtFmtColl
*)pIo
->pCollA
[0].pFmt
;
4704 pIo
->pDfltTxtFmtColl
= pIo
->rDoc
.GetDfltTxtFmtColl();
4707 // set Hyphenation flag on BASIC para-style
4708 if (pIo
->mbNewDoc
&& pIo
->pStandardFmtColl
)
4710 if (pIo
->pWDop
->fAutoHyphen
4711 && SFX_ITEM_SET
!= pIo
->pStandardFmtColl
->GetItemState(
4712 RES_PARATR_HYPHENZONE
, false) )
4714 SvxHyphenZoneItem
aAttr(true, RES_PARATR_HYPHENZONE
);
4715 aAttr
.GetMinLead() = 2;
4716 aAttr
.GetMinTrail() = 2;
4717 aAttr
.GetMaxHyphens() = 0;
4719 pIo
->pStandardFmtColl
->SetFmtAttr( aAttr
);
4723 Word defaults to ltr not from environment like writer. Regardless of
4724 the page/sections rtl setting the standard style lack of rtl still
4727 if (SFX_ITEM_SET
!= pIo
->pStandardFmtColl
->GetItemState(RES_FRAMEDIR
,
4730 pIo
->pStandardFmtColl
->SetFmtAttr(
4731 SvxFrameDirectionItem(FRMDIR_HORI_LEFT_TOP
, RES_FRAMEDIR
));
4735 // wir sind jetzt nicht mehr beim Style einlesen:
4739 CharSet
SwWW8StyInf::GetCharSet() const
4741 if ((pFmt
) && (pFmt
->GetFrmDir().GetValue() == FRMDIR_HORI_RIGHT_TOP
))
4742 return eRTLFontSrcCharSet
;
4743 return eLTRFontSrcCharSet
;
4746 CharSet
SwWW8StyInf::GetCJKCharSet() const
4748 if ((pFmt
) && (pFmt
->GetFrmDir().GetValue() == FRMDIR_HORI_RIGHT_TOP
))
4749 return eRTLFontSrcCharSet
;
4750 return eCJKFontSrcCharSet
;
4753 /* vi:set tabstop=4 shiftwidth=4 expandtab: */