Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <stdlib.h>
21 : #include <hintids.hxx>
22 : #include <comphelper/string.hxx>
23 : #include <svl/urihelper.hxx>
24 : #include <rtl/tencinfo.h>
25 : #include <vcl/wrkwin.hxx>
26 : #include <sfx2/linkmgr.hxx>
27 :
28 : #include <svtools/htmlcfg.hxx>
29 : #include <vcl/svapp.hxx>
30 : #include <i18npool/languagetag.hxx>
31 : #include <sfx2/frmhtmlw.hxx>
32 : #include <svx/xoutbmp.hxx>
33 : #include <svx/htmlmode.hxx>
34 : #include <editeng/lrspitem.hxx>
35 : #include <editeng/colritem.hxx>
36 : #include <editeng/brshitem.hxx>
37 : #include <editeng/fontitem.hxx>
38 : #include <editeng/scripttypeitem.hxx>
39 : #include <editeng/langitem.hxx>
40 : #include <svl/stritem.hxx>
41 : #include <editeng/frmdiritem.hxx>
42 :
43 : #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
44 : #include <com/sun/star/document/XDocumentProperties.hpp>
45 : #include <com/sun/star/form/XFormsSupplier.hpp>
46 : #include <com/sun/star/form/XForm.hpp>
47 : #include <com/sun/star/form/XImageProducerSupplier.hpp>
48 : #include <com/sun/star/form/XFormController.hpp>
49 : #include <com/sun/star/container/XContainer.hpp>
50 : #include <com/sun/star/container/XIndexContainer.hpp>
51 : #include <com/sun/star/container/XSet.hpp>
52 : #include <fmthdft.hxx>
53 : #include <fmtfld.hxx>
54 : #include <fmtpdsc.hxx>
55 : #include <txatbase.hxx>
56 : #include <frmatr.hxx>
57 : #include <charfmt.hxx>
58 : #include <docary.hxx>
59 : #include <pam.hxx>
60 : #include <doc.hxx>
61 : #include <ndtxt.hxx>
62 : #include <mdiexp.hxx> // ...Percent()
63 : #include <fltini.hxx>
64 : #include <viewopt.hxx>
65 : #include <IMark.hxx> // fuer SwBookmark ...
66 : #include <poolfmt.hxx>
67 : #include <pagedesc.hxx>
68 : #include <section.hxx>
69 : #include <swtable.hxx>
70 : #include <fldbas.hxx>
71 : #include <fmtclds.hxx>
72 : #include <docsh.hxx>
73 : #include <wrthtml.hxx>
74 : #include <htmlnum.hxx>
75 : #include <htmlfly.hxx>
76 : #include <swmodule.hxx>
77 : #include <statstr.hrc> // ResId fuer Statusleiste
78 : #include <swerror.h>
79 : #include <rtl/strbuf.hxx>
80 :
81 : #define MAX_INDENT_LEVEL 20
82 :
83 : #if defined(UNX)
84 : const sal_Char SwHTMLWriter::sNewLine = '\012';
85 : #else
86 : const sal_Char SwHTMLWriter::sNewLine[] = "\015\012";
87 : #endif
88 :
89 : static sal_Char sIndentTabs[MAX_INDENT_LEVEL+2] =
90 : "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
91 :
92 0 : SwHTMLWriter::SwHTMLWriter( const String& rBaseURL )
93 : : bCfgOutStyles( sal_False )
94 : , bCfgPreferStyles( sal_False )
95 : , bCfgFormFeed( sal_False )
96 : , bCfgStarBasic( sal_False )
97 : , bCfgCpyLinkedGrfs( sal_False )
98 : , bFirstLine( sal_False )
99 : , bTagOn( sal_False )
100 : , bTxtAttr( sal_False )
101 : , bOutOpts( sal_False )
102 : , bOutTable( sal_False )
103 : , bOutHeader( sal_False )
104 : , bOutFooter( sal_False )
105 : , bOutFlyFrame( sal_False )
106 : , bFirstCSS1Rule( sal_False )
107 : , bFirstCSS1Property( sal_False )
108 : , bPoolCollTextModified( sal_False )
109 : , bCSS1IgnoreFirstPageDesc( sal_False )
110 : , bNoAlign( sal_False )
111 : , bClearLeft( sal_False )
112 : , bClearRight( sal_False )
113 : , bLFPossible( sal_False )
114 : , bPreserveForm( sal_False )
115 0 : , bCfgNetscape4( sal_False )
116 :
117 : {
118 0 : SetBaseURL( rBaseURL );
119 0 : bFirstLine = sal_True;
120 0 : nBkmkTabPos = -1;
121 0 : pDfltColor = 0;
122 0 : nImgMapCnt = 1;
123 0 : pStartNdIdx = 0;
124 0 : pTemplate = 0;
125 0 : pNumRuleInfo = new SwHTMLNumRuleInfo;
126 0 : pNextNumRuleInfo = 0;
127 0 : pFootEndNotes = 0;
128 0 : pFmtFtn = 0;
129 0 : eDestEnc = RTL_TEXTENCODING_MS_1252;
130 0 : nDirection = FRMDIR_HORI_LEFT_TOP;
131 0 : }
132 :
133 :
134 0 : SwHTMLWriter::~SwHTMLWriter()
135 : {
136 0 : delete pNumRuleInfo;
137 0 : }
138 :
139 0 : sal_uLong SwHTMLWriter::WriteStream()
140 : {
141 : // neue Konfiguration setzen
142 0 : SvxHtmlOptions& rHtmlOptions = SvxHtmlOptions::Get();
143 :
144 : // die Fontgroessen 1-7
145 0 : aFontHeights[0] = rHtmlOptions.GetFontSize( 0 ) * 20;
146 0 : aFontHeights[1] = rHtmlOptions.GetFontSize( 1 ) * 20;
147 0 : aFontHeights[2] = rHtmlOptions.GetFontSize( 2 ) * 20;
148 0 : aFontHeights[3] = rHtmlOptions.GetFontSize( 3 ) * 20;
149 0 : aFontHeights[4] = rHtmlOptions.GetFontSize( 4 ) * 20;
150 0 : aFontHeights[5] = rHtmlOptions.GetFontSize( 5 ) * 20;
151 0 : aFontHeights[6] = rHtmlOptions.GetFontSize( 6 ) * 20;
152 :
153 : // ueberhaupt Styles ausgeben
154 : // (dann auch obere und untere Absatz-Abstaende)
155 0 : nExportMode = rHtmlOptions.GetExportMode();
156 0 : nHTMLMode = GetHtmlMode(0);
157 0 : if( HTML_CFG_WRITER==nExportMode ||
158 : HTML_CFG_NS40==nExportMode )
159 0 : nHTMLMode |= HTMLMODE_BLOCK_SPACER;
160 :
161 0 : if( HTML_CFG_WRITER==nExportMode || HTML_CFG_MSIE==nExportMode )
162 0 : nHTMLMode |= (HTMLMODE_FLOAT_FRAME | HTMLMODE_LSPACE_IN_NUMBUL);
163 :
164 0 : if( HTML_CFG_MSIE==nExportMode )
165 0 : nHTMLMode |= HTMLMODE_NBSP_IN_TABLES;
166 :
167 0 : if( HTML_CFG_WRITER==nExportMode || HTML_CFG_NS40==nExportMode ||
168 : HTML_CFG_MSIE==nExportMode )
169 0 : nHTMLMode |= HTMLMODE_ABS_POS_FLY|HTMLMODE_ABS_POS_DRAW;
170 :
171 0 : if( HTML_CFG_WRITER==nExportMode )
172 0 : nHTMLMode |= HTMLMODE_FLY_MARGINS;
173 :
174 0 : if( HTML_CFG_NS40==nExportMode )
175 0 : nHTMLMode |= HTMLMODE_BORDER_NONE;
176 :
177 0 : nHTMLMode |= HTMLMODE_FONT_GENERIC;
178 :
179 0 : if( HTML_CFG_NS40==nExportMode )
180 0 : nHTMLMode |= HTMLMODE_NO_CONTROL_CENTERING;
181 :
182 : bCfgOutStyles = IsHTMLMode(HTMLMODE_SOME_STYLES |
183 0 : HTMLMODE_FULL_STYLES);
184 0 : bCfgNetscape4 = (HTML_CFG_NS40==nExportMode);
185 :
186 0 : if( IsHTMLMode(HTMLMODE_SOME_STYLES | HTMLMODE_FULL_STYLES) )
187 0 : nHTMLMode |= HTMLMODE_PRINT_EXT;
188 :
189 0 : const sal_Char *pHelpHack = getenv( "HelpEx" );
190 0 : if( pHelpHack )
191 : {
192 0 : rtl::OString aTmp(pHelpHack);
193 0 : if (aTmp.equalsIgnoreAsciiCase("Hilfe"))
194 0 : nHTMLMode |= HTMLMODE_NO_BR_AT_PAREND;
195 : }
196 :
197 0 : eCSS1Unit = (FieldUnit)SW_MOD()->GetMetric( pDoc->get(IDocumentSettingAccess::HTML_MODE) );
198 :
199 0 : sal_Bool bWriteUTF8 = bWriteClipboardDoc;
200 : eDestEnc = bWriteUTF8 ? RTL_TEXTENCODING_UTF8
201 0 : : rHtmlOptions.GetTextEncoding();
202 : const sal_Char *pCharSet =
203 0 : rtl_getBestMimeCharsetFromTextEncoding( eDestEnc );
204 0 : eDestEnc = rtl_getTextEncodingFromMimeCharset( pCharSet );
205 :
206 : // Nur noch fuer den MS-IE ziehen wir den Export von Styles vor.
207 0 : bCfgPreferStyles = HTML_CFG_MSIE==nExportMode;
208 :
209 0 : bCfgStarBasic = rHtmlOptions.IsStarBasic();
210 :
211 0 : bCfgFormFeed = !IsHTMLMode(HTMLMODE_PRINT_EXT);
212 0 : bCfgCpyLinkedGrfs = rHtmlOptions.IsSaveGraphicsLocal();
213 :
214 : // die HTML-Vorlage holen
215 0 : sal_Bool bOldHTMLMode = sal_False;
216 0 : sal_uInt16 nOldTxtFmtCollCnt = 0, nOldCharFmtCnt = 0;
217 :
218 : OSL_ENSURE( !pTemplate, "Wo kommt denn die HTML-Vorlage hier her?" );
219 0 : pTemplate = ((HTMLReader*)ReadHTML)->GetTemplateDoc();
220 0 : if( pTemplate )
221 : {
222 0 : pTemplate->acquire();
223 0 : bOldHTMLMode = pTemplate->get(IDocumentSettingAccess::HTML_MODE);
224 0 : pTemplate->set(IDocumentSettingAccess::HTML_MODE, true);
225 :
226 0 : nOldTxtFmtCollCnt = pTemplate->GetTxtFmtColls()->size();
227 0 : nOldCharFmtCnt = pTemplate->GetCharFmts()->size();
228 : }
229 :
230 0 : if( bShowProgress )
231 0 : ::StartProgress( STR_STATSTR_W4WWRITE, 0, pDoc->GetNodes().Count(),
232 0 : pDoc->GetDocShell());
233 :
234 0 : pDfltColor = 0;
235 0 : pFootEndNotes = 0;
236 0 : pFmtFtn = 0;
237 0 : bOutTable = bOutHeader = bOutFooter = bOutFlyFrame = sal_False;
238 0 : pxFormComps = 0;
239 0 : nFormCntrlCnt = 0;
240 0 : bPreserveForm = sal_False;
241 0 : bClearLeft = bClearRight = sal_False;
242 0 : bLFPossible = sal_False;
243 :
244 0 : nLeftMargin = nDfltLeftMargin = nDfltRightMargin = 0;
245 0 : nDfltTopMargin = nDfltBottomMargin = 0;
246 0 : nFirstLineIndent = nDfltFirstLineIndent = 0;
247 0 : bPoolCollTextModified = sal_False;
248 0 : bFirstCSS1Property = bFirstCSS1Rule = sal_False;
249 0 : bCSS1IgnoreFirstPageDesc = sal_False;
250 0 : nIndentLvl = 0;
251 0 : nWhishLineLen = 70;
252 0 : nLastLFPos = 0;
253 0 : nDefListLvl = 0;
254 0 : nDefListMargin = ((pTemplate && !bCfgOutStyles) ? pTemplate : pDoc)
255 0 : ->GetTxtCollFromPool( RES_POOLCOLL_HTML_DD, false )
256 0 : ->GetLRSpace().GetTxtLeft();
257 0 : nHeaderFooterSpace = 0;
258 0 : nTxtAttrsToIgnore = 0;
259 0 : nCSS1OutMode = 0;
260 0 : sal_uInt16 nScript = SvtLanguageOptions::GetScriptTypeOfLanguage( GetAppLanguage() );
261 0 : switch( nScript )
262 : {
263 : case SCRIPTTYPE_ASIAN:
264 0 : nCSS1Script = CSS1_OUTMODE_CJK;
265 0 : break;
266 : case SCRIPTTYPE_COMPLEX:
267 0 : nCSS1Script = CSS1_OUTMODE_CTL;
268 0 : break;
269 : default:
270 0 : nCSS1Script = CSS1_OUTMODE_WESTERN;
271 0 : break;
272 : }
273 : eLang = ((const SvxLanguageItem&)pDoc
274 0 : ->GetDefault(GetLangWhichIdFromScript(nCSS1Script))).GetLanguage();
275 :
276 0 : nFootNote = nEndNote = 0;
277 :
278 0 : nWarn = 0;
279 0 : GetNumInfo().Clear();
280 0 : pNextNumRuleInfo = 0;
281 :
282 0 : rtl::OString aStartTags;
283 :
284 : // Tabellen und Bereiche am Doc.-Anfang beachten
285 : {
286 0 : SwTableNode * pTNd = pCurPam->GetNode()->FindTableNode();
287 0 : if( pTNd && bWriteAll )
288 : {
289 : // mit dem Tabellen-Node anfangen !!
290 0 : pCurPam->GetPoint()->nNode = *pTNd;
291 :
292 0 : if( bWriteOnlyFirstTable )
293 0 : pCurPam->GetMark()->nNode = *pTNd->EndOfSectionNode();
294 : }
295 :
296 : // erster Node (der einen Seitenumbruch enthalten darf)
297 0 : pStartNdIdx = new SwNodeIndex( pCurPam->GetPoint()->nNode );
298 :
299 0 : SwSectionNode * pSNd = pCurPam->GetNode()->FindSectionNode();
300 0 : while( pSNd )
301 : {
302 0 : if( bWriteAll )
303 : {
304 : // mit dem Section-Node anfangen !!
305 0 : pCurPam->GetPoint()->nNode = *pSNd;
306 : }
307 : else
308 : {
309 : OSL_ENSURE( FILE_LINK_SECTION != pSNd->GetSection().GetType(),
310 : "Export gelinkter Bereiche am Dok-Anfang ist nicht implemntiert" );
311 :
312 : // nur das Tag fuer die Section merken
313 : rtl::OString aName = HTMLOutFuncs::ConvertStringToHTML(
314 0 : pSNd->GetSection().GetSectionName(), eDestEnc,
315 0 : &aNonConvertableCharacters );
316 :
317 0 : rtl::OStringBuffer sOut;
318 0 : sOut.append('<').append(OOO_STRING_SVTOOLS_HTML_division)
319 0 : .append(' ').append(OOO_STRING_SVTOOLS_HTML_O_id)
320 0 : .append("=\"").append(aName).append('\"').append('>')
321 0 : .append(aStartTags);
322 0 : aStartTags = sOut.makeStringAndClear();
323 : }
324 : // FindSectionNode() an einem SectionNode liefert den selben!
325 0 : pSNd = pSNd->StartOfSectionNode()->FindSectionNode();
326 : }
327 : }
328 :
329 :
330 : // Tabelle fuer die freifliegenden Rahmen erzeugen, aber nur wenn
331 : // das gesamte Dokument geschrieben wird
332 0 : pHTMLPosFlyFrms = 0;
333 0 : CollectFlyFrms();
334 0 : nLastParaToken = 0;
335 0 : GetControls();
336 0 : CollectLinkTargets();
337 :
338 0 : sal_uInt16 nHeaderAttrs = 0;
339 0 : pCurrPageDesc = MakeHeader( nHeaderAttrs );
340 :
341 0 : bLFPossible = sal_True;
342 :
343 : // Formulare, die nur HiddenControls enthalten ausgeben.
344 0 : OutHiddenForms();
345 :
346 0 : if( !aStartTags.isEmpty() )
347 0 : Strm() << aStartTags.getStr();
348 :
349 : const SfxPoolItem *pItem;
350 0 : const SfxItemSet& rPageItemSet = pCurrPageDesc->GetMaster().GetAttrSet();
351 0 : if( !bWriteClipboardDoc && pDoc->GetDocShell() &&
352 0 : (!pDoc->get(IDocumentSettingAccess::HTML_MODE) &&
353 0 : !pDoc->get(IDocumentSettingAccess::BROWSE_MODE)) &&
354 0 : SFX_ITEM_SET == rPageItemSet.GetItemState( RES_HEADER, sal_True, &pItem) )
355 : {
356 : const SwFrmFmt *pHeaderFmt =
357 0 : ((const SwFmtHeader *)pItem)->GetHeaderFmt();
358 0 : if( pHeaderFmt )
359 0 : OutHTML_HeaderFooter( *this, *pHeaderFmt, sal_True );
360 : }
361 :
362 0 : nTxtAttrsToIgnore = nHeaderAttrs;
363 0 : Out_SwDoc( pOrigPam );
364 0 : nTxtAttrsToIgnore = 0;
365 :
366 0 : if( pxFormComps && pxFormComps->is() )
367 0 : OutForm( sal_False, *pxFormComps );
368 :
369 0 : if( pFootEndNotes )
370 0 : OutFootEndNotes();
371 :
372 0 : if( !bWriteClipboardDoc && pDoc->GetDocShell() &&
373 0 : (!pDoc->get(IDocumentSettingAccess::HTML_MODE) && !pDoc->get(IDocumentSettingAccess::BROWSE_MODE)) &&
374 0 : SFX_ITEM_SET == rPageItemSet.GetItemState( RES_FOOTER, sal_True, &pItem) )
375 : {
376 : const SwFrmFmt *pFooterFmt =
377 0 : ((const SwFmtFooter *)pItem)->GetFooterFmt();
378 0 : if( pFooterFmt )
379 0 : OutHTML_HeaderFooter( *this, *pFooterFmt, sal_False );
380 : }
381 :
382 0 : if( bLFPossible )
383 0 : OutNewLine();
384 0 : HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_body, sal_False );
385 0 : OutNewLine();
386 0 : HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_html, sal_False );
387 :
388 : // loesche die Tabelle mit den freifliegenden Rahmen
389 : sal_uInt16 i;
390 : OSL_ENSURE( !pHTMLPosFlyFrms, "Wurden nicht alle Rahmen ausgegeben" );
391 0 : if( pHTMLPosFlyFrms )
392 : {
393 0 : pHTMLPosFlyFrms->DeleteAndDestroyAll();
394 0 : delete pHTMLPosFlyFrms;
395 0 : pHTMLPosFlyFrms = 0;
396 : }
397 :
398 0 : aHTMLControls.DeleteAndDestroyAll();
399 :
400 0 : if( !aChrFmtInfos.empty() )
401 0 : aChrFmtInfos.clear();
402 :
403 0 : if( !aTxtCollInfos.empty() )
404 0 : aTxtCollInfos.clear();
405 :
406 0 : if(!aImgMapNames.empty())
407 0 : aImgMapNames.clear();
408 :
409 0 : aImplicitMarks.clear();
410 :
411 0 : aOutlineMarks.clear();
412 :
413 0 : aOutlineMarkPoss.clear();
414 :
415 0 : aNumRuleNames.clear();
416 :
417 0 : aScriptParaStyles.clear();
418 0 : aScriptTextStyles.clear();
419 :
420 0 : delete pDfltColor;
421 0 : pDfltColor = 0;
422 :
423 0 : delete pStartNdIdx;
424 0 : pStartNdIdx = 0;
425 :
426 0 : delete pxFormComps;
427 0 : pxFormComps = 0;
428 :
429 : OSL_ENSURE( !pFootEndNotes,
430 : "SwHTMLWriter::Write: Ftns nicht durch OutFootEndNotes geloescht" );
431 :
432 0 : pCurrPageDesc = 0;
433 :
434 0 : ClearNextNumInfo();
435 :
436 0 : for( i=0; i<MAXLEVEL; i++ )
437 0 : aBulletGrfs[i].Erase();
438 :
439 0 : aNonConvertableCharacters.Erase();
440 :
441 0 : if( bShowProgress )
442 0 : ::EndProgress( pDoc->GetDocShell() );
443 :
444 0 : if( pTemplate )
445 : {
446 : // Waehrend des Exports angelegte Zeichen- und Abastzvorlagen
447 : // loeschen
448 0 : sal_uInt16 nTxtFmtCollCnt = pTemplate->GetTxtFmtColls()->size();
449 0 : while( nTxtFmtCollCnt > nOldTxtFmtCollCnt )
450 0 : pTemplate->DelTxtFmtColl( --nTxtFmtCollCnt );
451 : OSL_ENSURE( pTemplate->GetTxtFmtColls()->size() == nOldTxtFmtCollCnt,
452 : "falsche Anzahl TxtFmtColls geloescht" );
453 :
454 0 : sal_uInt16 nCharFmtCnt = pTemplate->GetCharFmts()->size();
455 0 : while( nCharFmtCnt > nOldCharFmtCnt )
456 0 : pTemplate->DelCharFmt( --nCharFmtCnt );
457 : OSL_ENSURE( pTemplate->GetCharFmts()->size() == nOldCharFmtCnt,
458 : "falsche Anzahl CharFmts geloescht" );
459 :
460 : // HTML-Modus wieder restaurieren
461 0 : pTemplate->set(IDocumentSettingAccess::HTML_MODE, bOldHTMLMode);
462 :
463 0 : if( 0 == pTemplate->release() )
464 0 : delete pTemplate;
465 :
466 0 : pTemplate = 0;
467 : }
468 :
469 0 : return nWarn;
470 : }
471 :
472 0 : static const SwFmtCol *lcl_html_GetFmtCol( const SwHTMLWriter& rHTMLWrt,
473 : const SwSection& rSection,
474 : const SwSectionFmt& rFmt )
475 : {
476 0 : const SwFmtCol *pCol = 0;
477 :
478 : const SfxPoolItem* pItem;
479 0 : if( rHTMLWrt.IsHTMLMode( HTMLMODE_FRM_COLUMNS ) &&
480 0 : FILE_LINK_SECTION != rSection.GetType() &&
481 0 : SFX_ITEM_SET == rFmt.GetAttrSet().GetItemState(RES_COL,sal_False,&pItem) &&
482 0 : ((const SwFmtCol *)pItem)->GetNumCols() > 1 )
483 : {
484 0 : pCol = (const SwFmtCol *)pItem;
485 : }
486 :
487 0 : return pCol;
488 : }
489 :
490 0 : static bool lcl_html_IsMultiColStart( const SwHTMLWriter& rHTMLWrt, sal_uLong nIndex )
491 : {
492 0 : bool bRet = false;
493 : const SwSectionNode *pSectNd =
494 0 : rHTMLWrt.pDoc->GetNodes()[nIndex]->GetSectionNode();
495 0 : if( pSectNd )
496 : {
497 0 : const SwSection& rSection = pSectNd->GetSection();
498 0 : const SwSectionFmt *pFmt = rSection.GetFmt();
499 0 : if( pFmt && lcl_html_GetFmtCol( rHTMLWrt, rSection, *pFmt ) )
500 0 : bRet = true;
501 : }
502 :
503 0 : return bRet;
504 : }
505 :
506 0 : static bool lcl_html_IsMultiColEnd( const SwHTMLWriter& rHTMLWrt, sal_uLong nIndex )
507 : {
508 0 : bool bRet = false;
509 0 : const SwEndNode *pEndNd = rHTMLWrt.pDoc->GetNodes()[nIndex]->GetEndNode();
510 0 : if( pEndNd )
511 : bRet = lcl_html_IsMultiColStart( rHTMLWrt,
512 0 : pEndNd->StartOfSectionIndex() );
513 :
514 0 : return bRet;
515 : }
516 :
517 :
518 0 : static void lcl_html_OutSectionStartTag( SwHTMLWriter& rHTMLWrt,
519 : const SwSection& rSection,
520 : const SwSectionFmt& rFmt,
521 : const SwFmtCol *pCol,
522 : bool bContinued=false )
523 : {
524 : OSL_ENSURE( pCol || !bContinued, "Continuation of DIV" );
525 :
526 0 : if( rHTMLWrt.bLFPossible )
527 0 : rHTMLWrt.OutNewLine();
528 :
529 0 : const sal_Char *pTag = pCol ? OOO_STRING_SVTOOLS_HTML_multicol : OOO_STRING_SVTOOLS_HTML_division;
530 :
531 0 : rtl::OStringBuffer sOut;
532 0 : sOut.append('<').append(pTag);
533 :
534 0 : const String& rName = rSection.GetSectionName();
535 0 : if( rName.Len() && !bContinued )
536 : {
537 0 : sOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_id).
538 0 : append(RTL_CONSTASCII_STRINGPARAM("=\""));
539 0 : rHTMLWrt.Strm() << sOut.makeStringAndClear().getStr();
540 0 : HTMLOutFuncs::Out_String( rHTMLWrt.Strm(), rName, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters );
541 0 : sOut.append('\"');
542 : }
543 :
544 0 : sal_uInt16 nDir = rHTMLWrt.GetHTMLDirection( rFmt.GetAttrSet() );
545 0 : rHTMLWrt.Strm() << sOut.makeStringAndClear().getStr();
546 0 : rHTMLWrt.OutDirection( nDir );
547 :
548 0 : if( FILE_LINK_SECTION == rSection.GetType() )
549 : {
550 0 : sOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_href).
551 0 : append(RTL_CONSTASCII_STRINGPARAM("=\""));
552 0 : rHTMLWrt.Strm() << sOut.makeStringAndClear().getStr();
553 :
554 0 : const String& aFName = rSection.GetLinkFileName();
555 0 : String aURL( aFName.GetToken(0,sfx2::cTokenSeperator) );
556 0 : String aFilter( aFName.GetToken(1,sfx2::cTokenSeperator) );
557 0 : String aSection( aFName.GetToken(2,sfx2::cTokenSeperator) );
558 :
559 0 : String aEncURL( URIHelper::simpleNormalizedMakeRelative(rHTMLWrt.GetBaseURL(), aURL ) );
560 0 : sal_Unicode cDelim = 255U;
561 : bool bURLContainsDelim =
562 0 : (STRING_NOTFOUND != aEncURL.Search( cDelim ) );
563 :
564 0 : HTMLOutFuncs::Out_String( rHTMLWrt.Strm(), aEncURL,
565 : rHTMLWrt.eDestEnc,
566 0 : &rHTMLWrt.aNonConvertableCharacters );
567 0 : const sal_Char *pDelim = "ÿ";
568 0 : if( aFilter.Len() || aSection.Len() || bURLContainsDelim )
569 0 : rHTMLWrt.Strm() << pDelim;
570 0 : if( aFilter.Len() )
571 0 : HTMLOutFuncs::Out_String( rHTMLWrt.Strm(), aFilter,
572 0 : rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters );
573 0 : if( aSection.Len() || bURLContainsDelim )
574 0 : rHTMLWrt.Strm() << pDelim;
575 0 : if( aSection.Len() )
576 : {
577 0 : xub_StrLen nPos = aSection.Search( '%' );
578 0 : while( STRING_NOTFOUND != nPos )
579 : {
580 0 : aSection.Erase( nPos, 1 );
581 0 : aSection.InsertAscii( "%25", nPos );
582 0 : nPos = aSection.Search( '%', nPos+3 );
583 : }
584 0 : nPos = aSection.Search( cDelim );
585 0 : while( STRING_NOTFOUND != nPos )
586 : {
587 0 : aSection.Erase( nPos, 1 );
588 0 : aSection.InsertAscii( "%FF", nPos );
589 0 : nPos = aSection.Search( cDelim, nPos+3 );
590 : }
591 0 : HTMLOutFuncs::Out_String( rHTMLWrt.Strm(), aSection,
592 0 : rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters );
593 : }
594 0 : sOut.append('\"');
595 : }
596 0 : else if( pCol )
597 : {
598 0 : sOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_cols).
599 0 : append('=').append(static_cast<sal_Int32>(pCol->GetNumCols()));
600 :
601 : // minumum gutter width
602 0 : sal_uInt16 nGutter = pCol->GetGutterWidth( sal_True );
603 0 : if( nGutter!=USHRT_MAX )
604 : {
605 0 : if( nGutter && Application::GetDefaultDevice() )
606 : {
607 : nGutter = (sal_uInt16)Application::GetDefaultDevice()
608 : ->LogicToPixel( Size(nGutter,0),
609 0 : MapMode(MAP_TWIP) ).Width();
610 : }
611 0 : sOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_gutter).
612 0 : append('=').append(static_cast<sal_Int32>(nGutter));
613 : }
614 : }
615 :
616 0 : rHTMLWrt.Strm() << sOut.makeStringAndClear().getStr();
617 0 : if( rHTMLWrt.IsHTMLMode( rHTMLWrt.bCfgOutStyles ) )
618 0 : rHTMLWrt.OutCSS1_SectionFmtOptions( rFmt );
619 :
620 0 : rHTMLWrt.Strm() << '>';
621 :
622 0 : rHTMLWrt.bLFPossible = sal_True;
623 0 : if( rName.Len() && !bContinued )
624 0 : rHTMLWrt.OutImplicitMark( rName, pMarkToRegion );
625 :
626 0 : rHTMLWrt.IncIndentLevel();
627 0 : }
628 :
629 0 : static void lcl_html_OutSectionEndTag( SwHTMLWriter& rHTMLWrt,
630 : const SwFmtCol *pCol )
631 : {
632 0 : const sal_Char *pTag = pCol ? OOO_STRING_SVTOOLS_HTML_multicol : OOO_STRING_SVTOOLS_HTML_division;
633 :
634 0 : rHTMLWrt.DecIndentLevel();
635 0 : if( rHTMLWrt.bLFPossible )
636 0 : rHTMLWrt.OutNewLine();
637 0 : HTMLOutFuncs::Out_AsciiTag( rHTMLWrt.Strm(), pTag, sal_False );
638 0 : rHTMLWrt.bLFPossible = sal_True;
639 0 : }
640 :
641 0 : static Writer& OutHTML_Section( Writer& rWrt, const SwSectionNode& rSectNd )
642 : {
643 0 : SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
644 :
645 : // End <PRE> and any <DL>, because a definition list's level may
646 : // change inside the section.
647 0 : rHTMLWrt.ChangeParaToken( 0 );
648 0 : rHTMLWrt.OutAndSetDefList( 0 );
649 :
650 0 : const SwSection& rSection = rSectNd.GetSection();
651 0 : const SwSectionFmt *pFmt = rSection.GetFmt();
652 : OSL_ENSURE( pFmt, "Section without a format?" );
653 :
654 0 : bool bStartTag = true;
655 0 : bool bEndTag = true;
656 0 : const SwSectionFmt *pSurrFmt = 0;
657 0 : const SwSectionNode *pSurrSectNd = 0;
658 0 : const SwSection *pSurrSection = 0;
659 0 : const SwFmtCol *pSurrCol = 0;
660 :
661 0 : sal_uInt32 nSectSttIdx = rSectNd.GetIndex();
662 0 : sal_uInt32 nSectEndIdx = rSectNd.EndOfSectionIndex();
663 0 : const SwFmtCol *pCol = lcl_html_GetFmtCol( rHTMLWrt, rSection, *pFmt );
664 0 : if( pCol )
665 : {
666 : // If the next node is a columned section node, too, don't export
667 : // an empty section.
668 0 : if( lcl_html_IsMultiColStart( rHTMLWrt, nSectSttIdx+1 ) )
669 0 : bStartTag = false;
670 :
671 : // The same applies if the section end with another columned section.
672 0 : if( lcl_html_IsMultiColEnd( rHTMLWrt, nSectEndIdx-1 ) )
673 0 : bEndTag = false;
674 :
675 : //.is there a columned section arround this one?
676 0 : const SwStartNode *pSttNd = rSectNd.StartOfSectionNode();
677 0 : if( pSttNd )
678 : {
679 0 : pSurrSectNd = pSttNd->FindSectionNode();
680 0 : if( pSurrSectNd )
681 : {
682 0 : const SwStartNode *pBoxSttNd = pSttNd->FindTableBoxStartNode();
683 0 : if( !pBoxSttNd ||
684 0 : pBoxSttNd->GetIndex() < pSurrSectNd->GetIndex() )
685 : {
686 0 : pSurrSection = &pSurrSectNd->GetSection();
687 0 : pSurrFmt = pSurrSection->GetFmt();
688 0 : if( pSurrFmt )
689 : pSurrCol = lcl_html_GetFmtCol( rHTMLWrt, *pSurrSection,
690 0 : *pSurrFmt );
691 : }
692 : }
693 : }
694 : }
695 :
696 : // The surrounding section must be closed before the current one is
697 : // opended, except that it start immediatly before the current one or
698 : // another end immediately before the current one
699 0 : if( pSurrCol && nSectSttIdx - pSurrSectNd->GetIndex() > 1 &&
700 0 : !lcl_html_IsMultiColEnd( rHTMLWrt, nSectSttIdx-1 ) )
701 0 : lcl_html_OutSectionEndTag( rHTMLWrt, pSurrCol );
702 :
703 0 : if( bStartTag )
704 0 : lcl_html_OutSectionStartTag( rHTMLWrt, rSection, *pFmt, pCol );
705 :
706 : {
707 : HTMLSaveData aSaveData( rHTMLWrt,
708 0 : rHTMLWrt.pCurPam->GetPoint()->nNode.GetIndex()+1,
709 : rSectNd.EndOfSectionIndex(),
710 0 : sal_False, pFmt );
711 0 : rHTMLWrt.Out_SwDoc( rHTMLWrt.pCurPam );
712 : }
713 :
714 0 : rHTMLWrt.pCurPam->GetPoint()->nNode = *rSectNd.EndOfSectionNode();
715 :
716 0 : if( bEndTag )
717 0 : lcl_html_OutSectionEndTag( rHTMLWrt, pCol );
718 :
719 : // The surrounding section must be started again, except that it ends
720 : // immeditaly behind the current one.
721 0 : if( pSurrCol &&
722 0 : pSurrSectNd->EndOfSectionIndex() - nSectEndIdx > 1 &&
723 0 : !lcl_html_IsMultiColStart( rHTMLWrt, nSectEndIdx+1 ) )
724 : lcl_html_OutSectionStartTag( rHTMLWrt, *pSurrSection, *pSurrFmt,
725 0 : pSurrCol, true );
726 :
727 0 : return rWrt;
728 : }
729 :
730 0 : void SwHTMLWriter::Out_SwDoc( SwPaM* pPam )
731 : {
732 0 : sal_Bool bSaveWriteAll = bWriteAll; // sichern
733 :
734 : // suche die naechste text::Bookmark-Position aus der text::Bookmark-Tabelle
735 0 : nBkmkTabPos = bWriteAll ? FindPos_Bkmk( *pCurPam->GetPoint() ) : -1;
736 :
737 : // gebe alle Bereiche des Pams in das HTML-File aus.
738 0 : do {
739 0 : bWriteAll = bSaveWriteAll;
740 0 : bFirstLine = sal_True;
741 :
742 : // suche den ersten am Pam-auszugebenen FlyFrame
743 : // fehlt noch:
744 :
745 0 : while( pCurPam->GetPoint()->nNode.GetIndex() < pCurPam->GetMark()->nNode.GetIndex() ||
746 0 : (pCurPam->GetPoint()->nNode.GetIndex() == pCurPam->GetMark()->nNode.GetIndex() &&
747 0 : pCurPam->GetPoint()->nContent.GetIndex() <= pCurPam->GetMark()->nContent.GetIndex()) )
748 : {
749 0 : SwNode * pNd = pCurPam->GetNode();
750 :
751 : OSL_ENSURE( !(pNd->IsGrfNode() || pNd->IsOLENode()),
752 : "Grf- oder OLE-Node hier unerwartet" );
753 0 : if( pNd->IsTxtNode() )
754 : {
755 0 : SwTxtNode* pTxtNd = pNd->GetTxtNode();
756 :
757 0 : if( !bFirstLine )
758 0 : pCurPam->GetPoint()->nContent.Assign( pTxtNd, 0 );
759 :
760 0 : OutHTML_SwTxtNode( *this, *pTxtNd );
761 : }
762 0 : else if( pNd->IsTableNode() )
763 : {
764 0 : OutHTML_SwTblNode( *this, *pNd->GetTableNode(), 0 );
765 0 : nBkmkTabPos = bWriteAll ? FindPos_Bkmk( *pCurPam->GetPoint() ) : -1;
766 : }
767 0 : else if( pNd->IsSectionNode() )
768 : {
769 0 : OutHTML_Section( *this, *pNd->GetSectionNode() );
770 0 : nBkmkTabPos = bWriteAll ? FindPos_Bkmk( *pCurPam->GetPoint() ) : -1;
771 : }
772 0 : else if( pNd == &pDoc->GetNodes().GetEndOfContent() )
773 0 : break;
774 :
775 0 : pCurPam->GetPoint()->nNode++; // Bewegen
776 0 : sal_uInt32 nPos = pCurPam->GetPoint()->nNode.GetIndex();
777 :
778 0 : if( bShowProgress )
779 0 : ::SetProgressState( nPos, pDoc->GetDocShell() ); // Wie weit ?
780 :
781 : /* sollen nur die Selectierten Bereiche gesichert werden, so
782 : * duerfen nur die vollstaendigen Nodes gespeichert werde,
783 : * d.H. der 1. und n. Node teilweise, der 2. bis n-1. Node
784 : * vollstaendig. (vollstaendig heisst mit allen Formaten! )
785 : */
786 : bWriteAll = bSaveWriteAll ||
787 0 : nPos != pCurPam->GetMark()->nNode.GetIndex();
788 0 : bFirstLine = sal_False;
789 0 : bOutFooter = sal_False; // Nach einem Node keine Fusszeile mehr
790 : }
791 :
792 0 : ChangeParaToken( 0 ); // MIB 8.7.97: Machen wir jetzt hier und nicht
793 : // beim Aufrufer
794 0 : OutAndSetDefList( 0 );
795 :
796 0 : } while( CopyNextPam( &pPam ) ); // bis alle PaM's bearbeitet
797 :
798 0 : bWriteAll = bSaveWriteAll; // wieder auf alten Wert zurueck
799 0 : }
800 :
801 :
802 : // schreibe die StyleTabelle, algemeine Angaben,Header/Footer/Footnotes
803 0 : static void OutBodyColor( const sal_Char *pTag, const SwFmt *pFmt,
804 : SwHTMLWriter& rHWrt )
805 : {
806 0 : const SwFmt *pRefFmt = 0;
807 :
808 0 : if( rHWrt.pTemplate )
809 0 : pRefFmt = SwHTMLWriter::GetTemplateFmt( pFmt->GetPoolFmtId(),
810 0 : rHWrt.pTemplate );
811 :
812 0 : const SvxColorItem *pColorItem = 0;
813 :
814 0 : const SfxItemSet& rItemSet = pFmt->GetAttrSet();
815 0 : const SfxPoolItem *pRefItem = 0, *pItem = 0;
816 : bool bItemSet = SFX_ITEM_SET == rItemSet.GetItemState( RES_CHRATR_COLOR,
817 0 : sal_True, &pItem);
818 : bool bRefItemSet = pRefFmt &&
819 0 : SFX_ITEM_SET == pRefFmt->GetAttrSet().GetItemState( RES_CHRATR_COLOR,
820 0 : sal_True, &pRefItem);
821 0 : if( bItemSet )
822 : {
823 : // wenn das Item nur in der Vorlage des aktuellen Doks gesetzt
824 : // ist oder einen anderen Wert hat, als in der HTML-Vorlage,
825 : // wird es gesetzt
826 0 : const SvxColorItem *pCItem = (const SvxColorItem*)pItem;
827 :
828 0 : if( !bRefItemSet )
829 : {
830 0 : pColorItem = pCItem;
831 : }
832 : else
833 : {
834 0 : Color aColor( pCItem->GetValue() );
835 0 : if( COL_AUTO == aColor.GetColor() )
836 0 : aColor.SetColor( COL_BLACK );
837 :
838 0 : Color aRefColor( ((const SvxColorItem*)pRefItem)->GetValue() );
839 0 : if( COL_AUTO == aRefColor.GetColor() )
840 0 : aRefColor.SetColor( COL_BLACK );
841 :
842 0 : if( !aColor.IsRGBEqual( aRefColor ) )
843 0 : pColorItem = pCItem;
844 : }
845 : }
846 0 : else if( bRefItemSet )
847 : {
848 : // Das Item war in der HTML-Vorlage noch gesetzt, also geben wir
849 : // das Default aus
850 0 : pColorItem = (const SvxColorItem*)&rItemSet.GetPool()
851 0 : ->GetDefaultItem( RES_CHRATR_COLOR );
852 : }
853 :
854 0 : if( pColorItem )
855 : {
856 0 : rtl::OStringBuffer sOut;
857 0 : sOut.append(' ').append(pTag).append('=');
858 0 : rHWrt.Strm() << sOut.makeStringAndClear().getStr();
859 0 : Color aColor( pColorItem->GetValue() );
860 0 : if( COL_AUTO == aColor.GetColor() )
861 0 : aColor.SetColor( COL_BLACK );
862 0 : HTMLOutFuncs::Out_Color( rHWrt.Strm(), aColor, rHWrt.eDestEnc );
863 0 : if( RES_POOLCOLL_STANDARD==pFmt->GetPoolFmtId() )
864 0 : rHWrt.pDfltColor = new Color( aColor );
865 : }
866 0 : }
867 :
868 0 : sal_uInt16 SwHTMLWriter::OutHeaderAttrs()
869 : {
870 0 : sal_uLong nIdx = pCurPam->GetPoint()->nNode.GetIndex();
871 0 : sal_uLong nEndIdx = pCurPam->GetMark()->nNode.GetIndex();
872 :
873 0 : SwTxtNode *pTxtNd = 0;
874 0 : while( nIdx<=nEndIdx &&
875 0 : 0==(pTxtNd=pDoc->GetNodes()[nIdx]->GetTxtNode()) )
876 0 : nIdx++;
877 :
878 : OSL_ENSURE( pTxtNd, "Kein Text-Node gefunden" );
879 0 : if( !pTxtNd || !pTxtNd->HasHints() )
880 0 : return 0;
881 :
882 0 : sal_uInt16 nAttrs = 0;
883 0 : sal_uInt16 nCntAttr = pTxtNd->GetSwpHints().Count();
884 0 : xub_StrLen nOldPos = 0;
885 0 : for( sal_uInt16 i=0; i<nCntAttr; i++ )
886 : {
887 0 : const SwTxtAttr *pHt = pTxtNd->GetSwpHints()[i];
888 0 : if( !pHt->GetEnd() )
889 : {
890 0 : xub_StrLen nPos = *pHt->GetStart();
891 0 : if( nPos-nOldPos > 1 || RES_TXTATR_FIELD != pHt->Which() )
892 0 : break;
893 :
894 0 : sal_uInt16 nFldWhich = ((const SwFmtFld&)pHt->GetAttr()).GetFld()
895 0 : ->GetTyp()->Which();
896 0 : if( RES_POSTITFLD!=nFldWhich &&
897 : RES_SCRIPTFLD!=nFldWhich )
898 0 : break;
899 :
900 0 : OutNewLine();
901 0 : OutHTML_SwFmtFld( *this, pHt->GetAttr() );
902 0 : nOldPos = nPos;
903 0 : nAttrs++;
904 : }
905 : }
906 :
907 0 : return nAttrs;
908 : }
909 :
910 0 : const SwPageDesc *SwHTMLWriter::MakeHeader( sal_uInt16 &rHeaderAttrs )
911 : {
912 0 : rtl::OStringBuffer sOut;
913 0 : sOut.append(OOO_STRING_SVTOOLS_HTML_doctype).append(' ')
914 0 : .append(OOO_STRING_SVTOOLS_HTML_doctype40);
915 0 : HTMLOutFuncs::Out_AsciiTag( Strm(), sOut.makeStringAndClear().getStr() );
916 :
917 : // baue den Vorspann
918 0 : OutNewLine();
919 0 : HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_html );
920 :
921 0 : OutNewLine();
922 0 : HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_head );
923 :
924 0 : IncIndentLevel(); // Inhalt von <HEAD> einruecken
925 :
926 : // DokumentInfo
927 0 : rtl::OString sIndent = GetIndentString();
928 : using namespace ::com::sun::star;
929 0 : uno::Reference<document::XDocumentProperties> xDocProps;
930 0 : SwDocShell *pDocShell(pDoc->GetDocShell());
931 0 : if (pDocShell)
932 : {
933 : uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
934 0 : pDocShell->GetModel(), uno::UNO_QUERY_THROW);
935 0 : xDocProps.set(xDPS->getDocumentProperties());
936 : }
937 :
938 : // xDocProps may be null here (when copying)
939 0 : SfxFrameHTMLWriter::Out_DocInfo( Strm(), GetBaseURL(), xDocProps,
940 : sIndent.getStr(), eDestEnc,
941 0 : &aNonConvertableCharacters );
942 :
943 : // Kommentare und Meta-Tags des ersten Absatzes
944 0 : rHeaderAttrs = OutHeaderAttrs();
945 :
946 0 : OutFootEndNoteInfo();
947 :
948 0 : const SwPageDesc *pPageDesc = 0;
949 :
950 : // In Nicht-HTML-Dokumenten wird die erste gesetzte Seitenvorlage
951 : // exportiert und wenn keine gesetzt ist die Standard-Vorlage
952 0 : sal_uLong nNodeIdx = pCurPam->GetPoint()->nNode.GetIndex();
953 :
954 0 : while( nNodeIdx < pDoc->GetNodes().Count() )
955 : {
956 0 : SwNode *pNd = pDoc->GetNodes()[ nNodeIdx ];
957 0 : if( pNd->IsCntntNode() )
958 : {
959 : pPageDesc = ((const SwFmtPageDesc &)pNd->GetCntntNode()
960 0 : ->GetAttr(RES_PAGEDESC)).GetPageDesc();
961 0 : break;
962 : }
963 0 : else if( pNd->IsTableNode() )
964 : {
965 0 : pPageDesc = pNd->GetTableNode()->GetTable().GetFrmFmt()
966 0 : ->GetPageDesc().GetPageDesc();
967 0 : break;
968 : }
969 :
970 0 : nNodeIdx++;
971 : }
972 :
973 0 : if( !pPageDesc )
974 0 : pPageDesc = &pDoc->GetPageDesc( 0 );
975 :
976 : // und nun ... das Style-Sheet!!!
977 0 : if( bCfgOutStyles )
978 : {
979 0 : OutStyleSheet( *pPageDesc );
980 : }
981 :
982 : // und nun ... das BASIC und JavaScript!
983 0 : if( pDoc->GetDocShell() ) // nur mit DocShell ist Basic moeglich
984 0 : OutBasic();
985 :
986 0 : DecIndentLevel(); // Inhalt von <HEAD> einruecken
987 0 : OutNewLine();
988 0 : HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_head, sal_False );
989 :
990 : // der Body wird nicht eingerueckt, weil sonst alles eingerueckt waere!
991 0 : OutNewLine();
992 0 : sOut.append('<').append(OOO_STRING_SVTOOLS_HTML_body);
993 0 : Strm() << sOut.makeStringAndClear().getStr();
994 :
995 : // language
996 0 : OutLanguage( eLang );
997 :
998 : // Textfarbe ausgeben, wenn sie an der Standard-Vorlage gesetzt ist
999 : // und sich geaendert hat.
1000 : OutBodyColor( OOO_STRING_SVTOOLS_HTML_O_text,
1001 0 : pDoc->GetTxtCollFromPool( RES_POOLCOLL_STANDARD, false ),
1002 0 : *this );
1003 :
1004 : // Farben fuer (un)besuchte Links
1005 : OutBodyColor( OOO_STRING_SVTOOLS_HTML_O_link,
1006 0 : pDoc->GetCharFmtFromPool( RES_POOLCHR_INET_NORMAL ),
1007 0 : *this );
1008 : OutBodyColor( OOO_STRING_SVTOOLS_HTML_O_vlink,
1009 0 : pDoc->GetCharFmtFromPool( RES_POOLCHR_INET_VISIT ),
1010 0 : *this );
1011 :
1012 0 : const SfxItemSet& rItemSet = pPageDesc->GetMaster().GetAttrSet();
1013 :
1014 0 : String aEmbGrfName;
1015 0 : OutBackground( rItemSet, aEmbGrfName, sal_True );
1016 :
1017 0 : nDirection = GetHTMLDirection( rItemSet );
1018 0 : OutDirection( nDirection );
1019 :
1020 0 : if( bCfgOutStyles )
1021 0 : OutCSS1_BodyTagStyleOpt( *this, rItemSet, aEmbGrfName );
1022 :
1023 : // Events anhaengen
1024 0 : if( pDoc->GetDocShell() ) // nur mit DocShell ist Basic moeglich
1025 0 : OutBasicBodyEvents();
1026 :
1027 0 : Strm() << '>';
1028 :
1029 0 : return pPageDesc;
1030 : }
1031 :
1032 0 : void SwHTMLWriter::OutAnchor( const String& rName )
1033 : {
1034 0 : rtl::OStringBuffer sOut;
1035 0 : sOut.append('<').append(OOO_STRING_SVTOOLS_HTML_anchor).append(' ')
1036 0 : .append(OOO_STRING_SVTOOLS_HTML_O_name).append("=\"");
1037 0 : Strm() << sOut.makeStringAndClear().getStr();
1038 0 : HTMLOutFuncs::Out_String( Strm(), rName, eDestEnc, &aNonConvertableCharacters ) << "\">";
1039 0 : HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_anchor, sal_False );
1040 0 : }
1041 :
1042 0 : void SwHTMLWriter::OutBookmarks()
1043 : {
1044 : // hole das aktuelle Bookmark
1045 0 : const ::sw::mark::IMark* pBookmark = NULL;
1046 0 : IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
1047 0 : if(nBkmkTabPos != -1)
1048 0 : pBookmark = (pMarkAccess->getMarksBegin() + nBkmkTabPos)->get();
1049 : // Ausgabe aller Bookmarks in diesem Absatz. Die Content-Position
1050 : // wird vorerst nicht beruecksichtigt!
1051 0 : sal_uInt32 nNode = pCurPam->GetPoint()->nNode.GetIndex();
1052 0 : while( nBkmkTabPos != -1 &&
1053 0 : pBookmark->GetMarkPos().nNode.GetIndex() == nNode )
1054 : {
1055 : // Der Bereich derBookmark wird erstam ignoriert, da er von uns
1056 : // auch nicht eingelesen wird.
1057 :
1058 : // erst die SWG spezifischen Daten:
1059 0 : if(dynamic_cast< const ::sw::mark::IBookmark* >(pBookmark) && !pBookmark->GetName().isEmpty() )
1060 0 : OutAnchor( pBookmark->GetName() );
1061 :
1062 0 : if( ++nBkmkTabPos >= pMarkAccess->getMarksCount() )
1063 0 : nBkmkTabPos = -1;
1064 : else
1065 0 : pBookmark = (pMarkAccess->getMarksBegin() + nBkmkTabPos)->get();
1066 : }
1067 :
1068 : sal_uInt32 nPos;
1069 0 : for( nPos = 0; nPos < aOutlineMarkPoss.size() &&
1070 0 : aOutlineMarkPoss[nPos] < nNode; nPos++ )
1071 : ;
1072 :
1073 0 : while( nPos < aOutlineMarkPoss.size() && aOutlineMarkPoss[nPos] == nNode )
1074 : {
1075 0 : String sMark( aOutlineMarks[nPos] );
1076 0 : sMark.SearchAndReplaceAll( '?', '_' ); // '?' causes problems in IE/Netscape 5
1077 0 : OutAnchor( sMark );
1078 0 : aOutlineMarkPoss.erase( aOutlineMarkPoss.begin()+nPos );
1079 0 : aOutlineMarks.erase( aOutlineMarks.begin() + nPos );
1080 0 : }
1081 0 : }
1082 :
1083 0 : void SwHTMLWriter::OutImplicitMark( const String& rMark,
1084 : const sal_Char *pMarkType )
1085 : {
1086 0 : if( rMark.Len() && !aImplicitMarks.empty() )
1087 : {
1088 0 : String sMark( rMark );
1089 0 : sMark.Append( cMarkSeperator );
1090 0 : sMark.AppendAscii( pMarkType );
1091 0 : if( 0 != aImplicitMarks.erase( sMark ) )
1092 : {
1093 0 : sMark.SearchAndReplaceAll( '?', '_' ); // '?' causes problems in IE/Netscape 5
1094 0 : OutAnchor( sMark );
1095 0 : }
1096 : }
1097 0 : }
1098 :
1099 0 : void SwHTMLWriter::OutHyperlinkHRefValue( const String& rURL )
1100 : {
1101 0 : String sURL( rURL );
1102 0 : xub_StrLen nPos = sURL.SearchBackward( cMarkSeperator );
1103 0 : if( STRING_NOTFOUND != nPos )
1104 : {
1105 0 : String sCmp(comphelper::string::remove(sURL.Copy(nPos+1), ' '));
1106 0 : if( sCmp.Len() )
1107 : {
1108 0 : sCmp.ToLowerAscii();
1109 0 : if( sCmp.EqualsAscii( pMarkToRegion ) ||
1110 0 : sCmp.EqualsAscii( pMarkToFrame ) ||
1111 0 : sCmp.EqualsAscii( pMarkToGraphic ) ||
1112 0 : sCmp.EqualsAscii( pMarkToOLE ) ||
1113 0 : sCmp.EqualsAscii( pMarkToTable ) ||
1114 0 : sCmp.EqualsAscii( pMarkToOutline ) ||
1115 0 : sCmp.EqualsAscii( pMarkToText ) )
1116 : {
1117 0 : sURL.SearchAndReplaceAll( '?', '_' ); // '?' causes problems in IE/Netscape 5
1118 : }
1119 0 : }
1120 : }
1121 :
1122 0 : sURL = URIHelper::simpleNormalizedMakeRelative( GetBaseURL(), sURL);
1123 0 : HTMLOutFuncs::Out_String( Strm(), sURL, eDestEnc,
1124 0 : &aNonConvertableCharacters );
1125 0 : }
1126 :
1127 0 : void SwHTMLWriter::OutBackground( const SvxBrushItem *pBrushItem,
1128 : String& rEmbGrfNm, sal_Bool bGraphic )
1129 : {
1130 0 : const Color &rBackColor = pBrushItem->GetColor();
1131 : /// check, if background color is not "no fill"/"auto fill", instead of
1132 : /// only checking, if transparency is not set.
1133 0 : if( rBackColor.GetColor() != COL_TRANSPARENT )
1134 : {
1135 0 : rtl::OStringBuffer sOut;
1136 0 : sOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_bgcolor).append('=');
1137 0 : Strm() << sOut.makeStringAndClear().getStr();
1138 0 : HTMLOutFuncs::Out_Color( Strm(), rBackColor, eDestEnc);
1139 : }
1140 :
1141 0 : if( !bGraphic )
1142 0 : return;
1143 :
1144 0 : const String *pLink = pBrushItem->GetGraphicLink();
1145 :
1146 : // embeddete Grafik -> WriteEmbedded schreiben
1147 0 : if( !pLink )
1148 : {
1149 0 : const Graphic* pGrf = pBrushItem->GetGraphic();
1150 0 : if( pGrf )
1151 : {
1152 : // Grafik als (JPG-)File speichern
1153 0 : const String* pTempFileName = GetOrigFileName();
1154 0 : if(pTempFileName)
1155 0 : rEmbGrfNm = *pTempFileName;
1156 : sal_uInt16 nErr = XOutBitmap::WriteGraphic( *pGrf, rEmbGrfNm,
1157 : rtl::OUString("JPG"),
1158 0 : XOUTBMP_USE_NATIVE_IF_POSSIBLE );
1159 0 : if( !nErr ) // fehlerhaft, da ist nichts auszugeben
1160 : {
1161 : rEmbGrfNm = URIHelper::SmartRel2Abs(
1162 0 : INetURLObject( GetBaseURL() ), rEmbGrfNm,
1163 0 : URIHelper::GetMaybeFileHdl() );
1164 0 : pLink = &rEmbGrfNm;
1165 : }
1166 : else
1167 : {
1168 0 : nWarn = WARN_SWG_POOR_LOAD | WARN_SW_WRITE_BASE;
1169 : }
1170 : }
1171 : }
1172 : else
1173 : {
1174 0 : rEmbGrfNm = *pLink;
1175 0 : if( bCfgCpyLinkedGrfs )
1176 : {
1177 0 : CopyLocalFileToINet( rEmbGrfNm );
1178 0 : pLink = &rEmbGrfNm;
1179 : }
1180 : }
1181 :
1182 0 : if( pLink )
1183 : {
1184 0 : String s( URIHelper::simpleNormalizedMakeRelative( GetBaseURL(), *pLink));
1185 0 : Strm() << " " OOO_STRING_SVTOOLS_HTML_O_background "=\"";
1186 0 : HTMLOutFuncs::Out_String( Strm(), s, eDestEnc, &aNonConvertableCharacters ) << '\"';
1187 : }
1188 : }
1189 :
1190 0 : void SwHTMLWriter::OutBackground( const SfxItemSet& rItemSet,
1191 : String& rEmbGrfNm, sal_Bool bGraphic )
1192 : {
1193 : const SfxPoolItem* pItem;
1194 0 : if( SFX_ITEM_SET == rItemSet.GetItemState( RES_BACKGROUND, sal_False,
1195 0 : &pItem ))
1196 : {
1197 0 : OutBackground( ((const SvxBrushItem*)pItem), rEmbGrfNm, bGraphic );
1198 : }
1199 0 : }
1200 :
1201 0 : sal_uInt16 SwHTMLWriter::GetLangWhichIdFromScript( sal_uInt16 nScript )
1202 : {
1203 : sal_uInt16 nWhichId;
1204 0 : switch( nScript )
1205 : {
1206 : case CSS1_OUTMODE_CJK:
1207 0 : nWhichId = RES_CHRATR_CJK_LANGUAGE;
1208 0 : break;
1209 : case CSS1_OUTMODE_CTL:
1210 0 : nWhichId = RES_CHRATR_CJK_LANGUAGE;
1211 0 : break;
1212 : default:
1213 0 : nWhichId = RES_CHRATR_LANGUAGE;
1214 0 : break;
1215 : }
1216 0 : return nWhichId;
1217 : }
1218 :
1219 0 : void SwHTMLWriter::OutLanguage( LanguageType nLang )
1220 : {
1221 0 : if( LANGUAGE_DONTKNOW != nLang )
1222 : {
1223 0 : rtl::OStringBuffer sOut;
1224 0 : sOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_lang)
1225 0 : .append("=\"");
1226 0 : Strm() << sOut.makeStringAndClear().getStr();
1227 0 : HTMLOutFuncs::Out_String( Strm(), LanguageTag(nLang).getBcp47(),
1228 0 : eDestEnc, &aNonConvertableCharacters ) << '"';
1229 : }
1230 0 : }
1231 :
1232 0 : sal_uInt16 SwHTMLWriter::GetHTMLDirection( const SfxItemSet& rItemSet ) const
1233 : {
1234 : return GetHTMLDirection(
1235 0 : static_cast < const SvxFrameDirectionItem& >( rItemSet.Get( RES_FRAMEDIR ) )
1236 0 : .GetValue() );
1237 : }
1238 :
1239 0 : sal_uInt16 SwHTMLWriter::GetHTMLDirection( sal_uInt16 nDir ) const
1240 : {
1241 0 : switch( nDir )
1242 : {
1243 : case FRMDIR_VERT_TOP_LEFT:
1244 0 : nDir = FRMDIR_HORI_LEFT_TOP;
1245 0 : break;
1246 : case FRMDIR_VERT_TOP_RIGHT:
1247 0 : nDir = FRMDIR_HORI_RIGHT_TOP;
1248 0 : break;
1249 : case FRMDIR_ENVIRONMENT:
1250 0 : nDir = nDirection;
1251 : }
1252 :
1253 0 : return nDir;
1254 : }
1255 :
1256 0 : void SwHTMLWriter::OutDirection( sal_uInt16 nDir )
1257 : {
1258 0 : const sal_Char *pValue = 0;
1259 0 : switch( nDir )
1260 : {
1261 : case FRMDIR_HORI_LEFT_TOP:
1262 : case FRMDIR_VERT_TOP_LEFT:
1263 0 : pValue = "LTR";
1264 0 : break;
1265 : case FRMDIR_HORI_RIGHT_TOP:
1266 : case FRMDIR_VERT_TOP_RIGHT:
1267 0 : pValue = "RTL";
1268 0 : break;
1269 : }
1270 0 : if( pValue != 0 )
1271 : {
1272 0 : rtl::OStringBuffer sOut;
1273 0 : sOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_dir)
1274 0 : .append("=\"").append(pValue).append('\"');
1275 0 : Strm() << sOut.makeStringAndClear().getStr();
1276 : }
1277 0 : }
1278 :
1279 0 : rtl::OString SwHTMLWriter::GetIndentString(sal_uInt16 nIncLvl)
1280 : {
1281 0 : rtl::OString sRet;
1282 :
1283 : // etwas umstaendlich, aber wir haben nur einen Indent-String!
1284 0 : sal_uInt16 nLevel = nIndentLvl + nIncLvl;
1285 :
1286 0 : if( nLevel && nLevel <= MAX_INDENT_LEVEL)
1287 : {
1288 0 : sIndentTabs[nLevel] = 0;
1289 0 : sRet = sIndentTabs;
1290 0 : sIndentTabs[nLevel] = '\t';
1291 : }
1292 :
1293 0 : return sRet;
1294 : }
1295 :
1296 0 : void SwHTMLWriter::OutNewLine( sal_Bool bCheck )
1297 : {
1298 0 : if( !bCheck || (Strm().Tell()-nLastLFPos) > nIndentLvl )
1299 : {
1300 0 : Strm() << sNewLine;
1301 0 : nLastLFPos = Strm().Tell();
1302 : }
1303 :
1304 0 : if( nIndentLvl && nIndentLvl <= MAX_INDENT_LEVEL)
1305 : {
1306 0 : sIndentTabs[nIndentLvl] = 0;
1307 0 : Strm() << sIndentTabs;
1308 0 : sIndentTabs[nIndentLvl] = '\t';
1309 : }
1310 0 : }
1311 :
1312 0 : sal_uInt16 SwHTMLWriter::GetHTMLFontSize( sal_uInt32 nHeight ) const
1313 : {
1314 0 : sal_uInt16 nSize = 1;
1315 0 : for( sal_uInt16 i=6; i>0; i-- )
1316 : {
1317 0 : if( nHeight > (aFontHeights[i] + aFontHeights[i-1])/2 )
1318 : {
1319 0 : nSize = i+1;
1320 0 : break;
1321 : }
1322 : }
1323 :
1324 0 : return nSize;
1325 : }
1326 :
1327 : // Struktur speichert die aktuellen Daten des Writers zwischen, um
1328 : // einen anderen Dokument-Teil auszugeben, wie z.B. Header/Footer
1329 0 : HTMLSaveData::HTMLSaveData( SwHTMLWriter& rWriter, sal_uLong nStt,
1330 : sal_uLong nEnd, sal_Bool bSaveNum,
1331 : const SwFrmFmt *pFrmFmt ) :
1332 : rWrt( rWriter ),
1333 : pOldPam( rWrt.pCurPam ),
1334 0 : pOldEnd( rWrt.GetEndPaM() ),
1335 : pOldNumRuleInfo( 0 ),
1336 : pOldNextNumRuleInfo( 0 ),
1337 : nOldDefListLvl( rWrt.nDefListLvl ),
1338 : nOldDirection( rWrt.nDirection ),
1339 : bOldOutHeader( rWrt.bOutHeader ),
1340 : bOldOutFooter( rWrt.bOutFooter ),
1341 0 : bOldOutFlyFrame( rWrt.bOutFlyFrame )
1342 : {
1343 0 : bOldWriteAll = rWrt.bWriteAll;
1344 :
1345 0 : rWrt.pCurPam = rWrt.NewSwPaM( *rWrt.pDoc, nStt, nEnd );
1346 :
1347 : // Tabelle in Sonderbereichen erkennen
1348 0 : if( nStt != rWrt.pCurPam->GetMark()->nNode.GetIndex() )
1349 : {
1350 0 : const SwNode *pNd = rWrt.pDoc->GetNodes()[ nStt ];
1351 0 : if( pNd->IsTableNode() || pNd->IsSectionNode() )
1352 0 : rWrt.pCurPam->GetMark()->nNode = nStt;
1353 : }
1354 :
1355 0 : rWrt.SetEndPaM( rWrt.pCurPam );
1356 0 : rWrt.pCurPam->Exchange( );
1357 0 : rWrt.bWriteAll = sal_True;
1358 0 : rWrt.nDefListLvl = 0;
1359 0 : rWrt.bOutHeader = rWrt.bOutFooter = sal_False;
1360 :
1361 : // Ggf. die aktuelle Numerierungs-Info merken, damit sie wieder
1362 : // neu aufgenommen werden kann. Nur dann belibt auch die Numerierungs-
1363 : // Info des nachsten Absatz gueltig.
1364 0 : if( bSaveNum )
1365 : {
1366 0 : pOldNumRuleInfo = new SwHTMLNumRuleInfo( rWrt.GetNumInfo() );
1367 0 : pOldNextNumRuleInfo = rWrt.GetNextNumInfo();
1368 0 : rWrt.SetNextNumInfo( 0 );
1369 : }
1370 : else
1371 : {
1372 0 : rWrt.ClearNextNumInfo();
1373 : }
1374 :
1375 : // Die Numerierung wird in jedem Fall unterbrochen.
1376 0 : rWrt.GetNumInfo().Clear();
1377 :
1378 0 : if( pFrmFmt )
1379 0 : rWrt.nDirection = rWrt.GetHTMLDirection( pFrmFmt->GetAttrSet() );
1380 0 : }
1381 :
1382 :
1383 0 : HTMLSaveData::~HTMLSaveData()
1384 : {
1385 0 : delete rWrt.pCurPam; // Pam wieder loeschen
1386 :
1387 0 : rWrt.pCurPam = pOldPam;
1388 0 : rWrt.SetEndPaM( pOldEnd );
1389 0 : rWrt.bWriteAll = bOldWriteAll;
1390 0 : rWrt.nBkmkTabPos = bOldWriteAll ? rWrt.FindPos_Bkmk( *pOldPam->GetPoint() ) : -1;
1391 0 : rWrt.nLastParaToken = 0;
1392 0 : rWrt.nDefListLvl = nOldDefListLvl;
1393 0 : rWrt.nDirection = nOldDirection;
1394 0 : rWrt.bOutHeader = bOldOutHeader;
1395 0 : rWrt.bOutFooter = bOldOutFooter;
1396 0 : rWrt.bOutFlyFrame = bOldOutFlyFrame;
1397 :
1398 : // Ggf. die Numerierung von vor der Section fortsetzen. Die Numerierung
1399 : // des naecshten Absatz wird in jedem Fall ungueltig.
1400 0 : if( pOldNumRuleInfo )
1401 : {
1402 0 : rWrt.GetNumInfo().Set( *pOldNumRuleInfo );
1403 0 : delete pOldNumRuleInfo;
1404 0 : rWrt.SetNextNumInfo( pOldNextNumRuleInfo );
1405 : }
1406 : else
1407 : {
1408 0 : rWrt.GetNumInfo().Clear();
1409 0 : rWrt.ClearNextNumInfo();
1410 : }
1411 0 : }
1412 :
1413 :
1414 0 : void GetHTMLWriter( const String&, const String& rBaseURL, WriterRef& xRet )
1415 : {
1416 0 : xRet = new SwHTMLWriter( rBaseURL );
1417 0 : }
1418 :
1419 :
1420 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|