xref: /trunk/main/sw/source/filter/html/htmlnum.cxx (revision efeef26f)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 
27 
28 #include <com/sun/star/style/NumberingType.hpp>
29 #include <hintids.hxx>
30 #include <svtools/htmltokn.h>
31 #include <svtools/htmlkywd.hxx>
32 #include <svtools/htmlout.hxx>
33 #include <svl/urihelper.hxx>
34 #include <editeng/brshitem.hxx>
35 #include <editeng/lrspitem.hxx>
36 #include <vcl/svapp.hxx>
37 #include <vcl/wrkwin.hxx>
38 #include <numrule.hxx>
39 #include <doc.hxx>
40 #include <docary.hxx>
41 #include <poolfmt.hxx>
42 #include <ndtxt.hxx>
43 #include <paratr.hxx>
44 
45 #include "htmlnum.hxx"
46 #include "swcss1.hxx"
47 #include "swhtml.hxx"
48 #include "wrthtml.hxx"
49 
50 #include <SwNodeNum.hxx>
51 
52 using namespace ::com::sun::star;
53 
54 // TODO: Unicode: Are these characters the correct ones?
55 #define HTML_BULLETCHAR_DISC	(0xe008)
56 #define HTML_BULLETCHAR_CIRCLE	(0xe009)
57 #define HTML_BULLETCHAR_SQUARE	(0xe00b)
58 
59 
60 // <UL TYPE=...>
61 static HTMLOptionEnum __FAR_DATA aHTMLULTypeTable[] =
62 {
63 	{ OOO_STRING_SVTOOLS_HTML_ULTYPE_disc,	HTML_BULLETCHAR_DISC		},
64 	{ OOO_STRING_SVTOOLS_HTML_ULTYPE_circle,	HTML_BULLETCHAR_CIRCLE		},
65 	{ OOO_STRING_SVTOOLS_HTML_ULTYPE_square,	HTML_BULLETCHAR_SQUARE		},
66 	{ 0,					0							}
67 };
68 
69 /*  */
70 
Set(const SwTxtNode & rTxtNd)71 void SwHTMLNumRuleInfo::Set( const SwTxtNode& rTxtNd )
72 {
73     // --> OD 2006-06-12 #b6435904#
74     // export all numberings, except the outline numbering.
75 //    if( rTxtNd.GetNumRule() && ! rTxtNd.IsOutline())
76     const SwNumRule* pTxtNdNumRule( rTxtNd.GetNumRule() );
77     if ( pTxtNdNumRule &&
78          pTxtNdNumRule != rTxtNd.GetDoc()->GetOutlineNumRule() )
79 	{
80         pNumRule = const_cast<SwNumRule*>(pTxtNdNumRule);
81         nDeep = static_cast< sal_uInt16 >(pNumRule ? rTxtNd.GetActualListLevel() + 1 : 0);
82         bNumbered = rTxtNd.IsCountedInList();
83         // --> OD 2008-02-27 #refactorlists#
84         // --> OD 2005-11-16 #i57919#
85         // correction of refactoring done by cws swnumtree:
86         // <bRestart> has to be set to <true>, if numbering is restarted at this
87         // text node and the start value equals <USHRT_MAX>.
88         // Start value <USHRT_MAX> indicates, that at this text node the numbering
89         // is restarted with the value given at the corresponding level.
90 //        bRestart = rTxtNd.IsListRestart() &&
91 //                   GetNum() && rTxtNd.GetNum()->GetStartValue() == USHRT_MAX;
92         bRestart = rTxtNd.IsListRestart() && !rTxtNd.HasAttrListRestartValue();
93         // <--
94 	}
95     // <--
96 	else
97 	{
98 		pNumRule = 0;
99 		nDeep = 0;
100 		bNumbered = bRestart = sal_False;
101 	}
102 }
103 
104 /*  */
105 
NewNumBulList(int nToken)106 void SwHTMLParser::NewNumBulList( int nToken )
107 {
108 	SwHTMLNumRuleInfo& rInfo = GetNumInfo();
109 
110 	// Erstmal einen neuen Absatz aufmachen
111 	sal_Bool bSpace = (rInfo.GetDepth() + nDefListDeep) == 0;
112 	if( pPam->GetPoint()->nContent.GetIndex() )
113 		AppendTxtNode( bSpace ? AM_SPACE : AM_NOSPACE, sal_False );
114 	else if( bSpace )
115 		AddParSpace();
116 
117 	// Die Numerierung-Ebene erhoehen
118 	rInfo.IncDepth();
119 	sal_uInt8 nLevel = (sal_uInt8)( (rInfo.GetDepth() <= MAXLEVEL ? rInfo.GetDepth()
120 														: MAXLEVEL) - 1 );
121 
122 	// ggf. ein Regelwerk anlegen
123 	if( !rInfo.GetNumRule() )
124 	{
125 		sal_uInt16 nPos = pDoc->MakeNumRule( pDoc->GetUniqueNumRuleName() );
126 		rInfo.SetNumRule( pDoc->GetNumRuleTbl()[nPos] );
127 	}
128 
129 	// das Format anpassen, falls es fuer den Level noch nicht
130 	// geschehen ist!
131 	sal_Bool bNewNumFmt = rInfo.GetNumRule()->GetNumFmt( nLevel ) == 0;
132 	sal_Bool bChangeNumFmt = sal_False;
133 
134 	// das default Numerierungsformat erstellen
135 	SwNumFmt aNumFmt( rInfo.GetNumRule()->Get(nLevel) );
136 	rInfo.SetNodeStartValue( nLevel );
137 	if( bNewNumFmt )
138 	{
139 		sal_uInt16 nChrFmtPoolId = 0;
140 		if( HTML_ORDERLIST_ON == nToken )
141 		{
142 			aNumFmt.SetNumberingType(SVX_NUM_ARABIC);
143 			nChrFmtPoolId = RES_POOLCHR_NUM_LEVEL;
144 		}
145 		else
146 		{
147 			// Wir setzen hier eine Zeichenvorlage, weil die UI das auch
148 			// so macht. Dadurch wurd immer auch eine 9pt-Schrift
149 			// eingestellt, was in Netscape nicht der Fall ist. Bisher hat
150 			// das noch niemanden gestoert.
151             // --> OD 2008-06-03 #i63395#
152             // Only apply user defined default bullet font
153             if ( numfunc::IsDefBulletFontUserDefined() )
154             {
155                 aNumFmt.SetBulletFont( &numfunc::GetDefBulletFont() );
156             }
157             // <--
158 			aNumFmt.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
159 			aNumFmt.SetBulletChar( cBulletChar );		// das Bulletzeichen !!
160 			nChrFmtPoolId = RES_POOLCHR_BUL_LEVEL;
161 		}
162 
163 		sal_uInt16 nAbsLSpace = HTML_NUMBUL_MARGINLEFT;
164 
165 		short nFirstLineIndent  = HTML_NUMBUL_INDENT;
166 		if( nLevel > 0 )
167 		{
168 			const SwNumFmt& rPrevNumFmt = rInfo.GetNumRule()->Get( nLevel-1 );
169             nAbsLSpace = nAbsLSpace + rPrevNumFmt.GetAbsLSpace();
170 			nFirstLineIndent = rPrevNumFmt.GetFirstLineOffset();
171 		}
172 		aNumFmt.SetAbsLSpace( nAbsLSpace );
173 		aNumFmt.SetFirstLineOffset( nFirstLineIndent );
174 		aNumFmt.SetCharFmt( pCSS1Parser->GetCharFmtFromPool(nChrFmtPoolId) );
175 
176 		bChangeNumFmt = sal_True;
177 	}
178 	else if( 1 != aNumFmt.GetStart() )
179 	{
180 		// Wenn die Ebene schon mal benutzt wurde, muss der Start-Wert
181 		// ggf. hart am Absatz gesetzt werden.
182 		rInfo.SetNodeStartValue( nLevel, 1 );
183 	}
184 
185 	// und es ggf. durch die Optionen veraendern
186 	String aId, aStyle, aClass, aBulletSrc, aLang, aDir;
187     sal_Int16 eVertOri = text::VertOrientation::NONE;
188 	sal_uInt16 nWidth=USHRT_MAX, nHeight=USHRT_MAX;
189 	const HTMLOptions *pHTMLOptions = GetOptions();
190 	for( sal_uInt16 i = pHTMLOptions->Count(); i; )
191 	{
192 		const HTMLOption *pOption = (*pHTMLOptions)[--i];
193 		switch( pOption->GetToken() )
194 		{
195 		case HTML_O_ID:
196 			aId = pOption->GetString();
197 			break;
198 		case HTML_O_TYPE:
199 			if( bNewNumFmt && pOption->GetString().Len() )
200 			{
201 				switch( nToken )
202 				{
203 				case HTML_ORDERLIST_ON:
204 					bChangeNumFmt = sal_True;
205 					switch( pOption->GetString().GetChar(0) )
206 					{
207 					case 'A':   aNumFmt.SetNumberingType(SVX_NUM_CHARS_UPPER_LETTER); break;
208 					case 'a':   aNumFmt.SetNumberingType(SVX_NUM_CHARS_LOWER_LETTER); break;
209 					case 'I':   aNumFmt.SetNumberingType(SVX_NUM_ROMAN_UPPER);        break;
210 					case 'i':   aNumFmt.SetNumberingType(SVX_NUM_ROMAN_LOWER);        break;
211 					default:	bChangeNumFmt = sal_False;
212 					}
213 					break;
214 
215 				case HTML_UNORDERLIST_ON:
216 					aNumFmt.SetBulletChar( (sal_Unicode)pOption->GetEnum(
217 									aHTMLULTypeTable,aNumFmt.GetBulletChar() ) );
218 					bChangeNumFmt = sal_True;
219 					break;
220 				}
221 			}
222 			break;
223 		case HTML_O_START:
224 			{
225 				sal_uInt16 nStart = (sal_uInt16)pOption->GetNumber();
226 				if( bNewNumFmt )
227 				{
228 					aNumFmt.SetStart( nStart );
229 					bChangeNumFmt = sal_True;
230 				}
231 				else
232 				{
233 					rInfo.SetNodeStartValue( nLevel, nStart );
234 				}
235 			}
236 			break;
237 		case HTML_O_STYLE:
238 			aStyle = pOption->GetString();
239 			break;
240 		case HTML_O_CLASS:
241 			aClass = pOption->GetString();
242 			break;
243 		case HTML_O_LANG:
244 			aLang = pOption->GetString();
245 			break;
246 		case HTML_O_DIR:
247 			aDir = pOption->GetString();
248 			break;
249 		case HTML_O_SRC:
250 			if( bNewNumFmt )
251 			{
252 				aBulletSrc = pOption->GetString();
253 				if( !InternalImgToPrivateURL(aBulletSrc) )
254                     aBulletSrc = URIHelper::SmartRel2Abs( INetURLObject( sBaseURL ), aBulletSrc, Link(), false );
255 			}
256 			break;
257 		case HTML_O_WIDTH:
258 			nWidth = (sal_uInt16)pOption->GetNumber();
259 			break;
260 		case HTML_O_HEIGHT:
261 			nHeight = (sal_uInt16)pOption->GetNumber();
262 			break;
263 		case HTML_O_ALIGN:
264 			eVertOri =
265                 (sal_Int16)pOption->GetEnum( aHTMLImgVAlignTable,
266                                                 static_cast< sal_uInt16 >(eVertOri) );
267 			break;
268 		}
269 	}
270 
271 	if( aBulletSrc.Len() )
272 	{
273 		// Eine Bullet-Liste mit Grafiken
274 		aNumFmt.SetNumberingType(SVX_NUM_BITMAP);
275 
276 		// Die Grafik als Brush anlegen
277         SvxBrushItem aBrushItem( RES_BACKGROUND );
278 		aBrushItem.SetGraphicLink( aBulletSrc );
279 		aBrushItem.SetGraphicPos( GPOS_AREA );
280 
281 		// Die Groesse nur beachten, wenn Breite und Hoehe vorhanden sind
282 		Size aTwipSz( nWidth, nHeight), *pTwipSz=0;
283 		if( nWidth!=USHRT_MAX && nHeight!=USHRT_MAX )
284 		{
285 			aTwipSz =
286 				Application::GetDefaultDevice()->PixelToLogic( aTwipSz,
287 													MapMode(MAP_TWIP) );
288 			pTwipSz = &aTwipSz;
289 		}
290 
291 		// Die Ausrichtung auch nur beachten, wenn eine Ausrichtung
292 		// angegeben wurde
293 		aNumFmt.SetGraphicBrush( &aBrushItem, pTwipSz,
294                             text::VertOrientation::NONE!=eVertOri ? &eVertOri : 0);
295 
296 		// Und noch die Grafik merken, um sie in den Absaetzen nicht
297 		// einzufuegen
298 		aBulletGrfs[nLevel] = aBulletSrc;
299 		bChangeNumFmt = sal_True;
300 	}
301 	else
302 		aBulletGrfs[nLevel].Erase();
303 
304 	// den aktuellen Absatz erst einmal nicht numerieren
305     {
306         sal_uInt8 nLvl = nLevel;
307         // --> OD 2008-04-02 #refactorlists#
308 //        SetNoNum(&nLvl, sal_True); // #115962#
309 //        SetNodeNum( nLvl );
310         SetNodeNum( nLvl, false );
311         // <--
312     }
313 
314 	// einen neuen Kontext anlegen
315     _HTMLAttrContext *pCntxt = new _HTMLAttrContext( static_cast< sal_uInt16 >(nToken) );
316 
317 	// Styles parsen
318 	if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) )
319 	{
320 		SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() );
321 		SvxCSS1PropertyInfo aPropInfo;
322 
323 		if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) )
324 		{
325 			if( bNewNumFmt )
326 			{
327 				if( aPropInfo.bLeftMargin )
328 				{
329 					// Der Der Default-Einzug wurde schon eingefuegt.
330 					sal_uInt16 nAbsLSpace =
331 						aNumFmt.GetAbsLSpace() - HTML_NUMBUL_MARGINLEFT;
332 					if( aPropInfo.nLeftMargin < 0 &&
333 						nAbsLSpace < -aPropInfo.nLeftMargin )
334 						nAbsLSpace = 0U;
335 					else if( aPropInfo.nLeftMargin > USHRT_MAX ||
336 							 (long)nAbsLSpace +
337 											aPropInfo.nLeftMargin > USHRT_MAX )
338 						nAbsLSpace = USHRT_MAX;
339 					else
340 						nAbsLSpace = nAbsLSpace + (sal_uInt16)aPropInfo.nLeftMargin;
341 
342 					aNumFmt.SetAbsLSpace( nAbsLSpace );
343 					bChangeNumFmt = sal_True;
344 				}
345 				if( aPropInfo.bTextIndent )
346 				{
347 					short nTextIndent =
348 						((const SvxLRSpaceItem &)aItemSet.Get( RES_LR_SPACE ))
349 														.GetTxtFirstLineOfst();
350 					aNumFmt.SetFirstLineOffset( nTextIndent );
351 					bChangeNumFmt = sal_True;
352 				}
353 			}
354 			aPropInfo.bLeftMargin = aPropInfo.bTextIndent = sal_False;
355 			if( !aPropInfo.bRightMargin )
356 				aItemSet.ClearItem( RES_LR_SPACE );
357 
358             // --> OD 2008-06-26 #i89812#
359             // Perform change to list style before calling <DoPositioning(..)>,
360             // because <DoPositioning(..)> may open a new context and thus may
361             // clear the <SwHTMLNumRuleInfo> instance hold by local variable <rInfo>.
362             if( bChangeNumFmt )
363             {
364                 rInfo.GetNumRule()->Set( nLevel, aNumFmt );
365                 pDoc->ChgNumRuleFmts( *rInfo.GetNumRule() );
366                 bChangeNumFmt = sal_False;
367             }
368             // <--
369 
370 			DoPositioning( aItemSet, aPropInfo, pCntxt );
371 
372 			InsertAttrs( aItemSet, aPropInfo, pCntxt );
373 		}
374 	}
375 
376 	if( bChangeNumFmt )
377 	{
378 		rInfo.GetNumRule()->Set( nLevel, aNumFmt );
379 		pDoc->ChgNumRuleFmts( *rInfo.GetNumRule() );
380 	}
381 
382 	PushContext( pCntxt );
383 
384 	// die Attribute der neuen Vorlage setzen
385 	SetTxtCollAttrs( pCntxt );
386 }
387 
EndNumBulList(int nToken)388 void SwHTMLParser::EndNumBulList( int nToken )
389 {
390 	SwHTMLNumRuleInfo& rInfo = GetNumInfo();
391 
392 	// Ein neuer Absatz muss aufgemacht werden, wenn
393 	// - der aktuelle nicht leer ist, also Text oder absatzgebundene Objekte
394 	//   enthaelt.
395 	// - der aktuelle Absatz numeriert ist.
396 	sal_Bool bAppend = pPam->GetPoint()->nContent.GetIndex() > 0;
397 	if( !bAppend )
398 	{
399 	    SwTxtNode* pTxtNode = pPam->GetNode()->GetTxtNode();
400 
401         bAppend = (pTxtNode && ! pTxtNode->IsOutline() && pTxtNode->IsCountedInList()) ||
402 
403             HasCurrentParaFlys();
404 	}
405 
406 	sal_Bool bSpace = (rInfo.GetDepth() + nDefListDeep) == 1;
407 	if( bAppend )
408 		AppendTxtNode( bSpace ? AM_SPACE : AM_NOSPACE, sal_False );
409 	else if( bSpace )
410 		AddParSpace();
411 
412 	// den aktuellen Kontext vom Stack holen
413     _HTMLAttrContext *pCntxt = nToken!=0 ? PopContext( static_cast< sal_uInt16 >(nToken & ~1) ) : 0;
414 
415 	// Keine Liste aufgrund eines Tokens beenden, wenn der Kontext
416 	// nie angelgt wurde oder nicht beendet werden darf.
417 	if( rInfo.GetDepth()>0 && (!nToken || pCntxt) )
418 	{
419 		rInfo.DecDepth();
420 		if( !rInfo.GetDepth() )		// wars der letze Level ?
421 		{
422 			// Die noch nicht angepassten Formate werden jetzt noch
423 			// angepasst, damit es sich besser Editieren laesst.
424 			const SwNumFmt *pRefNumFmt = 0;
425 			sal_Bool bChanged = sal_False;
426 			for( sal_uInt16 i=0; i<MAXLEVEL; i++ )
427 			{
428 				const SwNumFmt *pNumFmt = rInfo.GetNumRule()->GetNumFmt(i);
429 				if( pNumFmt )
430 				{
431 					pRefNumFmt = pNumFmt;
432 				}
433 				else if( pRefNumFmt )
434 				{
435 					SwNumFmt aNumFmt( rInfo.GetNumRule()->Get(i) );
436 					aNumFmt.SetNumberingType(pRefNumFmt->GetNumberingType() != SVX_NUM_BITMAP
437 										? pRefNumFmt->GetNumberingType() : style::NumberingType::CHAR_SPECIAL);
438 					if( SVX_NUM_CHAR_SPECIAL == aNumFmt.GetNumberingType() )
439 					{
440                         // --> OD 2008-06-03 #i63395#
441                         // Only apply user defined default bullet font
442                         if ( numfunc::IsDefBulletFontUserDefined() )
443                         {
444                             aNumFmt.SetBulletFont( &numfunc::GetDefBulletFont() );
445                         }
446                         // <--
447 						aNumFmt.SetBulletChar( cBulletChar );
448 					}
449 					aNumFmt.SetAbsLSpace( (i+1) * HTML_NUMBUL_MARGINLEFT );
450 					aNumFmt.SetFirstLineOffset( HTML_NUMBUL_INDENT );
451 					aNumFmt.SetCharFmt( pRefNumFmt->GetCharFmt() );
452 					rInfo.GetNumRule()->Set( i, aNumFmt );
453 					bChanged = sal_True;
454 				}
455 			}
456 			if( bChanged )
457 				pDoc->ChgNumRuleFmts( *rInfo.GetNumRule() );
458 
459 			// Beim letzen Append wurde das NumRule-Item und das
460 			// NodeNum-Objekt mit kopiert. Beides muessen wir noch
461 			// loeschen. Das ResetAttr loescht das NodeNum-Objekt mit!
462 			pPam->GetNode()->GetTxtNode()->ResetAttr( RES_PARATR_NUMRULE );
463 
464 			rInfo.Clear();
465 		}
466 		else
467 		{
468 			// den naechsten Absatz erstmal nicht numerieren
469             // --> OD 2008-04-02 #refactorlists#
470 //            SetNodeNum( rInfo.GetLevel() | NO_NUMLEVEL );
471             SetNodeNum( rInfo.GetLevel(), false );
472             // <--
473 		}
474 	}
475 
476 	// und noch Attribute beenden
477 	sal_Bool bSetAttrs = sal_False;
478 	if( pCntxt )
479 	{
480 		EndContext( pCntxt );
481 		delete pCntxt;
482 		bSetAttrs = sal_True;
483 	}
484 
485 	if( nToken )
486 		SetTxtCollAttrs();
487 
488 	if( bSetAttrs )
489 		SetAttr();	// Absatz-Atts wegen JavaScript moeglichst schnell setzen
490 
491 }
492 
493 /*  */
494 
NewNumBulListItem(int nToken)495 void SwHTMLParser::NewNumBulListItem( int nToken )
496 {
497 	sal_uInt8 nLevel = GetNumInfo().GetLevel();
498 	String aId, aStyle, aClass, aLang, aDir;
499 	sal_uInt16 nStart = HTML_LISTHEADER_ON != nToken
500 						? GetNumInfo().GetNodeStartValue( nLevel )
501 						: USHRT_MAX;
502 	if( USHRT_MAX != nStart )
503 		GetNumInfo().SetNodeStartValue( nLevel );
504 
505 	const HTMLOptions *pHTMLOptions = GetOptions();
506 	for( sal_uInt16 i = pHTMLOptions->Count(); i; )
507 	{
508 		const HTMLOption *pOption = (*pHTMLOptions)[--i];
509 		switch( pOption->GetToken() )
510 		{
511 			case HTML_O_VALUE:
512 				nStart = (sal_uInt16)pOption->GetNumber();
513 				break;
514 			case HTML_O_ID:
515 				aId = pOption->GetString();
516 				break;
517 			case HTML_O_STYLE:
518 				aStyle = pOption->GetString();
519 				break;
520 			case HTML_O_CLASS:
521 				aClass = pOption->GetString();
522 				break;
523 			case HTML_O_LANG:
524 				aLang = pOption->GetString();
525 				break;
526 			case HTML_O_DIR:
527 				aDir = pOption->GetString();
528 				break;
529 		}
530 	}
531 
532 	// einen neuen Absatz aufmachen
533 	if( pPam->GetPoint()->nContent.GetIndex() )
534 		AppendTxtNode( AM_NOSPACE, sal_False );
535 	bNoParSpace = sal_False;	// In <LI> wird kein Abstand eingefuegt!
536 
537     // --> OD 2008-04-02 #refactorlists#
538 //    if( HTML_LISTHEADER_ON==nToken )
539 //        SetNoNum(&nLevel, sal_True);
540     const bool bCountedInList( HTML_LISTHEADER_ON==nToken ? false : true );
541     // <--
542 
543     _HTMLAttrContext *pCntxt = new _HTMLAttrContext( static_cast< sal_uInt16 >(nToken) );
544 
545 	String aNumRuleName;
546 	if( GetNumInfo().GetNumRule() )
547 	{
548 		aNumRuleName = GetNumInfo().GetNumRule()->GetName();
549 	}
550 	else
551 	{
552 		aNumRuleName = pDoc->GetUniqueNumRuleName();
553         // --> OD 2008-02-11 #newlistlevelattrs#
554         SwNumRule aNumRule( aNumRuleName,
555                             SvxNumberFormat::LABEL_WIDTH_AND_POSITION );
556         // <--
557 		SwNumFmt aNumFmt( aNumRule.Get( 0 ) );
558         // --> OD 2008-06-03 #i63395#
559         // Only apply user defined default bullet font
560         if ( numfunc::IsDefBulletFontUserDefined() )
561         {
562             aNumFmt.SetBulletFont( &numfunc::GetDefBulletFont() );
563         }
564         // <--
565 		aNumFmt.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
566 		aNumFmt.SetBulletChar( cBulletChar );	// das Bulletzeichen !!
567 		aNumFmt.SetCharFmt( pCSS1Parser->GetCharFmtFromPool(RES_POOLCHR_BUL_LEVEL) );
568 		aNumFmt.SetLSpace( (sal_uInt16)(-HTML_NUMBUL_INDENT) );
569 		aNumFmt.SetFirstLineOffset( HTML_NUMBUL_INDENT );
570 		aNumRule.Set( 0, aNumFmt );
571 
572 		pDoc->MakeNumRule( aNumRuleName, &aNumRule );
573 
574 		ASSERT( !nOpenParaToken,
575 				"Jetzt geht ein offenes Absatz-Element verloren" );
576 		// Wir tun so, als ob wir in einem Absatz sind. Dann wird
577 		// beim naechsten Absatz wenigstens die Numerierung
578 		// weggeschmissen, die nach dem naechsten AppendTxtNode uebernommen
579 		// wird.
580         nOpenParaToken = static_cast< sal_uInt16 >(nToken);
581 	}
582 
583 	SwTxtNode* pTxtNode = pPam->GetNode()->GetTxtNode();
584 	((SwCntntNode *)pTxtNode)->SetAttr( SwNumRuleItem(aNumRuleName) );
585     pTxtNode->SetAttrListLevel(nLevel);
586     // --> OD 2005-11-14 #i57656#
587     // <IsCounted()> state of text node has to be adjusted accordingly.
588     if ( /*nLevel >= 0 &&*/ nLevel < MAXLEVEL )
589     {
590         // --> OD 2008-04-02 #refactorlists#
591         pTxtNode->SetCountedInList( bCountedInList );
592         // <--
593     }
594     // <--
595     // --> OD 2005-11-15 #i57919#
596     // correction of refactoring done by cws swnumtree
597     // - <nStart> contains the start value, if the numbering has to be restarted
598     //   at this text node. Value <USHRT_MAX> indicates, that numbering isn't
599     //   restarted at this text node
600     if ( nStart != USHRT_MAX )
601     {
602         pTxtNode->SetListRestart( true );
603         pTxtNode->SetAttrListRestartValue( nStart );
604     }
605     // <--
606 
607 	if( GetNumInfo().GetNumRule() )
608 		GetNumInfo().GetNumRule()->SetInvalidRule( sal_True );
609 
610 	// Styles parsen
611 	if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) )
612 	{
613 		SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() );
614 		SvxCSS1PropertyInfo aPropInfo;
615 
616 		if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) )
617 		{
618 			DoPositioning( aItemSet, aPropInfo, pCntxt );
619 			InsertAttrs( aItemSet, aPropInfo, pCntxt );
620 		}
621 	}
622 
623 	PushContext( pCntxt );
624 
625 	// die neue Vorlage setzen
626 	SetTxtCollAttrs( pCntxt );
627 
628 	// Laufbalkenanzeige aktualisieren
629 	ShowStatline();
630 }
631 
EndNumBulListItem(int nToken,sal_Bool bSetColl,sal_Bool)632 void SwHTMLParser::EndNumBulListItem( int nToken, sal_Bool bSetColl,
633 									  sal_Bool /*bLastPara*/ )
634 {
635 	// einen neuen Absatz aufmachen
636 	if( !nToken && pPam->GetPoint()->nContent.GetIndex() )
637 		AppendTxtNode( AM_NOSPACE );
638 
639 	// Kontext zu dem Token suchen und vom Stack holen
640 	_HTMLAttrContext *pCntxt = 0;
641 	sal_uInt16 nPos = aContexts.Count();
642 	nToken &= ~1;
643 	while( !pCntxt && nPos>nContextStMin )
644 	{
645 		sal_uInt16 nCntxtToken = aContexts[--nPos]->GetToken();
646 		switch( nCntxtToken )
647 		{
648 		case HTML_LI_ON:
649 		case HTML_LISTHEADER_ON:
650 			if( !nToken || nToken == nCntxtToken  )
651 			{
652 				pCntxt = aContexts[nPos];
653 				aContexts.Remove( nPos, 1 );
654 			}
655 			break;
656 		case HTML_ORDERLIST_ON:
657 		case HTML_UNORDERLIST_ON:
658 		case HTML_MENULIST_ON:
659 		case HTML_DIRLIST_ON:
660 			// keine LI/LH ausserhalb der aktuellen Liste betrachten
661 			nPos = nContextStMin;
662 			break;
663 		}
664 	}
665 
666 	// und noch Attribute beenden
667 	if( pCntxt )
668 	{
669 		EndContext( pCntxt );
670 		SetAttr();	// Absatz-Atts wegen JavaScript moeglichst schnell setzen
671 		delete pCntxt;
672 	}
673 
674 	// und die bisherige Vorlage setzen
675 	if( bSetColl )
676 		SetTxtCollAttrs();
677 }
678 
679 /*  */
680 
681 // --> OD 2008-04-02 #refactorlists#
SetNodeNum(sal_uInt8 nLevel,bool bCountedInList)682 void SwHTMLParser::SetNodeNum( sal_uInt8 nLevel, bool bCountedInList )
683 {
684 	SwTxtNode* pTxtNode = pPam->GetNode()->GetTxtNode();
685 	ASSERT( pTxtNode, "Kein Text-Node an PaM-Position" );
686 
687 	ASSERT( GetNumInfo().GetNumRule(), "Kein Numerierungs-Regel" );
688 	const String& rName = GetNumInfo().GetNumRule()->GetName();
689 	((SwCntntNode *)pTxtNode)->SetAttr( SwNumRuleItem(rName) );
690 
691     // --> OD 2008-04-02 #refactorlists#
692 //    // --> OD 2005-11-14 #i57656#
693 //    // consider usage of NO_NUMLEVEL - see implementation of <SwTxtNode::SetLevel(..)>
694 //    if ( /*nLevel >= 0 &&*/ ( nLevel & NO_NUMLEVEL ) )
695 //    {
696 //        pTxtNode->SetAttrListLevel( nLevel & ~NO_NUMLEVEL );
697 //        pTxtNode->SetCountedInList( false );
698 //    }
699 //    else
700 //    {
701 //        pTxtNode->SetAttrListLevel( nLevel );
702 //        pTxtNode->SetCountedInList( true );
703 //    }
704     pTxtNode->SetAttrListLevel( nLevel );
705     pTxtNode->SetCountedInList( bCountedInList );
706     // <--
707 
708 	// NumRule invalidieren, weil sie durch ein EndAction bereits
709 	// auf valid geschaltet worden sein kann.
710 	GetNumInfo().GetNumRule()->SetInvalidRule( sal_False );
711 }
712 
713 
714 /*  */
715 
FillNextNumInfo()716 void SwHTMLWriter::FillNextNumInfo()
717 {
718 	pNextNumRuleInfo = 0;
719 
720 	sal_uLong nPos = pCurPam->GetPoint()->nNode.GetIndex() + 1;
721 
722 	sal_Bool bTable = sal_False;
723 	do
724 	{
725 		const SwNode* pNd = pDoc->GetNodes()[nPos];
726 		if( pNd->IsTxtNode() )
727 		{
728 			// Der naechste wird als naechstes ausgegeben.
729 			pNextNumRuleInfo = new SwHTMLNumRuleInfo( *pNd->GetTxtNode() );
730 
731 			// Vor einer Tabelle behalten wir erst einmal die alte Ebene bei,
732 			// wenn die gleiche Numerierung hinter der Tabelle
733 			// fortgesetzt wird und dort nicht von vorne numeriert
734 			// wird. Die Tabelle wird ann beim Import so weit eingeruckt,
735 			// wie es der Num-Ebene entspricht.
736 			if( bTable &&
737 				pNextNumRuleInfo->GetNumRule()==GetNumInfo().GetNumRule() &&
738 				!pNextNumRuleInfo->IsRestart() )
739 			{
740 				pNextNumRuleInfo->SetDepth( GetNumInfo().GetDepth() );
741 			}
742 		}
743 		else if( pNd->IsTableNode() )
744 		{
745 			// Eine Tabelle wird uebersprungen, also den Node
746 			// hinter der Tabelle betrachten.
747 			nPos = pNd->EndOfSectionIndex() + 1;
748 			bTable = sal_True;
749 		}
750 		else
751 		{
752 			// In allen anderen Faellen ist die Numerierung erstmal
753 			// zu Ende.
754 			pNextNumRuleInfo = new SwHTMLNumRuleInfo;
755 		}
756 	}
757 	while( !pNextNumRuleInfo );
758 }
759 
ClearNextNumInfo()760 void SwHTMLWriter::ClearNextNumInfo()
761 {
762 	delete pNextNumRuleInfo;
763 	pNextNumRuleInfo = 0;
764 }
765 
OutHTML_NumBulListStart(SwHTMLWriter & rWrt,const SwHTMLNumRuleInfo & rInfo)766 Writer& OutHTML_NumBulListStart( SwHTMLWriter& rWrt,
767 								 const SwHTMLNumRuleInfo& rInfo )
768 {
769 	SwHTMLNumRuleInfo& rPrevInfo = rWrt.GetNumInfo();
770 	sal_Bool bSameRule = rPrevInfo.GetNumRule() == rInfo.GetNumRule();
771 	if( bSameRule && rPrevInfo.GetDepth() >= rInfo.GetDepth() &&
772 		!rInfo.IsRestart() )
773 	{
774 		return rWrt;
775 	}
776 
777 	sal_Bool bStartValue = sal_False;
778 	if( !bSameRule && rInfo.GetDepth() )
779 	{
780 		String aName( rInfo.GetNumRule()->GetName() );
781 		if( rWrt.aNumRuleNames.Seek_Entry( &aName ) )
782 		{
783 			// The rule has been applied before
784 			sal_Int16 eType = rInfo.GetNumRule()
785 				->Get( rInfo.GetDepth()-1 ).GetNumberingType();
786 			if( SVX_NUM_CHAR_SPECIAL != eType && SVX_NUM_BITMAP != eType )
787 			{
788 				// If its a numbering rule, the current number should be
789 				// exported as start value, but only if there are no nodes
790 				// within the numbering that have a lower level
791 				bStartValue = sal_True;
792 				if( rInfo.GetDepth() > 1 )
793 				{
794 					sal_uLong nPos =
795 						rWrt.pCurPam->GetPoint()->nNode.GetIndex() + 1;
796 					do
797 					{
798 						const SwNode* pNd = rWrt.pDoc->GetNodes()[nPos];
799 						if( pNd->IsTxtNode() )
800 						{
801 							const SwTxtNode *pTxtNd = pNd->GetTxtNode();
802 							if( !pTxtNd->GetNumRule() )
803 							{
804 								// node isn't numbered => check completed
805 								break;
806 							}
807 
808                             ASSERT(! pTxtNd->IsOutline(),
809                                    "outline not expected");
810 
811                             if( pTxtNd->GetActualListLevel() + 1 <
812                                 rInfo.GetDepth() )
813 							{
814 								// node is numbered, but level is lower
815 								// => check completed
816 								bStartValue = sal_False;
817 								break;
818 							}
819 							nPos++;
820 						}
821 						else if( pNd->IsTableNode() )
822 						{
823 							// skip table
824 							nPos = pNd->EndOfSectionIndex() + 1;
825 						}
826 						else
827 						{
828 							// end node or sections start node -> check
829 							// completed
830 							break;
831 						}
832 					}
833 					while( sal_True );
834 				}
835 			}
836 		}
837 		else
838 		{
839 			rWrt.aNumRuleNames.Insert( new String( aName ) );
840 		}
841 	}
842 
843 
844 	DBG_ASSERT( rWrt.nLastParaToken == 0,
845 				"<PRE> wurde nicht vor <OL> beendet." );
846 	sal_uInt16 nPrevDepth =
847 		(bSameRule && !rInfo.IsRestart()) ? rPrevInfo.GetDepth() : 0;
848 
849 	for( sal_uInt16 i=nPrevDepth; i<rInfo.GetDepth(); i++ )
850 	{
851 		rWrt.OutNewLine(); // <OL>/<UL> in eine neue Zeile
852 
853 		rWrt.aBulletGrfs[i].Erase();
854 		ByteString sOut( '<' );
855 		const SwNumFmt& rNumFmt = rInfo.GetNumRule()->Get( i );
856 		sal_Int16 eType = rNumFmt.GetNumberingType();
857 		if( SVX_NUM_CHAR_SPECIAL == eType )
858 		{
859 			// Aufzaehlungs-Liste: <OL>
860 			sOut += OOO_STRING_SVTOOLS_HTML_unorderlist;
861 
862 			// den Typ ueber das Bullet-Zeichen bestimmen
863 			const sal_Char *pStr = 0;
864 			switch( rNumFmt.GetBulletChar() )
865 			{
866 			case HTML_BULLETCHAR_DISC:
867 				pStr = OOO_STRING_SVTOOLS_HTML_ULTYPE_disc;
868 				break;
869 			case HTML_BULLETCHAR_CIRCLE:
870 				pStr = OOO_STRING_SVTOOLS_HTML_ULTYPE_circle;
871 				break;
872 			case HTML_BULLETCHAR_SQUARE:
873 				pStr = OOO_STRING_SVTOOLS_HTML_ULTYPE_square;
874 				break;
875 			}
876 
877 			if( pStr )
878 				(((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_type) += '=') += pStr;
879 		}
880 		else if( SVX_NUM_BITMAP == eType )
881 		{
882 			// Aufzaehlungs-Liste: <OL>
883 			sOut += OOO_STRING_SVTOOLS_HTML_unorderlist;
884 			rWrt.Strm() << sOut.GetBuffer();
885 			sOut.Erase();
886 
887 			OutHTML_BulletImage( rWrt,
888 									0,
889 									rNumFmt.GetBrush(),
890 									rWrt.aBulletGrfs[i],
891 									rNumFmt.GetGraphicSize(),
892 									rNumFmt.GetGraphicOrientation() );
893 		}
894 		else
895 		{
896 			// Numerierungs-Liste: <UL>
897 			sOut += OOO_STRING_SVTOOLS_HTML_orderlist;
898 
899 			// den Typ ueber das Format bestimmen
900 			sal_Char cType = 0;
901 			switch( eType )
902 			{
903 			case SVX_NUM_CHARS_UPPER_LETTER:	cType = 'A'; break;
904 			case SVX_NUM_CHARS_LOWER_LETTER:	cType = 'a'; break;
905 			case SVX_NUM_ROMAN_UPPER:			cType = 'I'; break;
906 			case SVX_NUM_ROMAN_LOWER:			cType = 'i'; break;
907 			}
908 			if( cType )
909 				(((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_type) += '=') += cType;
910 
911 			sal_uInt16 nStartVal = rNumFmt.GetStart();
912 			if( bStartValue && 1 == nStartVal && i == rInfo.GetDepth()-1 )
913             {
914                 // --> OD 2005-11-02 #i51089 - TUNING#
915                 if ( rWrt.pCurPam->GetNode()->GetTxtNode()->GetNum() )
916                 {
917                     nStartVal = static_cast< sal_uInt16 >( rWrt.pCurPam->GetNode()
918                                 ->GetTxtNode()->GetNumberVector()[i] );
919                 }
920                 else
921                 {
922                     ASSERT( false,
923                             "<OutHTML_NumBulListStart(..) - text node has no number." );
924                 }
925             }
926 			if( nStartVal != 1 )
927 			{
928 				(((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_start) += '=')
929 					+= ByteString::CreateFromInt32( nStartVal );
930 			}
931 		}
932 
933 		if( sOut.Len() )
934 			rWrt.Strm() << sOut.GetBuffer();
935 
936 		if( rWrt.bCfgOutStyles )
937 			OutCSS1_NumBulListStyleOpt( rWrt, *rInfo.GetNumRule(), (sal_uInt8)i );
938 
939 		rWrt.Strm() << '>';
940 
941 		rWrt.IncIndentLevel(); // Inhalt von <OL> einruecken
942 	}
943 
944 	return rWrt;
945 }
946 
OutHTML_NumBulListEnd(SwHTMLWriter & rWrt,const SwHTMLNumRuleInfo & rNextInfo)947 Writer& OutHTML_NumBulListEnd( SwHTMLWriter& rWrt,
948 							   const SwHTMLNumRuleInfo& rNextInfo )
949 {
950 	SwHTMLNumRuleInfo& rInfo = rWrt.GetNumInfo();
951 	sal_Bool bSameRule = rNextInfo.GetNumRule() == rInfo.GetNumRule();
952 	if( bSameRule && rNextInfo.GetDepth() >= rInfo.GetDepth() &&
953 		!rNextInfo.IsRestart() )
954 	{
955 		return rWrt;
956 	}
957 
958 	DBG_ASSERT( rWrt.nLastParaToken == 0,
959 				"<PRE> wurde nicht vor </OL> beendet." );
960 	sal_uInt16 nNextDepth =
961 		(bSameRule && !rNextInfo.IsRestart()) ? rNextInfo.GetDepth() : 0;
962 
963 	// MIB 23.7.97: Die Schleife muss doch rueckwaerts durchlaufen
964 	// werden, weil die Reihenfolge von </OL>/</UL> stimmen muss
965 	for( sal_uInt16 i=rInfo.GetDepth(); i>nNextDepth; i-- )
966 	{
967 		rWrt.DecIndentLevel(); // Inhalt von <OL> einruecken
968 		if( rWrt.bLFPossible )
969 			rWrt.OutNewLine(); // </OL>/</UL> in eine neue Zeile
970 
971 		// es wird also eine Liste angefangen oder beendet:
972 		sal_Int16 eType = rInfo.GetNumRule()->Get( i-1 ).GetNumberingType();
973 		const sal_Char *pStr;
974 		if( SVX_NUM_CHAR_SPECIAL == eType || SVX_NUM_BITMAP == eType)
975 			pStr = OOO_STRING_SVTOOLS_HTML_unorderlist;
976 		else
977 			pStr = OOO_STRING_SVTOOLS_HTML_orderlist;
978 		HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), pStr, sal_False );
979 		rWrt.bLFPossible = sal_True;
980 	}
981 
982 	return rWrt;
983 }
984