xref: /trunk/main/sw/source/filter/html/htmlsect.cxx (revision 870262e3)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 
27 #include <rtl/uri.hxx>
28 
29 #include <svl/urihelper.hxx>
30 #include <vcl/svapp.hxx>
31 #include <vcl/wrkwin.hxx>
32 #include <editeng/adjitem.hxx>
33 #include <editeng/ulspitem.hxx>
34 #include <editeng/brkitem.hxx>
35 #include <svtools/htmltokn.h>
36 #include <svtools/htmlkywd.hxx>
37 #include <sfx2/linkmgr.hxx>
38 
39 #include "hintids.hxx"
40 #include <fmtornt.hxx>
41 #include <fmthdft.hxx>
42 #include <fmtcntnt.hxx>
43 #include <fmtfsize.hxx>
44 #include <fmtclds.hxx>
45 #include <fmtanchr.hxx>
46 #include <fmtpdsc.hxx>
47 #include <fmtsrnd.hxx>
48 #include <fmtflcnt.hxx>
49 #include "frmatr.hxx"
50 #include "doc.hxx"
51 #include "pam.hxx"
52 #include "ndtxt.hxx"
53 #include "shellio.hxx"
54 #include "section.hxx"
55 #include "poolfmt.hxx"
56 #include "pagedesc.hxx"
57 #include "swtable.hxx"
58 #include "viewsh.hxx"
59 #include "swcss1.hxx"
60 #include "swhtml.hxx"
61 
62 #define CONTEXT_FLAGS_MULTICOL (HTML_CNTXT_STRIP_PARA |  \
63 								HTML_CNTXT_KEEP_NUMRULE | \
64 								HTML_CNTXT_KEEP_ATTRS)
65 //#define CONTEXT_FLAGS_HDRFTR (HTML_CNTXT_STRIP_PARA|HTML_CNTXT_PROTECT_STACK)
66 #define CONTEXT_FLAGS_HDRFTR (CONTEXT_FLAGS_MULTICOL)
67 #define CONTEXT_FLAGS_FTN (CONTEXT_FLAGS_MULTICOL)
68 
69 
70 using namespace ::com::sun::star;
71 
72 
73 /*  */
74 
NewDivision(int nToken)75 void SwHTMLParser::NewDivision( int nToken )
76 {
77 	String aId, aHRef, aStyle, aClass, aLang, aDir;
78 	SvxAdjust eAdjust = HTML_CENTER_ON==nToken ? SVX_ADJUST_CENTER
79 											   : SVX_ADJUST_END;
80 
81 	sal_Bool bHeader=sal_False, bFooter=sal_False;
82 	const HTMLOptions *pHTMLOptions = GetOptions();
83 	for( sal_uInt16 i = pHTMLOptions->Count(); i; )
84 	{
85 		const HTMLOption *pOption = (*pHTMLOptions)[--i];
86 		switch( pOption->GetToken() )
87 		{
88 		case HTML_O_ID:
89 			aId = pOption->GetString();
90 			break;
91 		case HTML_O_ALIGN:
92 			if( HTML_DIVISION_ON==nToken )
93 				eAdjust = (SvxAdjust)pOption->GetEnum( aHTMLPAlignTable,
94                                                        static_cast< sal_uInt16 >(eAdjust) );
95 			break;
96 		case HTML_O_STYLE:
97 			aStyle = pOption->GetString();
98 			break;
99 		case HTML_O_CLASS:
100 			aClass = pOption->GetString();
101 			break;
102 		case HTML_O_LANG:
103 			aLang = pOption->GetString();
104 			break;
105 		case HTML_O_DIR:
106 			aDir = pOption->GetString();
107 			break;
108 		case HTML_O_HREF:
109 			aHRef =  pOption->GetString();
110 			break;
111 		case HTML_O_TYPE:
112 			{
113 				const String& rType = pOption->GetString();
114 				if( rType.EqualsIgnoreCaseAscii( "HEADER" ) )
115 					bHeader = sal_True;
116 				else if( rType.EqualsIgnoreCaseAscii( "FOOTER" ) )
117 					bFooter = sal_True;
118 			}
119 		}
120 	}
121 
122 	sal_Bool bAppended = sal_False;
123 	if( pPam->GetPoint()->nContent.GetIndex() )
124 	{
125 		AppendTxtNode( bHeader||bFooter||aId.Len()||aHRef.Len() ? AM_NORMAL
126 																: AM_NOSPACE );
127 		bAppended = sal_True;
128 	}
129 
130     _HTMLAttrContext *pCntxt = new _HTMLAttrContext( static_cast< sal_uInt16 >(nToken) );
131 
132 	sal_Bool bStyleParsed = sal_False, bPositioned = sal_False;
133 	SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() );
134 	SvxCSS1PropertyInfo aPropInfo;
135 	if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) )
136 	{
137 		bStyleParsed = ParseStyleOptions( aStyle, aId, aClass,
138 										  aItemSet, aPropInfo, &aLang, &aDir );
139 		if( bStyleParsed )
140 		{
141 			bPositioned = HTML_DIVISION_ON == nToken && aClass.Len() &&
142 						  CreateContainer( aClass, aItemSet, aPropInfo,
143 										   pCntxt );
144 			if( !bPositioned )
145 				bPositioned = DoPositioning( aItemSet, aPropInfo, pCntxt );
146 		}
147 	}
148 
149 	if( !bPositioned && (bHeader || bFooter) && IsNewDoc() )
150 	{
151 		SwPageDesc *pPageDesc =	pCSS1Parser->GetMasterPageDesc();
152 		SwFrmFmt& rPageFmt = pPageDesc->GetMaster();
153 
154 		SwFrmFmt *pHdFtFmt;
155 		sal_Bool bNew = sal_False;
156 		sal_uInt16 nFlags = CONTEXT_FLAGS_HDRFTR;
157 		if( bHeader )
158 		{
159 			pHdFtFmt = (SwFrmFmt*)rPageFmt.GetHeader().GetHeaderFmt();
160 			if( !pHdFtFmt )
161 			{
162 				// noch keine Header, dann erzeuge einen.
163                 rPageFmt.SetFmtAttr( SwFmtHeader( sal_True ));
164 				pHdFtFmt = (SwFrmFmt*)rPageFmt.GetHeader().GetHeaderFmt();
165 				bNew = sal_True;
166 			}
167 			nFlags |= HTML_CNTXT_HEADER_DIST;
168 		}
169 		else
170 		{
171 			pHdFtFmt = (SwFrmFmt*)rPageFmt.GetFooter().GetFooterFmt();
172 			if( !pHdFtFmt )
173 			{
174 				// noch keine Footer, dann erzeuge einen.
175                 rPageFmt.SetFmtAttr( SwFmtFooter( sal_True ));
176 				pHdFtFmt = (SwFrmFmt*)rPageFmt.GetFooter().GetFooterFmt();
177 				bNew = sal_True;
178 			}
179 			nFlags |= HTML_CNTXT_FOOTER_DIST;
180 		}
181 
182 		const SwFmtCntnt& rFlyCntnt = pHdFtFmt->GetCntnt();
183 		const SwNodeIndex& rCntntStIdx = *rFlyCntnt.GetCntntIdx();
184 		SwCntntNode *pCNd;
185 
186 		if( bNew )
187 		{
188 			pCNd = pDoc->GetNodes()[rCntntStIdx.GetIndex()+1]
189 					   ->GetCntntNode();
190 		}
191 		else
192 		{
193 			// Einen neuen Node zu Beginn der Section anlegen
194 			SwNodeIndex aSttIdx( rCntntStIdx, 1 );
195 			pCNd = pDoc->GetNodes().MakeTxtNode( aSttIdx,
196 							pCSS1Parser->GetTxtCollFromPool(RES_POOLCOLL_TEXT));
197 
198 			// Den bisherigen Inhalt der Section loeschen
199 			SwPaM aDelPam( aSttIdx );
200 			aDelPam.SetMark();
201 
202 			const SwStartNode *pStNd =
203                 (const SwStartNode *) &rCntntStIdx.GetNode();
204 			aDelPam.GetPoint()->nNode = pStNd->EndOfSectionIndex() - 1;
205 
206 			pDoc->DelFullPara( aDelPam );
207 
208 			// Die Seitenvorlage aktualisieren
209 			for( sal_uInt16 i=0; i < pDoc->GetPageDescCnt(); i++ )
210 			{
211 				if( RES_POOLPAGE_HTML==const_cast<const SwDoc *>(pDoc)
212                     ->GetPageDesc(i).GetPoolFmtId() )
213 				{
214 					pDoc->ChgPageDesc( i, *pPageDesc );
215 					break;
216 				}
217 			}
218 		}
219 
220 		SwPosition aNewPos( SwNodeIndex( rCntntStIdx, 1 ), SwIndex( pCNd, 0 ) );
221 		SaveDocContext( pCntxt, nFlags, &aNewPos );
222 	}
223 	else if( !bPositioned && aId.Len() > 9 &&
224 			 ('s' == aId.GetChar(0) || 'S' == aId.GetChar(0) ) &&
225 			 ('d' == aId.GetChar(1) || 'D' == aId.GetChar(1) ) )
226 	{
227 		sal_Bool bEndNote = sal_False, bFootNote = sal_False;
228 		if( aId.CompareIgnoreCaseToAscii( OOO_STRING_SVTOOLS_HTML_sdendnote, 9 ) == COMPARE_EQUAL )
229 			bEndNote = sal_True;
230 		else if( aId.CompareIgnoreCaseToAscii( OOO_STRING_SVTOOLS_HTML_sdfootnote, 10 ) == COMPARE_EQUAL )
231 			bFootNote = sal_True;
232 		if( bFootNote || bEndNote )
233 		{
234 			SwNodeIndex *pStartNdIdx = GetFootEndNoteSection( aId );
235 			if( pStartNdIdx )
236 			{
237 				SwCntntNode *pCNd =
238 					pDoc->GetNodes()[pStartNdIdx->GetIndex()+1]->GetCntntNode();
239 				SwNodeIndex aTmpSwNodeIndex = SwNodeIndex(*pCNd);
240 				SwPosition aNewPos( aTmpSwNodeIndex, SwIndex( pCNd, 0 ) );
241 				SaveDocContext( pCntxt, CONTEXT_FLAGS_FTN, &aNewPos );
242 				aId = aPropInfo.aId = aEmptyStr;
243 			}
244 		}
245 	}
246 
247 	// Bereiche fuegen wir in Rahmen nur dann ein, wenn der Bereich gelinkt ist.
248 	if( (aId.Len() && !bPositioned) || aHRef.Len()  )
249 	{
250 		// Bereich einfuegen (muss vor dem Setzten von Attributen erfolgen,
251 		// weil die Section vor der PaM-Position eingefuegt.
252 
253 		// wenn wir im ersten Node einer Section stehen, wir die neue
254 		// Section nicht in der aktuellen, sondern vor der aktuellen
255 		// Section eingefuegt. Deshalb muessen wir dann einen Node
256 		// einfuegen. UND IN LOESCHEN!!!
257 		if( !bAppended )
258 		{
259 			SwNodeIndex aPrvNdIdx( pPam->GetPoint()->nNode, -1 );
260             if (aPrvNdIdx.GetNode().IsSectionNode())
261 			{
262 				AppendTxtNode();
263 				bAppended = sal_True;
264 			}
265 		}
266 		_HTMLAttrs *pPostIts = bAppended ? 0 : new _HTMLAttrs;
267 		SetAttr( sal_True, sal_True, pPostIts );
268 
269 		// Namen der Section eindeutig machen
270 		String aName( pDoc->GetUniqueSectionName( aId.Len() ? &aId : 0 ) );
271 
272 		if( aHRef.Len() )
273 		{
274 			sal_Unicode cDelim = 255U;
275 			String aURL;
276 			xub_StrLen nPos = aHRef.SearchBackward( cDelim );
277 			xub_StrLen nPos2 = STRING_NOTFOUND;
278 			if( STRING_NOTFOUND != nPos )
279 			{
280 				nPos2 = aHRef.SearchBackward( cDelim, nPos );
281 				if( STRING_NOTFOUND != nPos2 )
282 				{
283 					xub_StrLen nTmp = nPos;
284 					nPos = nPos2;
285 					nPos2 = nTmp;
286 				}
287 			}
288 			if( STRING_NOTFOUND == nPos )
289 			{
290                 aURL = URIHelper::SmartRel2Abs(INetURLObject( sBaseURL ), aHRef, Link(), false);
291 			}
292 			else
293 			{
294                 aURL = URIHelper::SmartRel2Abs(INetURLObject( sBaseURL ), aHRef.Copy( 0, nPos ), Link(), false );
295                 aURL += sfx2::cTokenSeperator;
296                 if( STRING_NOTFOUND == nPos2 )
297 				{
298 					aURL += aHRef.Copy( nPos+1 );
299 				}
300 				else
301 				{
302 					aURL += aHRef.Copy( nPos+1, nPos2 - (nPos+1) );
303                     aURL += sfx2::cTokenSeperator;
304 					aURL += String(rtl::Uri::decode( aHRef.Copy( nPos2+1 ),
305 											  rtl_UriDecodeWithCharset,
306 											  RTL_TEXTENCODING_ISO_8859_1 ));
307 				}
308 			}
309 			aHRef = aURL;
310 		}
311 
312         SwSectionData aSection( (aHRef.Len()) ? FILE_LINK_SECTION
313 										: CONTENT_SECTION, aName );
314 		if( aHRef.Len() )
315 		{
316 			aSection.SetLinkFileName( aHRef );
317             aSection.SetProtectFlag(true);
318         }
319 
320 		SfxItemSet aFrmItemSet( pDoc->GetAttrPool(),
321 								RES_FRMATR_BEGIN, RES_FRMATR_END-1 );
322 		if( !IsNewDoc() )
323 			Reader::ResetFrmFmtAttrs(aFrmItemSet );
324 
325 		const SfxPoolItem *pItem;
326 		if( SFX_ITEM_SET == aItemSet.GetItemState( RES_BACKGROUND, sal_False,
327 												   &pItem ) )
328 		{
329 			aFrmItemSet.Put( *pItem );
330 			aItemSet.ClearItem( RES_BACKGROUND );
331 		}
332 		if( SFX_ITEM_SET == aItemSet.GetItemState( RES_FRAMEDIR, sal_False,
333 												   &pItem ) )
334 		{
335 			aFrmItemSet.Put( *pItem );
336 			aItemSet.ClearItem( RES_FRAMEDIR );
337 		}
338 
339         pDoc->InsertSwSection( *pPam, aSection, 0, &aFrmItemSet, false );
340 
341 		// ggfs. einen Bereich anspringen
342 		if( JUMPTO_REGION == eJumpTo && aName == sJmpMark )
343 		{
344 			bChkJumpMark = sal_True;
345 			eJumpTo = JUMPTO_NONE;
346 		}
347 
348 		SwTxtNode* pOldTxtNd =
349             (bAppended) ? 0 : pPam->GetPoint()->nNode.GetNode().GetTxtNode();
350 
351 		pPam->Move( fnMoveBackward );
352 
353 		// PageDesc- und SwFmtBreak Attribute vom aktuellen Node in den
354 		// (ersten) Node des Bereich verschieben.
355 		if( pOldTxtNd )
356 			MovePageDescAttrs( pOldTxtNd, pPam->GetPoint()->nNode.GetIndex(),
357 							   sal_True	 );
358 
359 		if( pPostIts )
360 		{
361 			// noch vorhandene PostIts in den ersten Absatz
362 			// der Tabelle setzen
363 			InsertAttrs( *pPostIts );
364 			delete pPostIts;
365 			pPostIts = 0;
366 		}
367 
368 		pCntxt->SetSpansSection( sal_True );
369 
370         // keine text::Bookmarks mit dem gleichen Namen wie Bereiche einfuegen
371 		if( aPropInfo.aId.Len() && aPropInfo.aId==aName )
372 			aPropInfo.aId.Erase();
373 	}
374 	else
375 	{
376 		pCntxt->SetAppendMode( AM_NOSPACE );
377 	}
378 
379 	if( SVX_ADJUST_END != eAdjust )
380 	{
381         InsertAttr( &aAttrTab.pAdjust, SvxAdjustItem(eAdjust, RES_PARATR_ADJUST), pCntxt );
382 	}
383 
384 	// Style parsen
385 	if( bStyleParsed )
386 		InsertAttrs( aItemSet, aPropInfo, pCntxt, sal_True );
387 
388 	PushContext( pCntxt );
389 }
390 
EndDivision(int)391 void SwHTMLParser::EndDivision( int /*nToken*/ )
392 {
393 	// Stack-Eintrag zu dem Token suchen (weil wir noch den Div-Stack
394 	// haben unterscheiden wir erst einmal nicht zwischen DIV und CENTER
395 	_HTMLAttrContext *pCntxt = 0;
396 	sal_uInt16 nPos = aContexts.Count();
397 	while( !pCntxt && nPos>nContextStMin )
398 	{
399 		switch( aContexts[--nPos]->GetToken() )
400 		{
401 		case HTML_CENTER_ON:
402 		case HTML_DIVISION_ON:
403 			pCntxt = aContexts[nPos];
404 			aContexts.Remove( nPos, 1 );
405 			break;
406 		}
407 	}
408 
409 	if( pCntxt )
410 	{
411 		// Attribute beenden
412 		EndContext( pCntxt );
413 		SetAttr();	// Absatz-Atts wegen JavaScript moeglichst schnell setzen
414 
415 		delete pCntxt;
416 	}
417 }
418 
FixHeaderFooterDistance(sal_Bool bHeader,const SwPosition * pOldPos)419 void SwHTMLParser::FixHeaderFooterDistance( sal_Bool bHeader,
420 											const SwPosition *pOldPos )
421 {
422 	SwPageDesc *pPageDesc =	pCSS1Parser->GetMasterPageDesc();
423 	SwFrmFmt& rPageFmt = pPageDesc->GetMaster();
424 
425 	SwFrmFmt *pHdFtFmt =
426 		bHeader ? (SwFrmFmt*)rPageFmt.GetHeader().GetHeaderFmt()
427 				: (SwFrmFmt*)rPageFmt.GetFooter().GetFooterFmt();
428 	ASSERT( pHdFtFmt, "Doch keine Kopf- oder Fusszeile" );
429 
430 	const SwFmtCntnt& rFlyCntnt = pHdFtFmt->GetCntnt();
431 	const SwNodeIndex& rCntntStIdx = *rFlyCntnt.GetCntntIdx();
432 
433 	sal_uLong nPrvNxtIdx;
434 	if( bHeader )
435     {
436         nPrvNxtIdx = rCntntStIdx.GetNode().EndOfSectionIndex()-1;
437     }
438 	else
439 	{
440 		nPrvNxtIdx = pOldPos->nNode.GetIndex() - 1;
441 	}
442 
443 	sal_uInt16 nSpace = 0;
444 	SwTxtNode *pTxtNode = pDoc->GetNodes()[nPrvNxtIdx]->GetTxtNode();
445 	if( pTxtNode )
446 	{
447 		const SvxULSpaceItem& rULSpace =
448 			((const SvxULSpaceItem&)pTxtNode
449 				->SwCntntNode::GetAttr( RES_UL_SPACE ));
450 
451 		// Der untere Absatz-Abstand wird zum Abstand zur
452 		// Kopf- oder Fusszeile
453 		nSpace = rULSpace.GetLower();
454 
455 		// und anschliessend auf einen vernuenftigen Wert
456 		// gesetzt
457 		const SvxULSpaceItem& rCollULSpace =
458 			pTxtNode->GetAnyFmtColl().GetULSpace();
459 		if( rCollULSpace.GetUpper() == rULSpace.GetUpper() )
460 			pTxtNode->ResetAttr( RES_UL_SPACE );
461 		else
462             pTxtNode->SetAttr(
463 				SvxULSpaceItem( rULSpace.GetUpper(),
464                                 rCollULSpace.GetLower(), RES_UL_SPACE ) );
465 	}
466 
467 	if( bHeader )
468 	{
469 		nPrvNxtIdx = pOldPos->nNode.GetIndex();
470 	}
471 	else
472 	{
473 		nPrvNxtIdx = rCntntStIdx.GetIndex() + 1;
474 	}
475 
476 	pTxtNode = pDoc->GetNodes()[nPrvNxtIdx]
477 					->GetTxtNode();
478 	if( pTxtNode )
479 	{
480 		const SvxULSpaceItem& rULSpace =
481 			((const SvxULSpaceItem&)pTxtNode
482 				->SwCntntNode::GetAttr( RES_UL_SPACE ));
483 
484 		// Der obere Absatz-Abstand wird zum Abstand zur
485 		// Kopf- oder Fusszeile, wenn er groesser ist als
486 		// der untere vom Absatz davor
487 		if( rULSpace.GetUpper() > nSpace )
488 			nSpace = rULSpace.GetUpper();
489 
490 		// und anschliessend auf einen vernuenftigen Wert gesetzt
491 		const SvxULSpaceItem& rCollULSpace =
492 			pTxtNode->GetAnyFmtColl().GetULSpace();
493 		if( rCollULSpace.GetLower() == rULSpace.GetLower() )
494 			pTxtNode->ResetAttr( RES_UL_SPACE );
495 		else
496             pTxtNode->SetAttr(
497 				SvxULSpaceItem( rCollULSpace.GetUpper(),
498                                 rULSpace.GetLower(), RES_UL_SPACE ) );
499 	}
500 
501     SvxULSpaceItem aULSpace( RES_UL_SPACE );
502 	if( bHeader )
503 		aULSpace.SetLower( nSpace );
504 	else
505 		aULSpace.SetUpper( nSpace );
506 
507     pHdFtFmt->SetFmtAttr( aULSpace );
508 }
509 
EndSection(sal_Bool bLFStripped)510 sal_Bool SwHTMLParser::EndSection( sal_Bool bLFStripped )
511 {
512 	SwEndNode *pEndNd = pDoc->GetNodes()[pPam->GetPoint()->nNode.GetIndex()+1]
513 							->GetEndNode();
514     if( pEndNd && pEndNd->StartOfSectionNode()->IsSectionNode() )
515 	{
516 		// den Bereich beenden
517 		if( !bLFStripped )
518 			StripTrailingPara();
519 		pPam->Move( fnMoveForward );
520 		return sal_True;
521 	}
522 
523 	ASSERT( sal_False, "Wrong PaM position ending a range" );
524 
525 	return sal_False;
526 }
527 
EndSections(sal_Bool bLFStripped)528 sal_Bool SwHTMLParser::EndSections( sal_Bool bLFStripped )
529 {
530 	sal_Bool bSectionClosed = sal_False;
531 	sal_uInt16 nPos = aContexts.Count();
532 	while( nPos>nContextStMin )
533 	{
534 		_HTMLAttrContext *pCntxt = aContexts[--nPos];
535 		if( pCntxt->GetSpansSection() && EndSection( bLFStripped ) )
536 		{
537 			bSectionClosed = sal_True;
538 			pCntxt->SetSpansSection( sal_False );
539 			bLFStripped = sal_False;
540 		}
541 	}
542 
543 	return bSectionClosed;
544 }
545 
546 /*  */
547 
NewMultiCol()548 void SwHTMLParser::NewMultiCol()
549 {
550 	String aId, aStyle, aClass, aLang, aDir;
551 	long nWidth = 100;
552 	sal_uInt16 nCols = 0, nGutter = 10;
553 	sal_Bool bPrcWidth = sal_True;
554 
555 	const HTMLOptions *pHTMLOptions = GetOptions();
556 	sal_uInt16 i;
557 
558 	for( i = pHTMLOptions->Count(); i; )
559 	{
560 		const HTMLOption *pOption = (*pHTMLOptions)[--i];
561 		switch( pOption->GetToken() )
562 		{
563 		case HTML_O_ID:
564 			aId = pOption->GetString();
565 			break;
566 		case HTML_O_STYLE:
567 			aStyle = pOption->GetString();
568 			break;
569 		case HTML_O_CLASS:
570 			aClass = pOption->GetString();
571 			break;
572 		case HTML_O_LANG:
573 			aLang = pOption->GetString();
574 			break;
575 		case HTML_O_DIR:
576 			aDir = pOption->GetString();
577 			break;
578 		case HTML_O_COLS:
579 			nCols = (sal_uInt16)pOption->GetNumber();
580 			break;
581 		case HTML_O_WIDTH:
582 			nWidth = pOption->GetNumber();
583 			bPrcWidth = (pOption->GetString().Search('%') != STRING_NOTFOUND);
584 			if( bPrcWidth && nWidth>100 )
585 				nWidth = 100;
586 			break;
587 		case HTML_O_GUTTER:
588 			nGutter = (sal_uInt16)pOption->GetNumber();
589 			break;
590 
591 		}
592 	}
593 
594 	_HTMLAttrContext *pCntxt = new _HTMLAttrContext( HTML_MULTICOL_ON );
595 
596 	//.is the multicol elememt contained in a container? That may be the
597 	// case for 5.0 documents.
598 	sal_Bool bInCntnr = sal_False;
599 	i = aContexts.Count();
600 	while( !bInCntnr && i > nContextStMin )
601 		bInCntnr = 0 != aContexts[--i]->GetFrmItemSet();
602 
603 	// Parse style sheets, but don't position anything by now.
604 	sal_Bool bStyleParsed = sal_False;
605 	SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() );
606 	SvxCSS1PropertyInfo aPropInfo;
607 	if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) )
608 		bStyleParsed = ParseStyleOptions( aStyle, aId, aClass,
609 										  aItemSet, aPropInfo, &aLang, &aDir );
610 
611 	// Calculate width.
612 	sal_uInt8 nPrcWidth = bPrcWidth ? (sal_uInt8)nWidth : 0;
613 	sal_uInt16 nTwipWidth = 0;
614 	if( !bPrcWidth && nWidth && Application::GetDefaultDevice() )
615 	{
616 		nTwipWidth = (sal_uInt16)Application::GetDefaultDevice()
617 							 ->PixelToLogic( Size(nWidth, 0),
618 											 MapMode(MAP_TWIP) ).Width();
619 	}
620 
621 	if( !nPrcWidth && nTwipWidth < MINFLY )
622 		nTwipWidth = MINFLY;
623 
624 	// Do positioning.
625 	sal_Bool bPositioned = sal_False;
626 	if( bInCntnr || pCSS1Parser->MayBePositioned( aPropInfo, sal_True ) )
627 	{
628 		SfxItemSet aFrmItemSet( pDoc->GetAttrPool(),
629 								RES_FRMATR_BEGIN, RES_FRMATR_END-1 );
630 		if( !IsNewDoc() )
631 			Reader::ResetFrmFmtAttrs(aFrmItemSet );
632 
633         SetAnchorAndAdjustment( text::VertOrientation::NONE, text::HoriOrientation::NONE, aItemSet, aPropInfo,
634 								aFrmItemSet );
635 
636 		// The width is either the WIDTH attribute's value or contained
637 		// in some style option.
638 		SetVarSize( aItemSet, aPropInfo, aFrmItemSet, nTwipWidth, nPrcWidth );
639 
640 		SetSpace( Size(0,0), aItemSet, aPropInfo, aFrmItemSet );
641 
642 		// Set some other frame attributes. If the background is set, its
643 		// it will be cleared here. That for, it won't be set at the section,
644 		// too.
645 		SetFrmFmtAttrs( aItemSet, aPropInfo,
646 						HTML_FF_BOX|HTML_FF_BACKGROUND|HTML_FF_PADDING|HTML_FF_DIRECTION,
647 						aFrmItemSet );
648 
649 		// Insert fly frame. If the are columns, the fly frame's name is not
650 		// the sections name but a generated one.
651 		String aFlyName( aEmptyStr );
652 		if( nCols < 2 )
653 		{
654 			aFlyName = aId;
655 			aPropInfo.aId.Erase();
656 		}
657 
658 		InsertFlyFrame( aFrmItemSet, pCntxt, aFlyName, CONTEXT_FLAGS_ABSPOS );
659 
660 		pCntxt->SetPopStack( sal_True );
661 		bPositioned = sal_True;
662 	}
663 
664 	sal_Bool bAppended = sal_False;
665 	if( !bPositioned )
666 	{
667 		if( pPam->GetPoint()->nContent.GetIndex() )
668 		{
669 			AppendTxtNode( AM_SPACE );
670 			bAppended = sal_True;
671 		}
672 		else
673 		{
674 			AddParSpace();
675 		}
676 	}
677 
678 	// If there are less then 2 columns, no section is inserted.
679 	if( nCols >= 2 )
680 	{
681 		if( !bAppended )
682 		{
683 			// If the pam is at the start of a section, a additional text
684 			// node must be inserted. Otherwise, the new section will be
685 			// inserted in front of the old one.
686 			SwNodeIndex aPrvNdIdx( pPam->GetPoint()->nNode, -1 );
687             if (aPrvNdIdx.GetNode().IsSectionNode())
688             {
689 				AppendTxtNode();
690 				bAppended = sal_True;
691 			}
692 		}
693 		_HTMLAttrs *pPostIts = bAppended ? 0 : new _HTMLAttrs;
694 		SetAttr( sal_True, sal_True, pPostIts );
695 
696 		// Make section name unique.
697 		String aName( pDoc->GetUniqueSectionName( aId.Len() ? &aId : 0 ) );
698         SwSectionData aSection( CONTENT_SECTION, aName );
699 
700 		SfxItemSet aFrmItemSet( pDoc->GetAttrPool(),
701 								RES_FRMATR_BEGIN, RES_FRMATR_END-1 );
702 		if( !IsNewDoc() )
703 			Reader::ResetFrmFmtAttrs(aFrmItemSet );
704 
705 		if( nGutter && Application::GetDefaultDevice() )
706 		{
707 			nGutter = (sal_uInt16)Application::GetDefaultDevice()
708 							 ->PixelToLogic( Size(nGutter, 0),
709 											 MapMode(MAP_TWIP) ).Width();
710 		}
711 
712 		SwFmtCol aFmtCol;
713 #ifndef WIDTH_SUPPORTED_BY_SECTIONS
714 		nPrcWidth = 100;
715 #endif
716 
717 		aFmtCol.Init( nCols, nGutter, nPrcWidth ? USHRT_MAX : nTwipWidth );
718 		aFrmItemSet.Put( aFmtCol );
719 
720 		const SfxPoolItem *pItem;
721 		if( SFX_ITEM_SET == aItemSet.GetItemState( RES_BACKGROUND, sal_False,
722 												   &pItem ) )
723 		{
724 			aFrmItemSet.Put( *pItem );
725 			aItemSet.ClearItem( RES_BACKGROUND );
726 		}
727 		if( SFX_ITEM_SET == aItemSet.GetItemState( RES_FRAMEDIR, sal_False,
728 												   &pItem ) )
729 		{
730 			aFrmItemSet.Put( *pItem );
731 			aItemSet.ClearItem( RES_FRAMEDIR );
732 		}
733         pDoc->InsertSwSection( *pPam, aSection, 0, &aFrmItemSet, false );
734 
735 		// Jump to section, if this is requested.
736 		if( JUMPTO_REGION == eJumpTo && aName == sJmpMark )
737 		{
738 			bChkJumpMark = sal_True;
739 			eJumpTo = JUMPTO_NONE;
740 		}
741 
742 		SwTxtNode* pOldTxtNd =
743             (bAppended) ? 0 : pPam->GetPoint()->nNode.GetNode().GetTxtNode();
744 
745 		pPam->Move( fnMoveBackward );
746 
747 		// Move PageDesc and SwFmtBreak attributes of the current node
748 		// to the section's first node.
749 		if( pOldTxtNd )
750 			MovePageDescAttrs( pOldTxtNd, pPam->GetPoint()->nNode.GetIndex(),
751 							   sal_True	 );
752 
753 		if( pPostIts )
754 		{
755 			// Move pending PostIts into the section.
756 			InsertAttrs( *pPostIts );
757 			delete pPostIts;
758 			pPostIts = 0;
759 		}
760 
761 		pCntxt->SetSpansSection( sal_True );
762 
763 		// Insert a bookmark if its name differs from the section's name only.
764 		if( aPropInfo.aId.Len() && aPropInfo.aId==aName )
765 			aPropInfo.aId.Erase();
766 	}
767 
768 	// Additional attributes must be set as hard ones.
769 	if( bStyleParsed )
770 		InsertAttrs( aItemSet, aPropInfo, pCntxt, sal_True );
771 
772 	PushContext( pCntxt );
773 }
774 
775 /*  */
776 
InsertFlyFrame(const SfxItemSet & rItemSet,_HTMLAttrContext * pCntxt,const String & rName,sal_uInt16 nFlags)777 void SwHTMLParser::InsertFlyFrame( const SfxItemSet& rItemSet,
778 								   _HTMLAttrContext *pCntxt,
779 								   const String& rName,
780 								   sal_uInt16 nFlags )
781 {
782 	RndStdIds eAnchorId =
783 		((const SwFmtAnchor&)rItemSet.Get( RES_ANCHOR )).GetAnchorId();
784 
785 	// Den Rahmen anlegen
786 	SwFlyFrmFmt* pFlyFmt = pDoc->MakeFlySection( eAnchorId, pPam->GetPoint(),
787 													&rItemSet );
788 	// Ggf. den Namen setzen
789 	if( rName.Len() )
790 		pFlyFmt->SetName( rName );
791 
792 	RegisterFlyFrm( pFlyFmt );
793 
794 	const SwFmtCntnt& rFlyCntnt = pFlyFmt->GetCntnt();
795 	const SwNodeIndex& rFlyCntIdx = *rFlyCntnt.GetCntntIdx();
796 	SwCntntNode *pCNd = pDoc->GetNodes()[rFlyCntIdx.GetIndex()+1]
797 							->GetCntntNode();
798 
799 	SwPosition aNewPos( SwNodeIndex( rFlyCntIdx, 1 ), SwIndex( pCNd, 0 ) );
800 	SaveDocContext( pCntxt, nFlags, &aNewPos );
801 }
802 
803 
804 /*  */
805 
MovePageDescAttrs(SwNode * pSrcNd,sal_uLong nDestIdx,sal_Bool bFmtBreak)806 void SwHTMLParser::MovePageDescAttrs( SwNode *pSrcNd,
807 									  sal_uLong nDestIdx,
808 									  sal_Bool bFmtBreak )
809 {
810 	SwCntntNode* pDestCntntNd =
811 		pDoc->GetNodes()[nDestIdx]->GetCntntNode();
812 
813 	ASSERT( pDestCntntNd, "Wieso ist das Ziel kein Content-Node?" );
814 
815 	if( pSrcNd->IsCntntNode() )
816 	{
817 		SwCntntNode* pSrcCntntNd = pSrcNd->GetCntntNode();
818 
819 		const SfxPoolItem* pItem;
820 		if( SFX_ITEM_SET ==	pSrcCntntNd->GetSwAttrSet()
821 				.GetItemState( RES_PAGEDESC, sal_False, &pItem ) &&
822 			((SwFmtPageDesc *)pItem)->GetPageDesc() )
823 		{
824 			pDestCntntNd->SetAttr( *pItem );
825 			pSrcCntntNd->ResetAttr( RES_PAGEDESC );
826 		}
827 		if( SFX_ITEM_SET ==	pSrcCntntNd->GetSwAttrSet()
828 				.GetItemState( RES_BREAK, sal_False, &pItem ) )
829 		{
830 			switch( ((SvxFmtBreakItem *)pItem)->GetBreak() )
831 			{
832 			case SVX_BREAK_PAGE_BEFORE:
833 			case SVX_BREAK_PAGE_AFTER:
834 			case SVX_BREAK_PAGE_BOTH:
835 				if( bFmtBreak )
836 					pDestCntntNd->SetAttr( *pItem );
837 				pSrcCntntNd->ResetAttr( RES_BREAK );
838 			default:
839 				;
840 			}
841 		}
842 	}
843 	else if( pSrcNd->IsTableNode() )
844 	{
845 		SwFrmFmt *pFrmFmt = pSrcNd->GetTableNode()->GetTable().GetFrmFmt();
846 
847 		const SfxPoolItem* pItem;
848 		if( SFX_ITEM_SET ==	pFrmFmt->GetAttrSet().
849 				GetItemState( RES_PAGEDESC, sal_False, &pItem ) )
850 		{
851 			pDestCntntNd->SetAttr( *pItem );
852             pFrmFmt->ResetFmtAttr( RES_PAGEDESC );
853 		}
854 	}
855 }
856 
857