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