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