xref: /AOO41X/main/sw/source/filter/html/htmlnum.cxx (revision efeef26f81c84063fb0a91bde3856d4a51172d90)
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