Version 5.2.6.1, tag libreoffice-5.2.6.1
[LibreOffice.git] / sc / source / filter / html / htmlexp.cxx
blob7518ddffe37fd71338840ff4f9310086e01b562e
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 <comphelper/string.hxx>
22 #include <editeng/eeitem.hxx>
24 #include <rtl/tencinfo.h>
26 #include <vcl/svapp.hxx>
27 #include <svx/algitem.hxx>
28 #include <editeng/boxitem.hxx>
29 #include <editeng/brushitem.hxx>
30 #include <editeng/colritem.hxx>
31 #include <editeng/fhgtitem.hxx>
32 #include <editeng/fontitem.hxx>
33 #include <editeng/postitem.hxx>
34 #include <editeng/udlnitem.hxx>
35 #include <editeng/wghtitem.hxx>
36 #include <editeng/justifyitem.hxx>
37 #include <svx/xoutbmp.hxx>
38 #include <editeng/editeng.hxx>
39 #include <svtools/htmlcfg.hxx>
40 #include <sfx2/docfile.hxx>
41 #include <sfx2/frmhtmlw.hxx>
42 #include <sfx2/objsh.hxx>
43 #include <svl/stritem.hxx>
44 #include <svl/urihelper.hxx>
45 #include <svl/zforlist.hxx>
46 #include <svtools/htmlkywd.hxx>
47 #include <svtools/htmlout.hxx>
48 #include <svtools/parhtml.hxx>
49 #include <vcl/outdev.hxx>
50 #include <stdio.h>
52 #include "htmlexp.hxx"
53 #include "filter.hxx"
54 #include "global.hxx"
55 #include "postit.hxx"
56 #include "document.hxx"
57 #include "attrib.hxx"
58 #include "patattr.hxx"
59 #include "stlpool.hxx"
60 #include "scresid.hxx"
61 #include "formulacell.hxx"
62 #include "cellform.hxx"
63 #include "docoptio.hxx"
64 #include "editutil.hxx"
65 #include "ftools.hxx"
66 #include "cellvalue.hxx"
68 #include <editeng/flditem.hxx>
69 #include <editeng/borderline.hxx>
70 #include <unotools/syslocale.hxx>
72 // Without sc.hrc: error C2679: binary '=' : no operator defined which takes a
73 // right-hand operand of type 'const class String (__stdcall *)(class ScResId)'
74 // at
75 // const String aStrTable( ScResId( SCSTR_TABLE ) ); aStrOut = aStrTable;
76 // ?!???
77 #include "sc.hrc"
78 #include "globstr.hrc"
80 #include <com/sun/star/uno/Reference.h>
81 #include <com/sun/star/document/XDocumentProperties.hpp>
82 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
83 #include <rtl/strbuf.hxx>
85 using ::editeng::SvxBorderLine;
86 using namespace ::com::sun::star;
88 const static sal_Char sMyBegComment[] = "<!-- ";
89 const static sal_Char sMyEndComment[] = " -->";
90 const static sal_Char sFontFamily[] = "font-family:";
91 const static sal_Char sFontSize[] = "font-size:";
92 const static sal_Char sDisplay[] = "display:";
93 const static sal_Char sBorder[] = "border:";
94 const static sal_Char sPadding[] = "padding:";
95 const static sal_Char sPosition[] = "position:";
96 const static sal_Char sBackground[] = "background:";
97 const static sal_Char sWidth[] = "width:";
98 const static sal_Char sHeight[] = "height:";
100 const sal_uInt16 ScHTMLExport::nDefaultFontSize[SC_HTML_FONTSIZES] =
102 HTMLFONTSZ1_DFLT, HTMLFONTSZ2_DFLT, HTMLFONTSZ3_DFLT, HTMLFONTSZ4_DFLT,
103 HTMLFONTSZ5_DFLT, HTMLFONTSZ6_DFLT, HTMLFONTSZ7_DFLT
106 sal_uInt16 ScHTMLExport::nFontSize[SC_HTML_FONTSIZES] = { 0 };
108 const char* ScHTMLExport::pFontSizeCss[SC_HTML_FONTSIZES] =
110 "xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large"
113 const sal_uInt16 ScHTMLExport::nCellSpacing = 0;
114 const sal_Char ScHTMLExport::sIndentSource[nIndentMax+1] =
115 "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
117 // Macros for HTML export
119 #define TAG_ON( tag ) HTMLOutFuncs::Out_AsciiTag( rStrm, tag )
120 #define TAG_OFF( tag ) HTMLOutFuncs::Out_AsciiTag( rStrm, tag, false )
121 #define OUT_STR( str ) HTMLOutFuncs::Out_String( rStrm, str, eDestEnc, &aNonConvertibleChars )
122 #define OUT_LF() rStrm.WriteCharPtr( SAL_NEWLINE_STRING ).WriteCharPtr( GetIndentStr() )
123 #define TAG_ON_LF( tag ) (TAG_ON( tag ).WriteCharPtr( SAL_NEWLINE_STRING ).WriteCharPtr( GetIndentStr() ))
124 #define TAG_OFF_LF( tag ) (TAG_OFF( tag ).WriteCharPtr( SAL_NEWLINE_STRING ).WriteCharPtr( GetIndentStr() ))
125 #define OUT_HR() TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_horzrule )
126 #define OUT_COMMENT( comment ) (rStrm.WriteCharPtr( sMyBegComment ), OUT_STR( comment ) \
127 .WriteCharPtr( sMyEndComment ).WriteCharPtr( SAL_NEWLINE_STRING ) \
128 .WriteCharPtr( GetIndentStr() ))
130 #define OUT_SP_CSTR_ASS( s ) rStrm.WriteChar( ' ').WriteCharPtr( s ).WriteChar( '=' )
132 #define GLOBSTR(id) ScGlobal::GetRscString( id )
134 void ScFormatFilterPluginImpl::ScExportHTML( SvStream& rStrm, const OUString& rBaseURL, ScDocument* pDoc,
135 const ScRange& rRange, const rtl_TextEncoding /*eNach*/, bool bAll,
136 const OUString& rStreamPath, OUString& rNonConvertibleChars, const OUString& rFilterOptions )
138 ScHTMLExport aEx( rStrm, rBaseURL, pDoc, rRange, bAll, rStreamPath, rFilterOptions );
139 aEx.Write();
140 rNonConvertibleChars = aEx.GetNonConvertibleChars();
143 static OString lcl_getColGroupString(sal_Int32 nSpan, sal_Int32 nWidth)
145 OStringBuffer aByteStr(OOO_STRING_SVTOOLS_HTML_colgroup);
146 aByteStr.append(' ');
147 if( nSpan > 1 )
149 aByteStr.append(OOO_STRING_SVTOOLS_HTML_O_span);
150 aByteStr.append("=\"");
151 aByteStr.append(nSpan);
152 aByteStr.append("\" ");
154 aByteStr.append(OOO_STRING_SVTOOLS_HTML_O_width);
155 aByteStr.append("=\"");
156 aByteStr.append(nWidth);
157 aByteStr.append('"');
158 return aByteStr.makeStringAndClear();
161 static void lcl_AddStamp( OUString& rStr, const OUString& rName,
162 const css::util::DateTime& rDateTime,
163 const LocaleDataWrapper& rLoc )
165 Date aD(rDateTime.Day, rDateTime.Month, rDateTime.Year);
166 tools::Time aT(rDateTime.Hours, rDateTime.Minutes, rDateTime.Seconds,
167 rDateTime.NanoSeconds);
168 DateTime aDateTime(aD,aT);
170 OUString aStrDate = rLoc.getDate( aDateTime );
171 OUString aStrTime = rLoc.getTime( aDateTime );
173 rStr += GLOBSTR( STR_BY ) + " ";
174 if (!rName.isEmpty())
175 rStr += rName;
176 else
177 rStr += "???";
178 rStr += " " + GLOBSTR( STR_ON ) + " ";
179 if (!aStrDate.isEmpty())
180 rStr += aStrDate;
181 else
182 rStr += "???";
183 rStr += ", ";
184 if (!aStrTime.isEmpty())
185 rStr += aStrTime;
186 else
187 rStr += "???";
190 static OString lcl_makeHTMLColorTriplet(const Color& rColor)
192 OStringBuffer aStr( "\"#" );
193 // <font COLOR="#00FF40">hello</font>
194 sal_Char buf[64];
195 sal_Char* p = buf;
196 p += sprintf( p, "%02X", rColor.GetRed() );
197 p += sprintf( p, "%02X", rColor.GetGreen() );
198 sprintf( p, "%02X", rColor.GetBlue() );
199 aStr.append(buf);
200 aStr.append('\"');
201 return aStr.makeStringAndClear();
204 ScHTMLExport::ScHTMLExport( SvStream& rStrmP, const OUString& rBaseURL, ScDocument* pDocP,
205 const ScRange& rRangeP, bool bAllP,
206 const OUString& rStreamPathP, const OUString& rFilterOptions ) :
207 ScExportBase( rStrmP, pDocP, rRangeP ),
208 aBaseURL( rBaseURL ),
209 aStreamPath( rStreamPathP ),
210 pAppWin( Application::GetDefaultDevice() ),
211 nUsedTables( 0 ),
212 nIndent( 0 ),
213 bAll( bAllP ),
214 bTabHasGraphics( false ),
215 bTabAlignedLeft( false ),
216 bCalcAsShown( pDocP->GetDocOptions().IsCalcAsShown() ),
217 bTableDataWidth( true ),
218 bTableDataHeight( true ),
219 mbSkipImages ( false ),
220 mbSkipHeaderFooter( false )
222 strcpy( sIndent, sIndentSource );
223 sIndent[0] = 0;
225 // set HTML configuration
226 SvxHtmlOptions& rHtmlOptions = SvxHtmlOptions::Get();
227 eDestEnc = (pDoc->IsClipOrUndo() ? RTL_TEXTENCODING_UTF8 : rHtmlOptions.GetTextEncoding());
228 bCopyLocalFileToINet = rHtmlOptions.IsSaveGraphicsLocal();
230 if (rFilterOptions == "SkipImages")
232 mbSkipImages = true;
234 else if (rFilterOptions == "SkipHeaderFooter")
236 mbSkipHeaderFooter = true;
239 for ( sal_uInt16 j=0; j < SC_HTML_FONTSIZES; j++ )
241 sal_uInt16 nSize = rHtmlOptions.GetFontSize( j );
242 // remember in Twips, like our SvxFontHeightItem
243 if ( nSize )
244 nFontSize[j] = nSize * 20;
245 else
246 nFontSize[j] = nDefaultFontSize[j] * 20;
249 const SCTAB nCount = pDoc->GetTableCount();
250 for ( SCTAB nTab = 0; nTab < nCount; nTab++ )
252 if ( !IsEmptyTable( nTab ) )
253 nUsedTables++;
256 // Content-Id for Mail export?
257 SfxObjectShell* pDocSh = pDoc->GetDocumentShell();
258 if ( pDocSh )
260 const SfxPoolItem* pItem = pDocSh->GetItem( SID_ORIGURL );
261 if( pItem )
263 aCId = static_cast<const SfxStringItem *>(pItem)->GetValue();
264 OSL_ENSURE( !aCId.isEmpty(), "CID without length!" );
269 ScHTMLExport::~ScHTMLExport()
271 aGraphList.clear();
274 sal_uInt16 ScHTMLExport::GetFontSizeNumber( sal_uInt16 nHeight )
276 sal_uInt16 nSize = 1;
277 for ( sal_uInt16 j=SC_HTML_FONTSIZES-1; j>0; j-- )
279 if( nHeight > (nFontSize[j] + nFontSize[j-1]) / 2 )
280 { // The one next to it
281 nSize = j+1;
282 break;
285 return nSize;
288 const char* ScHTMLExport::GetFontSizeCss( sal_uInt16 nHeight )
290 sal_uInt16 nSize = GetFontSizeNumber( nHeight );
291 return pFontSizeCss[ nSize-1 ];
294 sal_uInt16 ScHTMLExport::ToPixel( sal_uInt16 nVal )
296 if( nVal )
298 nVal = (sal_uInt16)pAppWin->LogicToPixel(
299 Size( nVal, nVal ), MapMode( MAP_TWIP ) ).Width();
300 if( !nVal ) // If there's a Twip there should also be a Pixel
301 nVal = 1;
303 return nVal;
306 Size ScHTMLExport::MMToPixel( const Size& rSize )
308 Size aSize( rSize );
309 aSize = pAppWin->LogicToPixel( rSize, MapMode( MAP_100TH_MM ) );
310 // If there's something there should also be a Pixel
311 if ( !aSize.Width() && rSize.Width() )
312 aSize.Width() = 1;
313 if ( !aSize.Height() && rSize.Height() )
314 aSize.Height() = 1;
315 return aSize;
318 void ScHTMLExport::Write()
320 if (!mbSkipHeaderFooter)
322 rStrm.WriteChar( '<' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_doctype ).WriteChar( ' ' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_doctype40 ).WriteChar( '>' )
323 .WriteCharPtr( SAL_NEWLINE_STRING ).WriteCharPtr( SAL_NEWLINE_STRING );
324 TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_html );
325 WriteHeader();
326 OUT_LF();
328 WriteBody();
329 OUT_LF();
330 if (!mbSkipHeaderFooter)
331 TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_html );
334 void ScHTMLExport::WriteHeader()
336 IncIndent(1); TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_head );
338 if ( pDoc->IsClipOrUndo() )
339 { // no real DocInfo available, but some META information like charset needed
340 SfxFrameHTMLWriter::Out_DocInfo( rStrm, aBaseURL, nullptr, sIndent, eDestEnc, &aNonConvertibleChars );
342 else
344 using namespace ::com::sun::star;
345 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
346 pDoc->GetDocumentShell()->GetModel(), uno::UNO_QUERY_THROW);
347 uno::Reference<document::XDocumentProperties> xDocProps
348 = xDPS->getDocumentProperties();
349 SfxFrameHTMLWriter::Out_DocInfo( rStrm, aBaseURL, xDocProps,
350 sIndent, eDestEnc, &aNonConvertibleChars );
351 OUT_LF();
353 if (!xDocProps->getPrintedBy().isEmpty())
355 OUT_COMMENT( GLOBSTR( STR_DOC_INFO ) );
356 OUString aStrOut = ( GLOBSTR( STR_DOC_PRINTED ) ) + ": ";
357 lcl_AddStamp( aStrOut, xDocProps->getPrintedBy(),
358 xDocProps->getPrintDate(), *ScGlobal::pLocaleData );
359 OUT_COMMENT( aStrOut );
363 OUT_LF();
365 // CSS1 StyleSheet
366 PageDefaults( bAll ? 0 : aRange.aStart.Tab() );
367 IncIndent(1);
368 rStrm.WriteCharPtr( "<" ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_style ).WriteCharPtr( " " ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_O_type ).WriteCharPtr( "=\"text/css\">" );
370 OUT_LF();
371 rStrm.WriteCharPtr( OOO_STRING_SVTOOLS_HTML_body ).WriteCharPtr( "," ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_division ).WriteCharPtr( "," ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_table ).WriteCharPtr( "," )
372 .WriteCharPtr( OOO_STRING_SVTOOLS_HTML_thead ).WriteCharPtr( "," ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_tbody ).WriteCharPtr( "," ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_tfoot ).WriteCharPtr( "," )
373 .WriteCharPtr( OOO_STRING_SVTOOLS_HTML_tablerow ).WriteCharPtr( "," ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_tableheader ).WriteCharPtr( "," )
374 .WriteCharPtr( OOO_STRING_SVTOOLS_HTML_tabledata ).WriteCharPtr( "," ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_parabreak ).WriteCharPtr( " { " ).WriteCharPtr( sFontFamily );
375 sal_Int32 nFonts = comphelper::string::getTokenCount(aHTMLStyle.aFontFamilyName, ';');
376 if ( nFonts == 1 )
378 rStrm.WriteChar( '\"' );
379 OUT_STR( aHTMLStyle.aFontFamilyName );
380 rStrm.WriteChar( '\"' );
382 else
383 { // Fontlist, VCL: Semicolon as separator
384 // CSS1: Comma as separator and every single font name quoted
385 const OUString& rList = aHTMLStyle.aFontFamilyName;
386 for ( sal_Int32 j = 0, nPos = 0; j < (sal_Int32) nFonts; j++ )
388 rStrm.WriteChar( '\"' );
389 OUT_STR( rList.getToken( 0, ';', nPos ) );
390 rStrm.WriteChar( '\"' );
391 if ( j < nFonts-1 )
392 rStrm.WriteCharPtr( ", " );
395 rStrm.WriteCharPtr( "; " ).WriteCharPtr( sFontSize )
396 .WriteCharPtr( GetFontSizeCss( ( sal_uInt16 ) aHTMLStyle.nFontHeight ) ).WriteCharPtr( " }" );
398 OUT_LF();
400 // write the style for the comments to make them stand out from normal cell content
401 // this is done through only showing the cell contents when the custom indicator is hovered
402 rStrm.WriteCharPtr( OOO_STRING_SVTOOLS_HTML_anchor ).WriteCharPtr(".comment-indicator:hover")
403 .WriteCharPtr(" + ").WriteCharPtr( OOO_STRING_SVTOOLS_HTML_comment2 ).WriteCharPtr(" { ")
404 .WriteCharPtr(sBackground).WriteCharPtr("#ffd").WriteCharPtr("; ")
405 .WriteCharPtr(sPosition).WriteCharPtr("absolute").WriteCharPtr("; ")
406 .WriteCharPtr(sDisplay).WriteCharPtr("block").WriteCharPtr("; ")
407 .WriteCharPtr(sBorder).WriteCharPtr("1px solid black").WriteCharPtr("; ")
408 .WriteCharPtr(sPadding).WriteCharPtr("0.5em").WriteCharPtr("; ")
409 .WriteCharPtr(" } ");
411 OUT_LF();
413 rStrm.WriteCharPtr( OOO_STRING_SVTOOLS_HTML_anchor ).WriteCharPtr(".comment-indicator")
414 .WriteCharPtr(" { ")
415 .WriteCharPtr(sBackground).WriteCharPtr("red").WriteCharPtr("; ")
416 .WriteCharPtr(sDisplay).WriteCharPtr("inline-block").WriteCharPtr("; ")
417 .WriteCharPtr(sBorder).WriteCharPtr("1px solid black").WriteCharPtr("; ")
418 .WriteCharPtr(sWidth).WriteCharPtr("0.5em").WriteCharPtr("; ")
419 .WriteCharPtr(sHeight).WriteCharPtr("0.5em").WriteCharPtr("; ")
420 .WriteCharPtr(" } ");
422 OUT_LF();
424 rStrm.WriteCharPtr( OOO_STRING_SVTOOLS_HTML_comment2 ).WriteCharPtr(" { ")
425 .WriteCharPtr(sDisplay).WriteCharPtr("none").WriteCharPtr("; ")
426 .WriteCharPtr(" } ");
429 IncIndent(-1); OUT_LF(); TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_style );
431 IncIndent(-1); OUT_LF(); TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_head );
434 void ScHTMLExport::WriteOverview()
436 if ( nUsedTables > 1 )
438 IncIndent(1);
439 OUT_HR();
440 IncIndent(1); TAG_ON( OOO_STRING_SVTOOLS_HTML_parabreak ); TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_center );
441 TAG_ON( OOO_STRING_SVTOOLS_HTML_head1 );
442 OUT_STR( ScGlobal::GetRscString( STR_OVERVIEW ) );
443 TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_head1 );
445 OUString aStr;
447 const SCTAB nCount = pDoc->GetTableCount();
448 for ( SCTAB nTab = 0; nTab < nCount; nTab++ )
450 if ( !IsEmptyTable( nTab ) )
452 pDoc->GetName( nTab, aStr );
453 rStrm.WriteCharPtr( "<A HREF=\"#table" )
454 .WriteCharPtr( OString::number(nTab).getStr() )
455 .WriteCharPtr( "\">" );
456 OUT_STR( aStr );
457 rStrm.WriteCharPtr( "</A>" );
458 TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_linebreak );
462 IncIndent(-1); OUT_LF();
463 IncIndent(-1); TAG_OFF( OOO_STRING_SVTOOLS_HTML_center ); TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_parabreak );
467 const SfxItemSet& ScHTMLExport::PageDefaults( SCTAB nTab )
469 SfxStyleSheetBasePool* pStylePool = pDoc->GetStyleSheetPool();
470 SfxStyleSheetBase* pStyleSheet = nullptr;
471 OSL_ENSURE( pStylePool, "StylePool not found! :-(" );
473 // remember defaults for compare in WriteCell
474 if ( !aHTMLStyle.bInitialized )
476 pStylePool->SetSearchMask( SfxStyleFamily::Para );
477 pStyleSheet = pStylePool->Find(
478 ScGlobal::GetRscString(STR_STYLENAME_STANDARD),
479 SfxStyleFamily::Para );
480 OSL_ENSURE( pStyleSheet, "ParaStyle not found! :-(" );
481 if (!pStyleSheet)
482 pStyleSheet = pStylePool->First();
483 const SfxItemSet& rSetPara = pStyleSheet->GetItemSet();
485 aHTMLStyle.nDefaultScriptType = ScGlobal::GetDefaultScriptType();
486 aHTMLStyle.aFontFamilyName = static_cast<const SvxFontItem&>((rSetPara.Get(
487 ScGlobal::GetScriptedWhichID(
488 aHTMLStyle.nDefaultScriptType, ATTR_FONT
489 )))).GetFamilyName();
490 aHTMLStyle.nFontHeight = static_cast<const SvxFontHeightItem&>((rSetPara.Get(
491 ScGlobal::GetScriptedWhichID(
492 aHTMLStyle.nDefaultScriptType, ATTR_FONT_HEIGHT
493 )))).GetHeight();
494 aHTMLStyle.nFontSizeNumber = GetFontSizeNumber( static_cast< sal_uInt16 >( aHTMLStyle.nFontHeight ) );
497 // Page style sheet printer settings, e.g. for background graphics.
498 // There's only one background graphic in HTML!
499 pStylePool->SetSearchMask( SfxStyleFamily::Page );
500 pStyleSheet = pStylePool->Find( pDoc->GetPageStyle( nTab ), SfxStyleFamily::Page );
501 OSL_ENSURE( pStyleSheet, "PageStyle not found! :-(" );
502 if (!pStyleSheet)
503 pStyleSheet = pStylePool->First();
504 const SfxItemSet& rSet = pStyleSheet->GetItemSet();
505 if ( !aHTMLStyle.bInitialized )
507 const SvxBrushItem* pBrushItem = static_cast<const SvxBrushItem*>(&rSet.Get( ATTR_BACKGROUND ));
508 aHTMLStyle.aBackgroundColor = pBrushItem->GetColor();
509 aHTMLStyle.bInitialized = true;
511 return rSet;
514 OString ScHTMLExport::BorderToStyle(const char* pBorderName,
515 const SvxBorderLine* pLine, bool& bInsertSemicolon)
517 OStringBuffer aOut;
519 if ( pLine )
521 if ( bInsertSemicolon )
522 aOut.append("; ");
524 // which border
525 aOut.append("border-").append(pBorderName).append(": ");
527 // thickness
528 int nWidth = pLine->GetWidth();
529 int nPxWidth = (nWidth > 0) ?
530 std::max(int(nWidth / TWIPS_PER_PIXEL), 1) : 0;
531 aOut.append(static_cast<sal_Int32>(nPxWidth)).
532 append("px ");
533 switch (pLine->GetBorderLineStyle())
535 case table::BorderLineStyle::SOLID:
536 aOut.append("solid");
537 break;
538 case table::BorderLineStyle::DOTTED:
539 aOut.append("dotted");
540 break;
541 case table::BorderLineStyle::DASHED:
542 case table::BorderLineStyle::DASH_DOT:
543 case table::BorderLineStyle::DASH_DOT_DOT:
544 aOut.append("dashed");
545 break;
546 case table::BorderLineStyle::DOUBLE:
547 case table::BorderLineStyle::DOUBLE_THIN:
548 case table::BorderLineStyle::THINTHICK_SMALLGAP:
549 case table::BorderLineStyle::THINTHICK_MEDIUMGAP:
550 case table::BorderLineStyle::THINTHICK_LARGEGAP:
551 case table::BorderLineStyle::THICKTHIN_SMALLGAP:
552 case table::BorderLineStyle::THICKTHIN_MEDIUMGAP:
553 case table::BorderLineStyle::THICKTHIN_LARGEGAP:
554 aOut.append("double");
555 break;
556 case table::BorderLineStyle::EMBOSSED:
557 aOut.append("ridge");
558 break;
559 case table::BorderLineStyle::ENGRAVED:
560 aOut.append("groove");
561 break;
562 case table::BorderLineStyle::OUTSET:
563 aOut.append("outset");
564 break;
565 case table::BorderLineStyle::INSET:
566 aOut.append("inset");
567 break;
568 default:
569 aOut.append("hidden");
571 aOut.append(" #");
573 // color
574 char hex[7];
575 snprintf( hex, 7, "%06x", static_cast< unsigned int >( pLine->GetColor().GetRGBColor() ) );
576 hex[6] = 0;
578 aOut.append(hex);
580 bInsertSemicolon = true;
583 return aOut.makeStringAndClear();
586 void ScHTMLExport::WriteBody()
588 const SfxItemSet& rSet = PageDefaults( bAll ? 0 : aRange.aStart.Tab() );
589 const SvxBrushItem* pBrushItem = static_cast<const SvxBrushItem*>(&rSet.Get( ATTR_BACKGROUND ));
591 // default text color black
592 if (!mbSkipHeaderFooter)
594 rStrm.WriteChar( '<' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_body );
596 if (!mbSkipImages)
598 if ( bAll && GPOS_NONE != pBrushItem->GetGraphicPos() )
600 OUString aLink = pBrushItem->GetGraphicLink();
601 OUString aGrfNm;
603 // Embedded graphic -> write using WriteGraphic
604 if( aLink.isEmpty() )
606 const Graphic* pGrf = pBrushItem->GetGraphic();
607 if( pGrf )
609 // Save graphic as (JPG) file
610 aGrfNm = aStreamPath;
611 sal_uInt16 nErr = XOutBitmap::WriteGraphic( *pGrf, aGrfNm,
612 "JPG", XOutFlags::UseNativeIfPossible );
613 if( !nErr ) // Contains errors, as we have nothing to output
615 aGrfNm = URIHelper::SmartRel2Abs(
616 INetURLObject(aBaseURL),
617 aGrfNm, URIHelper::GetMaybeFileHdl());
618 if ( HasCId() )
619 MakeCIdURL( aGrfNm );
620 aLink = aGrfNm;
624 else
626 aGrfNm = aLink;
627 if( bCopyLocalFileToINet || HasCId() )
629 CopyLocalFileToINet( aGrfNm, aStreamPath );
630 if ( HasCId() )
631 MakeCIdURL( aGrfNm );
633 else
634 aGrfNm = URIHelper::SmartRel2Abs(
635 INetURLObject(aBaseURL),
636 aGrfNm, URIHelper::GetMaybeFileHdl());
637 aLink = aGrfNm;
639 if( !aLink.isEmpty() )
641 rStrm.WriteChar( ' ' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_O_background ).WriteCharPtr( "=\"" );
642 OUT_STR( URIHelper::simpleNormalizedMakeRelative(
643 aBaseURL,
644 aLink ) ).WriteChar( '\"' );
648 if ( !aHTMLStyle.aBackgroundColor.GetTransparency() )
649 { // A transparent background color should always result in default
650 // background of the browser. Also, HTMLOutFuncs::Out_Color() writes
651 // black #000000 for COL_AUTO which is the same as white #ffffff with
652 // transparency set to 0xff, our default background.
653 OUT_SP_CSTR_ASS( OOO_STRING_SVTOOLS_HTML_O_bgcolor );
654 HTMLOutFuncs::Out_Color( rStrm, aHTMLStyle.aBackgroundColor );
657 rStrm.WriteChar( '>' ); OUT_LF();
660 if ( bAll )
661 WriteOverview();
663 WriteTables();
665 if (!mbSkipHeaderFooter)
666 TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_body );
669 void ScHTMLExport::WriteTables()
671 const SCTAB nTabCount = pDoc->GetTableCount();
672 const OUString aStrTable( ScResId( SCSTR_TABLE ) );
673 OUString aStr;
674 OUString aStrOut;
675 SCCOL nStartCol;
676 SCROW nStartRow;
677 SCTAB nStartTab;
678 SCCOL nEndCol;
679 SCROW nEndRow;
680 SCTAB nEndTab;
681 SCCOL nStartColFix = 0;
682 SCROW nStartRowFix = 0;
683 SCCOL nEndColFix = 0;
684 SCROW nEndRowFix = 0;
685 ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
686 if ( bAll )
688 nStartTab = 0;
689 nEndTab = nTabCount - 1;
691 else
693 nStartCol = nStartColFix = aRange.aStart.Col();
694 nStartRow = nStartRowFix = aRange.aStart.Row();
695 nStartTab = aRange.aStart.Tab();
696 nEndCol = nEndColFix = aRange.aEnd.Col();
697 nEndRow = nEndRowFix = aRange.aEnd.Row();
698 nEndTab = aRange.aEnd.Tab();
700 SCTAB nTableStrNum = 1;
701 for ( SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++ )
703 if ( !pDoc->IsVisible( nTab ) )
704 continue; // for
706 if ( bAll )
708 if ( !GetDataArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow ) )
709 continue; // for
711 if ( nUsedTables > 1 )
713 aStrOut = aStrTable + " " + OUString::number( nTableStrNum++ ) + ": ";
715 OUT_HR();
717 // Write anchor
718 rStrm.WriteCharPtr( "<A NAME=\"table" )
719 .WriteCharPtr( OString::number(nTab).getStr() )
720 .WriteCharPtr( "\">" );
721 TAG_ON( OOO_STRING_SVTOOLS_HTML_head1 );
722 OUT_STR( aStrOut );
723 TAG_ON( OOO_STRING_SVTOOLS_HTML_emphasis );
725 pDoc->GetName( nTab, aStr );
726 OUT_STR( aStr );
728 TAG_OFF( OOO_STRING_SVTOOLS_HTML_emphasis );
729 TAG_OFF( OOO_STRING_SVTOOLS_HTML_head1 );
730 rStrm.WriteCharPtr( "</A>" ); OUT_LF();
733 else
735 nStartCol = nStartColFix;
736 nStartRow = nStartRowFix;
737 nEndCol = nEndColFix;
738 nEndRow = nEndRowFix;
739 if ( !TrimDataArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow ) )
740 continue; // for
743 // <TABLE ...>
744 OStringBuffer aByteStrOut(OOO_STRING_SVTOOLS_HTML_table);
746 bTabHasGraphics = bTabAlignedLeft = false;
747 if ( bAll && pDrawLayer )
748 PrepareGraphics( pDrawLayer, nTab, nStartCol, nStartRow,
749 nEndCol, nEndRow );
751 // more <TABLE ...>
752 if ( bTabAlignedLeft )
754 aByteStrOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_align).
755 append("=\"").
756 append(OOO_STRING_SVTOOLS_HTML_AL_left).append('"');
758 // ALIGN=LEFT allow text and graphics to flow around
759 // CELLSPACING
760 aByteStrOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_cellspacing).
761 append("=\"").
762 append(static_cast<sal_Int32>(nCellSpacing)).append('"');
764 // BORDER=0, we do the styling of the cells in <TD>
765 aByteStrOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_border).
766 append("=\"0\"");
767 IncIndent(1); TAG_ON_LF( aByteStrOut.makeStringAndClear().getStr() );
769 // --- <COLGROUP> ----
771 SCCOL nCol = nStartCol;
772 sal_Int32 nWidth = 0;
773 sal_Int32 nSpan = 0;
774 while( nCol <= nEndCol )
776 if( pDoc->ColHidden(nCol, nTab) )
778 ++nCol;
779 continue;
782 if( nWidth != ToPixel( pDoc->GetColWidth( nCol, nTab ) ) )
784 if( nSpan != 0 )
786 TAG_ON(lcl_getColGroupString(nSpan, nWidth).getStr());
787 TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_colgroup );
789 nWidth = ToPixel( pDoc->GetColWidth( nCol, nTab ) );
790 nSpan = 1;
792 else
793 nSpan++;
794 nCol++;
796 if( nSpan )
798 TAG_ON(lcl_getColGroupString(nSpan, nWidth).getStr());
799 TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_colgroup );
803 // <TBODY> // Re-enable only when THEAD and TFOOT are exported
804 // IncIndent(1); TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_tbody );
805 // At least old (3.x, 4.x?) Netscape doesn't follow <TABLE COLS=n> and
806 // <COL WIDTH=x> specified, but needs a width at every column.
807 bTableDataWidth = true; // widths in first row
808 bool bHasHiddenRows = pDoc->HasHiddenRows(nStartRow, nEndRow, nTab);
809 for ( SCROW nRow=nStartRow; nRow<=nEndRow; nRow++ )
811 if ( bHasHiddenRows && pDoc->RowHidden(nRow, nTab) )
813 nRow = pDoc->FirstVisibleRow(nRow+1, nEndRow, nTab);
814 --nRow;
815 continue; // for
818 IncIndent(1); TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_tablerow );
819 bTableDataHeight = true; // height at every first cell of each row
820 for ( SCCOL nCol2=nStartCol; nCol2<=nEndCol; nCol2++ )
822 if ( pDoc->ColHidden(nCol2, nTab) )
823 continue; // for
825 if ( nCol2 == nEndCol )
826 IncIndent(-1);
827 WriteCell( nCol2, nRow, nTab );
828 bTableDataHeight = false;
830 bTableDataWidth = false; // widths only in first row
832 if ( nRow == nEndRow )
833 IncIndent(-1);
834 TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_tablerow );
836 // TODO: Uncomment later
837 // IncIndent(-1); TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_tbody );
839 IncIndent(-1); TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_table );
841 if ( bTabHasGraphics && !mbSkipImages )
843 // the rest that is not in a cell
844 size_t ListSize = aGraphList.size();
845 for ( size_t i = 0; i < ListSize; ++i )
847 ScHTMLGraphEntry* pE = &aGraphList[ i ];
848 if ( !pE->bWritten )
849 WriteGraphEntry( pE );
851 aGraphList.clear();
852 if ( bTabAlignedLeft )
854 // clear <TABLE ALIGN=LEFT> with <BR CLEAR=LEFT>
855 aByteStrOut.append(OOO_STRING_SVTOOLS_HTML_linebreak);
856 aByteStrOut.append(' ').
857 append(OOO_STRING_SVTOOLS_HTML_O_clear).append('=').
858 append(OOO_STRING_SVTOOLS_HTML_AL_left);
859 TAG_ON_LF( aByteStrOut.makeStringAndClear().getStr() );
863 if ( bAll )
864 OUT_COMMENT( "**************************************************************************" );
868 void ScHTMLExport::WriteCell( SCCOL nCol, SCROW nRow, SCTAB nTab )
870 const ScPatternAttr* pAttr = pDoc->GetPattern( nCol, nRow, nTab );
871 const SfxItemSet* pCondItemSet = pDoc->GetCondResult( nCol, nRow, nTab );
873 const ScMergeFlagAttr& rMergeFlagAttr = static_cast<const ScMergeFlagAttr&>( pAttr->GetItem( ATTR_MERGE_FLAG, pCondItemSet ) );
874 if ( rMergeFlagAttr.IsOverlapped() )
875 return ;
877 ScAddress aPos( nCol, nRow, nTab );
878 ScHTMLGraphEntry* pGraphEntry = nullptr;
879 if ( bTabHasGraphics && !mbSkipImages )
881 size_t ListSize = aGraphList.size();
882 for ( size_t i = 0; i < ListSize; ++i )
884 ScHTMLGraphEntry* pE = &aGraphList[ i ];
885 if ( pE->bInCell && pE->aRange.In( aPos ) )
887 if ( pE->aRange.aStart == aPos )
889 pGraphEntry = pE;
890 break; // for
892 else
893 return ; // Is a Col/RowSpan, Overlapped
898 ScRefCellValue aCell(*pDoc, aPos);
900 sal_uLong nFormat = pAttr->GetNumberFormat( pFormatter );
901 bool bValueData = aCell.hasNumeric();
902 SvtScriptType nScriptType = SvtScriptType::NONE;
903 if (!aCell.isEmpty())
904 nScriptType = pDoc->GetScriptType(nCol, nRow, nTab);
906 if ( nScriptType == SvtScriptType::NONE )
907 nScriptType = aHTMLStyle.nDefaultScriptType;
909 OStringBuffer aStrTD(OOO_STRING_SVTOOLS_HTML_tabledata);
911 // border of the cells
912 const SvxBoxItem* pBorder = static_cast<const SvxBoxItem*>( pDoc->GetAttr( nCol, nRow, nTab, ATTR_BORDER ) );
913 if ( pBorder && (pBorder->GetTop() || pBorder->GetBottom() || pBorder->GetLeft() || pBorder->GetRight()) )
915 aStrTD.append(' ').append(OOO_STRING_SVTOOLS_HTML_style).
916 append("=\"");
918 bool bInsertSemicolon = false;
919 aStrTD.append(BorderToStyle("top", pBorder->GetTop(),
920 bInsertSemicolon));
921 aStrTD.append(BorderToStyle("bottom", pBorder->GetBottom(),
922 bInsertSemicolon));
923 aStrTD.append(BorderToStyle("left", pBorder->GetLeft(),
924 bInsertSemicolon));
925 aStrTD.append(BorderToStyle("right", pBorder->GetRight(),
926 bInsertSemicolon));
928 aStrTD.append('"');
931 const sal_Char* pChar;
932 sal_uInt16 nHeightPixel;
934 const ScMergeAttr& rMergeAttr = static_cast<const ScMergeAttr&>( pAttr->GetItem( ATTR_MERGE, pCondItemSet ) );
935 if ( pGraphEntry || rMergeAttr.IsMerged() )
937 SCCOL nC, jC;
938 SCROW nR;
939 sal_uLong v;
940 if ( pGraphEntry )
941 nC = std::max( SCCOL(pGraphEntry->aRange.aEnd.Col() - nCol + 1),
942 SCCOL(rMergeAttr.GetColMerge()) );
943 else
944 nC = rMergeAttr.GetColMerge();
945 if ( nC > 1 )
947 aStrTD.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_colspan).
948 append('=').append(static_cast<sal_Int32>(nC));
949 nC = nC + nCol;
950 for ( jC=nCol, v=0; jC<nC; jC++ )
951 v += pDoc->GetColWidth( jC, nTab );
954 if ( pGraphEntry )
955 nR = std::max( SCROW(pGraphEntry->aRange.aEnd.Row() - nRow + 1),
956 SCROW(rMergeAttr.GetRowMerge()) );
957 else
958 nR = rMergeAttr.GetRowMerge();
959 if ( nR > 1 )
961 aStrTD.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_rowspan).
962 append('=').append(static_cast<sal_Int32>(nR));
963 nR += nRow;
964 v = pDoc->GetRowHeight( nRow, nR-1, nTab );
965 nHeightPixel = ToPixel( static_cast< sal_uInt16 >( v ) );
967 else
968 nHeightPixel = ToPixel( pDoc->GetRowHeight( nRow, nTab ) );
970 else
971 nHeightPixel = ToPixel( pDoc->GetRowHeight( nRow, nTab ) );
973 if ( bTableDataHeight )
975 aStrTD.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_height).
976 append("=\"").
977 append(static_cast<sal_Int32>(nHeightPixel)).append('"');
980 const SvxFontItem& rFontItem = static_cast<const SvxFontItem&>( pAttr->GetItem(
981 ScGlobal::GetScriptedWhichID( nScriptType, ATTR_FONT),
982 pCondItemSet) );
984 const SvxFontHeightItem& rFontHeightItem = static_cast<const SvxFontHeightItem&>(
985 pAttr->GetItem( ScGlobal::GetScriptedWhichID( nScriptType,
986 ATTR_FONT_HEIGHT), pCondItemSet) );
988 const SvxWeightItem& rWeightItem = static_cast<const SvxWeightItem&>( pAttr->GetItem(
989 ScGlobal::GetScriptedWhichID( nScriptType, ATTR_FONT_WEIGHT),
990 pCondItemSet) );
992 const SvxPostureItem& rPostureItem = static_cast<const SvxPostureItem&>(
993 pAttr->GetItem( ScGlobal::GetScriptedWhichID( nScriptType,
994 ATTR_FONT_POSTURE), pCondItemSet) );
996 const SvxUnderlineItem& rUnderlineItem = static_cast<const SvxUnderlineItem&>(
997 pAttr->GetItem( ATTR_FONT_UNDERLINE, pCondItemSet ) );
999 const SvxColorItem& rColorItem = static_cast<const SvxColorItem&>( pAttr->GetItem(
1000 ATTR_FONT_COLOR, pCondItemSet ) );
1002 const SvxHorJustifyItem& rHorJustifyItem = static_cast<const SvxHorJustifyItem&>(
1003 pAttr->GetItem( ATTR_HOR_JUSTIFY, pCondItemSet ) );
1005 const SvxVerJustifyItem& rVerJustifyItem = static_cast<const SvxVerJustifyItem&>(
1006 pAttr->GetItem( ATTR_VER_JUSTIFY, pCondItemSet ) );
1008 const SvxBrushItem& rBrushItem = static_cast<const SvxBrushItem&>( pAttr->GetItem(
1009 ATTR_BACKGROUND, pCondItemSet ) );
1011 Color aBgColor;
1012 if ( rBrushItem.GetColor().GetTransparency() == 255 )
1013 aBgColor = aHTMLStyle.aBackgroundColor; // No unwanted background color
1014 else
1015 aBgColor = rBrushItem.GetColor();
1017 bool bBold = ( WEIGHT_BOLD <= rWeightItem.GetWeight() );
1018 bool bItalic = ( ITALIC_NONE != rPostureItem.GetPosture() );
1019 bool bUnderline = ( LINESTYLE_NONE != rUnderlineItem.GetLineStyle() );
1020 bool bSetFontColor = ( COL_AUTO != rColorItem.GetValue().GetColor() ); // default is AUTO now
1021 bool bSetFontName = ( aHTMLStyle.aFontFamilyName != rFontItem.GetFamilyName() );
1022 sal_uInt16 nSetFontSizeNumber = 0;
1023 sal_uInt32 nFontHeight = rFontHeightItem.GetHeight();
1024 if ( nFontHeight != aHTMLStyle.nFontHeight )
1026 nSetFontSizeNumber = GetFontSizeNumber( (sal_uInt16) nFontHeight );
1027 if ( nSetFontSizeNumber == aHTMLStyle.nFontSizeNumber )
1028 nSetFontSizeNumber = 0; // no difference, don't set
1031 bool bSetFont = (bSetFontColor || bSetFontName || nSetFontSizeNumber);
1033 //! TODO: we could entirely use CSS1 here instead, but that would exclude
1034 //! Netscape 3.0 and Netscape 4.x without JavaScript enabled.
1035 //! Do we want that?
1037 switch( rHorJustifyItem.GetValue() )
1039 case SVX_HOR_JUSTIFY_STANDARD:
1040 pChar = (bValueData ? OOO_STRING_SVTOOLS_HTML_AL_right : OOO_STRING_SVTOOLS_HTML_AL_left);
1041 break;
1042 case SVX_HOR_JUSTIFY_CENTER: pChar = OOO_STRING_SVTOOLS_HTML_AL_center; break;
1043 case SVX_HOR_JUSTIFY_BLOCK: pChar = OOO_STRING_SVTOOLS_HTML_AL_justify; break;
1044 case SVX_HOR_JUSTIFY_RIGHT: pChar = OOO_STRING_SVTOOLS_HTML_AL_right; break;
1045 case SVX_HOR_JUSTIFY_LEFT:
1046 case SVX_HOR_JUSTIFY_REPEAT:
1047 default: pChar = OOO_STRING_SVTOOLS_HTML_AL_left; break;
1050 aStrTD.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_align).
1051 append("=\"").append(pChar).append('"');
1053 switch( rVerJustifyItem.GetValue() )
1055 case SVX_VER_JUSTIFY_TOP: pChar = OOO_STRING_SVTOOLS_HTML_VA_top; break;
1056 case SVX_VER_JUSTIFY_CENTER: pChar = OOO_STRING_SVTOOLS_HTML_VA_middle; break;
1057 case SVX_VER_JUSTIFY_BOTTOM: pChar = OOO_STRING_SVTOOLS_HTML_VA_bottom; break;
1058 case SVX_VER_JUSTIFY_STANDARD:
1059 default: pChar = nullptr;
1061 if ( pChar )
1063 aStrTD.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_valign).
1064 append('=').append(pChar);
1067 if ( aHTMLStyle.aBackgroundColor != aBgColor )
1069 aStrTD.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_bgcolor).
1070 append('=');
1071 aStrTD.append(lcl_makeHTMLColorTriplet(aBgColor));
1074 double fVal = 0.0;
1075 if ( bValueData )
1077 switch (aCell.meType)
1079 case CELLTYPE_VALUE:
1080 fVal = aCell.mfValue;
1081 if ( bCalcAsShown && fVal != 0.0 )
1082 fVal = pDoc->RoundValueAsShown( fVal, nFormat );
1083 break;
1084 case CELLTYPE_FORMULA:
1085 fVal = aCell.mpFormula->GetValue();
1086 break;
1087 default:
1088 OSL_FAIL( "value data with unsupported cell type" );
1092 aStrTD.append(HTMLOutFuncs::CreateTableDataOptionsValNum(bValueData, fVal,
1093 nFormat, *pFormatter, eDestEnc, &aNonConvertibleChars));
1095 TAG_ON(aStrTD.makeStringAndClear().getStr());
1097 //write the note for this as the first thing in the tag
1098 if (pDoc->HasNote(aPos))
1100 ScPostIt* pNote = pDoc->GetNote(aPos);
1102 //create the comment indicator
1103 OStringBuffer aStr(OOO_STRING_SVTOOLS_HTML_anchor);
1104 aStr.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_class)
1105 .append("=\"").append("comment-indicator").append("\"");
1106 TAG_ON(aStr.makeStringAndClear().getStr());
1107 TAG_OFF(OOO_STRING_SVTOOLS_HTML_anchor);
1108 OUT_LF();
1110 //create the element holding the contents
1111 //this is a bit naive, since it doesn't separate
1112 //lines into html breaklines yet
1113 TAG_ON(OOO_STRING_SVTOOLS_HTML_comment2);
1114 OUT_STR( pNote->GetText() );
1115 TAG_OFF(OOO_STRING_SVTOOLS_HTML_comment2);
1116 OUT_LF();
1119 if ( bBold ) TAG_ON( OOO_STRING_SVTOOLS_HTML_bold );
1120 if ( bItalic ) TAG_ON( OOO_STRING_SVTOOLS_HTML_italic );
1121 if ( bUnderline ) TAG_ON( OOO_STRING_SVTOOLS_HTML_underline );
1123 if ( bSetFont )
1125 OStringBuffer aStr(OOO_STRING_SVTOOLS_HTML_font);
1126 if ( bSetFontName )
1128 aStr.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_face).
1129 append("=\"");
1130 sal_Int32 nFonts = comphelper::string::getTokenCount(rFontItem.GetFamilyName(), ';');
1131 if ( nFonts == 1 )
1133 OString aTmpStr = HTMLOutFuncs::ConvertStringToHTML(
1134 rFontItem.GetFamilyName(), eDestEnc, &aNonConvertibleChars);
1135 aStr.append(aTmpStr);
1137 else
1138 { // Font list, VCL: Semicolon as separator, HTML: Comma
1139 const OUString& rList = rFontItem.GetFamilyName();
1140 for ( sal_Int32 j = 0, nPos = 0; j < (sal_Int32)nFonts; j++ )
1142 OString aTmpStr = HTMLOutFuncs::ConvertStringToHTML(
1143 rList.getToken( 0, ';', nPos ), eDestEnc,
1144 &aNonConvertibleChars);
1145 aStr.append(aTmpStr);
1146 if ( j < nFonts-1 )
1147 aStr.append(',');
1150 aStr.append('\"');
1152 if ( nSetFontSizeNumber )
1154 aStr.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_size).
1155 append('=').append(static_cast<sal_Int32>(nSetFontSizeNumber));
1157 if ( bSetFontColor )
1159 Color aColor = rColorItem.GetValue();
1161 // always export automatic text color as black
1162 if ( aColor.GetColor() == COL_AUTO )
1163 aColor.SetColor( COL_BLACK );
1165 aStr.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_color).
1166 append('=').append(lcl_makeHTMLColorTriplet(aColor));
1168 TAG_ON(aStr.makeStringAndClear().getStr());
1171 OUString aStrOut;
1172 bool bFieldText = false;
1174 Color* pColor;
1175 switch (aCell.meType)
1177 case CELLTYPE_EDIT :
1178 bFieldText = WriteFieldText(aCell.mpEditText);
1179 if ( bFieldText )
1180 break;
1181 SAL_FALLTHROUGH;
1182 default:
1183 ScCellFormat::GetString(aCell, nFormat, aStrOut, &pColor, *pFormatter, pDoc);
1186 if ( !bFieldText )
1188 if ( aStrOut.isEmpty() )
1190 TAG_ON( OOO_STRING_SVTOOLS_HTML_linebreak ); // No completely empty line
1192 else
1194 sal_Int32 nPos = aStrOut.indexOf( '\n' );
1195 if ( nPos == -1 )
1197 OUT_STR( aStrOut );
1199 else
1201 sal_Int32 nStartPos = 0;
1204 OUString aSingleLine = aStrOut.copy( nStartPos, nPos - nStartPos );
1205 OUT_STR( aSingleLine );
1206 TAG_ON( OOO_STRING_SVTOOLS_HTML_linebreak );
1207 nStartPos = nPos + 1;
1209 while( ( nPos = aStrOut.indexOf( '\n', nStartPos ) ) != -1 );
1210 OUString aSingleLine = aStrOut.copy( nStartPos, aStrOut.getLength() - nStartPos );
1211 OUT_STR( aSingleLine );
1215 if ( pGraphEntry )
1216 WriteGraphEntry( pGraphEntry );
1218 if ( bSetFont ) TAG_OFF( OOO_STRING_SVTOOLS_HTML_font );
1219 if ( bUnderline ) TAG_OFF( OOO_STRING_SVTOOLS_HTML_underline );
1220 if ( bItalic ) TAG_OFF( OOO_STRING_SVTOOLS_HTML_italic );
1221 if ( bBold ) TAG_OFF( OOO_STRING_SVTOOLS_HTML_bold );
1223 TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_tabledata );
1226 bool ScHTMLExport::WriteFieldText( const EditTextObject* pData )
1228 bool bFields = false;
1229 // text and anchor of URL fields, Doc-Engine is a ScFieldEditEngine
1230 EditEngine& rEngine = pDoc->GetEditEngine();
1231 rEngine.SetText( *pData );
1232 sal_Int32 nParas = rEngine.GetParagraphCount();
1233 if ( nParas )
1235 ESelection aSel( 0, 0, nParas-1, rEngine.GetTextLen( nParas-1 ) );
1236 SfxItemSet aSet( rEngine.GetAttribs( aSel ) );
1237 SfxItemState eFieldState = aSet.GetItemState( EE_FEATURE_FIELD, false );
1238 if ( eFieldState == SfxItemState::DONTCARE || eFieldState == SfxItemState::SET )
1239 bFields = true;
1241 if ( bFields )
1243 bool bOldUpdateMode = rEngine.GetUpdateMode();
1244 rEngine.SetUpdateMode( true ); // no portions if not formatted
1245 for ( sal_Int32 nPar=0; nPar < nParas; nPar++ )
1247 if ( nPar > 0 )
1248 TAG_ON( OOO_STRING_SVTOOLS_HTML_linebreak );
1249 std::vector<sal_Int32> aPortions;
1250 rEngine.GetPortions( nPar, aPortions );
1251 sal_Int32 nStart = 0;
1252 for ( std::vector<sal_Int32>::const_iterator it(aPortions.begin()); it != aPortions.end(); ++it )
1254 sal_Int32 nEnd = *it;
1255 ESelection aSel( nPar, nStart, nPar, nEnd );
1256 bool bUrl = false;
1257 // fields are single characters
1258 if ( nEnd == nStart+1 )
1260 const SfxPoolItem* pItem;
1261 SfxItemSet aSet = rEngine.GetAttribs( aSel );
1262 if ( aSet.GetItemState( EE_FEATURE_FIELD, false, &pItem ) == SfxItemState::SET )
1264 const SvxFieldData* pField = static_cast<const SvxFieldItem*>(pItem)->GetField();
1265 if (const SvxURLField* pURLField = dynamic_cast<const SvxURLField*>(pField))
1267 bUrl = true;
1268 rStrm.WriteChar( '<' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_anchor ).WriteChar( ' ' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_O_href ).WriteCharPtr( "=\"" );
1269 OUT_STR( pURLField->GetURL() );
1270 rStrm.WriteCharPtr( "\">" );
1271 OUT_STR( pURLField->GetRepresentation() );
1272 rStrm.WriteCharPtr( "</" ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_anchor ).WriteChar( '>' );
1276 if ( !bUrl )
1277 OUT_STR( rEngine.GetText( aSel ) );
1278 nStart = nEnd;
1281 rEngine.SetUpdateMode( bOldUpdateMode );
1283 return bFields;
1286 void ScHTMLExport::CopyLocalFileToINet( OUString& rFileNm,
1287 const OUString& rTargetNm )
1289 INetURLObject aFileUrl, aTargetUrl;
1290 aFileUrl.SetSmartURL( rFileNm );
1291 aTargetUrl.SetSmartURL( rTargetNm );
1292 if( INetProtocol::File == aFileUrl.GetProtocol() &&
1293 ( INetProtocol::File != aTargetUrl.GetProtocol() &&
1294 INetProtocol::Ftp <= aTargetUrl.GetProtocol() &&
1295 INetProtocol::Javascript >= aTargetUrl.GetProtocol()) )
1297 if( pFileNameMap )
1299 // Did we already move the file?
1300 std::map<OUString, OUString>::iterator it = pFileNameMap->find( rFileNm );
1301 if( it != pFileNameMap->end() )
1303 rFileNm = it->second;
1304 return;
1307 else
1309 pFileNameMap.reset( new std::map<OUString, OUString>() );
1312 bool bRet = false;
1313 SvFileStream aTmp( aFileUrl.PathToFileName(), StreamMode::READ );
1315 OUString aSrc = rFileNm;
1316 OUString aDest = aTargetUrl.GetPartBeforeLastName();
1317 aDest += aFileUrl.GetName();
1319 SfxMedium aMedium( aDest, StreamMode::WRITE | StreamMode::SHARE_DENYNONE );
1322 SvFileStream aCpy( aMedium.GetPhysicalName(), StreamMode::WRITE );
1323 aCpy.WriteStream( aTmp );
1326 // Take over
1327 aMedium.Close();
1328 aMedium.Commit();
1330 bRet = 0 == aMedium.GetError();
1332 if( bRet )
1334 pFileNameMap->insert( std::make_pair( aSrc, aDest ) );
1335 rFileNm = aDest;
1340 void ScHTMLExport::MakeCIdURL( OUString& rURL )
1342 if( aCId.isEmpty() )
1343 return;
1345 INetURLObject aURLObj( rURL );
1346 if( INetProtocol::File != aURLObj.GetProtocol() )
1347 return;
1349 OUString aLastName( aURLObj.GetLastName().toAsciiLowerCase() );
1350 OSL_ENSURE( !aLastName.isEmpty(), "filename without length!" );
1352 rURL = "cid:" + aLastName + "." + aCId;
1355 void ScHTMLExport::IncIndent( short nVal )
1357 sIndent[nIndent] = '\t';
1358 nIndent = nIndent + nVal;
1359 if ( nIndent < 0 )
1360 nIndent = 0;
1361 else if ( nIndent > nIndentMax )
1362 nIndent = nIndentMax;
1363 sIndent[nIndent] = 0;
1366 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */