1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 //#define TEST_RESIZE
27
28
29 #include "hintids.hxx"
30 #include <vcl/svapp.hxx>
31 #ifndef _WRKWIN_HXX //autogen
32 #include <vcl/wrkwin.hxx>
33 #endif
34 #include <editeng/boxitem.hxx>
35 #include <editeng/brshitem.hxx>
36 #include <editeng/adjitem.hxx>
37 #include <editeng/fhgtitem.hxx>
38 #include <editeng/ulspitem.hxx>
39 #include <editeng/lrspitem.hxx>
40 #include <editeng/brkitem.hxx>
41 #include <editeng/spltitem.hxx>
42 #include <svtools/htmltokn.h>
43 #include <svtools/htmlkywd.hxx>
44 #include <svl/urihelper.hxx>
45
46
47 #include <fmtornt.hxx>
48 #include <frmfmt.hxx>
49 #include <fmtfsize.hxx>
50 #include <fmtsrnd.hxx>
51 #include <fmtpdsc.hxx>
52 #include <fmtcntnt.hxx>
53 #include <fmtanchr.hxx>
54 #include <fmtlsplt.hxx>
55 #include "frmatr.hxx"
56 #include "pam.hxx"
57 #include "doc.hxx"
58 #include "ndtxt.hxx"
59 #include "shellio.hxx"
60 #include "poolfmt.hxx"
61 #include "swtable.hxx"
62 #include "cellatr.hxx"
63 #ifdef TEST_RESIZE
64 #include "viewsh.hxx"
65 #endif
66 #include "htmltbl.hxx"
67 #include "swtblfmt.hxx"
68 #include "htmlnum.hxx"
69 #include "swhtml.hxx"
70 #include "swcss1.hxx"
71 #include <numrule.hxx>
72
73 #define NETSCAPE_DFLT_BORDER 1
74 #define NETSCAPE_DFLT_CELLPADDING 1
75 #define NETSCAPE_DFLT_CELLSPACING 2
76
77 //#define FIX56334
78
79 using namespace ::com::sun::star;
80
81
82 static HTMLOptionEnum __FAR_DATA aHTMLTblVAlignTable[] =
83 {
84 { OOO_STRING_SVTOOLS_HTML_VA_top, text::VertOrientation::NONE },
85 { OOO_STRING_SVTOOLS_HTML_VA_middle, text::VertOrientation::CENTER },
86 { OOO_STRING_SVTOOLS_HTML_VA_bottom, text::VertOrientation::BOTTOM },
87 { 0, 0 }
88 };
89
90
91
92 // Die Optionen eines Table-Tags
93
94 struct HTMLTableOptions
95 {
96 sal_uInt16 nCols;
97 sal_uInt16 nWidth;
98 sal_uInt16 nHeight;
99 sal_uInt16 nCellPadding;
100 sal_uInt16 nCellSpacing;
101 sal_uInt16 nBorder;
102 sal_uInt16 nHSpace;
103 sal_uInt16 nVSpace;
104
105 SvxAdjust eAdjust;
106 sal_Int16 eVertOri;
107 HTMLTableFrame eFrame;
108 HTMLTableRules eRules;
109
110 sal_Bool bPrcWidth : 1;
111 sal_Bool bTableAdjust : 1;
112 sal_Bool bBGColor : 1;
113
114 Color aBorderColor;
115 Color aBGColor;
116
117 String aBGImage, aStyle, aId, aClass, aDir;
118
119 HTMLTableOptions( const HTMLOptions *pOptions, SvxAdjust eParentAdjust );
120 };
121
122
123 class _HTMLTableContext
124 {
125 SwHTMLNumRuleInfo aNumRuleInfo; // Vor der Tabelle gueltige Numerierung
126
127 SwTableNode *pTblNd; // der Tabellen-Node
128 SwFrmFmt *pFrmFmt; // der Fly frame::Frame, in dem die Tabelle steht
129 SwPosition *pPos; // die Position hinter der Tabelle
130
131 sal_uInt16 nContextStAttrMin;
132 sal_uInt16 nContextStMin;
133
134 sal_Bool bRestartPRE : 1;
135 sal_Bool bRestartXMP : 1;
136 sal_Bool bRestartListing : 1;
137
138 public:
139
140 _HTMLAttrTable aAttrTab; // und die Attribute
141
_HTMLTableContext(SwPosition * pPs,sal_uInt16 nCntxtStMin,sal_uInt16 nCntxtStAttrMin)142 _HTMLTableContext( SwPosition *pPs, sal_uInt16 nCntxtStMin,
143 sal_uInt16 nCntxtStAttrMin ) :
144 pTblNd( 0 ),
145 pFrmFmt( 0 ),
146 pPos( pPs ),
147 nContextStAttrMin( nCntxtStAttrMin ),
148 nContextStMin( nCntxtStMin ),
149 bRestartPRE( sal_False ),
150 bRestartXMP( sal_False ),
151 bRestartListing( sal_False )
152 {
153 memset( &aAttrTab, 0, sizeof( _HTMLAttrTable ));
154 }
155
156 ~_HTMLTableContext();
157
SetNumInfo(const SwHTMLNumRuleInfo & rInf)158 void SetNumInfo( const SwHTMLNumRuleInfo& rInf ) { aNumRuleInfo.Set(rInf); }
GetNumInfo() const159 const SwHTMLNumRuleInfo& GetNumInfo() const { return aNumRuleInfo; };
160
161 void SavePREListingXMP( SwHTMLParser& rParser );
162 void RestorePREListingXMP( SwHTMLParser& rParser );
163
GetPos() const164 SwPosition *GetPos() const { return pPos; }
165
SetTableNode(SwTableNode * pNd)166 void SetTableNode( SwTableNode *pNd ) { pTblNd = pNd; }
GetTableNode() const167 SwTableNode *GetTableNode() const { return pTblNd; }
168
SetFrmFmt(SwFrmFmt * pFmt)169 void SetFrmFmt( SwFrmFmt *pFmt ) { pFrmFmt = pFmt; }
GetFrmFmt() const170 SwFrmFmt *GetFrmFmt() const { return pFrmFmt; }
171
GetContextStMin() const172 sal_uInt16 GetContextStMin() const { return nContextStMin; }
GetContextStAttrMin() const173 sal_uInt16 GetContextStAttrMin() const { return nContextStAttrMin; }
174 };
175
176
177 // der Inhalt einer Zelle ist eine verkettete Liste mit SwStartNodes und
178 // HTMLTables.
179
180 class HTMLTableCnts
181 {
182 HTMLTableCnts *pNext; // der naechste Inhalt
183
184 // von den beiden naechsten Pointern darf nur einer gesetzt sein!
185 const SwStartNode *pStartNode; // ein Absatz
186 HTMLTable *pTable; // eine Tabelle
187
188 SwHTMLTableLayoutCnts* pLayoutInfo;
189
190 sal_Bool bNoBreak;
191
192 void InitCtor();
193
194 public:
195
196 HTMLTableCnts( const SwStartNode* pStNd );
197 HTMLTableCnts( HTMLTable* pTab );
198
199 ~HTMLTableCnts(); // nur in ~HTMLTableCell erlaubt
200
201 // Ermitteln des SwStartNode bzw. der HTMLTable
GetStartNode() const202 const SwStartNode *GetStartNode() const { return pStartNode; }
GetTable() const203 const HTMLTable *GetTable() const { return pTable; }
GetTable()204 HTMLTable *GetTable() { return pTable; }
205
206 // hinzufuegen eines neuen Knotens am Listenende
207 void Add( HTMLTableCnts* pNewCnts );
208
209 // Ermitteln des naechsten Knotens
Next() const210 const HTMLTableCnts *Next() const { return pNext; }
Next()211 HTMLTableCnts *Next() { return pNext; }
212
213 inline void SetTableBox( SwTableBox *pBox );
214
SetNoBreak()215 void SetNoBreak() { bNoBreak = sal_True; }
216
217 SwHTMLTableLayoutCnts *CreateLayoutInfo();
218 };
219
220
221 // Eine Zelle der HTML-Tabelle
222
223 class HTMLTableCell
224 {
225 // !!!ACHTUNG!!!!! Fuer jeden neuen Pointer muss die SetProtected-
226 // Methode (und natuerlich der Destruktor) bearbeitet werden.
227 HTMLTableCnts *pContents; // der Inhalt der Zelle
228 SvxBrushItem *pBGBrush; // Hintergrund der Zelle
229 // !!!ACHTUNG!!!!!
230
231 sal_uInt32 nNumFmt;
232 sal_uInt16 nRowSpan; // ROWSPAN der Zelle
233 sal_uInt16 nColSpan; // COLSPAN der Zelle
234 sal_uInt16 nWidth; // WIDTH der Zelle
235 double nValue;
236 sal_Int16 eVertOri; // vertikale Ausrichtung der Zelle
237 sal_Bool bProtected : 1; // Zelle darf nicht belegt werden
238 sal_Bool bRelWidth : 1; // nWidth ist %-Angabe
239 sal_Bool bHasNumFmt : 1;
240 sal_Bool bHasValue : 1;
241 sal_Bool bNoWrap : 1;
242 sal_Bool mbCovered : 1;
243
244 public:
245
246 HTMLTableCell(); // neue Zellen sind immer leer
247
248 ~HTMLTableCell(); // nur in ~HTMLTableRow erlaubt
249
250 // Belegen einer nicht-leeren Zelle
251 void Set( HTMLTableCnts *pCnts, sal_uInt16 nRSpan, sal_uInt16 nCSpan,
252 sal_Int16 eVertOri, SvxBrushItem *pBGBrush,
253 sal_Bool bHasNumFmt, sal_uInt32 nNumFmt,
254 sal_Bool bHasValue, double nValue, sal_Bool bNoWrap, sal_Bool bCovered );
255
256 // Schuetzen einer leeren 1x1-Zelle
257 void SetProtected();
258
259 // Setzen/Ermitteln des Inhalts einer Zelle
SetContents(HTMLTableCnts * pCnts)260 void SetContents( HTMLTableCnts *pCnts ) { pContents = pCnts; }
GetContents() const261 const HTMLTableCnts *GetContents() const { return pContents; }
GetContents()262 HTMLTableCnts *GetContents() { return pContents; }
263
264 // ROWSPAN/COLSPAN der Zelle Setzen/Ermitteln
SetRowSpan(sal_uInt16 nRSpan)265 void SetRowSpan( sal_uInt16 nRSpan ) { nRowSpan = nRSpan; }
GetRowSpan() const266 sal_uInt16 GetRowSpan() const { return nRowSpan; }
267
SetColSpan(sal_uInt16 nCSpan)268 void SetColSpan( sal_uInt16 nCSpan ) { nColSpan = nCSpan; }
GetColSpan() const269 sal_uInt16 GetColSpan() const { return nColSpan; }
270
271 inline void SetWidth( sal_uInt16 nWidth, sal_Bool bRelWidth );
272
GetBGBrush() const273 const SvxBrushItem *GetBGBrush() const { return pBGBrush; }
274
275 inline sal_Bool GetNumFmt( sal_uInt32& rNumFmt ) const;
276 inline sal_Bool GetValue( double& rValue ) const;
277
GetVertOri() const278 sal_Int16 GetVertOri() const { return eVertOri; }
279
280 // Ist die Zelle belegt oder geschuetzt?
IsUsed() const281 sal_Bool IsUsed() const { return pContents!=0 || bProtected; }
282
283 SwHTMLTableLayoutCell *CreateLayoutInfo();
284
IsCovered() const285 sal_Bool IsCovered() const { return mbCovered; }
286 };
287
288
289 // Eine Zeile der HTML-Tabelle
290
291 typedef HTMLTableCell* HTMLTableCellPtr;
292 SV_DECL_PTRARR_DEL(HTMLTableCells,HTMLTableCellPtr,5,5)
293
294 class HTMLTableRow
295 {
296 HTMLTableCells *pCells; // die Zellen der Zeile
297
298 sal_Bool bIsEndOfGroup : 1;
299 sal_Bool bSplitable : 1;
300
301 sal_uInt16 nHeight; // Optionen von <TR>/<TD>
302 sal_uInt16 nEmptyRows; // wieviele Leere Zeilen folgen
303
304 SvxAdjust eAdjust;
305 sal_Int16 eVertOri;
306 SvxBrushItem *pBGBrush; // Hintergrund der Zelle aus STYLE
307
308 public:
309
310 sal_Bool bBottomBorder; // kommt hinter der Zeile eine Linie?
311
312 HTMLTableRow( sal_uInt16 nCells=0 ); // die Zellen der Zeile sind leer
313
314 ~HTMLTableRow();
315
316 inline void SetHeight( sal_uInt16 nHeight );
GetHeight() const317 sal_uInt16 GetHeight() const { return nHeight; }
318
319 // Ermitteln einer Zelle
320 inline HTMLTableCell *GetCell( sal_uInt16 nCell ) const;
GetCells() const321 inline const HTMLTableCells *GetCells() const { return pCells; }
322
323
SetAdjust(SvxAdjust eAdj)324 inline void SetAdjust( SvxAdjust eAdj ) { eAdjust = eAdj; }
GetAdjust() const325 inline SvxAdjust GetAdjust() const { return eAdjust; }
326
SetVertOri(sal_Int16 eV)327 inline void SetVertOri( sal_Int16 eV) { eVertOri = eV; }
GetVertOri() const328 inline sal_Int16 GetVertOri() const { return eVertOri; }
329
SetBGBrush(SvxBrushItem * pBrush)330 void SetBGBrush( SvxBrushItem *pBrush ) { pBGBrush = pBrush; }
GetBGBrush() const331 const SvxBrushItem *GetBGBrush() const { return pBGBrush; }
332
SetEndOfGroup()333 inline void SetEndOfGroup() { bIsEndOfGroup = sal_True; }
IsEndOfGroup() const334 inline sal_Bool IsEndOfGroup() const { return bIsEndOfGroup; }
335
IncEmptyRows()336 void IncEmptyRows() { nEmptyRows++; }
GetEmptyRows() const337 sal_uInt16 GetEmptyRows() const { return nEmptyRows; }
338
339 // Expandieren einer Zeile durch hinzufuegen leerer Zellen
340 void Expand( sal_uInt16 nCells, sal_Bool bOneCell=sal_False );
341
342 // Verkuerzen einer Zeile durch loesen von leeren Zellen
343 void Shrink( sal_uInt16 nCells );
344
SetSplitable(sal_Bool bSet)345 void SetSplitable( sal_Bool bSet ) { bSplitable = bSet; }
IsSplitable() const346 sal_Bool IsSplitable() const { return bSplitable; }
347 };
348
349
350 // Eine Spalte der HTML-Tabelle
351
352 class HTMLTableColumn
353 {
354 sal_Bool bIsEndOfGroup;
355
356 sal_uInt16 nWidth; // Optionen von <COL>
357 sal_Bool bRelWidth;
358
359 SvxAdjust eAdjust;
360 sal_Int16 eVertOri;
361
362 SwFrmFmt *aFrmFmts[6];
363
364 inline sal_uInt16 GetFrmFmtIdx( sal_Bool bBorderLine,
365 sal_Int16 eVertOri ) const;
366
367 public:
368
369 sal_Bool bLeftBorder; // kommt vor der Spalte eine Linie
370
371 HTMLTableColumn();
372
373 inline void SetWidth( sal_uInt16 nWidth, sal_Bool bRelWidth);
374
SetAdjust(SvxAdjust eAdj)375 inline void SetAdjust( SvxAdjust eAdj ) { eAdjust = eAdj; }
GetAdjust() const376 inline SvxAdjust GetAdjust() const { return eAdjust; }
377
SetVertOri(sal_Int16 eV)378 inline void SetVertOri( sal_Int16 eV) { eVertOri = eV; }
GetVertOri() const379 inline sal_Int16 GetVertOri() const { return eVertOri; }
380
SetEndOfGroup()381 inline void SetEndOfGroup() { bIsEndOfGroup = sal_True; }
IsEndOfGroup() const382 inline sal_Bool IsEndOfGroup() const { return bIsEndOfGroup; }
383
384 inline void SetFrmFmt( SwFrmFmt *pFmt, sal_Bool bBorderLine,
385 sal_Int16 eVertOri );
386 inline SwFrmFmt *GetFrmFmt( sal_Bool bBorderLine,
387 sal_Int16 eVertOri ) const;
388
389 SwHTMLTableLayoutColumn *CreateLayoutInfo();
390 };
391
392
393 // eine HTML-Tabelle
394
395 typedef HTMLTableRow* HTMLTableRowPtr;
396 SV_DECL_PTRARR_DEL(HTMLTableRows,HTMLTableRowPtr,5,5)
397
398 typedef HTMLTableColumn* HTMLTableColumnPtr;
399 SV_DECL_PTRARR_DEL(HTMLTableColumns,HTMLTableColumnPtr,5,5)
400
401 SV_DECL_PTRARR(SdrObjects,SdrObject *,1,1)
402
403 class HTMLTable
404 {
405 String aId;
406 String aStyle;
407 String aClass;
408 String aDir;
409
410 SdrObjects *pResizeDrawObjs;// SDR-Objekte
411 SvUShorts *pDrawObjPrcWidths; // Spalte des Zeichen-Objekts und dessen
412 // relative Breite
413
414 HTMLTableRows *pRows; // die Zeilen der Tabelle
415 HTMLTableColumns *pColumns; // die Spalten der Tabelle
416
417 sal_uInt16 nRows; // Anzahl Zeilen
418 sal_uInt16 nCols; // Anzahl Spalten
419 sal_uInt16 nFilledCols; // Anzahl tatsaechlich gefuellter Spalten
420
421 sal_uInt16 nCurRow; // aktuelle Zeile
422 sal_uInt16 nCurCol; // aktuelle Spalte
423
424 sal_uInt16 nLeftMargin; // Abstand zum linken Rand (aus Absatz)
425 sal_uInt16 nRightMargin; // Abstand zum rechten Rand (aus Absatz)
426
427 sal_uInt16 nCellPadding; // Abstand Umrandung zum Text
428 sal_uInt16 nCellSpacing; // Abstand zwischen zwei Zellen
429 sal_uInt16 nHSpace;
430 sal_uInt16 nVSpace;
431
432 sal_uInt16 nBoxes; // Wieviele Boxen enthaelt die Tabelle
433
434 const SwStartNode *pPrevStNd; // der Table-Node oder der Start-Node
435 // der vorhergehenden Section
436 const SwTable *pSwTable; // die SW-Tabelle (nur auf dem Top-Level)
437 SwTableBox *pBox1; // die TableBox, die beim Erstellen
438 // der Top-Level-Tabelle angelegt wird
439
440 SwTableBoxFmt *pBoxFmt; // das frame::Frame-Format einer SwTableBox
441 SwTableLineFmt *pLineFmt; // das frame::Frame-Format einer SwTableLine
442 SwTableLineFmt *pLineFrmFmtNoHeight;
443 SvxBrushItem *pBGBrush; // Hintergrund der Tabelle
444 SvxBrushItem *pInhBGBrush; // "geerbter" Hintergrund der Tabelle
445 const SwStartNode *pCaptionStartNode; // Start-Node der Tabellen-Ueberschrift
446
447 SvxBorderLine aTopBorderLine; // die Linie fuer die Umrandung
448 SvxBorderLine aBottomBorderLine;// die Linie fuer die Umrandung
449 SvxBorderLine aLeftBorderLine; // die Linie fuer die Umrandung
450 SvxBorderLine aRightBorderLine; // die Linie fuer die Umrandung
451 SvxBorderLine aBorderLine; // die Linie fuer die Umrandung
452 SvxBorderLine aInhLeftBorderLine; // die Linie fuer die Umrandung
453 SvxBorderLine aInhRightBorderLine; // die Linie fuer die Umrandung
454 sal_Bool bTopBorder; // besitzt die Tabelle oben eine Linie
455 sal_Bool bRightBorder; // besitzt die Tabelle rechts eine Linie
456 sal_Bool bTopAlwd; // duerfen die Raender gesetzt werden?
457 sal_Bool bRightAlwd;
458 sal_Bool bFillerTopBorder; // bekommt eine linke/rechter Filler-
459 sal_Bool bFillerBottomBorder; // Zelle eine obere/untere Umrandung?
460 sal_Bool bInhLeftBorder;
461 sal_Bool bInhRightBorder;
462 sal_Bool bBordersSet; // die Umrandung wurde bereits gesetzt
463 sal_Bool bForceFrame;
464 sal_Bool bTableAdjustOfTag; // stammt nTableAdjust aus <TABLE>?
465 sal_uInt32 nHeadlineRepeat; // repeating rows
466 sal_Bool bIsParentHead;
467 sal_Bool bHasParentSection;
468 sal_Bool bMakeTopSubTable;
469 sal_Bool bHasToFly;
470 sal_Bool bFixedCols;
471 sal_Bool bColSpec; // Gab es COL(GROUP)-Elemente?
472 sal_Bool bPrcWidth; // Breite ist eine %-Angabe
473
474 SwHTMLParser *pParser; // der aktuelle Parser
475 HTMLTable *pTopTable; // die Tabelle auf dem Top-Level
476 HTMLTableCnts *pParentContents;
477
478 _HTMLTableContext *pContext; // der Kontext der Tabelle
479
480 SwHTMLTableLayout *pLayoutInfo;
481
482
483 // die folgenden Parameter stammen aus der dem <TABLE>-Tag
484 sal_uInt16 nWidth; // die Breite der Tabelle
485 sal_uInt16 nHeight; // absolute Hoehe der Tabelle
486 SvxAdjust eTableAdjust; // drawing::Alignment der Tabelle
487 sal_Int16 eVertOri; // Default vertikale Ausr. der Zellen
488 sal_uInt16 nBorder; // Breite der auesseren Umrandung
489 HTMLTableFrame eFrame; // Rahmen um die Tabelle
490 HTMLTableRules eRules; // Rahmen in der Tabelle
491 sal_Bool bTopCaption; // Ueberschrift ueber der Tabelle
492
493 void InitCtor( const HTMLTableOptions *pOptions );
494
495 // Korrigieren des Row-Spans fuer alle Zellen oberhalb der
496 // angegeben Zelle und der Zelle selbst, fuer die den angegebenen
497 // Inhalt besitzen. Die angegeben Zelle bekommt den Row-Span 1
498 void FixRowSpan( sal_uInt16 nRow, sal_uInt16 nCol, const HTMLTableCnts *pCnts );
499
500 // Schuetzen der angegeben Zelle und den darunterliegenden
501 void ProtectRowSpan( sal_uInt16 nRow, sal_uInt16 nCol, sal_uInt16 nRowSpan );
502
503 // Suchen des SwStartNodes der logisch vorhergehenden Box
504 // bei nRow==nCell==USHRT_MAX wird der allerletzte Start-Node
505 // der Tabelle zurueckgegeben
506 const SwStartNode* GetPrevBoxStartNode( sal_uInt16 nRow, sal_uInt16 nCell ) const;
507
508 sal_uInt16 GetTopCellSpace( sal_uInt16 nRow, sal_uInt16 nRowSpan,
509 sal_Bool bSwBorders=sal_True ) const;
510 sal_uInt16 GetBottomCellSpace( sal_uInt16 nRow, sal_uInt16 nRowSpan,
511 sal_Bool bSwBorders=sal_True ) const;
512
513 // Anpassen des frame::Frame-Formates einer Box
514 void FixFrameFmt( SwTableBox *pBox, sal_uInt16 nRow, sal_uInt16 nCol,
515 sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
516 sal_Bool bFirstPara=sal_True, sal_Bool bLastPara=sal_True ) const;
517 void FixFillerFrameFmt( SwTableBox *pBox, sal_Bool bRight ) const;
518
519 // den Inhalt (Lines/Boxen) eine Tabelle erstellen
520 void _MakeTable( SwTableBox *pUpper=0 );
521
522 // Anlegen einer neuen SwTableBox, die einen SwStartNode enthaelt
523 SwTableBox *NewTableBox( const SwStartNode *pStNd,
524 SwTableLine *pUpper ) const;
525
526 // Erstellen einer SwTableLine aus den Zellen des Rechtecks
527 // (nTopRow/nLeftCol) inklusive bis (nBottomRow/nRightRow) exklusive
528 SwTableLine *MakeTableLine( SwTableBox *pUpper,
529 sal_uInt16 nTopRow, sal_uInt16 nLeftCol,
530 sal_uInt16 nBottomRow, sal_uInt16 nRightCol );
531
532 // Erstellen einer SwTableBox aus dem Inhalt einer Zelle
533 SwTableBox *MakeTableBox( SwTableLine *pUpper,
534 HTMLTableCnts *pCnts,
535 sal_uInt16 nTopRow, sal_uInt16 nLeftCol,
536 sal_uInt16 nBootomRow, sal_uInt16 nRightCol );
537
538 // der Autolayout-Algorithmus
539
540 // Setzen der Umrandung anhand der Vorgaben der Parent-Tabelle
541 void InheritBorders( const HTMLTable *pParent,
542 sal_uInt16 nRow, sal_uInt16 nCol,
543 sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
544 sal_Bool bFirstPara, sal_Bool bLastPara );
545
546 // Linke und rechte Umrandung der umgebenen Tabelle erben
547 void InheritVertBorders( const HTMLTable *pParent,
548 sal_uInt16 nCol, sal_uInt16 nColSpan );
549
550
551 // Setzen der Umrandung anhand der Benutzervorgaben
552 void SetBorders();
553
554 // wurde die Umrandung der Tabelle schon gesetzt
BordersSet() const555 sal_Bool BordersSet() const { return bBordersSet; }
556
GetBGBrush() const557 const SvxBrushItem *GetBGBrush() const { return pBGBrush; }
GetInhBGBrush() const558 const SvxBrushItem *GetInhBGBrush() const { return pInhBGBrush; }
559
560 sal_uInt16 GetBorderWidth( const SvxBorderLine& rBLine,
561 sal_Bool bWithDistance=sal_False ) const;
562
563 public:
564
565 sal_Bool bFirstCell; // wurde schon eine Zelle angelegt?
566
567 HTMLTable( SwHTMLParser* pPars, HTMLTable *pTopTab,
568 sal_Bool bParHead, sal_Bool bHasParentSec,
569 sal_Bool bTopTbl, sal_Bool bHasToFly,
570 const HTMLTableOptions *pOptions );
571
572 ~HTMLTable();
573
574 // Ermitteln einer Zelle
575 inline HTMLTableCell *GetCell( sal_uInt16 nRow, sal_uInt16 nCell ) const;
576
577 // Ueberschrift setzen/ermitteln
578 inline void SetCaption( const SwStartNode *pStNd, sal_Bool bTop );
GetCaptionStartNode() const579 const SwStartNode *GetCaptionStartNode() const { return pCaptionStartNode; }
IsTopCaption() const580 sal_Bool IsTopCaption() const { return bTopCaption; }
581
GetTableAdjust(sal_Bool bAny) const582 SvxAdjust GetTableAdjust( sal_Bool bAny ) const
583 {
584 return (bTableAdjustOfTag || bAny) ? eTableAdjust : SVX_ADJUST_END;
585 }
GetVertOri() const586 sal_Int16 GetVertOri() const { return eVertOri; }
587
GetHSpace() const588 sal_uInt16 GetHSpace() const { return nHSpace; }
GetVSpace() const589 sal_uInt16 GetVSpace() const { return nVSpace; }
590
HasPrcWidth() const591 sal_Bool HasPrcWidth() const { return bPrcWidth; }
GetPrcWidth() const592 sal_uInt8 GetPrcWidth() const { return bPrcWidth ? (sal_uInt8)nWidth : 0; }
593
GetMinWidth() const594 sal_uInt16 GetMinWidth() const
595 {
596 sal_uInt32 nMin = pLayoutInfo->GetMin();
597 return nMin < USHRT_MAX ? (sal_uInt16)nMin : USHRT_MAX;
598 }
599
600 // von Zeilen oder Spalten geerbtes drawing::Alignment holen
601 SvxAdjust GetInheritedAdjust() const;
602 sal_Int16 GetInheritedVertOri() const;
603
604 // Einfuegen einer Zelle an der aktuellen Position
605 void InsertCell( HTMLTableCnts *pCnts, sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
606 sal_uInt16 nWidth, sal_Bool bRelWidth, sal_uInt16 nHeight,
607 sal_Int16 eVertOri, SvxBrushItem *pBGBrush,
608 sal_Bool bHasNumFmt, sal_uInt32 nNumFmt,
609 sal_Bool bHasValue, double nValue, sal_Bool bNoWrap );
610
611 // Start/Ende einer neuen Zeile bekanntgeben
612 void OpenRow( SvxAdjust eAdjust, sal_Int16 eVertOri,
613 SvxBrushItem *pBGBrush );
614 void CloseRow( sal_Bool bEmpty );
615
616 // Ende einer neuen Section bekanntgeben
617 inline void CloseSection( sal_Bool bHead );
618
619 // Ende einer Spalten-Gruppe bekanntgeben
620 inline void CloseColGroup( sal_uInt16 nSpan, sal_uInt16 nWidth, sal_Bool bRelWidth,
621 SvxAdjust eAdjust, sal_Int16 eVertOri );
622
623 // Einfuegen einer Spalte
624 void InsertCol( sal_uInt16 nSpan, sal_uInt16 nWidth, sal_Bool bRelWidth,
625 SvxAdjust eAdjust, sal_Int16 eVertOri );
626
627 // Beenden einer Tab-Definition (MUSS fuer ALLE Tabs aufgerufen werden)
628 void CloseTable();
629
630 // SwTable konstruieren (inkl. der Child-Tabellen)
631 void MakeTable( SwTableBox *pUpper, sal_uInt16 nAbsAvail,
632 sal_uInt16 nRelAvail=0, sal_uInt16 nAbsLeftSpace=0,
633 sal_uInt16 nAbsRightSpace=0, sal_uInt16 nInhAbsSpace=0 );
634
IsNewDoc() const635 inline sal_Bool IsNewDoc() const { return pParser->IsNewDoc(); }
636
SetHasParentSection(sal_Bool bSet)637 void SetHasParentSection( sal_Bool bSet ) { bHasParentSection = bSet; }
HasParentSection() const638 sal_Bool HasParentSection() const { return bHasParentSection; }
639
SetParentContents(HTMLTableCnts * pCnts)640 void SetParentContents( HTMLTableCnts *pCnts ) { pParentContents = pCnts; }
GetParentContents() const641 HTMLTableCnts *GetParentContents() const { return pParentContents; }
642
643 void MakeParentContents();
644
GetIsParentHeader() const645 sal_Bool GetIsParentHeader() const { return bIsParentHead; }
646
IsMakeTopSubTable() const647 sal_Bool IsMakeTopSubTable() const { return bMakeTopSubTable; }
SetHasToFly()648 void SetHasToFly() { bHasToFly=sal_True; }
HasToFly() const649 sal_Bool HasToFly() const { return bHasToFly; }
650
651 void SetTable( const SwStartNode *pStNd, _HTMLTableContext *pCntxt,
652 sal_uInt16 nLeft, sal_uInt16 nRight,
653 const SwTable *pSwTab=0, sal_Bool bFrcFrame=sal_False );
654
GetContext() const655 _HTMLTableContext *GetContext() const { return pContext; }
656
657 SwHTMLTableLayout *CreateLayoutInfo();
658
HasColTags() const659 sal_Bool HasColTags() const { return bColSpec; }
660
IncGrfsThatResize()661 sal_uInt16 IncGrfsThatResize() { return pSwTable ? ((SwTable *)pSwTable)->IncGrfsThatResize() : 0; }
662
663 void RegisterDrawObject( SdrObject *pObj, sal_uInt8 nPrcWidth );
664
GetSwTable() const665 const SwTable *GetSwTable() const { return pSwTable; }
666
SetBGBrush(const SvxBrushItem & rBrush)667 void SetBGBrush( const SvxBrushItem& rBrush ) { delete pBGBrush; pBGBrush = new SvxBrushItem( rBrush ); }
668
GetId() const669 const String& GetId() const { return aId; }
GetClass() const670 const String& GetClass() const { return aClass; }
GetStyle() const671 const String& GetStyle() const { return aStyle; }
GetDirection() const672 const String& GetDirection() const { return aDir; }
673
IncBoxCount()674 void IncBoxCount() { nBoxes++; }
IsOverflowing() const675 sal_Bool IsOverflowing() const { return nBoxes > 64000; }
676 };
677
SV_IMPL_PTRARR(HTMLTableCells,HTMLTableCellPtr)678 SV_IMPL_PTRARR(HTMLTableCells,HTMLTableCellPtr)
679 SV_IMPL_PTRARR(HTMLTableRows,HTMLTableRowPtr)
680 SV_IMPL_PTRARR(HTMLTableColumns,HTMLTableColumnPtr)
681
682
683
684 void HTMLTableCnts::InitCtor()
685 {
686 pNext = 0;
687 pLayoutInfo = 0;
688
689 bNoBreak = sal_False;
690 }
691
HTMLTableCnts(const SwStartNode * pStNd)692 HTMLTableCnts::HTMLTableCnts( const SwStartNode* pStNd ):
693 pStartNode(pStNd), pTable(0)
694 {
695 InitCtor();
696 }
697
HTMLTableCnts(HTMLTable * pTab)698 HTMLTableCnts::HTMLTableCnts( HTMLTable* pTab ):
699 pStartNode(0), pTable(pTab)
700 {
701 InitCtor();
702 }
703
~HTMLTableCnts()704 HTMLTableCnts::~HTMLTableCnts()
705 {
706 delete pTable; // die Tabellen brauchen wir nicht mehr
707 delete pNext;
708 }
709
Add(HTMLTableCnts * pNewCnts)710 void HTMLTableCnts::Add( HTMLTableCnts* pNewCnts )
711 {
712 HTMLTableCnts *pCnts = this;
713
714 while( pCnts->pNext )
715 pCnts = pCnts->pNext;
716
717 pCnts->pNext = pNewCnts;
718 }
719
SetTableBox(SwTableBox * pBox)720 inline void HTMLTableCnts::SetTableBox( SwTableBox *pBox )
721 {
722 ASSERT( pLayoutInfo, "Da ist noch keine Layout-Info" );
723 if( pLayoutInfo )
724 pLayoutInfo->SetTableBox( pBox );
725 }
726
CreateLayoutInfo()727 SwHTMLTableLayoutCnts *HTMLTableCnts::CreateLayoutInfo()
728 {
729 if( !pLayoutInfo )
730 {
731 SwHTMLTableLayoutCnts *pNextInfo = pNext ? pNext->CreateLayoutInfo() : 0;
732 SwHTMLTableLayout *pTableInfo = pTable ? pTable->CreateLayoutInfo() : 0;
733
734 pLayoutInfo = new SwHTMLTableLayoutCnts( pStartNode, pTableInfo,
735 bNoBreak, pNextInfo );
736 }
737
738 return pLayoutInfo;
739 }
740
741
HTMLTableCell()742 HTMLTableCell::HTMLTableCell():
743 pContents(0),
744 pBGBrush(0),
745 nNumFmt(0),
746 nRowSpan(1),
747 nColSpan(1),
748 nWidth( 0 ),
749 nValue(0),
750 eVertOri( text::VertOrientation::NONE ),
751 bProtected(sal_False),
752 bRelWidth( sal_False ),
753 bHasNumFmt(sal_False),
754 bHasValue(sal_False),
755 mbCovered(sal_False)
756 {}
757
~HTMLTableCell()758 HTMLTableCell::~HTMLTableCell()
759 {
760 // der Inhalt ist in mehrere Zellen eingetragen, darf aber nur einmal
761 // geloescht werden
762 if( 1==nRowSpan && 1==nColSpan )
763 {
764 delete pContents;
765 delete pBGBrush;
766 }
767 }
768
Set(HTMLTableCnts * pCnts,sal_uInt16 nRSpan,sal_uInt16 nCSpan,sal_Int16 eVert,SvxBrushItem * pBrush,sal_Bool bHasNF,sal_uInt32 nNF,sal_Bool bHasV,double nVal,sal_Bool bNWrap,sal_Bool bCovered)769 void HTMLTableCell::Set( HTMLTableCnts *pCnts, sal_uInt16 nRSpan, sal_uInt16 nCSpan,
770 sal_Int16 eVert, SvxBrushItem *pBrush,
771 sal_Bool bHasNF, sal_uInt32 nNF, sal_Bool bHasV, double nVal,
772 sal_Bool bNWrap, sal_Bool bCovered )
773 {
774 pContents = pCnts;
775 nRowSpan = nRSpan;
776 nColSpan = nCSpan;
777 bProtected = sal_False;
778 eVertOri = eVert;
779 pBGBrush = pBrush;
780
781 bHasNumFmt = bHasNF;
782 bHasValue = bHasV;
783 nNumFmt = nNF;
784 nValue = nVal;
785
786 bNoWrap = bNWrap;
787 mbCovered = bCovered;
788 }
789
SetWidth(sal_uInt16 nWdth,sal_Bool bRelWdth)790 inline void HTMLTableCell::SetWidth( sal_uInt16 nWdth, sal_Bool bRelWdth )
791 {
792 nWidth = nWdth;
793 bRelWidth = bRelWdth;
794 }
795
SetProtected()796 void HTMLTableCell::SetProtected()
797 {
798 // Die Inhalte dieser Zelle muessen nicht irgendwo anders verankert
799 // sein, weil sie nicht geloescht werden!!!
800
801 // Inhalt loeschen
802 pContents = 0;
803
804 // Hintergrundfarbe kopieren.
805 if( pBGBrush )
806 pBGBrush = new SvxBrushItem( *pBGBrush );
807
808 nRowSpan = 1;
809 nColSpan = 1;
810 bProtected = sal_True;
811 }
812
GetNumFmt(sal_uInt32 & rNumFmt) const813 inline sal_Bool HTMLTableCell::GetNumFmt( sal_uInt32& rNumFmt ) const
814 {
815 rNumFmt = nNumFmt;
816 return bHasNumFmt;
817 }
818
GetValue(double & rValue) const819 inline sal_Bool HTMLTableCell::GetValue( double& rValue ) const
820 {
821 rValue = nValue;
822 return bHasValue;
823 }
824
CreateLayoutInfo()825 SwHTMLTableLayoutCell *HTMLTableCell::CreateLayoutInfo()
826 {
827 SwHTMLTableLayoutCnts *pCntInfo = pContents ? pContents->CreateLayoutInfo() : 0;
828
829 return new SwHTMLTableLayoutCell( pCntInfo, nRowSpan, nColSpan, nWidth,
830 bRelWidth, bNoWrap );
831 }
832
833
HTMLTableRow(sal_uInt16 nCells)834 HTMLTableRow::HTMLTableRow( sal_uInt16 nCells ):
835 pCells(new HTMLTableCells),
836 bIsEndOfGroup(sal_False),
837 bSplitable( sal_False ),
838 nHeight(0),
839 nEmptyRows(0),
840 eAdjust(SVX_ADJUST_END),
841 eVertOri(text::VertOrientation::TOP),
842 pBGBrush(0),
843 bBottomBorder(sal_False)
844 {
845 for( sal_uInt16 i=0; i<nCells; i++ )
846 {
847 pCells->Insert( new HTMLTableCell, pCells->Count() );
848 }
849
850 ASSERT( nCells==pCells->Count(),
851 "Zellenzahl in neuer HTML-Tabellenzeile stimmt nicht" );
852 }
853
~HTMLTableRow()854 HTMLTableRow::~HTMLTableRow()
855 {
856 delete pCells;
857 delete pBGBrush;
858 }
859
SetHeight(sal_uInt16 nHght)860 inline void HTMLTableRow::SetHeight( sal_uInt16 nHght )
861 {
862 if( nHght > nHeight )
863 nHeight = nHght;
864 }
865
GetCell(sal_uInt16 nCell) const866 inline HTMLTableCell *HTMLTableRow::GetCell( sal_uInt16 nCell ) const
867 {
868 ASSERT( nCell<pCells->Count(),
869 "ungueltiger Zellen-Index in HTML-Tabellenzeile" );
870 return (*pCells)[nCell];
871 }
872
Expand(sal_uInt16 nCells,sal_Bool bOneCell)873 void HTMLTableRow::Expand( sal_uInt16 nCells, sal_Bool bOneCell )
874 {
875 // die Zeile wird mit einer einzigen Zelle aufgefuellt, wenn
876 // bOneCell gesetzt ist. Das geht, nur fuer Zeilen, in die keine
877 // Zellen mehr eingefuegt werden!
878
879 sal_uInt16 nColSpan = nCells-pCells->Count();
880 for( sal_uInt16 i=pCells->Count(); i<nCells; i++ )
881 {
882 HTMLTableCell *pCell = new HTMLTableCell;
883 if( bOneCell )
884 pCell->SetColSpan( nColSpan );
885
886 pCells->Insert( pCell, pCells->Count() );
887 nColSpan--;
888 }
889
890 ASSERT( nCells==pCells->Count(),
891 "Zellenzahl in expandierter HTML-Tabellenzeile stimmt nicht" );
892 }
893
Shrink(sal_uInt16 nCells)894 void HTMLTableRow::Shrink( sal_uInt16 nCells )
895 {
896 ASSERT( nCells < pCells->Count(), "Anzahl Zellen falsch" );
897
898 #ifdef DBG_UTIL
899 sal_uInt16 nEnd = pCells->Count();
900 #endif
901 // The colspan of empty cells at the end has to be fixed to the new
902 // number of cells.
903 sal_uInt16 i=nCells;
904 while( i )
905 {
906 HTMLTableCell *pCell = (*pCells)[--i];
907 if( !pCell->GetContents() )
908 {
909 ASSERT( pCell->GetColSpan() == nEnd - i,
910 "invalid col span for empty cell at row end" );
911 pCell->SetColSpan( nCells-i);
912 }
913 else
914 break;
915 }
916 #ifdef DBG_UTIL
917 for( i=nCells; i<nEnd; i++ )
918 {
919 HTMLTableCell *pCell = (*pCells)[i];
920 ASSERT( pCell->GetRowSpan() == 1,
921 "RowSpan von zu loesender Zelle ist falsch" );
922 ASSERT( pCell->GetColSpan() == nEnd - i,
923 "ColSpan von zu loesender Zelle ist falsch" );
924 ASSERT( !pCell->GetContents(), "Zu loeschende Zelle hat Inhalt" );
925 }
926 #endif
927
928 pCells->DeleteAndDestroy( nCells, pCells->Count()-nCells );
929 }
930
931
HTMLTableColumn()932 HTMLTableColumn::HTMLTableColumn():
933 bIsEndOfGroup(sal_False),
934 nWidth(0), bRelWidth(sal_False),
935 eAdjust(SVX_ADJUST_END), eVertOri(text::VertOrientation::TOP),
936 bLeftBorder(sal_False)
937 {
938 for( sal_uInt16 i=0; i<6; i++ )
939 aFrmFmts[i] = 0;
940 }
941
SetWidth(sal_uInt16 nWdth,sal_Bool bRelWdth)942 inline void HTMLTableColumn::SetWidth( sal_uInt16 nWdth, sal_Bool bRelWdth )
943 {
944 if( bRelWidth==bRelWdth )
945 {
946 if( nWdth > nWidth )
947 nWidth = nWdth;
948 }
949 else
950 nWidth = nWdth;
951 bRelWidth = bRelWdth;
952 }
953
CreateLayoutInfo()954 inline SwHTMLTableLayoutColumn *HTMLTableColumn::CreateLayoutInfo()
955 {
956 return new SwHTMLTableLayoutColumn( nWidth, bRelWidth, bLeftBorder );
957 }
958
GetFrmFmtIdx(sal_Bool bBorderLine,sal_Int16 eVertOrient) const959 inline sal_uInt16 HTMLTableColumn::GetFrmFmtIdx( sal_Bool bBorderLine,
960 sal_Int16 eVertOrient ) const
961 {
962 ASSERT( text::VertOrientation::TOP != eVertOrient, "TOP is not allowed!" );
963 sal_uInt16 n = bBorderLine ? 3 : 0;
964 switch( eVertOrient )
965 {
966 case text::VertOrientation::CENTER: n+=1; break;
967 case text::VertOrientation::BOTTOM: n+=2; break;
968 default:
969 ;
970 }
971 return n;
972 }
973
SetFrmFmt(SwFrmFmt * pFmt,sal_Bool bBorderLine,sal_Int16 eVertOrient)974 inline void HTMLTableColumn::SetFrmFmt( SwFrmFmt *pFmt, sal_Bool bBorderLine,
975 sal_Int16 eVertOrient )
976 {
977 aFrmFmts[GetFrmFmtIdx(bBorderLine,eVertOrient)] = pFmt;
978 }
979
GetFrmFmt(sal_Bool bBorderLine,sal_Int16 eVertOrient) const980 inline SwFrmFmt *HTMLTableColumn::GetFrmFmt( sal_Bool bBorderLine,
981 sal_Int16 eVertOrient ) const
982 {
983 return aFrmFmts[GetFrmFmtIdx(bBorderLine,eVertOrient)];
984 }
985
986
987
InitCtor(const HTMLTableOptions * pOptions)988 void HTMLTable::InitCtor( const HTMLTableOptions *pOptions )
989 {
990 pResizeDrawObjs = 0;
991 pDrawObjPrcWidths = 0;
992
993 pRows = new HTMLTableRows;
994 pColumns = new HTMLTableColumns;
995 nRows = 0;
996 nCurRow = 0; nCurCol = 0;
997
998 pBox1 = 0;
999 pBoxFmt = 0; pLineFmt = 0;
1000 pLineFrmFmtNoHeight = 0;
1001 pInhBGBrush = 0;
1002
1003 pPrevStNd = 0;
1004 pSwTable = 0;
1005
1006 bTopBorder = sal_False; bRightBorder = sal_False;
1007 bTopAlwd = sal_True; bRightAlwd = sal_True;
1008 bFillerTopBorder = sal_False; bFillerBottomBorder = sal_False;
1009 bInhLeftBorder = sal_False; bInhRightBorder = sal_False;
1010 bBordersSet = sal_False;
1011 bForceFrame = sal_False;
1012 nHeadlineRepeat = 0;
1013
1014 nLeftMargin = 0;
1015 nRightMargin = 0;
1016
1017 const Color& rBorderColor = pOptions->aBorderColor;
1018
1019 long nBorderOpt = (long)pOptions->nBorder;
1020 long nPWidth = nBorderOpt==USHRT_MAX ? NETSCAPE_DFLT_BORDER
1021 : nBorderOpt;
1022 long nPHeight = nBorderOpt==USHRT_MAX ? 0 : nBorderOpt;
1023 SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
1024
1025 // nBorder gibt die Breite der Umrandung an, wie sie in die
1026 // Breitenberechnung in Netscape einfliesst. Wenn pOption->nBorder
1027 // == USHRT_MAX, wurde keine BORDER-Option angegeben. Trotzdem fliesst
1028 // eine 1 Pixel breite Umrandung in die Breitenberechnung mit ein.
1029 nBorder = (sal_uInt16)nPWidth;
1030 if( nBorderOpt==USHRT_MAX )
1031 nPWidth = 0;
1032
1033 // HACK: ein Pixel-breite Linien sollen zur Haarlinie werden, wenn
1034 // wir mit doppelter Umrandung arbeiten
1035 if( pOptions->nCellSpacing!=0 && nBorderOpt==1 )
1036 {
1037 nPWidth = 1;
1038 nPHeight = 1;
1039 }
1040
1041 SvxCSS1Parser::SetBorderWidth( aTopBorderLine, (sal_uInt16)nPHeight,
1042 pOptions->nCellSpacing!=0, sal_True );
1043 aTopBorderLine.SetColor( rBorderColor );
1044 aBottomBorderLine = aTopBorderLine;
1045
1046 if( nPWidth == nPHeight )
1047 {
1048 aLeftBorderLine = aTopBorderLine;
1049 }
1050 else
1051 {
1052 SvxCSS1Parser::SetBorderWidth( aLeftBorderLine, (sal_uInt16)nPWidth,
1053 pOptions->nCellSpacing!=0, sal_True );
1054 aLeftBorderLine.SetColor( rBorderColor );
1055 }
1056 aRightBorderLine = aLeftBorderLine;
1057
1058 if( pOptions->nCellSpacing != 0 )
1059 {
1060 aBorderLine.SetOutWidth( DEF_DOUBLE_LINE7_OUT );
1061 aBorderLine.SetInWidth( DEF_DOUBLE_LINE7_IN );
1062 aBorderLine.SetDistance( DEF_DOUBLE_LINE7_DIST );
1063 }
1064 else
1065 {
1066 aBorderLine.SetOutWidth( DEF_LINE_WIDTH_1 );
1067 }
1068 aBorderLine.SetColor( rBorderColor );
1069
1070 if( nCellPadding )
1071 {
1072 if( nCellPadding==USHRT_MAX )
1073 nCellPadding = MIN_BORDER_DIST; // default
1074 else
1075 {
1076 nCellPadding = pParser->ToTwips( nCellPadding );
1077 if( nCellPadding<MIN_BORDER_DIST )
1078 nCellPadding = MIN_BORDER_DIST;
1079 }
1080 }
1081 if( nCellSpacing )
1082 {
1083 if( nCellSpacing==USHRT_MAX )
1084 nCellSpacing = NETSCAPE_DFLT_CELLSPACING;
1085 nCellSpacing = pParser->ToTwips( nCellSpacing );
1086 }
1087
1088 nPWidth = pOptions->nHSpace;
1089 nPHeight = pOptions->nVSpace;
1090 SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
1091 nHSpace = (sal_uInt16)nPWidth;
1092 nVSpace = (sal_uInt16)nPHeight;
1093
1094 bColSpec = sal_False;
1095
1096 pBGBrush = pParser->CreateBrushItem(
1097 pOptions->bBGColor ? &(pOptions->aBGColor) : 0,
1098 pOptions->aBGImage, aEmptyStr, aEmptyStr, aEmptyStr );
1099
1100 pContext = 0;
1101 pParentContents = 0;
1102
1103 aId = pOptions->aId;
1104 aClass = pOptions->aClass;
1105 aStyle = pOptions->aStyle;
1106 aDir = pOptions->aDir;
1107 }
1108
HTMLTable(SwHTMLParser * pPars,HTMLTable * pTopTab,sal_Bool bParHead,sal_Bool bHasParentSec,sal_Bool bTopTbl,sal_Bool bHasToFlw,const HTMLTableOptions * pOptions)1109 HTMLTable::HTMLTable( SwHTMLParser* pPars, HTMLTable *pTopTab,
1110 sal_Bool bParHead,
1111 sal_Bool bHasParentSec, sal_Bool bTopTbl, sal_Bool bHasToFlw,
1112 const HTMLTableOptions *pOptions ) :
1113 nCols( pOptions->nCols ),
1114 nFilledCols( 0 ),
1115 nCellPadding( pOptions->nCellPadding ),
1116 nCellSpacing( pOptions->nCellSpacing ),
1117 nBoxes( 1 ),
1118 pCaptionStartNode( 0 ),
1119 bTableAdjustOfTag( pTopTab ? sal_False : pOptions->bTableAdjust ),
1120 bIsParentHead( bParHead ),
1121 bHasParentSection( bHasParentSec ),
1122 bMakeTopSubTable( bTopTbl ),
1123 bHasToFly( bHasToFlw ),
1124 bFixedCols( pOptions->nCols>0 ),
1125 bPrcWidth( pOptions->bPrcWidth ),
1126 pParser( pPars ),
1127 pTopTable( pTopTab ? pTopTab : this ),
1128 pLayoutInfo( 0 ),
1129 nWidth( pOptions->nWidth ),
1130 nHeight( pTopTab ? 0 : pOptions->nHeight ),
1131 eTableAdjust( pOptions->eAdjust ),
1132 eVertOri( pOptions->eVertOri ),
1133 eFrame( pOptions->eFrame ),
1134 eRules( pOptions->eRules ),
1135 bTopCaption( sal_False ),
1136 bFirstCell( !pTopTab )
1137 {
1138 InitCtor( pOptions );
1139
1140 for( sal_uInt16 i=0; i<nCols; i++ )
1141 pColumns->Insert( new HTMLTableColumn, pColumns->Count() );
1142 }
1143
1144
~HTMLTable()1145 HTMLTable::~HTMLTable()
1146 {
1147 delete pResizeDrawObjs;
1148 delete pDrawObjPrcWidths;
1149
1150 delete pRows;
1151 delete pColumns;
1152 delete pBGBrush;
1153 delete pInhBGBrush;
1154
1155 delete pContext;
1156
1157 // pLayoutInfo wurde entweder bereits geloescht oder muss aber es
1158 // in den Besitz der SwTable uebergegangen.
1159 }
1160
CreateLayoutInfo()1161 SwHTMLTableLayout *HTMLTable::CreateLayoutInfo()
1162 {
1163 sal_uInt16 nW = bPrcWidth ? nWidth : pParser->ToTwips( nWidth );
1164
1165 sal_uInt16 nBorderWidth = GetBorderWidth( aBorderLine, sal_True );
1166 sal_uInt16 nLeftBorderWidth =
1167 ((*pColumns)[0])->bLeftBorder ? GetBorderWidth( aLeftBorderLine, sal_True ) : 0;
1168 sal_uInt16 nRightBorderWidth =
1169 bRightBorder ? GetBorderWidth( aRightBorderLine, sal_True ) : 0;
1170 sal_uInt16 nInhLeftBorderWidth = 0;
1171 sal_uInt16 nInhRightBorderWidth = 0;
1172
1173 pLayoutInfo = new SwHTMLTableLayout(
1174 pSwTable,
1175 nRows, nCols, bFixedCols, bColSpec,
1176 nW, bPrcWidth, nBorder, nCellPadding,
1177 nCellSpacing, eTableAdjust,
1178 nLeftMargin, nRightMargin,
1179 nBorderWidth, nLeftBorderWidth, nRightBorderWidth,
1180 nInhLeftBorderWidth, nInhRightBorderWidth );
1181
1182 sal_Bool bExportable = sal_True;
1183 sal_uInt16 i;
1184 for( i=0; i<nRows; i++ )
1185 {
1186 HTMLTableRow *pRow = (*pRows)[i];
1187 for( sal_uInt16 j=0; j<nCols; j++ )
1188 {
1189 SwHTMLTableLayoutCell *pLayoutCell =
1190 pRow->GetCell(j)->CreateLayoutInfo();
1191
1192 pLayoutInfo->SetCell( pLayoutCell, i, j );
1193
1194 if( bExportable )
1195 {
1196 SwHTMLTableLayoutCnts *pLayoutCnts =
1197 pLayoutCell->GetContents();
1198 bExportable = !pLayoutCnts ||
1199 ( pLayoutCnts->GetStartNode() &&
1200 !pLayoutCnts->GetNext() );
1201 }
1202 }
1203 }
1204
1205 pLayoutInfo->SetExportable( bExportable );
1206
1207 for( i=0; i<nCols; i++ )
1208 pLayoutInfo->SetColumn( ((*pColumns)[i])->CreateLayoutInfo(), i );
1209
1210 return pLayoutInfo;
1211 }
1212
SetCaption(const SwStartNode * pStNd,sal_Bool bTop)1213 inline void HTMLTable::SetCaption( const SwStartNode *pStNd, sal_Bool bTop )
1214 {
1215 pCaptionStartNode = pStNd;
1216 bTopCaption = bTop;
1217 }
1218
FixRowSpan(sal_uInt16 nRow,sal_uInt16 nCol,const HTMLTableCnts * pCnts)1219 void HTMLTable::FixRowSpan( sal_uInt16 nRow, sal_uInt16 nCol,
1220 const HTMLTableCnts *pCnts )
1221 {
1222 sal_uInt16 nRowSpan=1;
1223 HTMLTableCell *pCell;
1224 while( ( pCell=GetCell(nRow,nCol), pCell->GetContents()==pCnts ) )
1225 {
1226 pCell->SetRowSpan( nRowSpan );
1227 if( pLayoutInfo )
1228 pLayoutInfo->GetCell(nRow,nCol)->SetRowSpan( nRowSpan );
1229
1230 if( !nRow ) break;
1231 nRowSpan++; nRow--;
1232 }
1233 }
1234
ProtectRowSpan(sal_uInt16 nRow,sal_uInt16 nCol,sal_uInt16 nRowSpan)1235 void HTMLTable::ProtectRowSpan( sal_uInt16 nRow, sal_uInt16 nCol, sal_uInt16 nRowSpan )
1236 {
1237 for( sal_uInt16 i=0; i<nRowSpan; i++ )
1238 {
1239 GetCell(nRow+i,nCol)->SetProtected();
1240 if( pLayoutInfo )
1241 pLayoutInfo->GetCell(nRow+i,nCol)->SetProtected();
1242 }
1243 }
1244
1245
1246 // Suchen des SwStartNodes der letzten belegten Vorgaengerbox
GetPrevBoxStartNode(sal_uInt16 nRow,sal_uInt16 nCol) const1247 const SwStartNode* HTMLTable::GetPrevBoxStartNode( sal_uInt16 nRow, sal_uInt16 nCol ) const
1248 {
1249 const HTMLTableCnts *pPrevCnts = 0;
1250
1251 if( 0==nRow )
1252 {
1253 // immer die Vorgaenger-Zelle
1254 if( nCol>0 )
1255 pPrevCnts = GetCell( 0, nCol-1 )->GetContents();
1256 else
1257 return pPrevStNd;
1258 }
1259 else if( USHRT_MAX==nRow && USHRT_MAX==nCol )
1260 // der Contents der letzten Zelle
1261 pPrevCnts = GetCell( nRows-1, nCols-1 )->GetContents();
1262 else
1263 {
1264 sal_uInt16 i;
1265 HTMLTableRow *pPrevRow = (*pRows)[nRow-1];
1266
1267 // evtl. eine Zelle in der aktuellen Zeile
1268 i = nCol;
1269 while( i )
1270 {
1271 i--;
1272 if( 1 == pPrevRow->GetCell(i)->GetRowSpan() )
1273 {
1274 pPrevCnts = GetCell(nRow,i)->GetContents();
1275 break;
1276 }
1277 }
1278
1279 // sonst die letzte gefuellte Zelle der Zeile davor suchen
1280 if( !pPrevCnts )
1281 {
1282 i = nCols;
1283 while( !pPrevCnts && i )
1284 {
1285 i--;
1286 pPrevCnts = pPrevRow->GetCell(i)->GetContents();
1287 }
1288 }
1289 }
1290 ASSERT( pPrevCnts, "keine gefuellte Vorgaenger-Zelle gefunden" );
1291 if( !pPrevCnts )
1292 {
1293 pPrevCnts = GetCell(0,0)->GetContents();
1294 if( !pPrevCnts )
1295 return pPrevStNd;
1296 }
1297
1298 while( pPrevCnts->Next() )
1299 pPrevCnts = pPrevCnts->Next();
1300
1301 return ( pPrevCnts->GetStartNode() ? pPrevCnts->GetStartNode()
1302 : pPrevCnts->GetTable()->GetPrevBoxStartNode( USHRT_MAX, USHRT_MAX ) );
1303 }
1304
1305
IsBoxEmpty(const SwTableBox * pBox)1306 static sal_Bool IsBoxEmpty( const SwTableBox *pBox )
1307 {
1308 const SwStartNode *pSttNd = pBox->GetSttNd();
1309 if( pSttNd &&
1310 pSttNd->GetIndex() + 2 == pSttNd->EndOfSectionIndex() )
1311 {
1312 const SwCntntNode *pCNd =
1313 pSttNd->GetNodes()[pSttNd->GetIndex()+1]->GetCntntNode();
1314 if( pCNd && !pCNd->Len() )
1315 return sal_True;
1316 }
1317
1318 return sal_False;
1319 }
1320
GetTopCellSpace(sal_uInt16 nRow,sal_uInt16 nRowSpan,sal_Bool bSwBorders) const1321 sal_uInt16 HTMLTable::GetTopCellSpace( sal_uInt16 nRow, sal_uInt16 nRowSpan,
1322 sal_Bool bSwBorders ) const
1323 {
1324 sal_uInt16 nSpace = nCellPadding;
1325
1326 if( nRow == 0 )
1327 {
1328 nSpace += nBorder + nCellSpacing;
1329 if( bSwBorders )
1330 {
1331 sal_uInt16 nTopBorderWidth =
1332 GetBorderWidth( aTopBorderLine, sal_True );
1333 if( nSpace < nTopBorderWidth )
1334 nSpace = nTopBorderWidth;
1335 }
1336 }
1337 else if( bSwBorders && ((*pRows)[nRow+nRowSpan-1])->bBottomBorder &&
1338 nSpace < MIN_BORDER_DIST )
1339 {
1340 ASSERT( !nCellPadding, "GetTopCellSpace: CELLPADDING!=0" );
1341 // Wenn die Gegenueberliegende Seite umrandet ist muessen
1342 // wir zumindest den minimalen Abstand zum Inhalt
1343 // beruecksichtigen. (Koennte man zusaetzlich auch an
1344 // nCellPadding festmachen.)
1345 nSpace = MIN_BORDER_DIST;
1346 }
1347
1348 return nSpace;
1349 }
1350
GetBottomCellSpace(sal_uInt16 nRow,sal_uInt16 nRowSpan,sal_Bool bSwBorders) const1351 sal_uInt16 HTMLTable::GetBottomCellSpace( sal_uInt16 nRow, sal_uInt16 nRowSpan,
1352 sal_Bool bSwBorders ) const
1353 {
1354 sal_uInt16 nSpace = nCellSpacing + nCellPadding;
1355
1356 if( nRow+nRowSpan == nRows )
1357 {
1358 nSpace = nSpace + nBorder;
1359
1360 if( bSwBorders )
1361 {
1362 sal_uInt16 nBottomBorderWidth =
1363 GetBorderWidth( aBottomBorderLine, sal_True );
1364 if( nSpace < nBottomBorderWidth )
1365 nSpace = nBottomBorderWidth;
1366 }
1367 }
1368 else if( bSwBorders )
1369 {
1370 if( ((*pRows)[nRow+nRowSpan+1])->bBottomBorder )
1371 {
1372 sal_uInt16 nBorderWidth = GetBorderWidth( aBorderLine, sal_True );
1373 if( nSpace < nBorderWidth )
1374 nSpace = nBorderWidth;
1375 }
1376 else if( nRow==0 && bTopBorder && nSpace < MIN_BORDER_DIST )
1377 {
1378 ASSERT( GetBorderWidth( aTopBorderLine, sal_True ) > 0,
1379 "GetBottomCellSpace: |aTopLine| == 0" );
1380 ASSERT( !nCellPadding, "GetBottomCellSpace: CELLPADDING!=0" );
1381 // Wenn die Gegenueberliegende Seite umrandet ist muessen
1382 // wir zumindest den minimalen Abstand zum Inhalt
1383 // beruecksichtigen. (Koennte man zusaetzlich auch an
1384 // nCellPadding festmachen.)
1385 nSpace = MIN_BORDER_DIST;
1386 }
1387 }
1388
1389 return nSpace;
1390 }
1391
FixFrameFmt(SwTableBox * pBox,sal_uInt16 nRow,sal_uInt16 nCol,sal_uInt16 nRowSpan,sal_uInt16 nColSpan,sal_Bool bFirstPara,sal_Bool bLastPara) const1392 void HTMLTable::FixFrameFmt( SwTableBox *pBox,
1393 sal_uInt16 nRow, sal_uInt16 nCol,
1394 sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
1395 sal_Bool bFirstPara, sal_Bool bLastPara ) const
1396 {
1397 SwFrmFmt *pFrmFmt = 0; // frame::Frame-Format
1398 sal_Int16 eVOri = text::VertOrientation::NONE;
1399 const SvxBrushItem *pBGBrushItem = 0; // Hintergrund
1400 sal_Bool bTopLine = sal_False, bBottomLine = sal_False, bLastBottomLine = sal_False;
1401 sal_Bool bReUsable = sal_False; // Format nochmals verwendbar?
1402 sal_uInt16 nEmptyRows = 0;
1403 sal_Bool bHasNumFmt = sal_False;
1404 sal_Bool bHasValue = sal_False;
1405 sal_uInt32 nNumFmt = 0;
1406 double nValue = 0.0;
1407
1408 HTMLTableColumn *pColumn = (*pColumns)[nCol];
1409
1410 if( pBox->GetSttNd() )
1411 {
1412 // die Hintergrundfarbe/-grafik bestimmen
1413 const HTMLTableCell *pCell = GetCell( nRow, nCol );
1414 pBGBrushItem = pCell->GetBGBrush();
1415 if( !pBGBrushItem )
1416 {
1417 // Wenn die Zelle ueber mehrere Zeilen geht muss ein evtl.
1418 // an der Zeile gesetzter Hintergrund an die Zelle uebernommen
1419 // werden.
1420 #ifndef FIX56334
1421 // Wenn es sich um eine Tabelle in der Tabelle handelt und
1422 // die Zelle ueber die gesamte Hoehe der Tabelle geht muss
1423 // ebenfalls der Hintergrund der Zeile uebernommen werden, weil
1424 // die Line von der GC (zu Recht) wegoptimiert wird.
1425 if( nRowSpan > 1 || (this != pTopTable && nRowSpan==nRows) )
1426 #else
1427 if( nRowSpan > 1 )
1428 #endif
1429 {
1430 pBGBrushItem = ((*pRows)[nRow])->GetBGBrush();
1431 if( !pBGBrushItem && this != pTopTable )
1432 {
1433 pBGBrushItem = GetBGBrush();
1434 if( !pBGBrushItem )
1435 pBGBrushItem = GetInhBGBrush();
1436 }
1437 }
1438 }
1439
1440 bTopLine = 0==nRow && bTopBorder && bFirstPara;
1441 if( ((*pRows)[nRow+nRowSpan-1])->bBottomBorder && bLastPara )
1442 {
1443 nEmptyRows = ((*pRows)[nRow+nRowSpan-1])->GetEmptyRows();
1444 if( nRow+nRowSpan == nRows )
1445 bLastBottomLine = sal_True;
1446 else
1447 bBottomLine = sal_True;
1448 }
1449
1450 eVOri = pCell->GetVertOri();
1451 bHasNumFmt = pCell->GetNumFmt( nNumFmt );
1452 if( bHasNumFmt )
1453 bHasValue = pCell->GetValue( nValue );
1454
1455 if( nColSpan==1 && !bTopLine && !bLastBottomLine && !nEmptyRows &&
1456 !pBGBrushItem && !bHasNumFmt )
1457 {
1458 pFrmFmt = pColumn->GetFrmFmt( bBottomLine, eVOri );
1459 bReUsable = !pFrmFmt;
1460 }
1461 }
1462
1463 if( !pFrmFmt )
1464 {
1465 pFrmFmt = pBox->ClaimFrmFmt();
1466
1467 // die Breite der Box berechnen
1468 SwTwips nFrmWidth = (SwTwips)pLayoutInfo->GetColumn(nCol)
1469 ->GetRelColWidth();
1470 for( sal_uInt16 i=1; i<nColSpan; i++ )
1471 nFrmWidth += (SwTwips)pLayoutInfo->GetColumn(nCol+i)
1472 ->GetRelColWidth();
1473
1474 // die Umrandung nur an Edit-Boxen setzen (bei der oberen und unteren
1475 // Umrandung muss beruecks. werden, ob es sich um den ersten oder
1476 // letzten Absatz der Zelle handelt)
1477 if( pBox->GetSttNd() )
1478 {
1479 sal_Bool bSet = (nCellPadding > 0);
1480
1481 SvxBoxItem aBoxItem( RES_BOX );
1482 long nInnerFrmWidth = nFrmWidth;
1483
1484 if( bTopLine )
1485 {
1486 aBoxItem.SetLine( &aTopBorderLine, BOX_LINE_TOP );
1487 bSet = sal_True;
1488 }
1489 if( bLastBottomLine )
1490 {
1491 aBoxItem.SetLine( &aBottomBorderLine, BOX_LINE_BOTTOM );
1492 bSet = sal_True;
1493 }
1494 else if( bBottomLine )
1495 {
1496 if( nEmptyRows && !aBorderLine.GetInWidth() )
1497 {
1498 // Leere Zeilen koennen zur Zeit nur dann ueber
1499 // dicke Linien simuliert werden, wenn die Linie
1500 // einfach ist.
1501 SvxBorderLine aThickBorderLine( aBorderLine );
1502
1503 sal_uInt16 nBorderWidth = aBorderLine.GetOutWidth();
1504 nBorderWidth *= (nEmptyRows + 1);
1505 SvxCSS1Parser::SetBorderWidth( aThickBorderLine,
1506 nBorderWidth, sal_False );
1507 aBoxItem.SetLine( &aThickBorderLine, BOX_LINE_BOTTOM );
1508 }
1509 else
1510 {
1511 aBoxItem.SetLine( &aBorderLine, BOX_LINE_BOTTOM );
1512 }
1513 bSet = sal_True;
1514 }
1515 if( ((*pColumns)[nCol])->bLeftBorder )
1516 {
1517 const SvxBorderLine& rBorderLine =
1518 0==nCol ? aLeftBorderLine : aBorderLine;
1519 aBoxItem.SetLine( &rBorderLine, BOX_LINE_LEFT );
1520 nInnerFrmWidth -= GetBorderWidth( rBorderLine );
1521 bSet = sal_True;
1522 }
1523 if( nCol+nColSpan == nCols && bRightBorder )
1524 {
1525 aBoxItem.SetLine( &aRightBorderLine, BOX_LINE_RIGHT );
1526 nInnerFrmWidth -= GetBorderWidth( aRightBorderLine );
1527 bSet = sal_True;
1528 }
1529
1530 if( bSet )
1531 {
1532 // fix #30588#: BorderDist nicht mehr Bestandteil
1533 // einer Zelle mit fixer Breite
1534 sal_uInt16 nBDist = static_cast< sal_uInt16 >(
1535 (2*nCellPadding <= nInnerFrmWidth) ? nCellPadding
1536 : (nInnerFrmWidth / 2) );
1537 // wir setzen das Item nur, wenn es eine Umrandung gibt
1538 // oder eine sheet::Border-Distanz vorgegeben ist. Fehlt letztere,
1539 // dann gibt es eine Umrandung, und wir muessen die Distanz
1540 // setzen
1541 aBoxItem.SetDistance( nBDist ? nBDist : MIN_BORDER_DIST );
1542 pFrmFmt->SetFmtAttr( aBoxItem );
1543 }
1544 else
1545 pFrmFmt->ResetFmtAttr( RES_BOX );
1546
1547 if( pBGBrushItem )
1548 {
1549 pFrmFmt->SetFmtAttr( *pBGBrushItem );
1550 }
1551 else
1552 pFrmFmt->ResetFmtAttr( RES_BACKGROUND );
1553
1554 // fix #41003#: Format nur setzten, wenn es auch einen Value
1555 // gibt oder die Box leer ist.
1556 if( bHasNumFmt && (bHasValue || IsBoxEmpty(pBox)) )
1557 {
1558 sal_Bool bLock = pFrmFmt->GetDoc()->GetNumberFormatter()
1559 ->IsTextFormat( nNumFmt );
1560 SfxItemSet aItemSet( *pFrmFmt->GetAttrSet().GetPool(),
1561 RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
1562 SvxAdjust eAdjust = SVX_ADJUST_END;
1563 SwCntntNode *pCNd = 0;
1564 if( !bLock )
1565 {
1566 const SwStartNode *pSttNd = pBox->GetSttNd();
1567 pCNd = pSttNd->GetNodes()[pSttNd->GetIndex()+1]
1568 ->GetCntntNode();
1569 const SfxPoolItem *pItem;
1570 if( pCNd && pCNd->HasSwAttrSet() &&
1571 SFX_ITEM_SET==pCNd->GetpSwAttrSet()->GetItemState(
1572 RES_PARATR_ADJUST, sal_False, &pItem ) )
1573 {
1574 eAdjust = ((const SvxAdjustItem *)pItem)
1575 ->GetAdjust();
1576 }
1577 }
1578 aItemSet.Put( SwTblBoxNumFormat(nNumFmt) );
1579 if( bHasValue )
1580 aItemSet.Put( SwTblBoxValue(nValue) );
1581
1582 if( bLock )
1583 pFrmFmt->LockModify();
1584 pFrmFmt->SetFmtAttr( aItemSet );
1585 if( bLock )
1586 pFrmFmt->UnlockModify();
1587 else if( pCNd && SVX_ADJUST_END != eAdjust )
1588 {
1589 SvxAdjustItem aAdjItem( eAdjust, RES_PARATR_ADJUST );
1590 pCNd->SetAttr( aAdjItem );
1591 }
1592 }
1593 else
1594 pFrmFmt->ResetFmtAttr( RES_BOXATR_FORMAT );
1595
1596 ASSERT( eVOri != text::VertOrientation::TOP, "text::VertOrientation::TOP is not allowed!" );
1597 if( text::VertOrientation::NONE != eVOri )
1598 {
1599 pFrmFmt->SetFmtAttr( SwFmtVertOrient( 0, eVOri ) );
1600 }
1601 else
1602 pFrmFmt->ResetFmtAttr( RES_VERT_ORIENT );
1603
1604 if( bReUsable )
1605 pColumn->SetFrmFmt( pFrmFmt, bBottomLine, eVOri );
1606 }
1607 else
1608 {
1609 pFrmFmt->ResetFmtAttr( RES_BOX );
1610 pFrmFmt->ResetFmtAttr( RES_BACKGROUND );
1611 pFrmFmt->ResetFmtAttr( RES_VERT_ORIENT );
1612 pFrmFmt->ResetFmtAttr( RES_BOXATR_FORMAT );
1613 }
1614 }
1615 else
1616 {
1617 ASSERT( pBox->GetSttNd() ||
1618 SFX_ITEM_SET!=pFrmFmt->GetAttrSet().GetItemState(
1619 RES_VERT_ORIENT, sal_False ),
1620 "Box ohne Inhalt hat vertikale Ausrichtung" );
1621 pBox->ChgFrmFmt( (SwTableBoxFmt*)pFrmFmt );
1622 }
1623
1624 }
1625
FixFillerFrameFmt(SwTableBox * pBox,sal_Bool bRight) const1626 void HTMLTable::FixFillerFrameFmt( SwTableBox *pBox, sal_Bool bRight ) const
1627 {
1628 SwFrmFmt *pFrmFmt = pBox->ClaimFrmFmt();
1629
1630 if( bFillerTopBorder || bFillerBottomBorder ||
1631 (!bRight && bInhLeftBorder) || (bRight && bInhRightBorder) )
1632 {
1633 SvxBoxItem aBoxItem( RES_BOX );
1634 if( bFillerTopBorder )
1635 aBoxItem.SetLine( &aTopBorderLine, BOX_LINE_TOP );
1636 if( bFillerBottomBorder )
1637 aBoxItem.SetLine( &aBottomBorderLine, BOX_LINE_BOTTOM );
1638 if( !bRight && bInhLeftBorder )
1639 aBoxItem.SetLine( &aInhLeftBorderLine, BOX_LINE_LEFT );
1640 if( bRight && bInhRightBorder )
1641 aBoxItem.SetLine( &aInhRightBorderLine, BOX_LINE_RIGHT );
1642 aBoxItem.SetDistance( MIN_BORDER_DIST );
1643 pFrmFmt->SetFmtAttr( aBoxItem );
1644 }
1645 else
1646 {
1647 pFrmFmt->ResetFmtAttr( RES_BOX );
1648 }
1649
1650 if( GetInhBGBrush() )
1651 pFrmFmt->SetFmtAttr( *GetInhBGBrush() );
1652 else
1653 pFrmFmt->ResetFmtAttr( RES_BACKGROUND );
1654
1655 pFrmFmt->ResetFmtAttr( RES_VERT_ORIENT );
1656 pFrmFmt->ResetFmtAttr( RES_BOXATR_FORMAT );
1657 }
1658
NewTableBox(const SwStartNode * pStNd,SwTableLine * pUpper) const1659 SwTableBox *HTMLTable::NewTableBox( const SwStartNode *pStNd,
1660 SwTableLine *pUpper ) const
1661 {
1662 SwTableBox *pBox;
1663
1664 if( pTopTable->pBox1 &&
1665 pTopTable->pBox1->GetSttNd() == pStNd )
1666 {
1667 // wenn der StartNode dem StartNode der initial angelegten Box
1668 // entspricht nehmen wir diese Box
1669 pBox = pTopTable->pBox1;
1670 pBox->SetUpper( pUpper );
1671 pTopTable->pBox1 = 0;
1672 }
1673 else
1674 pBox = new SwTableBox( pBoxFmt, *pStNd, pUpper );
1675
1676 return pBox;
1677 }
1678
1679
ResetLineFrmFmtAttrs(SwFrmFmt * pFrmFmt)1680 static void ResetLineFrmFmtAttrs( SwFrmFmt *pFrmFmt )
1681 {
1682 pFrmFmt->ResetFmtAttr( RES_FRM_SIZE );
1683 pFrmFmt->ResetFmtAttr( RES_BACKGROUND );
1684 ASSERT( SFX_ITEM_SET!=pFrmFmt->GetAttrSet().GetItemState(
1685 RES_VERT_ORIENT, sal_False ),
1686 "Zeile hat vertikale Ausrichtung" );
1687 }
1688
1689 // !!! kann noch vereinfacht werden
MakeTableLine(SwTableBox * pUpper,sal_uInt16 nTopRow,sal_uInt16 nLeftCol,sal_uInt16 nBottomRow,sal_uInt16 nRightCol)1690 SwTableLine *HTMLTable::MakeTableLine( SwTableBox *pUpper,
1691 sal_uInt16 nTopRow, sal_uInt16 nLeftCol,
1692 sal_uInt16 nBottomRow, sal_uInt16 nRightCol )
1693 {
1694 SwTableLine *pLine;
1695 if( this==pTopTable && !pUpper && 0==nTopRow )
1696 pLine = (pSwTable->GetTabLines())[0];
1697 else
1698 pLine = new SwTableLine( pLineFrmFmtNoHeight ? pLineFrmFmtNoHeight
1699 : pLineFmt,
1700 0, pUpper );
1701
1702 HTMLTableRow *pTopRow = (*pRows)[nTopRow];
1703 sal_uInt16 nRowHeight = pTopRow->GetHeight();
1704 const SvxBrushItem *pBGBrushItem = 0;
1705 #ifndef FIX56334
1706 if( this == pTopTable || nTopRow>0 || nBottomRow<nRows )
1707 {
1708 // An der Line eine Farbe zu setzen macht keinen Sinn, wenn sie
1709 // die auesserste und gleichzeitig einzige Zeile einer Tabelle in
1710 // der Tabelle ist.
1711 #endif
1712 pBGBrushItem = pTopRow->GetBGBrush();
1713
1714 if( !pBGBrushItem && this != pTopTable )
1715 {
1716 // Ein an einer Tabellen in der Tabelle gesetzter Hintergrund
1717 // wird an den Rows gesetzt. Das gilt auch fuer den Hintergrund
1718 // der Zelle, in dem die Tabelle vorkommt.
1719 pBGBrushItem = GetBGBrush();
1720 if( !pBGBrushItem )
1721 pBGBrushItem = GetInhBGBrush();
1722 }
1723 #ifndef FIX56334
1724 }
1725 #endif
1726 if( nTopRow==nBottomRow-1 && (nRowHeight || pBGBrushItem) )
1727 {
1728 SwTableLineFmt *pFrmFmt = (SwTableLineFmt*)pLine->ClaimFrmFmt();
1729 ResetLineFrmFmtAttrs( pFrmFmt );
1730
1731 if( nRowHeight )
1732 {
1733 // Tabellenhoehe einstellen. Da es sich um eine
1734 // Mindesthoehe handelt, kann sie genauso wie in
1735 // Netscape berechnet werden, also ohne Beruecksichtigung
1736 // der tatsaechlichen Umrandungsbreite.
1737 nRowHeight += GetTopCellSpace( nTopRow, 1, sal_False ) +
1738 GetBottomCellSpace( nTopRow, 1, sal_False );
1739
1740 pFrmFmt->SetFmtAttr( SwFmtFrmSize( ATT_MIN_SIZE, 0, nRowHeight ) );
1741 }
1742
1743 if( pBGBrushItem )
1744 {
1745 pFrmFmt->SetFmtAttr( *pBGBrushItem );
1746 }
1747
1748 }
1749 else if( !pLineFrmFmtNoHeight )
1750 {
1751 // sonst muessen wir die Hoehe aus dem Attribut entfernen
1752 // und koennen uns das Format merken
1753 pLineFrmFmtNoHeight = (SwTableLineFmt*)pLine->ClaimFrmFmt();
1754
1755 ResetLineFrmFmtAttrs( pLineFrmFmtNoHeight );
1756 }
1757
1758
1759 SwTableBoxes& rBoxes = pLine->GetTabBoxes();
1760
1761 sal_uInt16 nStartCol = nLeftCol;
1762 while( nStartCol<nRightCol )
1763 {
1764 sal_uInt16 nCol = nStartCol;
1765 sal_uInt16 nSplitCol = nRightCol;
1766 sal_Bool bSplitted = sal_False;
1767 while( !bSplitted )
1768 {
1769 ASSERT( nCol < nRightCol, "Zu weit gelaufen" );
1770
1771 HTMLTableCell *pCell = GetCell(nTopRow,nCol);
1772 const sal_Bool bSplit = 1 == pCell->GetColSpan();
1773
1774 #ifdef DBG_UTIL
1775 if( nCol == nRightCol-1 )
1776 {
1777 ASSERT( bSplit, "Split-Flag falsch" );
1778 }
1779 #endif
1780 if( bSplit )
1781 {
1782 SwTableBox* pBox = 0;
1783 HTMLTableCell *pCell2 = GetCell( nTopRow, nStartCol );
1784 if( pCell2->GetColSpan() == (nCol+1-nStartCol) )
1785 {
1786 // Die HTML-Tabellen-Zellen bilden genau eine Box.
1787 // Dann muss hinter der Box gesplittet werden
1788 nSplitCol = nCol + 1;
1789
1790 long nBoxRowSpan = pCell2->GetRowSpan();
1791 if ( !pCell2->GetContents() || pCell2->IsCovered() )
1792 {
1793 if ( pCell2->IsCovered() )
1794 nBoxRowSpan = -1 * nBoxRowSpan;
1795
1796 const SwStartNode* pPrevStartNd =
1797 GetPrevBoxStartNode( nTopRow, nStartCol );
1798 HTMLTableCnts *pCnts = new HTMLTableCnts(
1799 pParser->InsertTableSection(pPrevStartNd) );
1800 SwHTMLTableLayoutCnts *pCntsLayoutInfo =
1801 pCnts->CreateLayoutInfo();
1802
1803 pCell2->SetContents( pCnts );
1804 SwHTMLTableLayoutCell *pCurrCell = pLayoutInfo->GetCell( nTopRow, nStartCol );
1805 pCurrCell->SetContents( pCntsLayoutInfo );
1806 if( nBoxRowSpan < 0 )
1807 pCurrCell->SetRowSpan( 0 );
1808
1809 // ggf. COLSPAN beachten
1810 for( sal_uInt16 j=nStartCol+1; j<nSplitCol; j++ )
1811 {
1812 GetCell(nTopRow,j)->SetContents( pCnts );
1813 pLayoutInfo->GetCell( nTopRow, j )
1814 ->SetContents( pCntsLayoutInfo );
1815 }
1816 }
1817
1818 pBox = MakeTableBox( pLine, pCell2->GetContents(),
1819 nTopRow, nStartCol,
1820 nBottomRow, nSplitCol );
1821
1822 if ( 1 != nBoxRowSpan )
1823 pBox->setRowSpan( nBoxRowSpan );
1824
1825 bSplitted = sal_True;
1826 }
1827
1828 ASSERT( pBox, "Colspan trouble" )
1829
1830 if( pBox )
1831 rBoxes.C40_INSERT( SwTableBox, pBox, rBoxes.Count() );
1832 }
1833 nCol++;
1834 }
1835 nStartCol = nSplitCol;
1836 }
1837
1838 return pLine;
1839 }
1840
MakeTableBox(SwTableLine * pUpper,HTMLTableCnts * pCnts,sal_uInt16 nTopRow,sal_uInt16 nLeftCol,sal_uInt16 nBottomRow,sal_uInt16 nRightCol)1841 SwTableBox *HTMLTable::MakeTableBox( SwTableLine *pUpper,
1842 HTMLTableCnts *pCnts,
1843 sal_uInt16 nTopRow, sal_uInt16 nLeftCol,
1844 sal_uInt16 nBottomRow, sal_uInt16 nRightCol )
1845 {
1846 SwTableBox *pBox;
1847 sal_uInt16 nColSpan = nRightCol - nLeftCol;
1848 sal_uInt16 nRowSpan = nBottomRow - nTopRow;
1849
1850 if( !pCnts->Next() )
1851 {
1852 // nur eine Inhalts-Section
1853 if( pCnts->GetStartNode() )
1854 {
1855 // und die ist keine Tabelle
1856 pBox = NewTableBox( pCnts->GetStartNode(), pUpper );
1857 pCnts->SetTableBox( pBox );
1858 }
1859 else
1860 {
1861 pCnts->GetTable()->InheritVertBorders( this, nLeftCol,
1862 nRightCol-nLeftCol );
1863 // und die ist eine Tabelle: dann bauen wir eine neue
1864 // Box und fuegen die Zeilen der Tabelle in die Zeilen
1865 // der Box ein
1866 pBox = new SwTableBox( pBoxFmt, 0, pUpper );
1867 sal_uInt16 nAbs, nRel;
1868 pLayoutInfo->GetAvail( nLeftCol, nColSpan, nAbs, nRel );
1869 sal_uInt16 nLSpace = pLayoutInfo->GetLeftCellSpace( nLeftCol, nColSpan );
1870 sal_uInt16 nRSpace = pLayoutInfo->GetRightCellSpace( nLeftCol, nColSpan );
1871 sal_uInt16 nInhSpace = pLayoutInfo->GetInhCellSpace( nLeftCol, nColSpan );
1872 pCnts->GetTable()->MakeTable( pBox, nAbs, nRel, nLSpace, nRSpace,
1873 nInhSpace );
1874 }
1875 }
1876 else
1877 {
1878 // mehrere Inhalts Sections: dann brauchen wir eine Box mit Zeilen
1879 pBox = new SwTableBox( pBoxFmt, 0, pUpper );
1880 SwTableLines& rLines = pBox->GetTabLines();
1881 sal_Bool bFirstPara = sal_True;
1882
1883 while( pCnts )
1884 {
1885 if( pCnts->GetStartNode() )
1886 {
1887 // normale Absaetze werden zu einer Box in einer Zeile
1888 SwTableLine *pLine =
1889 new SwTableLine( pLineFrmFmtNoHeight ? pLineFrmFmtNoHeight
1890 : pLineFmt, 0, pBox );
1891 if( !pLineFrmFmtNoHeight )
1892 {
1893 // Wenn es noch kein Line-Format ohne Hoehe gibt, koennen
1894 // wir uns dieses her als solches merken
1895 pLineFrmFmtNoHeight = (SwTableLineFmt*)pLine->ClaimFrmFmt();
1896
1897 ResetLineFrmFmtAttrs( pLineFrmFmtNoHeight );
1898 }
1899
1900 SwTableBox* pCntBox = NewTableBox( pCnts->GetStartNode(),
1901 pLine );
1902 pCnts->SetTableBox( pCntBox );
1903 FixFrameFmt( pCntBox, nTopRow, nLeftCol, nRowSpan, nColSpan,
1904 bFirstPara, 0==pCnts->Next() );
1905 pLine->GetTabBoxes().C40_INSERT( SwTableBox, pCntBox,
1906 pLine->GetTabBoxes().Count() );
1907
1908 rLines.C40_INSERT( SwTableLine, pLine, rLines.Count() );
1909 }
1910 else
1911 {
1912 pCnts->GetTable()->InheritVertBorders( this, nLeftCol,
1913 nRightCol-nLeftCol );
1914 // Tabellen werden direkt eingetragen
1915 sal_uInt16 nAbs, nRel;
1916 pLayoutInfo->GetAvail( nLeftCol, nColSpan, nAbs, nRel );
1917 sal_uInt16 nLSpace = pLayoutInfo->GetLeftCellSpace( nLeftCol,
1918 nColSpan );
1919 sal_uInt16 nRSpace = pLayoutInfo->GetRightCellSpace( nLeftCol,
1920 nColSpan );
1921 sal_uInt16 nInhSpace = pLayoutInfo->GetInhCellSpace( nLeftCol, nColSpan );
1922 pCnts->GetTable()->MakeTable( pBox, nAbs, nRel, nLSpace,
1923 nRSpace, nInhSpace );
1924 }
1925
1926 pCnts = pCnts->Next();
1927 bFirstPara = sal_False;
1928 }
1929 }
1930
1931 FixFrameFmt( pBox, nTopRow, nLeftCol, nRowSpan, nColSpan );
1932
1933 return pBox;
1934 }
1935
InheritBorders(const HTMLTable * pParent,sal_uInt16 nRow,sal_uInt16 nCol,sal_uInt16 nRowSpan,sal_uInt16,sal_Bool bFirstPara,sal_Bool bLastPara)1936 void HTMLTable::InheritBorders( const HTMLTable *pParent,
1937 sal_uInt16 nRow, sal_uInt16 nCol,
1938 sal_uInt16 nRowSpan, sal_uInt16 /*nColSpan*/,
1939 sal_Bool bFirstPara, sal_Bool bLastPara )
1940 {
1941 ASSERT( nRows>0 && nCols>0 && nCurRow==nRows,
1942 "Wurde CloseTable nicht aufgerufen?" );
1943
1944 // Die Child-Tabelle muss einen Rahmen bekommen, wenn die umgebende
1945 // Zelle einen Rand an der betreffenden Seite besitzt.
1946 // Der obere bzw. untere Rand wird nur gesetzt, wenn die Tabelle
1947 // als erster bzw. letzter Absatz in der Zelle vorkommt. Ansonsten
1948 // Fuer den linken/rechten Rand kann noch nicht entschieden werden,
1949 // ob eine Umrandung der Tabelle noetig/moeglich ist, weil das davon
1950 // abhaengt, ob "Filler"-Zellen eingefuegt werden. Hier werden deshalb
1951 // erstmal nur Informationen gesammelt
1952 //
1953 if( 0==nRow && pParent->bTopBorder && bFirstPara )
1954 {
1955 bTopBorder = sal_True;
1956 bFillerTopBorder = sal_True; // auch Filler bekommt eine Umrandung
1957 aTopBorderLine = pParent->aTopBorderLine;
1958 }
1959 if( ((*pParent->pRows)[nRow+nRowSpan-1])->bBottomBorder && bLastPara )
1960 {
1961 ((*pRows)[nRows-1])->bBottomBorder = sal_True;
1962 bFillerBottomBorder = sal_True; // auch Filler bekommt eine Umrandung
1963 aBottomBorderLine =
1964 nRow+nRowSpan==pParent->nRows ? pParent->aBottomBorderLine
1965 : pParent->aBorderLine;
1966 }
1967
1968
1969 // Die Child Tabelle darf keinen oberen oder linken Rahmen bekommen,
1970 // wenn der bereits durch die umgebende Tabelle gesetzt ist.
1971 // Sie darf jedoch immer einen oberen Rand bekommen, wenn die Tabelle
1972 // nicht der erste Absatz in der Zelle ist.
1973 bTopAlwd = ( !bFirstPara || (pParent->bTopAlwd &&
1974 (0==nRow || !((*pParent->pRows)[nRow-1])->bBottomBorder)) );
1975
1976 // die Child-Tabelle muss die Farbe der Zelle erben, in der sie
1977 // vorkommt, wenn sie keine eigene besitzt
1978 const SvxBrushItem *pInhBG = pParent->GetCell(nRow,nCol)->GetBGBrush();
1979 if( !pInhBG && pParent != pTopTable &&
1980 pParent->GetCell(nRow,nCol)->GetRowSpan() == pParent->nRows )
1981 {
1982 // die ganze umgebende Tabelle ist eine Tabelle in der Tabelle
1983 // und besteht nur aus einer Line, die bei der GC (zu Recht)
1984 // wegoptimiert wird. Deshalb muss der Hintergrund der Line in
1985 // diese Tabelle uebernommen werden.
1986 pInhBG = ((*pParent->pRows)[nRow])->GetBGBrush();
1987 if( !pInhBG )
1988 pInhBG = pParent->GetBGBrush();
1989 if( !pInhBG )
1990 pInhBG = pParent->GetInhBGBrush();
1991 }
1992 if( pInhBG )
1993 pInhBGBrush = new SvxBrushItem( *pInhBG );
1994 }
1995
InheritVertBorders(const HTMLTable * pParent,sal_uInt16 nCol,sal_uInt16 nColSpan)1996 void HTMLTable::InheritVertBorders( const HTMLTable *pParent,
1997 sal_uInt16 nCol, sal_uInt16 nColSpan )
1998 {
1999 sal_uInt16 nInhLeftBorderWidth = 0;
2000 sal_uInt16 nInhRightBorderWidth = 0;
2001
2002 if( nCol+nColSpan==pParent->nCols && pParent->bRightBorder )
2003 {
2004 bInhRightBorder = sal_True; // erstmal nur merken
2005 aInhRightBorderLine = pParent->aRightBorderLine;
2006 nInhRightBorderWidth =
2007 GetBorderWidth( aInhRightBorderLine, sal_True ) + MIN_BORDER_DIST;
2008 }
2009
2010 if( ((*pParent->pColumns)[nCol])->bLeftBorder )
2011 {
2012 bInhLeftBorder = sal_True; // erstmal nur merken
2013 aInhLeftBorderLine = 0==nCol ? pParent->aLeftBorderLine
2014 : pParent->aBorderLine;
2015 nInhLeftBorderWidth =
2016 GetBorderWidth( aInhLeftBorderLine, sal_True ) + MIN_BORDER_DIST;
2017 }
2018
2019 if( !bInhLeftBorder && (bFillerTopBorder || bFillerBottomBorder) )
2020 nInhLeftBorderWidth = 2 * MIN_BORDER_DIST;
2021 if( !bInhRightBorder && (bFillerTopBorder || bFillerBottomBorder) )
2022 nInhRightBorderWidth = 2 * MIN_BORDER_DIST;
2023 pLayoutInfo->SetInhBorderWidths( nInhLeftBorderWidth,
2024 nInhRightBorderWidth );
2025
2026 bRightAlwd = ( pParent->bRightAlwd &&
2027 (nCol+nColSpan==pParent->nCols ||
2028 !((*pParent->pColumns)[nCol+nColSpan])->bLeftBorder) );
2029 }
2030
SetBorders()2031 void HTMLTable::SetBorders()
2032 {
2033 sal_uInt16 i;
2034 for( i=1; i<nCols; i++ )
2035 if( HTML_TR_ALL==eRules || HTML_TR_COLS==eRules ||
2036 ((HTML_TR_ROWS==eRules || HTML_TR_GROUPS==eRules) &&
2037 ((*pColumns)[i-1])->IsEndOfGroup()) )
2038 ((*pColumns)[i])->bLeftBorder = sal_True;
2039
2040 for( i=0; i<nRows-1; i++ )
2041 if( HTML_TR_ALL==eRules || HTML_TR_ROWS==eRules ||
2042 ((HTML_TR_COLS==eRules || HTML_TR_GROUPS==eRules) &&
2043 ((*pRows)[i])->IsEndOfGroup()) )
2044 ((*pRows)[i])->bBottomBorder = sal_True;
2045
2046 if( bTopAlwd && (HTML_TF_ABOVE==eFrame || HTML_TF_HSIDES==eFrame ||
2047 HTML_TF_BOX==eFrame) )
2048 bTopBorder = sal_True;
2049 if( HTML_TF_BELOW==eFrame || HTML_TF_HSIDES==eFrame ||
2050 HTML_TF_BOX==eFrame )
2051 ((*pRows)[nRows-1])->bBottomBorder = sal_True;
2052 if( /*bRightAlwd &&*/ (HTML_TF_RHS==eFrame || HTML_TF_VSIDES==eFrame ||
2053 HTML_TF_BOX==eFrame) )
2054 bRightBorder = sal_True;
2055 if( HTML_TF_LHS==eFrame || HTML_TF_VSIDES==eFrame || HTML_TF_BOX==eFrame )
2056 ((*pColumns)[0])->bLeftBorder = sal_True;
2057
2058 for( i=0; i<nRows; i++ )
2059 {
2060 HTMLTableRow *pRow = (*pRows)[i];
2061 for( sal_uInt16 j=0; j<nCols; j++ )
2062 {
2063 HTMLTableCell *pCell = pRow->GetCell(j);
2064 if( pCell->GetContents() )
2065 {
2066 HTMLTableCnts *pCnts = pCell->GetContents();
2067 sal_Bool bFirstPara = sal_True;
2068 while( pCnts )
2069 {
2070 HTMLTable *pTable = pCnts->GetTable();
2071 if( pTable && !pTable->BordersSet() )
2072 {
2073 pTable->InheritBorders( this, i, j,
2074 pCell->GetRowSpan(),
2075 pCell->GetColSpan(),
2076 bFirstPara,
2077 0==pCnts->Next() );
2078 pTable->SetBorders();
2079 }
2080 bFirstPara = sal_False;
2081 pCnts = pCnts->Next();
2082 }
2083 }
2084 }
2085 }
2086
2087 bBordersSet = sal_True;
2088 }
2089
GetBorderWidth(const SvxBorderLine & rBLine,sal_Bool bWithDistance) const2090 sal_uInt16 HTMLTable::GetBorderWidth( const SvxBorderLine& rBLine,
2091 sal_Bool bWithDistance ) const
2092 {
2093 sal_uInt16 nBorderWidth = rBLine.GetOutWidth() + rBLine.GetInWidth() +
2094 rBLine.GetDistance();
2095 if( bWithDistance )
2096 {
2097 if( nCellPadding )
2098 nBorderWidth = nBorderWidth + nCellPadding;
2099 else if( nBorderWidth )
2100 nBorderWidth = nBorderWidth + MIN_BORDER_DIST;
2101 }
2102
2103 return nBorderWidth;
2104 }
2105
GetCell(sal_uInt16 nRow,sal_uInt16 nCell) const2106 inline HTMLTableCell *HTMLTable::GetCell( sal_uInt16 nRow,
2107 sal_uInt16 nCell ) const
2108 {
2109 ASSERT( nRow<pRows->Count(),
2110 "ungueltiger Zeilen-Index in HTML-Tabelle" );
2111 return ((*pRows)[nRow])->GetCell( nCell );
2112 }
2113
2114
2115
GetInheritedAdjust() const2116 SvxAdjust HTMLTable::GetInheritedAdjust() const
2117 {
2118 SvxAdjust eAdjust = (nCurCol<nCols ? ((*pColumns)[nCurCol])->GetAdjust()
2119 : SVX_ADJUST_END );
2120 if( SVX_ADJUST_END==eAdjust )
2121 eAdjust = ((*pRows)[nCurRow])->GetAdjust();
2122
2123 return eAdjust;
2124 }
2125
GetInheritedVertOri() const2126 sal_Int16 HTMLTable::GetInheritedVertOri() const
2127 {
2128 // text::VertOrientation::TOP ist der default!
2129 sal_Int16 eVOri = ((*pRows)[nCurRow])->GetVertOri();
2130 if( text::VertOrientation::TOP==eVOri && nCurCol<nCols )
2131 eVOri = ((*pColumns)[nCurCol])->GetVertOri();
2132 if( text::VertOrientation::TOP==eVOri )
2133 eVOri = eVertOri;
2134
2135 ASSERT( eVertOri != text::VertOrientation::TOP, "text::VertOrientation::TOP is not allowed!" );
2136 return eVOri;
2137 }
2138
InsertCell(HTMLTableCnts * pCnts,sal_uInt16 nRowSpan,sal_uInt16 nColSpan,sal_uInt16 nCellWidth,sal_Bool bRelWidth,sal_uInt16 nCellHeight,sal_Int16 eVertOrient,SvxBrushItem * pBGBrushItem,sal_Bool bHasNumFmt,sal_uInt32 nNumFmt,sal_Bool bHasValue,double nValue,sal_Bool bNoWrap)2139 void HTMLTable::InsertCell( HTMLTableCnts *pCnts,
2140 sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
2141 sal_uInt16 nCellWidth, sal_Bool bRelWidth, sal_uInt16 nCellHeight,
2142 sal_Int16 eVertOrient, SvxBrushItem *pBGBrushItem,
2143 sal_Bool bHasNumFmt, sal_uInt32 nNumFmt,
2144 sal_Bool bHasValue, double nValue, sal_Bool bNoWrap )
2145 {
2146 if( !nRowSpan || (sal_uInt32)nCurRow + nRowSpan > USHRT_MAX )
2147 nRowSpan = 1;
2148
2149 if( !nColSpan || (sal_uInt32)nCurCol + nColSpan > USHRT_MAX )
2150 nColSpan = 1;
2151
2152 sal_uInt16 nColsReq = nCurCol + nColSpan; // benoetigte Spalten
2153 sal_uInt16 nRowsReq = nCurRow + nRowSpan; // benoetigte Zeilen
2154 sal_uInt16 i, j;
2155
2156 // falls wir mehr Spalten benoetigen als wir zur Zeit haben,
2157 // muessen wir in allen Zeilen noch Zellen hinzufuegen
2158 if( nCols < nColsReq )
2159 {
2160 for( i=nCols; i<nColsReq; i++ )
2161 pColumns->Insert( new HTMLTableColumn, pColumns->Count() );
2162 for( i=0; i<nRows; i++ )
2163 ((*pRows)[i])->Expand( nColsReq, i<nCurRow );
2164 nCols = nColsReq;
2165 ASSERT( pColumns->Count()==nCols,
2166 "Anzahl der Spalten nach Expandieren stimmt nicht" );
2167 }
2168 if( nColsReq > nFilledCols )
2169 nFilledCols = nColsReq;
2170
2171 // falls wir mehr Zeilen benoetigen als wir zur Zeit haben,
2172 // muessen wir noch neue Zeilen hinzufuegen
2173 if( nRows < nRowsReq )
2174 {
2175 for( i=nRows; i<nRowsReq; i++ )
2176 pRows->Insert( new HTMLTableRow(nCols), pRows->Count() );
2177 nRows = nRowsReq;
2178 ASSERT( nRows==pRows->Count(), "Zeilenzahl in Insert stimmt nicht" );
2179 }
2180
2181 // Testen, ob eine Ueberschneidung vorliegt und diese
2182 // gegebenenfalls beseitigen
2183 sal_uInt16 nSpanedCols = 0;
2184 if( nCurRow>0 )
2185 {
2186 HTMLTableRow *pCurRow = (*pRows)[nCurRow];
2187 for( i=nCurCol; i<nColsReq; i++ )
2188 {
2189 HTMLTableCell *pCell = pCurRow->GetCell(i);
2190 if( pCell->GetContents() )
2191 {
2192 // Der Inhalt reicht von einer weiter oben stehenden Zelle
2193 // hier herein. Inhalt und Farbe der Zelle sind deshalb in
2194 // jedem Fall noch dort verankert und koennen deshalb
2195 // ueberschrieben werden bzw. von ProtectRowSpan geloescht
2196 // (Inhalt) oder kopiert (Farbe) werden.
2197 nSpanedCols = i + pCell->GetColSpan();
2198 FixRowSpan( nCurRow-1, i, pCell->GetContents() );
2199 if( pCell->GetRowSpan() > nRowSpan )
2200 ProtectRowSpan( nRowsReq, i,
2201 pCell->GetRowSpan()-nRowSpan );
2202 }
2203 }
2204 for( i=nColsReq; i<nSpanedCols; i++ )
2205 {
2206 // Auch diese Inhalte sind in jedem Fall nicht in der Zeile
2207 // darueber verankert.
2208 HTMLTableCell *pCell = pCurRow->GetCell(i);
2209 FixRowSpan( nCurRow-1, i, pCell->GetContents() );
2210 ProtectRowSpan( nCurRow, i, pCell->GetRowSpan() );
2211 }
2212 }
2213
2214 // Fill the cells
2215 for( i=nColSpan; i>0; i-- )
2216 {
2217 for( j=nRowSpan; j>0; j-- )
2218 {
2219 const bool bCovered = i != nColSpan || j != nRowSpan;
2220 GetCell( nRowsReq-j, nColsReq-i )
2221 ->Set( pCnts, j, i, eVertOrient, pBGBrushItem,
2222 bHasNumFmt, nNumFmt, bHasValue, nValue, bNoWrap, bCovered );
2223 }
2224 }
2225
2226 Size aTwipSz( bRelWidth ? 0 : nCellWidth, nCellHeight );
2227 if( (aTwipSz.Width() || aTwipSz.Height()) && Application::GetDefaultDevice() )
2228 {
2229 aTwipSz = Application::GetDefaultDevice()
2230 ->PixelToLogic( aTwipSz, MapMode( MAP_TWIP ) );
2231 }
2232
2233 // die Breite nur in die erste Zelle setzen!
2234 if( nCellWidth )
2235 {
2236 sal_uInt16 nTmp = bRelWidth ? nCellWidth : (sal_uInt16)aTwipSz.Width();
2237 GetCell( nCurRow, nCurCol )->SetWidth( nTmp, bRelWidth );
2238 }
2239
2240 // Ausserdem noch die Hoehe merken
2241 if( nCellHeight && 1==nRowSpan )
2242 {
2243 if( nCellHeight < MINLAY )
2244 nCellHeight = MINLAY;
2245 ((*pRows)[nCurRow])->SetHeight( (sal_uInt16)aTwipSz.Height() );
2246 }
2247
2248 // den Spaltenzaehler hinter die neuen Zellen setzen
2249 nCurCol = nColsReq;
2250 if( nSpanedCols > nCurCol )
2251 nCurCol = nSpanedCols;
2252
2253 // und die naechste freie Zelle suchen
2254 while( nCurCol<nCols && GetCell(nCurRow,nCurCol)->IsUsed() )
2255 nCurCol++;
2256 }
2257
CloseSection(sal_Bool bHead)2258 inline void HTMLTable::CloseSection( sal_Bool bHead )
2259 {
2260 // die vorhergehende Section beenden, falls es schon eine Zeile gibt
2261 ASSERT( nCurRow<=nRows, "ungueltige aktuelle Zeile" );
2262 if( nCurRow>0 && nCurRow<=nRows )
2263 ((*pRows)[nCurRow-1])->SetEndOfGroup();
2264 if( bHead /*&& nCurRow==1*/ )
2265 // bHeadlineRepeat = sal_True;
2266 nHeadlineRepeat = nCurRow;
2267 }
2268
OpenRow(SvxAdjust eAdjust,sal_Int16 eVertOrient,SvxBrushItem * pBGBrushItem)2269 void HTMLTable::OpenRow( SvxAdjust eAdjust, sal_Int16 eVertOrient,
2270 SvxBrushItem *pBGBrushItem )
2271 {
2272 sal_uInt16 nRowsReq = nCurRow+1; // Anzahl benoetigter Zeilen;
2273
2274 // die naechste Zeile anlegen, falls sie nicht schon da ist
2275 if( nRows<nRowsReq )
2276 {
2277 for( sal_uInt16 i=nRows; i<nRowsReq; i++ )
2278 pRows->Insert( new HTMLTableRow(nCols), pRows->Count() );
2279 nRows = nRowsReq;
2280 ASSERT( nRows==pRows->Count(),
2281 "Zeilenzahl in OpenRow stimmt nicht" );
2282 }
2283
2284 HTMLTableRow *pCurRow = ((*pRows)[nCurRow]);
2285 pCurRow->SetAdjust( eAdjust );
2286 pCurRow->SetVertOri( eVertOrient );
2287 if( pBGBrushItem )
2288 ((*pRows)[nCurRow])->SetBGBrush( pBGBrushItem );
2289
2290 // den Spaltenzaehler wieder an den Anfang setzen
2291 nCurCol=0;
2292
2293 // und die naechste freie Zelle suchen
2294 while( nCurCol<nCols && GetCell(nCurRow,nCurCol)->IsUsed() )
2295 nCurCol++;
2296 }
2297
CloseRow(sal_Bool bEmpty)2298 void HTMLTable::CloseRow( sal_Bool bEmpty )
2299 {
2300 ASSERT( nCurRow<nRows, "aktuelle Zeile hinter dem Tabellenende" );
2301
2302 // leere Zellen bekommen einfach einen etwas dickeren unteren Rand!
2303 if( bEmpty )
2304 {
2305 if( nCurRow > 0 )
2306 ((*pRows)[nCurRow-1])->IncEmptyRows();
2307 return;
2308 }
2309
2310 HTMLTableRow *pRow = (*pRows)[nCurRow];
2311
2312 // den COLSPAN aller leeren Zellen am Zeilenende so anpassen, dass
2313 // eine Zelle daraus wird. Das kann man hier machen (und auf keinen
2314 // Fall frueher), weil jetzt keine Zellen mehr in die Zeile eingefuegt
2315 // werden.
2316 sal_uInt16 i=nCols;
2317 while( i )
2318 {
2319 HTMLTableCell *pCell = pRow->GetCell(--i);
2320 if( !pCell->GetContents() )
2321 {
2322 sal_uInt16 nColSpan = nCols-i;
2323 if( nColSpan > 1 )
2324 pCell->SetColSpan( nColSpan );
2325 }
2326 else
2327 break;
2328 }
2329
2330
2331 nCurRow++;
2332 }
2333
CloseColGroup(sal_uInt16 nSpan,sal_uInt16 _nWidth,sal_Bool bRelWidth,SvxAdjust eAdjust,sal_Int16 eVertOrient)2334 inline void HTMLTable::CloseColGroup( sal_uInt16 nSpan, sal_uInt16 _nWidth,
2335 sal_Bool bRelWidth, SvxAdjust eAdjust,
2336 sal_Int16 eVertOrient )
2337 {
2338 if( nSpan )
2339 InsertCol( nSpan, _nWidth, bRelWidth, eAdjust, eVertOrient );
2340
2341 ASSERT( nCurCol<=nCols, "ungueltige Spalte" );
2342 if( nCurCol>0 && nCurCol<=nCols )
2343 ((*pColumns)[nCurCol-1])->SetEndOfGroup();
2344 }
2345
InsertCol(sal_uInt16 nSpan,sal_uInt16 nColWidth,sal_Bool bRelWidth,SvxAdjust eAdjust,sal_Int16 eVertOrient)2346 void HTMLTable::InsertCol( sal_uInt16 nSpan, sal_uInt16 nColWidth, sal_Bool bRelWidth,
2347 SvxAdjust eAdjust, sal_Int16 eVertOrient )
2348 {
2349 // --> OD, MIB 2004-11-08 #i35143# - no columns, if rows already exist.
2350 if ( nRows > 0 )
2351 return;
2352 // <--
2353
2354 sal_uInt16 i;
2355
2356 if( !nSpan )
2357 nSpan = 1;
2358
2359 sal_uInt16 nColsReq = nCurCol + nSpan; // benoetigte Spalten
2360
2361 if( nCols < nColsReq )
2362 {
2363 for( i=nCols; i<nColsReq; i++ )
2364 pColumns->Insert( new HTMLTableColumn, pColumns->Count() );
2365 nCols = nColsReq;
2366 }
2367
2368 Size aTwipSz( bRelWidth ? 0 : nColWidth, 0 );
2369 if( aTwipSz.Width() && Application::GetDefaultDevice() )
2370 {
2371 aTwipSz = Application::GetDefaultDevice()
2372 ->PixelToLogic( aTwipSz, MapMode( MAP_TWIP ) );
2373 }
2374
2375 for( i=nCurCol; i<nColsReq; i++ )
2376 {
2377 HTMLTableColumn *pCol = (*pColumns)[i];
2378 sal_uInt16 nTmp = bRelWidth ? nColWidth : (sal_uInt16)aTwipSz.Width();
2379 pCol->SetWidth( nTmp, bRelWidth );
2380 pCol->SetAdjust( eAdjust );
2381 pCol->SetVertOri( eVertOrient );
2382 }
2383
2384 bColSpec = sal_True;
2385
2386 nCurCol = nColsReq;
2387 }
2388
2389
CloseTable()2390 void HTMLTable::CloseTable()
2391 {
2392 sal_uInt16 i;
2393
2394 // Die Anzahl der Tabellenzeilen richtet sich nur nach den
2395 // <TR>-Elementen (d.h. nach nCurRow). Durch ROWSPAN aufgespannte
2396 // Zeilen hinter Zeile nCurRow muessen wir deshalb loeschen
2397 // und vor allem aber den ROWSPAN in den darueberliegenden Zeilen
2398 // anpassen.
2399 if( nRows>nCurRow )
2400 {
2401 HTMLTableRow *pPrevRow = (*pRows)[nCurRow-1];
2402 HTMLTableCell *pCell;
2403 for( i=0; i<nCols; i++ )
2404 if( ( pCell=pPrevRow->GetCell(i), pCell->GetRowSpan() > 1 ) )
2405 {
2406 FixRowSpan( nCurRow-1, i, pCell->GetContents() );
2407 ProtectRowSpan( nCurRow, i, (*pRows)[nCurRow]->GetCell(i)->GetRowSpan() );
2408 }
2409 for( i=nRows-1; i>=nCurRow; i-- )
2410 pRows->DeleteAndDestroy(i);
2411 nRows = nCurRow;
2412 }
2413
2414 // falls die Tabelle keine Spalte hat, muessen wir eine hinzufuegen
2415 if( 0==nCols )
2416 {
2417 pColumns->Insert( new HTMLTableColumn, pColumns->Count() );
2418 for( i=0; i<nRows; i++ )
2419 ((*pRows)[i])->Expand(1);
2420 nCols = 1;
2421 nFilledCols = 1;
2422 }
2423
2424 // falls die Tabelle keine Zeile hat, muessen wir eine hinzufuegen
2425 if( 0==nRows )
2426 {
2427 pRows->Insert( new HTMLTableRow(nCols), pRows->Count() );
2428 nRows = 1;
2429 nCurRow = 1;
2430 }
2431
2432 if( nFilledCols < nCols )
2433 {
2434 pColumns->DeleteAndDestroy( nFilledCols, nCols-nFilledCols );
2435 for( i=0; i<nRows; i++ )
2436 ((*pRows)[i])->Shrink( nFilledCols );
2437 nCols = nFilledCols;
2438 }
2439 }
2440
_MakeTable(SwTableBox * pBox)2441 void HTMLTable::_MakeTable( SwTableBox *pBox )
2442 {
2443 SwTableLines& rLines = (pBox ? pBox->GetTabLines()
2444 : ((SwTable *)pSwTable)->GetTabLines() );
2445
2446 // jetzt geht's richtig los ...
2447
2448 for( sal_uInt16 i=0; i<nRows; i++ )
2449 {
2450 SwTableLine *pLine = MakeTableLine( pBox, i, 0, i+1, nCols );
2451 if( pBox || i > 0 )
2452 rLines.C40_INSERT( SwTableLine, pLine, rLines.Count() );
2453 }
2454 }
2455
2456 /* Wie werden Tabellen ausgerichtet?
2457
2458 erste Zeile: ohne Absatz-Einzuege
2459 zweite Zeile: mit Absatz-Einzuegen
2460
2461 ALIGN= LEFT RIGHT CENTER -
2462 -------------------------------------------------------------------------
2463 xxx bei Tabellen mit WIDTH=nn% ist die Prozent-Angabe von Bedeutung:
2464 xxx nn = 100 text::HoriOrientation::FULL text::HoriOrientation::FULL text::HoriOrientation::FULL text::HoriOrientation::FULL %
2465 xxx text::HoriOrientation::NONE text::HoriOrientation::NONE text::HoriOrientation::NONE % text::HoriOrientation::NONE %
2466 xxx nn < 100 Rahmen F Rahmen F text::HoriOrientation::CENTER % text::HoriOrientation::LEFT %
2467 xxx Rahmen F Rahmen F text::HoriOrientation::CENTER % text::HoriOrientation::NONE %
2468
2469 bei Tabellen mit WIDTH=nn% ist die Prozent-Angabe von Bedeutung:
2470 nn = 100 text::HoriOrientation::LEFT text::HoriOrientation::RIGHT text::HoriOrientation::CENTER % text::HoriOrientation::LEFT %
2471 text::HoriOrientation::LEFT_AND text::HoriOrientation::RIGHT text::HoriOrientation::CENTER % text::HoriOrientation::LEFT_AND %
2472 nn < 100 Rahmen F Rahmen F text::HoriOrientation::CENTER % text::HoriOrientation::LEFT %
2473 Rahmen F Rahmen F text::HoriOrientation::CENTER % text::HoriOrientation::NONE %
2474
2475 sonst die berechnete Breite w
2476 w = avail* text::HoriOrientation::LEFT text::HoriOrientation::RIGHT text::HoriOrientation::CENTER text::HoriOrientation::LEFT
2477 HORI_LEDT_AND text::HoriOrientation::RIGHT text::HoriOrientation::CENTER text::HoriOrientation::LEFT_AND
2478 w < avail Rahmen L Rahmen L text::HoriOrientation::CENTER text::HoriOrientation::LEFT
2479 Rahmen L Rahmen L text::HoriOrientation::CENTER text::HoriOrientation::NONE
2480
2481 xxx *) wenn fuer die Tabelle keine Groesse angegeben wurde, wird immer
2482 xxx text::HoriOrientation::FULL genommen
2483
2484 */
2485
MakeTable(SwTableBox * pBox,sal_uInt16 nAbsAvail,sal_uInt16 nRelAvail,sal_uInt16 nAbsLeftSpace,sal_uInt16 nAbsRightSpace,sal_uInt16 nInhAbsSpace)2486 void HTMLTable::MakeTable( SwTableBox *pBox, sal_uInt16 nAbsAvail,
2487 sal_uInt16 nRelAvail, sal_uInt16 nAbsLeftSpace,
2488 sal_uInt16 nAbsRightSpace, sal_uInt16 nInhAbsSpace )
2489 {
2490 ASSERT( nRows>0 && nCols>0 && nCurRow==nRows,
2491 "Wurde CloseTable nicht aufgerufen?" );
2492
2493 ASSERT( (pLayoutInfo==0) == (this==pTopTable),
2494 "Top-Tabelle hat keine Layout-Info oder umgekehrt" );
2495
2496 if( this==pTopTable )
2497 {
2498 // Umrandung der Tabelle und aller in ihr enthaltenen berechnen
2499 SetBorders();
2500
2501 // Schritt 1: Die benoetigten Layout-Strukturen werden angelegt
2502 // (inklusive Tabellen in Tabellen).
2503 CreateLayoutInfo();
2504
2505 // Schritt 2: Die minimalen und maximalen Spaltenbreiten werden
2506 // berechnet (inklusive Tabellen in Tabellen). Da wir noch keine
2507 // Boxen haben, arabeiten wir noch auf den Start-Nodes.
2508 pLayoutInfo->AutoLayoutPass1();
2509 }
2510
2511 // Schritt 3: Die tatsaechlichen Spaltenbreiten dieser Tabelle werden
2512 // berechnet (nicht von Tabellen in Tabellen). Dies muss jetzt schon
2513 // sein, damit wir entscheiden koennen ob Filler-Zellen benoetigt werden
2514 // oder nicht (deshalb war auch Pass1 schon noetig).
2515 pLayoutInfo->AutoLayoutPass2( nAbsAvail, nRelAvail, nAbsLeftSpace,
2516 nAbsRightSpace, nInhAbsSpace );
2517
2518 if( this!=pTopTable )
2519 {
2520 // die linke und rechte Umrandung der Tabelle kann jetzt endgueltig
2521 // festgelegt werden
2522 if( pLayoutInfo->GetRelRightFill() == 0 )
2523 {
2524 if( !bRightBorder )
2525 {
2526 // linke Umrandung von auesserer Tabelle uebernehmen
2527 if( bInhRightBorder )
2528 {
2529 bRightBorder = sal_True;
2530 aRightBorderLine = aInhRightBorderLine;
2531 }
2532 }
2533 else
2534 {
2535 // Umrandung nur setzen, wenn es erlaubt ist
2536 bRightBorder = bRightAlwd;
2537 }
2538 }
2539
2540 if( pLayoutInfo->GetRelLeftFill() == 0 &&
2541 !((*pColumns)[0])->bLeftBorder &&
2542 bInhLeftBorder )
2543 {
2544 // ggf. rechte Umrandung von auesserer Tabelle uebernehmen
2545 ((*pColumns)[0])->bLeftBorder = sal_True;
2546 aLeftBorderLine = aInhLeftBorderLine;
2547 }
2548 }
2549
2550 // Fuer die Top-Table muss die Ausrichtung gesetzt werden
2551 if( this==pTopTable )
2552 {
2553 sal_Int16 eHoriOri;
2554 if( bForceFrame )
2555 {
2556 // Die Tabelle soll in einen Rahmen und ist auch schmaler
2557 // als der verfuegbare Platz und nicht 100% breit.
2558 // Dann kommt sie in einen Rahmen
2559 eHoriOri = bPrcWidth ? text::HoriOrientation::FULL : text::HoriOrientation::LEFT;
2560 }
2561 else switch( eTableAdjust )
2562 {
2563 // Die Tabelle passt entweder auf die Seite, soll aber in keinen
2564 // Rahmen oder sie ist Breiter als die Seite und soll deshalb
2565 // in keinen Rahmen
2566
2567 case SVX_ADJUST_RIGHT:
2568 // in rechtsbuendigen Tabellen kann nicht auf den rechten
2569 // Rand Ruecksicht genommen werden
2570 eHoriOri = text::HoriOrientation::RIGHT;
2571 break;
2572 case SVX_ADJUST_CENTER:
2573 // zentrierte Tabellen nehmen keine Ruecksicht auf Raender!
2574 eHoriOri = text::HoriOrientation::CENTER;
2575 break;
2576 case SVX_ADJUST_LEFT:
2577 default:
2578 // linksbuendige Tabellen nehmen nur auf den linken Rand
2579 // Ruecksicht
2580 eHoriOri = nLeftMargin ? text::HoriOrientation::LEFT_AND_WIDTH : text::HoriOrientation::LEFT;
2581 break;
2582 }
2583
2584 // das Tabellenform holen und anpassen
2585 SwFrmFmt *pFrmFmt = pSwTable->GetFrmFmt();
2586 pFrmFmt->SetFmtAttr( SwFmtHoriOrient(0,eHoriOri) );
2587 if( text::HoriOrientation::LEFT_AND_WIDTH==eHoriOri )
2588 {
2589 ASSERT( nLeftMargin || nRightMargin,
2590 "Da gibt's wohl noch Reste von relativen Breiten" );
2591
2592 // The right margin will be ignored anyway.
2593 SvxLRSpaceItem aLRItem( pSwTable->GetFrmFmt()->GetLRSpace() );
2594 aLRItem.SetLeft( nLeftMargin );
2595 aLRItem.SetRight( nRightMargin );
2596 pFrmFmt->SetFmtAttr( aLRItem );
2597 }
2598
2599 if( bPrcWidth && text::HoriOrientation::FULL!=eHoriOri )
2600 {
2601 pFrmFmt->LockModify();
2602 SwFmtFrmSize aFrmSize( pFrmFmt->GetFrmSize() );
2603 aFrmSize.SetWidthPercent( (sal_uInt8)nWidth );
2604 pFrmFmt->SetFmtAttr( aFrmSize );
2605 pFrmFmt->UnlockModify();
2606 }
2607 }
2608
2609 // die Default Line- und Box-Formate holen
2610 if( this==pTopTable )
2611 {
2612 // die erste Box merken und aus der ersten Zeile ausketten
2613 SwTableLine *pLine1 = (pSwTable->GetTabLines())[0];
2614 pBox1 = (pLine1->GetTabBoxes())[0];
2615 pLine1->GetTabBoxes().Remove(0);
2616
2617 pLineFmt = (SwTableLineFmt*)pLine1->GetFrmFmt();
2618 pBoxFmt = (SwTableBoxFmt*)pBox1->GetFrmFmt();
2619 }
2620 else
2621 {
2622 pLineFmt = (SwTableLineFmt*)pTopTable->pLineFmt;
2623 pBoxFmt = (SwTableBoxFmt*)pTopTable->pBoxFmt;
2624 }
2625
2626 // ggf. muessen fuer Tabellen in Tabellen "Filler"-Zellen eingefuegt
2627 // werden
2628 if( this != pTopTable &&
2629 ( pLayoutInfo->GetRelLeftFill() > 0 ||
2630 pLayoutInfo->GetRelRightFill() > 0 ) )
2631 {
2632 ASSERT( pBox, "kein TableBox fuer Tabelle in Tabelle" );
2633
2634 SwTableLines& rLines = pBox->GetTabLines();
2635
2636 // dazu brauchen wir erstmal ein eine neue Table-Line in der Box
2637 SwTableLine *pLine =
2638 new SwTableLine( pLineFrmFmtNoHeight ? pLineFrmFmtNoHeight
2639 : pLineFmt, 0, pBox );
2640 rLines.C40_INSERT( SwTableLine, pLine, rLines.Count() );
2641
2642 // Sicherstellen, dass wie ein Format ohne Hoehe erwischt haben
2643 if( !pLineFrmFmtNoHeight )
2644 {
2645 // sonst muessen wir die Hoehe aus dem Attribut entfernen
2646 // und koennen uns das Format merken
2647 pLineFrmFmtNoHeight = (SwTableLineFmt*)pLine->ClaimFrmFmt();
2648
2649 ResetLineFrmFmtAttrs( pLineFrmFmtNoHeight );
2650 }
2651
2652 SwTableBoxes& rBoxes = pLine->GetTabBoxes();
2653 SwTableBox *pNewBox;
2654
2655 // ggf. links eine Zelle einfuegen
2656 if( pLayoutInfo->GetRelLeftFill() > 0 )
2657 {
2658 // pPrevStNd ist der Vorgaenger-Start-Node der Tabelle. Den
2659 // "Filler"-Node fuegen wir einfach dahinter ein ...
2660 pPrevStNd = pParser->InsertTableSection( pPrevStNd );
2661
2662 pNewBox = NewTableBox( pPrevStNd, pLine );
2663 rBoxes.C40_INSERT( SwTableBox, pNewBox, rBoxes.Count() );
2664 FixFillerFrameFmt( pNewBox, sal_False );
2665 pLayoutInfo->SetLeftFillerBox( pNewBox );
2666 }
2667
2668 // jetzt die Tabelle bearbeiten
2669 pNewBox = new SwTableBox( pBoxFmt, 0, pLine );
2670 rBoxes.C40_INSERT( SwTableBox, pNewBox, rBoxes.Count() );
2671
2672 SwFrmFmt *pFrmFmt = pNewBox->ClaimFrmFmt();
2673 pFrmFmt->ResetFmtAttr( RES_BOX );
2674 pFrmFmt->ResetFmtAttr( RES_BACKGROUND );
2675 pFrmFmt->ResetFmtAttr( RES_VERT_ORIENT );
2676 pFrmFmt->ResetFmtAttr( RES_BOXATR_FORMAT );
2677
2678
2679 _MakeTable( pNewBox );
2680
2681 // und noch ggf. rechts eine Zelle einfuegen
2682 if( pLayoutInfo->GetRelRightFill() > 0 )
2683 {
2684 const SwStartNode *pStNd =
2685 GetPrevBoxStartNode( USHRT_MAX, USHRT_MAX );
2686 pStNd = pParser->InsertTableSection( pStNd );
2687
2688 pNewBox = NewTableBox( pStNd, pLine );
2689 rBoxes.C40_INSERT( SwTableBox, pNewBox, rBoxes.Count() );
2690
2691 FixFillerFrameFmt( pNewBox, sal_True );
2692 pLayoutInfo->SetRightFillerBox( pNewBox );
2693 }
2694 }
2695 else
2696 {
2697 _MakeTable( pBox );
2698 }
2699
2700 // zum Schluss fuehren wir noch eine Garbage-Collection fuer die
2701 // Top-Level-Tabelle durch
2702 if( this==pTopTable )
2703 {
2704 if( 1==nRows && nHeight && 1==pSwTable->GetTabLines().Count() )
2705 {
2706 // Hoehe einer einzeiligen Tabelle als Mindesthoehe der
2707 // Zeile setzen. (War mal fixe Hoehe, aber das gibt manchmal
2708 // Probleme (fix #34972#) und ist auch nicht Netscape 4.0
2709 // konform
2710 nHeight = pParser->ToTwips( nHeight );
2711 if( nHeight < MINLAY )
2712 nHeight = MINLAY;
2713
2714 (pSwTable->GetTabLines())[0]->ClaimFrmFmt();
2715 (pSwTable->GetTabLines())[0]->GetFrmFmt()
2716 ->SetFmtAttr( SwFmtFrmSize( ATT_MIN_SIZE, 0, nHeight ) );
2717 }
2718
2719 if( GetBGBrush() )
2720 pSwTable->GetFrmFmt()->SetFmtAttr( *GetBGBrush() );
2721
2722 ((SwTable *)pSwTable)->SetRowsToRepeat( static_cast< sal_uInt16 >(nHeadlineRepeat) );
2723 ((SwTable *)pSwTable)->GCLines();
2724
2725 sal_Bool bIsInFlyFrame = pContext && pContext->GetFrmFmt();
2726 if( bIsInFlyFrame && !nWidth )
2727 {
2728 SvxAdjust eTblAdjust = GetTableAdjust(sal_False);
2729 if( eTblAdjust != SVX_ADJUST_LEFT &&
2730 eTblAdjust != SVX_ADJUST_RIGHT )
2731 {
2732 // Wenn eine Tabelle ohne Breitenangabe nicht links oder
2733 // rechts umflossen werden soll, dann stacken wir sie
2734 // in einem Rahmen mit 100%-Breite, damit ihre Groesse
2735 // angepasst wird. Der Rahmen darf nicht angepasst werden.
2736 ASSERT( HasToFly(), "Warum ist die Tabelle in einem Rahmen?" );
2737 sal_uInt32 nMin = pLayoutInfo->GetMin();
2738 if( nMin > USHRT_MAX )
2739 nMin = USHRT_MAX;
2740 SwFmtFrmSize aFlyFrmSize( ATT_VAR_SIZE, (SwTwips)nMin, MINLAY );
2741 aFlyFrmSize.SetWidthPercent( 100 );
2742 pContext->GetFrmFmt()->SetFmtAttr( aFlyFrmSize );
2743 bIsInFlyFrame = sal_False;
2744 }
2745 else
2746 {
2747 // Links und rechts ausgerichtete Tabellen ohne Breite
2748 // duerfen leider nicht in der Breite angepasst werden, denn
2749 // sie wuerden nur schrumpfen aber nie wachsen.
2750 pLayoutInfo->SetMustNotRecalc( sal_True );
2751 if( pContext->GetFrmFmt()->GetAnchor().GetCntntAnchor()
2752 ->nNode.GetNode().FindTableNode() )
2753 {
2754 sal_uInt32 nMax = pLayoutInfo->GetMax();
2755 if( nMax > USHRT_MAX )
2756 nMax = USHRT_MAX;
2757 SwFmtFrmSize aFlyFrmSize( ATT_VAR_SIZE, (SwTwips)nMax, MINLAY );
2758 pContext->GetFrmFmt()->SetFmtAttr( aFlyFrmSize );
2759 bIsInFlyFrame = sal_False;
2760 }
2761 else
2762 {
2763 pLayoutInfo->SetMustNotResize( sal_True );
2764 }
2765 }
2766 }
2767 pLayoutInfo->SetMayBeInFlyFrame( bIsInFlyFrame );
2768
2769 // Nur Tabellen mit relativer Breite oder ohne Breite muessen
2770 // angepasst werden.
2771 pLayoutInfo->SetMustResize( bPrcWidth || !nWidth );
2772
2773 pLayoutInfo->SetWidths();
2774
2775 ((SwTable *)pSwTable)->SetHTMLTableLayout( pLayoutInfo );
2776
2777 if( pResizeDrawObjs )
2778 {
2779 sal_uInt16 nCount = pResizeDrawObjs->Count();
2780 for( sal_uInt16 i=0; i<nCount; i++ )
2781 {
2782 SdrObject *pObj = (*pResizeDrawObjs)[i];
2783 sal_uInt16 nRow = (*pDrawObjPrcWidths)[3*i];
2784 sal_uInt16 nCol = (*pDrawObjPrcWidths)[3*i+1];
2785 sal_uInt8 nPrcWidth = (sal_uInt8)(*pDrawObjPrcWidths)[3*i+2];
2786
2787 SwHTMLTableLayoutCell *pLayoutCell =
2788 pLayoutInfo->GetCell( nRow, nCol );
2789 sal_uInt16 nColSpan = pLayoutCell->GetColSpan();
2790
2791 sal_uInt16 nWidth2, nDummy;
2792 pLayoutInfo->GetAvail( nCol, nColSpan, nWidth2, nDummy );
2793 nWidth2 = nWidth2 - pLayoutInfo->GetLeftCellSpace( nCol, nColSpan );
2794 nWidth2 = nWidth2 - pLayoutInfo->GetRightCellSpace( nCol, nColSpan );
2795 nWidth2 = static_cast< sal_uInt16 >(((long)nWidth * nPrcWidth) / 100);
2796
2797 pParser->ResizeDrawObject( pObj, nWidth2 );
2798 }
2799 }
2800 }
2801 }
2802
SetTable(const SwStartNode * pStNd,_HTMLTableContext * pCntxt,sal_uInt16 nLeft,sal_uInt16 nRight,const SwTable * pSwTab,sal_Bool bFrcFrame)2803 void HTMLTable::SetTable( const SwStartNode *pStNd, _HTMLTableContext *pCntxt,
2804 sal_uInt16 nLeft, sal_uInt16 nRight,
2805 const SwTable *pSwTab, sal_Bool bFrcFrame )
2806 {
2807 pPrevStNd = pStNd;
2808 pSwTable = pSwTab;
2809 pContext = pCntxt;
2810
2811 nLeftMargin = nLeft;
2812 nRightMargin = nRight;
2813
2814 bForceFrame = bFrcFrame;
2815 }
2816
RegisterDrawObject(SdrObject * pObj,sal_uInt8 nPrcWidth)2817 void HTMLTable::RegisterDrawObject( SdrObject *pObj, sal_uInt8 nPrcWidth )
2818 {
2819 if( !pResizeDrawObjs )
2820 pResizeDrawObjs = new SdrObjects;
2821 pResizeDrawObjs->C40_INSERT( SdrObject, pObj, pResizeDrawObjs->Count() );
2822
2823 if( !pDrawObjPrcWidths )
2824 pDrawObjPrcWidths = new SvUShorts;
2825 pDrawObjPrcWidths->Insert( nCurRow, pDrawObjPrcWidths->Count() );
2826 pDrawObjPrcWidths->Insert( nCurCol, pDrawObjPrcWidths->Count() );
2827 pDrawObjPrcWidths->Insert( (sal_uInt16)nPrcWidth, pDrawObjPrcWidths->Count() );
2828 }
2829
MakeParentContents()2830 void HTMLTable::MakeParentContents()
2831 {
2832 if( !GetContext() && !HasParentSection() )
2833 {
2834 SetParentContents(
2835 pParser->InsertTableContents( GetIsParentHeader() ) );
2836
2837 SetHasParentSection( sal_True );
2838 }
2839 }
2840
~_HTMLTableContext()2841 _HTMLTableContext::~_HTMLTableContext()
2842 {
2843 delete pPos;
2844 }
2845
SavePREListingXMP(SwHTMLParser & rParser)2846 void _HTMLTableContext::SavePREListingXMP( SwHTMLParser& rParser )
2847 {
2848 bRestartPRE = rParser.IsReadPRE();
2849 bRestartXMP = rParser.IsReadXMP();
2850 bRestartListing = rParser.IsReadListing();
2851 rParser.FinishPREListingXMP();
2852 }
2853
RestorePREListingXMP(SwHTMLParser & rParser)2854 void _HTMLTableContext::RestorePREListingXMP( SwHTMLParser& rParser )
2855 {
2856 rParser.FinishPREListingXMP();
2857
2858 if( bRestartPRE )
2859 rParser.StartPRE();
2860
2861 if( bRestartXMP )
2862 rParser.StartXMP();
2863
2864 if( bRestartListing )
2865 rParser.StartListing();
2866 }
2867
2868
InsertTableSection(const SwStartNode * pPrevStNd)2869 const SwStartNode *SwHTMLParser::InsertTableSection
2870 ( const SwStartNode *pPrevStNd )
2871 {
2872 ASSERT( pPrevStNd, "Start-Node ist NULL" );
2873
2874 pCSS1Parser->SetTDTagStyles();
2875 SwTxtFmtColl *pColl = pCSS1Parser->GetTxtCollFromPool( RES_POOLCOLL_TABLE );
2876
2877 const SwStartNode *pStNd;
2878 if( pTable && pTable->bFirstCell )
2879 {
2880 SwNode *const pNd = & pPam->GetPoint()->nNode.GetNode();
2881 pNd->GetTxtNode()->ChgFmtColl( pColl );
2882 pStNd = pNd->FindTableBoxStartNode();
2883 pTable->bFirstCell = sal_False;
2884 }
2885 else
2886 {
2887 const SwNode* pNd;
2888 if( pPrevStNd->IsTableNode() )
2889 pNd = pPrevStNd;
2890 else
2891 pNd = pPrevStNd->EndOfSectionNode();
2892 SwNodeIndex nIdx( *pNd, 1 );
2893 pStNd = pDoc->GetNodes().MakeTextSection( nIdx, SwTableBoxStartNode,
2894 pColl );
2895 pTable->IncBoxCount();
2896 }
2897
2898 SwCntntNode *pCNd = pDoc->GetNodes()[pStNd->GetIndex()+1] ->GetCntntNode();
2899 SvxFontHeightItem aFontHeight( 40, 100, RES_CHRATR_FONTSIZE );
2900 pCNd->SetAttr( aFontHeight );
2901 aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE );
2902 pCNd->SetAttr( aFontHeight );
2903 aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE );
2904 pCNd->SetAttr( aFontHeight );
2905
2906 return pStNd;
2907 }
2908
InsertTableSection(sal_uInt16 nPoolId)2909 const SwStartNode *SwHTMLParser::InsertTableSection( sal_uInt16 nPoolId )
2910 {
2911 switch( nPoolId )
2912 {
2913 case RES_POOLCOLL_TABLE_HDLN:
2914 pCSS1Parser->SetTHTagStyles();
2915 break;
2916 case RES_POOLCOLL_TABLE:
2917 pCSS1Parser->SetTDTagStyles();
2918 break;
2919 }
2920
2921 SwTxtFmtColl *pColl = pCSS1Parser->GetTxtCollFromPool( nPoolId );
2922
2923 SwNode *const pNd = & pPam->GetPoint()->nNode.GetNode();
2924 const SwStartNode *pStNd;
2925 if( pTable && pTable->bFirstCell )
2926 {
2927 pNd->GetTxtNode()->ChgFmtColl( pColl );
2928 pTable->bFirstCell = sal_False;
2929 pStNd = pNd->FindTableBoxStartNode();
2930 }
2931 else
2932 {
2933 SwTableNode *pTblNd = pNd->FindTableNode();
2934 if( pTblNd->GetTable().GetHTMLTableLayout() )
2935 { // if there is already a HTMTableLayout, this table is already finished
2936 // and we have to look for the right table in the environment
2937 SwTableNode *pOutTbl = pTblNd;
2938 do {
2939 pTblNd = pOutTbl;
2940 pOutTbl = pOutTbl->StartOfSectionNode()->FindTableNode();
2941 } while( pOutTbl && pTblNd->GetTable().GetHTMLTableLayout() );
2942 }
2943 SwNodeIndex aIdx( *pTblNd->EndOfSectionNode() );
2944 pStNd = pDoc->GetNodes().MakeTextSection( aIdx, SwTableBoxStartNode,
2945 pColl );
2946
2947 pPam->GetPoint()->nNode = pStNd->GetIndex() + 1;
2948 SwTxtNode *pTxtNd = pPam->GetPoint()->nNode.GetNode().GetTxtNode();
2949 pPam->GetPoint()->nContent.Assign( pTxtNd, 0 );
2950 pTable->IncBoxCount();
2951 }
2952
2953 return pStNd;
2954 }
2955
InsertTempTableCaptionSection()2956 SwStartNode *SwHTMLParser::InsertTempTableCaptionSection()
2957 {
2958 SwTxtFmtColl *pColl = pCSS1Parser->GetTxtCollFromPool( RES_POOLCOLL_TEXT );
2959 SwNodeIndex& rIdx = pPam->GetPoint()->nNode;
2960 rIdx = pDoc->GetNodes().GetEndOfExtras();
2961 SwStartNode *pStNd = pDoc->GetNodes().MakeTextSection( rIdx,
2962 SwNormalStartNode, pColl );
2963
2964 rIdx = pStNd->GetIndex() + 1;
2965 pPam->GetPoint()->nContent.Assign( rIdx.GetNode().GetTxtNode(), 0 );
2966
2967 return pStNd;
2968 }
2969
2970
StripTrailingLF()2971 xub_StrLen SwHTMLParser::StripTrailingLF()
2972 {
2973 xub_StrLen nStripped = 0;
2974
2975 xub_StrLen nLen = pPam->GetPoint()->nContent.GetIndex();
2976 if( nLen )
2977 {
2978 SwTxtNode* pTxtNd = pPam->GetPoint()->nNode.GetNode().GetTxtNode();
2979 // vorsicht, wenn Kommentare nicht ueberlesen werden!!!
2980 if( pTxtNd )
2981 {
2982 xub_StrLen nPos = nLen;
2983 xub_StrLen nLFCount = 0;
2984 while( nPos && '\x0a' == (pTxtNd->GetTxt()).GetChar(--nPos) )
2985 nLFCount++;
2986
2987 if( nLFCount )
2988 {
2989 // MIB 6.6.97: Warum sollte man bei leeren Absaetzen nur ein LF loeschen?
2990 // Das stimmt doch irgendwie nicht ...
2991 // if( nLFCount == nLen )
2992 // {
2993 // // nur Lfs, dann nur ein LF loeschen
2994 // nLFCount = 1;
2995 // }
2996 // else if( nLFCount > 2 )
2997 if( nLFCount > 2 )
2998 {
2999 // Bei Netscape entspricht ein Absatz-Ende zwei LFs
3000 // (mit einem kommt man in die naechste Zeile, das
3001 // zweite erzeugt eine Leerzeile) Diesen Abstand
3002 // erreichen wie aber schon mit dem unteren
3003 // Absatz-Abstand. Wenn nach den <BR> ein neuer
3004 // Absatz aufgemacht wird, wird das Maximum des Abstands,
3005 // der sich aus den BR und dem P ergibt genommen.
3006 // Deshalb muessen wir 2 bzw. alle bei weniger
3007 // als zweien loeschen
3008 nLFCount = 2;
3009 }
3010
3011 nPos = nLen - nLFCount;
3012 SwIndex nIdx( pTxtNd, nPos );
3013 pTxtNd->EraseText( nIdx, nLFCount );
3014 nStripped = nLFCount;
3015 }
3016 }
3017 }
3018
3019 return nStripped;
3020 }
3021
CreateBrushItem(const Color * pColor,const String & rImageURL,const String & rStyle,const String & rId,const String & rClass)3022 SvxBrushItem* SwHTMLParser::CreateBrushItem( const Color *pColor,
3023 const String& rImageURL,
3024 const String& rStyle,
3025 const String& rId,
3026 const String& rClass )
3027 {
3028 SvxBrushItem *pBrushItem = 0;
3029
3030 if( rStyle.Len() || rId.Len() || rClass.Len() )
3031 {
3032 SfxItemSet aItemSet( pDoc->GetAttrPool(), RES_BACKGROUND,
3033 RES_BACKGROUND );
3034 SvxCSS1PropertyInfo aPropInfo;
3035
3036 if( rClass.Len() )
3037 {
3038 String aClass( rClass );
3039 SwCSS1Parser::GetScriptFromClass( aClass );
3040 SvxCSS1MapEntry *pClass = pCSS1Parser->GetClass( aClass );
3041 if( pClass )
3042 aItemSet.Put( pClass->GetItemSet() );
3043 }
3044
3045 if( rId.Len() )
3046 {
3047 SvxCSS1MapEntry *pId = pCSS1Parser->GetId( rId );
3048 if( pId )
3049 aItemSet.Put( pId->GetItemSet() );
3050 }
3051
3052 pCSS1Parser->ParseStyleOption( rStyle, aItemSet, aPropInfo );
3053 const SfxPoolItem *pItem = 0;
3054 if( SFX_ITEM_SET == aItemSet.GetItemState( RES_BACKGROUND, sal_False,
3055 &pItem ) )
3056 {
3057 pBrushItem = new SvxBrushItem( *((const SvxBrushItem *)pItem) );
3058 }
3059 }
3060
3061 if( !pBrushItem && (pColor || rImageURL.Len()) )
3062 {
3063 pBrushItem = new SvxBrushItem(RES_BACKGROUND);
3064
3065 if( pColor )
3066 pBrushItem->SetColor(*pColor);
3067
3068 if( rImageURL.Len() )
3069 {
3070 pBrushItem->SetGraphicLink( URIHelper::SmartRel2Abs( INetURLObject(sBaseURL), rImageURL, Link(), false) );
3071 pBrushItem->SetGraphicPos( GPOS_TILED );
3072 }
3073 }
3074
3075 return pBrushItem;
3076 }
3077
3078
3079 class _SectionSaveStruct : public SwPendingStackData
3080 {
3081 sal_uInt16 nBaseFontStMinSave, nFontStMinSave, nFontStHeadStartSave;
3082 sal_uInt16 nDefListDeepSave, nContextStMinSave, nContextStAttrMinSave;
3083
3084 public:
3085
3086 HTMLTable *pTable;
3087
3088 _SectionSaveStruct( SwHTMLParser& rParser );
3089 virtual ~_SectionSaveStruct();
3090
GetContextStAttrMin() const3091 sal_uInt16 GetContextStAttrMin() const { return nContextStAttrMinSave; }
3092
3093 void Restore( SwHTMLParser& rParser );
3094 };
3095
_SectionSaveStruct(SwHTMLParser & rParser)3096 _SectionSaveStruct::_SectionSaveStruct( SwHTMLParser& rParser ) :
3097 nBaseFontStMinSave(0), nFontStMinSave(0), nFontStHeadStartSave(0),
3098 nDefListDeepSave(0), nContextStMinSave(0), nContextStAttrMinSave(0),
3099 pTable( 0 )
3100 {
3101 // Font-Stacks einfrieren
3102 nBaseFontStMinSave = rParser.nBaseFontStMin;
3103 rParser.nBaseFontStMin = rParser.aBaseFontStack.Count();
3104
3105 nFontStMinSave = rParser.nFontStMin;
3106 nFontStHeadStartSave = rParser.nFontStHeadStart;
3107 rParser.nFontStMin = rParser.aFontStack.Count();
3108
3109 // Kontext-Stack einfrieren
3110 nContextStMinSave = rParser.nContextStMin;
3111 nContextStAttrMinSave = rParser.nContextStAttrMin;
3112 rParser.nContextStMin = rParser.aContexts.Count();
3113 rParser.nContextStAttrMin = rParser.nContextStMin;
3114
3115 // und noch ein paar Zaehler retten
3116 nDefListDeepSave = rParser.nDefListDeep;
3117 rParser.nDefListDeep = 0;
3118 }
3119
~_SectionSaveStruct()3120 _SectionSaveStruct::~_SectionSaveStruct()
3121 {}
3122
Restore(SwHTMLParser & rParser)3123 void _SectionSaveStruct::Restore( SwHTMLParser& rParser )
3124 {
3125 // Font-Stacks wieder auftauen
3126 sal_uInt16 nMin = rParser.nBaseFontStMin;
3127 if( rParser.aBaseFontStack.Count() > nMin )
3128 rParser.aBaseFontStack.Remove( nMin,
3129 rParser.aBaseFontStack.Count() - nMin );
3130 rParser.nBaseFontStMin = nBaseFontStMinSave;
3131
3132
3133 nMin = rParser.nFontStMin;
3134 if( rParser.aFontStack.Count() > nMin )
3135 rParser.aFontStack.Remove( nMin,
3136 rParser.aFontStack.Count() - nMin );
3137 rParser.nFontStMin = nFontStMinSave;
3138 rParser.nFontStHeadStart = nFontStHeadStartSave;
3139
3140 // Der Kontext-Stack muss schon aufgeraeumt sein!
3141 ASSERT( rParser.aContexts.Count() == rParser.nContextStMin &&
3142 rParser.aContexts.Count() == rParser.nContextStAttrMin,
3143 "Der Kontext-Stack wurde nicht aufgeraeumt" );
3144 rParser.nContextStMin = nContextStMinSave;
3145 rParser.nContextStAttrMin = nContextStAttrMinSave;
3146
3147 // und noch ein paar Zaehler rekonstruieren
3148 rParser.nDefListDeep = nDefListDeepSave;
3149
3150 // und ein paar Flags zuruecksetzen
3151 rParser.bNoParSpace = sal_False;
3152 rParser.nOpenParaToken = 0;
3153
3154 if( rParser.aParaAttrs.Count() )
3155 rParser.aParaAttrs.Remove( 0, rParser.aParaAttrs.Count() );
3156 }
3157
3158
3159 class _CellSaveStruct : public _SectionSaveStruct
3160 {
3161 String aStyle, aId, aClass, aLang, aDir;
3162 String aBGImage;
3163 Color aBGColor;
3164
3165 HTMLTableCnts* pCnts; // Liste aller Inhalte
3166 HTMLTableCnts* pCurrCnts; // der aktuelle Inhalt oder 0
3167 SwNodeIndex *pNoBreakEndParaIdx;// Absatz-Index eines </NOBR>
3168
3169 double nValue;
3170
3171 sal_uInt32 nNumFmt;
3172
3173 sal_uInt16 nRowSpan, nColSpan, nWidth, nHeight;
3174 xub_StrLen nNoBreakEndCntntPos; // Zeichen-Index eines </NOBR>
3175
3176 SvxAdjust eAdjust;
3177 sal_Int16 eVertOri;
3178
3179 sal_Bool bHead : 1;
3180 sal_Bool bPrcWidth : 1;
3181 sal_Bool bHasNumFmt : 1;
3182 sal_Bool bHasValue : 1;
3183 sal_Bool bBGColor : 1;
3184 sal_Bool bNoWrap : 1; // NOWRAP-Option
3185 sal_Bool bNoBreak : 1; // NOBREAK-Tag
3186
3187 public:
3188
3189 _CellSaveStruct( SwHTMLParser& rParser, HTMLTable *pCurTable, sal_Bool bHd,
3190 sal_Bool bReadOpt );
3191
3192 virtual ~_CellSaveStruct();
3193
3194 void AddContents( HTMLTableCnts *pNewCnts );
GetFirstContents()3195 HTMLTableCnts *GetFirstContents() { return pCnts; }
3196
ClearIsInSection()3197 void ClearIsInSection() { pCurrCnts = 0; }
IsInSection() const3198 sal_Bool IsInSection() const { return pCurrCnts!=0; }
GetCurrContents() const3199 HTMLTableCnts *GetCurrContents() const { return pCurrCnts; }
3200
3201 void InsertCell( SwHTMLParser& rParser, HTMLTable *pCurTable );
3202
IsHeaderCell() const3203 sal_Bool IsHeaderCell() const { return bHead; }
3204
3205 void StartNoBreak( const SwPosition& rPos );
3206 void EndNoBreak( const SwPosition& rPos );
3207 void CheckNoBreak( const SwPosition& rPos, SwDoc *pDoc );
3208 };
3209
3210
_CellSaveStruct(SwHTMLParser & rParser,HTMLTable * pCurTable,sal_Bool bHd,sal_Bool bReadOpt)3211 _CellSaveStruct::_CellSaveStruct( SwHTMLParser& rParser, HTMLTable *pCurTable,
3212 sal_Bool bHd, sal_Bool bReadOpt ) :
3213 _SectionSaveStruct( rParser ),
3214 pCnts( 0 ),
3215 pCurrCnts( 0 ),
3216 pNoBreakEndParaIdx( 0 ),
3217 nValue( 0.0 ),
3218 nNumFmt( 0 ),
3219 nRowSpan( 1 ),
3220 nColSpan( 1 ),
3221 nWidth( 0 ),
3222 nHeight( 0 ),
3223 nNoBreakEndCntntPos( 0 ),
3224 eAdjust( pCurTable->GetInheritedAdjust() ),
3225 eVertOri( pCurTable->GetInheritedVertOri() ),
3226 bHead( bHd ),
3227 bPrcWidth( sal_False ),
3228 bHasNumFmt( sal_False ),
3229 bHasValue( sal_False ),
3230 bBGColor( sal_False ),
3231 bNoWrap( sal_False ),
3232 bNoBreak( sal_False )
3233 {
3234 String aNumFmt, aValue;
3235
3236 if( bReadOpt )
3237 {
3238 const HTMLOptions *pOptions = rParser.GetOptions();
3239 for( sal_uInt16 i = pOptions->Count(); i; )
3240 {
3241 const HTMLOption *pOption = (*pOptions)[--i];
3242 switch( pOption->GetToken() )
3243 {
3244 case HTML_O_ID:
3245 aId = pOption->GetString();
3246 break;
3247 case HTML_O_COLSPAN:
3248 nColSpan = (sal_uInt16)pOption->GetNumber();
3249 break;
3250 case HTML_O_ROWSPAN:
3251 nRowSpan = (sal_uInt16)pOption->GetNumber();
3252 break;
3253 case HTML_O_ALIGN:
3254 eAdjust = (SvxAdjust)pOption->GetEnum(
3255 aHTMLPAlignTable, static_cast< sal_uInt16 >(eAdjust) );
3256 break;
3257 case HTML_O_VALIGN:
3258 eVertOri = pOption->GetEnum(
3259 aHTMLTblVAlignTable, eVertOri );
3260 break;
3261 case HTML_O_WIDTH:
3262 nWidth = (sal_uInt16)pOption->GetNumber(); // nur fuer Netscape
3263 bPrcWidth = (pOption->GetString().Search('%') != STRING_NOTFOUND);
3264 if( bPrcWidth && nWidth>100 )
3265 nWidth = 100;
3266 break;
3267 case HTML_O_HEIGHT:
3268 nHeight = (sal_uInt16)pOption->GetNumber(); // nur fuer Netscape
3269 if( pOption->GetString().Search('%') != STRING_NOTFOUND)
3270 nHeight = 0; // keine %-Angaben beruecksichtigen
3271 break;
3272 case HTML_O_BGCOLOR:
3273 // Leere BGCOLOR bei <TABLE>, <TR> und <TD>/<TH> wie Netscape
3274 // ignorieren, bei allen anderen Tags *wirklich* nicht.
3275 if( pOption->GetString().Len() )
3276 {
3277 pOption->GetColor( aBGColor );
3278 bBGColor = sal_True;
3279 }
3280 break;
3281 case HTML_O_BACKGROUND:
3282 aBGImage = pOption->GetString();
3283 break;
3284 case HTML_O_STYLE:
3285 aStyle = pOption->GetString();
3286 break;
3287 case HTML_O_CLASS:
3288 aClass = pOption->GetString();
3289 break;
3290 case HTML_O_LANG:
3291 aLang = pOption->GetString();
3292 break;
3293 case HTML_O_DIR:
3294 aDir = pOption->GetString();
3295 break;
3296 case HTML_O_SDNUM:
3297 aNumFmt = pOption->GetString();
3298 bHasNumFmt = sal_True;
3299 break;
3300 case HTML_O_SDVAL:
3301 bHasValue = sal_True;
3302 aValue = pOption->GetString();
3303 break;
3304 case HTML_O_NOWRAP:
3305 bNoWrap = sal_True;
3306 break;
3307 }
3308 }
3309
3310 if( aId.Len() )
3311 rParser.InsertBookmark( aId );
3312 }
3313
3314 if( bHasNumFmt )
3315 {
3316 LanguageType eLang;
3317 nValue = rParser.GetTableDataOptionsValNum(
3318 nNumFmt, eLang, aValue, aNumFmt,
3319 *rParser.pDoc->GetNumberFormatter() );
3320 }
3321
3322 // einen neuen Kontext anlegen, aber das drawing::Alignment-Attribut
3323 // nicht dort verankern, weil es noch gar keine Section gibt, in der
3324 // es gibt.
3325 sal_uInt16 nToken, nColl;
3326 if( bHead )
3327 {
3328 nToken = HTML_TABLEHEADER_ON;
3329 nColl = RES_POOLCOLL_TABLE_HDLN;
3330 }
3331 else
3332 {
3333 nToken = HTML_TABLEDATA_ON;
3334 nColl = RES_POOLCOLL_TABLE;
3335 }
3336 _HTMLAttrContext *pCntxt = new _HTMLAttrContext( nToken, nColl, aEmptyStr, sal_True );
3337 if( SVX_ADJUST_END != eAdjust )
3338 rParser.InsertAttr( &rParser.aAttrTab.pAdjust, SvxAdjustItem(eAdjust, RES_PARATR_ADJUST),
3339 pCntxt );
3340
3341 if( rParser.HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) )
3342 {
3343 SfxItemSet aItemSet( rParser.pDoc->GetAttrPool(),
3344 rParser.pCSS1Parser->GetWhichMap() );
3345 SvxCSS1PropertyInfo aPropInfo;
3346
3347 if( rParser.ParseStyleOptions( aStyle, aId, aClass, aItemSet,
3348 aPropInfo, &aLang, &aDir ) )
3349 rParser.InsertAttrs( aItemSet, aPropInfo, pCntxt );
3350 }
3351
3352 rParser.SplitPREListingXMP( pCntxt );
3353
3354 rParser.PushContext( pCntxt );
3355 }
3356
~_CellSaveStruct()3357 _CellSaveStruct::~_CellSaveStruct()
3358 {
3359 delete pNoBreakEndParaIdx;
3360 }
3361
AddContents(HTMLTableCnts * pNewCnts)3362 void _CellSaveStruct::AddContents( HTMLTableCnts *pNewCnts )
3363 {
3364 if( pCnts )
3365 pCnts->Add( pNewCnts );
3366 else
3367 pCnts = pNewCnts;
3368
3369 pCurrCnts = pNewCnts;
3370 }
3371
InsertCell(SwHTMLParser & rParser,HTMLTable * pCurTable)3372 void _CellSaveStruct::InsertCell( SwHTMLParser& rParser,
3373 HTMLTable *pCurTable )
3374 {
3375 #ifdef DBG_UTIL
3376 // Die Attribute muessen schon beim Auefrauemen des Kontext-Stacks
3377 // entfernt worden sein, sonst ist etwas schiefgelaufen. Das
3378 // Checken wir mal eben ...
3379 // MIB 8.1.98: Wenn ausserhalb einer Zelle Attribute geoeffnet
3380 // wurden stehen diese noch in der Attribut-Tabelle und werden erst
3381 // ganz zum Schluss durch die CleanContext-Aufrufe in BuildTable
3382 // geloescht. Damit es in diesem Fall keine Asserts gibt findet dann
3383 // keine Ueberpruefung statt. Erkennen tut man diesen Fall an
3384 // nContextStAttrMin: Der gemerkte Wert nContextStAttrMinSave ist der
3385 // Wert, den nContextStAttrMin beim Start der Tabelle hatte. Und
3386 // der aktuelle Wert von nContextStAttrMin entspricht der Anzahl der
3387 // Kontexte, die beim Start der Zelle vorgefunden wurden. Sind beide
3388 // Werte unterschiedlich, wurden ausserhalb der Zelle Kontexte
3389 // angelegt und wir ueberpruefen nichts.
3390
3391 if( rParser.nContextStAttrMin == GetContextStAttrMin() )
3392 {
3393 _HTMLAttr** pTbl = (_HTMLAttr**)&rParser.aAttrTab;
3394
3395 for( sal_uInt16 nCnt = sizeof( _HTMLAttrTable ) / sizeof( _HTMLAttr* );
3396 nCnt--; ++pTbl )
3397 {
3398 ASSERT( !*pTbl, "Die Attribut-Tabelle ist nicht leer" );
3399 }
3400 }
3401 #endif
3402
3403 // jetzt muessen wir noch die Zelle an der aktuellen Position einfuegen
3404 SvxBrushItem *pBrushItem =
3405 rParser.CreateBrushItem( bBGColor ? &aBGColor : 0, aBGImage,
3406 aStyle, aId, aClass );
3407 pCurTable->InsertCell( pCnts, nRowSpan, nColSpan, nWidth,
3408 bPrcWidth, nHeight, eVertOri, pBrushItem,
3409 bHasNumFmt, nNumFmt, bHasValue, nValue,
3410 bNoWrap );
3411 Restore( rParser );
3412 }
3413
StartNoBreak(const SwPosition & rPos)3414 void _CellSaveStruct::StartNoBreak( const SwPosition& rPos )
3415 {
3416 if( !pCnts ||
3417 (!rPos.nContent.GetIndex() && pCurrCnts==pCnts &&
3418 pCnts->GetStartNode() &&
3419 pCnts->GetStartNode()->GetIndex() + 1 ==
3420 rPos.nNode.GetIndex()) )
3421 {
3422 bNoBreak = sal_True;
3423 }
3424 }
3425
EndNoBreak(const SwPosition & rPos)3426 void _CellSaveStruct::EndNoBreak( const SwPosition& rPos )
3427 {
3428 if( bNoBreak )
3429 {
3430 delete pNoBreakEndParaIdx;
3431 pNoBreakEndParaIdx = new SwNodeIndex( rPos.nNode );
3432 nNoBreakEndCntntPos = rPos.nContent.GetIndex();
3433 bNoBreak = sal_False;
3434 }
3435 }
3436
CheckNoBreak(const SwPosition & rPos,SwDoc *)3437 void _CellSaveStruct::CheckNoBreak( const SwPosition& rPos, SwDoc * /*pDoc*/ )
3438 {
3439 if( pCnts && pCurrCnts==pCnts )
3440 {
3441 if( bNoBreak )
3442 {
3443 // <NOBR> wurde nicht beendet
3444 pCnts->SetNoBreak();
3445 }
3446 else if( pNoBreakEndParaIdx &&
3447 pNoBreakEndParaIdx->GetIndex() == rPos.nNode.GetIndex() )
3448 {
3449 if( nNoBreakEndCntntPos == rPos.nContent.GetIndex() )
3450 {
3451 // <NOBR> wurde unmittelbar vor dem Zellen-Ende beendet
3452 pCnts->SetNoBreak();
3453 }
3454 else if( nNoBreakEndCntntPos + 1 == rPos.nContent.GetIndex() )
3455 {
3456 SwTxtNode const*const pTxtNd(rPos.nNode.GetNode().GetTxtNode());
3457 if( pTxtNd )
3458 {
3459 sal_Unicode cLast =
3460 pTxtNd->GetTxt().GetChar(nNoBreakEndCntntPos);
3461 if( ' '==cLast || '\x0a'==cLast )
3462 {
3463 // Zwischem dem </NOBR> und dem Zellen-Ende gibt es nur
3464 // ein Blank oder einen Zeilenumbruch.
3465 pCnts->SetNoBreak();
3466 }
3467 }
3468 }
3469 }
3470 }
3471 }
3472
3473
3474
InsertTableContents(sal_Bool bHead)3475 HTMLTableCnts *SwHTMLParser::InsertTableContents(
3476 sal_Bool bHead )
3477 {
3478 // eine neue Section anlegen, der PaM steht dann darin
3479 const SwStartNode *pStNd =
3480 InsertTableSection( static_cast< sal_uInt16 >(bHead ? RES_POOLCOLL_TABLE_HDLN
3481 : RES_POOLCOLL_TABLE) );
3482
3483 if( GetNumInfo().GetNumRule() )
3484 {
3485 // 1. Absatz auf nicht numeriert setzen
3486 sal_uInt8 nLvl = GetNumInfo().GetLevel();
3487 // --> OD 2008-04-02 #refactorlists#
3488 // SetNoNum(&nLvl, sal_True);
3489 // SetNodeNum( nLvl);
3490 SetNodeNum( nLvl, false );
3491 }
3492
3493 // Attributierungs-Anfang neu setzen
3494 const SwNodeIndex& rSttPara = pPam->GetPoint()->nNode;
3495 xub_StrLen nSttCnt = pPam->GetPoint()->nContent.GetIndex();
3496
3497 _HTMLAttr** pTbl = (_HTMLAttr**)&aAttrTab;
3498 for( sal_uInt16 nCnt = sizeof( _HTMLAttrTable ) / sizeof( _HTMLAttr* );
3499 nCnt--; ++pTbl )
3500 {
3501
3502 _HTMLAttr *pAttr = *pTbl;
3503 while( pAttr )
3504 {
3505 ASSERT( !pAttr->GetPrev(), "Attribut hat Previous-Liste" );
3506 pAttr->nSttPara = rSttPara;
3507 pAttr->nEndPara = rSttPara;
3508 pAttr->nSttCntnt = nSttCnt;
3509 pAttr->nEndCntnt = nSttCnt;
3510
3511 pAttr = pAttr->GetNext();
3512 }
3513 }
3514
3515 return new HTMLTableCnts( pStNd );
3516 }
3517
IncGrfsThatResizeTable()3518 sal_uInt16 SwHTMLParser::IncGrfsThatResizeTable()
3519 {
3520 return pTable ? pTable->IncGrfsThatResize() : 0;
3521 }
3522
RegisterDrawObjectToTable(HTMLTable * pCurTable,SdrObject * pObj,sal_uInt8 nPrcWidth)3523 void SwHTMLParser::RegisterDrawObjectToTable( HTMLTable *pCurTable,
3524 SdrObject *pObj, sal_uInt8 nPrcWidth )
3525 {
3526 pCurTable->RegisterDrawObject( pObj, nPrcWidth );
3527 }
3528
BuildTableCell(HTMLTable * pCurTable,sal_Bool bReadOptions,sal_Bool bHead)3529 void SwHTMLParser::BuildTableCell( HTMLTable *pCurTable, sal_Bool bReadOptions,
3530 sal_Bool bHead )
3531 {
3532 if( !IsParserWorking() && !pPendStack )
3533 return;
3534
3535 _CellSaveStruct* pSaveStruct;
3536
3537 int nToken = 0;
3538 sal_Bool bPending = sal_False;
3539 if( pPendStack )
3540 {
3541 pSaveStruct = (_CellSaveStruct*)pPendStack->pData;
3542
3543 SwPendingStack* pTmp = pPendStack->pNext;
3544 delete pPendStack;
3545 pPendStack = pTmp;
3546 nToken = pPendStack ? pPendStack->nToken : GetSaveToken();
3547 bPending = SVPAR_ERROR == eState && pPendStack != 0;
3548
3549 SaveState( nToken );
3550 }
3551 else
3552 {
3553 // <TH> bzw. <TD> wurde bereits gelesen
3554 if( pTable->IsOverflowing() )
3555 {
3556 SaveState( 0 );
3557 return;
3558 }
3559
3560 if( !pCurTable->GetContext() )
3561 {
3562 sal_Bool bTopTable = pTable==pCurTable;
3563
3564 // die Tabelle besitzt noch keinen Inhalt, d.h. die eigentliche
3565 // Tabelle muss erst noch angelegt werden
3566
3567 static sal_uInt16 aWhichIds[] =
3568 {
3569 RES_PARATR_SPLIT, RES_PARATR_SPLIT,
3570 RES_PAGEDESC, RES_PAGEDESC,
3571 RES_BREAK, RES_BREAK,
3572 RES_BACKGROUND, RES_BACKGROUND,
3573 RES_KEEP, RES_KEEP,
3574 RES_LAYOUT_SPLIT, RES_LAYOUT_SPLIT,
3575 RES_FRAMEDIR, RES_FRAMEDIR,
3576 0
3577 };
3578
3579 SfxItemSet aItemSet( pDoc->GetAttrPool(), aWhichIds );
3580 SvxCSS1PropertyInfo aPropInfo;
3581
3582 sal_Bool bStyleParsed = ParseStyleOptions( pCurTable->GetStyle(),
3583 pCurTable->GetId(),
3584 pCurTable->GetClass(),
3585 aItemSet, aPropInfo,
3586 0, &pCurTable->GetDirection() );
3587 const SfxPoolItem *pItem = 0;
3588 if( bStyleParsed )
3589 {
3590 if( SFX_ITEM_SET == aItemSet.GetItemState(
3591 RES_BACKGROUND, sal_False, &pItem ) )
3592 {
3593 pCurTable->SetBGBrush( *(const SvxBrushItem *)pItem );
3594 aItemSet.ClearItem( RES_BACKGROUND );
3595 }
3596 if( SFX_ITEM_SET == aItemSet.GetItemState(
3597 RES_PARATR_SPLIT, sal_False, &pItem ) )
3598 {
3599 aItemSet.Put(
3600 SwFmtLayoutSplit( ((const SvxFmtSplitItem *)pItem)
3601 ->GetValue() ) );
3602 aItemSet.ClearItem( RES_PARATR_SPLIT );
3603 }
3604 }
3605
3606 // Den linken/rechten Absatzeinzug ermitteln
3607 sal_uInt16 nLeftSpace = 0;
3608 sal_uInt16 nRightSpace = 0;
3609 short nIndent;
3610 GetMarginsFromContextWithNumBul( nLeftSpace, nRightSpace, nIndent );
3611
3612 // die aktuelle Position an die wir irgendwann zurueckkehren
3613 SwPosition *pSavePos = 0;
3614 sal_Bool bForceFrame = sal_False;
3615 sal_Bool bAppended = sal_False;
3616 sal_Bool bParentLFStripped = sal_False;
3617 if( bTopTable )
3618 {
3619 SvxAdjust eTblAdjust = pTable->GetTableAdjust(sal_False);
3620
3621 // Wenn die Tabelle links oder rechts ausgerichtet ist,
3622 // oder in einen Rahmen soll, dann kommt sie auch in einen
3623 // solchen.
3624 bForceFrame = eTblAdjust == SVX_ADJUST_LEFT ||
3625 eTblAdjust == SVX_ADJUST_RIGHT ||
3626 pCurTable->HasToFly();
3627
3628 // Entweder kommt die Tabelle in keinen Rahmen und befindet
3629 // sich in keinem Rahmen (wird also durch Zellen simuliert),
3630 // oder es gibt bereits Inhalt an der entsprechenden Stelle.
3631 ASSERT( !bForceFrame || pCurTable->HasParentSection(),
3632 "Tabelle im Rahmen hat keine Umgebung!" );
3633 // SCHOEN WAER'S, aber wie bekommen den Inhalt nicht zurueck
3634 // in die umgebende Zelle
3635 // if( bForceFrame && !pCurTable->HasParentSection() )
3636 // {
3637 // pCurTable->SetParentContents(
3638 // InsertTableContents( sal_False, SVX_ADJUST_END ) );
3639 // pCurTable->SetHasParentSection( sal_True );
3640 // }
3641
3642 sal_Bool bAppend = sal_False;
3643 if( bForceFrame )
3644 {
3645 // Wenn die Tabelle in einen Rahmen kommt, muss
3646 // nur ein neuer Absatz aufgemacht werden, wenn
3647 // der Absatz Rahmen ohne Umlauf enthaelt.
3648 bAppend = HasCurrentParaFlys(sal_True);
3649 }
3650 else
3651 {
3652 // Sonst muss ein neuer Absatz aufgemacht werden,
3653 // wenn der Absatz nicht leer ist, oder Rahmen
3654 // oder text::Bookmarks enthaelt.
3655 bAppend =
3656 pPam->GetPoint()->nContent.GetIndex() ||
3657 HasCurrentParaFlys() ||
3658 HasCurrentParaBookmarks();
3659 }
3660 if( bAppend )
3661 {
3662 if( !pPam->GetPoint()->nContent.GetIndex() )
3663 {
3664 pDoc->SetTxtFmtColl( *pPam,
3665 pCSS1Parser->GetTxtCollFromPool(RES_POOLCOLL_STANDARD) );
3666 SvxFontHeightItem aFontHeight( 40, 100, RES_CHRATR_FONTSIZE );
3667
3668 _HTMLAttr* pTmp =
3669 new _HTMLAttr( *pPam->GetPoint(), aFontHeight );
3670 aSetAttrTab.Insert( pTmp, aSetAttrTab.Count() );
3671
3672 aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE );
3673 pTmp = new _HTMLAttr( *pPam->GetPoint(), aFontHeight );
3674 aSetAttrTab.Insert( pTmp, aSetAttrTab.Count() );
3675
3676 aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE );
3677 pTmp = new _HTMLAttr( *pPam->GetPoint(), aFontHeight );
3678 aSetAttrTab.Insert( pTmp, aSetAttrTab.Count() );
3679
3680 pTmp = new _HTMLAttr( *pPam->GetPoint(),
3681 SvxULSpaceItem( 0, 0, RES_UL_SPACE ) );
3682 aSetAttrTab.Insert( pTmp, 0 ); // ja, 0, weil schon
3683 // vom Tabellenende vorher
3684 // was gesetzt sein kann.
3685 }
3686 AppendTxtNode( AM_NOSPACE );
3687 bAppended = sal_True;
3688 }
3689 else if( aParaAttrs.Count() )
3690 {
3691 if( !bForceFrame )
3692 {
3693 // Der Absatz wird gleich hinter die Tabelle
3694 // verschoben. Deshalb entfernen wir alle harten
3695 // Attribute des Absatzes
3696
3697 for( sal_uInt16 i=0; i<aParaAttrs.Count(); i++ )
3698 aParaAttrs[i]->Invalidate();
3699 }
3700
3701 aParaAttrs.Remove( 0, aParaAttrs.Count() );
3702 }
3703
3704 pSavePos = new SwPosition( *pPam->GetPoint() );
3705 }
3706 else if( pCurTable->HasParentSection() )
3707 {
3708 bParentLFStripped = StripTrailingLF() > 0;
3709
3710 // Absaetze bzw. ueberschriften beeenden
3711 nOpenParaToken = 0;
3712 nFontStHeadStart = nFontStMin;
3713
3714 // die harten Attribute an diesem Absatz werden nie mehr ungueltig
3715 if( aParaAttrs.Count() )
3716 aParaAttrs.Remove( 0, aParaAttrs.Count() );
3717 }
3718
3719 // einen Tabellen Kontext anlegen
3720 _HTMLTableContext *pTCntxt =
3721 new _HTMLTableContext( pSavePos, nContextStMin,
3722 nContextStAttrMin );
3723
3724 // alle noch offenen Attribute beenden und hinter der Tabelle
3725 // neu aufspannen
3726 _HTMLAttrs *pPostIts = 0;
3727 if( !bForceFrame && (bTopTable || pCurTable->HasParentSection()) )
3728 {
3729 SplitAttrTab( pTCntxt->aAttrTab, bTopTable );
3730 // Wenn wir einen schon vorhandenen Absatz verwenden, duerfen
3731 // in den keine PostIts eingefuegt werden, weil der Absatz
3732 // ja hinter die Tabelle wandert. Sie werden deshalb in den
3733 // ersten Absatz der Tabelle verschoben.
3734 // Bei Tabellen in Tabellen duerfen ebenfalls keine PostIts
3735 // in einen noch leeren Absatz eingefuegt werden, weil
3736 // der sonst nicht geloescht wird.
3737 if( (bTopTable && !bAppended) ||
3738 (!bTopTable && !bParentLFStripped &&
3739 !pPam->GetPoint()->nContent.GetIndex()) )
3740 pPostIts = new _HTMLAttrs;
3741 SetAttr( bTopTable, bTopTable, pPostIts );
3742 }
3743 else
3744 {
3745 SaveAttrTab( pTCntxt->aAttrTab );
3746 if( bTopTable && !bAppended )
3747 {
3748 pPostIts = new _HTMLAttrs;
3749 SetAttr( sal_True, sal_True, pPostIts );
3750 }
3751 }
3752 bNoParSpace = sal_False;
3753
3754 // Aktuelle Nummerierung retten und ausschalten.
3755 pTCntxt->SetNumInfo( GetNumInfo() );
3756 GetNumInfo().Clear();
3757 pTCntxt->SavePREListingXMP( *this );
3758
3759 if( bTopTable )
3760 {
3761 if( bForceFrame )
3762 {
3763 // Die Tabelle soll in einen Rahmen geschaufelt werden.
3764
3765 SfxItemSet aFrmSet( pDoc->GetAttrPool(),
3766 RES_FRMATR_BEGIN, RES_FRMATR_END-1 );
3767 if( !pCurTable->IsNewDoc() )
3768 Reader::ResetFrmFmtAttrs( aFrmSet );
3769
3770 SwSurround eSurround = SURROUND_NONE;
3771 sal_Int16 eHori;
3772
3773 switch( pCurTable->GetTableAdjust(sal_True) )
3774 {
3775 case SVX_ADJUST_RIGHT:
3776 eHori = text::HoriOrientation::RIGHT;
3777 eSurround = SURROUND_LEFT;
3778 break;
3779 case SVX_ADJUST_CENTER:
3780 eHori = text::HoriOrientation::CENTER;
3781 break;
3782 case SVX_ADJUST_LEFT:
3783 eSurround = SURROUND_RIGHT;
3784 default:
3785 eHori = text::HoriOrientation::LEFT;
3786 break;
3787 }
3788 SetAnchorAndAdjustment( text::VertOrientation::NONE, eHori, aFrmSet,
3789 sal_True );
3790 aFrmSet.Put( SwFmtSurround(eSurround) );
3791
3792 SwFmtFrmSize aFrmSize( ATT_VAR_SIZE, 20*MM50, MINLAY );
3793 aFrmSize.SetWidthPercent( 100 );
3794 aFrmSet.Put( aFrmSize );
3795
3796 sal_uInt16 nSpace = pCurTable->GetHSpace();
3797 if( nSpace )
3798 aFrmSet.Put( SvxLRSpaceItem(nSpace,nSpace, 0, 0, RES_LR_SPACE) );
3799 nSpace = pCurTable->GetVSpace();
3800 if( nSpace )
3801 aFrmSet.Put( SvxULSpaceItem(nSpace,nSpace, RES_UL_SPACE) );
3802
3803 RndStdIds eAnchorId = ((const SwFmtAnchor&)aFrmSet.
3804 Get( RES_ANCHOR )).
3805 GetAnchorId();
3806 SwFrmFmt *pFrmFmt = pDoc->MakeFlySection(
3807 eAnchorId, pPam->GetPoint(), &aFrmSet );
3808
3809 pTCntxt->SetFrmFmt( pFrmFmt );
3810 const SwFmtCntnt& rFlyCntnt = pFrmFmt->GetCntnt();
3811 pPam->GetPoint()->nNode = *rFlyCntnt.GetCntntIdx();
3812 SwCntntNode *pCNd =
3813 pDoc->GetNodes().GoNext( &(pPam->GetPoint()->nNode) );
3814 pPam->GetPoint()->nContent.Assign( pCNd, 0 );
3815
3816 // automatisch verankerte Rahmen muessen noch um
3817 // eine Position nach vorne verschoben werden.
3818 //if( FLY_AUTO_CNTNT==eAnchorId )
3819 // aMoveFlyFrms.C40_INSERT( SwFrmFmt, pFrmFmt,
3820 // aMoveFlyFrms.Count() );
3821 }
3822
3823 // eine SwTable mit einer Box anlegen und den PaM in den
3824 // Inhalt der Box-Section bewegen (der Ausrichtungs-Parameter
3825 // ist erstmal nur ein Dummy und wird spaeter noch richtig
3826 // gesetzt)
3827 ASSERT( !pPam->GetPoint()->nContent.GetIndex(),
3828 "Der Absatz hinter der Tabelle ist nicht leer!" );
3829 const SwTable* pSwTable = pDoc->InsertTable(
3830 SwInsertTableOptions( tabopts::HEADLINE_NO_BORDER, 1 ),
3831 *pPam->GetPoint(), 1, 1, text::HoriOrientation::LEFT );
3832
3833 if( bForceFrame )
3834 {
3835 SwNodeIndex aDstIdx( pPam->GetPoint()->nNode );
3836 pPam->Move( fnMoveBackward );
3837 pDoc->GetNodes().Delete( aDstIdx );
3838 }
3839 else
3840 {
3841 if( bStyleParsed )
3842 {
3843 pCSS1Parser->SetFmtBreak( aItemSet, aPropInfo );
3844 pSwTable->GetFrmFmt()->SetFmtAttr( aItemSet );
3845 }
3846 pPam->Move( fnMoveBackward );
3847 }
3848
3849 SwNode const*const pNd = & pPam->GetPoint()->nNode.GetNode();
3850 if( !bAppended && !bForceFrame )
3851 {
3852 SwTxtNode *const pOldTxtNd =
3853 pSavePos->nNode.GetNode().GetTxtNode();
3854 ASSERT( pOldTxtNd, "Wieso stehen wir in keinem Txt-Node?" );
3855 SwFrmFmt *pFrmFmt = pSwTable->GetFrmFmt();
3856
3857 const SfxPoolItem* pItem2;
3858 if( SFX_ITEM_SET == pOldTxtNd->GetSwAttrSet()
3859 .GetItemState( RES_PAGEDESC, sal_False, &pItem2 ) &&
3860 ((SwFmtPageDesc *)pItem2)->GetPageDesc() )
3861 {
3862 pFrmFmt->SetFmtAttr( *pItem2 );
3863 pOldTxtNd->ResetAttr( RES_PAGEDESC );
3864 }
3865 if( SFX_ITEM_SET == pOldTxtNd->GetSwAttrSet()
3866 .GetItemState( RES_BREAK, sal_True, &pItem2 ) )
3867 {
3868 switch( ((SvxFmtBreakItem *)pItem2)->GetBreak() )
3869 {
3870 case SVX_BREAK_PAGE_BEFORE:
3871 case SVX_BREAK_PAGE_AFTER:
3872 case SVX_BREAK_PAGE_BOTH:
3873 pFrmFmt->SetFmtAttr( *pItem2 );
3874 pOldTxtNd->ResetAttr( RES_BREAK );
3875 default:
3876 ;
3877 }
3878 }
3879 }
3880
3881 if( !bAppended && pPostIts )
3882 {
3883 // noch vorhandene PostIts in den ersten Absatz
3884 // der Tabelle setzen
3885 InsertAttrs( *pPostIts );
3886 delete pPostIts;
3887 pPostIts = 0;
3888 }
3889
3890 pTCntxt->SetTableNode( (SwTableNode *)pNd->FindTableNode() );
3891
3892 pCurTable->SetTable( pTCntxt->GetTableNode(), pTCntxt,
3893 nLeftSpace, nRightSpace,
3894 pSwTable, bForceFrame );
3895
3896 ASSERT( !pPostIts, "ubenutzte PostIts" );
3897 }
3898 else
3899 {
3900 // noch offene Bereiche muessen noch entfernt werden
3901 if( EndSections( bParentLFStripped ) )
3902 bParentLFStripped = sal_False;
3903
3904 if( pCurTable->HasParentSection() )
3905 {
3906 // danach entfernen wir ein ggf. zu viel vorhandenen
3907 // leeren Absatz, aber nur, wenn er schon vor dem
3908 // entfernen von LFs leer war
3909 if( !bParentLFStripped )
3910 StripTrailingPara();
3911
3912 if( pPostIts )
3913 {
3914 // noch vorhandene PostIts an das Ende des jetzt
3915 // aktuellen Absatzes schieben
3916 InsertAttrs( *pPostIts );
3917 delete pPostIts;
3918 pPostIts = 0;
3919 }
3920 }
3921
3922 SwNode const*const pNd = & pPam->GetPoint()->nNode.GetNode();
3923 const SwStartNode *pStNd = (pTable->bFirstCell ? pNd->FindTableNode()
3924 : pNd->FindTableBoxStartNode() );
3925
3926 pCurTable->SetTable( pStNd, pTCntxt, nLeftSpace, nRightSpace );
3927 }
3928
3929 // Den Kontext-Stack einfrieren, denn es koennen auch mal
3930 // irgendwo ausserhalb von Zellen Attribute gesetzt werden.
3931 // Darf nicht frueher passieren, weil eventuell noch im
3932 // Stack gesucht wird!!!
3933 nContextStMin = aContexts.Count();
3934 nContextStAttrMin = nContextStMin;
3935 }
3936
3937 pSaveStruct = new _CellSaveStruct( *this, pCurTable, bHead,
3938 bReadOptions );
3939
3940 // ist beim ersten GetNextToken schon pending, muss bei
3941 // wiederaufsetzen auf jeden Fall neu gelesen werden!
3942 SaveState( 0 );
3943 }
3944
3945 if( !nToken )
3946 nToken = GetNextToken(); // Token nach <TABLE>
3947
3948 sal_Bool bDone = sal_False;
3949 while( (IsParserWorking() && !bDone) || bPending )
3950 {
3951 SaveState( nToken );
3952
3953 nToken = FilterToken( nToken );
3954
3955 ASSERT( pPendStack || !bCallNextToken || pSaveStruct->IsInSection(),
3956 "Wo ist die Section gebieben?" );
3957 if( !pPendStack && bCallNextToken && pSaveStruct->IsInSection() )
3958 {
3959 // NextToken direkt aufrufen (z.B. um den Inhalt von
3960 // Floating-Frames oder Applets zu ignorieren)
3961 NextToken( nToken );
3962 }
3963 else switch( nToken )
3964 {
3965 case HTML_TABLEHEADER_ON:
3966 case HTML_TABLEDATA_ON:
3967 case HTML_TABLEROW_ON:
3968 case HTML_TABLEROW_OFF:
3969 case HTML_THEAD_ON:
3970 case HTML_THEAD_OFF:
3971 case HTML_TFOOT_ON:
3972 case HTML_TFOOT_OFF:
3973 case HTML_TBODY_ON:
3974 case HTML_TBODY_OFF:
3975 case HTML_TABLE_OFF:
3976 SkipToken(-1);
3977 case HTML_TABLEHEADER_OFF:
3978 case HTML_TABLEDATA_OFF:
3979 bDone = sal_True;
3980 break;
3981 case HTML_TABLE_ON:
3982 {
3983 sal_Bool bTopTable = sal_False;
3984 sal_Bool bHasToFly = sal_False;
3985 SvxAdjust eTabAdjust = SVX_ADJUST_END;
3986 if( !pPendStack )
3987 {
3988 // nur wenn eine neue Tabelle aufgemacht wird, aber
3989 // nicht wenn nach einem Pending in der Tabelle
3990 // weitergelesen wird!
3991 pSaveStruct->pTable = pTable;
3992
3993 // HACK: Eine Section fuer eine Tabelle anlegen, die
3994 // in einen Rahmen kommt.
3995 if( !pSaveStruct->IsInSection() )
3996 {
3997 // Diese Schleife muss vorwaerts sein, weil die
3998 // erste Option immer gewinnt.
3999 sal_Bool bNeedsSection = sal_False;
4000 const HTMLOptions *pHTMLOptions = GetOptions();
4001 for( sal_uInt16 i=0; i<pHTMLOptions->Count(); i++ )
4002 {
4003 const HTMLOption *pOption = (*pHTMLOptions)[i];
4004 if( HTML_O_ALIGN==pOption->GetToken() )
4005 {
4006 SvxAdjust eAdjust =
4007 (SvxAdjust)pOption->GetEnum(
4008 aHTMLPAlignTable, SVX_ADJUST_END );
4009 bNeedsSection = SVX_ADJUST_LEFT == eAdjust ||
4010 SVX_ADJUST_RIGHT == eAdjust;
4011 break;
4012 }
4013 }
4014 if( bNeedsSection )
4015 {
4016 pSaveStruct->AddContents(
4017 InsertTableContents(bHead ) );
4018 }
4019 }
4020 else
4021 {
4022 // Wenn wir mittlerweile in einem Rahmen stehen
4023 // koennen wir erneut eine echte Tabelle aufmachen.
4024 // Wir erkennen das daran, dass wir keinen
4025 // Tabellen-Node mehr finden.
4026 bTopTable = (0 ==
4027 pPam->GetPoint()->nNode.GetNode().FindTableNode());
4028
4029 // Wenn im aktuellen Absatz Flys verankert sind,
4030 // muss die neue Tabelle in einen Rahmen.
4031 bHasToFly = HasCurrentParaFlys(sal_False,sal_True);
4032 }
4033
4034 // in der Zelle kann sich ein Bereich befinden!
4035 eTabAdjust = aAttrTab.pAdjust
4036 ? ((const SvxAdjustItem&)aAttrTab.pAdjust->GetItem()).
4037 GetAdjust()
4038 : SVX_ADJUST_END;
4039 }
4040
4041 HTMLTable *pSubTable = BuildTable( eTabAdjust,
4042 bHead,
4043 pSaveStruct->IsInSection(),
4044 bTopTable, bHasToFly );
4045 if( SVPAR_PENDING != GetStatus() )
4046 {
4047 // nur wenn die Tabelle wirklich zu Ende ist!
4048 if( pSubTable )
4049 {
4050 ASSERT( pSubTable->GetTableAdjust(sal_False)!= SVX_ADJUST_LEFT &&
4051 pSubTable->GetTableAdjust(sal_False)!= SVX_ADJUST_RIGHT,
4052 "links oder rechts ausgerichtete Tabellen gehoehren in Rahmen" );
4053
4054
4055 HTMLTableCnts *pParentContents =
4056 pSubTable->GetParentContents();
4057 if( pParentContents )
4058 {
4059 ASSERT( !pSaveStruct->IsInSection(),
4060 "Wo ist die Section geblieben" );
4061
4062 // Wenn jetzt keine Tabelle kommt haben wir eine
4063 // Section
4064 pSaveStruct->AddContents( pParentContents );
4065 }
4066
4067 const SwStartNode *pCapStNd =
4068 pSubTable->GetCaptionStartNode();
4069
4070 if( pSubTable->GetContext() )
4071 {
4072 ASSERT( !pSubTable->GetContext()->GetFrmFmt(),
4073 "Tabelle steht im Rahmen" );
4074
4075 if( pCapStNd && pSubTable->IsTopCaption() )
4076 {
4077 pSaveStruct->AddContents(
4078 new HTMLTableCnts(pCapStNd) );
4079 }
4080
4081 pSaveStruct->AddContents(
4082 new HTMLTableCnts(pSubTable) );
4083
4084 if( pCapStNd && !pSubTable->IsTopCaption() )
4085 {
4086 pSaveStruct->AddContents(
4087 new HTMLTableCnts(pCapStNd) );
4088 }
4089
4090 // Jetzt haben wir keine Section mehr
4091 pSaveStruct->ClearIsInSection();
4092 }
4093 else if( pCapStNd )
4094 {
4095 // Da wir diese Section nicht mehr loeschen
4096 // koennen (sie koennte zur erster Box
4097 // gehoeren), fuegen wir sie ein.
4098 pSaveStruct->AddContents(
4099 new HTMLTableCnts(pCapStNd) );
4100
4101 // Jetzt haben wir keine Section mehr
4102 pSaveStruct->ClearIsInSection();
4103 }
4104 }
4105
4106 pTable = pSaveStruct->pTable;
4107 }
4108 }
4109 break;
4110
4111 case HTML_NOBR_ON:
4112 // HACK fuer MS: Steht das <NOBR> zu beginn der Zelle?
4113 pSaveStruct->StartNoBreak( *pPam->GetPoint() );
4114 break;
4115
4116 case HTML_NOBR_OFF:
4117 pSaveStruct->EndNoBreak( *pPam->GetPoint() );
4118 break;
4119
4120 case HTML_COMMENT:
4121 // Mit Kommentar-Feldern werden Spaces nicht mehr geloescht
4122 // ausserdem wollen wir fuer einen Kommentar keine neue Zelle
4123 // anlegen !!!
4124 NextToken( nToken );
4125 break;
4126
4127 case HTML_MARQUEE_ON:
4128 if( !pSaveStruct->IsInSection() )
4129 {
4130 // eine neue Section anlegen, der PaM steht dann darin
4131 pSaveStruct->AddContents(
4132 InsertTableContents( bHead ) );
4133 }
4134 bCallNextToken = sal_True;
4135 NewMarquee( pCurTable );
4136 break;
4137
4138 case HTML_TEXTTOKEN:
4139 // keine Section fuer einen leeren String anlegen
4140 if( !pSaveStruct->IsInSection() && 1==aToken.Len() &&
4141 ' '==aToken.GetChar(0) )
4142 break;
4143 default:
4144 if( !pSaveStruct->IsInSection() )
4145 {
4146 // eine neue Section anlegen, der PaM steht dann darin
4147 pSaveStruct->AddContents(
4148 InsertTableContents( bHead ) );
4149 }
4150
4151 if( IsParserWorking() || bPending )
4152 NextToken( nToken );
4153 break;
4154 }
4155
4156 ASSERT( !bPending || !pPendStack,
4157 "SwHTMLParser::BuildTableCell: Es gibt wieder einen Pend-Stack" );
4158 bPending = sal_False;
4159 if( IsParserWorking() )
4160 SaveState( 0 );
4161
4162 if( !bDone )
4163 nToken = GetNextToken();
4164 }
4165
4166 if( SVPAR_PENDING == GetStatus() )
4167 {
4168 pPendStack = new SwPendingStack( bHead ? HTML_TABLEHEADER_ON
4169 : HTML_TABLEDATA_ON, pPendStack );
4170 pPendStack->pData = pSaveStruct;
4171
4172 return;
4173 }
4174
4175 // Falls der Inhalt der Zelle leer war, muessen wir noch einen
4176 // leeren Inhalt anlegen. Ausserdem legen wir einen leeren Inhalt
4177 // an, wenn die Zelle mit einer Tabelle aufgehoert hat und keine
4178 // COL-Tags hatte (sonst wurde sie wahrscheinlich von uns exportiert,
4179 // und dann wollen wir natuerlich keinen zusaetzlichen Absatz haben).
4180 if( !pSaveStruct->GetFirstContents() ||
4181 (!pSaveStruct->IsInSection() && !pCurTable->HasColTags()) )
4182 {
4183 ASSERT( pSaveStruct->GetFirstContents() ||
4184 !pSaveStruct->IsInSection(),
4185 "Section oder nicht, das ist hier die Frage" );
4186 const SwStartNode *pStNd =
4187 InsertTableSection( static_cast< sal_uInt16 >(pSaveStruct->IsHeaderCell()
4188 ? RES_POOLCOLL_TABLE_HDLN
4189 : RES_POOLCOLL_TABLE ));
4190 const SwEndNode *pEndNd = pStNd->EndOfSectionNode();
4191 SwCntntNode *pCNd = pDoc->GetNodes()[pEndNd->GetIndex()-1] ->GetCntntNode();
4192 SvxFontHeightItem aFontHeight( 40, 100, RES_CHRATR_FONTSIZE );
4193 pCNd->SetAttr( aFontHeight );
4194 aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE );
4195 pCNd->SetAttr( aFontHeight );
4196 aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE );
4197 pCNd->SetAttr( aFontHeight );
4198
4199 pSaveStruct->AddContents( new HTMLTableCnts(pStNd) );
4200 pSaveStruct->ClearIsInSection();
4201 }
4202
4203 if( pSaveStruct->IsInSection() )
4204 {
4205 pSaveStruct->CheckNoBreak( *pPam->GetPoint(), pDoc );
4206
4207 // Alle noch offenen Kontexte beenden. Wir nehmen hier
4208 // AttrMin, weil nContxtStMin evtl. veraendert wurde.
4209 // Da es durch EndContext wieder restauriert wird, geht das.
4210 while( aContexts.Count() > nContextStAttrMin+1 )
4211 {
4212 _HTMLAttrContext *pCntxt = PopContext();
4213 EndContext( pCntxt );
4214 delete pCntxt;
4215 }
4216
4217 // LFs am Absatz-Ende entfernen
4218 if( StripTrailingLF()==0 && !pPam->GetPoint()->nContent.GetIndex() )
4219 StripTrailingPara();
4220
4221 // falls fuer die Zelle eine Ausrichtung gesetzt wurde, muessen
4222 // wir die beenden
4223 _HTMLAttrContext *pCntxt = PopContext();
4224 EndContext( pCntxt );
4225 delete pCntxt;
4226 }
4227 else
4228 {
4229 // Alle noch offenen Kontexte beenden
4230 while( aContexts.Count() > nContextStAttrMin )
4231 {
4232 _HTMLAttrContext *pCntxt = PopContext();
4233 ClearContext( pCntxt );
4234 delete pCntxt;
4235 }
4236 }
4237
4238 // auch eine Nummerierung muss beendet werden
4239 GetNumInfo().Clear();
4240
4241 SetAttr( sal_False );
4242
4243 pSaveStruct->InsertCell( *this, pCurTable );
4244
4245 // wir stehen jetzt (wahrschenlich) vor <TH>, <TD>, <TR> oder </TABLE>
4246 delete pSaveStruct;
4247 }
4248
4249
4250 class _RowSaveStruct : public SwPendingStackData
4251 {
4252 public:
4253 SvxAdjust eAdjust;
4254 sal_Int16 eVertOri;
4255 sal_Bool bHasCells;
4256
_RowSaveStruct()4257 _RowSaveStruct() :
4258 eAdjust( SVX_ADJUST_END ), eVertOri( text::VertOrientation::TOP ), bHasCells( sal_False )
4259 {}
4260 };
4261
4262
BuildTableRow(HTMLTable * pCurTable,sal_Bool bReadOptions,SvxAdjust eGrpAdjust,sal_Int16 eGrpVertOri)4263 void SwHTMLParser::BuildTableRow( HTMLTable *pCurTable, sal_Bool bReadOptions,
4264 SvxAdjust eGrpAdjust,
4265 sal_Int16 eGrpVertOri )
4266 {
4267 // <TR> wurde bereist gelesen
4268
4269 if( !IsParserWorking() && !pPendStack )
4270 return;
4271
4272 int nToken = 0;
4273 _RowSaveStruct* pSaveStruct;
4274
4275 sal_Bool bPending = sal_False;
4276 if( pPendStack )
4277 {
4278 pSaveStruct = (_RowSaveStruct*)pPendStack->pData;
4279
4280 SwPendingStack* pTmp = pPendStack->pNext;
4281 delete pPendStack;
4282 pPendStack = pTmp;
4283 nToken = pPendStack ? pPendStack->nToken : GetSaveToken();
4284 bPending = SVPAR_ERROR == eState && pPendStack != 0;
4285
4286 SaveState( nToken );
4287 }
4288 else
4289 {
4290 SvxAdjust eAdjust = eGrpAdjust;
4291 sal_Int16 eVertOri = eGrpVertOri;
4292 Color aBGColor;
4293 String aBGImage, aStyle, aId, aClass;
4294 sal_Bool bBGColor = sal_False;
4295 pSaveStruct = new _RowSaveStruct;
4296
4297 if( bReadOptions )
4298 {
4299 const HTMLOptions *pHTMLOptions = GetOptions();
4300 for( sal_uInt16 i = pHTMLOptions->Count(); i; )
4301 {
4302 const HTMLOption *pOption = (*pHTMLOptions)[--i];
4303 switch( pOption->GetToken() )
4304 {
4305 case HTML_O_ID:
4306 aId = pOption->GetString();
4307 break;
4308 case HTML_O_ALIGN:
4309 eAdjust = (SvxAdjust)pOption->GetEnum(
4310 aHTMLPAlignTable, static_cast< sal_uInt16 >(eAdjust) );
4311 break;
4312 case HTML_O_VALIGN:
4313 eVertOri = pOption->GetEnum(
4314 aHTMLTblVAlignTable, eVertOri );
4315 break;
4316 case HTML_O_BGCOLOR:
4317 // Leere BGCOLOR bei <TABLE>, <TR> und <TD>/<TH> wie Netsc.
4318 // ignorieren, bei allen anderen Tags *wirklich* nicht.
4319 if( pOption->GetString().Len() )
4320 {
4321 pOption->GetColor( aBGColor );
4322 bBGColor = sal_True;
4323 }
4324 break;
4325 case HTML_O_BACKGROUND:
4326 aBGImage = pOption->GetString();
4327 break;
4328 case HTML_O_STYLE:
4329 aStyle = pOption->GetString();
4330 break;
4331 case HTML_O_CLASS:
4332 aClass= pOption->GetString();
4333 break;
4334 }
4335 }
4336 }
4337
4338 if( aId.Len() )
4339 InsertBookmark( aId );
4340
4341 SvxBrushItem *pBrushItem =
4342 CreateBrushItem( bBGColor ? &aBGColor : 0, aBGImage, aStyle,
4343 aId, aClass );
4344 pCurTable->OpenRow( eAdjust, eVertOri, pBrushItem );
4345 // ist beim ersten GetNextToken schon pending, muss bei
4346 // wiederaufsetzen auf jeden Fall neu gelesen werden!
4347 SaveState( 0 );
4348 }
4349
4350 if( !nToken )
4351 nToken = GetNextToken(); // naechstes Token
4352
4353 sal_Bool bDone = sal_False;
4354 while( (IsParserWorking() && !bDone) || bPending )
4355 {
4356 SaveState( nToken );
4357
4358 nToken = FilterToken( nToken );
4359
4360 ASSERT( pPendStack || !bCallNextToken ||
4361 pCurTable->GetContext() || pCurTable->HasParentSection(),
4362 "Wo ist die Section gebieben?" );
4363 if( !pPendStack && bCallNextToken &&
4364 (pCurTable->GetContext() || pCurTable->HasParentSection()) )
4365 {
4366 // NextToken direkt aufrufen (z.B. um den Inhalt von
4367 // Floating-Frames oder Applets zu ignorieren)
4368 NextToken( nToken );
4369 }
4370 else switch( nToken )
4371 {
4372 case HTML_TABLE_ON:
4373 if( !pCurTable->GetContext() )
4374 {
4375 SkipToken( -1 );
4376 bDone = sal_True;
4377 }
4378 // else
4379 // {
4380 // NextToken( nToken );
4381 // }
4382 break;
4383 case HTML_TABLEROW_ON:
4384 case HTML_THEAD_ON:
4385 case HTML_THEAD_OFF:
4386 case HTML_TBODY_ON:
4387 case HTML_TBODY_OFF:
4388 case HTML_TFOOT_ON:
4389 case HTML_TFOOT_OFF:
4390 case HTML_TABLE_OFF:
4391 SkipToken( -1 );
4392 case HTML_TABLEROW_OFF:
4393 bDone = sal_True;
4394 break;
4395 case HTML_TABLEHEADER_ON:
4396 case HTML_TABLEDATA_ON:
4397 BuildTableCell( pCurTable, sal_True, HTML_TABLEHEADER_ON==nToken );
4398 if( SVPAR_PENDING != GetStatus() )
4399 {
4400 pSaveStruct->bHasCells = sal_True;
4401 bDone = pTable->IsOverflowing();
4402 }
4403 break;
4404 case HTML_CAPTION_ON:
4405 BuildTableCaption( pCurTable );
4406 bDone = pTable->IsOverflowing();
4407 break;
4408 case HTML_CAPTION_OFF:
4409 case HTML_TABLEHEADER_OFF:
4410 case HTML_TABLEDATA_OFF:
4411 case HTML_COLGROUP_ON:
4412 case HTML_COLGROUP_OFF:
4413 case HTML_COL_ON:
4414 case HTML_COL_OFF:
4415 // wo keine Zelle anfing kann auch keine aufhoeren, oder?
4416 // und die ganzen anderen Tokens haben hier auch nicht zu
4417 // suchen und machen nur die Tabelle kaputt
4418 break;
4419 case HTML_MULTICOL_ON:
4420 // spaltige Rahmen koennen wir hier leider nicht einfuegen
4421 break;
4422 case HTML_FORM_ON:
4423 NewForm( sal_False ); // keinen neuen Absatz aufmachen!
4424 break;
4425 case HTML_FORM_OFF:
4426 EndForm( sal_False ); // keinen neuen Absatz aufmachen!
4427 break;
4428 case HTML_COMMENT:
4429 NextToken( nToken );
4430 break;
4431 case HTML_MAP_ON:
4432 // eine Image-Map fuegt nichts ein, deshalb koennen wir sie
4433 // problemlos auch ohne Zelle parsen
4434 NextToken( nToken );
4435 break;
4436 case HTML_TEXTTOKEN:
4437 if( (pCurTable->GetContext() ||
4438 !pCurTable->HasParentSection()) &&
4439 1==aToken.Len() && ' '==aToken.GetChar(0) )
4440 break;
4441 default:
4442 pCurTable->MakeParentContents();
4443 NextToken( nToken );
4444 break;
4445 }
4446
4447 ASSERT( !bPending || !pPendStack,
4448 "SwHTMLParser::BuildTableRow: Es gibt wieder einen Pend-Stack" );
4449 bPending = sal_False;
4450 if( IsParserWorking() )
4451 SaveState( 0 );
4452
4453 if( !bDone )
4454 nToken = GetNextToken();
4455 }
4456
4457 if( SVPAR_PENDING == GetStatus() )
4458 {
4459 pPendStack = new SwPendingStack( HTML_TABLEROW_ON, pPendStack );
4460 pPendStack->pData = pSaveStruct;
4461 }
4462 else
4463 {
4464 pCurTable->CloseRow( !pSaveStruct->bHasCells );
4465 delete pSaveStruct;
4466 }
4467
4468 // wir stehen jetzt (wahrscheinlich) vor <TR> oder </TABLE>
4469 }
4470
BuildTableSection(HTMLTable * pCurTable,sal_Bool bReadOptions,sal_Bool bHead)4471 void SwHTMLParser::BuildTableSection( HTMLTable *pCurTable,
4472 sal_Bool bReadOptions,
4473 sal_Bool bHead )
4474 {
4475 // <THEAD>, <TBODY> bzw. <TFOOT> wurde bereits gelesen
4476 if( !IsParserWorking() && !pPendStack )
4477 return;
4478
4479 int nToken = 0;
4480 sal_Bool bPending = sal_False;
4481 _RowSaveStruct* pSaveStruct;
4482
4483 if( pPendStack )
4484 {
4485 pSaveStruct = (_RowSaveStruct*)pPendStack->pData;
4486
4487 SwPendingStack* pTmp = pPendStack->pNext;
4488 delete pPendStack;
4489 pPendStack = pTmp;
4490 nToken = pPendStack ? pPendStack->nToken : GetSaveToken();
4491 bPending = SVPAR_ERROR == eState && pPendStack != 0;
4492
4493 SaveState( nToken );
4494 }
4495 else
4496 {
4497 pSaveStruct = new _RowSaveStruct;
4498
4499 if( bReadOptions )
4500 {
4501 const HTMLOptions *pHTMLOptions = GetOptions();
4502 for( sal_uInt16 i = pHTMLOptions->Count(); i; )
4503 {
4504 const HTMLOption *pOption = (*pHTMLOptions)[--i];
4505 switch( pOption->GetToken() )
4506 {
4507 case HTML_O_ID:
4508 InsertBookmark( pOption->GetString() );
4509 break;
4510 case HTML_O_ALIGN:
4511 pSaveStruct->eAdjust =
4512 (SvxAdjust)pOption->GetEnum( aHTMLPAlignTable,
4513 static_cast< sal_uInt16 >(pSaveStruct->eAdjust) );
4514 break;
4515 case HTML_O_VALIGN:
4516 pSaveStruct->eVertOri =
4517 pOption->GetEnum( aHTMLTblVAlignTable,
4518 pSaveStruct->eVertOri );
4519 break;
4520 }
4521 }
4522 }
4523
4524 // ist beim ersten GetNextToken schon pending, muss bei
4525 // wiederaufsetzen auf jeden Fall neu gelesen werden!
4526 SaveState( 0 );
4527 }
4528
4529 if( !nToken )
4530 nToken = GetNextToken(); // naechstes Token
4531
4532 sal_Bool bDone = sal_False;
4533 while( (IsParserWorking() && !bDone) || bPending )
4534 {
4535 SaveState( nToken );
4536
4537 nToken = FilterToken( nToken );
4538
4539 ASSERT( pPendStack || !bCallNextToken ||
4540 pCurTable->GetContext() || pCurTable->HasParentSection(),
4541 "Wo ist die Section gebieben?" );
4542 if( !pPendStack && bCallNextToken &&
4543 (pCurTable->GetContext() || pCurTable->HasParentSection()) )
4544 {
4545 // NextToken direkt aufrufen (z.B. um den Inhalt von
4546 // Floating-Frames oder Applets zu ignorieren)
4547 NextToken( nToken );
4548 }
4549 else switch( nToken )
4550 {
4551 case HTML_TABLE_ON:
4552 if( !pCurTable->GetContext() )
4553 {
4554 SkipToken( -1 );
4555 bDone = sal_True;
4556 }
4557 // else
4558 // {
4559 // NextToken( nToken );
4560 // }
4561 break;
4562 case HTML_THEAD_ON:
4563 case HTML_TFOOT_ON:
4564 case HTML_TBODY_ON:
4565 case HTML_TABLE_OFF:
4566 SkipToken( -1 );
4567 case HTML_THEAD_OFF:
4568 case HTML_TBODY_OFF:
4569 case HTML_TFOOT_OFF:
4570 bDone = sal_True;
4571 break;
4572 case HTML_CAPTION_ON:
4573 BuildTableCaption( pCurTable );
4574 bDone = pTable->IsOverflowing();
4575 break;
4576 case HTML_CAPTION_OFF:
4577 break;
4578 case HTML_TABLEHEADER_ON:
4579 case HTML_TABLEDATA_ON:
4580 SkipToken( -1 );
4581 BuildTableRow( pCurTable, sal_False, pSaveStruct->eAdjust,
4582 pSaveStruct->eVertOri );
4583 bDone = pTable->IsOverflowing();
4584 break;
4585 case HTML_TABLEROW_ON:
4586 BuildTableRow( pCurTable, sal_True, pSaveStruct->eAdjust,
4587 pSaveStruct->eVertOri );
4588 bDone = pTable->IsOverflowing();
4589 break;
4590 case HTML_MULTICOL_ON:
4591 // spaltige Rahmen koennen wir hier leider nicht einfuegen
4592 break;
4593 case HTML_FORM_ON:
4594 NewForm( sal_False ); // keinen neuen Absatz aufmachen!
4595 break;
4596 case HTML_FORM_OFF:
4597 EndForm( sal_False ); // keinen neuen Absatz aufmachen!
4598 break;
4599 case HTML_TEXTTOKEN:
4600 // Blank-Strings sind Folge von CR+LF und kein Text
4601 if( (pCurTable->GetContext() ||
4602 !pCurTable->HasParentSection()) &&
4603 1==aToken.Len() && ' '==aToken.GetChar(0) )
4604 break;
4605 default:
4606 pCurTable->MakeParentContents();
4607 NextToken( nToken );
4608 }
4609
4610 ASSERT( !bPending || !pPendStack,
4611 "SwHTMLParser::BuildTableSection: Es gibt wieder einen Pend-Stack" );
4612 bPending = sal_False;
4613 if( IsParserWorking() )
4614 SaveState( 0 );
4615
4616 if( !bDone )
4617 nToken = GetNextToken();
4618 }
4619
4620 if( SVPAR_PENDING == GetStatus() )
4621 {
4622 pPendStack = new SwPendingStack( bHead ? HTML_THEAD_ON
4623 : HTML_TBODY_ON, pPendStack );
4624 pPendStack->pData = pSaveStruct;
4625 }
4626 else
4627 {
4628 pCurTable->CloseSection( bHead );
4629 delete pSaveStruct;
4630 }
4631
4632 // wir stehen jetzt (wahrscheinlich) vor <TBODY>,... oder </TABLE>
4633 }
4634
4635 struct _TblColGrpSaveStruct : public SwPendingStackData
4636 {
4637 sal_uInt16 nColGrpSpan;
4638 sal_uInt16 nColGrpWidth;
4639 sal_Bool bRelColGrpWidth;
4640 SvxAdjust eColGrpAdjust;
4641 sal_Int16 eColGrpVertOri;
4642
4643 inline _TblColGrpSaveStruct();
4644
4645
4646 inline void CloseColGroup( HTMLTable *pTable );
4647 };
4648
_TblColGrpSaveStruct()4649 inline _TblColGrpSaveStruct::_TblColGrpSaveStruct() :
4650 nColGrpSpan( 1 ), nColGrpWidth( 0 ),
4651 bRelColGrpWidth( sal_False ), eColGrpAdjust( SVX_ADJUST_END ),
4652 eColGrpVertOri( text::VertOrientation::TOP )
4653 {}
4654
4655
CloseColGroup(HTMLTable * pTable)4656 inline void _TblColGrpSaveStruct::CloseColGroup( HTMLTable *pTable )
4657 {
4658 pTable->CloseColGroup( nColGrpSpan, nColGrpWidth,
4659 bRelColGrpWidth, eColGrpAdjust, eColGrpVertOri );
4660 }
4661
BuildTableColGroup(HTMLTable * pCurTable,sal_Bool bReadOptions)4662 void SwHTMLParser::BuildTableColGroup( HTMLTable *pCurTable,
4663 sal_Bool bReadOptions )
4664 {
4665 // <COLGROUP> wurde bereits gelesen, wenn bReadOptions
4666
4667 if( !IsParserWorking() && !pPendStack )
4668 return;
4669
4670 int nToken = 0;
4671 sal_Bool bPending = sal_False;
4672 _TblColGrpSaveStruct* pSaveStruct;
4673
4674 if( pPendStack )
4675 {
4676 pSaveStruct = (_TblColGrpSaveStruct*)pPendStack->pData;
4677
4678 SwPendingStack* pTmp = pPendStack->pNext;
4679 delete pPendStack;
4680 pPendStack = pTmp;
4681 nToken = pPendStack ? pPendStack->nToken : GetSaveToken();
4682 bPending = SVPAR_ERROR == eState && pPendStack != 0;
4683
4684 SaveState( nToken );
4685 }
4686 else
4687 {
4688
4689 pSaveStruct = new _TblColGrpSaveStruct;
4690 if( bReadOptions )
4691 {
4692 const HTMLOptions *pColGrpOptions = GetOptions();
4693 for( sal_uInt16 i = pColGrpOptions->Count(); i; )
4694 {
4695 const HTMLOption *pColGrpOption = (*pColGrpOptions)[--i];
4696 switch( pColGrpOption->GetToken() )
4697 {
4698 case HTML_O_ID:
4699 InsertBookmark( pColGrpOption->GetString() );
4700 break;
4701 case HTML_O_SPAN:
4702 pSaveStruct->nColGrpSpan = (sal_uInt16)pColGrpOption->GetNumber();
4703 break;
4704 case HTML_O_WIDTH:
4705 pSaveStruct->nColGrpWidth = (sal_uInt16)pColGrpOption->GetNumber();
4706 pSaveStruct->bRelColGrpWidth =
4707 (pColGrpOption->GetString().Search('*') != STRING_NOTFOUND);
4708 break;
4709 case HTML_O_ALIGN:
4710 pSaveStruct->eColGrpAdjust =
4711 (SvxAdjust)pColGrpOption->GetEnum( aHTMLPAlignTable,
4712 static_cast< sal_uInt16 >(pSaveStruct->eColGrpAdjust) );
4713 break;
4714 case HTML_O_VALIGN:
4715 pSaveStruct->eColGrpVertOri =
4716 pColGrpOption->GetEnum( aHTMLTblVAlignTable,
4717 pSaveStruct->eColGrpVertOri );
4718 break;
4719 }
4720 }
4721 }
4722 // ist beim ersten GetNextToken schon pending, muss bei
4723 // wiederaufsetzen auf jeden Fall neu gelesen werden!
4724 SaveState( 0 );
4725 }
4726
4727 if( !nToken )
4728 nToken = GetNextToken(); // naechstes Token
4729
4730 sal_Bool bDone = sal_False;
4731 while( (IsParserWorking() && !bDone) || bPending )
4732 {
4733 SaveState( nToken );
4734
4735 nToken = FilterToken( nToken );
4736
4737 ASSERT( pPendStack || !bCallNextToken ||
4738 pCurTable->GetContext() || pCurTable->HasParentSection(),
4739 "Wo ist die Section gebieben?" );
4740 if( !pPendStack && bCallNextToken &&
4741 (pCurTable->GetContext() || pCurTable->HasParentSection()) )
4742 {
4743 // NextToken direkt aufrufen (z.B. um den Inhalt von
4744 // Floating-Frames oder Applets zu ignorieren)
4745 NextToken( nToken );
4746 }
4747 else switch( nToken )
4748 {
4749 case HTML_TABLE_ON:
4750 if( !pCurTable->GetContext() )
4751 {
4752 SkipToken( -1 );
4753 bDone = sal_True;
4754 }
4755 // else
4756 // {
4757 // NextToken( nToken );
4758 // }
4759 break;
4760 case HTML_COLGROUP_ON:
4761 case HTML_THEAD_ON:
4762 case HTML_TFOOT_ON:
4763 case HTML_TBODY_ON:
4764 case HTML_TABLEROW_ON:
4765 case HTML_TABLE_OFF:
4766 SkipToken( -1 );
4767 case HTML_COLGROUP_OFF:
4768 bDone = sal_True;
4769 break;
4770 case HTML_COL_ON:
4771 {
4772 sal_uInt16 nColSpan = 1;
4773 sal_uInt16 nColWidth = pSaveStruct->nColGrpWidth;
4774 sal_Bool bRelColWidth = pSaveStruct->bRelColGrpWidth;
4775 SvxAdjust eColAdjust = pSaveStruct->eColGrpAdjust;
4776 sal_Int16 eColVertOri = pSaveStruct->eColGrpVertOri;
4777
4778 const HTMLOptions *pColOptions = GetOptions();
4779 for( sal_uInt16 i = pColOptions->Count(); i; )
4780 {
4781 const HTMLOption *pColOption = (*pColOptions)[--i];
4782 switch( pColOption->GetToken() )
4783 {
4784 case HTML_O_ID:
4785 InsertBookmark( pColOption->GetString() );
4786 break;
4787 case HTML_O_SPAN:
4788 nColSpan = (sal_uInt16)pColOption->GetNumber();
4789 break;
4790 case HTML_O_WIDTH:
4791 nColWidth = (sal_uInt16)pColOption->GetNumber();
4792 bRelColWidth =
4793 (pColOption->GetString().Search('*') != STRING_NOTFOUND);
4794 break;
4795 case HTML_O_ALIGN:
4796 eColAdjust =
4797 (SvxAdjust)pColOption->GetEnum( aHTMLPAlignTable,
4798 static_cast< sal_uInt16 >(eColAdjust) );
4799 break;
4800 case HTML_O_VALIGN:
4801 eColVertOri =
4802 pColOption->GetEnum( aHTMLTblVAlignTable,
4803 eColVertOri );
4804 break;
4805 }
4806 }
4807 pCurTable->InsertCol( nColSpan, nColWidth, bRelColWidth,
4808 eColAdjust, eColVertOri );
4809
4810 // die Angaben in <COLGRP> sollen ignoriert werden, wenn
4811 // <COL>-Elemente existieren
4812 pSaveStruct->nColGrpSpan = 0;
4813 }
4814 break;
4815 case HTML_COL_OFF:
4816 break; // Ignorieren
4817 case HTML_MULTICOL_ON:
4818 // spaltige Rahmen koennen wir hier leider nicht einfuegen
4819 break;
4820 case HTML_TEXTTOKEN:
4821 if( (pCurTable->GetContext() ||
4822 !pCurTable->HasParentSection()) &&
4823 1==aToken.Len() && ' '==aToken.GetChar(0) )
4824 break;
4825 default:
4826 pCurTable->MakeParentContents();
4827 NextToken( nToken );
4828 }
4829
4830 ASSERT( !bPending || !pPendStack,
4831 "SwHTMLParser::BuildTableColGrp: Es gibt wieder einen Pend-Stack" );
4832 bPending = sal_False;
4833 if( IsParserWorking() )
4834 SaveState( 0 );
4835
4836 if( !bDone )
4837 nToken = GetNextToken();
4838 }
4839
4840 if( SVPAR_PENDING == GetStatus() )
4841 {
4842 pPendStack = new SwPendingStack( HTML_COL_ON, pPendStack );
4843 pPendStack->pData = pSaveStruct;
4844 }
4845 else
4846 {
4847 pSaveStruct->CloseColGroup( pCurTable );
4848 delete pSaveStruct;
4849 }
4850 }
4851
4852 class _CaptionSaveStruct : public _SectionSaveStruct
4853 {
4854 SwPosition aSavePos;
4855 SwHTMLNumRuleInfo aNumRuleInfo; // gueltige Nummerierung
4856
4857 public:
4858
4859 _HTMLAttrTable aAttrTab; // und die Attribute
4860
_CaptionSaveStruct(SwHTMLParser & rParser,const SwPosition & rPos)4861 _CaptionSaveStruct( SwHTMLParser& rParser, const SwPosition& rPos ) :
4862 _SectionSaveStruct( rParser ), aSavePos( rPos )
4863 {
4864 rParser.SaveAttrTab( aAttrTab );
4865
4866 // Die aktuelle Nummerierung wurde gerettet und muss nur
4867 // noch beendet werden.
4868 aNumRuleInfo.Set( rParser.GetNumInfo() );
4869 rParser.GetNumInfo().Clear();
4870 }
4871
GetPos() const4872 const SwPosition& GetPos() const { return aSavePos; }
4873
RestoreAll(SwHTMLParser & rParser)4874 void RestoreAll( SwHTMLParser& rParser )
4875 {
4876 // Die alten Stack wiederherstellen
4877 Restore( rParser );
4878
4879 // Die alte Attribut-Tabelle wiederherstellen
4880 rParser.RestoreAttrTab( aAttrTab );
4881
4882 // Die alte Nummerierung wieder aufspannen
4883 rParser.GetNumInfo().Set( aNumRuleInfo );
4884 }
4885
4886 virtual ~_CaptionSaveStruct();
4887 };
4888
~_CaptionSaveStruct()4889 _CaptionSaveStruct::~_CaptionSaveStruct()
4890 {}
4891
BuildTableCaption(HTMLTable * pCurTable)4892 void SwHTMLParser::BuildTableCaption( HTMLTable *pCurTable )
4893 {
4894 // <CAPTION> wurde bereits gelesen
4895
4896 if( !IsParserWorking() && !pPendStack )
4897 return;
4898
4899 int nToken = 0;
4900 _CaptionSaveStruct* pSaveStruct;
4901
4902 if( pPendStack )
4903 {
4904 pSaveStruct = (_CaptionSaveStruct*)pPendStack->pData;
4905
4906 SwPendingStack* pTmp = pPendStack->pNext;
4907 delete pPendStack;
4908 pPendStack = pTmp;
4909 nToken = pPendStack ? pPendStack->nToken : GetSaveToken();
4910 ASSERT( !pPendStack, "Wo kommt hier ein Pending-Stack her?" );
4911
4912 SaveState( nToken );
4913 }
4914 else
4915 {
4916 if( pTable->IsOverflowing() )
4917 {
4918 SaveState( 0 );
4919 return;
4920 }
4921
4922 sal_Bool bTop = sal_True;
4923 const HTMLOptions *pHTMLOptions = GetOptions();
4924 for ( sal_uInt16 i = pHTMLOptions->Count(); i; )
4925 {
4926 const HTMLOption *pOption = (*pHTMLOptions)[--i];
4927 if( HTML_O_ALIGN == pOption->GetToken() )
4928 {
4929 if( pOption->GetString().EqualsIgnoreCaseAscii(OOO_STRING_SVTOOLS_HTML_VA_bottom))
4930 bTop = sal_False;
4931 }
4932 }
4933
4934 // Alte PaM-Position retten.
4935 pSaveStruct = new _CaptionSaveStruct( *this, *pPam->GetPoint() );
4936
4937 // Eine Text-Section im Icons-Bereich als Container fuer die
4938 // Ueberschrift anlegen und PaM dort reinstellen.
4939 const SwStartNode *pStNd;
4940 if( pTable == pCurTable )
4941 pStNd = InsertTempTableCaptionSection();
4942 else
4943 pStNd = InsertTableSection( RES_POOLCOLL_TEXT );
4944
4945 _HTMLAttrContext *pCntxt = new _HTMLAttrContext( HTML_CAPTION_ON );
4946
4947 // Tabellen-Ueberschriften sind immer zentriert.
4948 NewAttr( &aAttrTab.pAdjust, SvxAdjustItem(SVX_ADJUST_CENTER, RES_PARATR_ADJUST) );
4949
4950 _HTMLAttrs &rAttrs = pCntxt->GetAttrs();
4951 rAttrs.Insert( aAttrTab.pAdjust, rAttrs.Count() );
4952
4953 PushContext( pCntxt );
4954
4955 // StartNode der Section an der Tabelle merken.
4956 pCurTable->SetCaption( pStNd, bTop );
4957
4958 // ist beim ersten GetNextToken schon pending, muss bei
4959 // wiederaufsetzen auf jeden Fall neu gelesen werden!
4960 SaveState( 0 );
4961 }
4962
4963 if( !nToken )
4964 nToken = GetNextToken(); // naechstes Token
4965
4966 // </CAPTION> wird laut DTD benoetigt
4967 sal_Bool bDone = sal_False;
4968 while( IsParserWorking() && !bDone )
4969 {
4970 SaveState( nToken );
4971
4972 nToken = FilterToken( nToken );
4973
4974 switch( nToken )
4975 {
4976 case HTML_TABLE_ON:
4977 if( !pPendStack )
4978 {
4979 pSaveStruct->pTable = pTable;
4980 sal_Bool bHasToFly = pSaveStruct->pTable!=pCurTable;
4981 BuildTable( pCurTable->GetTableAdjust( sal_True ),
4982 sal_False, sal_True, sal_True, bHasToFly );
4983 }
4984 else
4985 {
4986 BuildTable( SVX_ADJUST_END );
4987 }
4988 if( SVPAR_PENDING != GetStatus() )
4989 {
4990 pTable = pSaveStruct->pTable;
4991 }
4992 break;
4993 case HTML_TABLE_OFF:
4994 case HTML_COLGROUP_ON:
4995 case HTML_THEAD_ON:
4996 case HTML_TFOOT_ON:
4997 case HTML_TBODY_ON:
4998 case HTML_TABLEROW_ON:
4999 SkipToken( -1 );
5000 bDone = sal_True;
5001 break;
5002
5003 case HTML_CAPTION_OFF:
5004 bDone = sal_True;
5005 break;
5006 default:
5007 int nNxtToken = nToken;
5008 if( pPendStack )
5009 {
5010 SwPendingStack* pTmp = pPendStack->pNext;
5011 delete pPendStack;
5012 pPendStack = pTmp;
5013
5014 ASSERT( !pTmp, "weiter kann es nicht gehen!" );
5015 nNxtToken = 0; // neu lesen
5016 }
5017
5018 if( IsParserWorking() )
5019 NextToken( nToken );
5020 break;
5021 }
5022
5023 if( IsParserWorking() )
5024 SaveState( 0 );
5025
5026 if( !bDone )
5027 nToken = GetNextToken();
5028 }
5029
5030 if( SVPAR_PENDING==GetStatus() )
5031 {
5032 pPendStack = new SwPendingStack( HTML_CAPTION_ON, pPendStack );
5033 pPendStack->pData = pSaveStruct;
5034 return;
5035 }
5036
5037 // Alle noch offenen Kontexte beenden
5038 while( aContexts.Count() > nContextStAttrMin+1 )
5039 {
5040 _HTMLAttrContext *pCntxt = PopContext();
5041 EndContext( pCntxt );
5042 delete pCntxt;
5043 }
5044
5045 // LF am Absatz-Ende entfernen
5046 sal_Bool bLFStripped = StripTrailingLF() > 0;
5047
5048 if( pTable==pCurTable )
5049 {
5050 // Beim spaeteren verschieben der Beschriftung vor oder hinter
5051 // die Tabelle wird der letzte Absatz nicht mitverschoben.
5052 // Deshalb muss sich am Ende der Section immer ein leerer
5053 // Absatz befinden.
5054 if( pPam->GetPoint()->nContent.GetIndex() || bLFStripped )
5055 AppendTxtNode( AM_NOSPACE );
5056 }
5057 else
5058 {
5059 // LFs am Absatz-Ende entfernen
5060 if( !pPam->GetPoint()->nContent.GetIndex() && !bLFStripped )
5061 StripTrailingPara();
5062 }
5063
5064 // falls fuer die Zelle eine Ausrichtung gesetzt wurde, muessen
5065 // wir die beenden
5066 _HTMLAttrContext *pCntxt = PopContext();
5067 EndContext( pCntxt );
5068 delete pCntxt;
5069
5070 SetAttr( sal_False );
5071
5072 // Stacks und Attribut-Tabelle wiederherstellen
5073 pSaveStruct->RestoreAll( *this );
5074
5075 // PaM wiederherstellen.
5076 *pPam->GetPoint() = pSaveStruct->GetPos();
5077
5078 delete pSaveStruct;
5079 }
5080
5081 class _TblSaveStruct : public SwPendingStackData
5082 {
5083 public:
5084 HTMLTable *pCurTable;
5085
_TblSaveStruct(HTMLTable * pCurTbl)5086 _TblSaveStruct( HTMLTable *pCurTbl ) :
5087 pCurTable( pCurTbl )
5088 {}
5089
5090 virtual ~_TblSaveStruct();
5091
5092 // Aufbau der Tabelle anstossen und die Tabelle ggf. in einen
5093 // Rahmen packen. Wenn sal_True zurueckgegeben wird muss noch ein
5094 // Absatz eingefuegt werden!
5095 void MakeTable( sal_uInt16 nWidth, SwPosition& rPos, SwDoc *pDoc );
5096 };
5097
~_TblSaveStruct()5098 _TblSaveStruct::~_TblSaveStruct()
5099 {}
5100
5101
MakeTable(sal_uInt16 nWidth,SwPosition & rPos,SwDoc * pDoc)5102 void _TblSaveStruct::MakeTable( sal_uInt16 nWidth, SwPosition& rPos, SwDoc *pDoc )
5103 {
5104 pCurTable->MakeTable( 0, nWidth );
5105
5106 _HTMLTableContext *pTCntxt = pCurTable->GetContext();
5107 ASSERT( pTCntxt, "Wo ist der Tabellen-Kontext" );
5108
5109 SwTableNode *pTblNd = pTCntxt->GetTableNode();
5110 ASSERT( pTblNd, "Wo ist der Tabellen-Node" );
5111
5112 if( pDoc->GetCurrentViewShell() && pTblNd ) //swmod 071108//swmod 071225
5113 {
5114 // Existiert schon ein Layout, dann muss an dieser Tabelle die
5115 // BoxFrames neu erzeugt werden.
5116
5117 if( pTCntxt->GetFrmFmt() )
5118 {
5119 pTCntxt->GetFrmFmt()->DelFrms();
5120 pTblNd->DelFrms();
5121 pTCntxt->GetFrmFmt()->MakeFrms();
5122 }
5123 else
5124 {
5125 pTblNd->DelFrms();
5126 SwNodeIndex aIdx( *pTblNd->EndOfSectionNode(), 1 );
5127 ASSERT( aIdx.GetIndex() <= pTCntxt->GetPos()->nNode.GetIndex(),
5128 "unerwarteter Node fuer das Tabellen-Layout" );
5129 pTblNd->MakeFrms( &aIdx );
5130 }
5131 }
5132
5133 rPos = *pTCntxt->GetPos();
5134 }
5135
5136
HTMLTableOptions(const HTMLOptions * pOptions,SvxAdjust eParentAdjust)5137 HTMLTableOptions::HTMLTableOptions( const HTMLOptions *pOptions,
5138 SvxAdjust eParentAdjust ) :
5139 nCols( 0 ),
5140 nWidth( 0 ), nHeight( 0 ),
5141 nCellPadding( USHRT_MAX ), nCellSpacing( USHRT_MAX ),
5142 nBorder( USHRT_MAX ),
5143 nHSpace( 0 ), nVSpace( 0 ),
5144 eAdjust( eParentAdjust ), eVertOri( text::VertOrientation::CENTER ),
5145 eFrame( HTML_TF_VOID ), eRules( HTML_TR_NONE ),
5146 bPrcWidth( sal_False ),
5147 bTableAdjust( sal_False ),
5148 bBGColor( sal_False ),
5149 aBorderColor( COL_GRAY )
5150 {
5151 sal_Bool bBorderColor = sal_False;
5152 sal_Bool bHasFrame = sal_False, bHasRules = sal_False;
5153
5154 for( sal_uInt16 i = pOptions->Count(); i; )
5155 {
5156 const HTMLOption *pOption = (*pOptions)[--i];
5157 switch( pOption->GetToken() )
5158 {
5159 case HTML_O_ID:
5160 aId = pOption->GetString();
5161 break;
5162 case HTML_O_COLS:
5163 nCols = (sal_uInt16)pOption->GetNumber();
5164 break;
5165 case HTML_O_WIDTH:
5166 nWidth = (sal_uInt16)pOption->GetNumber();
5167 bPrcWidth = (pOption->GetString().Search('%') != STRING_NOTFOUND);
5168 if( bPrcWidth && nWidth>100 )
5169 nWidth = 100;
5170 break;
5171 case HTML_O_HEIGHT:
5172 nHeight = (sal_uInt16)pOption->GetNumber();
5173 if( pOption->GetString().Search('%') != STRING_NOTFOUND )
5174 nHeight = 0; // keine %-Angaben benutzen!!!
5175 break;
5176 case HTML_O_CELLPADDING:
5177 nCellPadding = (sal_uInt16)pOption->GetNumber();
5178 break;
5179 case HTML_O_CELLSPACING:
5180 nCellSpacing = (sal_uInt16)pOption->GetNumber();
5181 break;
5182 case HTML_O_ALIGN:
5183 {
5184 sal_uInt16 nAdjust = static_cast< sal_uInt16 >(eAdjust);
5185 if( pOption->GetEnum( nAdjust, aHTMLPAlignTable ) )
5186 {
5187 eAdjust = (SvxAdjust)nAdjust;
5188 bTableAdjust = sal_True;
5189 }
5190 }
5191 break;
5192 case HTML_O_VALIGN:
5193 eVertOri = pOption->GetEnum( aHTMLTblVAlignTable, eVertOri );
5194 break;
5195 case HTML_O_BORDER:
5196 // BORDER und BORDER=BORDER wie BORDER=1 behandeln
5197 if( pOption->GetString().Len() &&
5198 !pOption->GetString().EqualsIgnoreCaseAscii(OOO_STRING_SVTOOLS_HTML_O_border) )
5199 nBorder = (sal_uInt16)pOption->GetNumber();
5200 else
5201 nBorder = 1;
5202
5203 if( !bHasFrame )
5204 eFrame = ( nBorder ? HTML_TF_BOX : HTML_TF_VOID );
5205 if( !bHasRules )
5206 eRules = ( nBorder ? HTML_TR_ALL : HTML_TR_NONE );
5207 break;
5208 case HTML_O_FRAME:
5209 eFrame = pOption->GetTableFrame();
5210 bHasFrame = sal_True;
5211 break;
5212 case HTML_O_RULES:
5213 eRules = pOption->GetTableRules();
5214 bHasRules = sal_True;
5215 break;
5216 case HTML_O_BGCOLOR:
5217 // Leere BGCOLOR bei <TABLE>, <TR> und <TD>/<TH> wie Netscape
5218 // ignorieren, bei allen anderen Tags *wirklich* nicht.
5219 if( pOption->GetString().Len() )
5220 {
5221 pOption->GetColor( aBGColor );
5222 bBGColor = sal_True;
5223 }
5224 break;
5225 case HTML_O_BACKGROUND:
5226 aBGImage = pOption->GetString();
5227 break;
5228 case HTML_O_BORDERCOLOR:
5229 pOption->GetColor( aBorderColor );
5230 bBorderColor = sal_True;
5231 break;
5232 case HTML_O_BORDERCOLORDARK:
5233 if( !bBorderColor )
5234 pOption->GetColor( aBorderColor );
5235 break;
5236 case HTML_O_STYLE:
5237 aStyle = pOption->GetString();
5238 break;
5239 case HTML_O_CLASS:
5240 aClass = pOption->GetString();
5241 break;
5242 case HTML_O_DIR:
5243 aDir = pOption->GetString();
5244 break;
5245 case HTML_O_HSPACE:
5246 nHSpace = (sal_uInt16)pOption->GetNumber();
5247 break;
5248 case HTML_O_VSPACE:
5249 nVSpace = (sal_uInt16)pOption->GetNumber();
5250 break;
5251 }
5252 }
5253
5254 if( nCols && !nWidth )
5255 {
5256 nWidth = 100;
5257 bPrcWidth = sal_True;
5258 }
5259
5260 // Wenn BORDER=0 oder kein BORDER gegeben ist, dann darf es auch
5261 // keine Umrandung geben
5262 if( 0==nBorder || USHRT_MAX==nBorder )
5263 {
5264 eFrame = HTML_TF_VOID;
5265 eRules = HTML_TR_NONE;
5266 }
5267 }
5268
5269
BuildTable(SvxAdjust eParentAdjust,sal_Bool bIsParentHead,sal_Bool bHasParentSection,sal_Bool bMakeTopSubTable,sal_Bool bHasToFly)5270 HTMLTable *SwHTMLParser::BuildTable( SvxAdjust eParentAdjust,
5271 sal_Bool bIsParentHead,
5272 sal_Bool bHasParentSection,
5273 sal_Bool bMakeTopSubTable,
5274 sal_Bool bHasToFly )
5275 {
5276 if( !IsParserWorking() && !pPendStack )
5277 return 0;
5278
5279 int nToken = 0;
5280 sal_Bool bPending = sal_False;
5281 _TblSaveStruct* pSaveStruct;
5282
5283 if( pPendStack )
5284 {
5285 pSaveStruct = (_TblSaveStruct*)pPendStack->pData;
5286
5287 SwPendingStack* pTmp = pPendStack->pNext;
5288 delete pPendStack;
5289 pPendStack = pTmp;
5290 nToken = pPendStack ? pPendStack->nToken : GetSaveToken();
5291 bPending = SVPAR_ERROR == eState && pPendStack != 0;
5292
5293 SaveState( nToken );
5294 }
5295 else
5296 {
5297 pTable = 0;
5298 HTMLTableOptions *pTblOptions =
5299 new HTMLTableOptions( GetOptions(), eParentAdjust );
5300
5301 if( pTblOptions->aId.Len() )
5302 InsertBookmark( pTblOptions->aId );
5303
5304 HTMLTable *pCurTable = new HTMLTable( this, pTable,
5305 bIsParentHead,
5306 bHasParentSection,
5307 bMakeTopSubTable,
5308 bHasToFly,
5309 pTblOptions );
5310 if( !pTable )
5311 pTable = pCurTable;
5312
5313 pSaveStruct = new _TblSaveStruct( pCurTable );
5314
5315 delete pTblOptions;
5316
5317 // ist beim ersten GetNextToken schon pending, muss bei
5318 // wiederaufsetzen auf jeden Fall neu gelesen werden!
5319 SaveState( 0 );
5320 }
5321
5322 HTMLTable *pCurTable = pSaveStruct->pCurTable;
5323
5324 // </TABLE> wird laut DTD benoetigt
5325 if( !nToken )
5326 nToken = GetNextToken(); // naechstes Token
5327
5328 sal_Bool bDone = sal_False;
5329 while( (IsParserWorking() && !bDone) || bPending )
5330 {
5331 SaveState( nToken );
5332
5333 nToken = FilterToken( nToken );
5334
5335 ASSERT( pPendStack || !bCallNextToken ||
5336 pCurTable->GetContext() || pCurTable->HasParentSection(),
5337 "Wo ist die Section gebieben?" );
5338 if( !pPendStack && bCallNextToken &&
5339 (pCurTable->GetContext() || pCurTable->HasParentSection()) )
5340 {
5341 // NextToken direkt aufrufen (z.B. um den Inhalt von
5342 // Floating-Frames oder Applets zu ignorieren)
5343 NextToken( nToken );
5344 }
5345 else switch( nToken )
5346 {
5347 case HTML_TABLE_ON:
5348 if( !pCurTable->GetContext() )
5349 {
5350 // Wenn noch keine Tabelle eingefuegt wurde,
5351 // die naechste Tabelle lesen
5352 SkipToken( -1 );
5353 bDone = sal_True;
5354 }
5355 // else
5356 // {
5357 // NextToken( nToken );
5358 // }
5359 break;
5360 case HTML_TABLE_OFF:
5361 bDone = sal_True;
5362 break;
5363 case HTML_CAPTION_ON:
5364 BuildTableCaption( pCurTable );
5365 bDone = pTable->IsOverflowing();
5366 break;
5367 case HTML_COL_ON:
5368 SkipToken( -1 );
5369 BuildTableColGroup( pCurTable, sal_False );
5370 break;
5371 case HTML_COLGROUP_ON:
5372 BuildTableColGroup( pCurTable, sal_True );
5373 break;
5374 case HTML_TABLEROW_ON:
5375 case HTML_TABLEHEADER_ON:
5376 case HTML_TABLEDATA_ON:
5377 SkipToken( -1 );
5378 BuildTableSection( pCurTable, sal_False, sal_False );
5379 bDone = pTable->IsOverflowing();
5380 break;
5381 case HTML_THEAD_ON:
5382 case HTML_TFOOT_ON:
5383 case HTML_TBODY_ON:
5384 BuildTableSection( pCurTable, sal_True, HTML_THEAD_ON==nToken );
5385 bDone = pTable->IsOverflowing();
5386 break;
5387 case HTML_MULTICOL_ON:
5388 // spaltige Rahmen koennen wir hier leider nicht einfuegen
5389 break;
5390 case HTML_FORM_ON:
5391 NewForm( sal_False ); // keinen neuen Absatz aufmachen!
5392 break;
5393 case HTML_FORM_OFF:
5394 EndForm( sal_False ); // keinen neuen Absatz aufmachen!
5395 break;
5396 case HTML_TEXTTOKEN:
5397 // Blank-Strings sind u. U. eine Folge von CR+LF und kein Text
5398 if( (pCurTable->GetContext() ||
5399 !pCurTable->HasParentSection()) &&
5400 1==aToken.Len() && ' '==aToken.GetChar(0) )
5401 break;
5402 default:
5403 pCurTable->MakeParentContents();
5404 NextToken( nToken );
5405 break;
5406 }
5407
5408 ASSERT( !bPending || !pPendStack,
5409 "SwHTMLParser::BuildTable: Es gibt wieder einen Pend-Stack" );
5410 bPending = sal_False;
5411 if( IsParserWorking() )
5412 SaveState( 0 );
5413
5414 if( !bDone )
5415 nToken = GetNextToken();
5416 }
5417
5418 if( SVPAR_PENDING == GetStatus() )
5419 {
5420 pPendStack = new SwPendingStack( HTML_TABLE_ON, pPendStack );
5421 pPendStack->pData = pSaveStruct;
5422 return 0;
5423 }
5424
5425 _HTMLTableContext *pTCntxt = pCurTable->GetContext();
5426 if( pTCntxt )
5427 {
5428 // Die Tabelle wurde auch angelegt
5429
5430 // Tabellen-Struktur anpassen
5431 pCurTable->CloseTable();
5432
5433 // ausserhalb von Zellen begonnene Kontexte beenden
5434 // muss vor(!) dem Umsetzten der Attribut Tabelle existieren,
5435 // weil die aktuelle danach nicht mehr existiert
5436 while( aContexts.Count() > nContextStAttrMin )
5437 {
5438 _HTMLAttrContext *pCntxt = PopContext();
5439 ClearContext( pCntxt );
5440 delete pCntxt;
5441 }
5442
5443 nContextStMin = pTCntxt->GetContextStMin();
5444 nContextStAttrMin = pTCntxt->GetContextStAttrMin();
5445
5446 if( pTable==pCurTable )
5447 {
5448 // Tabellen-Beschriftung setzen
5449 const SwStartNode *pCapStNd = pTable->GetCaptionStartNode();
5450 if( pCapStNd )
5451 {
5452 // Der letzte Absatz der Section wird nie mitkopiert. Deshalb
5453 // muss die Section mindestens zwei Absaetze enthalten.
5454
5455 if( pCapStNd->EndOfSectionIndex() - pCapStNd->GetIndex() > 2 )
5456 {
5457 // Start-Node und letzten Absatz nicht mitkopieren.
5458 SwNodeRange aSrcRg( *pCapStNd, 1,
5459 *pCapStNd->EndOfSectionNode(), -1 );
5460
5461 sal_Bool bTop = pTable->IsTopCaption();
5462 SwStartNode *pTblStNd = pTCntxt->GetTableNode();
5463
5464 ASSERT( pTblStNd, "Wo ist der Tabellen-Node" );
5465 ASSERT( pTblStNd==pPam->GetNode()->FindTableNode(),
5466 "Stehen wir in der falschen Tabelle?" );
5467
5468 SwNode* pNd;
5469 if( bTop )
5470 pNd = pTblStNd;
5471 else
5472 pNd = pTblStNd->EndOfSectionNode();
5473 SwNodeIndex aDstIdx( *pNd, bTop ? 0 : 1 );
5474
5475 pDoc->MoveNodeRange( aSrcRg, aDstIdx,
5476 IDocumentContentOperations::DOC_MOVEDEFAULT );
5477
5478 // Wenn die Caption vor der Tabelle eingefuegt wurde muss
5479 // eine an der Tabelle gesetzte Seitenvorlage noch in den
5480 // ersten Absatz der Ueberschrift verschoben werden.
5481 // Ausserdem muessen alle gemerkten Indizes, die auf den
5482 // Tabellen-Node zeigen noch verschoben werden.
5483 if( bTop )
5484 {
5485 MovePageDescAttrs( pTblStNd, aSrcRg.aStart.GetIndex(),
5486 sal_False );
5487 }
5488 }
5489
5490 // Die Section wird jetzt nicht mehr gebraucht.
5491 pPam->SetMark();
5492 pPam->DeleteMark();
5493 pDoc->DeleteSection( (SwStartNode *)pCapStNd );
5494 pTable->SetCaption( 0, sal_False );
5495 }
5496
5497 // SwTable aufbereiten
5498 sal_uInt16 nBrowseWidth = (sal_uInt16)GetCurrentBrowseWidth();
5499 pSaveStruct->MakeTable( nBrowseWidth, *pPam->GetPoint(), pDoc );
5500
5501 #ifdef TEST_RESIZE
5502 const SwTable *pSwTable = pTable->GetSwTable();
5503 SwHTMLTableLayout *pLayoutInfo =
5504 pSwTable ? ((SwTable *)pSwTable)->GetHTMLTableLayout() : 0;
5505 if( pLayoutInfo )
5506 {
5507 ViewShell *pVSh = CheckActionViewShell();
5508 if( pVSh )
5509 {
5510 CallEndAction( sal_False, sal_False );
5511 CallStartAction( pVSh, sal_False );
5512
5513 sal_uInt16 nNewBrowseWidth =
5514 (sal_uInt16)GetCurrentBrowseWidth();
5515 if( nBrowseWidth != nNewBrowseWidth )
5516 pLayoutInfo->Resize( nNewBrowseWidth );
5517 }
5518 }
5519 #endif
5520 }
5521
5522 GetNumInfo().Set( pTCntxt->GetNumInfo() );
5523 pTCntxt->RestorePREListingXMP( *this );
5524 RestoreAttrTab( pTCntxt->aAttrTab );
5525
5526 if( pTable==pCurTable )
5527 {
5528 // oberen Absatz-Abstand einstellen
5529 bUpperSpace = sal_True;
5530 SetTxtCollAttrs();
5531
5532 nParaCnt = nParaCnt - Min(nParaCnt, pTCntxt->GetTableNode()->GetTable().GetTabSortBoxes().Count());
5533
5534 // ggfs. eine Tabelle anspringen
5535 if( JUMPTO_TABLE == eJumpTo && pTable->GetSwTable() &&
5536 pTable->GetSwTable()->GetFrmFmt()->GetName() == sJmpMark )
5537 {
5538 bChkJumpMark = sal_True;
5539 eJumpTo = JUMPTO_NONE;
5540 }
5541
5542 // fix #37886#: Wenn Import abgebrochen wurde kein erneutes Show
5543 // aufrufen, weil die ViewShell schon geloescht wurde!
5544 // fix #41669#: Genuegt nicht. Auch im ACCEPTING_STATE darf
5545 // kein Show aufgerufen werden, weil sonst waehrend des
5546 // Reschedules der Parser zerstoert wird, wenn noch ein
5547 // DataAvailable-Link kommt. Deshalb: Nur im WORKING-State.
5548 if( !nParaCnt && SVPAR_WORKING == GetStatus() )
5549 Show();
5550 }
5551 }
5552 else if( pTable==pCurTable )
5553 {
5554 // Es wurde gar keine Tabelle gelesen.
5555
5556 // Dann muss eine evtl. gelesene Beschriftung noch geloescht werden.
5557 const SwStartNode *pCapStNd = pCurTable->GetCaptionStartNode();
5558 if( pCapStNd )
5559 {
5560 pPam->SetMark();
5561 pPam->DeleteMark();
5562 pDoc->DeleteSection( (SwStartNode *)pCapStNd );
5563 pCurTable->SetCaption( 0, sal_False );
5564 }
5565 }
5566
5567 if( pTable == pCurTable )
5568 {
5569 delete pSaveStruct->pCurTable;
5570 pSaveStruct->pCurTable = 0;
5571 pTable = 0;
5572 }
5573
5574 HTMLTable* pRetTbl = pSaveStruct->pCurTable;
5575 delete pSaveStruct;
5576
5577 return pRetTbl;
5578 }
5579
5580