Update ooo320-m1
[ooovba.git] / sw / source / filter / html / htmltab.cxx
blob90489ff3125b32992d7c2ba8be01bbf885b9560c
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: htmltab.cxx,v $
10 * $Revision: 1.28.186.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
33 //#define TEST_RESIZE
36 #include "hintids.hxx"
37 #include <vcl/svapp.hxx>
38 #ifndef _WRKWIN_HXX //autogen
39 #include <vcl/wrkwin.hxx>
40 #endif
41 #include <svx/boxitem.hxx>
42 #include <svx/brshitem.hxx>
43 #include <svx/adjitem.hxx>
44 #include <svx/fhgtitem.hxx>
45 #include <svx/ulspitem.hxx>
46 #include <svx/lrspitem.hxx>
47 #include <svx/brkitem.hxx>
48 #include <svx/spltitem.hxx>
49 #include <svtools/htmltokn.h>
50 #include <svtools/htmlkywd.hxx>
51 #include <svtools/urihelper.hxx>
54 #include <fmtornt.hxx>
55 #include <frmfmt.hxx>
56 #include <fmtfsize.hxx>
57 #include <fmtsrnd.hxx>
58 #include <fmtpdsc.hxx>
59 #include <fmtcntnt.hxx>
60 #include <fmtanchr.hxx>
61 #include <fmtlsplt.hxx>
62 #include "frmatr.hxx"
63 #include "pam.hxx"
64 #include "doc.hxx"
65 #include "ndtxt.hxx"
66 #include "shellio.hxx"
67 #include "poolfmt.hxx"
68 #include "swtable.hxx"
69 #include "cellatr.hxx"
70 #ifdef TEST_RESIZE
71 #include "viewsh.hxx"
72 #endif
73 #include "htmltbl.hxx"
74 #include "swtblfmt.hxx"
75 #include "htmlnum.hxx"
76 #include "swhtml.hxx"
77 #include "swcss1.hxx"
78 #include <numrule.hxx>
80 #define NETSCAPE_DFLT_BORDER 1
81 #define NETSCAPE_DFLT_CELLPADDING 1
82 #define NETSCAPE_DFLT_CELLSPACING 2
84 //#define FIX56334
86 using namespace ::com::sun::star;
89 static HTMLOptionEnum __FAR_DATA aHTMLTblVAlignTable[] =
91 { OOO_STRING_SVTOOLS_HTML_VA_top, text::VertOrientation::NONE },
92 { OOO_STRING_SVTOOLS_HTML_VA_middle, text::VertOrientation::CENTER },
93 { OOO_STRING_SVTOOLS_HTML_VA_bottom, text::VertOrientation::BOTTOM },
94 { 0, 0 }
98 /* \f */
100 // Die Optionen eines Table-Tags
102 struct HTMLTableOptions
104 sal_uInt16 nCols;
105 sal_uInt16 nWidth;
106 sal_uInt16 nHeight;
107 sal_uInt16 nCellPadding;
108 sal_uInt16 nCellSpacing;
109 sal_uInt16 nBorder;
110 sal_uInt16 nHSpace;
111 sal_uInt16 nVSpace;
113 SvxAdjust eAdjust;
114 sal_Int16 eVertOri;
115 HTMLTableFrame eFrame;
116 HTMLTableRules eRules;
118 sal_Bool bPrcWidth : 1;
119 sal_Bool bTableAdjust : 1;
120 sal_Bool bBGColor : 1;
122 Color aBorderColor;
123 Color aBGColor;
125 String aBGImage, aStyle, aId, aClass, aDir;
127 HTMLTableOptions( const HTMLOptions *pOptions, SvxAdjust eParentAdjust );
130 /* \f */
132 class _HTMLTableContext
134 SwHTMLNumRuleInfo aNumRuleInfo; // Vor der Tabelle gueltige Numerierung
136 SwTableNode *pTblNd; // der Tabellen-Node
137 SwFrmFmt *pFrmFmt; // der Fly frame::Frame, in dem die Tabelle steht
138 SwPosition *pPos; // die Position hinter der Tabelle
140 sal_uInt16 nContextStAttrMin;
141 sal_uInt16 nContextStMin;
143 sal_Bool bRestartPRE : 1;
144 sal_Bool bRestartXMP : 1;
145 sal_Bool bRestartListing : 1;
147 public:
149 _HTMLAttrTable aAttrTab; // und die Attribute
151 _HTMLTableContext( SwPosition *pPs, sal_uInt16 nCntxtStMin,
152 sal_uInt16 nCntxtStAttrMin ) :
153 pTblNd( 0 ),
154 pFrmFmt( 0 ),
155 pPos( pPs ),
156 nContextStAttrMin( nCntxtStAttrMin ),
157 nContextStMin( nCntxtStMin ),
158 bRestartPRE( sal_False ),
159 bRestartXMP( sal_False ),
160 bRestartListing( sal_False )
162 memset( &aAttrTab, 0, sizeof( _HTMLAttrTable ));
165 ~_HTMLTableContext();
167 void SetNumInfo( const SwHTMLNumRuleInfo& rInf ) { aNumRuleInfo.Set(rInf); }
168 const SwHTMLNumRuleInfo& GetNumInfo() const { return aNumRuleInfo; };
170 void SavePREListingXMP( SwHTMLParser& rParser );
171 void RestorePREListingXMP( SwHTMLParser& rParser );
173 SwPosition *GetPos() const { return pPos; }
175 void SetTableNode( SwTableNode *pNd ) { pTblNd = pNd; }
176 SwTableNode *GetTableNode() const { return pTblNd; }
178 void SetFrmFmt( SwFrmFmt *pFmt ) { pFrmFmt = pFmt; }
179 SwFrmFmt *GetFrmFmt() const { return pFrmFmt; }
181 sal_uInt16 GetContextStMin() const { return nContextStMin; }
182 sal_uInt16 GetContextStAttrMin() const { return nContextStAttrMin; }
185 /* \f */
187 // der Inhalt einer Zelle ist eine verkettete Liste mit SwStartNodes und
188 // HTMLTables.
190 class HTMLTableCnts
192 HTMLTableCnts *pNext; // der naechste Inhalt
194 // von den beiden naechsten Pointern darf nur einer gesetzt sein!
195 const SwStartNode *pStartNode; // ein Abastz
196 HTMLTable *pTable; // eine Tabelle
198 SwHTMLTableLayoutCnts* pLayoutInfo;
200 sal_Bool bNoBreak;
202 void InitCtor();
204 public:
206 HTMLTableCnts( const SwStartNode* pStNd );
207 HTMLTableCnts( HTMLTable* pTab );
209 ~HTMLTableCnts(); // nur in ~HTMLTableCell erlaubt
211 // Ermitteln des SwStartNode bzw. der HTMLTable
212 const SwStartNode *GetStartNode() const { return pStartNode; }
213 const HTMLTable *GetTable() const { return pTable; }
214 HTMLTable *GetTable() { return pTable; }
216 // hinzufuegen eines neuen Knotens am Listenende
217 void Add( HTMLTableCnts* pNewCnts );
219 // Ermitteln des naechsten Knotens
220 const HTMLTableCnts *Next() const { return pNext; }
221 HTMLTableCnts *Next() { return pNext; }
223 inline void SetTableBox( SwTableBox *pBox );
225 void SetNoBreak() { bNoBreak = sal_True; }
227 SwHTMLTableLayoutCnts *CreateLayoutInfo();
230 /* \f */
232 // Eine Zelle der HTML-Tabelle
234 class HTMLTableCell
236 // !!!ACHTUNG!!!!! Fuer jeden neuen Pointer muss die SetProtected-
237 // Methode (und natuerlich der Destruktor) bearbeitet werden.
238 HTMLTableCnts *pContents; // der Inhalt der Zelle
239 SvxBrushItem *pBGBrush; // Hintergrund der Zelle
240 // !!!ACHTUNG!!!!!
242 sal_uInt32 nNumFmt;
243 sal_uInt16 nRowSpan; // ROWSPAN der Zelle
244 sal_uInt16 nColSpan; // COLSPAN der Zelle
245 sal_uInt16 nWidth; // WIDTH der Zelle
246 double nValue;
247 sal_Int16 eVertOri; // vertikale Ausrichtung der Zelle
248 sal_Bool bProtected : 1; // Zelle darf nicht belegt werden
249 sal_Bool bRelWidth : 1; // nWidth ist %-Angabe
250 sal_Bool bHasNumFmt : 1;
251 sal_Bool bHasValue : 1;
252 sal_Bool bNoWrap : 1;
253 sal_Bool mbCovered : 1;
255 public:
257 HTMLTableCell(); // neue Zellen sind immer leer
259 ~HTMLTableCell(); // nur in ~HTMLTableRow erlaubt
261 // Belegen einer nicht-leeren Zelle
262 void Set( HTMLTableCnts *pCnts, sal_uInt16 nRSpan, sal_uInt16 nCSpan,
263 sal_Int16 eVertOri, SvxBrushItem *pBGBrush,
264 sal_Bool bHasNumFmt, sal_uInt32 nNumFmt,
265 sal_Bool bHasValue, double nValue, sal_Bool bNoWrap, sal_Bool bCovered );
267 // Schuetzen einer leeren 1x1-Zelle
268 void SetProtected();
270 // Setzen/Ermitteln des Inhalts einer Zelle
271 void SetContents( HTMLTableCnts *pCnts ) { pContents = pCnts; }
272 const HTMLTableCnts *GetContents() const { return pContents; }
273 HTMLTableCnts *GetContents() { return pContents; }
275 // ROWSPAN/COLSPAN der Zelle Setzen/Ermitteln
276 void SetRowSpan( sal_uInt16 nRSpan ) { nRowSpan = nRSpan; }
277 sal_uInt16 GetRowSpan() const { return nRowSpan; }
279 void SetColSpan( sal_uInt16 nCSpan ) { nColSpan = nCSpan; }
280 sal_uInt16 GetColSpan() const { return nColSpan; }
282 inline void SetWidth( sal_uInt16 nWidth, sal_Bool bRelWidth );
284 const SvxBrushItem *GetBGBrush() const { return pBGBrush; }
286 inline sal_Bool GetNumFmt( sal_uInt32& rNumFmt ) const;
287 inline sal_Bool GetValue( double& rValue ) const;
289 sal_Int16 GetVertOri() const { return eVertOri; }
291 // Ist die Zelle belegt oder geschuetzt?
292 sal_Bool IsUsed() const { return pContents!=0 || bProtected; }
294 SwHTMLTableLayoutCell *CreateLayoutInfo();
296 sal_Bool IsCovered() const { return mbCovered; }
299 /* \f */
301 // Eine Zeile der HTML-Tabelle
303 typedef HTMLTableCell* HTMLTableCellPtr;
304 SV_DECL_PTRARR_DEL(HTMLTableCells,HTMLTableCellPtr,5,5)
306 class HTMLTableRow
308 HTMLTableCells *pCells; // die Zellen der Zeile
310 sal_Bool bIsEndOfGroup : 1;
311 sal_Bool bSplitable : 1;
313 sal_uInt16 nHeight; // Optionen von <TR>/<TD>
314 sal_uInt16 nEmptyRows; // wieviele Leere Zeilen folgen
316 SvxAdjust eAdjust;
317 sal_Int16 eVertOri;
318 SvxBrushItem *pBGBrush; // Hintergrund der Zelle aus STYLE
320 public:
322 sal_Bool bBottomBorder; // kommt hinter der Zeile eine Linie?
324 HTMLTableRow( sal_uInt16 nCells=0 ); // die Zellen der Zeile sind leer
326 ~HTMLTableRow();
328 inline void SetHeight( sal_uInt16 nHeight );
329 sal_uInt16 GetHeight() const { return nHeight; }
331 // Ermitteln einer Zelle
332 inline HTMLTableCell *GetCell( sal_uInt16 nCell ) const;
333 inline const HTMLTableCells *GetCells() const { return pCells; }
336 inline void SetAdjust( SvxAdjust eAdj ) { eAdjust = eAdj; }
337 inline SvxAdjust GetAdjust() const { return eAdjust; }
339 inline void SetVertOri( sal_Int16 eV) { eVertOri = eV; }
340 inline sal_Int16 GetVertOri() const { return eVertOri; }
342 void SetBGBrush( SvxBrushItem *pBrush ) { pBGBrush = pBrush; }
343 const SvxBrushItem *GetBGBrush() const { return pBGBrush; }
345 inline void SetEndOfGroup() { bIsEndOfGroup = sal_True; }
346 inline sal_Bool IsEndOfGroup() const { return bIsEndOfGroup; }
348 void IncEmptyRows() { nEmptyRows++; }
349 sal_uInt16 GetEmptyRows() const { return nEmptyRows; }
351 // Expandieren einer Zeile durch hinzufuegen leerer Zellen
352 void Expand( sal_uInt16 nCells, sal_Bool bOneCell=sal_False );
354 // Verkuerzen einer Zeile durch loesen von leeren Zellen
355 void Shrink( sal_uInt16 nCells );
357 void SetSplitable( sal_Bool bSet ) { bSplitable = bSet; }
358 sal_Bool IsSplitable() const { return bSplitable; }
361 /* \f */
363 // Eine Spalte der HTML-Tabelle
365 class HTMLTableColumn
367 sal_Bool bIsEndOfGroup;
369 sal_uInt16 nWidth; // Optionen von <COL>
370 sal_Bool bRelWidth;
372 SvxAdjust eAdjust;
373 sal_Int16 eVertOri;
375 SwFrmFmt *aFrmFmts[6];
377 inline sal_uInt16 GetFrmFmtIdx( sal_Bool bBorderLine,
378 sal_Int16 eVertOri ) const;
380 public:
382 sal_Bool bLeftBorder; // kommt vor der Spalte eine Linie
384 HTMLTableColumn();
386 inline void SetWidth( sal_uInt16 nWidth, sal_Bool bRelWidth);
388 inline void SetAdjust( SvxAdjust eAdj ) { eAdjust = eAdj; }
389 inline SvxAdjust GetAdjust() const { return eAdjust; }
391 inline void SetVertOri( sal_Int16 eV) { eVertOri = eV; }
392 inline sal_Int16 GetVertOri() const { return eVertOri; }
394 inline void SetEndOfGroup() { bIsEndOfGroup = sal_True; }
395 inline sal_Bool IsEndOfGroup() const { return bIsEndOfGroup; }
397 inline void SetFrmFmt( SwFrmFmt *pFmt, sal_Bool bBorderLine,
398 sal_Int16 eVertOri );
399 inline SwFrmFmt *GetFrmFmt( sal_Bool bBorderLine,
400 sal_Int16 eVertOri ) const;
402 SwHTMLTableLayoutColumn *CreateLayoutInfo();
405 /* \f */
407 // eine HTML-Tabelle
409 typedef HTMLTableRow* HTMLTableRowPtr;
410 SV_DECL_PTRARR_DEL(HTMLTableRows,HTMLTableRowPtr,5,5)
412 typedef HTMLTableColumn* HTMLTableColumnPtr;
413 SV_DECL_PTRARR_DEL(HTMLTableColumns,HTMLTableColumnPtr,5,5)
415 SV_DECL_PTRARR(SdrObjects,SdrObject *,1,1)
417 class HTMLTable
419 String aId;
420 String aStyle;
421 String aClass;
422 String aDir;
424 SdrObjects *pResizeDrawObjs;// SDR-Objekte
425 SvUShorts *pDrawObjPrcWidths; // Spalte des Zeichen-Objekts und dessen
426 // relative Breite
428 HTMLTableRows *pRows; // die Zeilen der Tabelle
429 HTMLTableColumns *pColumns; // die Spalten der Tabelle
431 sal_uInt16 nRows; // Anzahl Zeilen
432 sal_uInt16 nCols; // Anzahl Spalten
433 sal_uInt16 nFilledCols; // Anzahl tatsaechlich gefuellter Spalten
435 sal_uInt16 nCurRow; // aktuelle Zeile
436 sal_uInt16 nCurCol; // aktuelle Spalte
438 sal_uInt16 nLeftMargin; // Abstand zum linken Rand (aus Absatz)
439 sal_uInt16 nRightMargin; // Abstand zum rechten Rand (aus Absatz)
441 sal_uInt16 nCellPadding; // Abstand Umrandung zum Text
442 sal_uInt16 nCellSpacing; // Abstand zwischen zwei Zellen
443 sal_uInt16 nHSpace;
444 sal_uInt16 nVSpace;
446 sal_uInt16 nBoxes; // Wievele Boxen enthaelt die Tabelle
448 const SwStartNode *pPrevStNd; // der Table-Node oder der Start-Node
449 // der vorhergehenden Section
450 const SwTable *pSwTable; // die SW-Tabelle (nur auf dem Top-Level)
451 SwTableBox *pBox1; // die TableBox, die beim Erstellen
452 // der Top-Level-Tabelle angelegt wird
454 SwTableBoxFmt *pBoxFmt; // das frame::Frame-Format einer SwTableBox
455 SwTableLineFmt *pLineFmt; // das frame::Frame-Format einer SwTableLine
456 SwTableLineFmt *pLineFrmFmtNoHeight;
457 SvxBrushItem *pBGBrush; // Hintergrund der Tabelle
458 SvxBrushItem *pInhBGBrush; // "geerbter" Hintergrund der Tabelle
459 const SwStartNode *pCaptionStartNode; // Start-Node der Tabellen-Ueberschrift
461 SvxBorderLine aTopBorderLine; // die Linie fuer die Umrandung
462 SvxBorderLine aBottomBorderLine;// die Linie fuer die Umrandung
463 SvxBorderLine aLeftBorderLine; // die Linie fuer die Umrandung
464 SvxBorderLine aRightBorderLine; // die Linie fuer die Umrandung
465 SvxBorderLine aBorderLine; // die Linie fuer die Umrandung
466 SvxBorderLine aInhLeftBorderLine; // die Linie fuer die Umrandung
467 SvxBorderLine aInhRightBorderLine; // die Linie fuer die Umrandung
468 sal_Bool bTopBorder; // besitzt die Tabelle oben eine Linie
469 sal_Bool bRightBorder; // besitzt die Tabelle rechts eine Linie
470 sal_Bool bTopAlwd; // duerfen die Raender gesetzt werden?
471 sal_Bool bRightAlwd;
472 sal_Bool bFillerTopBorder; // bekommt eine linke/rechter Filler-
473 sal_Bool bFillerBottomBorder; // Zelle eine obere/untere Umrandung?
474 sal_Bool bInhLeftBorder;
475 sal_Bool bInhRightBorder;
476 sal_Bool bBordersSet; // die Umrandung wurde bereits gesetzt
477 sal_Bool bForceFrame;
478 sal_Bool bTableAdjustOfTag; // stammt nTableAdjust aus <TABLE>?
479 sal_uInt32 nHeadlineRepeat; // repeating rows
480 sal_Bool bIsParentHead;
481 sal_Bool bHasParentSection;
482 sal_Bool bMakeTopSubTable;
483 sal_Bool bHasToFly;
484 sal_Bool bFixedCols;
485 sal_Bool bColSpec; // Gab es COL(GROUP)-Elemente?
486 sal_Bool bPrcWidth; // Breite ist eine %-Angabe
488 SwHTMLParser *pParser; // der aktuelle Parser
489 HTMLTable *pTopTable; // die Tabelle auf dem Top-Level
490 HTMLTableCnts *pParentContents;
492 _HTMLTableContext *pContext; // der Kontext der Tabelle
494 SwHTMLTableLayout *pLayoutInfo;
497 // die folgenden Parameter stammen aus der dem <TABLE>-Tag
498 sal_uInt16 nWidth; // die Breite der Tabelle
499 sal_uInt16 nHeight; // absolute Hoehe der Tabelle
500 SvxAdjust eTableAdjust; // drawing::Alignment der Tabelle
501 sal_Int16 eVertOri; // Default vertikale Ausr. der Zellen
502 sal_uInt16 nBorder; // Breite der auesseren Umrandung
503 HTMLTableFrame eFrame; // Rahmen um die Tabelle
504 HTMLTableRules eRules; // Ramhen in der Tabelle
505 sal_Bool bTopCaption; // Ueberschrift ueber der Tabelle
507 void InitCtor( const HTMLTableOptions *pOptions );
509 // Korigieren des Row-Spans fuer alle Zellen oberhalb der
510 // angegeben Zelle und der Zelle selbst, fuer die den anegebenen
511 // Inhalt besitzen. Die angegeben Zelle bekommt den Row-Span 1
512 void FixRowSpan( sal_uInt16 nRow, sal_uInt16 nCol, const HTMLTableCnts *pCnts );
514 // Schuetzen der angegeben Zelle und den darunterliegenden
515 void ProtectRowSpan( sal_uInt16 nRow, sal_uInt16 nCol, sal_uInt16 nRowSpan );
517 // Suchen des SwStartNodes der logisch vorhergehenden Box
518 // bei nRow==nCell==USHRT_MAX wird der allerletzte Start-Node
519 // der Tabelle zurueckgegeben
520 const SwStartNode* GetPrevBoxStartNode( sal_uInt16 nRow, sal_uInt16 nCell ) const;
522 sal_uInt16 GetTopCellSpace( sal_uInt16 nRow, sal_uInt16 nRowSpan,
523 sal_Bool bSwBorders=sal_True ) const;
524 sal_uInt16 GetBottomCellSpace( sal_uInt16 nRow, sal_uInt16 nRowSpan,
525 sal_Bool bSwBorders=sal_True ) const;
527 // Anpassen des frame::Frame-Formates einer Box
528 void FixFrameFmt( SwTableBox *pBox, sal_uInt16 nRow, sal_uInt16 nCol,
529 sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
530 sal_Bool bFirstPara=sal_True, sal_Bool bLastPara=sal_True ) const;
531 void FixFillerFrameFmt( SwTableBox *pBox, sal_Bool bRight ) const;
533 // den Inhalt (Lines/Boxen) eine Tabelle erstellen
534 void _MakeTable( SwTableBox *pUpper=0 );
536 // Anlegen einer neuen SwTableBox, die einen SwStartNode enthaelt
537 SwTableBox *NewTableBox( const SwStartNode *pStNd,
538 SwTableLine *pUpper ) const;
540 // Erstellen einer SwTableLine aus den Zellen des Rechtecks
541 // (nTopRow/nLeftCol) inklusive bis (nBottomRow/nRightRow) exklusive
542 SwTableLine *MakeTableLine( SwTableBox *pUpper,
543 sal_uInt16 nTopRow, sal_uInt16 nLeftCol,
544 sal_uInt16 nBottomRow, sal_uInt16 nRightCol );
546 // Erstellen einer SwTableBox aus dem Inhalt einer Zelle
547 SwTableBox *MakeTableBox( SwTableLine *pUpper,
548 HTMLTableCnts *pCnts,
549 sal_uInt16 nTopRow, sal_uInt16 nLeftCol,
550 sal_uInt16 nBootomRow, sal_uInt16 nRightCol );
552 // der Autolayout-Algorithmus
554 // Setzen der Umrandung anhand der Vorgaben der Parent-Tabelle
555 void InheritBorders( const HTMLTable *pParent,
556 sal_uInt16 nRow, sal_uInt16 nCol,
557 sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
558 sal_Bool bFirstPara, sal_Bool bLastPara );
560 // Linke und rechte Umrandung der umgebenen Tabelle erben
561 void InheritVertBorders( const HTMLTable *pParent,
562 sal_uInt16 nCol, sal_uInt16 nColSpan );
565 // Setzen der Umrandung anhand der Benutzervorgaben
566 void SetBorders();
568 // wurde die Umrandung der Tabelle schon gesetzt
569 sal_Bool BordersSet() const { return bBordersSet; }
571 const SvxBrushItem *GetBGBrush() const { return pBGBrush; }
572 const SvxBrushItem *GetInhBGBrush() const { return pInhBGBrush; }
574 sal_uInt16 GetBorderWidth( const SvxBorderLine& rBLine,
575 sal_Bool bWithDistance=sal_False ) const;
577 public:
579 sal_Bool bFirstCell; // wurde schon eine Zelle angelegt?
581 HTMLTable( SwHTMLParser* pPars, HTMLTable *pTopTab,
582 sal_Bool bParHead, sal_Bool bHasParentSec,
583 sal_Bool bTopTbl, sal_Bool bHasToFly,
584 const HTMLTableOptions *pOptions );
586 ~HTMLTable();
588 // Ermitteln einer Zelle
589 inline HTMLTableCell *GetCell( sal_uInt16 nRow, sal_uInt16 nCell ) const;
591 // Ueberschrift setzen/ermitteln
592 inline void SetCaption( const SwStartNode *pStNd, sal_Bool bTop );
593 const SwStartNode *GetCaptionStartNode() const { return pCaptionStartNode; }
594 sal_Bool IsTopCaption() const { return bTopCaption; }
596 SvxAdjust GetTableAdjust( sal_Bool bAny ) const
598 return (bTableAdjustOfTag || bAny) ? eTableAdjust : SVX_ADJUST_END;
600 sal_Int16 GetVertOri() const { return eVertOri; }
602 sal_uInt16 GetHSpace() const { return nHSpace; }
603 sal_uInt16 GetVSpace() const { return nVSpace; }
605 sal_Bool HasPrcWidth() const { return bPrcWidth; }
606 sal_uInt8 GetPrcWidth() const { return bPrcWidth ? (sal_uInt8)nWidth : 0; }
608 sal_uInt16 GetMinWidth() const
610 sal_uInt32 nMin = pLayoutInfo->GetMin();
611 return nMin < USHRT_MAX ? (sal_uInt16)nMin : USHRT_MAX;
614 // von Zeilen oder Spalten geerbtes drawing::Alignment holen
615 SvxAdjust GetInheritedAdjust() const;
616 sal_Int16 GetInheritedVertOri() const;
618 // Einfuegen einer Zelle an der aktuellen Position
619 void InsertCell( HTMLTableCnts *pCnts, sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
620 sal_uInt16 nWidth, sal_Bool bRelWidth, sal_uInt16 nHeight,
621 sal_Int16 eVertOri, SvxBrushItem *pBGBrush,
622 sal_Bool bHasNumFmt, sal_uInt32 nNumFmt,
623 sal_Bool bHasValue, double nValue, sal_Bool bNoWrap );
625 // Start/Ende einer neuen Zeile bekanntgeben
626 void OpenRow( SvxAdjust eAdjust, sal_Int16 eVertOri,
627 SvxBrushItem *pBGBrush );
628 void CloseRow( sal_Bool bEmpty );
630 // Ende einer neuen Section bekanntgeben
631 inline void CloseSection( sal_Bool bHead );
633 // Ende einer Spalten-Gruppe bekanntgeben
634 inline void CloseColGroup( sal_uInt16 nSpan, sal_uInt16 nWidth, sal_Bool bRelWidth,
635 SvxAdjust eAdjust, sal_Int16 eVertOri );
637 // Einfuegen einer Spalte
638 void InsertCol( sal_uInt16 nSpan, sal_uInt16 nWidth, sal_Bool bRelWidth,
639 SvxAdjust eAdjust, sal_Int16 eVertOri );
641 // Beenden einer Tab-Definition (MUSS fuer ALLE Tabs aufgerufen werden)
642 void CloseTable();
644 // SwTable konstruieren (inkl. der Child-Tabellen)
645 void MakeTable( SwTableBox *pUpper, sal_uInt16 nAbsAvail,
646 sal_uInt16 nRelAvail=0, sal_uInt16 nAbsLeftSpace=0,
647 sal_uInt16 nAbsRightSpace=0, sal_uInt16 nInhAbsSpace=0 );
649 inline sal_Bool IsNewDoc() const { return pParser->IsNewDoc(); }
651 void SetHasParentSection( sal_Bool bSet ) { bHasParentSection = bSet; }
652 sal_Bool HasParentSection() const { return bHasParentSection; }
654 void SetParentContents( HTMLTableCnts *pCnts ) { pParentContents = pCnts; }
655 HTMLTableCnts *GetParentContents() const { return pParentContents; }
657 void MakeParentContents();
659 sal_Bool GetIsParentHeader() const { return bIsParentHead; }
661 sal_Bool IsMakeTopSubTable() const { return bMakeTopSubTable; }
662 void SetHasToFly() { bHasToFly=sal_True; }
663 sal_Bool HasToFly() const { return bHasToFly; }
665 void SetTable( const SwStartNode *pStNd, _HTMLTableContext *pCntxt,
666 sal_uInt16 nLeft, sal_uInt16 nRight,
667 const SwTable *pSwTab=0, sal_Bool bFrcFrame=sal_False );
669 _HTMLTableContext *GetContext() const { return pContext; }
671 SwHTMLTableLayout *CreateLayoutInfo();
673 sal_Bool HasColTags() const { return bColSpec; }
675 sal_uInt16 IncGrfsThatResize() { return pSwTable ? ((SwTable *)pSwTable)->IncGrfsThatResize() : 0; }
677 void RegisterDrawObject( SdrObject *pObj, sal_uInt8 nPrcWidth );
679 const SwTable *GetSwTable() const { return pSwTable; }
681 void SetBGBrush( const SvxBrushItem& rBrush ) { delete pBGBrush; pBGBrush = new SvxBrushItem( rBrush ); }
683 const String& GetId() const { return aId; }
684 const String& GetClass() const { return aClass; }
685 const String& GetStyle() const { return aStyle; }
686 const String& GetDirection() const { return aDir; }
688 void IncBoxCount() { nBoxes++; }
689 sal_Bool IsOverflowing() const { return nBoxes > 64000; }
692 SV_IMPL_PTRARR(HTMLTableCells,HTMLTableCellPtr)
693 SV_IMPL_PTRARR(HTMLTableRows,HTMLTableRowPtr)
694 SV_IMPL_PTRARR(HTMLTableColumns,HTMLTableColumnPtr)
696 /* \f */
699 void HTMLTableCnts::InitCtor()
701 pNext = 0;
702 pLayoutInfo = 0;
704 bNoBreak = sal_False;
707 HTMLTableCnts::HTMLTableCnts( const SwStartNode* pStNd ):
708 pStartNode(pStNd), pTable(0)
710 InitCtor();
713 HTMLTableCnts::HTMLTableCnts( HTMLTable* pTab ):
714 pStartNode(0), pTable(pTab)
716 InitCtor();
719 HTMLTableCnts::~HTMLTableCnts()
721 delete pTable; // die Tabellen brauchen wir nicht mehr
722 delete pNext;
725 void HTMLTableCnts::Add( HTMLTableCnts* pNewCnts )
727 HTMLTableCnts *pCnts = this;
729 while( pCnts->pNext )
730 pCnts = pCnts->pNext;
732 pCnts->pNext = pNewCnts;
735 inline void HTMLTableCnts::SetTableBox( SwTableBox *pBox )
737 ASSERT( pLayoutInfo, "Da sit noch keine Layout-Info" );
738 if( pLayoutInfo )
739 pLayoutInfo->SetTableBox( pBox );
742 SwHTMLTableLayoutCnts *HTMLTableCnts::CreateLayoutInfo()
744 if( !pLayoutInfo )
746 SwHTMLTableLayoutCnts *pNextInfo = pNext ? pNext->CreateLayoutInfo() : 0;
747 SwHTMLTableLayout *pTableInfo = pTable ? pTable->CreateLayoutInfo() : 0;
749 pLayoutInfo = new SwHTMLTableLayoutCnts( pStartNode, pTableInfo,
750 bNoBreak, pNextInfo );
753 return pLayoutInfo;
756 /* \f */
758 HTMLTableCell::HTMLTableCell():
759 pContents(0),
760 pBGBrush(0),
761 nNumFmt(0),
762 nRowSpan(1),
763 nColSpan(1),
764 nWidth( 0 ),
765 nValue(0),
766 eVertOri( text::VertOrientation::NONE ),
767 bProtected(sal_False),
768 bRelWidth( sal_False ),
769 bHasNumFmt(sal_False),
770 bHasValue(sal_False),
771 mbCovered(sal_False)
774 HTMLTableCell::~HTMLTableCell()
776 // der Inhalt ist in mehrere Zellen eingetragen, darf aber nur einmal
777 // geloescht werden
778 if( 1==nRowSpan && 1==nColSpan )
780 delete pContents;
781 delete pBGBrush;
785 void HTMLTableCell::Set( HTMLTableCnts *pCnts, sal_uInt16 nRSpan, sal_uInt16 nCSpan,
786 sal_Int16 eVert, SvxBrushItem *pBrush,
787 sal_Bool bHasNF, sal_uInt32 nNF, sal_Bool bHasV, double nVal,
788 sal_Bool bNWrap, sal_Bool bCovered )
790 pContents = pCnts;
791 nRowSpan = nRSpan;
792 nColSpan = nCSpan;
793 bProtected = sal_False;
794 eVertOri = eVert;
795 pBGBrush = pBrush;
797 bHasNumFmt = bHasNF;
798 bHasValue = bHasV;
799 nNumFmt = nNF;
800 nValue = nVal;
802 bNoWrap = bNWrap;
803 mbCovered = bCovered;
806 inline void HTMLTableCell::SetWidth( sal_uInt16 nWdth, sal_Bool bRelWdth )
808 nWidth = nWdth;
809 bRelWidth = bRelWdth;
812 void HTMLTableCell::SetProtected()
814 // Die Inhalte dieser Zelle mussen nich irgenwo anders verankert
815 // sein, weil sie nicht geloescht werden!!!
817 // Inhalt loeschen
818 pContents = 0;
820 // Hintergrundfarbe kopieren.
821 if( pBGBrush )
822 pBGBrush = new SvxBrushItem( *pBGBrush );
824 nRowSpan = 1;
825 nColSpan = 1;
826 bProtected = sal_True;
829 inline sal_Bool HTMLTableCell::GetNumFmt( sal_uInt32& rNumFmt ) const
831 rNumFmt = nNumFmt;
832 return bHasNumFmt;
835 inline sal_Bool HTMLTableCell::GetValue( double& rValue ) const
837 rValue = nValue;
838 return bHasValue;
841 SwHTMLTableLayoutCell *HTMLTableCell::CreateLayoutInfo()
843 SwHTMLTableLayoutCnts *pCntInfo = pContents ? pContents->CreateLayoutInfo() : 0;
845 return new SwHTMLTableLayoutCell( pCntInfo, nRowSpan, nColSpan, nWidth,
846 bRelWidth, bNoWrap );
849 /* \f */
851 HTMLTableRow::HTMLTableRow( sal_uInt16 nCells ):
852 pCells(new HTMLTableCells),
853 bIsEndOfGroup(sal_False),
854 bSplitable( sal_False ),
855 nHeight(0),
856 nEmptyRows(0),
857 eAdjust(SVX_ADJUST_END),
858 eVertOri(text::VertOrientation::TOP),
859 pBGBrush(0),
860 bBottomBorder(sal_False)
862 for( sal_uInt16 i=0; i<nCells; i++ )
864 pCells->Insert( new HTMLTableCell, pCells->Count() );
867 ASSERT( nCells==pCells->Count(),
868 "Zellenzahl in neuer HTML-Tabellenzeile stimmt nicht" );
871 HTMLTableRow::~HTMLTableRow()
873 delete pCells;
874 delete pBGBrush;
877 inline void HTMLTableRow::SetHeight( sal_uInt16 nHght )
879 if( nHght > nHeight )
880 nHeight = nHght;
883 inline HTMLTableCell *HTMLTableRow::GetCell( sal_uInt16 nCell ) const
885 ASSERT( nCell<pCells->Count(),
886 "ungueltiger Zellen-Index in HTML-Tabellenzeile" );
887 return (*pCells)[nCell];
890 void HTMLTableRow::Expand( sal_uInt16 nCells, sal_Bool bOneCell )
892 // die Zeile wird mit einer einzigen Zelle aufgefuellt, wenn
893 // bOneCell gesetzt ist. Das geht, nur fuer Zeilen, in die keine
894 // Zellen mehr eingefuegt werden!
896 sal_uInt16 nColSpan = nCells-pCells->Count();
897 for( sal_uInt16 i=pCells->Count(); i<nCells; i++ )
899 HTMLTableCell *pCell = new HTMLTableCell;
900 if( bOneCell )
901 pCell->SetColSpan( nColSpan );
903 pCells->Insert( pCell, pCells->Count() );
904 nColSpan--;
907 ASSERT( nCells==pCells->Count(),
908 "Zellenzahl in expandierter HTML-Tabellenzeile stimmt nicht" );
911 void HTMLTableRow::Shrink( sal_uInt16 nCells )
913 ASSERT( nCells < pCells->Count(), "Anzahl Zellen falsch" );
915 #ifndef PRODUCT
916 sal_uInt16 nEnd = pCells->Count();
917 #endif
918 // The colspan of empty cells at the end has to be fixed to the new
919 // number of cells.
920 sal_uInt16 i=nCells;
921 while( i )
923 HTMLTableCell *pCell = (*pCells)[--i];
924 if( !pCell->GetContents() )
926 ASSERT( pCell->GetColSpan() == nEnd - i,
927 "invalid col span for empty cell at row end" );
928 pCell->SetColSpan( nCells-i);
930 else
931 break;
933 #ifndef PRODUCT
934 for( i=nCells; i<nEnd; i++ )
936 HTMLTableCell *pCell = (*pCells)[i];
937 ASSERT( pCell->GetRowSpan() == 1,
938 "RowSpan von zu loesender Zelle ist falsch" );
939 ASSERT( pCell->GetColSpan() == nEnd - i,
940 "ColSpan von zu loesender Zelle ist falsch" );
941 ASSERT( !pCell->GetContents(), "Zu loeschende Zelle hat Inhalt" );
943 #endif
945 pCells->DeleteAndDestroy( nCells, pCells->Count()-nCells );
948 /* \f */
950 HTMLTableColumn::HTMLTableColumn():
951 bIsEndOfGroup(sal_False),
952 nWidth(0), bRelWidth(sal_False),
953 eAdjust(SVX_ADJUST_END), eVertOri(text::VertOrientation::TOP),
954 bLeftBorder(sal_False)
956 for( sal_uInt16 i=0; i<6; i++ )
957 aFrmFmts[i] = 0;
960 inline void HTMLTableColumn::SetWidth( sal_uInt16 nWdth, sal_Bool bRelWdth )
962 if( bRelWidth==bRelWdth )
964 if( nWdth > nWidth )
965 nWidth = nWdth;
967 else
968 nWidth = nWdth;
969 bRelWidth = bRelWdth;
972 inline SwHTMLTableLayoutColumn *HTMLTableColumn::CreateLayoutInfo()
974 return new SwHTMLTableLayoutColumn( nWidth, bRelWidth, bLeftBorder );
977 inline sal_uInt16 HTMLTableColumn::GetFrmFmtIdx( sal_Bool bBorderLine,
978 sal_Int16 eVertOrient ) const
980 ASSERT( text::VertOrientation::TOP != eVertOrient, "Top ist nicht erlaubt" );
981 sal_uInt16 n = bBorderLine ? 3 : 0;
982 switch( eVertOrient )
984 case text::VertOrientation::CENTER: n+=1; break;
985 case text::VertOrientation::BOTTOM: n+=2; break;
986 default:
989 return n;
992 inline void HTMLTableColumn::SetFrmFmt( SwFrmFmt *pFmt, sal_Bool bBorderLine,
993 sal_Int16 eVertOrient )
995 aFrmFmts[GetFrmFmtIdx(bBorderLine,eVertOrient)] = pFmt;
998 inline SwFrmFmt *HTMLTableColumn::GetFrmFmt( sal_Bool bBorderLine,
999 sal_Int16 eVertOrient ) const
1001 return aFrmFmts[GetFrmFmtIdx(bBorderLine,eVertOrient)];
1004 /* \f */
1007 void HTMLTable::InitCtor( const HTMLTableOptions *pOptions )
1009 pResizeDrawObjs = 0;
1010 pDrawObjPrcWidths = 0;
1012 pRows = new HTMLTableRows;
1013 pColumns = new HTMLTableColumns;
1014 nRows = 0;
1015 nCurRow = 0; nCurCol = 0;
1017 pBox1 = 0;
1018 pBoxFmt = 0; pLineFmt = 0;
1019 pLineFrmFmtNoHeight = 0;
1020 pInhBGBrush = 0;
1022 pPrevStNd = 0;
1023 pSwTable = 0;
1025 bTopBorder = sal_False; bRightBorder = sal_False;
1026 bTopAlwd = sal_True; bRightAlwd = sal_True;
1027 bFillerTopBorder = sal_False; bFillerBottomBorder = sal_False;
1028 bInhLeftBorder = sal_False; bInhRightBorder = sal_False;
1029 bBordersSet = sal_False;
1030 bForceFrame = sal_False;
1031 nHeadlineRepeat = 0;
1033 nLeftMargin = 0;
1034 nRightMargin = 0;
1036 const Color& rBorderColor = pOptions->aBorderColor;
1038 long nBorderOpt = (long)pOptions->nBorder;
1039 long nPWidth = nBorderOpt==USHRT_MAX ? NETSCAPE_DFLT_BORDER
1040 : nBorderOpt;
1041 long nPHeight = nBorderOpt==USHRT_MAX ? 0 : nBorderOpt;
1042 SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
1044 // nBorder gibt die Breite der Umrandung an, wie sie in die
1045 // Breitenberechnung in Netscape einfliesst. Wenn pOption->nBorder
1046 // == USHRT_MAX, wurde keine BORDER-Option angegeben. Trotzdem fliesst
1047 // eine 1 Pixel breite Umrandung in die Breitenberechnung mit ein.
1048 nBorder = (sal_uInt16)nPWidth;
1049 if( nBorderOpt==USHRT_MAX )
1050 nPWidth = 0;
1052 // HACK: ein Pixel-breite Linien sollen zur Haarlinie werden, wenn
1053 // wir mit doppelter Umrandung arbeiten
1054 if( pOptions->nCellSpacing!=0 && nBorderOpt==1 )
1056 nPWidth = 1;
1057 nPHeight = 1;
1060 SvxCSS1Parser::SetBorderWidth( aTopBorderLine, (sal_uInt16)nPHeight,
1061 pOptions->nCellSpacing!=0, sal_True );
1062 aTopBorderLine.SetColor( rBorderColor );
1063 aBottomBorderLine = aTopBorderLine;
1065 if( nPWidth == nPHeight )
1067 aLeftBorderLine = aTopBorderLine;
1069 else
1071 SvxCSS1Parser::SetBorderWidth( aLeftBorderLine, (sal_uInt16)nPWidth,
1072 pOptions->nCellSpacing!=0, sal_True );
1073 aLeftBorderLine.SetColor( rBorderColor );
1075 aRightBorderLine = aLeftBorderLine;
1077 if( pOptions->nCellSpacing != 0 )
1079 aBorderLine.SetOutWidth( DEF_DOUBLE_LINE7_OUT );
1080 aBorderLine.SetInWidth( DEF_DOUBLE_LINE7_IN );
1081 aBorderLine.SetDistance( DEF_DOUBLE_LINE7_DIST );
1083 else
1085 aBorderLine.SetOutWidth( DEF_LINE_WIDTH_1 );
1087 aBorderLine.SetColor( rBorderColor );
1089 if( nCellPadding )
1091 if( nCellPadding==USHRT_MAX )
1092 nCellPadding = MIN_BORDER_DIST; // default
1093 else
1095 nCellPadding = pParser->ToTwips( nCellPadding );
1096 if( nCellPadding<MIN_BORDER_DIST )
1097 nCellPadding = MIN_BORDER_DIST;
1100 if( nCellSpacing )
1102 if( nCellSpacing==USHRT_MAX )
1103 nCellSpacing = NETSCAPE_DFLT_CELLSPACING;
1104 nCellSpacing = pParser->ToTwips( nCellSpacing );
1107 nPWidth = pOptions->nHSpace;
1108 nPHeight = pOptions->nVSpace;
1109 SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
1110 nHSpace = (sal_uInt16)nPWidth;
1111 nVSpace = (sal_uInt16)nPHeight;
1113 bColSpec = sal_False;
1115 pBGBrush = pParser->CreateBrushItem(
1116 pOptions->bBGColor ? &(pOptions->aBGColor) : 0,
1117 pOptions->aBGImage, aEmptyStr, aEmptyStr, aEmptyStr );
1119 pContext = 0;
1120 pParentContents = 0;
1122 aId = pOptions->aId;
1123 aClass = pOptions->aClass;
1124 aStyle = pOptions->aStyle;
1125 aDir = pOptions->aDir;
1128 HTMLTable::HTMLTable( SwHTMLParser* pPars, HTMLTable *pTopTab,
1129 sal_Bool bParHead,
1130 sal_Bool bHasParentSec, sal_Bool bTopTbl, sal_Bool bHasToFlw,
1131 const HTMLTableOptions *pOptions ) :
1132 nCols( pOptions->nCols ),
1133 nFilledCols( 0 ),
1134 nCellPadding( pOptions->nCellPadding ),
1135 nCellSpacing( pOptions->nCellSpacing ),
1136 nBoxes( 1 ),
1137 pCaptionStartNode( 0 ),
1138 bTableAdjustOfTag( pTopTab ? sal_False : pOptions->bTableAdjust ),
1139 bIsParentHead( bParHead ),
1140 bHasParentSection( bHasParentSec ),
1141 bMakeTopSubTable( bTopTbl ),
1142 bHasToFly( bHasToFlw ),
1143 bFixedCols( pOptions->nCols>0 ),
1144 bPrcWidth( pOptions->bPrcWidth ),
1145 pParser( pPars ),
1146 pTopTable( pTopTab ? pTopTab : this ),
1147 pLayoutInfo( 0 ),
1148 nWidth( pOptions->nWidth ),
1149 nHeight( pTopTab ? 0 : pOptions->nHeight ),
1150 eTableAdjust( pOptions->eAdjust ),
1151 eVertOri( pOptions->eVertOri ),
1152 eFrame( pOptions->eFrame ),
1153 eRules( pOptions->eRules ),
1154 bTopCaption( sal_False ),
1155 bFirstCell( !pTopTab )
1157 InitCtor( pOptions );
1159 for( sal_uInt16 i=0; i<nCols; i++ )
1160 pColumns->Insert( new HTMLTableColumn, pColumns->Count() );
1164 HTMLTable::~HTMLTable()
1166 delete pResizeDrawObjs;
1167 delete pDrawObjPrcWidths;
1169 delete pRows;
1170 delete pColumns;
1171 delete pBGBrush;
1172 delete pInhBGBrush;
1174 delete pContext;
1176 // pLayoutInfo wurde entweder bereits geloescht oder muss aber es
1177 // in den Besitz der SwTable uebergegangen.
1180 SwHTMLTableLayout *HTMLTable::CreateLayoutInfo()
1182 sal_uInt16 nW = bPrcWidth ? nWidth : pParser->ToTwips( nWidth );
1184 sal_uInt16 nBorderWidth = GetBorderWidth( aBorderLine, sal_True );
1185 sal_uInt16 nLeftBorderWidth =
1186 ((*pColumns)[0])->bLeftBorder ? GetBorderWidth( aLeftBorderLine, sal_True ) : 0;
1187 sal_uInt16 nRightBorderWidth =
1188 bRightBorder ? GetBorderWidth( aRightBorderLine, sal_True ) : 0;
1189 sal_uInt16 nInhLeftBorderWidth = 0;
1190 sal_uInt16 nInhRightBorderWidth = 0;
1192 pLayoutInfo = new SwHTMLTableLayout(
1193 pSwTable,
1194 nRows, nCols, bFixedCols, bColSpec,
1195 nW, bPrcWidth, nBorder, nCellPadding,
1196 nCellSpacing, eTableAdjust,
1197 nLeftMargin, nRightMargin,
1198 nBorderWidth, nLeftBorderWidth, nRightBorderWidth,
1199 nInhLeftBorderWidth, nInhRightBorderWidth );
1201 sal_Bool bExportable = sal_True;
1202 sal_uInt16 i;
1203 for( i=0; i<nRows; i++ )
1205 HTMLTableRow *pRow = (*pRows)[i];
1206 for( sal_uInt16 j=0; j<nCols; j++ )
1208 SwHTMLTableLayoutCell *pLayoutCell =
1209 pRow->GetCell(j)->CreateLayoutInfo();
1211 pLayoutInfo->SetCell( pLayoutCell, i, j );
1213 if( bExportable )
1215 SwHTMLTableLayoutCnts *pLayoutCnts =
1216 pLayoutCell->GetContents();
1217 bExportable = !pLayoutCnts ||
1218 ( pLayoutCnts->GetStartNode() &&
1219 !pLayoutCnts->GetNext() );
1224 pLayoutInfo->SetExportable( bExportable );
1226 for( i=0; i<nCols; i++ )
1227 pLayoutInfo->SetColumn( ((*pColumns)[i])->CreateLayoutInfo(), i );
1229 return pLayoutInfo;
1232 inline void HTMLTable::SetCaption( const SwStartNode *pStNd, sal_Bool bTop )
1234 pCaptionStartNode = pStNd;
1235 bTopCaption = bTop;
1238 void HTMLTable::FixRowSpan( sal_uInt16 nRow, sal_uInt16 nCol,
1239 const HTMLTableCnts *pCnts )
1241 sal_uInt16 nRowSpan=1;
1242 HTMLTableCell *pCell;
1243 while( ( pCell=GetCell(nRow,nCol), pCell->GetContents()==pCnts ) )
1245 pCell->SetRowSpan( nRowSpan );
1246 if( pLayoutInfo )
1247 pLayoutInfo->GetCell(nRow,nCol)->SetRowSpan( nRowSpan );
1249 if( !nRow ) break;
1250 nRowSpan++; nRow--;
1254 void HTMLTable::ProtectRowSpan( sal_uInt16 nRow, sal_uInt16 nCol, sal_uInt16 nRowSpan )
1256 for( sal_uInt16 i=0; i<nRowSpan; i++ )
1258 GetCell(nRow+i,nCol)->SetProtected();
1259 if( pLayoutInfo )
1260 pLayoutInfo->GetCell(nRow+i,nCol)->SetProtected();
1265 // Suchen des SwStartNodes der letzten belegten Vorgaengerbox
1266 const SwStartNode* HTMLTable::GetPrevBoxStartNode( sal_uInt16 nRow, sal_uInt16 nCol ) const
1268 const HTMLTableCnts *pPrevCnts = 0;
1270 if( 0==nRow )
1272 // immer die Vorgaenger-Zelle
1273 if( nCol>0 )
1274 pPrevCnts = GetCell( 0, nCol-1 )->GetContents();
1275 else
1276 return pPrevStNd;
1278 else if( USHRT_MAX==nRow && USHRT_MAX==nCol )
1279 // der Contents der letzten Zelle
1280 pPrevCnts = GetCell( nRows-1, nCols-1 )->GetContents();
1281 else
1283 sal_uInt16 i;
1284 HTMLTableRow *pPrevRow = (*pRows)[nRow-1];
1286 // evtl. eine Zelle in der aktuellen Zeile
1287 i = nCol;
1288 while( i )
1290 i--;
1291 if( 1 == pPrevRow->GetCell(i)->GetRowSpan() )
1293 pPrevCnts = GetCell(nRow,i)->GetContents();
1294 break;
1298 // sonst die letzte gefuellte Zelle der Zeile davor suchen
1299 if( !pPrevCnts )
1301 i = nCols;
1302 while( !pPrevCnts && i )
1304 i--;
1305 pPrevCnts = pPrevRow->GetCell(i)->GetContents();
1309 ASSERT( pPrevCnts, "keine gefuellte Vorgaenger-Zelle gefunden" );
1310 if( !pPrevCnts )
1312 pPrevCnts = GetCell(0,0)->GetContents();
1313 if( !pPrevCnts )
1314 return pPrevStNd;
1317 while( pPrevCnts->Next() )
1318 pPrevCnts = pPrevCnts->Next();
1320 return ( pPrevCnts->GetStartNode() ? pPrevCnts->GetStartNode()
1321 : pPrevCnts->GetTable()->GetPrevBoxStartNode( USHRT_MAX, USHRT_MAX ) );
1325 static sal_Bool IsBoxEmpty( const SwTableBox *pBox )
1327 const SwStartNode *pSttNd = pBox->GetSttNd();
1328 if( pSttNd &&
1329 pSttNd->GetIndex() + 2 == pSttNd->EndOfSectionIndex() )
1331 const SwCntntNode *pCNd =
1332 pSttNd->GetNodes()[pSttNd->GetIndex()+1]->GetCntntNode();
1333 if( pCNd && !pCNd->Len() )
1334 return sal_True;
1337 return sal_False;
1340 sal_uInt16 HTMLTable::GetTopCellSpace( sal_uInt16 nRow, sal_uInt16 nRowSpan,
1341 sal_Bool bSwBorders ) const
1343 sal_uInt16 nSpace = nCellPadding;
1345 if( nRow == 0 )
1347 nSpace += nBorder + nCellSpacing;
1348 if( bSwBorders )
1350 sal_uInt16 nTopBorderWidth =
1351 GetBorderWidth( aTopBorderLine, sal_True );
1352 if( nSpace < nTopBorderWidth )
1353 nSpace = nTopBorderWidth;
1356 else if( bSwBorders && ((*pRows)[nRow+nRowSpan-1])->bBottomBorder &&
1357 nSpace < MIN_BORDER_DIST )
1359 ASSERT( !nCellPadding, "GetTopCellSpace: CELLPADDING!=0" );
1360 // Wenn die Gegenueberliegende Seite umrandet ist muessen
1361 // wir zumindest den minimalen Abstand zum Inhalt
1362 // beruecksichtigen. (Koennte man zusaetzlich auch an
1363 // nCellPadding festmachen.)
1364 nSpace = MIN_BORDER_DIST;
1367 return nSpace;
1370 sal_uInt16 HTMLTable::GetBottomCellSpace( sal_uInt16 nRow, sal_uInt16 nRowSpan,
1371 sal_Bool bSwBorders ) const
1373 sal_uInt16 nSpace = nCellSpacing + nCellPadding;
1375 if( nRow+nRowSpan == nRows )
1377 nSpace = nSpace + nBorder;
1379 if( bSwBorders )
1381 sal_uInt16 nBottomBorderWidth =
1382 GetBorderWidth( aBottomBorderLine, sal_True );
1383 if( nSpace < nBottomBorderWidth )
1384 nSpace = nBottomBorderWidth;
1387 else if( bSwBorders )
1389 if( ((*pRows)[nRow+nRowSpan+1])->bBottomBorder )
1391 sal_uInt16 nBorderWidth = GetBorderWidth( aBorderLine, sal_True );
1392 if( nSpace < nBorderWidth )
1393 nSpace = nBorderWidth;
1395 else if( nRow==0 && bTopBorder && nSpace < MIN_BORDER_DIST )
1397 ASSERT( GetBorderWidth( aTopBorderLine, sal_True ) > 0,
1398 "GetBottomCellSpace: |aTopLine| == 0" );
1399 ASSERT( !nCellPadding, "GetBottomCellSpace: CELLPADDING!=0" );
1400 // Wenn die Gegenueberliegende Seite umrandet ist muessen
1401 // wir zumindest den minimalen Abstand zum Inhalt
1402 // beruecksichtigen. (Koennte man zusaetzlich auch an
1403 // nCellPadding festmachen.)
1404 nSpace = MIN_BORDER_DIST;
1408 return nSpace;
1411 void HTMLTable::FixFrameFmt( SwTableBox *pBox,
1412 sal_uInt16 nRow, sal_uInt16 nCol,
1413 sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
1414 sal_Bool bFirstPara, sal_Bool bLastPara ) const
1416 SwFrmFmt *pFrmFmt = 0; // frame::Frame-Format
1417 sal_Int16 eVOri = text::VertOrientation::NONE;
1418 const SvxBrushItem *pBGBrushItem = 0; // Hintergrund
1419 sal_Bool bTopLine = sal_False, bBottomLine = sal_False, bLastBottomLine = sal_False;
1420 sal_Bool bReUsable = sal_False; // Format nochmals verwendbar?
1421 sal_uInt16 nEmptyRows = 0;
1422 sal_Bool bHasNumFmt = sal_False;
1423 sal_Bool bHasValue = sal_False;
1424 sal_uInt32 nNumFmt = 0;
1425 double nValue = 0.0;
1427 HTMLTableColumn *pColumn = (*pColumns)[nCol];
1429 if( pBox->GetSttNd() )
1431 // die Hintergrundfarbe/-grafik bestimmen
1432 const HTMLTableCell *pCell = GetCell( nRow, nCol );
1433 pBGBrushItem = pCell->GetBGBrush();
1434 if( !pBGBrushItem )
1436 // Wenn die Zelle ueber mehrere Zeilen geht muss ein evtl.
1437 // an der Zeile gesetzter Hintergrund an die Zelle uebernommen
1438 // werden.
1439 #ifndef FIX56334
1440 // Wenn es sich um eine Tabelle in der Tabelle handelt und
1441 // die Zelle ueber die gesamte Heoehe der Tabelle geht muss
1442 // ebenfalls der Hintergrund der Zeile uebernommen werden, weil
1443 // die Line von der GC (zu Recht) wegoptimiert wird.
1444 if( nRowSpan > 1 || (this != pTopTable && nRowSpan==nRows) )
1445 #else
1446 if( nRowSpan > 1 )
1447 #endif
1449 pBGBrushItem = ((*pRows)[nRow])->GetBGBrush();
1450 if( !pBGBrushItem && this != pTopTable )
1452 pBGBrushItem = GetBGBrush();
1453 if( !pBGBrushItem )
1454 pBGBrushItem = GetInhBGBrush();
1459 bTopLine = 0==nRow && bTopBorder && bFirstPara;
1460 if( ((*pRows)[nRow+nRowSpan-1])->bBottomBorder && bLastPara )
1462 nEmptyRows = ((*pRows)[nRow+nRowSpan-1])->GetEmptyRows();
1463 if( nRow+nRowSpan == nRows )
1464 bLastBottomLine = sal_True;
1465 else
1466 bBottomLine = sal_True;
1469 eVOri = pCell->GetVertOri();
1470 bHasNumFmt = pCell->GetNumFmt( nNumFmt );
1471 if( bHasNumFmt )
1472 bHasValue = pCell->GetValue( nValue );
1474 if( nColSpan==1 && !bTopLine && !bLastBottomLine && !nEmptyRows &&
1475 !pBGBrushItem && !bHasNumFmt )
1477 pFrmFmt = pColumn->GetFrmFmt( bBottomLine, eVOri );
1478 bReUsable = !pFrmFmt;
1482 if( !pFrmFmt )
1484 pFrmFmt = pBox->ClaimFrmFmt();
1486 // die Breite der Box berechnen
1487 SwTwips nFrmWidth = (SwTwips)pLayoutInfo->GetColumn(nCol)
1488 ->GetRelColWidth();
1489 for( sal_uInt16 i=1; i<nColSpan; i++ )
1490 nFrmWidth += (SwTwips)pLayoutInfo->GetColumn(nCol+i)
1491 ->GetRelColWidth();
1493 // die Umrandung nur an Edit-Boxen setzen (bei der oberen und unteren
1494 // Umrandung muss beruecks. werden, ob es sich um den ersten oder
1495 // letzen Absatz der Zelle handelt)
1496 if( pBox->GetSttNd() )
1498 sal_Bool bSet = (nCellPadding > 0);
1500 SvxBoxItem aBoxItem( RES_BOX );
1501 long nInnerFrmWidth = nFrmWidth;
1503 if( bTopLine )
1505 aBoxItem.SetLine( &aTopBorderLine, BOX_LINE_TOP );
1506 bSet = sal_True;
1508 if( bLastBottomLine )
1510 aBoxItem.SetLine( &aBottomBorderLine, BOX_LINE_BOTTOM );
1511 bSet = sal_True;
1513 else if( bBottomLine )
1515 if( nEmptyRows && !aBorderLine.GetInWidth() )
1517 // Leere Zeilen koennen zur Zeit nur dann ueber
1518 // dicke Linien simuliert werden, wenn die Linie
1519 // einfach ist.
1520 SvxBorderLine aThickBorderLine( aBorderLine );
1522 sal_uInt16 nBorderWidth = aBorderLine.GetOutWidth();
1523 nBorderWidth *= (nEmptyRows + 1);
1524 SvxCSS1Parser::SetBorderWidth( aThickBorderLine,
1525 nBorderWidth, sal_False );
1526 aBoxItem.SetLine( &aThickBorderLine, BOX_LINE_BOTTOM );
1528 else
1530 aBoxItem.SetLine( &aBorderLine, BOX_LINE_BOTTOM );
1532 bSet = sal_True;
1534 if( ((*pColumns)[nCol])->bLeftBorder )
1536 const SvxBorderLine& rBorderLine =
1537 0==nCol ? aLeftBorderLine : aBorderLine;
1538 aBoxItem.SetLine( &rBorderLine, BOX_LINE_LEFT );
1539 nInnerFrmWidth -= GetBorderWidth( rBorderLine );
1540 bSet = sal_True;
1542 if( nCol+nColSpan == nCols && bRightBorder )
1544 aBoxItem.SetLine( &aRightBorderLine, BOX_LINE_RIGHT );
1545 nInnerFrmWidth -= GetBorderWidth( aRightBorderLine );
1546 bSet = sal_True;
1549 if( bSet )
1551 // fix #30588#: BorderDist nicht mehr Bestandteil
1552 // einer Zelle mit fixer Breite
1553 sal_uInt16 nBDist = static_cast< sal_uInt16 >(
1554 (2*nCellPadding <= nInnerFrmWidth) ? nCellPadding
1555 : (nInnerFrmWidth / 2) );
1556 // wir setzen das Item nur, wenn es eine Umrandung gibt
1557 // oder eine sheet::Border-Distanz vorgegeben ist. Fehlt letztere,
1558 // dann gibt es eine Umrandung, und wir muessen die Distanz
1559 // setzen
1560 aBoxItem.SetDistance( nBDist ? nBDist : MIN_BORDER_DIST );
1561 pFrmFmt->SetFmtAttr( aBoxItem );
1563 else
1564 pFrmFmt->ResetFmtAttr( RES_BOX );
1566 if( pBGBrushItem )
1568 pFrmFmt->SetFmtAttr( *pBGBrushItem );
1570 else
1571 pFrmFmt->ResetFmtAttr( RES_BACKGROUND );
1573 // fix #41003#: Format nur setzten, wenn es auch einen Value
1574 // gibt oder die Box leer ist.
1575 if( bHasNumFmt && (bHasValue || IsBoxEmpty(pBox)) )
1577 sal_Bool bLock = pFrmFmt->GetDoc()->GetNumberFormatter()
1578 ->IsTextFormat( nNumFmt );
1579 SfxItemSet aItemSet( *pFrmFmt->GetAttrSet().GetPool(),
1580 RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
1581 SvxAdjust eAdjust = SVX_ADJUST_END;
1582 SwCntntNode *pCNd = 0;
1583 if( !bLock )
1585 const SwStartNode *pSttNd = pBox->GetSttNd();
1586 pCNd = pSttNd->GetNodes()[pSttNd->GetIndex()+1]
1587 ->GetCntntNode();
1588 const SfxPoolItem *pItem;
1589 if( pCNd && pCNd->HasSwAttrSet() &&
1590 SFX_ITEM_SET==pCNd->GetpSwAttrSet()->GetItemState(
1591 RES_PARATR_ADJUST, sal_False, &pItem ) )
1593 eAdjust = ((const SvxAdjustItem *)pItem)
1594 ->GetAdjust();
1597 aItemSet.Put( SwTblBoxNumFormat(nNumFmt) );
1598 if( bHasValue )
1599 aItemSet.Put( SwTblBoxValue(nValue) );
1601 if( bLock )
1602 pFrmFmt->LockModify();
1603 pFrmFmt->SetFmtAttr( aItemSet );
1604 if( bLock )
1605 pFrmFmt->UnlockModify();
1606 else if( pCNd && SVX_ADJUST_END != eAdjust )
1608 SvxAdjustItem aAdjItem( eAdjust, RES_PARATR_ADJUST );
1609 pCNd->SetAttr( aAdjItem );
1612 else
1613 pFrmFmt->ResetFmtAttr( RES_BOXATR_FORMAT );
1615 ASSERT( eVOri != text::VertOrientation::TOP, "text::VertOrientation::TOP ist nicht erlaubt!" );
1616 if( text::VertOrientation::NONE != eVOri )
1618 pFrmFmt->SetFmtAttr( SwFmtVertOrient( 0, eVOri ) );
1620 else
1621 pFrmFmt->ResetFmtAttr( RES_VERT_ORIENT );
1623 if( bReUsable )
1624 pColumn->SetFrmFmt( pFrmFmt, bBottomLine, eVOri );
1626 else
1628 pFrmFmt->ResetFmtAttr( RES_BOX );
1629 pFrmFmt->ResetFmtAttr( RES_BACKGROUND );
1630 pFrmFmt->ResetFmtAttr( RES_VERT_ORIENT );
1631 pFrmFmt->ResetFmtAttr( RES_BOXATR_FORMAT );
1634 else
1636 ASSERT( pBox->GetSttNd() ||
1637 SFX_ITEM_SET!=pFrmFmt->GetAttrSet().GetItemState(
1638 RES_VERT_ORIENT, sal_False ),
1639 "Box ohne Inhalt hat vertikale Ausrichtung" );
1640 pBox->ChgFrmFmt( (SwTableBoxFmt*)pFrmFmt );
1645 void HTMLTable::FixFillerFrameFmt( SwTableBox *pBox, sal_Bool bRight ) const
1647 SwFrmFmt *pFrmFmt = pBox->ClaimFrmFmt();
1649 if( bFillerTopBorder || bFillerBottomBorder ||
1650 (!bRight && bInhLeftBorder) || (bRight && bInhRightBorder) )
1652 SvxBoxItem aBoxItem( RES_BOX );
1653 if( bFillerTopBorder )
1654 aBoxItem.SetLine( &aTopBorderLine, BOX_LINE_TOP );
1655 if( bFillerBottomBorder )
1656 aBoxItem.SetLine( &aBottomBorderLine, BOX_LINE_BOTTOM );
1657 if( !bRight && bInhLeftBorder )
1658 aBoxItem.SetLine( &aInhLeftBorderLine, BOX_LINE_LEFT );
1659 if( bRight && bInhRightBorder )
1660 aBoxItem.SetLine( &aInhRightBorderLine, BOX_LINE_RIGHT );
1661 aBoxItem.SetDistance( MIN_BORDER_DIST );
1662 pFrmFmt->SetFmtAttr( aBoxItem );
1664 else
1666 pFrmFmt->ResetFmtAttr( RES_BOX );
1669 if( GetInhBGBrush() )
1670 pFrmFmt->SetFmtAttr( *GetInhBGBrush() );
1671 else
1672 pFrmFmt->ResetFmtAttr( RES_BACKGROUND );
1674 pFrmFmt->ResetFmtAttr( RES_VERT_ORIENT );
1675 pFrmFmt->ResetFmtAttr( RES_BOXATR_FORMAT );
1678 SwTableBox *HTMLTable::NewTableBox( const SwStartNode *pStNd,
1679 SwTableLine *pUpper ) const
1681 SwTableBox *pBox;
1683 if( pTopTable->pBox1 &&
1684 pTopTable->pBox1->GetSttNd() == pStNd )
1686 // wenn der StartNode dem StartNode der initial angelegten Box
1687 // entspricht nehmen wir diese Box
1688 pBox = pTopTable->pBox1;
1689 pBox->SetUpper( pUpper );
1690 pTopTable->pBox1 = 0;
1692 else
1693 pBox = new SwTableBox( pBoxFmt, *pStNd, pUpper );
1695 return pBox;
1699 static void ResetLineFrmFmtAttrs( SwFrmFmt *pFrmFmt )
1701 pFrmFmt->ResetFmtAttr( RES_FRM_SIZE );
1702 pFrmFmt->ResetFmtAttr( RES_BACKGROUND );
1703 ASSERT( SFX_ITEM_SET!=pFrmFmt->GetAttrSet().GetItemState(
1704 RES_VERT_ORIENT, sal_False ),
1705 "Zeile hat vertikale Ausrichtung" );
1708 // !!! kann noch vereinfacht werden
1709 SwTableLine *HTMLTable::MakeTableLine( SwTableBox *pUpper,
1710 sal_uInt16 nTopRow, sal_uInt16 nLeftCol,
1711 sal_uInt16 nBottomRow, sal_uInt16 nRightCol )
1713 SwTableLine *pLine;
1714 if( this==pTopTable && !pUpper && 0==nTopRow )
1715 pLine = (pSwTable->GetTabLines())[0];
1716 else
1717 pLine = new SwTableLine( pLineFrmFmtNoHeight ? pLineFrmFmtNoHeight
1718 : pLineFmt,
1719 0, pUpper );
1721 HTMLTableRow *pTopRow = (*pRows)[nTopRow];
1722 sal_uInt16 nRowHeight = pTopRow->GetHeight();
1723 const SvxBrushItem *pBGBrushItem = 0;
1724 #ifndef FIX56334
1725 if( this == pTopTable || nTopRow>0 || nBottomRow<nRows )
1727 // An der Line eine Frabe zu setzen macht keinen Sinn, wenn sie
1728 // die auesserste und gleichzeitig einzige Zeile einer Tabelle in
1729 // der Tabelle ist.
1730 #endif
1731 pBGBrushItem = pTopRow->GetBGBrush();
1733 if( !pBGBrushItem && this != pTopTable )
1735 // Ein an einer Tabellen in der Tabelle gesetzter Hintergrund
1736 // wird an den Rows gesetzt. Das gilt auch fuer den Hintergrund
1737 // der Zelle, in dem die Tabelle vorkommt.
1738 pBGBrushItem = GetBGBrush();
1739 if( !pBGBrushItem )
1740 pBGBrushItem = GetInhBGBrush();
1742 #ifndef FIX56334
1744 #endif
1745 if( nTopRow==nBottomRow-1 && (nRowHeight || pBGBrushItem) )
1747 SwTableLineFmt *pFrmFmt = (SwTableLineFmt*)pLine->ClaimFrmFmt();
1748 ResetLineFrmFmtAttrs( pFrmFmt );
1750 if( nRowHeight )
1752 // Tabellenhoehe einstellen. Da es sich um eine
1753 // Mindesthoehe handelt, kann sie genauso wie in
1754 // Netscape berechnet werden, also ohne Beruecksichtigung
1755 // der tatsaechlichen Umrandungsbreite.
1756 nRowHeight += GetTopCellSpace( nTopRow, 1, sal_False ) +
1757 GetBottomCellSpace( nTopRow, 1, sal_False );
1759 pFrmFmt->SetFmtAttr( SwFmtFrmSize( ATT_MIN_SIZE, 0, nRowHeight ) );
1762 if( pBGBrushItem )
1764 pFrmFmt->SetFmtAttr( *pBGBrushItem );
1768 else if( !pLineFrmFmtNoHeight )
1770 // sonst muessen wir die Hoehe aus dem Attribut entfernen
1771 // und koennen uns das Format merken
1772 pLineFrmFmtNoHeight = (SwTableLineFmt*)pLine->ClaimFrmFmt();
1774 ResetLineFrmFmtAttrs( pLineFrmFmtNoHeight );
1778 SwTableBoxes& rBoxes = pLine->GetTabBoxes();
1780 sal_uInt16 nStartCol = nLeftCol;
1781 while( nStartCol<nRightCol )
1783 sal_uInt16 nCol = nStartCol;
1784 sal_uInt16 nSplitCol = nRightCol;
1785 sal_Bool bSplitted = sal_False;
1786 while( !bSplitted )
1788 ASSERT( nCol < nRightCol, "Zu weit gelaufen" );
1790 HTMLTableCell *pCell = GetCell(nTopRow,nCol);
1791 const sal_Bool bSplit = 1 == pCell->GetColSpan();
1793 #ifndef PRODUCT
1794 if( nCol == nRightCol-1 )
1796 ASSERT( bSplit, "Split-Flag falsch" );
1798 #endif
1799 if( bSplit )
1801 SwTableBox* pBox = 0;
1802 HTMLTableCell *pCell2 = GetCell( nTopRow, nStartCol );
1803 if( pCell2->GetColSpan() == (nCol+1-nStartCol) )
1805 // Die HTML-Tabellen-Zellen bilden genau eine Box.
1806 // Dann muss hinter der Box gesplittet werden
1807 nSplitCol = nCol + 1;
1809 long nBoxRowSpan = pCell2->GetRowSpan();
1810 if ( !pCell2->GetContents() || pCell2->IsCovered() )
1812 if ( pCell2->IsCovered() )
1813 nBoxRowSpan = -1 * nBoxRowSpan;
1815 const SwStartNode* pPrevStartNd =
1816 GetPrevBoxStartNode( nTopRow, nStartCol );
1817 HTMLTableCnts *pCnts = new HTMLTableCnts(
1818 pParser->InsertTableSection(pPrevStartNd) );
1819 SwHTMLTableLayoutCnts *pCntsLayoutInfo =
1820 pCnts->CreateLayoutInfo();
1822 pCell2->SetContents( pCnts );
1823 SwHTMLTableLayoutCell *pCurrCell = pLayoutInfo->GetCell( nTopRow, nStartCol );
1824 pCurrCell->SetContents( pCntsLayoutInfo );
1825 if( nBoxRowSpan < 0 )
1826 pCurrCell->SetRowSpan( 0 );
1828 // ggf. COLSPAN beachten
1829 for( sal_uInt16 j=nStartCol+1; j<nSplitCol; j++ )
1831 GetCell(nTopRow,j)->SetContents( pCnts );
1832 pLayoutInfo->GetCell( nTopRow, j )
1833 ->SetContents( pCntsLayoutInfo );
1837 pBox = MakeTableBox( pLine, pCell2->GetContents(),
1838 nTopRow, nStartCol,
1839 nBottomRow, nSplitCol );
1841 if ( 1 != nBoxRowSpan )
1842 pBox->setRowSpan( nBoxRowSpan );
1844 bSplitted = sal_True;
1847 ASSERT( pBox, "Colspan trouble" )
1849 if( pBox )
1850 rBoxes.C40_INSERT( SwTableBox, pBox, rBoxes.Count() );
1852 nCol++;
1854 nStartCol = nSplitCol;
1857 return pLine;
1860 SwTableBox *HTMLTable::MakeTableBox( SwTableLine *pUpper,
1861 HTMLTableCnts *pCnts,
1862 sal_uInt16 nTopRow, sal_uInt16 nLeftCol,
1863 sal_uInt16 nBottomRow, sal_uInt16 nRightCol )
1865 SwTableBox *pBox;
1866 sal_uInt16 nColSpan = nRightCol - nLeftCol;
1867 sal_uInt16 nRowSpan = nBottomRow - nTopRow;
1869 if( !pCnts->Next() )
1871 // nur eine Inhalts-Section
1872 if( pCnts->GetStartNode() )
1874 // und die ist keine Tabelle
1875 pBox = NewTableBox( pCnts->GetStartNode(), pUpper );
1876 pCnts->SetTableBox( pBox );
1878 else
1880 pCnts->GetTable()->InheritVertBorders( this, nLeftCol,
1881 nRightCol-nLeftCol );
1882 // und die ist eine Tabelle: dann bauen wir eine neue
1883 // Box und fuegen die Zeilen der Tabelle in die Zeilen
1884 // der Box ein
1885 pBox = new SwTableBox( pBoxFmt, 0, pUpper );
1886 sal_uInt16 nAbs, nRel;
1887 pLayoutInfo->GetAvail( nLeftCol, nColSpan, nAbs, nRel );
1888 sal_uInt16 nLSpace = pLayoutInfo->GetLeftCellSpace( nLeftCol, nColSpan );
1889 sal_uInt16 nRSpace = pLayoutInfo->GetRightCellSpace( nLeftCol, nColSpan );
1890 sal_uInt16 nInhSpace = pLayoutInfo->GetInhCellSpace( nLeftCol, nColSpan );
1891 pCnts->GetTable()->MakeTable( pBox, nAbs, nRel, nLSpace, nRSpace,
1892 nInhSpace );
1895 else
1897 // mehrere Inhalts Sections: dann brauchen wir eine Box mit Zeilen
1898 pBox = new SwTableBox( pBoxFmt, 0, pUpper );
1899 SwTableLines& rLines = pBox->GetTabLines();
1900 sal_Bool bFirstPara = sal_True;
1902 while( pCnts )
1904 if( pCnts->GetStartNode() )
1906 // normale Absaetze werden zu einer Box in einer Zeile
1907 SwTableLine *pLine =
1908 new SwTableLine( pLineFrmFmtNoHeight ? pLineFrmFmtNoHeight
1909 : pLineFmt, 0, pBox );
1910 if( !pLineFrmFmtNoHeight )
1912 // Wenn es noch kein Line-Format ohne Hoehe gibt, koennen
1913 // wir uns dieses her als soleches merken
1914 pLineFrmFmtNoHeight = (SwTableLineFmt*)pLine->ClaimFrmFmt();
1916 ResetLineFrmFmtAttrs( pLineFrmFmtNoHeight );
1919 SwTableBox* pCntBox = NewTableBox( pCnts->GetStartNode(),
1920 pLine );
1921 pCnts->SetTableBox( pCntBox );
1922 FixFrameFmt( pCntBox, nTopRow, nLeftCol, nRowSpan, nColSpan,
1923 bFirstPara, 0==pCnts->Next() );
1924 pLine->GetTabBoxes().C40_INSERT( SwTableBox, pCntBox,
1925 pLine->GetTabBoxes().Count() );
1927 rLines.C40_INSERT( SwTableLine, pLine, rLines.Count() );
1929 else
1931 pCnts->GetTable()->InheritVertBorders( this, nLeftCol,
1932 nRightCol-nLeftCol );
1933 // Tabellen werden direkt eingetragen
1934 sal_uInt16 nAbs, nRel;
1935 pLayoutInfo->GetAvail( nLeftCol, nColSpan, nAbs, nRel );
1936 sal_uInt16 nLSpace = pLayoutInfo->GetLeftCellSpace( nLeftCol,
1937 nColSpan );
1938 sal_uInt16 nRSpace = pLayoutInfo->GetRightCellSpace( nLeftCol,
1939 nColSpan );
1940 sal_uInt16 nInhSpace = pLayoutInfo->GetInhCellSpace( nLeftCol, nColSpan );
1941 pCnts->GetTable()->MakeTable( pBox, nAbs, nRel, nLSpace,
1942 nRSpace, nInhSpace );
1945 pCnts = pCnts->Next();
1946 bFirstPara = sal_False;
1950 FixFrameFmt( pBox, nTopRow, nLeftCol, nRowSpan, nColSpan );
1952 return pBox;
1955 void HTMLTable::InheritBorders( const HTMLTable *pParent,
1956 sal_uInt16 nRow, sal_uInt16 nCol,
1957 sal_uInt16 nRowSpan, sal_uInt16 /*nColSpan*/,
1958 sal_Bool bFirstPara, sal_Bool bLastPara )
1960 ASSERT( nRows>0 && nCols>0 && nCurRow==nRows,
1961 "Wurde CloseTable nicht aufgerufen?" );
1963 // Die Child-Tabelle muss einen Rahmen bekommen, wenn die umgebende
1964 // Zelle einen Rand an der betreffenden Seite besitzt.
1965 // Der obere bzw. untere Rand wird nur gesetzt, wenn die Tabelle
1966 // ale erster bzw. letzter Absatz in der Zelle vorkommt. Ansonsten
1967 // Fuer den linken/rechten Rand kann noch nicht entschieden werden,
1968 // ob eine Umrandung der Tabelle noetig/moeglich ist, weil das davon
1969 // abhaengt, ob "Filler"-Zellen eingefuegt werden. Hier werden deshalb
1970 // erstmal nur Informationen gesammelt
1972 if( 0==nRow && pParent->bTopBorder && bFirstPara )
1974 bTopBorder = sal_True;
1975 bFillerTopBorder = sal_True; // auch Filler bekommt eine Umrandung
1976 aTopBorderLine = pParent->aTopBorderLine;
1978 if( ((*pParent->pRows)[nRow+nRowSpan-1])->bBottomBorder && bLastPara )
1980 ((*pRows)[nRows-1])->bBottomBorder = sal_True;
1981 bFillerBottomBorder = sal_True; // auch Filler bekommt eine Umrandung
1982 aBottomBorderLine =
1983 nRow+nRowSpan==pParent->nRows ? pParent->aBottomBorderLine
1984 : pParent->aBorderLine;
1988 // Die Child Tabelle darf keinen oberen oder linken Rahmen bekommen,
1989 // wenn der bereits durch die umgebende Tabelle gesetzt ist.
1990 // Sie darf jedoch immer einen oberen Rand bekommen, wenn die Tabelle
1991 // nicht der erste Absatz in der Zelle ist.
1992 bTopAlwd = ( !bFirstPara || (pParent->bTopAlwd &&
1993 (0==nRow || !((*pParent->pRows)[nRow-1])->bBottomBorder)) );
1995 // die Child-Tabelle muss die Farbe der Zelle erben, in der sie
1996 // vorkommt, wenn sie keine eigene besitzt
1997 const SvxBrushItem *pInhBG = pParent->GetCell(nRow,nCol)->GetBGBrush();
1998 if( !pInhBG && pParent != pTopTable &&
1999 pParent->GetCell(nRow,nCol)->GetRowSpan() == pParent->nRows )
2001 // die ganze umgebende Tabelle ist eine Tabelle in der Tabelle
2002 // und besteht nur aus einer Line, die bei der GC (zu Recht)
2003 // wegoptimiert wird. Deshalb muss der Hintergrund der Line in
2004 // diese Tabelle uebernommen werden.
2005 pInhBG = ((*pParent->pRows)[nRow])->GetBGBrush();
2006 if( !pInhBG )
2007 pInhBG = pParent->GetBGBrush();
2008 if( !pInhBG )
2009 pInhBG = pParent->GetInhBGBrush();
2011 if( pInhBG )
2012 pInhBGBrush = new SvxBrushItem( *pInhBG );
2015 void HTMLTable::InheritVertBorders( const HTMLTable *pParent,
2016 sal_uInt16 nCol, sal_uInt16 nColSpan )
2018 sal_uInt16 nInhLeftBorderWidth = 0;
2019 sal_uInt16 nInhRightBorderWidth = 0;
2021 if( nCol+nColSpan==pParent->nCols && pParent->bRightBorder )
2023 bInhRightBorder = sal_True; // erstmal nur merken
2024 aInhRightBorderLine = pParent->aRightBorderLine;
2025 nInhRightBorderWidth =
2026 GetBorderWidth( aInhRightBorderLine, sal_True ) + MIN_BORDER_DIST;
2029 if( ((*pParent->pColumns)[nCol])->bLeftBorder )
2031 bInhLeftBorder = sal_True; // erstmal nur merken
2032 aInhLeftBorderLine = 0==nCol ? pParent->aLeftBorderLine
2033 : pParent->aBorderLine;
2034 nInhLeftBorderWidth =
2035 GetBorderWidth( aInhLeftBorderLine, sal_True ) + MIN_BORDER_DIST;
2038 if( !bInhLeftBorder && (bFillerTopBorder || bFillerBottomBorder) )
2039 nInhLeftBorderWidth = 2 * MIN_BORDER_DIST;
2040 if( !bInhRightBorder && (bFillerTopBorder || bFillerBottomBorder) )
2041 nInhRightBorderWidth = 2 * MIN_BORDER_DIST;
2042 pLayoutInfo->SetInhBorderWidths( nInhLeftBorderWidth,
2043 nInhRightBorderWidth );
2045 bRightAlwd = ( pParent->bRightAlwd &&
2046 (nCol+nColSpan==pParent->nCols ||
2047 !((*pParent->pColumns)[nCol+nColSpan])->bLeftBorder) );
2050 void HTMLTable::SetBorders()
2052 sal_uInt16 i;
2053 for( i=1; i<nCols; i++ )
2054 if( HTML_TR_ALL==eRules || HTML_TR_COLS==eRules ||
2055 ((HTML_TR_ROWS==eRules || HTML_TR_GROUPS==eRules) &&
2056 ((*pColumns)[i-1])->IsEndOfGroup()) )
2057 ((*pColumns)[i])->bLeftBorder = sal_True;
2059 for( i=0; i<nRows-1; i++ )
2060 if( HTML_TR_ALL==eRules || HTML_TR_ROWS==eRules ||
2061 ((HTML_TR_COLS==eRules || HTML_TR_GROUPS==eRules) &&
2062 ((*pRows)[i])->IsEndOfGroup()) )
2063 ((*pRows)[i])->bBottomBorder = sal_True;
2065 if( bTopAlwd && (HTML_TF_ABOVE==eFrame || HTML_TF_HSIDES==eFrame ||
2066 HTML_TF_BOX==eFrame) )
2067 bTopBorder = sal_True;
2068 if( HTML_TF_BELOW==eFrame || HTML_TF_HSIDES==eFrame ||
2069 HTML_TF_BOX==eFrame )
2070 ((*pRows)[nRows-1])->bBottomBorder = sal_True;
2071 if( /*bRightAlwd &&*/ (HTML_TF_RHS==eFrame || HTML_TF_VSIDES==eFrame ||
2072 HTML_TF_BOX==eFrame) )
2073 bRightBorder = sal_True;
2074 if( HTML_TF_LHS==eFrame || HTML_TF_VSIDES==eFrame || HTML_TF_BOX==eFrame )
2075 ((*pColumns)[0])->bLeftBorder = sal_True;
2077 for( i=0; i<nRows; i++ )
2079 HTMLTableRow *pRow = (*pRows)[i];
2080 for( sal_uInt16 j=0; j<nCols; j++ )
2082 HTMLTableCell *pCell = pRow->GetCell(j);
2083 if( pCell->GetContents() )
2085 HTMLTableCnts *pCnts = pCell->GetContents();
2086 sal_Bool bFirstPara = sal_True;
2087 while( pCnts )
2089 HTMLTable *pTable = pCnts->GetTable();
2090 if( pTable && !pTable->BordersSet() )
2092 pTable->InheritBorders( this, i, j,
2093 pCell->GetRowSpan(),
2094 pCell->GetColSpan(),
2095 bFirstPara,
2096 0==pCnts->Next() );
2097 pTable->SetBorders();
2099 bFirstPara = sal_False;
2100 pCnts = pCnts->Next();
2106 bBordersSet = sal_True;
2109 sal_uInt16 HTMLTable::GetBorderWidth( const SvxBorderLine& rBLine,
2110 sal_Bool bWithDistance ) const
2112 sal_uInt16 nBorderWidth = rBLine.GetOutWidth() + rBLine.GetInWidth() +
2113 rBLine.GetDistance();
2114 if( bWithDistance )
2116 if( nCellPadding )
2117 nBorderWidth = nBorderWidth + nCellPadding;
2118 else if( nBorderWidth )
2119 nBorderWidth = nBorderWidth + MIN_BORDER_DIST;
2122 return nBorderWidth;
2125 inline HTMLTableCell *HTMLTable::GetCell( sal_uInt16 nRow,
2126 sal_uInt16 nCell ) const
2128 ASSERT( nRow<pRows->Count(),
2129 "ungueltiger Zeilen-Index in HTML-Tabelle" );
2130 return ((*pRows)[nRow])->GetCell( nCell );
2135 SvxAdjust HTMLTable::GetInheritedAdjust() const
2137 SvxAdjust eAdjust = (nCurCol<nCols ? ((*pColumns)[nCurCol])->GetAdjust()
2138 : SVX_ADJUST_END );
2139 if( SVX_ADJUST_END==eAdjust )
2140 eAdjust = ((*pRows)[nCurRow])->GetAdjust();
2142 return eAdjust;
2145 sal_Int16 HTMLTable::GetInheritedVertOri() const
2147 // text::VertOrientation::TOP ist der default!
2148 sal_Int16 eVOri = ((*pRows)[nCurRow])->GetVertOri();
2149 if( text::VertOrientation::TOP==eVOri && nCurCol<nCols )
2150 eVOri = ((*pColumns)[nCurCol])->GetVertOri();
2151 if( text::VertOrientation::TOP==eVOri )
2152 eVOri = eVertOri;
2154 ASSERT( eVertOri != text::VertOrientation::TOP, "text::VertOrientation::TOP ist nicht erlaubt!" );
2155 return eVOri;
2158 void HTMLTable::InsertCell( HTMLTableCnts *pCnts,
2159 sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
2160 sal_uInt16 nCellWidth, sal_Bool bRelWidth, sal_uInt16 nCellHeight,
2161 sal_Int16 eVertOrient, SvxBrushItem *pBGBrushItem,
2162 sal_Bool bHasNumFmt, sal_uInt32 nNumFmt,
2163 sal_Bool bHasValue, double nValue, sal_Bool bNoWrap )
2165 if( !nRowSpan || (sal_uInt32)nCurRow + nRowSpan > USHRT_MAX )
2166 nRowSpan = 1;
2168 if( !nColSpan || (sal_uInt32)nCurCol + nColSpan > USHRT_MAX )
2169 nColSpan = 1;
2171 sal_uInt16 nColsReq = nCurCol + nColSpan; // benoetigte Spalten
2172 sal_uInt16 nRowsReq = nCurRow + nRowSpan; // benoetigte Zeilen
2173 sal_uInt16 i, j;
2175 // falls wir mehr Spalten benoetigen als wir zur Zeit haben,
2176 // muessen wir in allen Zeilen noch Zellen hinzufuegen
2177 if( nCols < nColsReq )
2179 for( i=nCols; i<nColsReq; i++ )
2180 pColumns->Insert( new HTMLTableColumn, pColumns->Count() );
2181 for( i=0; i<nRows; i++ )
2182 ((*pRows)[i])->Expand( nColsReq, i<nCurRow );
2183 nCols = nColsReq;
2184 ASSERT( pColumns->Count()==nCols,
2185 "Anzahl der Spalten nach Expandieren stimmt nicht" );
2187 if( nColsReq > nFilledCols )
2188 nFilledCols = nColsReq;
2190 // falls wir mehr Zeilen benoetigen als wir zur Zeit haben,
2191 // muessen wir noch neue Zeilen hinzufuegen
2192 if( nRows < nRowsReq )
2194 for( i=nRows; i<nRowsReq; i++ )
2195 pRows->Insert( new HTMLTableRow(nCols), pRows->Count() );
2196 nRows = nRowsReq;
2197 ASSERT( nRows==pRows->Count(), "Zeilenzahl in Insert stimmt nicht" );
2200 // Testen, ob eine Ueberschneidung vorliegt und diese
2201 // gegebenfalls beseitigen
2202 sal_uInt16 nSpanedCols = 0;
2203 if( nCurRow>0 )
2205 HTMLTableRow *pCurRow = (*pRows)[nCurRow];
2206 for( i=nCurCol; i<nColsReq; i++ )
2208 HTMLTableCell *pCell = pCurRow->GetCell(i);
2209 if( pCell->GetContents() )
2211 // Der Inhalt reicht von einer weiter oben stehenden Zelle
2212 // hier herein. Inhalt und Farbe der Zelle sind deshalb in
2213 // jedem Fall noch dort verankert und koennen deshalb
2214 // ueberschrieben werden bzw. von ProtectRowSpan geloescht
2215 // (Inhalt) oder kopiert (Farbe) werden.
2216 nSpanedCols = i + pCell->GetColSpan();
2217 FixRowSpan( nCurRow-1, i, pCell->GetContents() );
2218 if( pCell->GetRowSpan() > nRowSpan )
2219 ProtectRowSpan( nRowsReq, i,
2220 pCell->GetRowSpan()-nRowSpan );
2223 for( i=nColsReq; i<nSpanedCols; i++ )
2225 // Auch diese Inhalte sind in jedem Fall nich in der Zeile
2226 // darueber verankert.
2227 HTMLTableCell *pCell = pCurRow->GetCell(i);
2228 FixRowSpan( nCurRow-1, i, pCell->GetContents() );
2229 ProtectRowSpan( nCurRow, i, pCell->GetRowSpan() );
2233 // Fill the cells
2234 for( i=nColSpan; i>0; i-- )
2236 for( j=nRowSpan; j>0; j-- )
2238 const bool bCovered = i != nColSpan || j != nRowSpan;
2239 GetCell( nRowsReq-j, nColsReq-i )
2240 ->Set( pCnts, j, i, eVertOrient, pBGBrushItem,
2241 bHasNumFmt, nNumFmt, bHasValue, nValue, bNoWrap, bCovered );
2245 Size aTwipSz( bRelWidth ? 0 : nCellWidth, nCellHeight );
2246 if( (aTwipSz.Width() || aTwipSz.Height()) && Application::GetDefaultDevice() )
2248 aTwipSz = Application::GetDefaultDevice()
2249 ->PixelToLogic( aTwipSz, MapMode( MAP_TWIP ) );
2252 // die Breite nur in die erste Zelle setzen!
2253 if( nCellWidth )
2255 sal_uInt16 nTmp = bRelWidth ? nCellWidth : (sal_uInt16)aTwipSz.Width();
2256 GetCell( nCurRow, nCurCol )->SetWidth( nTmp, bRelWidth );
2259 // Ausserdem noch die Hoehe merken
2260 if( nCellHeight && 1==nRowSpan )
2262 if( nCellHeight < MINLAY )
2263 nCellHeight = MINLAY;
2264 ((*pRows)[nCurRow])->SetHeight( (sal_uInt16)aTwipSz.Height() );
2267 // den Spaltenzaehler hinter die neuen Zellen setzen
2268 nCurCol = nColsReq;
2269 if( nSpanedCols > nCurCol )
2270 nCurCol = nSpanedCols;
2272 // und die naechste freie Zelle suchen
2273 while( nCurCol<nCols && GetCell(nCurRow,nCurCol)->IsUsed() )
2274 nCurCol++;
2277 inline void HTMLTable::CloseSection( sal_Bool bHead )
2279 // die vorhergende Section beenden, falls es schon eine Zeile gibt
2280 ASSERT( nCurRow<=nRows, "ungeultige aktuelle Zeile" );
2281 if( nCurRow>0 && nCurRow<=nRows )
2282 ((*pRows)[nCurRow-1])->SetEndOfGroup();
2283 if( bHead /*&& nCurRow==1*/ )
2284 // bHeadlineRepeat = sal_True;
2285 nHeadlineRepeat = nCurRow;
2288 void HTMLTable::OpenRow( SvxAdjust eAdjust, sal_Int16 eVertOrient,
2289 SvxBrushItem *pBGBrushItem )
2291 sal_uInt16 nRowsReq = nCurRow+1; // Anzahl benoetigter Zeilen;
2293 // die naechste Zeile anlegen, falls sie nicht schon da ist
2294 if( nRows<nRowsReq )
2296 for( sal_uInt16 i=nRows; i<nRowsReq; i++ )
2297 pRows->Insert( new HTMLTableRow(nCols), pRows->Count() );
2298 nRows = nRowsReq;
2299 ASSERT( nRows==pRows->Count(),
2300 "Zeilenzahl in OpenRow stimmt nicht" );
2303 HTMLTableRow *pCurRow = ((*pRows)[nCurRow]);
2304 pCurRow->SetAdjust( eAdjust );
2305 pCurRow->SetVertOri( eVertOrient );
2306 if( pBGBrushItem )
2307 ((*pRows)[nCurRow])->SetBGBrush( pBGBrushItem );
2309 // den Spaltenzaehler wieder an den Anfang setzen
2310 nCurCol=0;
2312 // und die naechste freie Zelle suchen
2313 while( nCurCol<nCols && GetCell(nCurRow,nCurCol)->IsUsed() )
2314 nCurCol++;
2317 void HTMLTable::CloseRow( sal_Bool bEmpty )
2319 ASSERT( nCurRow<nRows, "aktulle Zeile hinter dem Tabellenende" );
2321 // leere Zellen bekommen einfach einen etwas dickeren unteren Rand!
2322 if( bEmpty )
2324 if( nCurRow > 0 )
2325 ((*pRows)[nCurRow-1])->IncEmptyRows();
2326 return;
2329 HTMLTableRow *pRow = (*pRows)[nCurRow];
2331 // den COLSPAN aller leeren Zellen am Zeilenende so anpassen, dass
2332 // eine Zelle daraus wird. Das kann man hier machen (und auf keinen
2333 // Fall frueher), weill jetzt keine Zellen mehr in die Zeile eingefuegt
2334 // werden.
2335 sal_uInt16 i=nCols;
2336 while( i )
2338 HTMLTableCell *pCell = pRow->GetCell(--i);
2339 if( !pCell->GetContents() )
2341 sal_uInt16 nColSpan = nCols-i;
2342 if( nColSpan > 1 )
2343 pCell->SetColSpan( nColSpan );
2345 else
2346 break;
2350 nCurRow++;
2353 inline void HTMLTable::CloseColGroup( sal_uInt16 nSpan, sal_uInt16 _nWidth,
2354 sal_Bool bRelWidth, SvxAdjust eAdjust,
2355 sal_Int16 eVertOrient )
2357 if( nSpan )
2358 InsertCol( nSpan, _nWidth, bRelWidth, eAdjust, eVertOrient );
2360 ASSERT( nCurCol<=nCols, "ungueltige Spalte" );
2361 if( nCurCol>0 && nCurCol<=nCols )
2362 ((*pColumns)[nCurCol-1])->SetEndOfGroup();
2365 void HTMLTable::InsertCol( sal_uInt16 nSpan, sal_uInt16 nColWidth, sal_Bool bRelWidth,
2366 SvxAdjust eAdjust, sal_Int16 eVertOrient )
2368 // --> OD, MIB 2004-11-08 #i35143# - no columns, if rows already exist.
2369 if ( nRows > 0 )
2370 return;
2371 // <--
2373 sal_uInt16 i;
2375 if( !nSpan )
2376 nSpan = 1;
2378 sal_uInt16 nColsReq = nCurCol + nSpan; // benoetigte Spalten
2380 if( nCols < nColsReq )
2382 for( i=nCols; i<nColsReq; i++ )
2383 pColumns->Insert( new HTMLTableColumn, pColumns->Count() );
2384 nCols = nColsReq;
2387 Size aTwipSz( bRelWidth ? 0 : nColWidth, 0 );
2388 if( aTwipSz.Width() && Application::GetDefaultDevice() )
2390 aTwipSz = Application::GetDefaultDevice()
2391 ->PixelToLogic( aTwipSz, MapMode( MAP_TWIP ) );
2394 for( i=nCurCol; i<nColsReq; i++ )
2396 HTMLTableColumn *pCol = (*pColumns)[i];
2397 sal_uInt16 nTmp = bRelWidth ? nColWidth : (sal_uInt16)aTwipSz.Width();
2398 pCol->SetWidth( nTmp, bRelWidth );
2399 pCol->SetAdjust( eAdjust );
2400 pCol->SetVertOri( eVertOrient );
2403 bColSpec = sal_True;
2405 nCurCol = nColsReq;
2409 void HTMLTable::CloseTable()
2411 sal_uInt16 i;
2413 // Die Anzahl der Tabellenzeilen richtet sich nur nach den
2414 // <TR>-Elementen (d.h. nach nCurRow). Durch ROWSPAN aufgespannte
2415 // Zeilen hinter Zeile nCurRow muessen wir deshalb loeschen
2416 // und vor allem aber den ROWSPAN in den darueberliegenden Zeilen
2417 // anpassen.
2418 if( nRows>nCurRow )
2420 HTMLTableRow *pPrevRow = (*pRows)[nCurRow-1];
2421 HTMLTableCell *pCell;
2422 for( i=0; i<nCols; i++ )
2423 if( ( pCell=pPrevRow->GetCell(i), pCell->GetRowSpan() > 1 ) )
2425 FixRowSpan( nCurRow-1, i, pCell->GetContents() );
2426 ProtectRowSpan( nCurRow, i, (*pRows)[nCurRow]->GetCell(i)->GetRowSpan() );
2428 for( i=nRows-1; i>=nCurRow; i-- )
2429 pRows->DeleteAndDestroy(i);
2430 nRows = nCurRow;
2433 // falls die Tabelle keine Spalte hat, muessen wir eine hinzufuegen
2434 if( 0==nCols )
2436 pColumns->Insert( new HTMLTableColumn, pColumns->Count() );
2437 for( i=0; i<nRows; i++ )
2438 ((*pRows)[i])->Expand(1);
2439 nCols = 1;
2440 nFilledCols = 1;
2443 // falls die Tabelle keine Zeile hat, muessen wir eine hinzufuegen
2444 if( 0==nRows )
2446 pRows->Insert( new HTMLTableRow(nCols), pRows->Count() );
2447 nRows = 1;
2448 nCurRow = 1;
2451 if( nFilledCols < nCols )
2453 pColumns->DeleteAndDestroy( nFilledCols, nCols-nFilledCols );
2454 for( i=0; i<nRows; i++ )
2455 ((*pRows)[i])->Shrink( nFilledCols );
2456 nCols = nFilledCols;
2460 void HTMLTable::_MakeTable( SwTableBox *pBox )
2462 SwTableLines& rLines = (pBox ? pBox->GetTabLines()
2463 : ((SwTable *)pSwTable)->GetTabLines() );
2465 // jetzt geht's richtig los ...
2467 for( sal_uInt16 i=0; i<nRows; i++ )
2469 SwTableLine *pLine = MakeTableLine( pBox, i, 0, i+1, nCols );
2470 if( pBox || i > 0 )
2471 rLines.C40_INSERT( SwTableLine, pLine, rLines.Count() );
2475 /* Wie werden Tabellen ausgerichtet?
2477 erste Zeile: ohne Absatz-Einzuege
2478 zweite Zeile: mit Absatz-Einzuegen
2480 ALIGN= LEFT RIGHT CENTER -
2481 -------------------------------------------------------------------------
2482 xxx bei Tabellen mit WIDTH=nn% ist die Prozent-Angabe von Bedeutung:
2483 xxx nn = 100 text::HoriOrientation::FULL text::HoriOrientation::FULL text::HoriOrientation::FULL text::HoriOrientation::FULL %
2484 xxx text::HoriOrientation::NONE text::HoriOrientation::NONE text::HoriOrientation::NONE % text::HoriOrientation::NONE %
2485 xxx nn < 100 Rahmen F Rahmen F text::HoriOrientation::CENTER % text::HoriOrientation::LEFT %
2486 xxx Rahmen F Rahmen F text::HoriOrientation::CENTER % text::HoriOrientation::NONE %
2488 bei Tabellen mit WIDTH=nn% ist die Prozent-Angabe von Bedeutung:
2489 nn = 100 text::HoriOrientation::LEFT text::HoriOrientation::RIGHT text::HoriOrientation::CENTER % text::HoriOrientation::LEFT %
2490 text::HoriOrientation::LEFT_AND text::HoriOrientation::RIGHT text::HoriOrientation::CENTER % text::HoriOrientation::LEFT_AND %
2491 nn < 100 Rahmen F Rahmen F text::HoriOrientation::CENTER % text::HoriOrientation::LEFT %
2492 Rahmen F Rahmen F text::HoriOrientation::CENTER % text::HoriOrientation::NONE %
2494 sonst die berechnete Breite w
2495 w = avail* text::HoriOrientation::LEFT text::HoriOrientation::RIGHT text::HoriOrientation::CENTER text::HoriOrientation::LEFT
2496 HORI_LEDT_AND text::HoriOrientation::RIGHT text::HoriOrientation::CENTER text::HoriOrientation::LEFT_AND
2497 w < avail Rahmen L Rahmen L text::HoriOrientation::CENTER text::HoriOrientation::LEFT
2498 Rahmen L Rahmen L text::HoriOrientation::CENTER text::HoriOrientation::NONE
2500 xxx *) wenn fuer die Tabelle keine Groesse angegeben wurde, wird immer
2501 xxx text::HoriOrientation::FULL genommen
2505 void HTMLTable::MakeTable( SwTableBox *pBox, sal_uInt16 nAbsAvail,
2506 sal_uInt16 nRelAvail, sal_uInt16 nAbsLeftSpace,
2507 sal_uInt16 nAbsRightSpace, sal_uInt16 nInhAbsSpace )
2509 ASSERT( nRows>0 && nCols>0 && nCurRow==nRows,
2510 "Wurde CloseTable nicht aufgerufen?" );
2512 ASSERT( (pLayoutInfo==0) == (this==pTopTable),
2513 "Top-Tabelle hat keine Layout-Info oder umgekehrt" );
2515 if( this==pTopTable )
2517 // Umrandung der Tabelle und aller in ihr enthaltenen berechnen
2518 SetBorders();
2520 // Schritt 1: Die benoetigten Layout-Strukturen werden angelegt
2521 // (inklusive Tabellen in Tabellen).
2522 CreateLayoutInfo();
2524 // Schritt 2: Die minimalen und maximalen Spaltenbreiten werden
2525 // berechnet (inklusive Tabellen in Tabellen). Da wir noch keine
2526 // Boxen haben, arabeiten wir noch auf den Start-Nodes.
2527 pLayoutInfo->AutoLayoutPass1();
2530 // Schritt 3: Die tatsaechlichen Spaltenbreiten dieser Tabelle werden
2531 // berechnet (nicht von Tabellen in Tabellen). Dies muss jetzt schon
2532 // sein, damit wir entscheiden koennen ob Filler-Zellen benoetigt werden
2533 // oder nicht (deshalb war auch Pass1 schon noetig).
2534 pLayoutInfo->AutoLayoutPass2( nAbsAvail, nRelAvail, nAbsLeftSpace,
2535 nAbsRightSpace, nInhAbsSpace );
2537 if( this!=pTopTable )
2539 // die linke und rechte Umrandung der Tabelle kann jetzt entgueltig
2540 // festgelegt werden
2541 if( pLayoutInfo->GetRelRightFill() == 0 )
2543 if( !bRightBorder )
2545 // linke Umrandung von auesserer Tabelle uebernehmen
2546 if( bInhRightBorder )
2548 bRightBorder = sal_True;
2549 aRightBorderLine = aInhRightBorderLine;
2552 else
2554 // Umrandung nur setzen, wenn es erlaubt ist
2555 bRightBorder = bRightAlwd;
2559 if( pLayoutInfo->GetRelLeftFill() == 0 &&
2560 !((*pColumns)[0])->bLeftBorder &&
2561 bInhLeftBorder )
2563 // ggf. rechte Umrandung von auesserer Tabelle uebernehmen
2564 ((*pColumns)[0])->bLeftBorder = sal_True;
2565 aLeftBorderLine = aInhLeftBorderLine;
2569 // Fuer die Top-Table muss die Ausrichtung gesetzt werden
2570 if( this==pTopTable )
2572 sal_Int16 eHoriOri;
2573 if( bForceFrame )
2575 // Die Tabelle soll in einen Rahmen und ist auch schmaler
2576 // als der verfuegbare Platz und nicht 100% breit.
2577 // Dann kommt sie in einen Rahmen
2578 eHoriOri = bPrcWidth ? text::HoriOrientation::FULL : text::HoriOrientation::LEFT;
2580 else switch( eTableAdjust )
2582 // Die Tabelle passt entweder auf die Seite, soll aber in keinen
2583 // Rahmen oder sie ist Breiter als die Seite und soll deshalb
2584 // in keinen Rahmen
2586 case SVX_ADJUST_RIGHT:
2587 // in rechtsbuendigen Tabellen kann nicht auf den rechten
2588 // Rand Ruecksicht genommen werden
2589 eHoriOri = text::HoriOrientation::RIGHT;
2590 break;
2591 case SVX_ADJUST_CENTER:
2592 // zentrierte Tabellen nehmen keine Ruecksicht auf Raender!
2593 eHoriOri = text::HoriOrientation::CENTER;
2594 break;
2595 case SVX_ADJUST_LEFT:
2596 default:
2597 // linksbuendige Tabellen nehmen nur auf den linken Rand
2598 // Ruecksicht
2599 eHoriOri = nLeftMargin ? text::HoriOrientation::LEFT_AND_WIDTH : text::HoriOrientation::LEFT;
2600 break;
2603 // das Tabellenform holen und anpassen
2604 SwFrmFmt *pFrmFmt = pSwTable->GetFrmFmt();
2605 pFrmFmt->SetFmtAttr( SwFmtHoriOrient(0,eHoriOri) );
2606 if( text::HoriOrientation::LEFT_AND_WIDTH==eHoriOri )
2608 ASSERT( nLeftMargin || nRightMargin,
2609 "Da gibt's wohl noch Reste von relativen Breiten" );
2611 // The right margin will be ignored anyway.
2612 SvxLRSpaceItem aLRItem( pSwTable->GetFrmFmt()->GetLRSpace() );
2613 aLRItem.SetLeft( nLeftMargin );
2614 aLRItem.SetRight( nRightMargin );
2615 pFrmFmt->SetFmtAttr( aLRItem );
2618 if( bPrcWidth && text::HoriOrientation::FULL!=eHoriOri )
2620 pFrmFmt->LockModify();
2621 SwFmtFrmSize aFrmSize( pFrmFmt->GetFrmSize() );
2622 aFrmSize.SetWidthPercent( (sal_uInt8)nWidth );
2623 pFrmFmt->SetFmtAttr( aFrmSize );
2624 pFrmFmt->UnlockModify();
2628 // die Default Line- und Box-Formate holen
2629 if( this==pTopTable )
2631 // die erste Box merken und aus der ersten Zeile ausketten
2632 SwTableLine *pLine1 = (pSwTable->GetTabLines())[0];
2633 pBox1 = (pLine1->GetTabBoxes())[0];
2634 pLine1->GetTabBoxes().Remove(0);
2636 pLineFmt = (SwTableLineFmt*)pLine1->GetFrmFmt();
2637 pBoxFmt = (SwTableBoxFmt*)pBox1->GetFrmFmt();
2639 else
2641 pLineFmt = (SwTableLineFmt*)pTopTable->pLineFmt;
2642 pBoxFmt = (SwTableBoxFmt*)pTopTable->pBoxFmt;
2645 // ggf. muessen fuer Tabellen in Tabellen "Filler"-Zellen eingefuegt
2646 // werden
2647 if( this != pTopTable &&
2648 ( pLayoutInfo->GetRelLeftFill() > 0 ||
2649 pLayoutInfo->GetRelRightFill() > 0 ) )
2651 ASSERT( pBox, "kein TableBox fuer Tabelle in Tabelle" );
2653 SwTableLines& rLines = pBox->GetTabLines();
2655 // dazu brauchen wir erstmal ein eine neue Table-Line in der Box
2656 SwTableLine *pLine =
2657 new SwTableLine( pLineFrmFmtNoHeight ? pLineFrmFmtNoHeight
2658 : pLineFmt, 0, pBox );
2659 rLines.C40_INSERT( SwTableLine, pLine, rLines.Count() );
2661 // Sicherstellen, dass wie ein Format ohne Hoehe erwischt haben
2662 if( !pLineFrmFmtNoHeight )
2664 // sonst muessen wir die Hoehe aus dem Attribut entfernen
2665 // und koennen uns das Format merken
2666 pLineFrmFmtNoHeight = (SwTableLineFmt*)pLine->ClaimFrmFmt();
2668 ResetLineFrmFmtAttrs( pLineFrmFmtNoHeight );
2671 SwTableBoxes& rBoxes = pLine->GetTabBoxes();
2672 SwTableBox *pNewBox;
2674 // ggf. links eine Zelle einfuegen
2675 if( pLayoutInfo->GetRelLeftFill() > 0 )
2677 // pPrevStNd ist der Vorgaenger-Start-Node der Tabelle. Den
2678 // "Filler"-Node fuegen wir einfach dahinter ein ...
2679 pPrevStNd = pParser->InsertTableSection( pPrevStNd );
2681 pNewBox = NewTableBox( pPrevStNd, pLine );
2682 rBoxes.C40_INSERT( SwTableBox, pNewBox, rBoxes.Count() );
2683 FixFillerFrameFmt( pNewBox, sal_False );
2684 pLayoutInfo->SetLeftFillerBox( pNewBox );
2687 // jetzt die Tabelle bearbeiten
2688 pNewBox = new SwTableBox( pBoxFmt, 0, pLine );
2689 rBoxes.C40_INSERT( SwTableBox, pNewBox, rBoxes.Count() );
2691 SwFrmFmt *pFrmFmt = pNewBox->ClaimFrmFmt();
2692 pFrmFmt->ResetFmtAttr( RES_BOX );
2693 pFrmFmt->ResetFmtAttr( RES_BACKGROUND );
2694 pFrmFmt->ResetFmtAttr( RES_VERT_ORIENT );
2695 pFrmFmt->ResetFmtAttr( RES_BOXATR_FORMAT );
2698 _MakeTable( pNewBox );
2700 // und noch ggf. rechts eine Zelle einfuegen
2701 if( pLayoutInfo->GetRelRightFill() > 0 )
2703 const SwStartNode *pStNd =
2704 GetPrevBoxStartNode( USHRT_MAX, USHRT_MAX );
2705 pStNd = pParser->InsertTableSection( pStNd );
2707 pNewBox = NewTableBox( pStNd, pLine );
2708 rBoxes.C40_INSERT( SwTableBox, pNewBox, rBoxes.Count() );
2710 FixFillerFrameFmt( pNewBox, sal_True );
2711 pLayoutInfo->SetRightFillerBox( pNewBox );
2714 else
2716 _MakeTable( pBox );
2719 // zum Schluss fuehren wir noch eine Garbage-Collection fuer die
2720 // Top-Level-Tabelle durch
2721 if( this==pTopTable )
2723 if( 1==nRows && nHeight && 1==pSwTable->GetTabLines().Count() )
2725 // Hoehe einer einzeiligen Tabelle als Mindesthoehe der
2726 // Zeile setzen. (War mal fixe Hoehe, aber das gibt manchmal
2727 // Probleme (fix #34972#) und ist auch nicht Netscape 4.0
2728 // konform
2729 nHeight = pParser->ToTwips( nHeight );
2730 if( nHeight < MINLAY )
2731 nHeight = MINLAY;
2733 (pSwTable->GetTabLines())[0]->ClaimFrmFmt();
2734 (pSwTable->GetTabLines())[0]->GetFrmFmt()
2735 ->SetFmtAttr( SwFmtFrmSize( ATT_MIN_SIZE, 0, nHeight ) );
2738 if( GetBGBrush() )
2739 pSwTable->GetFrmFmt()->SetFmtAttr( *GetBGBrush() );
2741 ((SwTable *)pSwTable)->SetRowsToRepeat( static_cast< USHORT >(nHeadlineRepeat) );
2742 ((SwTable *)pSwTable)->GCLines();
2744 sal_Bool bIsInFlyFrame = pContext && pContext->GetFrmFmt();
2745 if( bIsInFlyFrame && !nWidth )
2747 SvxAdjust eTblAdjust = GetTableAdjust(sal_False);
2748 if( eTblAdjust != SVX_ADJUST_LEFT &&
2749 eTblAdjust != SVX_ADJUST_RIGHT )
2751 // Wenn eine Tabelle ohne Breitenangabe nicht links oder
2752 // rechts umflossen werden soll, dann stacken wir sie
2753 // in einem Rahmen mit 100%-Breite, damit ihre Groesse
2754 // angepasst wird. Der Rahmen darf nicht angepasst werden.
2755 ASSERT( HasToFly(), "Warum ist die Tabelle in einem Rahmen?" );
2756 sal_uInt32 nMin = pLayoutInfo->GetMin();
2757 if( nMin > USHRT_MAX )
2758 nMin = USHRT_MAX;
2759 SwFmtFrmSize aFlyFrmSize( ATT_VAR_SIZE, (SwTwips)nMin, MINLAY );
2760 aFlyFrmSize.SetWidthPercent( 100 );
2761 pContext->GetFrmFmt()->SetFmtAttr( aFlyFrmSize );
2762 bIsInFlyFrame = sal_False;
2764 else
2766 // Links und rechts ausgerichtete Tabellen ohne Breite
2767 // duerfen leider nicht in der Breite angepasst werden, denn
2768 // sie wuerden nur schrumpfen aber nie wachsen.
2769 pLayoutInfo->SetMustNotRecalc( sal_True );
2770 if( pContext->GetFrmFmt()->GetAnchor().GetCntntAnchor()
2771 ->nNode.GetNode().FindTableNode() )
2773 sal_uInt32 nMax = pLayoutInfo->GetMax();
2774 if( nMax > USHRT_MAX )
2775 nMax = USHRT_MAX;
2776 SwFmtFrmSize aFlyFrmSize( ATT_VAR_SIZE, (SwTwips)nMax, MINLAY );
2777 pContext->GetFrmFmt()->SetFmtAttr( aFlyFrmSize );
2778 bIsInFlyFrame = sal_False;
2780 else
2782 pLayoutInfo->SetMustNotResize( sal_True );
2786 pLayoutInfo->SetMayBeInFlyFrame( bIsInFlyFrame );
2788 // Nur Tabellen mit relativer Breite oder ohne Breite muessen
2789 // angepasst werden.
2790 pLayoutInfo->SetMustResize( bPrcWidth || !nWidth );
2792 pLayoutInfo->SetWidths();
2794 ((SwTable *)pSwTable)->SetHTMLTableLayout( pLayoutInfo );
2796 if( pResizeDrawObjs )
2798 sal_uInt16 nCount = pResizeDrawObjs->Count();
2799 for( sal_uInt16 i=0; i<nCount; i++ )
2801 SdrObject *pObj = (*pResizeDrawObjs)[i];
2802 sal_uInt16 nRow = (*pDrawObjPrcWidths)[3*i];
2803 sal_uInt16 nCol = (*pDrawObjPrcWidths)[3*i+1];
2804 sal_uInt8 nPrcWidth = (sal_uInt8)(*pDrawObjPrcWidths)[3*i+2];
2806 SwHTMLTableLayoutCell *pLayoutCell =
2807 pLayoutInfo->GetCell( nRow, nCol );
2808 sal_uInt16 nColSpan = pLayoutCell->GetColSpan();
2810 sal_uInt16 nWidth2, nDummy;
2811 pLayoutInfo->GetAvail( nCol, nColSpan, nWidth2, nDummy );
2812 nWidth2 = nWidth2 - pLayoutInfo->GetLeftCellSpace( nCol, nColSpan );
2813 nWidth2 = nWidth2 - pLayoutInfo->GetRightCellSpace( nCol, nColSpan );
2814 nWidth2 = static_cast< sal_uInt16 >(((long)nWidth * nPrcWidth) / 100);
2816 pParser->ResizeDrawObject( pObj, nWidth2 );
2822 void HTMLTable::SetTable( const SwStartNode *pStNd, _HTMLTableContext *pCntxt,
2823 sal_uInt16 nLeft, sal_uInt16 nRight,
2824 const SwTable *pSwTab, sal_Bool bFrcFrame )
2826 pPrevStNd = pStNd;
2827 pSwTable = pSwTab;
2828 pContext = pCntxt;
2830 nLeftMargin = nLeft;
2831 nRightMargin = nRight;
2833 bForceFrame = bFrcFrame;
2836 void HTMLTable::RegisterDrawObject( SdrObject *pObj, sal_uInt8 nPrcWidth )
2838 if( !pResizeDrawObjs )
2839 pResizeDrawObjs = new SdrObjects;
2840 pResizeDrawObjs->C40_INSERT( SdrObject, pObj, pResizeDrawObjs->Count() );
2842 if( !pDrawObjPrcWidths )
2843 pDrawObjPrcWidths = new SvUShorts;
2844 pDrawObjPrcWidths->Insert( nCurRow, pDrawObjPrcWidths->Count() );
2845 pDrawObjPrcWidths->Insert( nCurCol, pDrawObjPrcWidths->Count() );
2846 pDrawObjPrcWidths->Insert( (sal_uInt16)nPrcWidth, pDrawObjPrcWidths->Count() );
2849 void HTMLTable::MakeParentContents()
2851 if( !GetContext() && !HasParentSection() )
2853 SetParentContents(
2854 pParser->InsertTableContents( GetIsParentHeader() ) );
2856 SetHasParentSection( sal_True );
2860 _HTMLTableContext::~_HTMLTableContext()
2862 delete pPos;
2865 void _HTMLTableContext::SavePREListingXMP( SwHTMLParser& rParser )
2867 bRestartPRE = rParser.IsReadPRE();
2868 bRestartXMP = rParser.IsReadXMP();
2869 bRestartListing = rParser.IsReadListing();
2870 rParser.FinishPREListingXMP();
2873 void _HTMLTableContext::RestorePREListingXMP( SwHTMLParser& rParser )
2875 rParser.FinishPREListingXMP();
2877 if( bRestartPRE )
2878 rParser.StartPRE();
2880 if( bRestartXMP )
2881 rParser.StartXMP();
2883 if( bRestartListing )
2884 rParser.StartListing();
2887 /* \f */
2889 const SwStartNode *SwHTMLParser::InsertTableSection
2890 ( const SwStartNode *pPrevStNd )
2892 ASSERT( pPrevStNd, "Start-Node ist NULL" );
2894 pCSS1Parser->SetTDTagStyles();
2895 SwTxtFmtColl *pColl = pCSS1Parser->GetTxtCollFromPool( RES_POOLCOLL_TABLE );
2897 const SwStartNode *pStNd;
2898 if( pTable && pTable->bFirstCell )
2900 SwNode *pNd = pDoc->GetNodes()[pPam->GetPoint()->nNode];
2901 pNd->GetTxtNode()->ChgFmtColl( pColl );
2902 pStNd = pNd->FindTableBoxStartNode();
2903 pTable->bFirstCell = sal_False;
2905 else
2907 const SwNode* pNd;
2908 if( pPrevStNd->IsTableNode() )
2909 pNd = pPrevStNd;
2910 else
2911 pNd = pPrevStNd->EndOfSectionNode();
2912 SwNodeIndex nIdx( *pNd, 1 );
2913 pStNd = pDoc->GetNodes().MakeTextSection( nIdx, SwTableBoxStartNode,
2914 pColl );
2915 pTable->IncBoxCount();
2918 SwCntntNode *pCNd = pDoc->GetNodes()[pStNd->GetIndex()+1] ->GetCntntNode();
2919 SvxFontHeightItem aFontHeight( 40, 100, RES_CHRATR_FONTSIZE );
2920 pCNd->SetAttr( aFontHeight );
2921 aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE );
2922 pCNd->SetAttr( aFontHeight );
2923 aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE );
2924 pCNd->SetAttr( aFontHeight );
2926 return pStNd;
2929 const SwStartNode *SwHTMLParser::InsertTableSection( sal_uInt16 nPoolId )
2931 switch( nPoolId )
2933 case RES_POOLCOLL_TABLE_HDLN:
2934 pCSS1Parser->SetTHTagStyles();
2935 break;
2936 case RES_POOLCOLL_TABLE:
2937 pCSS1Parser->SetTDTagStyles();
2938 break;
2941 SwTxtFmtColl *pColl = pCSS1Parser->GetTxtCollFromPool( nPoolId );
2943 SwNode *pNd = pDoc->GetNodes()[pPam->GetPoint()->nNode];
2944 const SwStartNode *pStNd;
2945 if( pTable && pTable->bFirstCell )
2947 pNd->GetTxtNode()->ChgFmtColl( pColl );
2948 pTable->bFirstCell = sal_False;
2949 pStNd = pNd->FindTableBoxStartNode();
2951 else
2953 SwTableNode *pTblNd = pNd->FindTableNode();
2954 if( pTblNd->GetTable().GetHTMLTableLayout() )
2955 { // if there is already a HTMTableLayout, this table is already finished
2956 // and we have to look for the right table in the environment
2957 SwTableNode *pOutTbl = pTblNd;
2958 do {
2959 pTblNd = pOutTbl;
2960 pOutTbl = pOutTbl->StartOfSectionNode()->FindTableNode();
2961 } while( pOutTbl && pTblNd->GetTable().GetHTMLTableLayout() );
2963 SwNodeIndex aIdx( *pTblNd->EndOfSectionNode() );
2964 pStNd = pDoc->GetNodes().MakeTextSection( aIdx, SwTableBoxStartNode,
2965 pColl );
2967 pPam->GetPoint()->nNode = pStNd->GetIndex() + 1;
2968 SwTxtNode *pTxtNd = pPam->GetPoint()->nNode.GetNode().GetTxtNode();
2969 pPam->GetPoint()->nContent.Assign( pTxtNd, 0 );
2970 pTable->IncBoxCount();
2973 return pStNd;
2976 SwStartNode *SwHTMLParser::InsertTempTableCaptionSection()
2978 SwTxtFmtColl *pColl = pCSS1Parser->GetTxtCollFromPool( RES_POOLCOLL_TEXT );
2979 SwNodeIndex& rIdx = pPam->GetPoint()->nNode;
2980 rIdx = pDoc->GetNodes().GetEndOfExtras();
2981 SwStartNode *pStNd = pDoc->GetNodes().MakeTextSection( rIdx,
2982 SwNormalStartNode, pColl );
2984 rIdx = pStNd->GetIndex() + 1;
2985 pPam->GetPoint()->nContent.Assign( rIdx.GetNode().GetTxtNode(), 0 );
2987 return pStNd;
2991 xub_StrLen SwHTMLParser::StripTrailingLF()
2993 xub_StrLen nStripped = 0;
2995 xub_StrLen nLen = pPam->GetPoint()->nContent.GetIndex();
2996 if( nLen )
2998 SwTxtNode* pTxtNd = pPam->GetPoint()->nNode.GetNode().GetTxtNode();
2999 // vorsicht, wenn Kommentare nicht uebrlesen werden!!!
3000 if( pTxtNd )
3002 xub_StrLen nPos = nLen;
3003 xub_StrLen nLFCount = 0;
3004 while( nPos && '\x0a' == (pTxtNd->GetTxt()).GetChar(--nPos) )
3005 nLFCount++;
3007 if( nLFCount )
3009 // MIB 6.6.97: Warum sollte man bei leeren Absaetzen nur ein LF loeschen?
3010 // Das stimmt doch irgendwi nicht ...
3011 // if( nLFCount == nLen )
3012 // {
3013 // // nur Lfs, dann nur ein LF loeschen
3014 // nLFCount = 1;
3015 // }
3016 // else if( nLFCount > 2 )
3017 if( nLFCount > 2 )
3019 // Bei Netscape entspricht ein Absatz-Ende zwei LFs
3020 // (mit einem kommt man in die naechste Zeile, das
3021 // zweite erzeugt eine Leerzeile) Diesen Abstand
3022 // erreichen wie aber schon mit dem unteren
3023 // Absatz-Abstand. Wenn nach den <BR> ein neuer
3024 // Absatz aufgemacht wird, wird das Maximum des Abstands,
3025 // der sich aus den BR und dem P ergibt genommen.
3026 // Deshalb muessen wir 2 bzw. alle bei weniger
3027 // als zweien loeschen
3028 nLFCount = 2;
3031 nPos = nLen - nLFCount;
3032 SwIndex nIdx( pTxtNd, nPos );
3033 pTxtNd->EraseText( nIdx, nLFCount );
3034 nStripped = nLFCount;
3039 return nStripped;
3042 SvxBrushItem* SwHTMLParser::CreateBrushItem( const Color *pColor,
3043 const String& rImageURL,
3044 const String& rStyle,
3045 const String& rId,
3046 const String& rClass )
3048 SvxBrushItem *pBrushItem = 0;
3050 if( rStyle.Len() || rId.Len() || rClass.Len() )
3052 SfxItemSet aItemSet( pDoc->GetAttrPool(), RES_BACKGROUND,
3053 RES_BACKGROUND );
3054 SvxCSS1PropertyInfo aPropInfo;
3056 if( rClass.Len() )
3058 String aClass( rClass );
3059 SwCSS1Parser::GetScriptFromClass( aClass );
3060 SvxCSS1MapEntry *pClass = pCSS1Parser->GetClass( aClass );
3061 if( pClass )
3062 aItemSet.Put( pClass->GetItemSet() );
3065 if( rId.Len() )
3067 SvxCSS1MapEntry *pId = pCSS1Parser->GetId( rId );
3068 if( pId )
3069 aItemSet.Put( pId->GetItemSet() );
3072 pCSS1Parser->ParseStyleOption( rStyle, aItemSet, aPropInfo );
3073 const SfxPoolItem *pItem = 0;
3074 if( SFX_ITEM_SET == aItemSet.GetItemState( RES_BACKGROUND, sal_False,
3075 &pItem ) )
3077 pBrushItem = new SvxBrushItem( *((const SvxBrushItem *)pItem) );
3081 if( !pBrushItem && (pColor || rImageURL.Len()) )
3083 pBrushItem = new SvxBrushItem(RES_BACKGROUND);
3085 if( pColor )
3086 pBrushItem->SetColor(*pColor);
3088 if( rImageURL.Len() )
3090 pBrushItem->SetGraphicLink( URIHelper::SmartRel2Abs( INetURLObject(sBaseURL), rImageURL, Link(), false) );
3091 pBrushItem->SetGraphicPos( GPOS_TILED );
3095 return pBrushItem;
3098 /* \f */
3100 class _SectionSaveStruct : public SwPendingStackData
3102 sal_uInt16 nBaseFontStMinSave, nFontStMinSave, nFontStHeadStartSave;
3103 sal_uInt16 nDefListDeepSave, nContextStMinSave, nContextStAttrMinSave;
3105 public:
3107 HTMLTable *pTable;
3109 _SectionSaveStruct( SwHTMLParser& rParser );
3110 virtual ~_SectionSaveStruct();
3112 sal_uInt16 GetContextStAttrMin() const { return nContextStAttrMinSave; }
3114 void Restore( SwHTMLParser& rParser );
3117 _SectionSaveStruct::_SectionSaveStruct( SwHTMLParser& rParser ) :
3118 nBaseFontStMinSave(0), nFontStMinSave(0), nFontStHeadStartSave(0),
3119 nDefListDeepSave(0), nContextStMinSave(0), nContextStAttrMinSave(0),
3120 pTable( 0 )
3122 // Font-Stacks einfrieren
3123 nBaseFontStMinSave = rParser.nBaseFontStMin;
3124 rParser.nBaseFontStMin = rParser.aBaseFontStack.Count();
3126 nFontStMinSave = rParser.nFontStMin;
3127 nFontStHeadStartSave = rParser.nFontStHeadStart;
3128 rParser.nFontStMin = rParser.aFontStack.Count();
3130 // Kontext-Stack einfrieren
3131 nContextStMinSave = rParser.nContextStMin;
3132 nContextStAttrMinSave = rParser.nContextStAttrMin;
3133 rParser.nContextStMin = rParser.aContexts.Count();
3134 rParser.nContextStAttrMin = rParser.nContextStMin;
3136 // und noch ein par Zaehler retten
3137 nDefListDeepSave = rParser.nDefListDeep;
3138 rParser.nDefListDeep = 0;
3141 _SectionSaveStruct::~_SectionSaveStruct()
3144 void _SectionSaveStruct::Restore( SwHTMLParser& rParser )
3146 // Font-Stacks wieder auftauen
3147 sal_uInt16 nMin = rParser.nBaseFontStMin;
3148 if( rParser.aBaseFontStack.Count() > nMin )
3149 rParser.aBaseFontStack.Remove( nMin,
3150 rParser.aBaseFontStack.Count() - nMin );
3151 rParser.nBaseFontStMin = nBaseFontStMinSave;
3154 nMin = rParser.nFontStMin;
3155 if( rParser.aFontStack.Count() > nMin )
3156 rParser.aFontStack.Remove( nMin,
3157 rParser.aFontStack.Count() - nMin );
3158 rParser.nFontStMin = nFontStMinSave;
3159 rParser.nFontStHeadStart = nFontStHeadStartSave;
3161 // Der Kontext-Stack muss schon aufgeraeumt sein!
3162 ASSERT( rParser.aContexts.Count() == rParser.nContextStMin &&
3163 rParser.aContexts.Count() == rParser.nContextStAttrMin,
3164 "Der Kontext-Stack wurde nicht aufgeraeumt" );
3165 rParser.nContextStMin = nContextStMinSave;
3166 rParser.nContextStAttrMin = nContextStAttrMinSave;
3168 // und noch ein par Zaehler rekonstruieren
3169 rParser.nDefListDeep = nDefListDeepSave;
3171 // und ein par Flags zuruecksetzen
3172 rParser.bNoParSpace = sal_False;
3173 rParser.nOpenParaToken = 0;
3175 if( rParser.aParaAttrs.Count() )
3176 rParser.aParaAttrs.Remove( 0, rParser.aParaAttrs.Count() );
3179 /* \f */
3181 class _CellSaveStruct : public _SectionSaveStruct
3183 String aStyle, aId, aClass, aLang, aDir;
3184 String aBGImage;
3185 Color aBGColor;
3187 HTMLTableCnts* pCnts; // Liste aller Inhalte
3188 HTMLTableCnts* pCurrCnts; // der aktuelle Inhalt oder 0
3189 SwNodeIndex *pNoBreakEndParaIdx;// Absatz-Index eines </NOBR>
3191 double nValue;
3193 sal_uInt32 nNumFmt;
3195 sal_uInt16 nRowSpan, nColSpan, nWidth, nHeight;
3196 xub_StrLen nNoBreakEndCntntPos; // Zeichen-Index eines </NOBR>
3198 SvxAdjust eAdjust;
3199 sal_Int16 eVertOri;
3201 sal_Bool bHead : 1;
3202 sal_Bool bPrcWidth : 1;
3203 sal_Bool bHasNumFmt : 1;
3204 sal_Bool bHasValue : 1;
3205 sal_Bool bBGColor : 1;
3206 sal_Bool bNoWrap : 1; // NOWRAP-Option
3207 sal_Bool bNoBreak : 1; // NOBREAK-Tag
3209 public:
3211 _CellSaveStruct( SwHTMLParser& rParser, HTMLTable *pCurTable, sal_Bool bHd,
3212 sal_Bool bReadOpt );
3214 virtual ~_CellSaveStruct();
3216 void AddContents( HTMLTableCnts *pNewCnts );
3217 HTMLTableCnts *GetFirstContents() { return pCnts; }
3219 void ClearIsInSection() { pCurrCnts = 0; }
3220 sal_Bool IsInSection() const { return pCurrCnts!=0; }
3221 HTMLTableCnts *GetCurrContents() const { return pCurrCnts; }
3223 void InsertCell( SwHTMLParser& rParser, HTMLTable *pCurTable );
3225 sal_Bool IsHeaderCell() const { return bHead; }
3227 void StartNoBreak( const SwPosition& rPos );
3228 void EndNoBreak( const SwPosition& rPos );
3229 void CheckNoBreak( const SwPosition& rPos, SwDoc *pDoc );
3233 _CellSaveStruct::_CellSaveStruct( SwHTMLParser& rParser, HTMLTable *pCurTable,
3234 sal_Bool bHd, sal_Bool bReadOpt ) :
3235 _SectionSaveStruct( rParser ),
3236 pCnts( 0 ),
3237 pCurrCnts( 0 ),
3238 pNoBreakEndParaIdx( 0 ),
3239 nValue( 0.0 ),
3240 nNumFmt( 0 ),
3241 nRowSpan( 1 ),
3242 nColSpan( 1 ),
3243 nWidth( 0 ),
3244 nHeight( 0 ),
3245 nNoBreakEndCntntPos( 0 ),
3246 eAdjust( pCurTable->GetInheritedAdjust() ),
3247 eVertOri( pCurTable->GetInheritedVertOri() ),
3248 bHead( bHd ),
3249 bPrcWidth( sal_False ),
3250 bHasNumFmt( sal_False ),
3251 bHasValue( sal_False ),
3252 bBGColor( sal_False ),
3253 bNoWrap( sal_False ),
3254 bNoBreak( sal_False )
3256 String aNumFmt, aValue;
3258 if( bReadOpt )
3260 const HTMLOptions *pOptions = rParser.GetOptions();
3261 for( sal_uInt16 i = pOptions->Count(); i; )
3263 const HTMLOption *pOption = (*pOptions)[--i];
3264 switch( pOption->GetToken() )
3266 case HTML_O_ID:
3267 aId = pOption->GetString();
3268 break;
3269 case HTML_O_COLSPAN:
3270 nColSpan = (sal_uInt16)pOption->GetNumber();
3271 break;
3272 case HTML_O_ROWSPAN:
3273 nRowSpan = (sal_uInt16)pOption->GetNumber();
3274 break;
3275 case HTML_O_ALIGN:
3276 eAdjust = (SvxAdjust)pOption->GetEnum(
3277 aHTMLPAlignTable, static_cast< sal_uInt16 >(eAdjust) );
3278 break;
3279 case HTML_O_VALIGN:
3280 eVertOri = pOption->GetEnum(
3281 aHTMLTblVAlignTable, eVertOri );
3282 break;
3283 case HTML_O_WIDTH:
3284 nWidth = (sal_uInt16)pOption->GetNumber(); // nur fuer Netscape
3285 bPrcWidth = (pOption->GetString().Search('%') != STRING_NOTFOUND);
3286 if( bPrcWidth && nWidth>100 )
3287 nWidth = 100;
3288 break;
3289 case HTML_O_HEIGHT:
3290 nHeight = (sal_uInt16)pOption->GetNumber(); // nur fuer Netscape
3291 if( pOption->GetString().Search('%') != STRING_NOTFOUND)
3292 nHeight = 0; // keine %-Angaben beruecksichtigen
3293 break;
3294 case HTML_O_BGCOLOR:
3295 // Leere BGCOLOR bei <TABLE>, <TR> und <TD>/<TH> wie Netscape
3296 // ignorieren, bei allen anderen Tags *wirklich* nicht.
3297 if( pOption->GetString().Len() )
3299 pOption->GetColor( aBGColor );
3300 bBGColor = sal_True;
3302 break;
3303 case HTML_O_BACKGROUND:
3304 aBGImage = pOption->GetString();
3305 break;
3306 case HTML_O_STYLE:
3307 aStyle = pOption->GetString();
3308 break;
3309 case HTML_O_CLASS:
3310 aClass = pOption->GetString();
3311 break;
3312 case HTML_O_LANG:
3313 aLang = pOption->GetString();
3314 break;
3315 case HTML_O_DIR:
3316 aDir = pOption->GetString();
3317 break;
3318 case HTML_O_SDNUM:
3319 aNumFmt = pOption->GetString();
3320 bHasNumFmt = sal_True;
3321 break;
3322 case HTML_O_SDVAL:
3323 bHasValue = sal_True;
3324 aValue = pOption->GetString();
3325 break;
3326 case HTML_O_NOWRAP:
3327 bNoWrap = sal_True;
3328 break;
3332 if( aId.Len() )
3333 rParser.InsertBookmark( aId );
3336 if( bHasNumFmt )
3338 LanguageType eLang;
3339 nValue = rParser.GetTableDataOptionsValNum(
3340 nNumFmt, eLang, aValue, aNumFmt,
3341 *rParser.pDoc->GetNumberFormatter() );
3344 // einen neuen Kontext anlegen, aber das drawing::Alignment-Attribut
3345 // nicht dort verankern, weil es noch ger keine Section gibt, in der
3346 // es gibt.
3347 sal_uInt16 nToken, nColl;
3348 if( bHead )
3350 nToken = HTML_TABLEHEADER_ON;
3351 nColl = RES_POOLCOLL_TABLE_HDLN;
3353 else
3355 nToken = HTML_TABLEDATA_ON;
3356 nColl = RES_POOLCOLL_TABLE;
3358 _HTMLAttrContext *pCntxt = new _HTMLAttrContext( nToken, nColl, aEmptyStr, sal_True );
3359 if( SVX_ADJUST_END != eAdjust )
3360 rParser.InsertAttr( &rParser.aAttrTab.pAdjust, SvxAdjustItem(eAdjust, RES_PARATR_ADJUST),
3361 pCntxt );
3363 if( rParser.HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) )
3365 SfxItemSet aItemSet( rParser.pDoc->GetAttrPool(),
3366 rParser.pCSS1Parser->GetWhichMap() );
3367 SvxCSS1PropertyInfo aPropInfo;
3369 if( rParser.ParseStyleOptions( aStyle, aId, aClass, aItemSet,
3370 aPropInfo, &aLang, &aDir ) )
3371 rParser.InsertAttrs( aItemSet, aPropInfo, pCntxt );
3374 rParser.SplitPREListingXMP( pCntxt );
3376 rParser.PushContext( pCntxt );
3379 _CellSaveStruct::~_CellSaveStruct()
3381 delete pNoBreakEndParaIdx;
3384 void _CellSaveStruct::AddContents( HTMLTableCnts *pNewCnts )
3386 if( pCnts )
3387 pCnts->Add( pNewCnts );
3388 else
3389 pCnts = pNewCnts;
3391 pCurrCnts = pNewCnts;
3394 void _CellSaveStruct::InsertCell( SwHTMLParser& rParser,
3395 HTMLTable *pCurTable )
3397 #ifndef PRODUCT
3398 // Die Attribute muessen schon beim Auefrauemen des Kontext-Stacks
3399 // entfernt worden sein, sonst ist etwas schiefgelaufen. Das
3400 // Checken wir mal eben ...
3401 // MIB 8.1.98: Wenn ausserhalb einer Zelle Attribute geoeffnet
3402 // wurden stehen diese noch in der Attribut-Tabelle und werden erst
3403 // ganz zum Schluss durch die CleanContext-Aufrufe in BuildTable
3404 // geloescht. Damit es in diesem Fall keine Asserts gibt findet dann
3405 // keine Ueberpruefung statt. Erkennen tut man diesen Fall an
3406 // nContextStAttrMin: Der gemerkte Wert nContextStAttrMinSave ist der
3407 // Wert, den nContextStAttrMin beim Start der Tabelle hatte. Und
3408 // der aktuelle Wert von nContextStAttrMin entspricht der Anzahl der
3409 // Kontexte, die beim Start der Zelle vorgefunden wurden. Sind beide
3410 // Werte unterschiedlich, wurden ausserhalb der Zelle Kontexte
3411 // angelegt und wir ueberpruefen nichts.
3413 if( rParser.nContextStAttrMin == GetContextStAttrMin() )
3415 _HTMLAttr** pTbl = (_HTMLAttr**)&rParser.aAttrTab;
3417 for( sal_uInt16 nCnt = sizeof( _HTMLAttrTable ) / sizeof( _HTMLAttr* );
3418 nCnt--; ++pTbl )
3420 ASSERT( !*pTbl, "Die Attribut-Tabelle ist nicht leer" );
3423 #endif
3425 // jetzt muessen wir noch die Zelle an der aktuellen Position einfuegen
3426 SvxBrushItem *pBrushItem =
3427 rParser.CreateBrushItem( bBGColor ? &aBGColor : 0, aBGImage,
3428 aStyle, aId, aClass );
3429 pCurTable->InsertCell( pCnts, nRowSpan, nColSpan, nWidth,
3430 bPrcWidth, nHeight, eVertOri, pBrushItem,
3431 bHasNumFmt, nNumFmt, bHasValue, nValue,
3432 bNoWrap );
3433 Restore( rParser );
3436 void _CellSaveStruct::StartNoBreak( const SwPosition& rPos )
3438 if( !pCnts ||
3439 (!rPos.nContent.GetIndex() && pCurrCnts==pCnts &&
3440 pCnts->GetStartNode() &&
3441 pCnts->GetStartNode()->GetIndex() + 1 ==
3442 rPos.nNode.GetIndex()) )
3444 bNoBreak = sal_True;
3448 void _CellSaveStruct::EndNoBreak( const SwPosition& rPos )
3450 if( bNoBreak )
3452 delete pNoBreakEndParaIdx;
3453 pNoBreakEndParaIdx = new SwNodeIndex( rPos.nNode );
3454 nNoBreakEndCntntPos = rPos.nContent.GetIndex();
3455 bNoBreak = sal_False;
3459 void _CellSaveStruct::CheckNoBreak( const SwPosition& rPos, SwDoc *pDoc )
3461 if( pCnts && pCurrCnts==pCnts )
3463 if( bNoBreak )
3465 // <NOBR> wurde nicht beendet
3466 pCnts->SetNoBreak();
3468 else if( pNoBreakEndParaIdx &&
3469 pNoBreakEndParaIdx->GetIndex() == rPos.nNode.GetIndex() )
3471 if( nNoBreakEndCntntPos == rPos.nContent.GetIndex() )
3473 // <NOBR> wurde unmittelbar vor dem Zellen-Ende beendet
3474 pCnts->SetNoBreak();
3476 else if( nNoBreakEndCntntPos + 1 == rPos.nContent.GetIndex() )
3478 const SwTxtNode *pTxtNd =
3479 pDoc->GetNodes()[rPos.nNode]->GetTxtNode();
3480 if( pTxtNd )
3482 sal_Unicode cLast =
3483 pTxtNd->GetTxt().GetChar(nNoBreakEndCntntPos);
3484 if( ' '==cLast || '\x0a'==cLast )
3486 // Zwischem dem </NOBR> und dem Zellen-Ende gibt es nur
3487 // ein Blank oder einen Zeilenumbruch.
3488 pCnts->SetNoBreak();
3498 HTMLTableCnts *SwHTMLParser::InsertTableContents(
3499 sal_Bool bHead )
3501 // eine neue Section anlegen, der PaM steht dann darin
3502 const SwStartNode *pStNd =
3503 InsertTableSection( static_cast< USHORT >(bHead ? RES_POOLCOLL_TABLE_HDLN
3504 : RES_POOLCOLL_TABLE) );
3506 if( GetNumInfo().GetNumRule() )
3508 // 1. Absatz auf nicht numeriert setzen
3509 BYTE nLvl = GetNumInfo().GetLevel();
3510 // --> OD 2008-04-02 #refactorlists#
3511 // SetNoNum(&nLvl, TRUE);
3512 // SetNodeNum( nLvl);
3513 SetNodeNum( nLvl, false );
3516 // Attributierungs-Anfang neu setzen
3517 const SwNodeIndex& rSttPara = pPam->GetPoint()->nNode;
3518 xub_StrLen nSttCnt = pPam->GetPoint()->nContent.GetIndex();
3520 _HTMLAttr** pTbl = (_HTMLAttr**)&aAttrTab;
3521 for( sal_uInt16 nCnt = sizeof( _HTMLAttrTable ) / sizeof( _HTMLAttr* );
3522 nCnt--; ++pTbl )
3525 _HTMLAttr *pAttr = *pTbl;
3526 while( pAttr )
3528 ASSERT( !pAttr->GetPrev(), "Attribut hat Previous-Liste" );
3529 pAttr->nSttPara = rSttPara;
3530 pAttr->nEndPara = rSttPara;
3531 pAttr->nSttCntnt = nSttCnt;
3532 pAttr->nEndCntnt = nSttCnt;
3534 pAttr = pAttr->GetNext();
3538 return new HTMLTableCnts( pStNd );
3541 sal_uInt16 SwHTMLParser::IncGrfsThatResizeTable()
3543 return pTable ? pTable->IncGrfsThatResize() : 0;
3546 void SwHTMLParser::RegisterDrawObjectToTable( HTMLTable *pCurTable,
3547 SdrObject *pObj, sal_uInt8 nPrcWidth )
3549 pCurTable->RegisterDrawObject( pObj, nPrcWidth );
3552 void SwHTMLParser::BuildTableCell( HTMLTable *pCurTable, sal_Bool bReadOptions,
3553 sal_Bool bHead )
3555 if( !IsParserWorking() && !pPendStack )
3556 return;
3558 _CellSaveStruct* pSaveStruct;
3560 int nToken = 0;
3561 sal_Bool bPending = sal_False;
3562 if( pPendStack )
3564 pSaveStruct = (_CellSaveStruct*)pPendStack->pData;
3566 SwPendingStack* pTmp = pPendStack->pNext;
3567 delete pPendStack;
3568 pPendStack = pTmp;
3569 nToken = pPendStack ? pPendStack->nToken : GetSaveToken();
3570 bPending = SVPAR_ERROR == eState && pPendStack != 0;
3572 SaveState( nToken );
3574 else
3576 // <TH> bzw. <TD> wurde bereits gelesen
3577 if( pTable->IsOverflowing() )
3579 SaveState( 0 );
3580 return;
3583 if( !pCurTable->GetContext() )
3585 sal_Bool bTopTable = pTable==pCurTable;
3587 // die Tabelle besitzt noch keinen Inhalt, d.h. die eigentliche
3588 // Tabelle muss erst noch angelegt werden
3590 static sal_uInt16 aWhichIds[] =
3592 RES_PARATR_SPLIT, RES_PARATR_SPLIT,
3593 RES_PAGEDESC, RES_PAGEDESC,
3594 RES_BREAK, RES_BREAK,
3595 RES_BACKGROUND, RES_BACKGROUND,
3596 RES_KEEP, RES_KEEP,
3597 RES_LAYOUT_SPLIT, RES_LAYOUT_SPLIT,
3598 RES_FRAMEDIR, RES_FRAMEDIR,
3602 SfxItemSet aItemSet( pDoc->GetAttrPool(), aWhichIds );
3603 SvxCSS1PropertyInfo aPropInfo;
3605 sal_Bool bStyleParsed = ParseStyleOptions( pCurTable->GetStyle(),
3606 pCurTable->GetId(),
3607 pCurTable->GetClass(),
3608 aItemSet, aPropInfo,
3609 0, &pCurTable->GetDirection() );
3610 const SfxPoolItem *pItem = 0;
3611 if( bStyleParsed )
3613 if( SFX_ITEM_SET == aItemSet.GetItemState(
3614 RES_BACKGROUND, sal_False, &pItem ) )
3616 pCurTable->SetBGBrush( *(const SvxBrushItem *)pItem );
3617 aItemSet.ClearItem( RES_BACKGROUND );
3619 if( SFX_ITEM_SET == aItemSet.GetItemState(
3620 RES_PARATR_SPLIT, sal_False, &pItem ) )
3622 aItemSet.Put(
3623 SwFmtLayoutSplit( ((const SvxFmtSplitItem *)pItem)
3624 ->GetValue() ) );
3625 aItemSet.ClearItem( RES_PARATR_SPLIT );
3629 // Den linken/rechten Absatzeinzug ermitteln
3630 sal_uInt16 nLeftSpace = 0;
3631 sal_uInt16 nRightSpace = 0;
3632 short nIndent;
3633 GetMarginsFromContextWithNumBul( nLeftSpace, nRightSpace, nIndent );
3635 // die aktuelle Position an die wir irgendwann zurueckkehren
3636 SwPosition *pSavePos = 0;
3637 sal_Bool bForceFrame = sal_False;
3638 sal_Bool bAppended = sal_False;
3639 sal_Bool bParentLFStripped = sal_False;
3640 if( bTopTable )
3642 SvxAdjust eTblAdjust = pTable->GetTableAdjust(sal_False);
3644 // Wenn die Tabelle links oder rechts ausgerivchtet ist,
3645 // oder in einen Rahmen soll, dann kommt sie auch in einen
3646 // solchen.
3647 bForceFrame = eTblAdjust == SVX_ADJUST_LEFT ||
3648 eTblAdjust == SVX_ADJUST_RIGHT ||
3649 pCurTable->HasToFly();
3651 // Entweder kommt die Tabelle in keinen Rahmen und befindet
3652 // sich in keinem Rahmen (wird also durch Zellen simuliert),
3653 // oder es gibt bereits Inhalt an der entsprechenden Stelle.
3654 ASSERT( !bForceFrame || pCurTable->HasParentSection(),
3655 "Tabelle im Rahmen hat keine Umgebung!" );
3656 // SCHOEN WAER'S, aber wie bekommen den Inhalt nicht zurueck
3657 // in die umgebende Zelle
3658 // if( bForceFrame && !pCurTable->HasParentSection() )
3659 // {
3660 // pCurTable->SetParentContents(
3661 // InsertTableContents( sal_False, SVX_ADJUST_END ) );
3662 // pCurTable->SetHasParentSection( sal_True );
3663 // }
3665 sal_Bool bAppend = sal_False;
3666 if( bForceFrame )
3668 // Wenn die Tabelle in einen Rahmen kommt, muss
3669 // nur ein neuer Absatz aufgemacht werden, wenn
3670 // der Absatz Rahmen ohne Umlauf enthaelt.
3671 bAppend = HasCurrentParaFlys(sal_True);
3673 else
3675 // Sonst muss ein neuer Absatz aufgemacht werden,
3676 // wenn der Absatz nicht leer ist, oder Rahmen
3677 // oder text::Bookmarks enthaelt.
3678 bAppend =
3679 pPam->GetPoint()->nContent.GetIndex() ||
3680 HasCurrentParaFlys() ||
3681 HasCurrentParaBookmarks();
3683 if( bAppend )
3685 if( !pPam->GetPoint()->nContent.GetIndex() )
3687 pDoc->SetTxtFmtColl( *pPam,
3688 pCSS1Parser->GetTxtCollFromPool(RES_POOLCOLL_STANDARD) );
3689 SvxFontHeightItem aFontHeight( 40, 100, RES_CHRATR_FONTSIZE );
3691 _HTMLAttr* pTmp =
3692 new _HTMLAttr( *pPam->GetPoint(), aFontHeight );
3693 aSetAttrTab.Insert( pTmp, aSetAttrTab.Count() );
3695 aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE );
3696 pTmp = new _HTMLAttr( *pPam->GetPoint(), aFontHeight );
3697 aSetAttrTab.Insert( pTmp, aSetAttrTab.Count() );
3699 aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE );
3700 pTmp = new _HTMLAttr( *pPam->GetPoint(), aFontHeight );
3701 aSetAttrTab.Insert( pTmp, aSetAttrTab.Count() );
3703 pTmp = new _HTMLAttr( *pPam->GetPoint(),
3704 SvxULSpaceItem( 0, 0, RES_UL_SPACE ) );
3705 aSetAttrTab.Insert( pTmp, 0 ); // ja, 0, weil schon
3706 // vom Tabellenende vorher
3707 // was gesetzt sein kann.
3709 AppendTxtNode( AM_NOSPACE );
3710 bAppended = sal_True;
3712 else if( aParaAttrs.Count() )
3714 if( !bForceFrame )
3716 // Der Absatz wird gleich hinter die Tabelle
3717 // verschoben. Deshalb entfernen wir alle harten
3718 // Attribute des Absatzes
3720 for( sal_uInt16 i=0; i<aParaAttrs.Count(); i++ )
3721 aParaAttrs[i]->Invalidate();
3724 aParaAttrs.Remove( 0, aParaAttrs.Count() );
3727 pSavePos = new SwPosition( *pPam->GetPoint() );
3729 else if( pCurTable->HasParentSection() )
3731 bParentLFStripped = StripTrailingLF() > 0;
3733 // Absaetze bzw. ueberschriften beeenden
3734 nOpenParaToken = 0;
3735 nFontStHeadStart = nFontStMin;
3737 // die harten Attribute an diesem Absatz werden nie mehr ungueltig
3738 if( aParaAttrs.Count() )
3739 aParaAttrs.Remove( 0, aParaAttrs.Count() );
3742 // einen Tabellen Kontext anlegen
3743 _HTMLTableContext *pTCntxt =
3744 new _HTMLTableContext( pSavePos, nContextStMin,
3745 nContextStAttrMin );
3747 // alle noch offenen Attribute beenden und hinter der Tabelle
3748 // neu aufspannen
3749 _HTMLAttrs *pPostIts = 0;
3750 if( !bForceFrame && (bTopTable || pCurTable->HasParentSection()) )
3752 SplitAttrTab( pTCntxt->aAttrTab, bTopTable );
3753 // Wenn wir einen schon vorhandenen Absatz verwenden, duerfen
3754 // in den keine PostIts eingefuegt werden, weil der Absatz
3755 // ja hinter die Tabelle wandert. Sie werden deshalb in den
3756 // ersten Absatz der Tabelle verschoben.
3757 // Bei Tabellen in Tabellen duerfen ebenfalls keine PostIts
3758 // in einen noch leeren Absatz eingefuegt werden, weil
3759 // der sonat nicht geloescht wird.
3760 if( (bTopTable && !bAppended) ||
3761 (!bTopTable && !bParentLFStripped &&
3762 !pPam->GetPoint()->nContent.GetIndex()) )
3763 pPostIts = new _HTMLAttrs;
3764 SetAttr( bTopTable, bTopTable, pPostIts );
3766 else
3768 SaveAttrTab( pTCntxt->aAttrTab );
3769 if( bTopTable && !bAppended )
3771 pPostIts = new _HTMLAttrs;
3772 SetAttr( sal_True, sal_True, pPostIts );
3775 bNoParSpace = sal_False;
3777 // Aktuelle Numerierung retten und auschalten.
3778 pTCntxt->SetNumInfo( GetNumInfo() );
3779 GetNumInfo().Clear();
3780 pTCntxt->SavePREListingXMP( *this );
3782 if( bTopTable )
3784 if( bForceFrame )
3786 // Die Tabelle soll in einen Rahmen geschaufelt werden.
3788 SfxItemSet aFrmSet( pDoc->GetAttrPool(),
3789 RES_FRMATR_BEGIN, RES_FRMATR_END-1 );
3790 if( !pCurTable->IsNewDoc() )
3791 Reader::ResetFrmFmtAttrs( aFrmSet );
3793 SwSurround eSurround = SURROUND_NONE;
3794 sal_Int16 eHori;
3796 switch( pCurTable->GetTableAdjust(sal_True) )
3798 case SVX_ADJUST_RIGHT:
3799 eHori = text::HoriOrientation::RIGHT;
3800 eSurround = SURROUND_LEFT;
3801 break;
3802 case SVX_ADJUST_CENTER:
3803 eHori = text::HoriOrientation::CENTER;
3804 break;
3805 case SVX_ADJUST_LEFT:
3806 eSurround = SURROUND_RIGHT;
3807 default:
3808 eHori = text::HoriOrientation::LEFT;
3809 break;
3811 SetAnchorAndAdjustment( text::VertOrientation::NONE, eHori, aFrmSet,
3812 sal_True );
3813 aFrmSet.Put( SwFmtSurround(eSurround) );
3815 SwFmtFrmSize aFrmSize( ATT_VAR_SIZE, 20*MM50, MINLAY );
3816 aFrmSize.SetWidthPercent( 100 );
3817 aFrmSet.Put( aFrmSize );
3819 sal_uInt16 nSpace = pCurTable->GetHSpace();
3820 if( nSpace )
3821 aFrmSet.Put( SvxLRSpaceItem(nSpace,nSpace, 0, 0, RES_LR_SPACE) );
3822 nSpace = pCurTable->GetVSpace();
3823 if( nSpace )
3824 aFrmSet.Put( SvxULSpaceItem(nSpace,nSpace, RES_UL_SPACE) );
3826 RndStdIds eAnchorId = ((const SwFmtAnchor&)aFrmSet.
3827 Get( RES_ANCHOR )).
3828 GetAnchorId();
3829 SwFrmFmt *pFrmFmt = pDoc->MakeFlySection(
3830 eAnchorId, pPam->GetPoint(), &aFrmSet );
3832 pTCntxt->SetFrmFmt( pFrmFmt );
3833 const SwFmtCntnt& rFlyCntnt = pFrmFmt->GetCntnt();
3834 pPam->GetPoint()->nNode = *rFlyCntnt.GetCntntIdx();
3835 SwCntntNode *pCNd =
3836 pDoc->GetNodes().GoNext( &(pPam->GetPoint()->nNode) );
3837 pPam->GetPoint()->nContent.Assign( pCNd, 0 );
3839 // automatisch verankerte Rahmen muessen noch um
3840 // eine Position nach vorne verschoben werden.
3841 //if( FLY_AUTO_CNTNT==eAnchorId )
3842 // aMoveFlyFrms.C40_INSERT( SwFrmFmt, pFrmFmt,
3843 // aMoveFlyFrms.Count() );
3846 // eine SwTable mit einer Box anlegen und den PaM in den
3847 // Inhalt der Box-Section bewegen (der Ausrichtungs-Parameter
3848 // ist erstmal nur ein Dummy und wird spaeter noch richtig
3849 // gesetzt)
3850 ASSERT( !pPam->GetPoint()->nContent.GetIndex(),
3851 "Der Absatz hinter der Tabelle ist nicht leer!" );
3852 const SwTable* pSwTable = pDoc->InsertTable(
3853 SwInsertTableOptions( tabopts::HEADLINE_NO_BORDER, 1 ),
3854 *pPam->GetPoint(), 1, 1, text::HoriOrientation::LEFT );
3856 if( bForceFrame )
3858 SwNodeIndex aDstIdx( pPam->GetPoint()->nNode );
3859 pPam->Move( fnMoveBackward );
3860 pDoc->GetNodes().Delete( aDstIdx );
3862 else
3864 if( bStyleParsed )
3866 pCSS1Parser->SetFmtBreak( aItemSet, aPropInfo );
3867 pSwTable->GetFrmFmt()->SetFmtAttr( aItemSet );
3869 pPam->Move( fnMoveBackward );
3872 const SwNode *pNd = pDoc->GetNodes()[pPam->GetPoint()->nNode];
3873 if( !bAppended && !bForceFrame )
3875 SwTxtNode* pOldTxtNd =
3876 pDoc->GetNodes()[pSavePos->nNode]->GetTxtNode();
3877 ASSERT( pOldTxtNd, "Wieso stehen wir in keinem Txt-Node?" );
3878 SwFrmFmt *pFrmFmt = pSwTable->GetFrmFmt();
3880 const SfxPoolItem* pItem2;
3881 if( SFX_ITEM_SET == pOldTxtNd->GetSwAttrSet()
3882 .GetItemState( RES_PAGEDESC, sal_False, &pItem2 ) &&
3883 ((SwFmtPageDesc *)pItem2)->GetPageDesc() )
3885 pFrmFmt->SetFmtAttr( *pItem2 );
3886 pOldTxtNd->ResetAttr( RES_PAGEDESC );
3888 if( SFX_ITEM_SET == pOldTxtNd->GetSwAttrSet()
3889 .GetItemState( RES_BREAK, sal_True, &pItem2 ) )
3891 switch( ((SvxFmtBreakItem *)pItem2)->GetBreak() )
3893 case SVX_BREAK_PAGE_BEFORE:
3894 case SVX_BREAK_PAGE_AFTER:
3895 case SVX_BREAK_PAGE_BOTH:
3896 pFrmFmt->SetFmtAttr( *pItem2 );
3897 pOldTxtNd->ResetAttr( RES_BREAK );
3898 default:
3904 if( !bAppended && pPostIts )
3906 // noch vorhandene PostIts in den ersten Absatz
3907 // der Tabelle setzen
3908 InsertAttrs( *pPostIts );
3909 delete pPostIts;
3910 pPostIts = 0;
3913 pTCntxt->SetTableNode( (SwTableNode *)pNd->FindTableNode() );
3915 pCurTable->SetTable( pTCntxt->GetTableNode(), pTCntxt,
3916 nLeftSpace, nRightSpace,
3917 pSwTable, bForceFrame );
3919 ASSERT( !pPostIts, "ubenutzte PostIts" );
3921 else
3923 // noch offene Bereiche muessen noch entfernt werden
3924 if( EndSections( bParentLFStripped ) )
3925 bParentLFStripped = sal_False;
3927 if( pCurTable->HasParentSection() )
3929 // dannach entfernen wir ein ggf. zu viel vorhandenen
3930 // leeren Absatz, aber nur, wenn er schon vor dem
3931 // entfernen von LFs leer war
3932 if( !bParentLFStripped )
3933 StripTrailingPara();
3935 if( pPostIts )
3937 // noch vorhandene PostIts an das Ende des jetzt
3938 // aktuellen Absatzes schieben
3939 InsertAttrs( *pPostIts );
3940 delete pPostIts;
3941 pPostIts = 0;
3945 const SwNode *pNd = pDoc->GetNodes()[pPam->GetPoint()->nNode];
3946 const SwStartNode *pStNd = (pTable->bFirstCell ? pNd->FindTableNode()
3947 : pNd->FindTableBoxStartNode() );
3949 pCurTable->SetTable( pStNd, pTCntxt, nLeftSpace, nRightSpace );
3952 // Den Kontext-Stack einfrieren, denn es koennen auch mal
3953 // irgendwo ausserhalb von Zellen Attribute gesetzt werden.
3954 // Darf nicht frueher passieren, weil eventuell noch im
3955 // Stack gesucht wird!!!
3956 nContextStMin = aContexts.Count();
3957 nContextStAttrMin = nContextStMin;
3960 pSaveStruct = new _CellSaveStruct( *this, pCurTable, bHead,
3961 bReadOptions );
3963 // ist beim ersten GetNextToken schon pending, muss bei
3964 // wiederaufsetzen auf jedenfall neu gelesen werden!
3965 SaveState( 0 );
3968 if( !nToken )
3969 nToken = GetNextToken(); // Token nach <TABLE>
3971 sal_Bool bDone = sal_False;
3972 while( (IsParserWorking() && !bDone) || bPending )
3974 SaveState( nToken );
3976 nToken = FilterToken( nToken );
3978 ASSERT( pPendStack || !bCallNextToken || pSaveStruct->IsInSection(),
3979 "Wo ist die Section gebieben?" );
3980 if( !pPendStack && bCallNextToken && pSaveStruct->IsInSection() )
3982 // NextToken direkt aufrufen (z.B. um den Inhalt von
3983 // Floating-Frames oder Applets zu ignorieren)
3984 NextToken( nToken );
3986 else switch( nToken )
3988 case HTML_TABLEHEADER_ON:
3989 case HTML_TABLEDATA_ON:
3990 case HTML_TABLEROW_ON:
3991 case HTML_TABLEROW_OFF:
3992 case HTML_THEAD_ON:
3993 case HTML_THEAD_OFF:
3994 case HTML_TFOOT_ON:
3995 case HTML_TFOOT_OFF:
3996 case HTML_TBODY_ON:
3997 case HTML_TBODY_OFF:
3998 case HTML_TABLE_OFF:
3999 SkipToken(-1);
4000 case HTML_TABLEHEADER_OFF:
4001 case HTML_TABLEDATA_OFF:
4002 bDone = sal_True;
4003 break;
4004 case HTML_TABLE_ON:
4006 sal_Bool bTopTable = sal_False;
4007 sal_Bool bHasToFly = sal_False;
4008 SvxAdjust eTabAdjust = SVX_ADJUST_END;
4009 if( !pPendStack )
4011 // nur wenn eine neue Tabelle aufgemacht wird, aber
4012 // nicht wenn nach einem Pending in der Tabelle
4013 // weitergelesen wird!
4014 pSaveStruct->pTable = pTable;
4016 // HACK: Eine Section fuer eine Tabelle anlegen, die
4017 // in einen Rahmen kommt.
4018 if( !pSaveStruct->IsInSection() )
4020 // Diese Schleife muss vorwartes sein, weil die
4021 // erste Option immer gewinnt.
4022 sal_Bool bNeedsSection = sal_False;
4023 const HTMLOptions *pHTMLOptions = GetOptions();
4024 for( sal_uInt16 i=0; i<pHTMLOptions->Count(); i++ )
4026 const HTMLOption *pOption = (*pHTMLOptions)[i];
4027 if( HTML_O_ALIGN==pOption->GetToken() )
4029 SvxAdjust eAdjust =
4030 (SvxAdjust)pOption->GetEnum(
4031 aHTMLPAlignTable, SVX_ADJUST_END );
4032 bNeedsSection = SVX_ADJUST_LEFT == eAdjust ||
4033 SVX_ADJUST_RIGHT == eAdjust;
4034 break;
4037 if( bNeedsSection )
4039 pSaveStruct->AddContents(
4040 InsertTableContents(bHead ) );
4043 else
4045 // Wenn wir mitlerweile in einem Rahmen stehen
4046 // koennen wir erneut eine echte Tabelle aufmachen.
4047 // Wir erkennen das daran, dass wir keinen
4048 // Tabellen-Node mehr finden.
4049 bTopTable = pDoc->GetNodes()[pPam->GetPoint()->nNode]
4050 ->FindTableNode() == 0;
4052 // Wenn im aktuellen Absatz Flys verankert sind,
4053 // muss die neue Tabelle in einen Rahmen.
4054 bHasToFly = HasCurrentParaFlys(sal_False,sal_True);
4057 // in der Zelle kann sich ein Bereich befinden!
4058 eTabAdjust = aAttrTab.pAdjust
4059 ? ((const SvxAdjustItem&)aAttrTab.pAdjust->GetItem()).
4060 GetAdjust()
4061 : SVX_ADJUST_END;
4064 HTMLTable *pSubTable = BuildTable( eTabAdjust,
4065 bHead,
4066 pSaveStruct->IsInSection(),
4067 bTopTable, bHasToFly );
4068 if( SVPAR_PENDING != GetStatus() )
4070 // nur wenn die Tabelle wirklich zu Ende ist!
4071 if( pSubTable )
4073 ASSERT( pSubTable->GetTableAdjust(sal_False)!= SVX_ADJUST_LEFT &&
4074 pSubTable->GetTableAdjust(sal_False)!= SVX_ADJUST_RIGHT,
4075 "links oder rechts ausgerichtete Tabellen gehoehren in Rahmen" );
4078 HTMLTableCnts *pParentContents =
4079 pSubTable->GetParentContents();
4080 if( pParentContents )
4082 ASSERT( !pSaveStruct->IsInSection(),
4083 "Wo ist die Section geblieben" );
4085 // Wenn jetzt keine Tabelle kommt haben wir eine
4086 // Section
4087 pSaveStruct->AddContents( pParentContents );
4090 const SwStartNode *pCapStNd =
4091 pSubTable->GetCaptionStartNode();
4093 if( pSubTable->GetContext() )
4095 ASSERT( !pSubTable->GetContext()->GetFrmFmt(),
4096 "Tabelle steht im Rahmen" );
4098 if( pCapStNd && pSubTable->IsTopCaption() )
4100 pSaveStruct->AddContents(
4101 new HTMLTableCnts(pCapStNd) );
4104 pSaveStruct->AddContents(
4105 new HTMLTableCnts(pSubTable) );
4107 if( pCapStNd && !pSubTable->IsTopCaption() )
4109 pSaveStruct->AddContents(
4110 new HTMLTableCnts(pCapStNd) );
4113 // Jetzt haben wir keine Section mehr
4114 pSaveStruct->ClearIsInSection();
4116 else if( pCapStNd )
4118 // Da wir diese Sction nicht mehr loeschen
4119 // koennen (sie koeente zur erster Box
4120 // gehoeren), fuegen wir sie ein.
4121 pSaveStruct->AddContents(
4122 new HTMLTableCnts(pCapStNd) );
4124 // Jetzt haben wir keine Section mehr
4125 pSaveStruct->ClearIsInSection();
4129 pTable = pSaveStruct->pTable;
4132 break;
4134 case HTML_NOBR_ON:
4135 // HACK fuer MS: Steht das <NOBR> zu beginn der Zelle?
4136 pSaveStruct->StartNoBreak( *pPam->GetPoint() );
4137 break;
4139 case HTML_NOBR_OFF:
4140 pSaveStruct->EndNoBreak( *pPam->GetPoint() );
4141 break;
4143 case HTML_COMMENT:
4144 // Mit Kommentar-Feldern werden Spaces nicht mehr geloescht
4145 // ausserdem wollen wir fuer einen Kommentar keine neue Zelle
4146 // anlegen !!!
4147 NextToken( nToken );
4148 break;
4150 case HTML_MARQUEE_ON:
4151 if( !pSaveStruct->IsInSection() )
4153 // eine neue Section anlegen, der PaM steht dann darin
4154 pSaveStruct->AddContents(
4155 InsertTableContents( bHead ) );
4157 bCallNextToken = sal_True;
4158 NewMarquee( pCurTable );
4159 break;
4161 case HTML_TEXTTOKEN:
4162 // keine Section fuer einen leeren String anlegen
4163 if( !pSaveStruct->IsInSection() && 1==aToken.Len() &&
4164 ' '==aToken.GetChar(0) )
4165 break;
4166 default:
4167 if( !pSaveStruct->IsInSection() )
4169 // eine neue Section anlegen, der PaM steht dann darin
4170 pSaveStruct->AddContents(
4171 InsertTableContents( bHead ) );
4174 if( IsParserWorking() || bPending )
4175 NextToken( nToken );
4176 break;
4179 ASSERT( !bPending || !pPendStack,
4180 "SwHTMLParser::BuildTableCell: Es gibt wieder einen Pend-Stack" );
4181 bPending = sal_False;
4182 if( IsParserWorking() )
4183 SaveState( 0 );
4185 if( !bDone )
4186 nToken = GetNextToken();
4189 if( SVPAR_PENDING == GetStatus() )
4191 pPendStack = new SwPendingStack( bHead ? HTML_TABLEHEADER_ON
4192 : HTML_TABLEDATA_ON, pPendStack );
4193 pPendStack->pData = pSaveStruct;
4195 return;
4198 // Falls der Inhalt der Zelle leer war, muessen wir noch einen
4199 // leeren Inhalt anlegen. Ausserdem legen wir einen leeren Inhalt
4200 // an, wenn die Zelle mit einer Tabelle aufgehoert hat und keine
4201 // COL-Tags hatte (sonst wurde sie wahrscheinlich von uns exportiert,
4202 // und dann wollen wir natuerlich keinen zusaetzlichen Absatz haben).
4203 if( !pSaveStruct->GetFirstContents() ||
4204 (!pSaveStruct->IsInSection() && !pCurTable->HasColTags()) )
4206 ASSERT( pSaveStruct->GetFirstContents() ||
4207 !pSaveStruct->IsInSection(),
4208 "Section oder nicht, das ist hier die Frage" );
4209 const SwStartNode *pStNd =
4210 InsertTableSection( static_cast< USHORT >(pSaveStruct->IsHeaderCell()
4211 ? RES_POOLCOLL_TABLE_HDLN
4212 : RES_POOLCOLL_TABLE ));
4213 const SwEndNode *pEndNd = pStNd->EndOfSectionNode();
4214 SwCntntNode *pCNd = pDoc->GetNodes()[pEndNd->GetIndex()-1] ->GetCntntNode();
4215 SvxFontHeightItem aFontHeight( 40, 100, RES_CHRATR_FONTSIZE );
4216 pCNd->SetAttr( aFontHeight );
4217 aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE );
4218 pCNd->SetAttr( aFontHeight );
4219 aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE );
4220 pCNd->SetAttr( aFontHeight );
4222 pSaveStruct->AddContents( new HTMLTableCnts(pStNd) );
4223 pSaveStruct->ClearIsInSection();
4226 if( pSaveStruct->IsInSection() )
4228 pSaveStruct->CheckNoBreak( *pPam->GetPoint(), pDoc );
4230 // Alle noch offenen Kontexte beenden. Wir nehmen hier
4231 // AttrMin, weil nContxtStMin evtl. veraendert wurde.
4232 // Da es durch EndContext wieder restauriert wird, geht das.
4233 while( aContexts.Count() > nContextStAttrMin+1 )
4235 _HTMLAttrContext *pCntxt = PopContext();
4236 EndContext( pCntxt );
4237 delete pCntxt;
4240 // LFs am Absatz-Ende entfernen
4241 if( StripTrailingLF()==0 && !pPam->GetPoint()->nContent.GetIndex() )
4242 StripTrailingPara();
4244 // falls fuer die Zelle eine Ausrichtung gesetzt wurde, muessen
4245 // wir die beenden
4246 _HTMLAttrContext *pCntxt = PopContext();
4247 EndContext( pCntxt );
4248 delete pCntxt;
4250 else
4252 // Alle noch offenen Kontexte beenden
4253 while( aContexts.Count() > nContextStAttrMin )
4255 _HTMLAttrContext *pCntxt = PopContext();
4256 ClearContext( pCntxt );
4257 delete pCntxt;
4261 // auch eine Numerierung muss beendet werden
4262 GetNumInfo().Clear();
4264 SetAttr( sal_False );
4266 pSaveStruct->InsertCell( *this, pCurTable );
4268 // wir stehen jetzt (wahrschenlich) vor <TH>, <TD>, <TR> oder </TABLE>
4269 delete pSaveStruct;
4273 class _RowSaveStruct : public SwPendingStackData
4275 public:
4276 SvxAdjust eAdjust;
4277 sal_Int16 eVertOri;
4278 sal_Bool bHasCells;
4280 _RowSaveStruct() :
4281 eAdjust( SVX_ADJUST_END ), eVertOri( text::VertOrientation::TOP ), bHasCells( sal_False )
4286 void SwHTMLParser::BuildTableRow( HTMLTable *pCurTable, sal_Bool bReadOptions,
4287 SvxAdjust eGrpAdjust,
4288 sal_Int16 eGrpVertOri )
4290 // <TR> wurde bereist gelesen
4292 if( !IsParserWorking() && !pPendStack )
4293 return;
4295 int nToken = 0;
4296 _RowSaveStruct* pSaveStruct;
4298 sal_Bool bPending = sal_False;
4299 if( pPendStack )
4301 pSaveStruct = (_RowSaveStruct*)pPendStack->pData;
4303 SwPendingStack* pTmp = pPendStack->pNext;
4304 delete pPendStack;
4305 pPendStack = pTmp;
4306 nToken = pPendStack ? pPendStack->nToken : GetSaveToken();
4307 bPending = SVPAR_ERROR == eState && pPendStack != 0;
4309 SaveState( nToken );
4311 else
4313 SvxAdjust eAdjust = eGrpAdjust;
4314 sal_Int16 eVertOri = eGrpVertOri;
4315 Color aBGColor;
4316 String aBGImage, aStyle, aId, aClass;
4317 sal_Bool bBGColor = sal_False;
4318 pSaveStruct = new _RowSaveStruct;
4320 if( bReadOptions )
4322 const HTMLOptions *pHTMLOptions = GetOptions();
4323 for( sal_uInt16 i = pHTMLOptions->Count(); i; )
4325 const HTMLOption *pOption = (*pHTMLOptions)[--i];
4326 switch( pOption->GetToken() )
4328 case HTML_O_ID:
4329 aId = pOption->GetString();
4330 break;
4331 case HTML_O_ALIGN:
4332 eAdjust = (SvxAdjust)pOption->GetEnum(
4333 aHTMLPAlignTable, static_cast< sal_uInt16 >(eAdjust) );
4334 break;
4335 case HTML_O_VALIGN:
4336 eVertOri = pOption->GetEnum(
4337 aHTMLTblVAlignTable, eVertOri );
4338 break;
4339 case HTML_O_BGCOLOR:
4340 // Leere BGCOLOR bei <TABLE>, <TR> und <TD>/<TH> wie Netsc.
4341 // ignorieren, bei allen anderen Tags *wirklich* nicht.
4342 if( pOption->GetString().Len() )
4344 pOption->GetColor( aBGColor );
4345 bBGColor = sal_True;
4347 break;
4348 case HTML_O_BACKGROUND:
4349 aBGImage = pOption->GetString();
4350 break;
4351 case HTML_O_STYLE:
4352 aStyle = pOption->GetString();
4353 break;
4354 case HTML_O_CLASS:
4355 aClass= pOption->GetString();
4356 break;
4361 if( aId.Len() )
4362 InsertBookmark( aId );
4364 SvxBrushItem *pBrushItem =
4365 CreateBrushItem( bBGColor ? &aBGColor : 0, aBGImage, aStyle,
4366 aId, aClass );
4367 pCurTable->OpenRow( eAdjust, eVertOri, pBrushItem );
4368 // ist beim ersten GetNextToken schon pending, muss bei
4369 // wiederaufsetzen auf jedenfall neu gelesen werden!
4370 SaveState( 0 );
4373 if( !nToken )
4374 nToken = GetNextToken(); // naechstes Token
4376 sal_Bool bDone = sal_False;
4377 while( (IsParserWorking() && !bDone) || bPending )
4379 SaveState( nToken );
4381 nToken = FilterToken( nToken );
4383 ASSERT( pPendStack || !bCallNextToken ||
4384 pCurTable->GetContext() || pCurTable->HasParentSection(),
4385 "Wo ist die Section gebieben?" );
4386 if( !pPendStack && bCallNextToken &&
4387 (pCurTable->GetContext() || pCurTable->HasParentSection()) )
4389 // NextToken direkt aufrufen (z.B. um den Inhalt von
4390 // Floating-Frames oder Applets zu ignorieren)
4391 NextToken( nToken );
4393 else switch( nToken )
4395 case HTML_TABLE_ON:
4396 if( !pCurTable->GetContext() )
4398 SkipToken( -1 );
4399 bDone = sal_True;
4401 // else
4402 // {
4403 // NextToken( nToken );
4404 // }
4405 break;
4406 case HTML_TABLEROW_ON:
4407 case HTML_THEAD_ON:
4408 case HTML_THEAD_OFF:
4409 case HTML_TBODY_ON:
4410 case HTML_TBODY_OFF:
4411 case HTML_TFOOT_ON:
4412 case HTML_TFOOT_OFF:
4413 case HTML_TABLE_OFF:
4414 SkipToken( -1 );
4415 case HTML_TABLEROW_OFF:
4416 bDone = sal_True;
4417 break;
4418 case HTML_TABLEHEADER_ON:
4419 case HTML_TABLEDATA_ON:
4420 BuildTableCell( pCurTable, sal_True, HTML_TABLEHEADER_ON==nToken );
4421 if( SVPAR_PENDING != GetStatus() )
4423 pSaveStruct->bHasCells = sal_True;
4424 bDone = pTable->IsOverflowing();
4426 break;
4427 case HTML_CAPTION_ON:
4428 BuildTableCaption( pCurTable );
4429 bDone = pTable->IsOverflowing();
4430 break;
4431 case HTML_CAPTION_OFF:
4432 case HTML_TABLEHEADER_OFF:
4433 case HTML_TABLEDATA_OFF:
4434 case HTML_COLGROUP_ON:
4435 case HTML_COLGROUP_OFF:
4436 case HTML_COL_ON:
4437 case HTML_COL_OFF:
4438 // wo keine Zelle anfing kann auch keine aufhoehren, oder?
4439 // und die ganzen anderen Tokens haben hier auch nicht zu
4440 // suchen und machen nur die Tabelle kaputt
4441 break;
4442 case HTML_MULTICOL_ON:
4443 // spaltige Rahmen koennen wir hier leider nicht einguegen
4444 break;
4445 case HTML_FORM_ON:
4446 NewForm( sal_False ); // keinen neuen Absatz aufmachen!
4447 break;
4448 case HTML_FORM_OFF:
4449 EndForm( sal_False ); // keinen neuen Absatz aufmachen!
4450 break;
4451 case HTML_COMMENT:
4452 NextToken( nToken );
4453 break;
4454 case HTML_MAP_ON:
4455 // eine Image-Map fuegt nichts ein, deshalb koennen wir sie
4456 // problemlos auch ohne Zelle parsen
4457 NextToken( nToken );
4458 break;
4459 case HTML_TEXTTOKEN:
4460 if( (pCurTable->GetContext() ||
4461 !pCurTable->HasParentSection()) &&
4462 1==aToken.Len() && ' '==aToken.GetChar(0) )
4463 break;
4464 default:
4465 pCurTable->MakeParentContents();
4466 NextToken( nToken );
4467 break;
4470 ASSERT( !bPending || !pPendStack,
4471 "SwHTMLParser::BuildTableRow: Es gibt wieder einen Pend-Stack" );
4472 bPending = sal_False;
4473 if( IsParserWorking() )
4474 SaveState( 0 );
4476 if( !bDone )
4477 nToken = GetNextToken();
4480 if( SVPAR_PENDING == GetStatus() )
4482 pPendStack = new SwPendingStack( HTML_TABLEROW_ON, pPendStack );
4483 pPendStack->pData = pSaveStruct;
4485 else
4487 pCurTable->CloseRow( !pSaveStruct->bHasCells );
4488 delete pSaveStruct;
4491 // wir stehen jetzt (wahrscheinlich) vor <TR> oder </TABLE>
4494 void SwHTMLParser::BuildTableSection( HTMLTable *pCurTable,
4495 sal_Bool bReadOptions,
4496 sal_Bool bHead )
4498 // <THEAD>, <TBODY> bzw. <TFOOT> wurde bereits gelesen
4499 if( !IsParserWorking() && !pPendStack )
4500 return;
4502 int nToken = 0;
4503 sal_Bool bPending = sal_False;
4504 _RowSaveStruct* pSaveStruct;
4506 if( pPendStack )
4508 pSaveStruct = (_RowSaveStruct*)pPendStack->pData;
4510 SwPendingStack* pTmp = pPendStack->pNext;
4511 delete pPendStack;
4512 pPendStack = pTmp;
4513 nToken = pPendStack ? pPendStack->nToken : GetSaveToken();
4514 bPending = SVPAR_ERROR == eState && pPendStack != 0;
4516 SaveState( nToken );
4518 else
4520 pSaveStruct = new _RowSaveStruct;
4522 if( bReadOptions )
4524 const HTMLOptions *pHTMLOptions = GetOptions();
4525 for( sal_uInt16 i = pHTMLOptions->Count(); i; )
4527 const HTMLOption *pOption = (*pHTMLOptions)[--i];
4528 switch( pOption->GetToken() )
4530 case HTML_O_ID:
4531 InsertBookmark( pOption->GetString() );
4532 break;
4533 case HTML_O_ALIGN:
4534 pSaveStruct->eAdjust =
4535 (SvxAdjust)pOption->GetEnum( aHTMLPAlignTable,
4536 static_cast< sal_uInt16 >(pSaveStruct->eAdjust) );
4537 break;
4538 case HTML_O_VALIGN:
4539 pSaveStruct->eVertOri =
4540 pOption->GetEnum( aHTMLTblVAlignTable,
4541 pSaveStruct->eVertOri );
4542 break;
4547 // ist beim ersten GetNextToken schon pending, muss bei
4548 // wiederaufsetzen auf jedenfall neu gelesen werden!
4549 SaveState( 0 );
4552 if( !nToken )
4553 nToken = GetNextToken(); // naechstes Token
4555 sal_Bool bDone = sal_False;
4556 while( (IsParserWorking() && !bDone) || bPending )
4558 SaveState( nToken );
4560 nToken = FilterToken( nToken );
4562 ASSERT( pPendStack || !bCallNextToken ||
4563 pCurTable->GetContext() || pCurTable->HasParentSection(),
4564 "Wo ist die Section gebieben?" );
4565 if( !pPendStack && bCallNextToken &&
4566 (pCurTable->GetContext() || pCurTable->HasParentSection()) )
4568 // NextToken direkt aufrufen (z.B. um den Inhalt von
4569 // Floating-Frames oder Applets zu ignorieren)
4570 NextToken( nToken );
4572 else switch( nToken )
4574 case HTML_TABLE_ON:
4575 if( !pCurTable->GetContext() )
4577 SkipToken( -1 );
4578 bDone = sal_True;
4580 // else
4581 // {
4582 // NextToken( nToken );
4583 // }
4584 break;
4585 case HTML_THEAD_ON:
4586 case HTML_TFOOT_ON:
4587 case HTML_TBODY_ON:
4588 case HTML_TABLE_OFF:
4589 SkipToken( -1 );
4590 case HTML_THEAD_OFF:
4591 case HTML_TBODY_OFF:
4592 case HTML_TFOOT_OFF:
4593 bDone = sal_True;
4594 break;
4595 case HTML_CAPTION_ON:
4596 BuildTableCaption( pCurTable );
4597 bDone = pTable->IsOverflowing();
4598 break;
4599 case HTML_CAPTION_OFF:
4600 break;
4601 case HTML_TABLEHEADER_ON:
4602 case HTML_TABLEDATA_ON:
4603 SkipToken( -1 );
4604 BuildTableRow( pCurTable, sal_False, pSaveStruct->eAdjust,
4605 pSaveStruct->eVertOri );
4606 bDone = pTable->IsOverflowing();
4607 break;
4608 case HTML_TABLEROW_ON:
4609 BuildTableRow( pCurTable, sal_True, pSaveStruct->eAdjust,
4610 pSaveStruct->eVertOri );
4611 bDone = pTable->IsOverflowing();
4612 break;
4613 case HTML_MULTICOL_ON:
4614 // spaltige Rahmen koennen wir hier leider nicht einguegen
4615 break;
4616 case HTML_FORM_ON:
4617 NewForm( sal_False ); // keinen neuen Absatz aufmachen!
4618 break;
4619 case HTML_FORM_OFF:
4620 EndForm( sal_False ); // keinen neuen Absatz aufmachen!
4621 break;
4622 case HTML_TEXTTOKEN:
4623 // Blank-Strings sind Folge von CR+LF und kein Text
4624 if( (pCurTable->GetContext() ||
4625 !pCurTable->HasParentSection()) &&
4626 1==aToken.Len() && ' '==aToken.GetChar(0) )
4627 break;
4628 default:
4629 pCurTable->MakeParentContents();
4630 NextToken( nToken );
4633 ASSERT( !bPending || !pPendStack,
4634 "SwHTMLParser::BuildTableSection: Es gibt wieder einen Pend-Stack" );
4635 bPending = sal_False;
4636 if( IsParserWorking() )
4637 SaveState( 0 );
4639 if( !bDone )
4640 nToken = GetNextToken();
4643 if( SVPAR_PENDING == GetStatus() )
4645 pPendStack = new SwPendingStack( bHead ? HTML_THEAD_ON
4646 : HTML_TBODY_ON, pPendStack );
4647 pPendStack->pData = pSaveStruct;
4649 else
4651 pCurTable->CloseSection( bHead );
4652 delete pSaveStruct;
4655 // wir stehen jetzt (wahrscheinlich) vor <TBODY>,... oder </TABLE>
4658 struct _TblColGrpSaveStruct : public SwPendingStackData
4660 sal_uInt16 nColGrpSpan;
4661 sal_uInt16 nColGrpWidth;
4662 sal_Bool bRelColGrpWidth;
4663 SvxAdjust eColGrpAdjust;
4664 sal_Int16 eColGrpVertOri;
4666 inline _TblColGrpSaveStruct();
4669 inline void CloseColGroup( HTMLTable *pTable );
4672 inline _TblColGrpSaveStruct::_TblColGrpSaveStruct() :
4673 nColGrpSpan( 1 ), nColGrpWidth( 0 ),
4674 bRelColGrpWidth( sal_False ), eColGrpAdjust( SVX_ADJUST_END ),
4675 eColGrpVertOri( text::VertOrientation::TOP )
4679 inline void _TblColGrpSaveStruct::CloseColGroup( HTMLTable *pTable )
4681 pTable->CloseColGroup( nColGrpSpan, nColGrpWidth,
4682 bRelColGrpWidth, eColGrpAdjust, eColGrpVertOri );
4685 void SwHTMLParser::BuildTableColGroup( HTMLTable *pCurTable,
4686 sal_Bool bReadOptions )
4688 // <COLGROUP> wurde bereits gelesen, wenn bReadOptions
4690 if( !IsParserWorking() && !pPendStack )
4691 return;
4693 int nToken = 0;
4694 sal_Bool bPending = sal_False;
4695 _TblColGrpSaveStruct* pSaveStruct;
4697 if( pPendStack )
4699 pSaveStruct = (_TblColGrpSaveStruct*)pPendStack->pData;
4701 SwPendingStack* pTmp = pPendStack->pNext;
4702 delete pPendStack;
4703 pPendStack = pTmp;
4704 nToken = pPendStack ? pPendStack->nToken : GetSaveToken();
4705 bPending = SVPAR_ERROR == eState && pPendStack != 0;
4707 SaveState( nToken );
4709 else
4712 pSaveStruct = new _TblColGrpSaveStruct;
4713 if( bReadOptions )
4715 const HTMLOptions *pColGrpOptions = GetOptions();
4716 for( sal_uInt16 i = pColGrpOptions->Count(); i; )
4718 const HTMLOption *pColGrpOption = (*pColGrpOptions)[--i];
4719 switch( pColGrpOption->GetToken() )
4721 case HTML_O_ID:
4722 InsertBookmark( pColGrpOption->GetString() );
4723 break;
4724 case HTML_O_SPAN:
4725 pSaveStruct->nColGrpSpan = (sal_uInt16)pColGrpOption->GetNumber();
4726 break;
4727 case HTML_O_WIDTH:
4728 pSaveStruct->nColGrpWidth = (sal_uInt16)pColGrpOption->GetNumber();
4729 pSaveStruct->bRelColGrpWidth =
4730 (pColGrpOption->GetString().Search('*') != STRING_NOTFOUND);
4731 break;
4732 case HTML_O_ALIGN:
4733 pSaveStruct->eColGrpAdjust =
4734 (SvxAdjust)pColGrpOption->GetEnum( aHTMLPAlignTable,
4735 static_cast< sal_uInt16 >(pSaveStruct->eColGrpAdjust) );
4736 break;
4737 case HTML_O_VALIGN:
4738 pSaveStruct->eColGrpVertOri =
4739 pColGrpOption->GetEnum( aHTMLTblVAlignTable,
4740 pSaveStruct->eColGrpVertOri );
4741 break;
4745 // ist beim ersten GetNextToken schon pending, muss bei
4746 // wiederaufsetzen auf jedenfall neu gelesen werden!
4747 SaveState( 0 );
4750 if( !nToken )
4751 nToken = GetNextToken(); // naechstes Token
4753 sal_Bool bDone = sal_False;
4754 while( (IsParserWorking() && !bDone) || bPending )
4756 SaveState( nToken );
4758 nToken = FilterToken( nToken );
4760 ASSERT( pPendStack || !bCallNextToken ||
4761 pCurTable->GetContext() || pCurTable->HasParentSection(),
4762 "Wo ist die Section gebieben?" );
4763 if( !pPendStack && bCallNextToken &&
4764 (pCurTable->GetContext() || pCurTable->HasParentSection()) )
4766 // NextToken direkt aufrufen (z.B. um den Inhalt von
4767 // Floating-Frames oder Applets zu ignorieren)
4768 NextToken( nToken );
4770 else switch( nToken )
4772 case HTML_TABLE_ON:
4773 if( !pCurTable->GetContext() )
4775 SkipToken( -1 );
4776 bDone = sal_True;
4778 // else
4779 // {
4780 // NextToken( nToken );
4781 // }
4782 break;
4783 case HTML_COLGROUP_ON:
4784 case HTML_THEAD_ON:
4785 case HTML_TFOOT_ON:
4786 case HTML_TBODY_ON:
4787 case HTML_TABLEROW_ON:
4788 case HTML_TABLE_OFF:
4789 SkipToken( -1 );
4790 case HTML_COLGROUP_OFF:
4791 bDone = sal_True;
4792 break;
4793 case HTML_COL_ON:
4795 sal_uInt16 nColSpan = 1;
4796 sal_uInt16 nColWidth = pSaveStruct->nColGrpWidth;
4797 sal_Bool bRelColWidth = pSaveStruct->bRelColGrpWidth;
4798 SvxAdjust eColAdjust = pSaveStruct->eColGrpAdjust;
4799 sal_Int16 eColVertOri = pSaveStruct->eColGrpVertOri;
4801 const HTMLOptions *pColOptions = GetOptions();
4802 for( sal_uInt16 i = pColOptions->Count(); i; )
4804 const HTMLOption *pColOption = (*pColOptions)[--i];
4805 switch( pColOption->GetToken() )
4807 case HTML_O_ID:
4808 InsertBookmark( pColOption->GetString() );
4809 break;
4810 case HTML_O_SPAN:
4811 nColSpan = (sal_uInt16)pColOption->GetNumber();
4812 break;
4813 case HTML_O_WIDTH:
4814 nColWidth = (sal_uInt16)pColOption->GetNumber();
4815 bRelColWidth =
4816 (pColOption->GetString().Search('*') != STRING_NOTFOUND);
4817 break;
4818 case HTML_O_ALIGN:
4819 eColAdjust =
4820 (SvxAdjust)pColOption->GetEnum( aHTMLPAlignTable,
4821 static_cast< sal_uInt16 >(eColAdjust) );
4822 break;
4823 case HTML_O_VALIGN:
4824 eColVertOri =
4825 pColOption->GetEnum( aHTMLTblVAlignTable,
4826 eColVertOri );
4827 break;
4830 pCurTable->InsertCol( nColSpan, nColWidth, bRelColWidth,
4831 eColAdjust, eColVertOri );
4833 // die Angaben in <COLGRP> sollen ignoriert werden, wenn
4834 // <COL>-Elemente existieren
4835 pSaveStruct->nColGrpSpan = 0;
4837 break;
4838 case HTML_COL_OFF:
4839 break; // Ignorieren
4840 case HTML_MULTICOL_ON:
4841 // spaltige Rahmen koennen wir hier leider nicht einguegen
4842 break;
4843 case HTML_TEXTTOKEN:
4844 if( (pCurTable->GetContext() ||
4845 !pCurTable->HasParentSection()) &&
4846 1==aToken.Len() && ' '==aToken.GetChar(0) )
4847 break;
4848 default:
4849 pCurTable->MakeParentContents();
4850 NextToken( nToken );
4853 ASSERT( !bPending || !pPendStack,
4854 "SwHTMLParser::BuildTableColGrp: Es gibt wieder einen Pend-Stack" );
4855 bPending = sal_False;
4856 if( IsParserWorking() )
4857 SaveState( 0 );
4859 if( !bDone )
4860 nToken = GetNextToken();
4863 if( SVPAR_PENDING == GetStatus() )
4865 pPendStack = new SwPendingStack( HTML_COL_ON, pPendStack );
4866 pPendStack->pData = pSaveStruct;
4868 else
4870 pSaveStruct->CloseColGroup( pCurTable );
4871 delete pSaveStruct;
4875 class _CaptionSaveStruct : public _SectionSaveStruct
4877 SwPosition aSavePos;
4878 SwHTMLNumRuleInfo aNumRuleInfo; // gueltige Numerierung
4880 public:
4882 _HTMLAttrTable aAttrTab; // und die Attribute
4884 _CaptionSaveStruct( SwHTMLParser& rParser, const SwPosition& rPos ) :
4885 _SectionSaveStruct( rParser ), aSavePos( rPos )
4887 rParser.SaveAttrTab( aAttrTab );
4889 // Die aktuelle Numerierung wurde gerettet und muss nur
4890 // noch beendet werden.
4891 aNumRuleInfo.Set( rParser.GetNumInfo() );
4892 rParser.GetNumInfo().Clear();
4895 const SwPosition& GetPos() const { return aSavePos; }
4897 void RestoreAll( SwHTMLParser& rParser )
4899 // Die alten Stack wiederherstellen
4900 Restore( rParser );
4902 // Die alte Attribut-Tabelle wiederherstellen
4903 rParser.RestoreAttrTab( aAttrTab );
4905 // Die alte Numerierung wieder aufspannen
4906 rParser.GetNumInfo().Set( aNumRuleInfo );
4909 virtual ~_CaptionSaveStruct();
4912 _CaptionSaveStruct::~_CaptionSaveStruct()
4915 void SwHTMLParser::BuildTableCaption( HTMLTable *pCurTable )
4917 // <CAPTION> wurde bereits gelesen
4919 if( !IsParserWorking() && !pPendStack )
4920 return;
4922 int nToken = 0;
4923 _CaptionSaveStruct* pSaveStruct;
4925 if( pPendStack )
4927 pSaveStruct = (_CaptionSaveStruct*)pPendStack->pData;
4929 SwPendingStack* pTmp = pPendStack->pNext;
4930 delete pPendStack;
4931 pPendStack = pTmp;
4932 nToken = pPendStack ? pPendStack->nToken : GetSaveToken();
4933 ASSERT( !pPendStack, "Wo kommt hier ein Pending-Stack her?" );
4935 SaveState( nToken );
4937 else
4939 if( pTable->IsOverflowing() )
4941 SaveState( 0 );
4942 return;
4945 sal_Bool bTop = sal_True;
4946 const HTMLOptions *pHTMLOptions = GetOptions();
4947 for ( sal_uInt16 i = pHTMLOptions->Count(); i; )
4949 const HTMLOption *pOption = (*pHTMLOptions)[--i];
4950 if( HTML_O_ALIGN == pOption->GetToken() )
4952 if( pOption->GetString().EqualsIgnoreCaseAscii(OOO_STRING_SVTOOLS_HTML_VA_bottom))
4953 bTop = sal_False;
4957 // Alte PaM-Position retten.
4958 pSaveStruct = new _CaptionSaveStruct( *this, *pPam->GetPoint() );
4960 // Eine Text-Section im Icons-Bereich als Container fuer die
4961 // Ueberschrift anlegen und PaM dort reinstellen.
4962 const SwStartNode *pStNd;
4963 if( pTable == pCurTable )
4964 pStNd = InsertTempTableCaptionSection();
4965 else
4966 pStNd = InsertTableSection( RES_POOLCOLL_TEXT );
4968 _HTMLAttrContext *pCntxt = new _HTMLAttrContext( HTML_CAPTION_ON );
4970 // Tabellen-Ueberschriften sind immer zentriert.
4971 NewAttr( &aAttrTab.pAdjust, SvxAdjustItem(SVX_ADJUST_CENTER, RES_PARATR_ADJUST) );
4973 _HTMLAttrs &rAttrs = pCntxt->GetAttrs();
4974 rAttrs.Insert( aAttrTab.pAdjust, rAttrs.Count() );
4976 PushContext( pCntxt );
4978 // StartNode der Section an der Tabelle merken.
4979 pCurTable->SetCaption( pStNd, bTop );
4981 // ist beim ersten GetNextToken schon pending, muss bei
4982 // wiederaufsetzen auf jedenfall neu gelesen werden!
4983 SaveState( 0 );
4986 if( !nToken )
4987 nToken = GetNextToken(); // naechstes Token
4989 // </CAPTION> wird laut DTD benoetigt
4990 sal_Bool bDone = sal_False;
4991 while( IsParserWorking() && !bDone )
4993 SaveState( nToken );
4995 nToken = FilterToken( nToken );
4997 switch( nToken )
4999 case HTML_TABLE_ON:
5000 if( !pPendStack )
5002 pSaveStruct->pTable = pTable;
5003 sal_Bool bHasToFly = pSaveStruct->pTable!=pCurTable;
5004 BuildTable( pCurTable->GetTableAdjust( sal_True ),
5005 sal_False, sal_True, sal_True, bHasToFly );
5007 else
5009 BuildTable( SVX_ADJUST_END );
5011 if( SVPAR_PENDING != GetStatus() )
5013 pTable = pSaveStruct->pTable;
5015 break;
5016 case HTML_TABLE_OFF:
5017 case HTML_COLGROUP_ON:
5018 case HTML_THEAD_ON:
5019 case HTML_TFOOT_ON:
5020 case HTML_TBODY_ON:
5021 case HTML_TABLEROW_ON:
5022 SkipToken( -1 );
5023 bDone = sal_True;
5024 break;
5026 case HTML_CAPTION_OFF:
5027 bDone = sal_True;
5028 break;
5029 default:
5030 int nNxtToken = nToken;
5031 if( pPendStack )
5033 SwPendingStack* pTmp = pPendStack->pNext;
5034 delete pPendStack;
5035 pPendStack = pTmp;
5037 ASSERT( !pTmp, "weiter kann es nicht gehen!" );
5038 nNxtToken = 0; // neu lesen
5041 if( IsParserWorking() )
5042 NextToken( nToken );
5043 break;
5046 if( IsParserWorking() )
5047 SaveState( 0 );
5049 if( !bDone )
5050 nToken = GetNextToken();
5053 if( SVPAR_PENDING==GetStatus() )
5055 pPendStack = new SwPendingStack( HTML_CAPTION_ON, pPendStack );
5056 pPendStack->pData = pSaveStruct;
5057 return;
5060 // Alle noch offenen Kontexte beenden
5061 while( aContexts.Count() > nContextStAttrMin+1 )
5063 _HTMLAttrContext *pCntxt = PopContext();
5064 EndContext( pCntxt );
5065 delete pCntxt;
5068 // LF am Absatz-Ende entfernen
5069 sal_Bool bLFStripped = StripTrailingLF() > 0;
5071 if( pTable==pCurTable )
5073 // Beim spaeteren verschieben der Beschriftung vor oder hinter
5074 // die Tabelle wird der letzte Absatz nicht mitverschoben.
5075 // Deshalb muss sich am Ende der Section immer ein leerer
5076 // Absatz befinden.
5077 if( pPam->GetPoint()->nContent.GetIndex() || bLFStripped )
5078 AppendTxtNode( AM_NOSPACE );
5080 else
5082 // LFs am Absatz-Ende entfernen
5083 if( !pPam->GetPoint()->nContent.GetIndex() && !bLFStripped )
5084 StripTrailingPara();
5087 // falls fuer die Zelle eine Ausrichtung gesetzt wurde, muessen
5088 // wir die beenden
5089 _HTMLAttrContext *pCntxt = PopContext();
5090 EndContext( pCntxt );
5091 delete pCntxt;
5093 SetAttr( sal_False );
5095 // Stacks und Attribut-Tabelle wiederherstellen
5096 pSaveStruct->RestoreAll( *this );
5098 // PaM wiederherstellen.
5099 *pPam->GetPoint() = pSaveStruct->GetPos();
5101 delete pSaveStruct;
5104 class _TblSaveStruct : public SwPendingStackData
5106 public:
5107 HTMLTable *pCurTable;
5109 _TblSaveStruct( HTMLTable *pCurTbl ) :
5110 pCurTable( pCurTbl )
5113 virtual ~_TblSaveStruct();
5115 // Aufbau der Tabelle anstossen und die Tabelle ggf. in einen
5116 // Rahmen packen. Wenn sal_True zurueckgegeben wird muss noch ein
5117 // Absatz eingefuegt werden!
5118 void MakeTable( sal_uInt16 nWidth, SwPosition& rPos, SwDoc *pDoc );
5121 _TblSaveStruct::~_TblSaveStruct()
5125 void _TblSaveStruct::MakeTable( sal_uInt16 nWidth, SwPosition& rPos, SwDoc *pDoc )
5127 pCurTable->MakeTable( 0, nWidth );
5129 _HTMLTableContext *pTCntxt = pCurTable->GetContext();
5130 ASSERT( pTCntxt, "Wo ist der Tabellen-Kontext" );
5132 SwTableNode *pTblNd = pTCntxt->GetTableNode();
5133 ASSERT( pTblNd, "Wo ist der Tabellen-Node" );
5135 if( pDoc->GetRootFrm() && pTblNd )
5137 // Existiert schon ein Layout, dann muss an dieser Tabelle die
5138 // BoxFrames neu erzeugt werden.
5140 if( pTCntxt->GetFrmFmt() )
5142 pTCntxt->GetFrmFmt()->DelFrms();
5143 pTblNd->DelFrms();
5144 pTCntxt->GetFrmFmt()->MakeFrms();
5146 else
5148 pTblNd->DelFrms();
5149 SwNodeIndex aIdx( *pTblNd->EndOfSectionNode(), 1 );
5150 ASSERT( aIdx.GetIndex() <= pTCntxt->GetPos()->nNode.GetIndex(),
5151 "unerwarteter Node fuer das Tabellen-Layout" );
5152 pTblNd->MakeFrms( &aIdx );
5156 rPos = *pTCntxt->GetPos();
5160 HTMLTableOptions::HTMLTableOptions( const HTMLOptions *pOptions,
5161 SvxAdjust eParentAdjust ) :
5162 nCols( 0 ),
5163 nWidth( 0 ), nHeight( 0 ),
5164 nCellPadding( USHRT_MAX ), nCellSpacing( USHRT_MAX ),
5165 nBorder( USHRT_MAX ),
5166 nHSpace( 0 ), nVSpace( 0 ),
5167 eAdjust( eParentAdjust ), eVertOri( text::VertOrientation::CENTER ),
5168 eFrame( HTML_TF_VOID ), eRules( HTML_TR_NONE ),
5169 bPrcWidth( sal_False ),
5170 bTableAdjust( sal_False ),
5171 bBGColor( sal_False ),
5172 aBorderColor( COL_GRAY )
5174 sal_Bool bBorderColor = sal_False;
5175 sal_Bool bHasFrame = sal_False, bHasRules = sal_False;
5177 for( sal_uInt16 i = pOptions->Count(); i; )
5179 const HTMLOption *pOption = (*pOptions)[--i];
5180 switch( pOption->GetToken() )
5182 case HTML_O_ID:
5183 aId = pOption->GetString();
5184 break;
5185 case HTML_O_COLS:
5186 nCols = (sal_uInt16)pOption->GetNumber();
5187 break;
5188 case HTML_O_WIDTH:
5189 nWidth = (sal_uInt16)pOption->GetNumber();
5190 bPrcWidth = (pOption->GetString().Search('%') != STRING_NOTFOUND);
5191 if( bPrcWidth && nWidth>100 )
5192 nWidth = 100;
5193 break;
5194 case HTML_O_HEIGHT:
5195 nHeight = (sal_uInt16)pOption->GetNumber();
5196 if( pOption->GetString().Search('%') != STRING_NOTFOUND )
5197 nHeight = 0; // keine %-Anagben benutzen!!!
5198 break;
5199 case HTML_O_CELLPADDING:
5200 nCellPadding = (sal_uInt16)pOption->GetNumber();
5201 break;
5202 case HTML_O_CELLSPACING:
5203 nCellSpacing = (sal_uInt16)pOption->GetNumber();
5204 break;
5205 case HTML_O_ALIGN:
5207 sal_uInt16 nAdjust = static_cast< sal_uInt16 >(eAdjust);
5208 if( pOption->GetEnum( nAdjust, aHTMLPAlignTable ) )
5210 eAdjust = (SvxAdjust)nAdjust;
5211 bTableAdjust = sal_True;
5214 break;
5215 case HTML_O_VALIGN:
5216 eVertOri = pOption->GetEnum( aHTMLTblVAlignTable, eVertOri );
5217 break;
5218 case HTML_O_BORDER:
5219 // BORDER und BORDER=BORDER wie BORDER=1 behandeln
5220 if( pOption->GetString().Len() &&
5221 !pOption->GetString().EqualsIgnoreCaseAscii(OOO_STRING_SVTOOLS_HTML_O_border) )
5222 nBorder = (sal_uInt16)pOption->GetNumber();
5223 else
5224 nBorder = 1;
5226 if( !bHasFrame )
5227 eFrame = ( nBorder ? HTML_TF_BOX : HTML_TF_VOID );
5228 if( !bHasRules )
5229 eRules = ( nBorder ? HTML_TR_ALL : HTML_TR_NONE );
5230 break;
5231 case HTML_O_FRAME:
5232 eFrame = pOption->GetTableFrame();
5233 bHasFrame = sal_True;
5234 break;
5235 case HTML_O_RULES:
5236 eRules = pOption->GetTableRules();
5237 bHasRules = sal_True;
5238 break;
5239 case HTML_O_BGCOLOR:
5240 // Leere BGCOLOR bei <TABLE>, <TR> und <TD>/<TH> wie Netscape
5241 // ignorieren, bei allen anderen Tags *wirklich* nicht.
5242 if( pOption->GetString().Len() )
5244 pOption->GetColor( aBGColor );
5245 bBGColor = sal_True;
5247 break;
5248 case HTML_O_BACKGROUND:
5249 aBGImage = pOption->GetString();
5250 break;
5251 case HTML_O_BORDERCOLOR:
5252 pOption->GetColor( aBorderColor );
5253 bBorderColor = sal_True;
5254 break;
5255 case HTML_O_BORDERCOLORDARK:
5256 if( !bBorderColor )
5257 pOption->GetColor( aBorderColor );
5258 break;
5259 case HTML_O_STYLE:
5260 aStyle = pOption->GetString();
5261 break;
5262 case HTML_O_CLASS:
5263 aClass = pOption->GetString();
5264 break;
5265 case HTML_O_DIR:
5266 aDir = pOption->GetString();
5267 break;
5268 case HTML_O_HSPACE:
5269 nHSpace = (sal_uInt16)pOption->GetNumber();
5270 break;
5271 case HTML_O_VSPACE:
5272 nVSpace = (sal_uInt16)pOption->GetNumber();
5273 break;
5277 if( nCols && !nWidth )
5279 nWidth = 100;
5280 bPrcWidth = sal_True;
5283 // Wenn BORDER=0 oder kein BORDER gegeben ist, daan darf es auch
5284 // keine Umrandung geben
5285 if( 0==nBorder || USHRT_MAX==nBorder )
5287 eFrame = HTML_TF_VOID;
5288 eRules = HTML_TR_NONE;
5293 HTMLTable *SwHTMLParser::BuildTable( SvxAdjust eParentAdjust,
5294 sal_Bool bIsParentHead,
5295 sal_Bool bHasParentSection,
5296 sal_Bool bMakeTopSubTable,
5297 sal_Bool bHasToFly )
5299 if( !IsParserWorking() && !pPendStack )
5300 return 0;
5302 int nToken = 0;
5303 sal_Bool bPending = sal_False;
5304 _TblSaveStruct* pSaveStruct;
5306 if( pPendStack )
5308 pSaveStruct = (_TblSaveStruct*)pPendStack->pData;
5310 SwPendingStack* pTmp = pPendStack->pNext;
5311 delete pPendStack;
5312 pPendStack = pTmp;
5313 nToken = pPendStack ? pPendStack->nToken : GetSaveToken();
5314 bPending = SVPAR_ERROR == eState && pPendStack != 0;
5316 SaveState( nToken );
5318 else
5320 pTable = 0;
5321 HTMLTableOptions *pTblOptions =
5322 new HTMLTableOptions( GetOptions(), eParentAdjust );
5324 if( pTblOptions->aId.Len() )
5325 InsertBookmark( pTblOptions->aId );
5327 HTMLTable *pCurTable = new HTMLTable( this, pTable,
5328 bIsParentHead,
5329 bHasParentSection,
5330 bMakeTopSubTable,
5331 bHasToFly,
5332 pTblOptions );
5333 if( !pTable )
5334 pTable = pCurTable;
5336 pSaveStruct = new _TblSaveStruct( pCurTable );
5338 delete pTblOptions;
5340 // ist beim ersten GetNextToken schon pending, muss bei
5341 // wiederaufsetzen auf jedenfall neu gelesen werden!
5342 SaveState( 0 );
5345 HTMLTable *pCurTable = pSaveStruct->pCurTable;
5347 // </TABLE> wird laut DTD benoetigt
5348 if( !nToken )
5349 nToken = GetNextToken(); // naechstes Token
5351 sal_Bool bDone = sal_False;
5352 while( (IsParserWorking() && !bDone) || bPending )
5354 SaveState( nToken );
5356 nToken = FilterToken( nToken );
5358 ASSERT( pPendStack || !bCallNextToken ||
5359 pCurTable->GetContext() || pCurTable->HasParentSection(),
5360 "Wo ist die Section gebieben?" );
5361 if( !pPendStack && bCallNextToken &&
5362 (pCurTable->GetContext() || pCurTable->HasParentSection()) )
5364 // NextToken direkt aufrufen (z.B. um den Inhalt von
5365 // Floating-Frames oder Applets zu ignorieren)
5366 NextToken( nToken );
5368 else switch( nToken )
5370 case HTML_TABLE_ON:
5371 if( !pCurTable->GetContext() )
5373 // Wenn noch keine Tabelle eingefuegt wurde,
5374 // die naechste Tabelle lesen
5375 SkipToken( -1 );
5376 bDone = sal_True;
5378 // else
5379 // {
5380 // NextToken( nToken );
5381 // }
5382 break;
5383 case HTML_TABLE_OFF:
5384 bDone = sal_True;
5385 break;
5386 case HTML_CAPTION_ON:
5387 BuildTableCaption( pCurTable );
5388 bDone = pTable->IsOverflowing();
5389 break;
5390 case HTML_COL_ON:
5391 SkipToken( -1 );
5392 BuildTableColGroup( pCurTable, sal_False );
5393 break;
5394 case HTML_COLGROUP_ON:
5395 BuildTableColGroup( pCurTable, sal_True );
5396 break;
5397 case HTML_TABLEROW_ON:
5398 case HTML_TABLEHEADER_ON:
5399 case HTML_TABLEDATA_ON:
5400 SkipToken( -1 );
5401 BuildTableSection( pCurTable, sal_False, sal_False );
5402 bDone = pTable->IsOverflowing();
5403 break;
5404 case HTML_THEAD_ON:
5405 case HTML_TFOOT_ON:
5406 case HTML_TBODY_ON:
5407 BuildTableSection( pCurTable, sal_True, HTML_THEAD_ON==nToken );
5408 bDone = pTable->IsOverflowing();
5409 break;
5410 case HTML_MULTICOL_ON:
5411 // spaltige Rahmen koennen wir hier leider nicht einguegen
5412 break;
5413 case HTML_FORM_ON:
5414 NewForm( sal_False ); // keinen neuen Absatz aufmachen!
5415 break;
5416 case HTML_FORM_OFF:
5417 EndForm( sal_False ); // keinen neuen Absatz aufmachen!
5418 break;
5419 case HTML_TEXTTOKEN:
5420 // Blank-Strings sind u. U. eine Folge von CR+LF und kein Text
5421 if( (pCurTable->GetContext() ||
5422 !pCurTable->HasParentSection()) &&
5423 1==aToken.Len() && ' '==aToken.GetChar(0) )
5424 break;
5425 default:
5426 pCurTable->MakeParentContents();
5427 NextToken( nToken );
5428 break;
5431 ASSERT( !bPending || !pPendStack,
5432 "SwHTMLParser::BuildTable: Es gibt wieder einen Pend-Stack" );
5433 bPending = sal_False;
5434 if( IsParserWorking() )
5435 SaveState( 0 );
5437 if( !bDone )
5438 nToken = GetNextToken();
5441 if( SVPAR_PENDING == GetStatus() )
5443 pPendStack = new SwPendingStack( HTML_TABLE_ON, pPendStack );
5444 pPendStack->pData = pSaveStruct;
5445 return 0;
5448 _HTMLTableContext *pTCntxt = pCurTable->GetContext();
5449 if( pTCntxt )
5451 // Die Tabelle wurde auch angelegt
5453 // Tabellen-Struktur anpassen
5454 pCurTable->CloseTable();
5456 // ausserhalb von Zellen begonnene Kontexte beenden
5457 // muss vor(!) dem Umsetzten der Attribut Tabelle existieren,
5458 // weil die aktuelle danach nicht mehr existiert
5459 while( aContexts.Count() > nContextStAttrMin )
5461 _HTMLAttrContext *pCntxt = PopContext();
5462 ClearContext( pCntxt );
5463 delete pCntxt;
5466 nContextStMin = pTCntxt->GetContextStMin();
5467 nContextStAttrMin = pTCntxt->GetContextStAttrMin();
5469 if( pTable==pCurTable )
5471 // Tabellen-Beschriftung setzen
5472 const SwStartNode *pCapStNd = pTable->GetCaptionStartNode();
5473 if( pCapStNd )
5475 // Der letzte Absatz der Section wird nie mitkopiert. Deshalb
5476 // muss die Section mindestens zwei Absaetze enthalten.
5478 if( pCapStNd->EndOfSectionIndex() - pCapStNd->GetIndex() > 2 )
5480 // Start-Node und letzten Absatz nicht mitkopieren.
5481 SwNodeRange aSrcRg( *pCapStNd, 1,
5482 *pCapStNd->EndOfSectionNode(), -1 );
5484 sal_Bool bTop = pTable->IsTopCaption();
5485 SwStartNode *pTblStNd = pTCntxt->GetTableNode();
5487 ASSERT( pTblStNd, "Wo ist der Tabellen-Node" );
5488 ASSERT( pTblStNd==pPam->GetNode()->FindTableNode(),
5489 "Stehen wir in der falschen Tabelle?" );
5491 SwNode* pNd;
5492 if( bTop )
5493 pNd = pTblStNd;
5494 else
5495 pNd = pTblStNd->EndOfSectionNode();
5496 SwNodeIndex aDstIdx( *pNd, bTop ? 0 : 1 );
5498 pDoc->MoveNodeRange( aSrcRg, aDstIdx,
5499 IDocumentContentOperations::DOC_MOVEDEFAULT );
5501 // Wenn die Caption vor der Tabelle eingefuegt wurde muss
5502 // eine an der Tabelle gestzte Seitenvorlage noch in den
5503 // ersten Absatz der Ueberschrift verschoben werden.
5504 // Ausserdem muessen alle gemerkten Indizes, die auf den
5505 // Tabellen-Node zeigen noch verschoben werden.
5506 if( bTop )
5508 MovePageDescAttrs( pTblStNd, aSrcRg.aStart.GetIndex(),
5509 sal_False );
5513 // Die Section wird jetzt nicht mehr gebraucht.
5514 pPam->SetMark();
5515 pPam->DeleteMark();
5516 pDoc->DeleteSection( (SwStartNode *)pCapStNd );
5517 pTable->SetCaption( 0, sal_False );
5520 // SwTable aufbereiten
5521 sal_uInt16 nBrowseWidth = (sal_uInt16)GetCurrentBrowseWidth();
5522 pSaveStruct->MakeTable( nBrowseWidth, *pPam->GetPoint(), pDoc );
5524 #ifdef TEST_RESIZE
5525 const SwTable *pSwTable = pTable->GetSwTable();
5526 SwHTMLTableLayout *pLayoutInfo =
5527 pSwTable ? ((SwTable *)pSwTable)->GetHTMLTableLayout() : 0;
5528 if( pLayoutInfo )
5530 ViewShell *pVSh = CheckActionViewShell();
5531 if( pVSh )
5533 CallEndAction( sal_False, sal_False );
5534 CallStartAction( pVSh, sal_False );
5536 sal_uInt16 nNewBrwoseWidth =
5537 (sal_uInt16)GetCurrentBrowseWidth();
5538 if( nBrowseWidth != nNewBrowseWidth )
5539 pLayoutInfo->Resize( nNewBrowseWidth );
5542 #endif
5545 GetNumInfo().Set( pTCntxt->GetNumInfo() );
5546 pTCntxt->RestorePREListingXMP( *this );
5547 RestoreAttrTab( pTCntxt->aAttrTab );
5549 if( pTable==pCurTable )
5551 // oberen Absatz-Abstand einstellen
5552 bUpperSpace = sal_True;
5553 SetTxtCollAttrs();
5555 nParaCnt = nParaCnt - Min(nParaCnt, pTCntxt->GetTableNode()->GetTable().GetTabSortBoxes().Count());
5557 // ggfs. eine Tabelle anspringen
5558 if( JUMPTO_TABLE == eJumpTo && pTable->GetSwTable() &&
5559 pTable->GetSwTable()->GetFrmFmt()->GetName() == sJmpMark )
5561 bChkJumpMark = sal_True;
5562 eJumpTo = JUMPTO_NONE;
5565 // fix #37886#: Wenn Import abgebrochen wurde kein erneutes Show
5566 // aufrufen, weil die ViewShell schon geloescht wurde!
5567 // fix #41669#: Genuegt nicht. Auch im ACCEPTING_STATE darf
5568 // kein Show aufgerufen werden, weil sonst waehrend des
5569 // Reschedules der Parser zerstoert wird, wenn noch ein
5570 // DataAvailable-Link kommt. Deshalb: Nur im WORKING-State.
5571 if( !nParaCnt && SVPAR_WORKING == GetStatus() )
5572 Show();
5575 else if( pTable==pCurTable )
5577 // Es wurde gar keine Tabelle gelesen.
5579 // Dann muss eine evtl gelesene Beschriftung noch geloescht werden.
5580 const SwStartNode *pCapStNd = pCurTable->GetCaptionStartNode();
5581 if( pCapStNd )
5583 pPam->SetMark();
5584 pPam->DeleteMark();
5585 pDoc->DeleteSection( (SwStartNode *)pCapStNd );
5586 pCurTable->SetCaption( 0, sal_False );
5590 if( pTable == pCurTable )
5592 delete pSaveStruct->pCurTable;
5593 pSaveStruct->pCurTable = 0;
5594 pTable = 0;
5597 HTMLTable* pRetTbl = pSaveStruct->pCurTable;
5598 delete pSaveStruct;
5600 return pRetTbl;