Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / sc / source / filter / html / htmlexp.cxx
bloba31caa8e31ca49de684e1338af83227cd0d1c6ea
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <scitems.hxx>
21 #include <editeng/eeitem.hxx>
23 #include <vcl/svapp.hxx>
24 #include <editeng/boxitem.hxx>
25 #include <editeng/brushitem.hxx>
26 #include <editeng/colritem.hxx>
27 #include <editeng/crossedoutitem.hxx>
28 #include <editeng/fhgtitem.hxx>
29 #include <editeng/fontitem.hxx>
30 #include <editeng/postitem.hxx>
31 #include <editeng/udlnitem.hxx>
32 #include <editeng/wghtitem.hxx>
33 #include <editeng/justifyitem.hxx>
34 #include <svx/xoutbmp.hxx>
35 #include <editeng/editeng.hxx>
36 #include <svtools/htmlcfg.hxx>
37 #include <sfx2/docfile.hxx>
38 #include <sfx2/frmhtmlw.hxx>
39 #include <sfx2/objsh.hxx>
40 #include <svl/urihelper.hxx>
41 #include <svtools/htmlkywd.hxx>
42 #include <svtools/htmlout.hxx>
43 #include <svtools/parhtml.hxx>
44 #include <vcl/outdev.hxx>
45 #include <stdio.h>
46 #include <osl/diagnose.h>
48 #include <htmlexp.hxx>
49 #include <global.hxx>
50 #include <postit.hxx>
51 #include <document.hxx>
52 #include <attrib.hxx>
53 #include <patattr.hxx>
54 #include <stlpool.hxx>
55 #include <scresid.hxx>
56 #include <formulacell.hxx>
57 #include <cellform.hxx>
58 #include <docoptio.hxx>
59 #include <editutil.hxx>
60 #include <ftools.hxx>
61 #include <cellvalue.hxx>
62 #include <mtvelements.hxx>
64 #include <editeng/flditem.hxx>
65 #include <editeng/borderline.hxx>
67 // Without strings.hrc: error C2679: binary '=' : no operator defined which takes a
68 // right-hand operand of type 'const class String (__stdcall *)(class ScResId)'
69 // at
70 // const String aStrTable( ScResId( SCSTR_TABLE ) ); aStrOut = aStrTable;
71 // ?!???
72 #include <strings.hrc>
73 #include <globstr.hrc>
75 #include <com/sun/star/uno/Reference.h>
76 #include <com/sun/star/document/XDocumentProperties.hpp>
77 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
78 #include <rtl/strbuf.hxx>
80 using ::editeng::SvxBorderLine;
81 using namespace ::com::sun::star;
83 const static sal_Char sMyBegComment[] = "<!-- ";
84 const static sal_Char sMyEndComment[] = " -->";
85 const static sal_Char sDisplay[] = "display:";
86 const static sal_Char sBorder[] = "border:";
87 const static sal_Char sBackground[] = "background:";
89 const sal_uInt16 ScHTMLExport::nDefaultFontSize[SC_HTML_FONTSIZES] =
91 HTMLFONTSZ1_DFLT, HTMLFONTSZ2_DFLT, HTMLFONTSZ3_DFLT, HTMLFONTSZ4_DFLT,
92 HTMLFONTSZ5_DFLT, HTMLFONTSZ6_DFLT, HTMLFONTSZ7_DFLT
95 sal_uInt16 ScHTMLExport::nFontSize[SC_HTML_FONTSIZES] = { 0 };
97 const char* ScHTMLExport::pFontSizeCss[SC_HTML_FONTSIZES] =
99 "xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large"
102 const sal_uInt16 ScHTMLExport::nCellSpacing = 0;
103 const sal_Char ScHTMLExport::sIndentSource[nIndentMax+1] =
104 "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
106 // Macros for HTML export
108 #define TAG_ON( tag ) HTMLOutFuncs::Out_AsciiTag( rStrm, tag )
109 #define TAG_OFF( tag ) HTMLOutFuncs::Out_AsciiTag( rStrm, tag, false )
110 #define OUT_STR( str ) HTMLOutFuncs::Out_String( rStrm, str, eDestEnc, &aNonConvertibleChars )
111 #define OUT_LF() rStrm.WriteCharPtr( SAL_NEWLINE_STRING ).WriteCharPtr( GetIndentStr() )
112 #define TAG_ON_LF( tag ) (TAG_ON( tag ).WriteCharPtr( SAL_NEWLINE_STRING ).WriteCharPtr( GetIndentStr() ))
113 #define TAG_OFF_LF( tag ) (TAG_OFF( tag ).WriteCharPtr( SAL_NEWLINE_STRING ).WriteCharPtr( GetIndentStr() ))
114 #define OUT_HR() TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_horzrule )
115 #define OUT_COMMENT( comment ) (rStrm.WriteCharPtr( sMyBegComment ), OUT_STR( comment ) \
116 .WriteCharPtr( sMyEndComment ).WriteCharPtr( SAL_NEWLINE_STRING ) \
117 .WriteCharPtr( GetIndentStr() ))
119 #define OUT_SP_CSTR_ASS( s ) rStrm.WriteChar( ' ').WriteCharPtr( s ).WriteChar( '=' )
121 #define GLOBSTR(id) ScResId( id )
123 void ScFormatFilterPluginImpl::ScExportHTML( SvStream& rStrm, const OUString& rBaseURL, ScDocument* pDoc,
124 const ScRange& rRange, const rtl_TextEncoding /*eNach*/, bool bAll,
125 const OUString& rStreamPath, OUString& rNonConvertibleChars, const OUString& rFilterOptions )
127 ScHTMLExport aEx( rStrm, rBaseURL, pDoc, rRange, bAll, rStreamPath, rFilterOptions );
128 aEx.Write();
129 rNonConvertibleChars = aEx.GetNonConvertibleChars();
132 static OString lcl_getColGroupString(sal_Int32 nSpan, sal_Int32 nWidth)
134 OStringBuffer aByteStr(OOO_STRING_SVTOOLS_HTML_colgroup);
135 aByteStr.append(' ');
136 if( nSpan > 1 )
138 aByteStr.append(OOO_STRING_SVTOOLS_HTML_O_span);
139 aByteStr.append("=\"");
140 aByteStr.append(nSpan);
141 aByteStr.append("\" ");
143 aByteStr.append(OOO_STRING_SVTOOLS_HTML_O_width);
144 aByteStr.append("=\"");
145 aByteStr.append(nWidth);
146 aByteStr.append('"');
147 return aByteStr.makeStringAndClear();
150 static void lcl_AddStamp( OUString& rStr, const OUString& rName,
151 const css::util::DateTime& rDateTime,
152 const LocaleDataWrapper& rLoc )
154 Date aD(rDateTime.Day, rDateTime.Month, rDateTime.Year);
155 tools::Time aT(rDateTime.Hours, rDateTime.Minutes, rDateTime.Seconds,
156 rDateTime.NanoSeconds);
157 DateTime aDateTime(aD,aT);
159 OUString aStrDate = rLoc.getDate( aDateTime );
160 OUString aStrTime = rLoc.getTime( aDateTime );
162 rStr += GLOBSTR( STR_BY ) + " ";
163 if (!rName.isEmpty())
164 rStr += rName;
165 else
166 rStr += "???";
167 rStr += " " + GLOBSTR( STR_ON ) + " ";
168 if (!aStrDate.isEmpty())
169 rStr += aStrDate;
170 else
171 rStr += "???";
172 rStr += ", ";
173 if (!aStrTime.isEmpty())
174 rStr += aStrTime;
175 else
176 rStr += "???";
179 static OString lcl_makeHTMLColorTriplet(const Color& rColor)
181 sal_Char buf[24];
183 // <font COLOR="#00FF40">hello</font>
184 snprintf( buf, 24, "\"#%02X%02X%02X\"", rColor.GetRed(), rColor.GetGreen(), rColor.GetBlue() );
186 return buf;
189 ScHTMLExport::ScHTMLExport( SvStream& rStrmP, const OUString& rBaseURL, ScDocument* pDocP,
190 const ScRange& rRangeP, bool bAllP,
191 const OUString& rStreamPathP, const OUString& rFilterOptions ) :
192 ScExportBase( rStrmP, pDocP, rRangeP ),
193 aBaseURL( rBaseURL ),
194 aStreamPath( rStreamPathP ),
195 pAppWin( Application::GetDefaultDevice() ),
196 nUsedTables( 0 ),
197 nIndent( 0 ),
198 bAll( bAllP ),
199 bTabHasGraphics( false ),
200 bTabAlignedLeft( false ),
201 bCalcAsShown( pDocP->GetDocOptions().IsCalcAsShown() ),
202 bTableDataHeight( true ),
203 mbSkipImages ( false ),
204 mbSkipHeaderFooter( false )
206 strcpy( sIndent, sIndentSource );
207 sIndent[0] = 0;
209 // set HTML configuration
210 SvxHtmlOptions& rHtmlOptions = SvxHtmlOptions::Get();
211 eDestEnc = (pDoc->IsClipOrUndo() ? RTL_TEXTENCODING_UTF8 : rHtmlOptions.GetTextEncoding());
212 bCopyLocalFileToINet = rHtmlOptions.IsSaveGraphicsLocal();
214 if (rFilterOptions == "SkipImages")
216 mbSkipImages = true;
218 else if (rFilterOptions == "SkipHeaderFooter")
220 mbSkipHeaderFooter = true;
223 for ( sal_uInt16 j=0; j < SC_HTML_FONTSIZES; j++ )
225 sal_uInt16 nSize = rHtmlOptions.GetFontSize( j );
226 // remember in Twips, like our SvxFontHeightItem
227 if ( nSize )
228 nFontSize[j] = nSize * 20;
229 else
230 nFontSize[j] = nDefaultFontSize[j] * 20;
233 const SCTAB nCount = pDoc->GetTableCount();
234 for ( SCTAB nTab = 0; nTab < nCount; nTab++ )
236 if ( !IsEmptyTable( nTab ) )
237 nUsedTables++;
241 ScHTMLExport::~ScHTMLExport()
243 aGraphList.clear();
246 sal_uInt16 ScHTMLExport::GetFontSizeNumber( sal_uInt16 nHeight )
248 sal_uInt16 nSize = 1;
249 for ( sal_uInt16 j=SC_HTML_FONTSIZES-1; j>0; j-- )
251 if( nHeight > (nFontSize[j] + nFontSize[j-1]) / 2 )
252 { // The one next to it
253 nSize = j+1;
254 break;
257 return nSize;
260 const char* ScHTMLExport::GetFontSizeCss( sal_uInt16 nHeight )
262 sal_uInt16 nSize = GetFontSizeNumber( nHeight );
263 return pFontSizeCss[ nSize-1 ];
266 sal_uInt16 ScHTMLExport::ToPixel( sal_uInt16 nVal )
268 if( nVal )
270 nVal = static_cast<sal_uInt16>(pAppWin->LogicToPixel(
271 Size( nVal, nVal ), MapMode( MapUnit::MapTwip ) ).Width());
272 if( !nVal ) // If there's a Twip there should also be a Pixel
273 nVal = 1;
275 return nVal;
278 Size ScHTMLExport::MMToPixel( const Size& rSize )
280 Size aSize = pAppWin->LogicToPixel( rSize, MapMode( MapUnit::Map100thMM ) );
281 // If there's something there should also be a Pixel
282 if ( !aSize.Width() && rSize.Width() )
283 aSize.setWidth( 1 );
284 if ( !aSize.Height() && rSize.Height() )
285 aSize.setHeight( 1 );
286 return aSize;
289 void ScHTMLExport::Write()
291 if (!mbSkipHeaderFooter)
293 rStrm.WriteChar( '<' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_doctype ).WriteChar( ' ' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_doctype40 ).WriteChar( '>' )
294 .WriteCharPtr( SAL_NEWLINE_STRING ).WriteCharPtr( SAL_NEWLINE_STRING );
295 TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_html );
296 WriteHeader();
297 OUT_LF();
299 WriteBody();
300 OUT_LF();
301 if (!mbSkipHeaderFooter)
302 TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_html );
305 void ScHTMLExport::WriteHeader()
307 IncIndent(1); TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_head );
309 if ( pDoc->IsClipOrUndo() )
310 { // no real DocInfo available, but some META information like charset needed
311 SfxFrameHTMLWriter::Out_DocInfo( rStrm, aBaseURL, nullptr, sIndent, eDestEnc, &aNonConvertibleChars );
313 else
315 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
316 pDoc->GetDocumentShell()->GetModel(), uno::UNO_QUERY_THROW);
317 uno::Reference<document::XDocumentProperties> xDocProps
318 = xDPS->getDocumentProperties();
319 SfxFrameHTMLWriter::Out_DocInfo( rStrm, aBaseURL, xDocProps,
320 sIndent, eDestEnc, &aNonConvertibleChars );
321 OUT_LF();
323 if (!xDocProps->getPrintedBy().isEmpty())
325 OUT_COMMENT( GLOBSTR( STR_DOC_INFO ) );
326 OUString aStrOut = GLOBSTR( STR_DOC_PRINTED ) + ": ";
327 lcl_AddStamp( aStrOut, xDocProps->getPrintedBy(),
328 xDocProps->getPrintDate(), *ScGlobal::pLocaleData );
329 OUT_COMMENT( aStrOut );
333 OUT_LF();
335 // CSS1 StyleSheet
336 PageDefaults( bAll ? 0 : aRange.aStart.Tab() );
337 IncIndent(1);
338 rStrm.WriteCharPtr( "<" ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_style ).WriteCharPtr( " " ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_O_type ).WriteCharPtr( "=\"text/css\">" );
340 OUT_LF();
341 rStrm.WriteCharPtr( OOO_STRING_SVTOOLS_HTML_body ).WriteCharPtr( "," ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_division ).WriteCharPtr( "," ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_table ).WriteCharPtr( "," )
342 .WriteCharPtr( OOO_STRING_SVTOOLS_HTML_thead ).WriteCharPtr( "," ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_tbody ).WriteCharPtr( "," ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_tfoot ).WriteCharPtr( "," )
343 .WriteCharPtr( OOO_STRING_SVTOOLS_HTML_tablerow ).WriteCharPtr( "," ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_tableheader ).WriteCharPtr( "," )
344 .WriteCharPtr( OOO_STRING_SVTOOLS_HTML_tabledata ).WriteCharPtr( "," ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_parabreak )
345 .WriteCharPtr( " { " ).WriteCharPtr( "font-family:" );
346 if (!aHTMLStyle.aFontFamilyName.isEmpty())
348 const OUString& rList = aHTMLStyle.aFontFamilyName;
349 for(sal_Int32 nPos {0};;)
351 rStrm.WriteChar( '\"' );
352 OUT_STR( rList.getToken( 0, ';', nPos ) );
353 rStrm.WriteChar( '\"' );
354 if (nPos<0)
355 break;
356 rStrm.WriteCharPtr( ", " );
359 rStrm.WriteCharPtr( "; " ).WriteCharPtr( "font-size:" )
360 .WriteCharPtr( GetFontSizeCss( static_cast<sal_uInt16>(aHTMLStyle.nFontHeight) ) ).WriteCharPtr( " }" );
362 OUT_LF();
364 // write the style for the comments to make them stand out from normal cell content
365 // this is done through only showing the cell contents when the custom indicator is hovered
366 rStrm.WriteCharPtr( OOO_STRING_SVTOOLS_HTML_anchor ).WriteCharPtr(".comment-indicator:hover")
367 .WriteCharPtr(" + ").WriteCharPtr( OOO_STRING_SVTOOLS_HTML_comment2 ).WriteCharPtr(" { ")
368 .WriteCharPtr(sBackground).WriteCharPtr("#ffd").WriteCharPtr("; ")
369 .WriteCharPtr("position:").WriteCharPtr("absolute").WriteCharPtr("; ")
370 .WriteCharPtr(sDisplay).WriteCharPtr("block").WriteCharPtr("; ")
371 .WriteCharPtr(sBorder).WriteCharPtr("1px solid black").WriteCharPtr("; ")
372 .WriteCharPtr("padding:").WriteCharPtr("0.5em").WriteCharPtr("; ")
373 .WriteCharPtr(" } ");
375 OUT_LF();
377 rStrm.WriteCharPtr( OOO_STRING_SVTOOLS_HTML_anchor ).WriteCharPtr(".comment-indicator")
378 .WriteCharPtr(" { ")
379 .WriteCharPtr(sBackground).WriteCharPtr("red").WriteCharPtr("; ")
380 .WriteCharPtr(sDisplay).WriteCharPtr("inline-block").WriteCharPtr("; ")
381 .WriteCharPtr(sBorder).WriteCharPtr("1px solid black").WriteCharPtr("; ")
382 .WriteCharPtr("width:").WriteCharPtr("0.5em").WriteCharPtr("; ")
383 .WriteCharPtr("height:").WriteCharPtr("0.5em").WriteCharPtr("; ")
384 .WriteCharPtr(" } ");
386 OUT_LF();
388 rStrm.WriteCharPtr( OOO_STRING_SVTOOLS_HTML_comment2 ).WriteCharPtr(" { ")
389 .WriteCharPtr(sDisplay).WriteCharPtr("none").WriteCharPtr("; ")
390 .WriteCharPtr(" } ");
393 IncIndent(-1); OUT_LF(); TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_style );
395 IncIndent(-1); OUT_LF(); TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_head );
398 void ScHTMLExport::WriteOverview()
400 if ( nUsedTables > 1 )
402 IncIndent(1);
403 OUT_HR();
404 IncIndent(1); TAG_ON( OOO_STRING_SVTOOLS_HTML_parabreak ); TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_center );
405 TAG_ON( OOO_STRING_SVTOOLS_HTML_head1 );
406 OUT_STR( ScResId( STR_OVERVIEW ) );
407 TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_head1 );
409 OUString aStr;
411 const SCTAB nCount = pDoc->GetTableCount();
412 for ( SCTAB nTab = 0; nTab < nCount; nTab++ )
414 if ( !IsEmptyTable( nTab ) )
416 pDoc->GetName( nTab, aStr );
417 rStrm.WriteCharPtr( "<A HREF=\"#table" )
418 .WriteOString( OString::number(nTab) )
419 .WriteCharPtr( "\">" );
420 OUT_STR( aStr );
421 rStrm.WriteCharPtr( "</A>" );
422 TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_linebreak );
426 IncIndent(-1); OUT_LF();
427 IncIndent(-1); TAG_OFF( OOO_STRING_SVTOOLS_HTML_center ); TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_parabreak );
431 const SfxItemSet& ScHTMLExport::PageDefaults( SCTAB nTab )
433 SfxStyleSheetBasePool* pStylePool = pDoc->GetStyleSheetPool();
434 SfxStyleSheetBase* pStyleSheet = nullptr;
435 OSL_ENSURE( pStylePool, "StylePool not found! :-(" );
437 // remember defaults for compare in WriteCell
438 if ( !aHTMLStyle.bInitialized )
440 pStylePool->SetSearchMask( SfxStyleFamily::Para );
441 pStyleSheet = pStylePool->Find(
442 ScResId(STR_STYLENAME_STANDARD),
443 SfxStyleFamily::Para );
444 OSL_ENSURE( pStyleSheet, "ParaStyle not found! :-(" );
445 if (!pStyleSheet)
446 pStyleSheet = pStylePool->First();
447 const SfxItemSet& rSetPara = pStyleSheet->GetItemSet();
449 aHTMLStyle.nDefaultScriptType = ScGlobal::GetDefaultScriptType();
450 aHTMLStyle.aFontFamilyName = static_cast<const SvxFontItem&>((rSetPara.Get(
451 ScGlobal::GetScriptedWhichID(
452 aHTMLStyle.nDefaultScriptType, ATTR_FONT
453 )))).GetFamilyName();
454 aHTMLStyle.nFontHeight = static_cast<const SvxFontHeightItem&>((rSetPara.Get(
455 ScGlobal::GetScriptedWhichID(
456 aHTMLStyle.nDefaultScriptType, ATTR_FONT_HEIGHT
457 )))).GetHeight();
458 aHTMLStyle.nFontSizeNumber = GetFontSizeNumber( static_cast< sal_uInt16 >( aHTMLStyle.nFontHeight ) );
461 // Page style sheet printer settings, e.g. for background graphics.
462 // There's only one background graphic in HTML!
463 pStylePool->SetSearchMask( SfxStyleFamily::Page );
464 pStyleSheet = pStylePool->Find( pDoc->GetPageStyle( nTab ), SfxStyleFamily::Page );
465 OSL_ENSURE( pStyleSheet, "PageStyle not found! :-(" );
466 if (!pStyleSheet)
467 pStyleSheet = pStylePool->First();
468 const SfxItemSet& rSet = pStyleSheet->GetItemSet();
469 if ( !aHTMLStyle.bInitialized )
471 const SvxBrushItem* pBrushItem = &rSet.Get( ATTR_BACKGROUND );
472 aHTMLStyle.aBackgroundColor = pBrushItem->GetColor();
473 aHTMLStyle.bInitialized = true;
475 return rSet;
478 OString ScHTMLExport::BorderToStyle(const char* pBorderName,
479 const SvxBorderLine* pLine, bool& bInsertSemicolon)
481 OStringBuffer aOut;
483 if ( pLine )
485 if ( bInsertSemicolon )
486 aOut.append("; ");
488 // which border
489 aOut.append("border-").append(pBorderName).append(": ");
491 // thickness
492 int nWidth = pLine->GetWidth();
493 int nPxWidth = (nWidth > 0) ?
494 std::max(int(nWidth / TWIPS_PER_PIXEL), 1) : 0;
495 aOut.append(static_cast<sal_Int32>(nPxWidth)).
496 append("px ");
497 switch (pLine->GetBorderLineStyle())
499 case SvxBorderLineStyle::SOLID:
500 aOut.append("solid");
501 break;
502 case SvxBorderLineStyle::DOTTED:
503 aOut.append("dotted");
504 break;
505 case SvxBorderLineStyle::DASHED:
506 case SvxBorderLineStyle::DASH_DOT:
507 case SvxBorderLineStyle::DASH_DOT_DOT:
508 aOut.append("dashed");
509 break;
510 case SvxBorderLineStyle::DOUBLE:
511 case SvxBorderLineStyle::DOUBLE_THIN:
512 case SvxBorderLineStyle::THINTHICK_SMALLGAP:
513 case SvxBorderLineStyle::THINTHICK_MEDIUMGAP:
514 case SvxBorderLineStyle::THINTHICK_LARGEGAP:
515 case SvxBorderLineStyle::THICKTHIN_SMALLGAP:
516 case SvxBorderLineStyle::THICKTHIN_MEDIUMGAP:
517 case SvxBorderLineStyle::THICKTHIN_LARGEGAP:
518 aOut.append("double");
519 break;
520 case SvxBorderLineStyle::EMBOSSED:
521 aOut.append("ridge");
522 break;
523 case SvxBorderLineStyle::ENGRAVED:
524 aOut.append("groove");
525 break;
526 case SvxBorderLineStyle::OUTSET:
527 aOut.append("outset");
528 break;
529 case SvxBorderLineStyle::INSET:
530 aOut.append("inset");
531 break;
532 default:
533 aOut.append("hidden");
535 aOut.append(" #");
537 // color
538 char hex[7];
539 snprintf( hex, 7, "%06" SAL_PRIxUINT32, static_cast<sal_uInt32>( pLine->GetColor().GetRGBColor() ) );
540 hex[6] = 0;
542 aOut.append(hex);
544 bInsertSemicolon = true;
547 return aOut.makeStringAndClear();
550 void ScHTMLExport::WriteBody()
552 const SfxItemSet& rSet = PageDefaults( bAll ? 0 : aRange.aStart.Tab() );
553 const SvxBrushItem* pBrushItem = &rSet.Get( ATTR_BACKGROUND );
555 // default text color black
556 if (!mbSkipHeaderFooter)
558 rStrm.WriteChar( '<' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_body );
560 if (!mbSkipImages)
562 if ( bAll && GPOS_NONE != pBrushItem->GetGraphicPos() )
564 OUString aLink = pBrushItem->GetGraphicLink();
565 OUString aGrfNm;
567 // Embedded graphic -> write using WriteGraphic
568 if( aLink.isEmpty() )
570 const Graphic* pGrf = pBrushItem->GetGraphic();
571 if( pGrf )
573 // Save graphic as (JPG) file
574 aGrfNm = aStreamPath;
575 ErrCode nErr = XOutBitmap::WriteGraphic( *pGrf, aGrfNm,
576 "JPG", XOutFlags::UseNativeIfPossible );
577 if( !nErr ) // Contains errors, as we have nothing to output
579 aGrfNm = URIHelper::SmartRel2Abs(
580 INetURLObject(aBaseURL),
581 aGrfNm, URIHelper::GetMaybeFileHdl());
582 aLink = aGrfNm;
586 else
588 aGrfNm = aLink;
589 if( bCopyLocalFileToINet )
591 CopyLocalFileToINet( aGrfNm, aStreamPath );
593 else
594 aGrfNm = URIHelper::SmartRel2Abs(
595 INetURLObject(aBaseURL),
596 aGrfNm, URIHelper::GetMaybeFileHdl());
597 aLink = aGrfNm;
599 if( !aLink.isEmpty() )
601 rStrm.WriteChar( ' ' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_O_background ).WriteCharPtr( "=\"" );
602 OUT_STR( URIHelper::simpleNormalizedMakeRelative(
603 aBaseURL,
604 aLink ) ).WriteChar( '\"' );
608 if ( !aHTMLStyle.aBackgroundColor.GetTransparency() )
609 { // A transparent background color should always result in default
610 // background of the browser. Also, HTMLOutFuncs::Out_Color() writes
611 // black #000000 for COL_AUTO which is the same as white #ffffff with
612 // transparency set to 0xff, our default background.
613 OUT_SP_CSTR_ASS( OOO_STRING_SVTOOLS_HTML_O_bgcolor );
614 HTMLOutFuncs::Out_Color( rStrm, aHTMLStyle.aBackgroundColor );
617 rStrm.WriteChar( '>' ); OUT_LF();
620 if ( bAll )
621 WriteOverview();
623 WriteTables();
625 if (!mbSkipHeaderFooter)
626 TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_body );
629 void ScHTMLExport::WriteTables()
631 const SCTAB nTabCount = pDoc->GetTableCount();
632 const OUString aStrTable( ScResId( SCSTR_TABLE ) );
633 OUString aStr;
634 OUString aStrOut;
635 SCCOL nStartCol;
636 SCROW nStartRow;
637 SCTAB nStartTab;
638 SCCOL nEndCol;
639 SCROW nEndRow;
640 SCTAB nEndTab;
641 SCCOL nStartColFix = 0;
642 SCROW nStartRowFix = 0;
643 SCCOL nEndColFix = 0;
644 SCROW nEndRowFix = 0;
645 ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
646 if ( bAll )
648 nStartTab = 0;
649 nEndTab = nTabCount - 1;
651 else
653 nStartCol = nStartColFix = aRange.aStart.Col();
654 nStartRow = nStartRowFix = aRange.aStart.Row();
655 nStartTab = aRange.aStart.Tab();
656 nEndCol = nEndColFix = aRange.aEnd.Col();
657 nEndRow = nEndRowFix = aRange.aEnd.Row();
658 nEndTab = aRange.aEnd.Tab();
660 SCTAB nTableStrNum = 1;
661 for ( SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++ )
663 if ( !pDoc->IsVisible( nTab ) )
664 continue; // for
666 if ( bAll )
668 if ( !GetDataArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow ) )
669 continue; // for
671 if ( nUsedTables > 1 )
673 aStrOut = aStrTable + " " + OUString::number( nTableStrNum++ ) + ": ";
675 OUT_HR();
677 // Write anchor
678 rStrm.WriteCharPtr( "<A NAME=\"table" )
679 .WriteOString( OString::number(nTab) )
680 .WriteCharPtr( "\">" );
681 TAG_ON( OOO_STRING_SVTOOLS_HTML_head1 );
682 OUT_STR( aStrOut );
683 TAG_ON( OOO_STRING_SVTOOLS_HTML_emphasis );
685 pDoc->GetName( nTab, aStr );
686 OUT_STR( aStr );
688 TAG_OFF( OOO_STRING_SVTOOLS_HTML_emphasis );
689 TAG_OFF( OOO_STRING_SVTOOLS_HTML_head1 );
690 rStrm.WriteCharPtr( "</A>" ); OUT_LF();
693 else
695 nStartCol = nStartColFix;
696 nStartRow = nStartRowFix;
697 nEndCol = nEndColFix;
698 nEndRow = nEndRowFix;
699 if ( !TrimDataArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow ) )
700 continue; // for
703 // <TABLE ...>
704 OStringBuffer aByteStrOut(OOO_STRING_SVTOOLS_HTML_table);
706 bTabHasGraphics = bTabAlignedLeft = false;
707 if ( bAll && pDrawLayer )
708 PrepareGraphics( pDrawLayer, nTab, nStartCol, nStartRow,
709 nEndCol, nEndRow );
711 // more <TABLE ...>
712 if ( bTabAlignedLeft )
714 aByteStrOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_align).
715 append("=\"").
716 append(OOO_STRING_SVTOOLS_HTML_AL_left).append('"');
718 // ALIGN=LEFT allow text and graphics to flow around
719 // CELLSPACING
720 aByteStrOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_cellspacing).
721 append("=\"").
722 append(static_cast<sal_Int32>(nCellSpacing)).append('"');
724 // BORDER=0, we do the styling of the cells in <TD>
725 aByteStrOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_border).
726 append("=\"0\"");
727 IncIndent(1); TAG_ON_LF( aByteStrOut.makeStringAndClear().getStr() );
729 // --- <COLGROUP> ----
731 SCCOL nCol = nStartCol;
732 sal_Int32 nWidth = 0;
733 sal_Int32 nSpan = 0;
734 while( nCol <= nEndCol )
736 if( pDoc->ColHidden(nCol, nTab) )
738 ++nCol;
739 continue;
742 if( nWidth != ToPixel( pDoc->GetColWidth( nCol, nTab ) ) )
744 if( nSpan != 0 )
746 TAG_ON(lcl_getColGroupString(nSpan, nWidth).getStr());
747 TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_colgroup );
749 nWidth = ToPixel( pDoc->GetColWidth( nCol, nTab ) );
750 nSpan = 1;
752 else
753 nSpan++;
754 nCol++;
756 if( nSpan )
758 TAG_ON(lcl_getColGroupString(nSpan, nWidth).getStr());
759 TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_colgroup );
763 // <TBODY> // Re-enable only when THEAD and TFOOT are exported
764 // IncIndent(1); TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_tbody );
765 // At least old (3.x, 4.x?) Netscape doesn't follow <TABLE COLS=n> and
766 // <COL WIDTH=x> specified, but needs a width at every column.
767 bool bHasHiddenRows = pDoc->HasHiddenRows(nStartRow, nEndRow, nTab);
768 // We need to cache sc::ColumnBlockPosition per each column.
769 std::vector< sc::ColumnBlockPosition > blockPos( nEndCol - nStartCol + 1 );
770 for( SCCOL i = nStartCol; i <= nEndCol; ++i )
771 pDoc->InitColumnBlockPosition( blockPos[ i - nStartCol ], nTab, i );
772 for ( SCROW nRow=nStartRow; nRow<=nEndRow; nRow++ )
774 if ( bHasHiddenRows && pDoc->RowHidden(nRow, nTab) )
776 nRow = pDoc->FirstVisibleRow(nRow+1, nEndRow, nTab);
777 --nRow;
778 continue; // for
781 IncIndent(1); TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_tablerow );
782 bTableDataHeight = true; // height at every first cell of each row
783 for ( SCCOL nCol2=nStartCol; nCol2<=nEndCol; nCol2++ )
785 if ( pDoc->ColHidden(nCol2, nTab) )
786 continue; // for
788 if ( nCol2 == nEndCol )
789 IncIndent(-1);
790 WriteCell( blockPos[ nCol2 - nStartCol ], nCol2, nRow, nTab );
791 bTableDataHeight = false;
794 if ( nRow == nEndRow )
795 IncIndent(-1);
796 TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_tablerow );
798 // TODO: Uncomment later
799 // IncIndent(-1); TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_tbody );
801 IncIndent(-1); TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_table );
803 if ( bTabHasGraphics && !mbSkipImages )
805 // the rest that is not in a cell
806 size_t ListSize = aGraphList.size();
807 for ( size_t i = 0; i < ListSize; ++i )
809 ScHTMLGraphEntry* pE = &aGraphList[ i ];
810 if ( !pE->bWritten )
811 WriteGraphEntry( pE );
813 aGraphList.clear();
814 if ( bTabAlignedLeft )
816 // clear <TABLE ALIGN=LEFT> with <BR CLEAR=LEFT>
817 aByteStrOut.append(OOO_STRING_SVTOOLS_HTML_linebreak);
818 aByteStrOut.append(' ').
819 append(OOO_STRING_SVTOOLS_HTML_O_clear).append('=').
820 append(OOO_STRING_SVTOOLS_HTML_AL_left);
821 TAG_ON_LF( aByteStrOut.makeStringAndClear().getStr() );
825 if ( bAll )
826 OUT_COMMENT( "**************************************************************************" );
830 void ScHTMLExport::WriteCell( sc::ColumnBlockPosition& rBlockPos, SCCOL nCol, SCROW nRow, SCTAB nTab )
832 ScAddress aPos( nCol, nRow, nTab );
833 ScRefCellValue aCell(*pDoc, aPos, rBlockPos);
834 const ScPatternAttr* pAttr = pDoc->GetPattern( nCol, nRow, nTab );
835 const SfxItemSet* pCondItemSet = pDoc->GetCondResult( nCol, nRow, nTab, &aCell );
837 const ScMergeFlagAttr& rMergeFlagAttr = pAttr->GetItem( ATTR_MERGE_FLAG, pCondItemSet );
838 if ( rMergeFlagAttr.IsOverlapped() )
839 return ;
841 ScHTMLGraphEntry* pGraphEntry = nullptr;
842 if ( bTabHasGraphics && !mbSkipImages )
844 size_t ListSize = aGraphList.size();
845 for ( size_t i = 0; i < ListSize; ++i )
847 ScHTMLGraphEntry* pE = &aGraphList[ i ];
848 if ( pE->bInCell && pE->aRange.In( aPos ) )
850 if ( pE->aRange.aStart == aPos )
852 pGraphEntry = pE;
853 break; // for
855 else
856 return ; // Is a Col/RowSpan, Overlapped
861 sal_uInt32 nFormat = pAttr->GetNumberFormat( pFormatter );
862 bool bValueData = aCell.hasNumeric();
863 SvtScriptType nScriptType = SvtScriptType::NONE;
864 if (!aCell.isEmpty())
865 nScriptType = pDoc->GetScriptType(nCol, nRow, nTab, &aCell);
867 if ( nScriptType == SvtScriptType::NONE )
868 nScriptType = aHTMLStyle.nDefaultScriptType;
870 OStringBuffer aStrTD(OOO_STRING_SVTOOLS_HTML_tabledata);
872 // border of the cells
873 const SvxBoxItem* pBorder = pDoc->GetAttr( nCol, nRow, nTab, ATTR_BORDER );
874 if ( pBorder && (pBorder->GetTop() || pBorder->GetBottom() || pBorder->GetLeft() || pBorder->GetRight()) )
876 aStrTD.append(' ').append(OOO_STRING_SVTOOLS_HTML_style).
877 append("=\"");
879 bool bInsertSemicolon = false;
880 aStrTD.append(BorderToStyle("top", pBorder->GetTop(),
881 bInsertSemicolon));
882 aStrTD.append(BorderToStyle("bottom", pBorder->GetBottom(),
883 bInsertSemicolon));
884 aStrTD.append(BorderToStyle("left", pBorder->GetLeft(),
885 bInsertSemicolon));
886 aStrTD.append(BorderToStyle("right", pBorder->GetRight(),
887 bInsertSemicolon));
889 aStrTD.append('"');
892 const sal_Char* pChar;
893 sal_uInt16 nHeightPixel;
895 const ScMergeAttr& rMergeAttr = pAttr->GetItem( ATTR_MERGE, pCondItemSet );
896 if ( pGraphEntry || rMergeAttr.IsMerged() )
898 SCCOL nC, jC;
899 SCROW nR;
900 sal_uLong v;
901 if ( pGraphEntry )
902 nC = std::max( SCCOL(pGraphEntry->aRange.aEnd.Col() - nCol + 1),
903 rMergeAttr.GetColMerge() );
904 else
905 nC = rMergeAttr.GetColMerge();
906 if ( nC > 1 )
908 aStrTD.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_colspan).
909 append('=').append(static_cast<sal_Int32>(nC));
910 nC = nC + nCol;
911 for ( jC=nCol, v=0; jC<nC; jC++ )
912 v += pDoc->GetColWidth( jC, nTab );
915 if ( pGraphEntry )
916 nR = std::max( SCROW(pGraphEntry->aRange.aEnd.Row() - nRow + 1),
917 rMergeAttr.GetRowMerge() );
918 else
919 nR = rMergeAttr.GetRowMerge();
920 if ( nR > 1 )
922 aStrTD.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_rowspan).
923 append('=').append(static_cast<sal_Int32>(nR));
924 nR += nRow;
925 v = pDoc->GetRowHeight( nRow, nR-1, nTab );
926 nHeightPixel = ToPixel( static_cast< sal_uInt16 >( v ) );
928 else
929 nHeightPixel = ToPixel( pDoc->GetRowHeight( nRow, nTab ) );
931 else
932 nHeightPixel = ToPixel( pDoc->GetRowHeight( nRow, nTab ) );
934 if ( bTableDataHeight )
936 aStrTD.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_height).
937 append("=\"").
938 append(static_cast<sal_Int32>(nHeightPixel)).append('"');
941 const SvxFontItem& rFontItem = static_cast<const SvxFontItem&>( pAttr->GetItem(
942 ScGlobal::GetScriptedWhichID( nScriptType, ATTR_FONT),
943 pCondItemSet) );
945 const SvxFontHeightItem& rFontHeightItem = static_cast<const SvxFontHeightItem&>(
946 pAttr->GetItem( ScGlobal::GetScriptedWhichID( nScriptType,
947 ATTR_FONT_HEIGHT), pCondItemSet) );
949 const SvxWeightItem& rWeightItem = static_cast<const SvxWeightItem&>( pAttr->GetItem(
950 ScGlobal::GetScriptedWhichID( nScriptType, ATTR_FONT_WEIGHT),
951 pCondItemSet) );
953 const SvxPostureItem& rPostureItem = static_cast<const SvxPostureItem&>(
954 pAttr->GetItem( ScGlobal::GetScriptedWhichID( nScriptType,
955 ATTR_FONT_POSTURE), pCondItemSet) );
957 const SvxUnderlineItem& rUnderlineItem =
958 pAttr->GetItem( ATTR_FONT_UNDERLINE, pCondItemSet );
960 const SvxCrossedOutItem& rCrossedOutItem =
961 pAttr->GetItem( ATTR_FONT_CROSSEDOUT, pCondItemSet );
963 const SvxColorItem& rColorItem = pAttr->GetItem(
964 ATTR_FONT_COLOR, pCondItemSet );
966 const SvxHorJustifyItem& rHorJustifyItem =
967 pAttr->GetItem( ATTR_HOR_JUSTIFY, pCondItemSet );
969 const SvxVerJustifyItem& rVerJustifyItem =
970 pAttr->GetItem( ATTR_VER_JUSTIFY, pCondItemSet );
972 const SvxBrushItem& rBrushItem = pAttr->GetItem(
973 ATTR_BACKGROUND, pCondItemSet );
975 Color aBgColor;
976 if ( rBrushItem.GetColor().GetTransparency() == 255 )
977 aBgColor = aHTMLStyle.aBackgroundColor; // No unwanted background color
978 else
979 aBgColor = rBrushItem.GetColor();
981 bool bBold = ( WEIGHT_BOLD <= rWeightItem.GetWeight() );
982 bool bItalic = ( ITALIC_NONE != rPostureItem.GetPosture() );
983 bool bUnderline = ( LINESTYLE_NONE != rUnderlineItem.GetLineStyle() );
984 bool bCrossedOut = ( STRIKEOUT_SINGLE <= rCrossedOutItem.GetStrikeout() );
985 bool bSetFontColor = ( COL_AUTO != rColorItem.GetValue() ); // default is AUTO now
986 bool bSetFontName = ( aHTMLStyle.aFontFamilyName != rFontItem.GetFamilyName() );
987 sal_uInt16 nSetFontSizeNumber = 0;
988 sal_uInt32 nFontHeight = rFontHeightItem.GetHeight();
989 if ( nFontHeight != aHTMLStyle.nFontHeight )
991 nSetFontSizeNumber = GetFontSizeNumber( static_cast<sal_uInt16>(nFontHeight) );
992 if ( nSetFontSizeNumber == aHTMLStyle.nFontSizeNumber )
993 nSetFontSizeNumber = 0; // no difference, don't set
996 bool bSetFont = (bSetFontColor || bSetFontName || nSetFontSizeNumber);
998 //! TODO: we could entirely use CSS1 here instead, but that would exclude
999 //! Netscape 3.0 and Netscape 4.x without JavaScript enabled.
1000 //! Do we want that?
1002 switch( rHorJustifyItem.GetValue() )
1004 case SvxCellHorJustify::Standard:
1005 pChar = (bValueData ? OOO_STRING_SVTOOLS_HTML_AL_right : OOO_STRING_SVTOOLS_HTML_AL_left);
1006 break;
1007 case SvxCellHorJustify::Center: pChar = OOO_STRING_SVTOOLS_HTML_AL_center; break;
1008 case SvxCellHorJustify::Block: pChar = OOO_STRING_SVTOOLS_HTML_AL_justify; break;
1009 case SvxCellHorJustify::Right: pChar = OOO_STRING_SVTOOLS_HTML_AL_right; break;
1010 case SvxCellHorJustify::Left:
1011 case SvxCellHorJustify::Repeat:
1012 default: pChar = OOO_STRING_SVTOOLS_HTML_AL_left; break;
1015 aStrTD.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_align).
1016 append("=\"").append(pChar).append('"');
1018 switch( rVerJustifyItem.GetValue() )
1020 case SvxCellVerJustify::Top: pChar = OOO_STRING_SVTOOLS_HTML_VA_top; break;
1021 case SvxCellVerJustify::Center: pChar = OOO_STRING_SVTOOLS_HTML_VA_middle; break;
1022 case SvxCellVerJustify::Bottom: pChar = OOO_STRING_SVTOOLS_HTML_VA_bottom; break;
1023 case SvxCellVerJustify::Standard:
1024 default: pChar = nullptr;
1026 if ( pChar )
1028 aStrTD.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_valign).
1029 append('=').append(pChar);
1032 if ( aHTMLStyle.aBackgroundColor != aBgColor )
1034 aStrTD.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_bgcolor).
1035 append('=');
1036 aStrTD.append(lcl_makeHTMLColorTriplet(aBgColor));
1039 double fVal = 0.0;
1040 if ( bValueData )
1042 switch (aCell.meType)
1044 case CELLTYPE_VALUE:
1045 fVal = aCell.mfValue;
1046 if ( bCalcAsShown && fVal != 0.0 )
1047 fVal = pDoc->RoundValueAsShown( fVal, nFormat );
1048 break;
1049 case CELLTYPE_FORMULA:
1050 fVal = aCell.mpFormula->GetValue();
1051 break;
1052 default:
1053 OSL_FAIL( "value data with unsupported cell type" );
1057 aStrTD.append(HTMLOutFuncs::CreateTableDataOptionsValNum(bValueData, fVal,
1058 nFormat, *pFormatter, eDestEnc, &aNonConvertibleChars));
1060 TAG_ON(aStrTD.makeStringAndClear().getStr());
1062 //write the note for this as the first thing in the tag
1063 ScPostIt* pNote = pDoc->HasNote(aPos) ? pDoc->GetNote(aPos) : nullptr;
1064 if (pNote)
1066 //create the comment indicator
1067 OString aStr = OOO_STRING_SVTOOLS_HTML_anchor " "
1068 OOO_STRING_SVTOOLS_HTML_O_class "=\"comment-indicator\"";
1069 TAG_ON(aStr.getStr());
1070 TAG_OFF(OOO_STRING_SVTOOLS_HTML_anchor);
1071 OUT_LF();
1073 //create the element holding the contents
1074 //this is a bit naive, since it doesn't separate
1075 //lines into html breaklines yet
1076 TAG_ON(OOO_STRING_SVTOOLS_HTML_comment2);
1077 OUT_STR( pNote->GetText() );
1078 TAG_OFF(OOO_STRING_SVTOOLS_HTML_comment2);
1079 OUT_LF();
1082 if ( bBold ) TAG_ON( OOO_STRING_SVTOOLS_HTML_bold );
1083 if ( bItalic ) TAG_ON( OOO_STRING_SVTOOLS_HTML_italic );
1084 if ( bUnderline ) TAG_ON( OOO_STRING_SVTOOLS_HTML_underline );
1085 if ( bCrossedOut ) TAG_ON( OOO_STRING_SVTOOLS_HTML_strikethrough );
1087 if ( bSetFont )
1089 OStringBuffer aStr(OOO_STRING_SVTOOLS_HTML_font);
1090 if ( bSetFontName )
1092 aStr.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_face).
1093 append("=\"");
1095 if (!rFontItem.GetFamilyName().isEmpty())
1097 const OUString& rList = rFontItem.GetFamilyName();
1098 for (sal_Int32 nPos {0};;)
1100 OString aTmpStr = HTMLOutFuncs::ConvertStringToHTML(
1101 rList.getToken( 0, ';', nPos ), eDestEnc,
1102 &aNonConvertibleChars);
1103 aStr.append(aTmpStr);
1104 if (nPos<0)
1105 break;
1106 aStr.append(',');
1110 aStr.append('\"');
1112 if ( nSetFontSizeNumber )
1114 aStr.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_size).
1115 append('=').append(static_cast<sal_Int32>(nSetFontSizeNumber));
1117 if ( bSetFontColor )
1119 Color aColor = rColorItem.GetValue();
1121 // always export automatic text color as black
1122 if ( aColor == COL_AUTO )
1123 aColor = COL_BLACK;
1125 aStr.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_color).
1126 append('=').append(lcl_makeHTMLColorTriplet(aColor));
1128 TAG_ON(aStr.makeStringAndClear().getStr());
1131 OUString aStrOut;
1132 bool bFieldText = false;
1134 Color* pColor;
1135 switch (aCell.meType)
1137 case CELLTYPE_EDIT :
1138 bFieldText = WriteFieldText(aCell.mpEditText);
1139 if ( bFieldText )
1140 break;
1141 [[fallthrough]];
1142 default:
1143 ScCellFormat::GetString(aCell, nFormat, aStrOut, &pColor, *pFormatter, pDoc);
1146 if ( !bFieldText )
1148 if ( aStrOut.isEmpty() )
1150 TAG_ON( OOO_STRING_SVTOOLS_HTML_linebreak ); // No completely empty line
1152 else
1154 sal_Int32 nPos = aStrOut.indexOf( '\n' );
1155 if ( nPos == -1 )
1157 OUT_STR( aStrOut );
1159 else
1161 sal_Int32 nStartPos = 0;
1164 OUString aSingleLine = aStrOut.copy( nStartPos, nPos - nStartPos );
1165 OUT_STR( aSingleLine );
1166 TAG_ON( OOO_STRING_SVTOOLS_HTML_linebreak );
1167 nStartPos = nPos + 1;
1169 while( ( nPos = aStrOut.indexOf( '\n', nStartPos ) ) != -1 );
1170 OUString aSingleLine = aStrOut.copy( nStartPos );
1171 OUT_STR( aSingleLine );
1175 if ( pGraphEntry )
1176 WriteGraphEntry( pGraphEntry );
1178 if ( bSetFont ) TAG_OFF( OOO_STRING_SVTOOLS_HTML_font );
1179 if ( bCrossedOut ) TAG_OFF( OOO_STRING_SVTOOLS_HTML_strikethrough );
1180 if ( bUnderline ) TAG_OFF( OOO_STRING_SVTOOLS_HTML_underline );
1181 if ( bItalic ) TAG_OFF( OOO_STRING_SVTOOLS_HTML_italic );
1182 if ( bBold ) TAG_OFF( OOO_STRING_SVTOOLS_HTML_bold );
1184 TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_tabledata );
1187 bool ScHTMLExport::WriteFieldText( const EditTextObject* pData )
1189 bool bFields = false;
1190 // text and anchor of URL fields, Doc-Engine is a ScFieldEditEngine
1191 EditEngine& rEngine = pDoc->GetEditEngine();
1192 rEngine.SetText( *pData );
1193 sal_Int32 nParas = rEngine.GetParagraphCount();
1194 if ( nParas )
1196 ESelection aSel( 0, 0, nParas-1, rEngine.GetTextLen( nParas-1 ) );
1197 SfxItemSet aSet( rEngine.GetAttribs( aSel ) );
1198 SfxItemState eFieldState = aSet.GetItemState( EE_FEATURE_FIELD, false );
1199 if ( eFieldState == SfxItemState::DONTCARE || eFieldState == SfxItemState::SET )
1200 bFields = true;
1202 if ( bFields )
1204 bool bOldUpdateMode = rEngine.GetUpdateMode();
1205 rEngine.SetUpdateMode( true ); // no portions if not formatted
1206 for ( sal_Int32 nPar=0; nPar < nParas; nPar++ )
1208 if ( nPar > 0 )
1209 TAG_ON( OOO_STRING_SVTOOLS_HTML_linebreak );
1210 std::vector<sal_Int32> aPortions;
1211 rEngine.GetPortions( nPar, aPortions );
1212 sal_Int32 nStart = 0;
1213 for ( const sal_Int32 nEnd : aPortions )
1215 ESelection aSel( nPar, nStart, nPar, nEnd );
1216 bool bUrl = false;
1217 // fields are single characters
1218 if ( nEnd == nStart+1 )
1220 const SfxPoolItem* pItem;
1221 SfxItemSet aSet = rEngine.GetAttribs( aSel );
1222 if ( aSet.GetItemState( EE_FEATURE_FIELD, false, &pItem ) == SfxItemState::SET )
1224 const SvxFieldData* pField = static_cast<const SvxFieldItem*>(pItem)->GetField();
1225 if (const SvxURLField* pURLField = dynamic_cast<const SvxURLField*>(pField))
1227 bUrl = true;
1228 rStrm.WriteChar( '<' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_anchor ).WriteChar( ' ' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_O_href ).WriteCharPtr( "=\"" );
1229 OUT_STR( pURLField->GetURL() );
1230 rStrm.WriteCharPtr( "\">" );
1231 OUT_STR( pURLField->GetRepresentation() );
1232 rStrm.WriteCharPtr( "</" ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_anchor ).WriteChar( '>' );
1236 if ( !bUrl )
1237 OUT_STR( rEngine.GetText( aSel ) );
1238 nStart = nEnd;
1241 rEngine.SetUpdateMode( bOldUpdateMode );
1243 return bFields;
1246 void ScHTMLExport::CopyLocalFileToINet( OUString& rFileNm,
1247 const OUString& rTargetNm )
1249 INetURLObject aFileUrl, aTargetUrl;
1250 aFileUrl.SetSmartURL( rFileNm );
1251 aTargetUrl.SetSmartURL( rTargetNm );
1252 if( INetProtocol::File == aFileUrl.GetProtocol() &&
1253 ( INetProtocol::File != aTargetUrl.GetProtocol() &&
1254 INetProtocol::Ftp <= aTargetUrl.GetProtocol() &&
1255 INetProtocol::Javascript >= aTargetUrl.GetProtocol()) )
1257 if( pFileNameMap )
1259 // Did we already move the file?
1260 std::map<OUString, OUString>::iterator it = pFileNameMap->find( rFileNm );
1261 if( it != pFileNameMap->end() )
1263 rFileNm = it->second;
1264 return;
1267 else
1269 pFileNameMap.reset( new std::map<OUString, OUString> );
1272 bool bRet = false;
1273 SvFileStream aTmp( aFileUrl.PathToFileName(), StreamMode::READ );
1275 OUString aSrc = rFileNm;
1276 OUString aDest = aTargetUrl.GetPartBeforeLastName() + aFileUrl.GetLastName();
1278 SfxMedium aMedium( aDest, StreamMode::WRITE | StreamMode::SHARE_DENYNONE );
1281 SvFileStream aCpy( aMedium.GetPhysicalName(), StreamMode::WRITE );
1282 aCpy.WriteStream( aTmp );
1285 // Take over
1286 aMedium.Close();
1287 aMedium.Commit();
1289 bRet = ERRCODE_NONE == aMedium.GetError();
1291 if( bRet )
1293 pFileNameMap->insert( std::make_pair( aSrc, aDest ) );
1294 rFileNm = aDest;
1299 void ScHTMLExport::IncIndent( short nVal )
1301 sIndent[nIndent] = '\t';
1302 nIndent = nIndent + nVal;
1303 if ( nIndent < 0 )
1304 nIndent = 0;
1305 else if ( nIndent > nIndentMax )
1306 nIndent = nIndentMax;
1307 sIndent[nIndent] = 0;
1310 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */