xref: /AOO41X/main/sw/source/filter/html/htmltabw.cxx (revision efeef26f81c84063fb0a91bde3856d4a51172d90)
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 
27 
28 #include <hintids.hxx>
29 #include <vcl/svapp.hxx>
30 #include <svtools/htmlout.hxx>
31 #include <svtools/htmltokn.h>
32 #include <svtools/htmlkywd.hxx>
33 #ifndef _WRKWIN_HXX //autogen
34 #include <vcl/wrkwin.hxx>
35 #endif
36 #include <editeng/ulspitem.hxx>
37 #include <editeng/lrspitem.hxx>
38 #include <editeng/brshitem.hxx>
39 #include <editeng/boxitem.hxx>
40 #include <com/sun/star/form/XFormsSupplier.hpp>
41 #include <com/sun/star/form/XForm.hpp>
42 #include <com/sun/star/form/XImageProducerSupplier.hpp>
43 #include <com/sun/star/form/XFormController.hpp>
44 #include <com/sun/star/container/XContainer.hpp>
45 #include <com/sun/star/container/XIndexContainer.hpp>
46 #include <com/sun/star/container/XSet.hpp>
47 #include <fmtornt.hxx>
48 #include <frmfmt.hxx>
49 #include <fmtfsize.hxx>
50 #include <fmtsrnd.hxx>
51 #include <frmatr.hxx>
52 #include <doc.hxx>
53 #include <pam.hxx>
54 #include <ndtxt.hxx>
55 #include <swrect.hxx>
56 #include <cellatr.hxx>
57 #include <poolfmt.hxx>
58 #include <swtable.hxx>
59 #include <htmltbl.hxx>
60 #include <htmlnum.hxx>
61 #include <wrthtml.hxx>
62 #include <wrtswtbl.hxx>
63 #ifdef DBG_UTIL
64 #ifndef _VIEWSH_HXX
65 #include <viewsh.hxx>
66 #endif
67 #include <viewopt.hxx>
68 #endif
69 #include <sal/types.h>
70 
71 //#define MAX_DEPTH (USHRT_MAX)
72 #define MAX_DEPTH (3)
73 
74 using namespace ::com::sun::star;
75 
76 
77 class SwHTMLWrtTable : public SwWriteTable
78 {
79     void Pixelize( sal_uInt16& rValue );
80     void PixelizeBorders();
81 
82     void OutTableCell( SwHTMLWriter& rWrt, const SwWriteTableCell *pCell,
83                        sal_Bool bOutVAlign ) const;
84 
85     void OutTableCells( SwHTMLWriter& rWrt,
86                         const SwWriteTableCells& rCells,
87                         const SvxBrushItem *pBrushItem ) const;
88 
89     virtual sal_Bool ShouldExpandSub( const SwTableBox *pBox,
90                             sal_Bool bExpandedBefore, sal_uInt16 nDepth ) const;
91 
92     static sal_Bool HasTabBackground( const SwTableLine& rLine,
93                         sal_Bool bTop, sal_Bool bBottom, sal_Bool bLeft, sal_Bool bRight );
94     static sal_Bool HasTabBackground( const SwTableBox& rBox,
95                         sal_Bool bTop, sal_Bool bBottom, sal_Bool bLeft, sal_Bool bRight );
96 
97 public:
98     SwHTMLWrtTable( const SwTableLines& rLines, long nWidth, sal_uInt32 nBWidth,
99                     sal_Bool bRel, sal_uInt16 nNumOfRowsToRepeat,
100                     sal_uInt16 nLeftSub=0, sal_uInt16 nRightSub=0 );
101     SwHTMLWrtTable( const SwHTMLTableLayout *pLayoutInfo );
102 
103     void Write( SwHTMLWriter& rWrt, sal_Int16 eAlign=text::HoriOrientation::NONE,
104                 sal_Bool bTHead=sal_False, const SwFrmFmt *pFrmFmt=0,
105                 const String *pCaption=0, sal_Bool bTopCaption=sal_False,
106                 sal_uInt16 nHSpace=0, sal_uInt16 nVSpace=0 ) const;
107 };
108 
109 
SwHTMLWrtTable(const SwTableLines & rLines,long nWidth,sal_uInt32 nBWidth,sal_Bool bRel,sal_uInt16 nNumOfRowsToRepeat,sal_uInt16 nLSub,sal_uInt16 nRSub)110 SwHTMLWrtTable::SwHTMLWrtTable( const SwTableLines& rLines, long nWidth,
111                                 sal_uInt32 nBWidth, sal_Bool bRel, sal_uInt16 nNumOfRowsToRepeat,
112                                 sal_uInt16 nLSub, sal_uInt16 nRSub )
113     : SwWriteTable( rLines, nWidth, nBWidth, bRel, MAX_DEPTH, nLSub, nRSub, nNumOfRowsToRepeat )
114 {
115     PixelizeBorders();
116 }
117 
SwHTMLWrtTable(const SwHTMLTableLayout * pLayoutInfo)118 SwHTMLWrtTable::SwHTMLWrtTable( const SwHTMLTableLayout *pLayoutInfo )
119     : SwWriteTable( pLayoutInfo )
120 {
121     // Einige Twip-Werte an Pixel-Grenzen anpassen
122     if( bCollectBorderWidth )
123         PixelizeBorders();
124 }
125 
Pixelize(sal_uInt16 & rValue)126 void SwHTMLWrtTable::Pixelize( sal_uInt16& rValue )
127 {
128     if( rValue && Application::GetDefaultDevice() )
129     {
130         Size aSz( rValue, 0 );
131         aSz = Application::GetDefaultDevice()->LogicToPixel( aSz, MapMode(MAP_TWIP) );
132         if( !aSz.Width() )
133             aSz.Width() = 1;
134         aSz = Application::GetDefaultDevice()->PixelToLogic( aSz, MapMode(MAP_TWIP) );
135         rValue = (sal_uInt16)aSz.Width();
136     }
137 }
138 
PixelizeBorders()139 void SwHTMLWrtTable::PixelizeBorders()
140 {
141     Pixelize( nBorder );
142     Pixelize( nCellSpacing );
143     Pixelize( nCellPadding );
144 }
145 
HasTabBackground(const SwTableBox & rBox,sal_Bool bTop,sal_Bool bBottom,sal_Bool bLeft,sal_Bool bRight)146 sal_Bool SwHTMLWrtTable::HasTabBackground( const SwTableBox& rBox,
147                         sal_Bool bTop, sal_Bool bBottom, sal_Bool bLeft, sal_Bool bRight )
148 {
149     ASSERT( bTop || bBottom || bLeft || bRight,
150             "HasTabBackground: darf nicht aufgerufen werden" );
151 
152     sal_Bool bRet = sal_False;
153     if( rBox.GetSttNd() )
154     {
155         const SvxBrushItem& rBrushItem =
156             rBox.GetFrmFmt()->GetBackground();
157 
158         /// OD 02.09.2002 #99657#
159         /// The table box has a background, if its background color is not "no fill"/
160         /// "auto fill" or it has a background graphic.
161         bRet = rBrushItem.GetColor() != COL_TRANSPARENT ||
162                rBrushItem.GetGraphicLink() || rBrushItem.GetGraphic();
163     }
164     else
165     {
166         const SwTableLines& rLines = rBox.GetTabLines();
167         sal_uInt16 nCount = rLines.Count();
168         sal_Bool bLeftRight = bLeft || bRight;
169         for( sal_uInt16 i=0; !bRet && i<nCount; i++ )
170         {
171             sal_Bool bT = bTop && 0 == i;
172             sal_Bool bB = bBottom && nCount-1 == i;
173             if( bT || bB || bLeftRight )
174                 bRet = HasTabBackground( *rLines[i], bT, bB, bLeft, bRight);
175         }
176     }
177 
178     return bRet;
179 }
180 
HasTabBackground(const SwTableLine & rLine,sal_Bool bTop,sal_Bool bBottom,sal_Bool bLeft,sal_Bool bRight)181 sal_Bool SwHTMLWrtTable::HasTabBackground( const SwTableLine& rLine,
182                         sal_Bool bTop, sal_Bool bBottom, sal_Bool bLeft, sal_Bool bRight )
183 {
184     ASSERT( bTop || bBottom || bLeft || bRight,
185             "HasTabBackground: darf nicht aufgerufen werden" );
186 
187     sal_Bool bRet = sal_False;
188     const SvxBrushItem& rBrushItem = rLine.GetFrmFmt()->GetBackground();
189     /// OD 02.09.2002 #99657#
190     /// The table line has a background, if its background color is not "no fill"/
191     /// "auto fill" or it has a background graphic.
192     bRet = rBrushItem.GetColor() != COL_TRANSPARENT ||
193            rBrushItem.GetGraphicLink() || rBrushItem.GetGraphic();
194 
195     if( !bRet )
196     {
197         const SwTableBoxes& rBoxes = rLine.GetTabBoxes();
198         sal_uInt16 nCount = rBoxes.Count();
199         sal_Bool bTopBottom = bTop || bBottom;
200         for( sal_uInt16 i=0; !bRet && i<nCount; i++ )
201         {
202             sal_Bool bL = bLeft && 0 == i;
203             sal_Bool bR = bRight && nCount-1 == i;
204             if( bTopBottom || bL || bR )
205                 bRet = HasTabBackground( *rBoxes[i], bTop, bBottom, bL, bR );
206         }
207     }
208 
209     return bRet;
210 }
211 
212 sal_Bool lcl_WrtHTMLTbl_HasTabBorders( const SwTableLine*& rpLine, void* pPara );
213 
lcl_WrtHTMLTbl_HasTabBorders(const SwTableBox * & rpBox,void * pPara)214 sal_Bool lcl_WrtHTMLTbl_HasTabBorders( const SwTableBox*& rpBox, void* pPara )
215 {
216     sal_Bool *pBorders = (sal_Bool *)pPara;
217     if( *pBorders )
218         return sal_False;
219 
220     if( !rpBox->GetSttNd() )
221     {
222         ((SwTableBox *)rpBox)->GetTabLines().ForEach(
223                                 &lcl_WrtHTMLTbl_HasTabBorders, pPara );
224     }
225     else
226     {
227         const SvxBoxItem& rBoxItem =
228             (const SvxBoxItem&)rpBox->GetFrmFmt()->GetFmtAttr( RES_BOX );
229 
230         *pBorders = rBoxItem.GetTop() || rBoxItem.GetBottom() ||
231                     rBoxItem.GetLeft() || rBoxItem.GetRight();
232     }
233 
234     return !*pBorders;
235 }
236 
lcl_WrtHTMLTbl_HasTabBorders(const SwTableLine * & rpLine,void * pPara)237 sal_Bool lcl_WrtHTMLTbl_HasTabBorders( const SwTableLine*& rpLine, void* pPara )
238 {
239     sal_Bool *pBorders = (sal_Bool *)pPara;
240     if( *pBorders )
241         return sal_False;
242 
243     ((SwTableLine *)rpLine)->GetTabBoxes().ForEach(
244                                     &lcl_WrtHTMLTbl_HasTabBorders, pPara );
245     return !*pBorders;
246 }
247 
248 
ShouldExpandSub(const SwTableBox * pBox,sal_Bool bExpandedBefore,sal_uInt16 nDepth) const249 sal_Bool SwHTMLWrtTable::ShouldExpandSub( const SwTableBox *pBox,
250                                       sal_Bool bExpandedBefore,
251                                       sal_uInt16 nDepth ) const
252 {
253     sal_Bool bExpand = !pBox->GetSttNd() && nDepth>0;
254     if( bExpand && bExpandedBefore )
255     {
256         // MIB 30.6.97: Wenn schon eine Box expandiert wurde, wird eine
257         // weitere nur expandiert, wenn sie Umrandungen besitzt.
258         sal_Bool bBorders = sal_False;
259         lcl_WrtHTMLTbl_HasTabBorders( pBox, &bBorders );
260         if( !bBorders )
261             bBorders = HasTabBackground( *pBox, sal_True, sal_True, sal_True, sal_True );
262         bExpand = bBorders;
263     }
264 
265     return bExpand;
266 }
267 
268 
269 // Eine Box als einzelne Zelle schreiben
OutTableCell(SwHTMLWriter & rWrt,const SwWriteTableCell * pCell,sal_Bool bOutVAlign) const270 void SwHTMLWrtTable::OutTableCell( SwHTMLWriter& rWrt,
271                                    const SwWriteTableCell *pCell,
272                                    sal_Bool bOutVAlign ) const
273 {
274     const SwTableBox *pBox = pCell->GetBox();
275     sal_uInt16 nRow = pCell->GetRow();
276     sal_uInt16 nCol = pCell->GetCol();
277     sal_uInt16 nRowSpan = pCell->GetRowSpan();
278     sal_uInt16 nColSpan = pCell->GetColSpan();
279 
280     if ( !nRowSpan )
281         return;
282 
283     SwWriteTableCol *pCol = aCols[nCol];
284 
285 //  sal_Bool bOutWidth = nColSpan>1 || pCol->GetOutWidth();
286     sal_Bool bOutWidth = sal_True; //nColSpan==1 && pCol->GetOutWidth();
287 
288     const SwStartNode* pSttNd = pBox->GetSttNd();
289     sal_Bool bHead = sal_False;
290     if( pSttNd )
291     {
292         sal_uLong nNdPos = pSttNd->GetIndex()+1;
293 
294         // Art der Zelle (TD/TH) bestimmen
295         SwNode* pNd;
296         while( !( pNd = rWrt.pDoc->GetNodes()[nNdPos])->IsEndNode() )
297         {
298             if( pNd->IsTxtNode() )
299             {
300                 // nur Absaetzte betrachten, an denen man was erkennt
301                 // Das ist der Fall, wenn die Vorlage eine der Tabellen-Vorlagen
302                 // ist oder von einer der beiden abgelitten ist.
303                 const SwFmt *pFmt = &((SwTxtNode*)pNd)->GetAnyFmtColl();
304                 sal_uInt16 nPoolId = pFmt->GetPoolFmtId();
305                 while( !pFmt->IsDefault() &&
306                        RES_POOLCOLL_TABLE_HDLN!=nPoolId &&
307                        RES_POOLCOLL_TABLE!=nPoolId )
308                 {
309                     pFmt = pFmt->DerivedFrom();
310                     nPoolId = pFmt->GetPoolFmtId();
311                 }
312 
313                 if( !pFmt->IsDefault() )
314                 {
315                     bHead = (RES_POOLCOLL_TABLE_HDLN==nPoolId);
316                     break;
317                 }
318             }
319             nNdPos++;
320         }
321     }
322 
323     rWrt.OutNewLine();  // <TH>/<TD> in neue Zeile
324     ByteString sOut( '<' );
325     sOut += (bHead ? OOO_STRING_SVTOOLS_HTML_tableheader : OOO_STRING_SVTOOLS_HTML_tabledata );
326 
327     // ROW- und COLSPAN ausgeben
328     if( nRowSpan>1 )
329         (((sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_rowspan ) += '=')
330             += ByteString::CreateFromInt32( nRowSpan );
331     if( nColSpan > 1 )
332         (((sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_colspan ) += '=')
333             += ByteString::CreateFromInt32( nColSpan );
334 
335 #ifndef PURE_HTML
336     long nWidth = 0;
337     sal_uInt32 nPrcWidth = USHRT_MAX;
338     if( bOutWidth )
339     {
340         if( bLayoutExport )
341         {
342             if( pCell->HasPrcWidthOpt() )
343             {
344                 nPrcWidth = pCell->GetWidthOpt();
345             }
346             else
347             {
348                 nWidth = pCell->GetWidthOpt();
349                 if( !nWidth )
350                     bOutWidth = sal_False;
351             }
352         }
353         else
354         {
355             if( HasRelWidths() )
356                 nPrcWidth = (sal_uInt16)GetPrcWidth(nCol,nColSpan);
357             else
358                 nWidth = GetAbsWidth( nCol, nColSpan );
359         }
360     }
361 
362     long nHeight = pCell->GetHeight() > 0
363                         ? GetAbsHeight( pCell->GetHeight(), nRow, nRowSpan )
364                         : 0;
365     Size aPixelSz( nWidth, nHeight );
366 
367     // WIDTH ausgeben (Grrr: nur fuer Netscape)
368     if( (aPixelSz.Width() || aPixelSz.Height()) && Application::GetDefaultDevice() )
369     {
370         Size aOldSz( aPixelSz );
371         aPixelSz = Application::GetDefaultDevice()->LogicToPixel( aPixelSz,
372                                                         MapMode(MAP_TWIP) );
373         if( aOldSz.Width() && !aPixelSz.Width() )
374             aPixelSz.Width() = 1;
375         if( aOldSz.Height() && !aPixelSz.Height() )
376             aPixelSz.Height() = 1;
377     }
378 
379     // WIDTH ausgeben: Aus Layout oder berechnet
380     if( bOutWidth )
381     {
382         ((sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_width ) += '=';
383         if( nPrcWidth != USHRT_MAX )
384             (sOut += ByteString::CreateFromInt32(nPrcWidth)) += '%';
385         else
386             sOut += ByteString::CreateFromInt32(aPixelSz.Width());
387         if( !bLayoutExport && nColSpan==1 )
388             pCol->SetOutWidth( sal_False );
389     }
390 
391     if( nHeight )
392     {
393         (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_height) += '=')
394             += ByteString::CreateFromInt32(aPixelSz.Height());
395     }
396 #endif
397 
398     const SfxItemSet& rItemSet = pBox->GetFrmFmt()->GetAttrSet();
399     const SfxPoolItem *pItem;
400 
401     // ALIGN wird jetzt nur noch an den Absaetzen ausgegeben
402 
403     // VALIGN ausgeben
404     if( bOutVAlign )
405     {
406         sal_Int16 eVertOri = pCell->GetVertOri();
407         if( text::VertOrientation::TOP==eVertOri || text::VertOrientation::BOTTOM==eVertOri )
408         {
409             (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_valign) += '=')
410                 += (text::VertOrientation::TOP==eVertOri ? OOO_STRING_SVTOOLS_HTML_VA_top : OOO_STRING_SVTOOLS_HTML_VA_bottom);
411         }
412     }
413 
414     rWrt.Strm() << sOut.GetBuffer();
415     sOut.Erase();
416 
417     rWrt.bTxtAttr = sal_False;
418     rWrt.bOutOpts = sal_True;
419     const SvxBrushItem *pBrushItem = 0;
420     if( SFX_ITEM_SET==rItemSet.GetItemState( RES_BACKGROUND, sal_False, &pItem ) )
421     {
422         pBrushItem = (const SvxBrushItem *)pItem;
423     }
424     if( !pBrushItem )
425         pBrushItem = pCell->GetBackground();
426 
427     if( pBrushItem )
428     {
429         // Hintergrund ausgeben
430         String aDummy;
431         rWrt.OutBackground( pBrushItem, aDummy, sal_False );
432 
433         if( rWrt.bCfgOutStyles )
434             OutCSS1_TableBGStyleOpt( rWrt, *pBrushItem );
435     }
436 
437     sal_uInt32 nNumFmt = 0;
438     double nValue = 0.0;
439     sal_Bool bNumFmt = sal_False, bValue = sal_False;
440     if( SFX_ITEM_SET==rItemSet.GetItemState( RES_BOXATR_FORMAT, sal_False, &pItem ) )
441     {
442         nNumFmt = ((const SwTblBoxNumFormat *)pItem)->GetValue();
443         bNumFmt = sal_True;
444     }
445     if( SFX_ITEM_SET==rItemSet.GetItemState( RES_BOXATR_VALUE, sal_False, &pItem ) )
446     {
447         nValue = ((const SwTblBoxValue *)pItem)->GetValue();
448         bValue = sal_True;
449         if( !bNumFmt )
450             nNumFmt = pBox->GetFrmFmt()->GetTblBoxNumFmt().GetValue();
451     }
452 
453     if( bNumFmt || bValue )
454         sOut = HTMLOutFuncs::CreateTableDataOptionsValNum( sOut,
455                     bValue, nValue, nNumFmt, *rWrt.pDoc->GetNumberFormatter(),
456                     rWrt.eDestEnc, &rWrt.aNonConvertableCharacters );
457     sOut += '>';
458     rWrt.Strm() << sOut.GetBuffer();
459     rWrt.bLFPossible = sal_True;
460 
461     rWrt.IncIndentLevel();  // den Inhalt von <TD>...</TD> einruecken
462 
463     if( pSttNd )
464     {
465         HTMLSaveData aSaveData( rWrt, pSttNd->GetIndex()+1,
466                                 pSttNd->EndOfSectionIndex() );
467         rWrt.Out_SwDoc( rWrt.pCurPam );
468     }
469     else
470     {
471         sal_uInt16 nTWidth;
472         sal_uInt32 nBWidth;
473         sal_uInt16 nLSub, nRSub;
474         if( HasRelWidths() )
475         {
476             nTWidth = 100;
477             nBWidth = GetRawWidth( nCol, nColSpan );
478             nLSub = 0;
479             nRSub = 0;
480         }
481         else
482         {
483             nTWidth = GetAbsWidth( nCol, nColSpan );
484             nBWidth = nTWidth;
485             nLSub = GetLeftSpace( nCol );
486             nRSub = GetRightSpace( nCol, nColSpan );
487         }
488 
489         SwHTMLWrtTable aTableWrt( pBox->GetTabLines(), nTWidth,
490                                   nBWidth, HasRelWidths(), nLSub, nRSub );
491         aTableWrt.Write( rWrt );
492     }
493 
494     rWrt.DecIndentLevel();  // den Inhalt von <TD>...</TD> einruecken
495 
496     if( rWrt.bLFPossible )
497         rWrt.OutNewLine();
498     HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), bHead ? OOO_STRING_SVTOOLS_HTML_tableheader
499                                                    : OOO_STRING_SVTOOLS_HTML_tabledata,
500                                 sal_False );
501     rWrt.bLFPossible = sal_True;
502 }
503 
504 
505 // Eine Line als Zeilen ausgeben
OutTableCells(SwHTMLWriter & rWrt,const SwWriteTableCells & rCells,const SvxBrushItem * pBrushItem) const506 void SwHTMLWrtTable::OutTableCells( SwHTMLWriter& rWrt,
507                                     const SwWriteTableCells& rCells,
508                                     const SvxBrushItem *pBrushItem ) const
509 {
510     // Wenn die Zeile mehr als eine Zelle nethaelt und alle Zellen
511     // die gleiche Ausrichtung besitzen, das VALIGN an der Zeile statt der
512     // Zelle ausgeben
513     sal_Int16 eRowVertOri = text::VertOrientation::NONE;
514     if( rCells.Count() > 1 )
515     {
516         for( sal_uInt16 nCell = 0; nCell<rCells.Count(); nCell++ )
517         {
518             sal_Int16 eCellVertOri = rCells[nCell]->GetVertOri();
519             if( 0==nCell )
520             {
521                 eRowVertOri = eCellVertOri;
522             }
523             else if( eRowVertOri != eCellVertOri )
524             {
525                 eRowVertOri = text::VertOrientation::NONE;
526                 break;
527             }
528         }
529     }
530 
531     rWrt.OutNewLine();  // <TR> in neuer Zeile
532     rWrt.Strm() << '<' << OOO_STRING_SVTOOLS_HTML_tablerow;
533     if( pBrushItem )
534     {
535         String aDummy;
536         rWrt.OutBackground( pBrushItem, aDummy, sal_False );
537 
538         rWrt.bTxtAttr = sal_False;
539         rWrt.bOutOpts = sal_True;
540         if( rWrt.bCfgOutStyles )
541             OutCSS1_TableBGStyleOpt( rWrt, *pBrushItem );
542     }
543 
544     if( text::VertOrientation::TOP==eRowVertOri || text::VertOrientation::BOTTOM==eRowVertOri )
545     {
546         ByteString sOut( ' ' );
547         ((sOut += OOO_STRING_SVTOOLS_HTML_O_valign) += '=')
548             += (text::VertOrientation::TOP==eRowVertOri ? OOO_STRING_SVTOOLS_HTML_VA_top : OOO_STRING_SVTOOLS_HTML_VA_bottom);
549         rWrt.Strm() << sOut.GetBuffer();
550     }
551 
552     rWrt.Strm() << '>';
553 
554     rWrt.IncIndentLevel(); // Inhalt von <TR>...</TR> einruecken
555 
556     for( sal_uInt16 nCell = 0; nCell<rCells.Count(); nCell++ )
557         OutTableCell( rWrt, rCells[nCell], text::VertOrientation::NONE==eRowVertOri );
558 
559     rWrt.DecIndentLevel(); // Inhalt von <TR>...</TR> einruecken
560 
561     rWrt.OutNewLine();  // </TR> in neuer Zeile
562     HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_tablerow, sal_False );
563 }
564 
565 
566 
Write(SwHTMLWriter & rWrt,sal_Int16 eAlign,sal_Bool bTHead,const SwFrmFmt * pFrmFmt,const String * pCaption,sal_Bool bTopCaption,sal_uInt16 nHSpace,sal_uInt16 nVSpace) const567 void SwHTMLWrtTable::Write( SwHTMLWriter& rWrt, sal_Int16 eAlign,
568                             sal_Bool bTHead, const SwFrmFmt *pFrmFmt,
569                             const String *pCaption, sal_Bool bTopCaption,
570                             sal_uInt16 nHSpace, sal_uInt16 nVSpace ) const
571 {
572     sal_uInt16 nRow;
573 
574     // Wert fuer FRAME bestimmen
575     sal_uInt16 nFrameMask = 15;
576     if( !(aRows[0])->bTopBorder )
577         nFrameMask &= ~1;
578     if( !(aRows[aRows.Count()-1])->bBottomBorder )
579         nFrameMask &= ~2;
580     if( !(aCols[0])->bLeftBorder )
581         nFrameMask &= ~4;
582     if( !(aCols[aCols.Count()-1])->bRightBorder )
583         nFrameMask &= ~8;
584 
585     // Wert fur RULES bestimmen
586     sal_Bool bRowsHaveBorder = sal_False;
587     sal_Bool bRowsHaveBorderOnly = sal_True;
588     SwWriteTableRow *pRow = aRows[0];
589     for( nRow=1; nRow < aRows.Count(); nRow++ )
590     {
591         SwWriteTableRow *pNextRow = aRows[nRow];
592         sal_Bool bBorder = ( pRow->bBottomBorder || pNextRow->bTopBorder );
593         bRowsHaveBorder |= bBorder;
594         bRowsHaveBorderOnly &= bBorder;
595 
596         sal_uInt16 nBorder2 = pRow->bBottomBorder ? pRow->nBottomBorder : USHRT_MAX;
597         if( pNextRow->bTopBorder && pNextRow->nTopBorder < nBorder2 )
598             nBorder2 = pNextRow->nTopBorder;
599 
600         pRow->bBottomBorder = bBorder;
601         pRow->nBottomBorder = nBorder2;
602 
603         pNextRow->bTopBorder = bBorder;
604         pNextRow->nTopBorder = nBorder2;
605 
606         pRow = pNextRow;
607     }
608 
609     sal_Bool bColsHaveBorder = sal_False;
610     sal_Bool bColsHaveBorderOnly = sal_True;
611     SwWriteTableCol *pCol = aCols[0];
612     sal_uInt16 nCol;
613     for( nCol=1; nCol<aCols.Count(); nCol++ )
614     {
615         SwWriteTableCol *pNextCol = aCols[nCol];
616         sal_Bool bBorder = ( pCol->bRightBorder || pNextCol->bLeftBorder );
617         bColsHaveBorder |= bBorder;
618         bColsHaveBorderOnly &= bBorder;
619         pCol->bRightBorder = bBorder;
620         pNextCol->bLeftBorder = bBorder;
621         pCol = pNextCol;
622     }
623 
624 
625     // vorhergende Aufzaehlung etc. beenden
626     rWrt.ChangeParaToken( 0 );
627 
628     if( rWrt.bLFPossible )
629         rWrt.OutNewLine();  // <TABLE> in neue Zeile
630     ByteString sOut( '<' );
631     sOut += OOO_STRING_SVTOOLS_HTML_table;
632 
633     sal_uInt16 nOldDirection = rWrt.nDirection;
634     if( pFrmFmt )
635         rWrt.nDirection = rWrt.GetHTMLDirection( pFrmFmt->GetAttrSet() );
636     if( rWrt.bOutFlyFrame || nOldDirection != rWrt.nDirection )
637     {
638         rWrt.Strm() << sOut.GetBuffer();
639         sOut.Erase();
640         rWrt.OutDirection( rWrt.nDirection );
641     }
642 
643     // COLS ausgeben: Nur bei Export ueber Layout, wenn es beim Import
644     // vorhanden war.
645     if( bColsOption )
646         (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_cols) += '=')
647             += ByteString::CreateFromInt32( aCols.Count() );
648 
649     // ALIGN= ausgeben
650     if( text::HoriOrientation::RIGHT == eAlign )
651         (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_align ) += '=') += OOO_STRING_SVTOOLS_HTML_AL_right;
652     else if( text::HoriOrientation::CENTER == eAlign )
653         (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_align ) += '=') += OOO_STRING_SVTOOLS_HTML_AL_center;
654     else if( text::HoriOrientation::LEFT == eAlign )
655         (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_align ) += '=') += OOO_STRING_SVTOOLS_HTML_AL_left;
656 
657     // WIDTH ausgeben: Stammt aus Layout oder ist berechnet
658     if( nTabWidth )
659     {
660         ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_width ) += '=';
661         if( HasRelWidths() )
662             (sOut += ByteString::CreateFromInt32( nTabWidth )) += '%';
663         else if( Application::GetDefaultDevice() )
664         {
665             long nPixWidth = Application::GetDefaultDevice()->LogicToPixel(
666                         Size(nTabWidth,0), MapMode(MAP_TWIP) ).Width();
667             if( !nPixWidth )
668                 nPixWidth = 1;
669 
670             sOut += ByteString::CreateFromInt32( nPixWidth );
671         }
672         else
673         {
674             ASSERT( Application::GetDefaultDevice(), "kein Application-Window!?" );
675             sOut += "100%";
676         }
677     }
678 
679     if( (nHSpace || nVSpace) && Application::GetDefaultDevice())
680     {
681         Size aPixelSpc =
682             Application::GetDefaultDevice()->LogicToPixel( Size(nHSpace,nVSpace),
683                                                    MapMode(MAP_TWIP) );
684         if( !aPixelSpc.Width() && nHSpace )
685             aPixelSpc.Width() = 1;
686         if( !aPixelSpc.Height() && nVSpace )
687             aPixelSpc.Height() = 1;
688 
689         if( aPixelSpc.Width() )
690         {
691             (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_hspace) += '=')
692                 += ByteString::CreateFromInt32( aPixelSpc.Width() );
693         }
694 
695         if( aPixelSpc.Height() )
696         {
697             (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_vspace) += '=')
698                 += ByteString::CreateFromInt32( aPixelSpc.Height() );
699         }
700     }
701 
702     // BORDER ausgeben, aber nur wenn wir die Umrandung selbst berechnet
703     // haben oder die Umrandung 0 ist oder es irgendwelche Umrandungen gibt.
704     // Anderenfalls enthaelt nBorder naemlich nur die Breite der Umrandung,
705     // die genutzt wird, wenn gar kein sheet::Border angegeben ist.
706     sal_Bool bHasAnyBorders = nFrameMask || bColsHaveBorder || bRowsHaveBorder;
707     if( bCollectBorderWidth || nBorder==0 || bHasAnyBorders )
708         (((sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_border ) += '=')
709             += ByteString::CreateFromInt32( rWrt.ToPixel( nBorder ) );
710 
711     // BORDERCOLOR ausgeben
712 
713     if( (sal_uInt32)-1 != nBorderColor && rWrt.bCfgOutStyles && bHasAnyBorders )
714     {
715         ((sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_bordercolor ) += '=';
716         rWrt.Strm() << sOut.GetBuffer();
717         HTMLOutFuncs::Out_Color( rWrt.Strm(), nBorderColor, rWrt.eDestEnc );
718         sOut.Erase();
719     }
720 
721     // CELLPADDING ausgeben: Stammt aus Layout oder ist berechnet
722     (((sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_cellpadding ) += '=')
723         += ByteString::CreateFromInt32( rWrt.ToPixel( nCellPadding ) );
724 
725     // CELLSPACING ausgeben: Stammt aus Layout oder ist berechnet
726     (((sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_cellspacing ) += '=')
727         += ByteString::CreateFromInt32( rWrt.ToPixel( nCellSpacing ) );
728 
729     // FRAME/RULES ausgeben (nur sinnvoll, wenn border!=0)
730     if( nBorder!=0 && (bCollectBorderWidth || bHasAnyBorders) )
731     {
732         const sal_Char *pFrame = 0;
733         switch( nFrameMask )
734         {
735             case 0:  pFrame = OOO_STRING_SVTOOLS_HTML_TF_void       ;break;
736             case 1:  pFrame = OOO_STRING_SVTOOLS_HTML_TF_above  ;break;
737             case 2:  pFrame = OOO_STRING_SVTOOLS_HTML_TF_below  ;break;
738             case 3:  pFrame = OOO_STRING_SVTOOLS_HTML_TF_hsides ;break;
739             case 4:  pFrame = OOO_STRING_SVTOOLS_HTML_TF_lhs        ;break;
740             case 8:  pFrame = OOO_STRING_SVTOOLS_HTML_TF_rhs        ;break;
741             case 12: pFrame = OOO_STRING_SVTOOLS_HTML_TF_vsides ;break;
742             //FRAME=BOX ist der default wenn BORDER>0
743             //case 15:
744             //default: pFrame = OOO_STRING_SVTOOLS_HTML_TF_box      ;break; // geht nicht
745         };
746         if( pFrame )
747             (((sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_frame ) += '=') += pFrame;
748 
749         const sal_Char *pRules = 0;
750         if( aCols.Count() > 1 && aRows.Count() > 1 )
751         {
752             if( !bColsHaveBorder )
753             {
754                 if( !bRowsHaveBorder )
755                     pRules = OOO_STRING_SVTOOLS_HTML_TR_none;
756                 else if( bRowsHaveBorderOnly )
757                     pRules = OOO_STRING_SVTOOLS_HTML_TR_rows;
758                 else
759                     pRules = OOO_STRING_SVTOOLS_HTML_TR_groups;
760             }
761             else if( bColsHaveBorderOnly )
762             {
763                 if( !bRowsHaveBorder || !bRowsHaveBorderOnly )
764                     pRules = OOO_STRING_SVTOOLS_HTML_TR_cols;
765             }
766             else
767             {
768                 if( !bRowsHaveBorder )
769                     pRules = OOO_STRING_SVTOOLS_HTML_TR_groups;
770                 else if( bRowsHaveBorderOnly )
771                     pRules = OOO_STRING_SVTOOLS_HTML_TR_rows;
772                 else
773                     pRules = OOO_STRING_SVTOOLS_HTML_TR_groups;
774             }
775         }
776         else if( aRows.Count() > 1 )
777         {
778             if( !bRowsHaveBorder )
779                 pRules = OOO_STRING_SVTOOLS_HTML_TR_none;
780             else if( !bRowsHaveBorderOnly )
781                 pRules = OOO_STRING_SVTOOLS_HTML_TR_groups;
782         }
783         else if( aCols.Count() > 1 )
784         {
785             if( !bColsHaveBorder )
786                 pRules = OOO_STRING_SVTOOLS_HTML_TR_none;
787             else if( !bColsHaveBorderOnly )
788                 pRules = OOO_STRING_SVTOOLS_HTML_TR_groups;
789         }
790 
791         if( pRules )
792             (((sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_rules ) += '=') += pRules;
793     }
794     rWrt.Strm() << sOut.GetBuffer();
795 
796     // Hintergrund ausgeben
797     if( pFrmFmt )
798     {
799         String aDummy;
800         rWrt.OutBackground( pFrmFmt->GetAttrSet(), aDummy, sal_False );
801 
802         if( rWrt.bCfgOutStyles && pFrmFmt )
803             rWrt.OutCSS1_TableFrmFmtOptions( *pFrmFmt );
804     }
805 
806     sOut = '>';
807     rWrt.Strm() << sOut.GetBuffer();
808 
809     rWrt.IncIndentLevel(); // Inhalte von Table einruecken
810 
811     // Ueberschrift ausgeben
812     if( pCaption && pCaption->Len() )
813     {
814         rWrt.OutNewLine(); // <CAPTION> in neue Zeile
815         ByteString sOutStr( OOO_STRING_SVTOOLS_HTML_caption );
816         (((sOutStr += ' ') += OOO_STRING_SVTOOLS_HTML_O_align) += '=')
817             += (bTopCaption ? OOO_STRING_SVTOOLS_HTML_VA_top : OOO_STRING_SVTOOLS_HTML_VA_bottom);
818         HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), sOutStr.GetBuffer(), sal_True );
819         HTMLOutFuncs::Out_String( rWrt.Strm(), *pCaption, rWrt.eDestEnc, &rWrt.aNonConvertableCharacters    );
820         HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_caption, sal_False );
821     }
822 
823     sal_uInt16 nCols = aCols.Count();
824 
825     // <COLGRP>/<COL> ausgeben: Bei Export ueber Layout nur wenn beim
826     // Import welche da waren, sonst immer.
827     sal_Bool bColGroups = (bColsHaveBorder && !bColsHaveBorderOnly);
828     if( bColTags )
829     {
830         if( bColGroups )
831         {
832             rWrt.OutNewLine(); // <COLGRP> in neue Zeile
833             HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_colgroup, sal_True );
834 
835             rWrt.IncIndentLevel(); // Inhalt von <COLGRP> einruecken
836         }
837 
838         for( nCol=0; nCol<nCols; nCol++ )
839         {
840             rWrt.OutNewLine(); // <COL> in neue Zeile
841 
842             const SwWriteTableCol *pColumn = aCols[nCol];
843 
844             ByteString sOutStr( '<' );
845             sOutStr += OOO_STRING_SVTOOLS_HTML_col;
846 
847             sal_uInt32 nWidth;
848             sal_Bool bRel;
849             if( bLayoutExport )
850             {
851                 bRel = pColumn->HasRelWidthOpt();
852                 nWidth = pColumn->GetWidthOpt();
853             }
854             else
855             {
856                 bRel = HasRelWidths();
857                 nWidth = bRel ? GetRelWidth(nCol,1) : GetAbsWidth(nCol,1);
858             }
859 
860             ((sOutStr += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_width ) += '=';
861             if( bRel )
862             {
863                 (sOutStr += ByteString::CreateFromInt32( nWidth ) ) += '*';
864             }
865             else
866             {
867                 sOutStr += ByteString::CreateFromInt32( rWrt.ToPixel( nWidth ) );
868             }
869             sOutStr += '>';
870             rWrt.Strm() << sOutStr.GetBuffer();
871 
872             if( bColGroups && pColumn->bRightBorder && nCol<nCols-1 )
873             {
874                 rWrt.DecIndentLevel(); // Inhalt von <COLGRP> einruecken
875                 rWrt.OutNewLine(); // </COLGRP> in neue Zeile
876                 HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_colgroup,
877                                             sal_False );
878                 rWrt.OutNewLine(); // <COLGRP> in neue Zeile
879                 HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_colgroup,
880                                             sal_True );
881                 rWrt.IncIndentLevel(); // Inhalt von <COLGRP> einruecken
882             }
883         }
884         if( bColGroups )
885         {
886             rWrt.DecIndentLevel(); // Inhalt von <COLGRP> einruecken
887 
888             rWrt.OutNewLine(); // </COLGRP> in neue Zeile
889             HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_colgroup,
890                                         sal_False );
891         }
892     }
893 
894     // die Lines als Tabellenzeilen rausschreiben
895 
896     // <TBODY> ausgeben?
897     sal_Bool bTSections = (bRowsHaveBorder && !bRowsHaveBorderOnly);
898     sal_Bool bTBody = bTSections;
899 
900     // Wenn Sections ausgegeben werden muessen darf ein THEAD um die erste
901     // Zeile nur ausgegeben werden, wenn unter der Zeile eine Linie ist
902     if( bTHead &&
903         (bTSections || bColGroups) &&
904         nHeadEndRow<aRows.Count()-1 && !aRows[nHeadEndRow]->bBottomBorder )
905         bTHead = sal_False;
906 
907     // <TBODY> aus ausgeben, wenn <THEAD> ausgegeben wird.
908     bTSections |= bTHead;
909 
910     if( bTSections )
911     {
912         rWrt.OutNewLine(); // <THEAD>/<TDATA> in neue Zeile
913         HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(),
914                             bTHead ? OOO_STRING_SVTOOLS_HTML_thead : OOO_STRING_SVTOOLS_HTML_tbody, sal_True );
915 
916         rWrt.IncIndentLevel(); // Inhalt von <THEAD>/<TDATA> einr.
917     }
918 
919     for( nRow = 0; nRow < aRows.Count(); nRow++ )
920     {
921         const SwWriteTableRow *pRow2 = aRows[nRow];
922 
923         OutTableCells( rWrt, pRow2->GetCells(), pRow2->GetBackground() );
924         if( !nCellSpacing && nRow < aRows.Count()-1 && pRow2->bBottomBorder &&
925             pRow2->nBottomBorder > DEF_LINE_WIDTH_1 )
926         {
927             sal_uInt16 nCnt = (pRow2->nBottomBorder / DEF_LINE_WIDTH_1) - 1;
928             for( ; nCnt; nCnt-- )
929             {
930                 rWrt.OutNewLine();
931                 HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_tablerow,
932                                             sal_True );
933                 HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_tablerow,
934                                             sal_False );
935             }
936         }
937         if( ( (bTHead && nRow==nHeadEndRow) ||
938               (bTBody && pRow2->bBottomBorder) ) &&
939             nRow < aRows.Count()-1 )
940         {
941             rWrt.DecIndentLevel(); // Inhalt von <THEAD>/<TDATA> einr.
942             rWrt.OutNewLine(); // </THEAD>/</TDATA> in neue Zeile
943             HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(),
944                             bTHead ? OOO_STRING_SVTOOLS_HTML_thead : OOO_STRING_SVTOOLS_HTML_tbody, sal_False );
945             rWrt.OutNewLine(); // <THEAD>/<TDATA> in neue Zeile
946 
947             if( bTHead && nRow==nHeadEndRow )
948                 bTHead = sal_False;
949 
950             HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(),
951                             bTHead ? OOO_STRING_SVTOOLS_HTML_thead : OOO_STRING_SVTOOLS_HTML_tbody, sal_True );
952             rWrt.IncIndentLevel(); // Inhalt von <THEAD>/<TDATA> einr.
953         }
954     }
955 
956     if( bTSections )
957     {
958         rWrt.DecIndentLevel(); // Inhalt von <THEAD>/<TDATA> einr.
959 
960         rWrt.OutNewLine(); // </THEAD>/</TDATA> in neue Zeile
961         HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(),
962                             bTHead ? OOO_STRING_SVTOOLS_HTML_thead : OOO_STRING_SVTOOLS_HTML_tbody, sal_False );
963     }
964 
965     rWrt.DecIndentLevel(); // Inhalt von <TABLE> einr.
966 
967     rWrt.OutNewLine(); // </TABLE> in neue Zeile
968     HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_table, sal_False );
969 
970     rWrt.nDirection = nOldDirection;
971 }
972 
OutHTML_SwTblNode(Writer & rWrt,SwTableNode & rNode,const SwFrmFmt * pFlyFrmFmt,const String * pCaption,sal_Bool bTopCaption)973 Writer& OutHTML_SwTblNode( Writer& rWrt, SwTableNode & rNode,
974                            const SwFrmFmt *pFlyFrmFmt,
975                            const String *pCaption, sal_Bool bTopCaption )
976 {
977 
978     SwTable& rTbl = rNode.GetTable();
979 
980     SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt;
981     rHTMLWrt.bOutTable = sal_True;
982 
983     // die horizontale Ausrichtung des Rahmens hat (falls vorhanden)
984     // Prioritaet. NONE bedeutet, dass keine horizontale
985     // Ausrichtung geschrieben wird.
986     sal_Int16 eFlyHoriOri = text::HoriOrientation::NONE;
987     SwSurround eSurround = SURROUND_NONE;
988     sal_uInt8 nFlyPrcWidth = 0;
989     long nFlyWidth = 0;
990     sal_uInt16 nFlyHSpace = 0;
991     sal_uInt16 nFlyVSpace = 0;
992     if( pFlyFrmFmt )
993     {
994         eSurround = pFlyFrmFmt->GetSurround().GetSurround();
995         const SwFmtFrmSize& rFrmSize = pFlyFrmFmt->GetFrmSize();
996         nFlyPrcWidth = rFrmSize.GetWidthPercent();
997         nFlyWidth = rFrmSize.GetSize().Width();
998 
999         eFlyHoriOri = pFlyFrmFmt->GetHoriOrient().GetHoriOrient();
1000         if( text::HoriOrientation::NONE == eFlyHoriOri )
1001             eFlyHoriOri = text::HoriOrientation::LEFT;
1002 
1003         const SvxLRSpaceItem& rLRSpace = pFlyFrmFmt->GetLRSpace();
1004         nFlyHSpace = static_cast< sal_uInt16 >((rLRSpace.GetLeft() + rLRSpace.GetRight()) / 2);
1005 
1006         const SvxULSpaceItem& rULSpace = pFlyFrmFmt->GetULSpace();
1007         nFlyVSpace = (rULSpace.GetUpper() + rULSpace.GetLower()) / 2;
1008     }
1009 
1010     // ggf. eine FORM oeffnen
1011     sal_Bool bPreserveForm = sal_False;
1012     if( !rHTMLWrt.bPreserveForm )
1013     {
1014         rHTMLWrt.OutForm( sal_True, &rNode );
1015         bPreserveForm = (rHTMLWrt.pxFormComps && rHTMLWrt.pxFormComps->is() );
1016         rHTMLWrt.bPreserveForm = bPreserveForm;
1017     }
1018 
1019     SwFrmFmt *pFmt = rTbl.GetFrmFmt();
1020 
1021     const SwFmtFrmSize& rFrmSize = pFmt->GetFrmSize();
1022     long nWidth = rFrmSize.GetSize().Width();
1023     sal_uInt8 nPrcWidth = rFrmSize.GetWidthPercent();
1024     sal_uInt16 nBaseWidth = (sal_uInt16)nWidth;
1025 
1026     sal_Int16 eTabHoriOri = pFmt->GetHoriOrient().GetHoriOrient();
1027 
1028     // text::HoriOrientation::NONE und text::HoriOrientation::FULL Tabellen benoetigen relative Breiten
1029     sal_uInt16 nNewDefListLvl = 0;
1030     sal_Bool bRelWidths = sal_False;
1031     sal_Bool bCheckDefList = sal_False;
1032     switch( eTabHoriOri )
1033     {
1034     case text::HoriOrientation::FULL:
1035         // Tabellen mit automatischer Ausrichtung werden zu Tabellen
1036         // mit 100%-Breite
1037         bRelWidths = sal_True;
1038         nWidth = 100;
1039         eTabHoriOri = text::HoriOrientation::LEFT;
1040         break;
1041     case text::HoriOrientation::NONE:
1042         {
1043             const SvxLRSpaceItem& aLRItem = pFmt->GetLRSpace();
1044             if( aLRItem.GetRight() )
1045             {
1046                 // Die Tabellenbreite wird anhand des linken und rechten
1047                 // Abstandes bestimmt. Deshalb versuchen wir die
1048                 // tatsaechliche Breite der Tabelle zu bestimmen. Wenn
1049                 // das nicht geht, machen wir eine 100% breite Tabelle
1050                 // draus.
1051                 nWidth = pFmt->FindLayoutRect(sal_True).Width();
1052                 if( !nWidth )
1053                 {
1054                     bRelWidths = sal_True;
1055                     nWidth = 100;
1056                 }
1057 
1058             }
1059             else if( nPrcWidth  )
1060             {
1061                 // Ohne rechten Rand bleibt die %-Breite erhalten
1062                 nWidth = nPrcWidth;
1063                 bRelWidths = sal_True;
1064             }
1065             else
1066             {
1067                 // Ohne rechten Rand bleibt auch eine absolute Breite erhalten
1068                 // Wir versuchen aber trotzdem ueber das Layout die
1069                 // tatsachliche Breite zu ermitteln.
1070                 long nRealWidth = pFmt->FindLayoutRect(sal_True).Width();
1071                 if( nRealWidth )
1072                     nWidth = nRealWidth;
1073             }
1074             bCheckDefList = sal_True;
1075         }
1076         break;
1077     case text::HoriOrientation::LEFT_AND_WIDTH:
1078         eTabHoriOri = text::HoriOrientation::LEFT;
1079         bCheckDefList = sal_True;
1080         // no break
1081     default:
1082         // In allen anderen Faellen kann eine absolute oder relative
1083         // Breite direkt uebernommen werden.
1084         if( nPrcWidth )
1085         {
1086             bRelWidths = sal_True;
1087             nWidth = nPrcWidth;
1088         }
1089         break;
1090     }
1091 
1092     if( bCheckDefList )
1093     {
1094         ASSERT( !rHTMLWrt.GetNumInfo().GetNumRule() ||
1095                 rHTMLWrt.GetNextNumInfo(),
1096                 "NumInfo fuer naechsten Absatz fehlt!" );
1097         const SvxLRSpaceItem& aLRItem = pFmt->GetLRSpace();
1098         if( aLRItem.GetLeft() > 0 && rHTMLWrt.nDefListMargin > 0 &&
1099             ( !rHTMLWrt.GetNumInfo().GetNumRule() ||
1100               ( rHTMLWrt.GetNextNumInfo() &&
1101                 (rHTMLWrt.GetNextNumInfo()->IsRestart() ||
1102                  rHTMLWrt.GetNumInfo().GetNumRule() !=
1103                     rHTMLWrt.GetNextNumInfo()->GetNumRule()) ) ) )
1104         {
1105             // Wenn der Absatz vor der Tabelle nicht numeriert ist oder
1106             // der Absatz nach der Tabelle mit einer anderen oder
1107             // (gar keiner) Regel numeriert ist, koennen wir
1108             // die Einrueckung ueber eine DL regeln. Sonst behalten wir
1109             // die Einrueckung der Numerierung bei.
1110             nNewDefListLvl = static_cast< sal_uInt16 >(
1111                 (aLRItem.GetLeft() + (rHTMLWrt.nDefListMargin/2)) /
1112                 rHTMLWrt.nDefListMargin );
1113         }
1114     }
1115 
1116     if( !pFlyFrmFmt && nNewDefListLvl != rHTMLWrt.nDefListLvl )
1117         rHTMLWrt.OutAndSetDefList( nNewDefListLvl );
1118 
1119     if( nNewDefListLvl )
1120     {
1121         if( rHTMLWrt.bLFPossible )
1122             rHTMLWrt.OutNewLine();
1123         HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_dd );
1124     }
1125 
1126     // eFlyHoriOri und eTabHoriOri besitzen nun nur noch die Werte
1127     // LEFT/CENTER und RIGHT!
1128     if( eFlyHoriOri!=text::HoriOrientation::NONE )
1129     {
1130         eTabHoriOri = eFlyHoriOri;
1131         // MIB 4.7.97: Wenn die Tabelle eine relative Breite besitzt,
1132         // dann richtet sich ihre Breite nach der des Rahmens, also
1133         // exportieren wir dessen Breite. Bei fixer Breite ist die Breite
1134         // der Tabelle massgeblich. Wer Tabellen mit relativer Breite <100%
1135         // in Rahmen steckt, ist selber schuld wenn nix Gutes bei rauskommt.
1136         if( bRelWidths )
1137         {
1138             nWidth = nFlyPrcWidth ? nFlyPrcWidth : nFlyWidth;
1139             bRelWidths = nFlyPrcWidth > 0;
1140         }
1141     }
1142 
1143     sal_Int16 eDivHoriOri = text::HoriOrientation::NONE;
1144     switch( eTabHoriOri )
1145     {
1146     case text::HoriOrientation::LEFT:
1147         // Wenn eine linksbuendigeTabelle keinen rechtsseiigen Durchlauf
1148         // hat, brauchen wir auch kein ALIGN=LEFT in der Tabelle.
1149         if( eSurround==SURROUND_NONE || eSurround==SURROUND_LEFT )
1150             eTabHoriOri = text::HoriOrientation::NONE;
1151         break;
1152     case text::HoriOrientation::RIGHT:
1153         // Aehnliches gilt fuer rechtsbuendigeTabelle, hier nehmen wir
1154         // stattdessen ein <DIV ALIGN=RIGHT>.
1155         if( eSurround==SURROUND_NONE || eSurround==SURROUND_RIGHT )
1156         {
1157             eDivHoriOri = text::HoriOrientation::RIGHT;
1158             eTabHoriOri = text::HoriOrientation::NONE;
1159         }
1160         break;
1161     case text::HoriOrientation::CENTER:
1162         // ALIGN=CENTER versteht so gut wie keiner, deshalb verzichten wir
1163         // daruf und nehmen ein <CENTER>.
1164         eDivHoriOri = text::HoriOrientation::CENTER;
1165         eTabHoriOri = text::HoriOrientation::NONE;
1166         break;
1167     default:
1168         ;
1169     }
1170     if( text::HoriOrientation::NONE==eTabHoriOri )
1171         nFlyHSpace = nFlyVSpace = 0;
1172 
1173     if( pFmt->GetName().Len() )
1174         rHTMLWrt.OutImplicitMark( pFmt->GetName(), pMarkToTable );
1175 
1176     if( text::HoriOrientation::NONE!=eDivHoriOri )
1177     {
1178         if( rHTMLWrt.bLFPossible )
1179             rHTMLWrt.OutNewLine();  // <CENTER> in neuer Zeile
1180         if( text::HoriOrientation::CENTER==eDivHoriOri )
1181             HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_center, sal_True );
1182         else
1183         {
1184             ByteString sOut( OOO_STRING_SVTOOLS_HTML_division );
1185             (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_align) += '=') += OOO_STRING_SVTOOLS_HTML_AL_right;
1186             HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), sOut.GetBuffer(),
1187                                         sal_True );
1188         }
1189         rHTMLWrt.IncIndentLevel();  // Inhalt von <CENTER> einruecken
1190         rHTMLWrt.bLFPossible = sal_True;
1191     }
1192 
1193     // Wenn die Tabelle in keinem Rahmen ist kann man immer ein LF ausgeben.
1194     if( text::HoriOrientation::NONE==eTabHoriOri )
1195         rHTMLWrt.bLFPossible = sal_True;
1196 
1197     const SwHTMLTableLayout *pLayout = rTbl.GetHTMLTableLayout();
1198 
1199 #ifdef DBG_UTIL
1200     ViewShell *pSh;
1201     rWrt.pDoc->GetEditShell( &pSh );
1202     if ( pSh && pSh->GetViewOptions()->IsTest1() )
1203         pLayout = 0;
1204 #endif
1205 
1206     if( pLayout && pLayout->IsExportable() )
1207     {
1208         SwHTMLWrtTable aTableWrt( pLayout );
1209         aTableWrt.Write( rHTMLWrt, eTabHoriOri, rTbl.GetRowsToRepeat() > 0,
1210                          pFmt, pCaption, bTopCaption,
1211                          nFlyHSpace, nFlyVSpace );
1212     }
1213     else
1214     {
1215         SwHTMLWrtTable aTableWrt( rTbl.GetTabLines(), nWidth,
1216                                   nBaseWidth, bRelWidths, rTbl.GetRowsToRepeat() );
1217         aTableWrt.Write( rHTMLWrt, eTabHoriOri, rTbl.GetRowsToRepeat() > 0,
1218                          pFmt, pCaption, bTopCaption,
1219                          nFlyHSpace, nFlyVSpace );
1220     }
1221 
1222     // Wenn die Tabelle in keinem Rahmen war kann man immer ein LF ausgeben.
1223     if( text::HoriOrientation::NONE==eTabHoriOri )
1224         rHTMLWrt.bLFPossible = sal_True;
1225 
1226     if( text::HoriOrientation::NONE!=eDivHoriOri )
1227     {
1228         rHTMLWrt.DecIndentLevel();  // Inhalt von <CENTER> einruecken
1229         rHTMLWrt.OutNewLine();      // </CENTER> in neue Teile
1230         HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(),
1231                                text::HoriOrientation::CENTER==eDivHoriOri ? OOO_STRING_SVTOOLS_HTML_center
1232                                                         : OOO_STRING_SVTOOLS_HTML_division, sal_False );
1233         rHTMLWrt.bLFPossible = sal_True;
1234     }
1235 
1236     // Pam hinter die Tabelle verschieben
1237     rHTMLWrt.pCurPam->GetPoint()->nNode = *rNode.EndOfSectionNode();
1238 
1239     if( bPreserveForm )
1240     {
1241         rHTMLWrt.bPreserveForm = sal_False;
1242         rHTMLWrt.OutForm( sal_False );
1243     }
1244 
1245     rHTMLWrt.bOutTable = sal_False;
1246 
1247     if( rHTMLWrt.GetNextNumInfo() &&
1248         !rHTMLWrt.GetNextNumInfo()->IsRestart() &&
1249         rHTMLWrt.GetNextNumInfo()->GetNumRule() ==
1250             rHTMLWrt.GetNumInfo().GetNumRule() )
1251     {
1252         // Wenn der Absatz hinter der Tabelle mit der gleichen Regel
1253         // numeriert ist wie der Absatz vor der Tabelle, dann steht in
1254         // der NumInfo des naechsten Absatzes noch die Ebene des Absatzes
1255         // vor der Tabelle. Es muss deshalb die NumInfo noch einmal geholt
1256         // werden um ggf. die Num-Liste noch zu beenden.
1257         rHTMLWrt.ClearNextNumInfo();
1258         rHTMLWrt.FillNextNumInfo();
1259         OutHTML_NumBulListEnd( rHTMLWrt, *rHTMLWrt.GetNextNumInfo() );
1260     }
1261     return rWrt;
1262 }
1263 
1264 
1265