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