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