1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: htmlpars.cxx,v $
10 * $Revision: 1.34.32.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 #include <boost/shared_ptr.hpp>
36 #define SC_HTMLPARS_CXX
37 #include "scitems.hxx"
38 #include <svx/eeitem.hxx>
40 #include <svx/htmlcfg.hxx>
41 #include <svx/algitem.hxx>
42 #include <svx/colritem.hxx>
43 #include <svx/brshitem.hxx>
44 #include <svx/editeng.hxx>
45 #include <svx/fhgtitem.hxx>
46 #include <svx/fontitem.hxx>
47 #include <svx/impgrf.hxx>
48 #include <svx/postitem.hxx>
49 #include <svx/udlnitem.hxx>
50 #include <svx/wghtitem.hxx>
51 #include <svx/boxitem.hxx>
52 #include <sfx2/objsh.hxx>
53 #include <svtools/eitem.hxx>
54 #include <svtools/filter.hxx>
55 #include <svtools/parhtml.hxx>
56 #include <svtools/htmlkywd.hxx>
57 #include <svtools/htmltokn.h>
58 #include <sfx2/docfile.hxx>
60 #include <vcl/svapp.hxx>
61 #include <tools/urlobj.hxx>
62 #include <tools/tenccvt.hxx>
64 #include "htmlpars.hxx"
66 #include "document.hxx"
67 #include "rangelst.hxx"
69 #include <com/sun/star/document/XDocumentProperties.hpp>
70 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
73 using namespace ::com::sun::star
;
76 SV_IMPL_VARARR_SORT( ScHTMLColOffset
, ULONG
);
79 // ============================================================================
80 // BASE class for HTML parser classes
81 // ============================================================================
83 ScHTMLParser::ScHTMLParser( EditEngine
* pEditEngine
, ScDocument
* pDoc
) :
84 ScEEParser( pEditEngine
),
87 SvxHtmlOptions
* pHtmlOptions
= SvxHtmlOptions::Get();
88 for( sal_uInt16 nIndex
= 0; nIndex
< SC_HTML_FONTSIZES
; ++nIndex
)
89 maFontHeights
[ nIndex
] = pHtmlOptions
->GetFontSize( nIndex
) * 20;
92 ScHTMLParser::~ScHTMLParser()
97 // ============================================================================
99 ScHTMLLayoutParser::ScHTMLLayoutParser( EditEngine
* pEditP
, const String
& rBaseURL
, const Size
& aPageSizeP
, ScDocument
* pDocP
) :
100 ScHTMLParser( pEditP
, pDocP
),
101 aPageSize( aPageSizeP
),
102 aBaseURL( rBaseURL
),
103 xLockedList( new ScRangeList
),
105 pColOffset( new ScHTMLColOffset
),
106 pLocalColOffset( new ScHTMLColOffset
),
117 nOffsetTolerance( SC_HTML_OFFSET_TOLERANCE_SMALL
),
118 bTabInTabCell( FALSE
),
123 MakeColNoRef( pLocalColOffset
, 0, 0, 0, 0 );
124 MakeColNoRef( pColOffset
, 0, 0, 0, 0 );
128 ScHTMLLayoutParser::~ScHTMLLayoutParser()
130 ScHTMLTableStackEntry
* pS
;
131 while ( (pS
= aTableStack
.Pop()) != 0 )
133 if ( pList
->GetPos( pS
->pCellEntry
) == LIST_ENTRY_NOTFOUND
)
134 delete pS
->pCellEntry
;
135 if ( pS
->pLocalColOffset
!= pLocalColOffset
)
136 delete pS
->pLocalColOffset
;
139 if ( pLocalColOffset
)
140 delete pLocalColOffset
;
145 for ( Table
* pT
= (Table
*) pTables
->First(); pT
; pT
= (Table
*) pTables
->Next() )
152 ULONG
ScHTMLLayoutParser::Read( SvStream
& rStream
, const String
& rBaseURL
)
154 Link aOldLink
= pEdit
->GetImportHdl();
155 pEdit
->SetImportHdl( LINK( this, ScHTMLLayoutParser
, HTMLImportHdl
) );
157 SfxObjectShell
* pObjSh
= mpDoc
->GetDocumentShell();
158 BOOL bLoading
= pObjSh
&& pObjSh
->IsLoading();
160 SvKeyValueIteratorRef xValues
;
161 SvKeyValueIterator
* pAttributes
= NULL
;
163 pAttributes
= pObjSh
->GetHeaderAttributes();
166 // When not loading, set up fake http headers to force the SfxHTMLParser to use UTF8
167 // (used when pasting from clipboard)
169 const sal_Char
* pCharSet
= rtl_getBestMimeCharsetFromTextEncoding( RTL_TEXTENCODING_UTF8
);
172 String aContentType
= String::CreateFromAscii( "text/html; charset=" );
173 aContentType
.AppendAscii( pCharSet
);
175 xValues
= new SvKeyValueIterator
;
176 xValues
->Append( SvKeyValue( String::CreateFromAscii( OOO_STRING_SVTOOLS_HTML_META_content_type
), aContentType
) );
177 pAttributes
= xValues
;
181 ULONG nErr
= pEdit
->Read( rStream
, rBaseURL
, EE_FORMAT_HTML
, pAttributes
);
183 pEdit
->SetImportHdl( aOldLink
);
184 // Spaltenbreiten erzeugen
186 OutputDevice
* pDefaultDev
= Application::GetDefaultDevice();
187 USHORT nCount
= pColOffset
->Count();
188 const ULONG
* pOff
= (const ULONG
*) pColOffset
->GetData();
189 ULONG nOff
= *pOff
++;
191 for ( USHORT j
= 1; j
< nCount
; j
++, pOff
++ )
193 aSize
.Width() = *pOff
- nOff
;
194 aSize
= pDefaultDev
->PixelToLogic( aSize
, MapMode( MAP_TWIP
) );
195 pColWidths
->Insert( j
-1, (void*)aSize
.Width() );
202 const ScHTMLTable
* ScHTMLLayoutParser::GetGlobalTable() const
208 void ScHTMLLayoutParser::NewActEntry( ScEEParseEntry
* pE
)
210 ScEEParser::NewActEntry( pE
);
213 if ( !pE
->aSel
.HasRange() )
214 { // komplett leer, nachfolgender Text landet im gleichen Absatz!
215 pActEntry
->aSel
.nStartPara
= pE
->aSel
.nEndPara
;
216 pActEntry
->aSel
.nStartPos
= pE
->aSel
.nEndPos
;
219 pActEntry
->aSel
.nEndPara
= pActEntry
->aSel
.nStartPara
;
220 pActEntry
->aSel
.nEndPos
= pActEntry
->aSel
.nStartPos
;
224 void ScHTMLLayoutParser::EntryEnd( ScEEParseEntry
* pE
, const ESelection
& rSel
)
226 if ( rSel
.nEndPara
>= pE
->aSel
.nStartPara
)
228 pE
->aSel
.nEndPara
= rSel
.nEndPara
;
229 pE
->aSel
.nEndPos
= rSel
.nEndPos
;
231 else if ( rSel
.nStartPara
== pE
->aSel
.nStartPara
- 1 && !pE
->aSel
.HasRange() )
232 { // kein Absatz angehaengt aber leer, nichts tun
236 DBG_ERRORFILE( "EntryEnd: EditEngine ESelection End < Start" );
241 void ScHTMLLayoutParser::NextRow( ImportInfo
* pInfo
)
245 if ( nRowMax
< ++nRowCnt
)
247 nColCnt
= nColCntStart
;
248 nColOffset
= nColOffsetStart
;
253 BOOL
ScHTMLLayoutParser::SeekOffset( ScHTMLColOffset
* pOffset
, USHORT nOffset
,
254 SCCOL
* pCol
, USHORT nOffsetTol
)
256 DBG_ASSERT( pOffset
, "ScHTMLLayoutParser::SeekOffset - illegal call" );
258 BOOL bFound
= pOffset
->Seek_Entry( nOffset
, &nPos
);
259 *pCol
= static_cast<SCCOL
>(nPos
);
262 USHORT nCount
= pOffset
->Count();
265 // nPos ist Einfuegeposition, da liegt der Naechsthoehere (oder auch nicht)
266 if ( nPos
< nCount
&& (((*pOffset
)[nPos
] - nOffsetTol
) <= nOffset
) )
268 // nicht kleiner als alles andere? dann mit Naechstniedrigerem vergleichen
269 else if ( nPos
&& (((*pOffset
)[nPos
-1] + nOffsetTol
) >= nOffset
) )
278 void ScHTMLLayoutParser::MakeCol( ScHTMLColOffset
* pOffset
, USHORT
& nOffset
,
279 USHORT
& nWidth
, USHORT nOffsetTol
, USHORT nWidthTol
)
281 DBG_ASSERT( pOffset
, "ScHTMLLayoutParser::MakeCol - illegal call" );
283 if ( SeekOffset( pOffset
, nOffset
, &nPos
, nOffsetTol
) )
284 nOffset
= (USHORT
)(*pOffset
)[nPos
];
286 pOffset
->Insert( nOffset
);
289 if ( SeekOffset( pOffset
, nOffset
+ nWidth
, &nPos
, nWidthTol
) )
290 nWidth
= (USHORT
)(*pOffset
)[nPos
] - nOffset
;
292 pOffset
->Insert( nOffset
+ nWidth
);
297 void ScHTMLLayoutParser::MakeColNoRef( ScHTMLColOffset
* pOffset
, USHORT nOffset
,
298 USHORT nWidth
, USHORT nOffsetTol
, USHORT nWidthTol
)
300 DBG_ASSERT( pOffset
, "ScHTMLLayoutParser::MakeColNoRef - illegal call" );
302 if ( SeekOffset( pOffset
, nOffset
, &nPos
, nOffsetTol
) )
303 nOffset
= (USHORT
)(*pOffset
)[nPos
];
305 pOffset
->Insert( nOffset
);
308 if ( !SeekOffset( pOffset
, nOffset
+ nWidth
, &nPos
, nWidthTol
) )
309 pOffset
->Insert( nOffset
+ nWidth
);
314 void ScHTMLLayoutParser::ModifyOffset( ScHTMLColOffset
* pOffset
, USHORT
& nOldOffset
,
315 USHORT
& nNewOffset
, USHORT nOffsetTol
)
317 DBG_ASSERT( pOffset
, "ScHTMLLayoutParser::ModifyOffset - illegal call" );
319 if ( !SeekOffset( pOffset
, nOldOffset
, &nPos
, nOffsetTol
) )
321 if ( SeekOffset( pOffset
, nNewOffset
, &nPos
, nOffsetTol
) )
322 nNewOffset
= (USHORT
)(*pOffset
)[nPos
];
324 pOffset
->Insert( nNewOffset
);
327 nOldOffset
= (USHORT
)(*pOffset
)[nPos
];
329 if ( SeekOffset( pOffset
, nNewOffset
, &nPos2
, nOffsetTol
) )
331 nNewOffset
= (USHORT
)(*pOffset
)[nPos2
];
334 ULONG
* pData
= ((ULONG
*) pOffset
->GetData()) + nPos
; //! QAD
335 long nDiff
= nNewOffset
- nOldOffset
;
338 const ULONG
* pStop
= pOffset
->GetData();
342 } while ( pStop
< pData
-- );
346 const ULONG
* pStop
= pOffset
->GetData() + pOffset
->Count();
350 } while ( ++pData
< pStop
);
355 void ScHTMLLayoutParser::SkipLocked( ScEEParseEntry
* pE
, BOOL bJoin
)
357 if ( ValidCol(pE
->nCol
) )
358 { // wuerde sonst bei ScAddress falschen Wert erzeugen, evtl. Endlosschleife!
359 BOOL bBadCol
= FALSE
;
361 ScRange
aRange( pE
->nCol
, pE
->nRow
, 0,
362 pE
->nCol
+ pE
->nColOverlap
- 1, pE
->nRow
+ pE
->nRowOverlap
- 1, 0 );
366 for ( ScRange
* pR
= xLockedList
->First(); pR
; pR
= xLockedList
->Next() )
368 if ( pR
->Intersects( aRange
) )
370 pE
->nCol
= pR
->aEnd
.Col() + 1;
371 SCCOL nTmp
= pE
->nCol
+ pE
->nColOverlap
- 1;
372 if ( pE
->nCol
> MAXCOL
|| nTmp
> MAXCOL
)
377 aRange
.aStart
.SetCol( pE
->nCol
);
378 aRange
.aEnd
.SetCol( nTmp
);
384 if ( bJoin
&& !bBadCol
)
385 xLockedList
->Join( aRange
);
390 void ScHTMLLayoutParser::Adjust()
392 for ( ScRange
* pR
= xLockedList
->First(); pR
; pR
= xLockedList
->Next() )
394 xLockedList
->Clear();
395 ScHTMLAdjustStack aStack
;
396 ScHTMLAdjustStackEntry
* pS
;
398 SCCOL nLastCol
= SCCOL_MAX
;
401 USHORT nPageWidth
= (USHORT
) aPageSize
.Width();
403 for ( ScEEParseEntry
* pE
= pList
->First(); pE
; pE
= pList
->Next() )
405 if ( pE
->nTab
< nTab
)
407 if ( (pS
= aStack
.Pop()) != 0 )
409 nLastCol
= pS
->nLastCol
;
410 nNextRow
= pS
->nNextRow
;
411 nCurRow
= pS
->nCurRow
;
415 pTab
= (pTables
? (Table
*) pTables
->Get( nTab
) : NULL
);
418 SCROW nRow
= pE
->nRow
;
419 if ( pE
->nCol
<= nLastCol
)
421 if ( pE
->nRow
< nNextRow
)
422 pE
->nRow
= nCurRow
= nNextRow
;
424 nCurRow
= nNextRow
= pE
->nRow
;
426 if ( pTab
&& ((nR
= (SCROW
)(ULONG
)pTab
->Get( nCurRow
)) != 0) )
433 nLastCol
= pE
->nCol
; // eingelesene Col
434 if ( pE
->nTab
> nTab
)
436 aStack
.Push( new ScHTMLAdjustStackEntry(
437 nLastCol
, nNextRow
, nCurRow
) );
439 pTab
= (pTables
? (Table
*) pTables
->Get( nTab
) : NULL
);
440 // neuer Zeilenabstand
442 if ( pTab
&& ((nR
= (SCROW
)(ULONG
)pTab
->Get( nCurRow
)) != 0) )
443 nNextRow
= nCurRow
+ nR
;
445 nNextRow
= nCurRow
+ 1;
448 pE
->nWidth
= nPageWidth
;
450 { // echte Table, keine Absaetze auf der Wiese
453 SCROW nRowSpan
= pE
->nRowOverlap
;
454 for ( SCROW j
=0; j
< nRowSpan
; j
++ )
455 { // aus merged Zeilen resultierendes RowSpan
456 SCROW nRows
= (SCROW
)(ULONG
)pTab
->Get( nRow
+j
);
459 pE
->nRowOverlap
+= nRows
- 1;
461 { // merged Zeilen verschieben die naechste Zeile
462 SCROW nTmp
= nCurRow
+ nRows
;
463 if ( nNextRow
< nTmp
)
471 SeekOffset( pColOffset
, pE
->nOffset
, &pE
->nCol
, nOffsetTolerance
);
472 SCCOL nColBeforeSkip
= pE
->nCol
;
473 SkipLocked( pE
, FALSE
);
474 if ( pE
->nCol
!= nColBeforeSkip
)
476 SCCOL nCount
= (SCCOL
)pColOffset
->Count();
477 if ( nCount
<= pE
->nCol
)
479 pE
->nOffset
= (USHORT
) (*pColOffset
)[nCount
-1];
480 MakeCol( pColOffset
, pE
->nOffset
, pE
->nWidth
, nOffsetTolerance
, nOffsetTolerance
);
484 pE
->nOffset
= (USHORT
) (*pColOffset
)[pE
->nCol
];
488 if ( pE
->nWidth
&& SeekOffset( pColOffset
, pE
->nOffset
+ pE
->nWidth
, &nPos
, nOffsetTolerance
) )
489 pE
->nColOverlap
= (nPos
> pE
->nCol
? nPos
- pE
->nCol
: 1);
492 //2do: das muss nicht korrekt sein, ist aber..
495 xLockedList
->Join( ScRange( pE
->nCol
, pE
->nRow
, 0,
496 pE
->nCol
+ pE
->nColOverlap
- 1, pE
->nRow
+ pE
->nRowOverlap
- 1, 0 ) );
497 // MaxDimensions mitfuehren
498 SCCOL nColTmp
= pE
->nCol
+ pE
->nColOverlap
;
499 if ( nColMax
< nColTmp
)
501 SCROW nRowTmp
= pE
->nRow
+ pE
->nRowOverlap
;
502 if ( nRowMax
< nRowTmp
)
505 while ( (pS
= aStack
.Pop()) != 0 )
510 USHORT
ScHTMLLayoutParser::GetWidth( ScEEParseEntry
* pE
)
514 sal_Int32 nTmp
= ::std::min( static_cast<sal_Int32
>( pE
->nCol
-
515 nColCntStart
+ pE
->nColOverlap
),
516 static_cast<sal_Int32
>( pLocalColOffset
->Count() - 1));
517 SCCOL nPos
= (nTmp
< 0 ? 0 : static_cast<SCCOL
>(nTmp
));
518 USHORT nOff2
= (USHORT
) (*pLocalColOffset
)[nPos
];
519 if ( pE
->nOffset
< nOff2
)
520 return nOff2
- pE
->nOffset
;
525 void ScHTMLLayoutParser::SetWidths()
530 nTableWidth
= (USHORT
) aPageSize
.Width();
531 SCCOL nColsPerRow
= nMaxCol
- nColCntStart
;
532 if ( nColsPerRow
<= 0 )
534 if ( pLocalColOffset
->Count() <= 2 )
535 { // nur PageSize, es gab keine Width-Angabe
536 USHORT nWidth
= nTableWidth
/ static_cast<USHORT
>(nColsPerRow
);
537 USHORT nOff
= nColOffsetStart
;
538 pLocalColOffset
->Remove( (USHORT
)0, pLocalColOffset
->Count() );
539 for ( nCol
= 0; nCol
<= nColsPerRow
; ++nCol
, nOff
= nOff
+ nWidth
)
541 MakeColNoRef( pLocalColOffset
, nOff
, 0, 0, 0 );
543 nTableWidth
= (USHORT
)((*pLocalColOffset
)[pLocalColOffset
->Count() -1 ] - (*pLocalColOffset
)[0]);
544 pE
= pList
->Seek( nFirstTableCell
);
547 if ( pE
->nTab
== nTable
)
549 pE
->nOffset
= (USHORT
) (*pLocalColOffset
)[pE
->nCol
- nColCntStart
];
550 pE
->nWidth
= 0; // to be recalculated later
556 { // einige mit einige ohne Width
557 pE
= pList
->Seek( nFirstTableCell
);
558 // #36350# wieso eigentlich kein pE ?!?
561 USHORT
* pOffsets
= new USHORT
[ nColsPerRow
+1 ];
562 memset( pOffsets
, 0, (nColsPerRow
+1) * sizeof(USHORT
) );
563 USHORT
* pWidths
= new USHORT
[ nColsPerRow
];
564 memset( pWidths
, 0, nColsPerRow
* sizeof(USHORT
) );
565 pOffsets
[0] = nColOffsetStart
;
568 if ( pE
->nTab
== nTable
&& pE
->nWidth
)
570 nCol
= pE
->nCol
- nColCntStart
;
571 if ( nCol
< nColsPerRow
)
573 if ( pE
->nColOverlap
== 1 )
575 if ( pWidths
[nCol
] < pE
->nWidth
)
576 pWidths
[nCol
] = pE
->nWidth
;
579 { // try to find a single undefined width
583 SCCOL nStop
= Min( static_cast<SCCOL
>(nCol
+ pE
->nColOverlap
), nColsPerRow
);
584 for ( ; nCol
< nStop
; nCol
++ )
587 nTotal
= nTotal
+ pWidths
[nCol
];
599 if ( bFound
&& pE
->nWidth
> nTotal
)
600 pWidths
[nHere
] = pE
->nWidth
- nTotal
;
608 for ( nCol
= 0; nCol
< nColsPerRow
; nCol
++ )
611 nWidths
= nWidths
+ pWidths
[nCol
];
617 USHORT nW
= ((nWidths
< nTableWidth
) ?
618 ((nTableWidth
- nWidths
) / nUnknown
) :
619 (nTableWidth
/ nUnknown
));
620 for ( nCol
= 0; nCol
< nColsPerRow
; nCol
++ )
622 if ( !pWidths
[nCol
] )
626 for ( nCol
= 1; nCol
<= nColsPerRow
; nCol
++ )
628 pOffsets
[nCol
] = pOffsets
[nCol
-1] + pWidths
[nCol
-1];
630 pLocalColOffset
->Remove( (USHORT
)0, pLocalColOffset
->Count() );
631 for ( nCol
= 0; nCol
<= nColsPerRow
; nCol
++ )
633 MakeColNoRef( pLocalColOffset
, pOffsets
[nCol
], 0, 0, 0 );
635 nTableWidth
= pOffsets
[nColsPerRow
] - pOffsets
[0];
637 pE
= pList
->Seek( nFirstTableCell
);
640 if ( pE
->nTab
== nTable
)
642 nCol
= pE
->nCol
- nColCntStart
;
643 DBG_ASSERT( nCol
< nColsPerRow
, "ScHTMLLayoutParser::SetWidths: column overflow" );
644 if ( nCol
< nColsPerRow
)
646 pE
->nOffset
= pOffsets
[nCol
];
647 nCol
= nCol
+ pE
->nColOverlap
;
648 if ( nCol
> nColsPerRow
)
650 pE
->nWidth
= pOffsets
[nCol
] - pE
->nOffset
;
660 if ( pLocalColOffset
->Count() )
662 USHORT nMax
= (USHORT
) (*pLocalColOffset
)[pLocalColOffset
->Count() - 1];
663 if ( aPageSize
.Width() < nMax
)
664 aPageSize
.Width() = nMax
;
666 pE
= pList
->Seek( nFirstTableCell
);
669 if ( pE
->nTab
== nTable
)
673 pE
->nWidth
= GetWidth( pE
);
674 DBG_ASSERT( pE
->nWidth
, "SetWidths: pE->nWidth == 0" );
676 MakeCol( pColOffset
, pE
->nOffset
, pE
->nWidth
, nOffsetTolerance
, nOffsetTolerance
);
683 void ScHTMLLayoutParser::Colonize( ScEEParseEntry
* pE
)
685 if ( pE
->nCol
== SCCOL_MAX
)
687 if ( pE
->nRow
== SCROW_MAX
)
689 SCCOL nCol
= pE
->nCol
;
690 SkipLocked( pE
); // Spaltenverdraengung nach rechts
692 if ( nCol
< pE
->nCol
)
694 nCol
= pE
->nCol
- nColCntStart
;
695 SCCOL nCount
= static_cast<SCCOL
>(pLocalColOffset
->Count());
697 nColOffset
= (USHORT
) (*pLocalColOffset
)[nCol
];
699 nColOffset
= (USHORT
) (*pLocalColOffset
)[nCount
- 1];
701 pE
->nOffset
= nColOffset
;
702 USHORT nWidth
= GetWidth( pE
);
703 MakeCol( pLocalColOffset
, pE
->nOffset
, nWidth
, nOffsetTolerance
, nOffsetTolerance
);
706 nColOffset
= pE
->nOffset
+ nWidth
;
707 if ( nTableWidth
< nColOffset
- nColOffsetStart
)
708 nTableWidth
= nColOffset
- nColOffsetStart
;
712 void ScHTMLLayoutParser::CloseEntry( ImportInfo
* pInfo
)
716 { // in TableOff vom Stack geholt
717 bTabInTabCell
= FALSE
;
718 if ( pList
->GetPos( pActEntry
) == LIST_ENTRY_NOTFOUND
)
720 NewActEntry( pList
->Last() ); // neuer freifliegender pActEntry
723 if ( pActEntry
->nTab
== 0 )
724 pActEntry
->nWidth
= (USHORT
) aPageSize
.Width();
725 Colonize( pActEntry
);
726 nColCnt
= pActEntry
->nCol
+ pActEntry
->nColOverlap
;
727 if ( nMaxCol
< nColCnt
)
728 nMaxCol
= nColCnt
; // TableStack MaxCol
729 if ( nColMax
< nColCnt
)
730 nColMax
= nColCnt
; // globales MaxCol fuer ScEEParser GetDimensions!
731 EntryEnd( pActEntry
, pInfo
->aSelection
);
732 ESelection
& rSel
= pActEntry
->aSel
;
733 while ( rSel
.nStartPara
< rSel
.nEndPara
734 && pEdit
->GetTextLen( rSel
.nStartPara
) == 0 )
735 { // vorgehaengte Leerabsaetze strippen
738 while ( rSel
.nEndPos
== 0 && rSel
.nEndPara
> rSel
.nStartPara
)
739 { // angehaengte Leerabsaetze strippen
741 rSel
.nEndPos
= pEdit
->GetTextLen( rSel
.nEndPara
);
743 if ( rSel
.nStartPara
> rSel
.nEndPara
)
744 { // gibt GPF in CreateTextObject
745 DBG_ERRORFILE( "CloseEntry: EditEngine ESelection Start > End" );
746 rSel
.nEndPara
= rSel
.nStartPara
;
748 if ( rSel
.HasRange() )
749 pActEntry
->aItemSet
.Put( SfxBoolItem( ATTR_LINEBREAK
, TRUE
) );
750 pList
->Insert( pActEntry
, LIST_APPEND
);
751 NewActEntry( pActEntry
); // neuer freifliegender pActEntry
755 IMPL_LINK( ScHTMLLayoutParser
, HTMLImportHdl
, ImportInfo
*, pInfo
)
757 #if defined(erDEBUG) //|| 1
758 static ESelection aDebugSel
;
759 static String aDebugStr
;
760 static SvFileStream
* pDebugStrm
= NULL
;
761 static ULONG nDebugStrmPos
= 0;
762 static ULONG nDebugCount
= 0;
763 static ULONG nDebugCountAll
= 0;
764 static const sal_Char
* sDebugState
[15] = {
765 "RTFIMP_START", "RTFIMP_END",
766 "RTFIMP_NEXTTOKEN", "RTFIMP_UNKNOWNATTR",
770 "HTMLIMP_START", "HTMLIMP_END",
771 "HTMLIMP_NEXTTOKEN", "HTMLIMP_UNKNOWNATTR",
773 "HTMLIMP_INSERTTEXT",
774 "HTMLIMP_INSERTPARA", "HTMLIMP_INSERTFIELD"
778 if ( pInfo
->eState
!= HTMLIMP_NEXTTOKEN
// not too much
779 || pInfo
->nToken
== HTML_TABLE_ON
780 || pInfo
->nToken
== HTML_TABLE_OFF
781 || pInfo
->nToken
== HTML_TABLEROW_ON
782 || pInfo
->nToken
== HTML_TABLEROW_OFF
783 || pInfo
->nToken
== HTML_TABLEHEADER_ON
784 || pInfo
->nToken
== HTML_TABLEHEADER_OFF
785 || pInfo
->nToken
== HTML_TABLEDATA_ON
786 || pInfo
->nToken
== HTML_TABLEDATA_OFF
787 || !aDebugSel
.IsEqual( pInfo
->aSelection
)
788 || pInfo
->aText
.Len() || aDebugStr
!= pInfo
->aText
791 aDebugSel
= pInfo
->aSelection
;
792 aDebugStr
= pInfo
->aText
;
796 pDebugStrm
= new SvFileStream( "d:\\erdbghtm.log",
797 STREAM_WRITE
| STREAM_TRUNC
);
801 pDebugStrm
->ReOpen();
802 pDebugStrm
->Seek( nDebugStrmPos
);
804 SvFileStream
& rS
= *pDebugStrm
;
805 rS
.WriteNumber( nDebugCountAll
); rS
<< ".: ";
806 rS
.WriteNumber( nDebugCount
); rS
<< ". State: ";
807 rS
.WriteNumber( (USHORT
) pInfo
->eState
);
808 rS
<< ' ' << sDebugState
[pInfo
->eState
] << endl
;
809 rS
<< "SPar,SPos EPar,EPos: ";
810 rS
.WriteNumber( aDebugSel
.nStartPara
); rS
<< ',';
811 rS
.WriteNumber( aDebugSel
.nStartPos
); rS
<< ' ';
812 rS
.WriteNumber( aDebugSel
.nEndPara
); rS
<< ',';
813 rS
.WriteNumber( aDebugSel
.nEndPos
); rS
<< endl
;
814 if ( aDebugStr
.Len() )
816 rS
<< "Text: \"" << aDebugStr
<< '\"' << endl
;
820 rS
<< "Text:" << endl
;
822 rS
<< "Token: "; rS
.WriteNumber( pInfo
->nToken
);
823 switch ( pInfo
->nToken
)
826 rS
<< " HTML_TABLE_ON";
829 rS
<< " HTML_TABLE_OFF";
831 case HTML_TABLEROW_ON
:
832 rS
<< " HTML_TABLEROW_ON";
834 case HTML_TABLEROW_OFF
:
835 rS
<< " HTML_TABLEROW_OFF";
837 case HTML_TABLEHEADER_ON
:
838 rS
<< " HTML_TABLEHEADER_ON";
840 case HTML_TABLEHEADER_OFF
:
841 rS
<< " HTML_TABLEHEADER_OFF";
843 case HTML_TABLEDATA_ON
:
844 rS
<< " HTML_TABLEDATA_ON";
846 case HTML_TABLEDATA_OFF
:
847 rS
<< " HTML_TABLEDATA_OFF";
850 rS
<< " Value: "; rS
.WriteNumber( pInfo
->nTokenValue
);
852 nDebugStrmPos
= pDebugStrm
->Tell();
856 switch ( pInfo
->eState
)
858 case HTMLIMP_NEXTTOKEN
:
861 case HTMLIMP_UNKNOWNATTR
:
867 if ( pInfo
->aSelection
.nEndPos
)
869 // If text remains: create paragraph, without calling CloseEntry().
870 if( bInCell
) // #108269# ...but only in opened table cells.
878 while ( nTableLevel
> 0 )
879 TableOff( pInfo
); // close tables, if </TABLE> missing
881 case HTMLIMP_SETATTR
:
883 case HTMLIMP_INSERTTEXT
:
885 case HTMLIMP_INSERTPARA
:
886 if ( nTableLevel
< 1 )
892 case HTMLIMP_INSERTFIELD
:
895 DBG_ERRORFILE("HTMLImportHdl: unknown ImportInfo.eState");
901 // Groesster Gemeinsamer Teiler nach Euklid (Kettendivision)
902 // Sonderfall: 0 und irgendwas geben 1
903 SCROW
lcl_GGT( SCROW a
, SCROW b
)
910 a
-= SCROW(a
/ b
) * b
;
912 b
-= SCROW(b
/ a
) * a
;
914 return ((a
!= 0) ? a
: b
);
918 // Kleinstes Gemeinsames Vielfaches: a * b / GGT(a,b)
919 SCROW
lcl_KGV( SCROW a
, SCROW b
)
921 if ( a
> b
) // Ueberlauf unwahrscheinlicher machen
922 return (a
/ lcl_GGT(a
,b
)) * b
;
924 return (b
/ lcl_GGT(a
,b
)) * a
;
928 void ScHTMLLayoutParser::TableDataOn( ImportInfo
* pInfo
)
934 DBG_ERROR( "Dummbatz-Dok! <TH> oder <TD> ohne vorheriges <TABLE>" );
938 BOOL bHorJustifyCenterTH
= (pInfo
->nToken
== HTML_TABLEHEADER_ON
);
939 const HTMLOptions
* pOptions
= ((HTMLParser
*)pInfo
->pParser
)->GetOptions();
940 USHORT nArrLen
= pOptions
->Count();
941 for ( USHORT i
= 0; i
< nArrLen
; i
++ )
943 const HTMLOption
* pOption
= (*pOptions
)[i
];
944 switch( pOption
->GetToken() )
948 pActEntry
->nColOverlap
= ( SCCOL
) pOption
->GetString().ToInt32();
953 pActEntry
->nRowOverlap
= ( SCROW
) pOption
->GetString().ToInt32();
958 bHorJustifyCenterTH
= FALSE
;
959 SvxCellHorJustify eVal
;
960 const String
& rOptVal
= pOption
->GetString();
961 if ( rOptVal
.CompareIgnoreCaseToAscii( OOO_STRING_SVTOOLS_HTML_AL_right
) == COMPARE_EQUAL
)
962 eVal
= SVX_HOR_JUSTIFY_RIGHT
;
963 else if ( rOptVal
.CompareIgnoreCaseToAscii( OOO_STRING_SVTOOLS_HTML_AL_center
) == COMPARE_EQUAL
)
964 eVal
= SVX_HOR_JUSTIFY_CENTER
;
965 else if ( rOptVal
.CompareIgnoreCaseToAscii( OOO_STRING_SVTOOLS_HTML_AL_left
) == COMPARE_EQUAL
)
966 eVal
= SVX_HOR_JUSTIFY_LEFT
;
968 eVal
= SVX_HOR_JUSTIFY_STANDARD
;
969 if ( eVal
!= SVX_HOR_JUSTIFY_STANDARD
)
970 pActEntry
->aItemSet
.Put( SvxHorJustifyItem( eVal
, ATTR_HOR_JUSTIFY
) );
975 SvxCellVerJustify eVal
;
976 const String
& rOptVal
= pOption
->GetString();
977 if ( rOptVal
.CompareIgnoreCaseToAscii( OOO_STRING_SVTOOLS_HTML_VA_top
) == COMPARE_EQUAL
)
978 eVal
= SVX_VER_JUSTIFY_TOP
;
979 else if ( rOptVal
.CompareIgnoreCaseToAscii( OOO_STRING_SVTOOLS_HTML_VA_middle
) == COMPARE_EQUAL
)
980 eVal
= SVX_VER_JUSTIFY_CENTER
;
981 else if ( rOptVal
.CompareIgnoreCaseToAscii( OOO_STRING_SVTOOLS_HTML_VA_bottom
) == COMPARE_EQUAL
)
982 eVal
= SVX_VER_JUSTIFY_BOTTOM
;
984 eVal
= SVX_VER_JUSTIFY_STANDARD
;
985 pActEntry
->aItemSet
.Put( SvxVerJustifyItem( eVal
, ATTR_VER_JUSTIFY
) );
990 pActEntry
->nWidth
= GetWidthPixel( pOption
);
996 pOption
->GetColor( aColor
);
997 pActEntry
->aItemSet
.Put(
998 SvxBrushItem( aColor
, ATTR_BACKGROUND
) );
1003 pActEntry
->pValStr
= new String( pOption
->GetString() );
1008 pActEntry
->pNumStr
= new String( pOption
->GetString() );
1013 pActEntry
->nCol
= nColCnt
;
1014 pActEntry
->nRow
= nRowCnt
;
1015 pActEntry
->nTab
= nTable
;
1017 if ( bHorJustifyCenterTH
)
1018 pActEntry
->aItemSet
.Put(
1019 SvxHorJustifyItem( SVX_HOR_JUSTIFY_CENTER
, ATTR_HOR_JUSTIFY
) );
1023 void ScHTMLLayoutParser::TableRowOn( ImportInfo
* pInfo
)
1025 if ( nColCnt
> nColCntStart
)
1026 NextRow( pInfo
); // das optionale TableRowOff war nicht
1027 nColOffset
= nColOffsetStart
;
1031 void ScHTMLLayoutParser::TableRowOff( ImportInfo
* pInfo
)
1037 void ScHTMLLayoutParser::TableDataOff( ImportInfo
* pInfo
)
1040 CloseEntry( pInfo
); // aber nur wenn's auch eine war
1044 void ScHTMLLayoutParser::TableOn( ImportInfo
* pInfo
)
1047 bool bBorderOn
= false;
1049 if ( ++nTableLevel
> 1 )
1051 USHORT nTmpColOffset
= nColOffset
; // wird in Colonize noch angepasst
1052 Colonize( pActEntry
);
1053 aTableStack
.Push( new ScHTMLTableStackEntry(
1054 pActEntry
, xLockedList
, pLocalColOffset
, nFirstTableCell
,
1055 nColCnt
, nRowCnt
, nColCntStart
, nMaxCol
, nTable
,
1056 nTableWidth
, nColOffset
, nColOffsetStart
,
1058 USHORT nLastWidth
= nTableWidth
;
1059 nTableWidth
= GetWidth( pActEntry
);
1060 if ( nTableWidth
== nLastWidth
&& nMaxCol
- nColCntStart
> 1 )
1061 { // es muss mehr als einen geben, also kann dieser nicht alles sein
1062 nTableWidth
= nLastWidth
/ static_cast<USHORT
>((nMaxCol
- nColCntStart
));
1064 nLastWidth
= nTableWidth
;
1065 if ( pInfo
->nToken
== HTML_TABLE_ON
)
1066 { // es kann auch TD oder TH sein, wenn es vorher kein TABLE gab
1067 const HTMLOptions
* pOptions
= ((HTMLParser
*)pInfo
->pParser
)->GetOptions();
1068 USHORT nArrLen
= pOptions
->Count();
1069 for ( USHORT i
= 0; i
< nArrLen
; i
++ )
1071 const HTMLOption
* pOption
= (*pOptions
)[i
];
1072 switch( pOption
->GetToken() )
1075 { // Prozent: von Dokumentbreite bzw. aeusserer Zelle
1076 nTableWidth
= GetWidthPixel( pOption
);
1080 bBorderOn
= ((pOption
->GetString().Len() == 0) || (pOption
->GetNumber() != 0));
1083 aTabName
.Assign( pOption
->GetString() );
1089 if ( bTabInTabCell
&& !(nTableWidth
< nLastWidth
) )
1090 { // mehrere Tabellen in einer Zelle, untereinander
1091 bTabInTabCell
= FALSE
;
1095 { // in dieser Zelle geht's los, oder nebeneinander
1096 bTabInTabCell
= FALSE
;
1097 nColCntStart
= nColCnt
;
1098 nColOffset
= nTmpColOffset
;
1099 nColOffsetStart
= nColOffset
;
1102 ScEEParseEntry
* pE
= pList
->Last();
1103 NewActEntry( pE
); // neuer freifliegender pActEntry
1104 xLockedList
= new ScRangeList
;
1107 { // einfache Table auf Dokumentebene
1108 EntryEnd( pActEntry
, pInfo
->aSelection
);
1109 if ( pActEntry
->aSel
.HasRange() )
1110 { // noch fliegender Text
1111 CloseEntry( pInfo
);
1114 aTableStack
.Push( new ScHTMLTableStackEntry(
1115 pActEntry
, xLockedList
, pLocalColOffset
, nFirstTableCell
,
1116 nColCnt
, nRowCnt
, nColCntStart
, nMaxCol
, nTable
,
1117 nTableWidth
, nColOffset
, nColOffsetStart
,
1119 // As soon as we have multiple tables we need to be tolerant with the offsets.
1121 nOffsetTolerance
= SC_HTML_OFFSET_TOLERANCE_LARGE
;
1123 if ( pInfo
->nToken
== HTML_TABLE_ON
)
1124 { // es kann auch TD oder TH sein, wenn es vorher kein TABLE gab
1125 const HTMLOptions
* pOptions
= ((HTMLParser
*)pInfo
->pParser
)->GetOptions();
1126 USHORT nArrLen
= pOptions
->Count();
1127 for ( USHORT i
= 0; i
< nArrLen
; i
++ )
1129 const HTMLOption
* pOption
= (*pOptions
)[i
];
1130 switch( pOption
->GetToken() )
1133 { // Prozent: von Dokumentbreite bzw. aeusserer Zelle
1134 nTableWidth
= GetWidthPixel( pOption
);
1138 bBorderOn
= ((pOption
->GetString().Len() == 0) || (pOption
->GetNumber() != 0));
1141 aTabName
.Assign( pOption
->GetString() );
1147 nTable
= ++nMaxTable
;
1149 nFirstTableCell
= pList
->Count();
1151 pLocalColOffset
= new ScHTMLColOffset
;
1152 MakeColNoRef( pLocalColOffset
, nColOffsetStart
, 0, 0, 0 );
1156 void ScHTMLLayoutParser::TableOff( ImportInfo
* pInfo
)
1159 CloseEntry( pInfo
);
1160 if ( nColCnt
> nColCntStart
)
1161 TableRowOff( pInfo
); // das optionale TableRowOff war nicht
1164 DBG_ERROR( "Dummbatz-Dok! </TABLE> ohne oeffnendes <TABLE>" );
1167 if ( --nTableLevel
> 0 )
1168 { // Table in Table beendet
1169 ScHTMLTableStackEntry
* pS
= aTableStack
.Pop();
1172 ScEEParseEntry
* pE
= pS
->pCellEntry
;
1173 SCROW nRows
= nRowCnt
- pS
->nRowCnt
;
1175 { // Groesse der Tabelle an dieser Position eintragen
1176 SCROW nRow
= pS
->nRowCnt
;
1177 USHORT nTab
= pS
->nTable
;
1179 pTables
= new Table
;
1180 // Hoehen der aeusseren Table
1181 Table
* pTab1
= (Table
*) pTables
->Get( nTab
);
1185 pTables
->Insert( nTab
, pTab1
);
1187 SCROW nRowSpan
= pE
->nRowOverlap
;
1189 SCROW nRowsPerRow1
; // aeussere Table
1190 SCROW nRowsPerRow2
; // innere Table
1192 { // KGV auf das sich aussere und innere Zeilen
1194 nRowKGV
= lcl_KGV( nRowSpan
, nRows
);
1195 nRowsPerRow1
= nRowKGV
/ nRowSpan
;
1196 nRowsPerRow2
= nRowKGV
/ nRows
;
1200 nRowKGV
= nRowsPerRow1
= nRows
;
1203 Table
* pTab2
= NULL
;
1204 if ( nRowsPerRow2
> 1 )
1205 { // Hoehen der inneren Table
1207 pTables
->Insert( nTable
, pTab2
);
1209 // void* Data-Entry der Table-Class fuer das
1210 // Hoehen-Mapping missbrauchen
1213 if ( nRowsPerRow1
> 1 )
1215 for ( SCROW j
=0; j
< nRowSpan
; j
++ )
1217 ULONG nRowKey
= nRow
+ j
;
1218 SCROW nR
= (SCROW
)(ULONG
)pTab1
->Get( nRowKey
);
1220 pTab1
->Insert( nRowKey
, (void*) nRowsPerRow1
);
1221 else if ( nRowsPerRow1
> nR
)
1222 pTab1
->Replace( nRowKey
, (void*) nRowsPerRow1
);
1223 //2do: wie geht das noch besser?
1224 else if ( nRowsPerRow1
< nR
&& nRowSpan
== 1
1225 && nTable
== nMaxTable
)
1226 { // Platz uebrig, evtl. besser mergen
1227 SCROW nAdd
= nRowsPerRow1
- (nR
% nRowsPerRow1
);
1229 if ( (nR
% nRows
) == 0 )
1230 { // nur wenn abbildbar
1231 SCROW nR2
= (SCROW
)(ULONG
)pTab1
->Get( nRowKey
+1 );
1233 { // nur wenn wirklich Platz
1234 pTab1
->Replace( nRowKey
, (void*) nR
);
1235 pTab1
->Replace( nRowKey
+1, (void*) (nR2
- nAdd
) );
1236 nRowsPerRow2
= nR
/ nRows
;
1242 if ( nRowsPerRow2
> 1 )
1245 { // nRowsPerRow2 kann erhoeht worden sein
1247 pTables
->Insert( nTable
, pTab2
);
1249 for ( SCROW j
=0; j
< nRows
; j
++ )
1251 ULONG nRowKey
= nRow
+ j
;
1252 SCROW nR
= (SCROW
)(ULONG
)pTab2
->Get( nRowKey
);
1254 pTab2
->Insert( nRowKey
, (void*) nRowsPerRow2
);
1255 else if ( nRowsPerRow2
> nR
)
1256 pTab2
->Replace( nRowKey
, (void*) nRowsPerRow2
);
1265 pE
->nWidth
= nTableWidth
;
1266 else if ( pE
->nWidth
< nTableWidth
)
1268 USHORT nOldOffset
= pE
->nOffset
+ pE
->nWidth
;
1269 USHORT nNewOffset
= pE
->nOffset
+ nTableWidth
;
1270 ModifyOffset( pS
->pLocalColOffset
, nOldOffset
, nNewOffset
, nOffsetTolerance
);
1271 USHORT nTmp
= nNewOffset
- pE
->nOffset
- pE
->nWidth
;
1272 pE
->nWidth
= nNewOffset
- pE
->nOffset
;
1273 pS
->nTableWidth
= pS
->nTableWidth
+ nTmp
;
1274 if ( pS
->nColOffset
>= nOldOffset
)
1275 pS
->nColOffset
= pS
->nColOffset
+ nTmp
;
1278 nColCnt
= pE
->nCol
+ pE
->nColOverlap
;
1279 nRowCnt
= pS
->nRowCnt
;
1280 nColCntStart
= pS
->nColCntStart
;
1281 nMaxCol
= pS
->nMaxCol
;
1282 nTable
= pS
->nTable
;
1283 nTableWidth
= pS
->nTableWidth
;
1284 nFirstTableCell
= pS
->nFirstTableCell
;
1285 nColOffset
= pS
->nColOffset
;
1286 nColOffsetStart
= pS
->nColOffsetStart
;
1287 bFirstRow
= pS
->bFirstRow
;
1288 xLockedList
= pS
->xLockedList
;
1289 if ( pLocalColOffset
)
1290 delete pLocalColOffset
;
1291 pLocalColOffset
= pS
->pLocalColOffset
;
1293 // pActEntry bleibt erstmal erhalten falls da noch 'ne Table in
1294 // der gleichen Zelle aufgemacht werden sollte (in HTML ist ja
1295 // alles moeglich..) und wird in CloseEntry deleted
1299 bTabInTabCell
= TRUE
;
1303 { // einfache Table beendet
1305 ScHTMLTableStackEntry
* pS
= aTableStack
.Pop();
1310 if ( pLocalColOffset
)
1311 delete pLocalColOffset
;
1312 pLocalColOffset
= pS
->pLocalColOffset
;
1319 void ScHTMLLayoutParser::Image( ImportInfo
* pInfo
)
1321 if ( !pActEntry
->pImageList
)
1322 pActEntry
->pImageList
= new ScHTMLImageList
;
1323 ScHTMLImageList
* pIL
= pActEntry
->pImageList
;
1324 ScHTMLImage
* pImage
= new ScHTMLImage
;
1325 pIL
->Insert( pImage
, LIST_APPEND
);
1326 const HTMLOptions
* pOptions
= ((HTMLParser
*)pInfo
->pParser
)->GetOptions();
1327 USHORT nArrLen
= pOptions
->Count();
1328 for ( USHORT i
= 0; i
< nArrLen
; i
++ )
1330 const HTMLOption
* pOption
= (*pOptions
)[i
];
1331 switch( pOption
->GetToken() )
1335 pImage
->aURL
= INetURLObject::GetAbsURL( aBaseURL
, pOption
->GetString() );
1340 if ( !pActEntry
->bHasGraphic
)
1341 { // ALT text only if not any image loaded
1342 if ( pActEntry
->aAltText
.Len() )
1343 pActEntry
->aAltText
.AppendAscii( "; " );
1344 pActEntry
->aAltText
+= pOption
->GetString();
1350 pImage
->aSize
.Width() = (long)pOption
->GetNumber();
1355 pImage
->aSize
.Height() = (long)pOption
->GetNumber();
1360 pImage
->aSpace
.X() = (long)pOption
->GetNumber();
1365 pImage
->aSpace
.Y() = (long)pOption
->GetNumber();
1370 if ( !pImage
->aURL
.Len() )
1372 DBG_ERRORFILE( "Image: Grafik ohne URL ?!?" );
1377 Graphic
* pGraphic
= new Graphic
;
1378 GraphicFilter
* pFilter
= ::GetGrfFilter();
1379 if ( GRFILTER_OK
!= ::LoadGraphic( pImage
->aURL
, pImage
->aFilterName
,
1380 *pGraphic
, pFilter
, &nFormat
) )
1383 return ; // dumm gelaufen
1385 if ( !pActEntry
->bHasGraphic
)
1386 { // discard any ALT text in this cell if we have any image
1387 pActEntry
->bHasGraphic
= TRUE
;
1388 pActEntry
->aAltText
.Erase();
1390 pImage
->aFilterName
= pFilter
->GetImportFormatName( nFormat
);
1391 pImage
->pGraphic
= pGraphic
;
1392 if ( !(pImage
->aSize
.Width() && pImage
->aSize
.Height()) )
1394 OutputDevice
* pDefaultDev
= Application::GetDefaultDevice();
1395 pImage
->aSize
= pDefaultDev
->LogicToPixel( pGraphic
->GetPrefSize(),
1396 pGraphic
->GetPrefMapMode() );
1398 if ( pIL
->Count() > 0 )
1401 for ( ScHTMLImage
* pI
= pIL
->First(); pI
; pI
= pIL
->Next() )
1403 if ( pI
->nDir
& nHorizontal
)
1404 nWidth
+= pI
->aSize
.Width() + 2 * pI
->aSpace
.X();
1408 if ( pActEntry
->nWidth
1409 && (nWidth
+ pImage
->aSize
.Width() + 2 * pImage
->aSpace
.X()
1410 >= pActEntry
->nWidth
) )
1411 pIL
->Last()->nDir
= nVertical
;
1416 void ScHTMLLayoutParser::ColOn( ImportInfo
* pInfo
)
1418 const HTMLOptions
* pOptions
= ((HTMLParser
*)pInfo
->pParser
)->GetOptions();
1419 USHORT nArrLen
= pOptions
->Count();
1420 for ( USHORT i
= 0; i
< nArrLen
; i
++ )
1422 const HTMLOption
* pOption
= (*pOptions
)[i
];
1423 switch( pOption
->GetToken() )
1427 USHORT nVal
= GetWidthPixel( pOption
);
1428 MakeCol( pLocalColOffset
, nColOffset
, nVal
, 0, 0 );
1429 nColOffset
= nColOffset
+ nVal
;
1437 USHORT
ScHTMLLayoutParser::GetWidthPixel( const HTMLOption
* pOption
)
1439 const String
& rOptVal
= pOption
->GetString();
1440 if ( rOptVal
.Search('%') != STRING_NOTFOUND
)
1442 USHORT nW
= (nTableWidth
? nTableWidth
: (USHORT
) aPageSize
.Width());
1443 return (USHORT
)((pOption
->GetNumber() * nW
) / 100);
1447 if ( rOptVal
.Search('*') != STRING_NOTFOUND
)
1448 { // relativ zu was?!?
1449 //2do: ColArray aller relativen Werte sammeln und dann MakeCol
1453 return (USHORT
)pOption
->GetNumber(); // Pixel
1458 void ScHTMLLayoutParser::AnchorOn( ImportInfo
* pInfo
)
1460 const HTMLOptions
* pOptions
= ((HTMLParser
*)pInfo
->pParser
)->GetOptions();
1461 USHORT nArrLen
= pOptions
->Count();
1462 for ( USHORT i
= 0; i
< nArrLen
; i
++ )
1464 const HTMLOption
* pOption
= (*pOptions
)[i
];
1465 switch( pOption
->GetToken() )
1469 pActEntry
->pName
= new String( pOption
->GetString() );
1477 BOOL
ScHTMLLayoutParser::IsAtBeginningOfText( ImportInfo
* pInfo
)
1479 ESelection
& rSel
= pActEntry
->aSel
;
1480 return rSel
.nStartPara
== rSel
.nEndPara
&&
1481 rSel
.nStartPara
<= pInfo
->aSelection
.nEndPara
&&
1482 pEdit
->GetTextLen( rSel
.nStartPara
) == 0;
1486 void ScHTMLLayoutParser::FontOn( ImportInfo
* pInfo
)
1488 if ( IsAtBeginningOfText( pInfo
) )
1489 { // nur am Anfang des Textes, gilt dann fuer gesamte Zelle
1490 const HTMLOptions
* pOptions
= ((HTMLParser
*)pInfo
->pParser
)->GetOptions();
1491 USHORT nArrLen
= pOptions
->Count();
1492 for ( USHORT i
= 0; i
< nArrLen
; i
++ )
1494 const HTMLOption
* pOption
= (*pOptions
)[i
];
1495 switch( pOption
->GetToken() )
1499 const String
& rFace
= pOption
->GetString();
1501 xub_StrLen nPos
= 0;
1502 while( nPos
!= STRING_NOTFOUND
)
1503 { // Fontliste, VCL: Semikolon als Separator, HTML: Komma
1504 String aFName
= rFace
.GetToken( 0, ',', nPos
);
1505 aFName
.EraseTrailingChars().EraseLeadingChars();
1506 if( aFontName
.Len() )
1508 aFontName
+= aFName
;
1510 if ( aFontName
.Len() )
1511 pActEntry
->aItemSet
.Put( SvxFontItem( FAMILY_DONTKNOW
,
1512 aFontName
, EMPTY_STRING
, PITCH_DONTKNOW
,
1513 RTL_TEXTENCODING_DONTKNOW
, ATTR_FONT
) );
1518 USHORT nSize
= (USHORT
) pOption
->GetNumber();
1521 else if ( nSize
> SC_HTML_FONTSIZES
)
1522 nSize
= SC_HTML_FONTSIZES
;
1523 pActEntry
->aItemSet
.Put( SvxFontHeightItem(
1524 maFontHeights
[nSize
-1], 100, ATTR_FONT_HEIGHT
) );
1530 pOption
->GetColor( aColor
);
1531 pActEntry
->aItemSet
.Put( SvxColorItem( aColor
, ATTR_FONT_COLOR
) );
1540 void ScHTMLLayoutParser::ProcToken( ImportInfo
* pInfo
)
1542 BOOL bSetLastToken
= TRUE
;
1543 switch ( pInfo
->nToken
)
1547 HTMLParser
* pParser
= (HTMLParser
*) pInfo
->pParser
;
1548 uno::Reference
<document::XDocumentPropertiesSupplier
> xDPS(
1549 mpDoc
->GetDocumentShell()->GetModel(), uno::UNO_QUERY_THROW
);
1550 pParser
->ParseMetaOptions(
1551 xDPS
->getDocumentProperties(),
1552 mpDoc
->GetDocumentShell()->GetHeaderAttributes() );
1561 case HTML_TITLE_OFF
:
1563 if ( bInTitle
&& aString
.Len() )
1565 // Leerzeichen von Zeilenumbruechen raus
1566 aString
.EraseLeadingChars();
1567 aString
.EraseTrailingChars();
1568 uno::Reference
<document::XDocumentPropertiesSupplier
> xDPS(
1569 mpDoc
->GetDocumentShell()->GetModel(),
1570 uno::UNO_QUERY_THROW
);
1571 xDPS
->getDocumentProperties()->setTitle(aString
);
1586 case HTML_TABLEHEADER_ON
: // oeffnet Zelle
1589 CloseEntry( pInfo
);
1590 // bInCell nicht TRUE setzen, das macht TableDataOn
1591 pActEntry
->aItemSet
.Put(
1592 SvxWeightItem( WEIGHT_BOLD
, ATTR_FONT_WEIGHT
) );
1594 case HTML_TABLEDATA_ON
: // oeffnet Zelle
1596 TableDataOn( pInfo
);
1599 case HTML_TABLEHEADER_OFF
:
1600 case HTML_TABLEDATA_OFF
: // schliesst Zelle
1602 TableDataOff( pInfo
);
1605 case HTML_TABLEROW_ON
: // vor erster Zelle in Row
1607 TableRowOn( pInfo
);
1610 case HTML_TABLEROW_OFF
: // nach letzter Zelle in Row
1612 TableRowOff( pInfo
);
1615 case HTML_TABLE_OFF
:
1625 case HTML_PARABREAK_OFF
:
1626 { // nach einem Image geht es vertikal weiter
1627 if ( pActEntry
->pImageList
&& pActEntry
->pImageList
->Count() > 0 )
1628 pActEntry
->pImageList
->Last()->nDir
= nVertical
;
1631 case HTML_ANCHOR_ON
:
1641 case HTML_BIGPRINT_ON
:
1643 //2do: aktuelle Fontgroesse merken und einen groesser
1644 if ( IsAtBeginningOfText( pInfo
) )
1645 pActEntry
->aItemSet
.Put( SvxFontHeightItem(
1646 maFontHeights
[3], 100, ATTR_FONT_HEIGHT
) );
1649 case HTML_SMALLPRINT_ON
:
1651 //2do: aktuelle Fontgroesse merken und einen kleiner
1652 if ( IsAtBeginningOfText( pInfo
) )
1653 pActEntry
->aItemSet
.Put( SvxFontHeightItem(
1654 maFontHeights
[0], 100, ATTR_FONT_HEIGHT
) );
1658 case HTML_STRONG_ON
:
1660 if ( IsAtBeginningOfText( pInfo
) )
1661 pActEntry
->aItemSet
.Put( SvxWeightItem( WEIGHT_BOLD
,
1662 ATTR_FONT_WEIGHT
) );
1665 case HTML_ITALIC_ON
:
1666 case HTML_EMPHASIS_ON
:
1667 case HTML_ADDRESS_ON
:
1668 case HTML_BLOCKQUOTE_ON
:
1669 case HTML_BLOCKQUOTE30_ON
:
1670 case HTML_CITIATION_ON
:
1671 case HTML_VARIABLE_ON
:
1673 if ( IsAtBeginningOfText( pInfo
) )
1674 pActEntry
->aItemSet
.Put( SvxPostureItem( ITALIC_NORMAL
,
1675 ATTR_FONT_POSTURE
) );
1678 case HTML_DEFINSTANCE_ON
:
1680 if ( IsAtBeginningOfText( pInfo
) )
1682 pActEntry
->aItemSet
.Put( SvxWeightItem( WEIGHT_BOLD
,
1683 ATTR_FONT_WEIGHT
) );
1684 pActEntry
->aItemSet
.Put( SvxPostureItem( ITALIC_NORMAL
,
1685 ATTR_FONT_POSTURE
) );
1689 case HTML_UNDERLINE_ON
:
1691 if ( IsAtBeginningOfText( pInfo
) )
1692 pActEntry
->aItemSet
.Put( SvxUnderlineItem( UNDERLINE_SINGLE
,
1693 ATTR_FONT_UNDERLINE
) );
1696 case HTML_TEXTTOKEN
:
1699 aString
+= pInfo
->aText
;
1703 { // nLastToken nicht setzen!
1704 bSetLastToken
= FALSE
;
1707 if ( bSetLastToken
)
1708 nLastToken
= pInfo
->nToken
;
1713 // ============================================================================
1714 // HTML DATA QUERY PARSER
1715 // ============================================================================
1717 template< typename Type
>
1718 inline Type
getLimitedValue( const Type
& rValue
, const Type
& rMin
, const Type
& rMax
)
1719 { return ::std::max( ::std::min( rValue
, rMax
), rMin
); }
1721 // ============================================================================
1723 /** Iterates through all HTML tag options of the passed ImportInfo struct. */
1724 class ScHTMLOptionIterator
1727 const HTMLOptions
* mpOptions
; /// The options array.
1728 const HTMLOption
* mpCurrOption
; /// Current option.
1729 sal_uInt16 mnCount
; /// Size of the options array.
1730 sal_uInt16 mnIndex
; /// Next option to return.
1733 explicit ScHTMLOptionIterator( const ImportInfo
& rInfo
);
1735 inline bool is() const { return mnIndex
< mnCount
; }
1736 inline const HTMLOption
* operator->() const { return mpCurrOption
; }
1737 inline const HTMLOption
& operator*() const { return *mpCurrOption
; }
1738 ScHTMLOptionIterator
& operator++();
1741 // ----------------------------------------------------------------------------
1743 ScHTMLOptionIterator::ScHTMLOptionIterator( const ImportInfo
& rInfo
) :
1749 const HTMLParser
* pParser
= static_cast< const HTMLParser
* >( rInfo
.pParser
);
1751 mpOptions
= pParser
->GetOptions();
1753 mnCount
= mpOptions
->Count();
1755 mpCurrOption
= mpOptions
->GetObject( 0 );
1758 ScHTMLOptionIterator
& ScHTMLOptionIterator::operator++()
1760 if( mnIndex
< mnCount
) ++mnIndex
;
1761 mpCurrOption
= (mnIndex
< mnCount
) ? mpOptions
->GetObject( mnIndex
) : 0;
1765 // ============================================================================
1767 ScHTMLEntry::ScHTMLEntry( const SfxItemSet
& rItemSet
, ScHTMLTableId nTableId
) :
1768 ScEEParseEntry( rItemSet
),
1769 mbImportAlways( false )
1772 bEntirePara
= false;
1775 bool ScHTMLEntry::HasContents() const
1777 return mbImportAlways
|| aSel
.HasRange() || aAltText
.Len() || IsTable();
1780 void ScHTMLEntry::AdjustStart( const ImportInfo
& rInfo
)
1782 // set start position
1783 aSel
.nStartPara
= rInfo
.aSelection
.nStartPara
;
1784 aSel
.nStartPos
= rInfo
.aSelection
.nStartPos
;
1785 // adjust end position
1786 if( (aSel
.nEndPara
< aSel
.nStartPara
) || ((aSel
.nEndPara
== aSel
.nStartPara
) && (aSel
.nEndPos
< aSel
.nStartPos
)) )
1788 aSel
.nEndPara
= aSel
.nStartPara
;
1789 aSel
.nEndPos
= aSel
.nStartPos
;
1793 void ScHTMLEntry::AdjustEnd( const ImportInfo
& rInfo
)
1795 DBG_ASSERT( (aSel
.nEndPara
< rInfo
.aSelection
.nEndPara
) ||
1796 ((aSel
.nEndPara
== rInfo
.aSelection
.nEndPara
) && (aSel
.nEndPos
<= rInfo
.aSelection
.nEndPos
)),
1797 "ScHTMLQueryParser::AdjustEntryEnd - invalid end position" );
1799 aSel
.nEndPara
= rInfo
.aSelection
.nEndPara
;
1800 aSel
.nEndPos
= rInfo
.aSelection
.nEndPos
;
1803 void ScHTMLEntry::Strip( const EditEngine
& rEditEngine
)
1805 // strip leading empty paragraphs
1806 while( (aSel
.nStartPara
< aSel
.nEndPara
) && (rEditEngine
.GetTextLen( aSel
.nStartPara
) <= aSel
.nStartPos
) )
1811 // strip trailing empty paragraphs
1812 while( (aSel
.nStartPara
< aSel
.nEndPara
) && (aSel
.nEndPos
== 0) )
1815 aSel
.nEndPos
= rEditEngine
.GetTextLen( aSel
.nEndPara
);
1819 // ============================================================================
1821 /** A map of ScHTMLTable objects.
1823 Organizes the tables with a unique table key. Stores nested tables inside
1824 the parent table and forms in this way a tree structure of tables. An
1825 instance of this class ownes the contained table objects and deletes them
1828 class ScHTMLTableMap
1831 typedef ::boost::shared_ptr
< ScHTMLTable
> ScHTMLTablePtr
;
1832 typedef ::std::map
< ScHTMLTableId
, ScHTMLTablePtr
> ScHTMLTableStdMap
;
1835 typedef ScHTMLTableStdMap::iterator iterator
;
1836 typedef ScHTMLTableStdMap::const_iterator const_iterator
;
1839 ScHTMLTable
& mrParentTable
; /// Reference to parent table.
1840 ScHTMLTableStdMap maTables
; /// Container for all table objects.
1841 mutable ScHTMLTable
* mpCurrTable
; /// Current table, used for fast search.
1844 explicit ScHTMLTableMap( ScHTMLTable
& rParentTable
);
1845 virtual ~ScHTMLTableMap();
1847 inline iterator
begin() { return maTables
.begin(); }
1848 inline const_iterator
begin() const { return maTables
.begin(); }
1849 inline iterator
end() { return maTables
.end(); }
1850 inline const_iterator
end() const { return maTables
.end(); }
1851 inline bool empty() const { return maTables
.empty(); }
1853 /** Returns the specified table.
1854 @param nTableId Unique identifier of the table.
1855 @param bDeep true = searches deep in all nested table; false = only in this container. */
1856 ScHTMLTable
* FindTable( ScHTMLTableId nTableId
, bool bDeep
= true ) const;
1858 /** Inserts a new table into the container. This container owns the created table.
1859 @param bPreFormText true = New table is based on preformatted text (<pre> tag). */
1860 ScHTMLTable
* CreateTable( const ImportInfo
& rInfo
, bool bPreFormText
);
1863 /** Sets a working table with its index for search optimization. */
1864 inline void SetCurrTable( ScHTMLTable
* pTable
) const
1865 { if( pTable
) mpCurrTable
= pTable
; }
1868 // ----------------------------------------------------------------------------
1870 ScHTMLTableMap::ScHTMLTableMap( ScHTMLTable
& rParentTable
) :
1871 mrParentTable( rParentTable
)
1875 ScHTMLTableMap::~ScHTMLTableMap()
1879 ScHTMLTable
* ScHTMLTableMap::FindTable( ScHTMLTableId nTableId
, bool bDeep
) const
1881 ScHTMLTable
* pResult
= 0;
1882 if( mpCurrTable
&& (nTableId
== mpCurrTable
->GetTableId()) )
1883 pResult
= mpCurrTable
; // cached table
1886 const_iterator aFind
= maTables
.find( nTableId
);
1887 if( aFind
!= maTables
.end() )
1888 pResult
= aFind
->second
.get(); // table from this container
1891 // not found -> search deep in nested tables
1892 if( !pResult
&& bDeep
)
1893 for( const_iterator aIter
= begin(), aEnd
= end(); !pResult
&& (aIter
!= aEnd
); ++aIter
)
1894 pResult
= aIter
->second
->FindNestedTable( nTableId
);
1896 SetCurrTable( pResult
);
1900 ScHTMLTable
* ScHTMLTableMap::CreateTable( const ImportInfo
& rInfo
, bool bPreFormText
)
1902 ScHTMLTable
* pTable
= new ScHTMLTable( mrParentTable
, rInfo
, bPreFormText
);
1903 maTables
[ pTable
->GetTableId() ].reset( pTable
);
1904 SetCurrTable( pTable
);
1908 // ----------------------------------------------------------------------------
1910 /** Simplified forward iterator for convenience.
1912 Before the iterator can be dereferenced, it must be tested with the is()
1913 method. The iterator may be invalid directly after construction (e.g. empty
1916 class ScHTMLTableIterator
1919 /** Constructs the iterator for the passed table map.
1920 @param pTableMap Pointer to the table map (is allowed to be NULL). */
1921 explicit ScHTMLTableIterator( const ScHTMLTableMap
* pTableMap
);
1923 inline bool is() const { return maIter
!= maEnd
; }
1924 inline ScHTMLTable
* operator->() { return maIter
->second
.get(); }
1925 inline ScHTMLTable
& operator*() { return *maIter
->second
; }
1926 inline ScHTMLTableIterator
& operator++() { ++maIter
; return *this; }
1929 ScHTMLTableMap::const_iterator maIter
;
1930 ScHTMLTableMap::const_iterator maEnd
;
1933 ScHTMLTableIterator::ScHTMLTableIterator( const ScHTMLTableMap
* pTableMap
)
1937 maIter
= pTableMap
->begin();
1938 maEnd
= pTableMap
->end();
1942 // ============================================================================
1944 ScHTMLTableAutoId::ScHTMLTableAutoId( ScHTMLTableId
& rnUnusedId
) :
1945 mnTableId( rnUnusedId
),
1946 mrnUnusedId( rnUnusedId
)
1951 // ----------------------------------------------------------------------------
1953 ScHTMLTable::ScHTMLTable( ScHTMLTable
& rParentTable
, const ImportInfo
& rInfo
, bool bPreFormText
) :
1954 mpParentTable( &rParentTable
),
1955 maTableId( rParentTable
.maTableId
.mrnUnusedId
),
1956 maTableItemSet( rParentTable
.GetCurrItemSet() ),
1957 mrEditEngine( rParentTable
.mrEditEngine
),
1958 mrEEParseList( rParentTable
.mrEEParseList
),
1959 mpCurrEntryList( 0 ),
1961 mbBorderOn( false ),
1962 mbPreFormText( bPreFormText
),
1965 mbPushEmptyLine( false )
1970 ImplDataOn( ScHTMLSize( 1, 1 ) );
1974 ProcessFormatOptions( maTableItemSet
, rInfo
);
1975 for( ScHTMLOptionIterator
aIter( rInfo
); aIter
.is(); ++aIter
)
1977 switch( aIter
->GetToken() )
1980 mbBorderOn
= ((aIter
->GetString().Len() == 0) || (aIter
->GetNumber() != 0));
1983 maTableName
= aIter
->GetString();
1989 CreateNewEntry( rInfo
);
1992 ScHTMLTable::ScHTMLTable( SfxItemPool
& rPool
, EditEngine
& rEditEngine
, ScEEParseList
& rEEParseList
, ScHTMLTableId
& rnUnusedId
) :
1994 maTableId( rnUnusedId
),
1995 maTableItemSet( rPool
),
1996 mrEditEngine( rEditEngine
),
1997 mrEEParseList( rEEParseList
),
1998 mpCurrEntryList( 0 ),
2000 mbBorderOn( false ),
2001 mbPreFormText( false ),
2004 mbPushEmptyLine( false )
2006 // open the first "cell" of the document
2008 ImplDataOn( ScHTMLSize( 1, 1 ) );
2009 mxCurrEntry
= CreateEntry();
2012 ScHTMLTable::~ScHTMLTable()
2016 const SfxItemSet
& ScHTMLTable::GetCurrItemSet() const
2018 // first try cell item set, then row item set, then table item set
2019 return mxDataItemSet
.get() ? *mxDataItemSet
: (mxRowItemSet
.get() ? *mxRowItemSet
: maTableItemSet
);
2022 ScHTMLSize
ScHTMLTable::GetSpan( const ScHTMLPos
& rCellPos
) const
2024 ScHTMLSize
aSpan( 1, 1 );
2025 ScRange
* pRange
= 0;
2026 if( ((pRange
= maVMergedCells
.Find( rCellPos
.MakeAddr() )) != 0) || ((pRange
= maHMergedCells
.Find( rCellPos
.MakeAddr() )) != 0) )
2027 aSpan
.Set( pRange
->aEnd
.Col() - pRange
->aStart
.Col() + 1, pRange
->aEnd
.Row() - pRange
->aStart
.Row() + 1 );
2031 ScHTMLTable
* ScHTMLTable::FindNestedTable( ScHTMLTableId nTableId
) const
2033 return mxNestedTables
.get() ? mxNestedTables
->FindTable( nTableId
, true ) : 0;
2036 void ScHTMLTable::PutItem( const SfxPoolItem
& rItem
)
2038 DBG_ASSERT( mxCurrEntry
.get(), "ScHTMLTable::PutItem - no current entry" );
2039 if( mxCurrEntry
.get() && mxCurrEntry
->IsEmpty() )
2040 mxCurrEntry
->GetItemSet().Put( rItem
);
2043 void ScHTMLTable::PutText( const ImportInfo
& rInfo
)
2045 DBG_ASSERT( mxCurrEntry
.get(), "ScHTMLTable::PutText - no current entry" );
2046 if( mxCurrEntry
.get() )
2048 if( !mxCurrEntry
->HasContents() && IsSpaceCharInfo( rInfo
) )
2049 mxCurrEntry
->AdjustStart( rInfo
);
2051 mxCurrEntry
->AdjustEnd( rInfo
);
2055 void ScHTMLTable::InsertPara( const ImportInfo
& rInfo
)
2057 if( mxCurrEntry
.get() && mbDataOn
&& !IsEmptyCell() )
2058 mxCurrEntry
->SetImportAlways();
2060 CreateNewEntry( rInfo
);
2061 InsertLeadingEmptyLine();
2064 void ScHTMLTable::BreakOn()
2066 // empty line, if <br> is at start of cell
2067 mbPushEmptyLine
= !mbPreFormText
&& mbDataOn
&& IsEmptyCell();
2070 void ScHTMLTable::HeadingOn()
2072 // call directly, InsertPara() has not been called before
2073 InsertLeadingEmptyLine();
2076 void ScHTMLTable::InsertLeadingEmptyLine()
2078 // empty line, if <p>, </p>, <h?>, or </h*> are not at start of cell
2079 mbPushEmptyLine
= !mbPreFormText
&& mbDataOn
&& !IsEmptyCell();
2082 void ScHTMLTable::AnchorOn()
2084 DBG_ASSERT( mxCurrEntry
.get(), "ScHTMLTable::AnchorOn - no current entry" );
2085 // don't skip entries with single hyperlinks
2086 if( mxCurrEntry
.get() )
2087 mxCurrEntry
->SetImportAlways();
2090 ScHTMLTable
* ScHTMLTable::TableOn( const ImportInfo
& rInfo
)
2093 return InsertNestedTable( rInfo
, false );
2096 ScHTMLTable
* ScHTMLTable::TableOff( const ImportInfo
& rInfo
)
2098 return mbPreFormText
? this : CloseTable( rInfo
);
2101 ScHTMLTable
* ScHTMLTable::PreOn( const ImportInfo
& rInfo
)
2104 return InsertNestedTable( rInfo
, true );
2107 ScHTMLTable
* ScHTMLTable::PreOff( const ImportInfo
& rInfo
)
2109 return mbPreFormText
? CloseTable( rInfo
) : this;
2112 void ScHTMLTable::RowOn( const ImportInfo
& rInfo
)
2114 PushEntry( rInfo
, true );
2115 if( mpParentTable
&& !mbPreFormText
) // no rows allowed in global and preformatted tables
2118 ProcessFormatOptions( *mxRowItemSet
, rInfo
);
2120 CreateNewEntry( rInfo
);
2123 void ScHTMLTable::RowOff( const ImportInfo
& rInfo
)
2125 PushEntry( rInfo
, true );
2126 if( mpParentTable
&& !mbPreFormText
) // no rows allowed in global and preformatted tables
2128 CreateNewEntry( rInfo
);
2131 void ScHTMLTable::DataOn( const ImportInfo
& rInfo
)
2133 PushEntry( rInfo
, true );
2134 if( mpParentTable
&& !mbPreFormText
) // no cells allowed in global and preformatted tables
2136 // read needed options from the <td> tag
2137 ScHTMLSize
aSpanSize( 1, 1 );
2138 ::std::auto_ptr
< String
> pValStr
, pNumStr
;
2139 for( ScHTMLOptionIterator
aIter( rInfo
); aIter
.is(); ++aIter
)
2141 switch( aIter
->GetToken() )
2143 case HTML_O_COLSPAN
:
2144 aSpanSize
.mnCols
= static_cast< SCCOL
>( getLimitedValue
< sal_Int32
>( aIter
->GetString().ToInt32(), 1, 256 ) );
2146 case HTML_O_ROWSPAN
:
2147 aSpanSize
.mnRows
= static_cast< SCROW
>( getLimitedValue
< sal_Int32
>( aIter
->GetString().ToInt32(), 1, 256 ) );
2150 pValStr
.reset( new String( aIter
->GetString() ) );
2153 pNumStr
.reset( new String( aIter
->GetString() ) );
2158 ImplDataOn( aSpanSize
);
2159 ProcessFormatOptions( *mxDataItemSet
, rInfo
);
2160 CreateNewEntry( rInfo
);
2161 mxCurrEntry
->pValStr
= pValStr
.release();
2162 mxCurrEntry
->pNumStr
= pNumStr
.release();
2165 CreateNewEntry( rInfo
);
2168 void ScHTMLTable::DataOff( const ImportInfo
& rInfo
)
2170 PushEntry( rInfo
, true );
2171 if( mpParentTable
&& !mbPreFormText
) // no cells allowed in global and preformatted tables
2173 CreateNewEntry( rInfo
);
2176 void ScHTMLTable::BodyOn( const ImportInfo
& rInfo
)
2178 bool bPushed
= PushEntry( rInfo
);
2179 if( !mpParentTable
)
2181 // #108269# do not start new row, if nothing (no title) precedes the body.
2182 if( bPushed
|| !mbRowOn
)
2184 if( bPushed
|| !mbDataOn
)
2185 ImplDataOn( ScHTMLSize( 1, 1 ) );
2186 ProcessFormatOptions( *mxDataItemSet
, rInfo
);
2188 CreateNewEntry( rInfo
);
2191 void ScHTMLTable::BodyOff( const ImportInfo
& rInfo
)
2194 if( !mpParentTable
)
2199 CreateNewEntry( rInfo
);
2202 ScHTMLTable
* ScHTMLTable::CloseTable( const ImportInfo
& rInfo
)
2204 if( mpParentTable
) // not allowed to close global table
2206 PushEntry( rInfo
, mbDataOn
);
2209 mpParentTable
->PushTableEntry( GetTableId() );
2210 mpParentTable
->CreateNewEntry( rInfo
);
2211 if( mbPreFormText
) // enclose preformatted table with empty lines in parent table
2212 mpParentTable
->InsertLeadingEmptyLine();
2213 return mpParentTable
;
2218 SCCOLROW
ScHTMLTable::GetDocSize( ScHTMLOrient eOrient
, SCCOLROW nCellPos
) const
2220 const ScSizeVec
& rSizes
= maCumSizes
[ eOrient
];
2221 size_t nIndex
= static_cast< size_t >( nCellPos
);
2222 if( nIndex
>= rSizes
.size() ) return 0;
2223 return (nIndex
== 0) ? rSizes
.front() : (rSizes
[ nIndex
] - rSizes
[ nIndex
- 1 ]);
2226 SCCOLROW
ScHTMLTable::GetDocSize( ScHTMLOrient eOrient
, SCCOLROW nCellBegin
, SCCOLROW nCellEnd
) const
2228 const ScSizeVec
& rSizes
= maCumSizes
[ eOrient
];
2229 size_t nBeginIdx
= static_cast< size_t >( ::std::max
< SCCOLROW
>( nCellBegin
, 0 ) );
2230 size_t nEndIdx
= static_cast< size_t >( ::std::min
< SCCOLROW
>( nCellEnd
, static_cast< SCCOLROW
>( rSizes
.size() ) ) );
2231 if (nBeginIdx
>= nEndIdx
) return 0;
2232 return rSizes
[ nEndIdx
- 1 ] - ((nBeginIdx
== 0) ? 0 : rSizes
[ nBeginIdx
- 1 ]);
2235 SCCOLROW
ScHTMLTable::GetDocSize( ScHTMLOrient eOrient
) const
2237 const ScSizeVec
& rSizes
= maCumSizes
[ eOrient
];
2238 return rSizes
.empty() ? 0 : rSizes
.back();
2241 ScHTMLSize
ScHTMLTable::GetDocSize( const ScHTMLPos
& rCellPos
) const
2243 ScHTMLSize aCellSpan
= GetSpan( rCellPos
);
2245 static_cast< SCCOL
>( GetDocSize( tdCol
, rCellPos
.mnCol
, rCellPos
.mnCol
+ aCellSpan
.mnCols
) ),
2246 static_cast< SCROW
>( GetDocSize( tdRow
, rCellPos
.mnRow
, rCellPos
.mnRow
+ aCellSpan
.mnRows
) ) );
2249 SCCOLROW
ScHTMLTable::GetDocPos( ScHTMLOrient eOrient
, SCCOLROW nCellPos
) const
2251 return maDocBasePos
.Get( eOrient
) + GetDocSize( eOrient
, 0, nCellPos
);
2254 ScHTMLPos
ScHTMLTable::GetDocPos( const ScHTMLPos
& rCellPos
) const
2257 static_cast< SCCOL
>( GetDocPos( tdCol
, rCellPos
.mnCol
) ),
2258 static_cast< SCROW
>( GetDocPos( tdRow
, rCellPos
.mnRow
) ) );
2261 void ScHTMLTable::GetDocRange( ScRange
& rRange
) const
2263 rRange
.aStart
= rRange
.aEnd
= maDocBasePos
.MakeAddr();
2264 rRange
.aEnd
.Move( static_cast< SCsCOL
>( GetDocSize( tdCol
) ) - 1, static_cast< SCsROW
>( GetDocSize( tdRow
) ) - 1, 0 );
2267 void ScHTMLTable::ApplyCellBorders( ScDocument
* pDoc
, const ScAddress
& rFirstPos
) const
2269 DBG_ASSERT( pDoc
, "ScHTMLTable::ApplyCellBorders - no document" );
2270 if( pDoc
&& mbBorderOn
)
2272 const SCCOL nLastCol
= maSize
.mnCols
- 1;
2273 const SCROW nLastRow
= maSize
.mnRows
- 1;
2274 const sal_uInt16 nOuterLine
= DEF_LINE_WIDTH_2
;
2275 const sal_uInt16 nInnerLine
= DEF_LINE_WIDTH_0
;
2276 SvxBorderLine aOuterLine
, aInnerLine
;
2277 aOuterLine
.SetColor( Color( COL_BLACK
) );
2278 aOuterLine
.SetOutWidth( nOuterLine
);
2279 aInnerLine
.SetColor( Color( COL_BLACK
) );
2280 aInnerLine
.SetOutWidth( nInnerLine
);
2281 SvxBoxItem
aBorderItem( ATTR_BORDER
);
2283 for( SCCOL nCol
= 0; nCol
<= nLastCol
; ++nCol
)
2285 SvxBorderLine
* pLeftLine
= (nCol
== 0) ? &aOuterLine
: &aInnerLine
;
2286 SvxBorderLine
* pRightLine
= (nCol
== nLastCol
) ? &aOuterLine
: &aInnerLine
;
2287 SCCOL nCellCol1
= static_cast< SCCOL
>( GetDocPos( tdCol
, nCol
) ) + rFirstPos
.Col();
2288 SCCOL nCellCol2
= nCellCol1
+ static_cast< SCCOL
>( GetDocSize( tdCol
, nCol
) ) - 1;
2289 for( SCROW nRow
= 0; nRow
<= nLastRow
; ++nRow
)
2291 SvxBorderLine
* pTopLine
= (nRow
== 0) ? &aOuterLine
: &aInnerLine
;
2292 SvxBorderLine
* pBottomLine
= (nRow
== nLastRow
) ? &aOuterLine
: &aInnerLine
;
2293 SCROW nCellRow1
= GetDocPos( tdRow
, nRow
) + rFirstPos
.Row();
2294 SCROW nCellRow2
= nCellRow1
+ GetDocSize( tdRow
, nRow
) - 1;
2295 for( SCCOL nCellCol
= nCellCol1
; nCellCol
<= nCellCol2
; ++nCellCol
)
2297 aBorderItem
.SetLine( (nCellCol
== nCellCol1
) ? pLeftLine
: 0, BOX_LINE_LEFT
);
2298 aBorderItem
.SetLine( (nCellCol
== nCellCol2
) ? pRightLine
: 0, BOX_LINE_RIGHT
);
2299 for( SCROW nCellRow
= nCellRow1
; nCellRow
<= nCellRow2
; ++nCellRow
)
2301 aBorderItem
.SetLine( (nCellRow
== nCellRow1
) ? pTopLine
: 0, BOX_LINE_TOP
);
2302 aBorderItem
.SetLine( (nCellRow
== nCellRow2
) ? pBottomLine
: 0, BOX_LINE_BOTTOM
);
2303 pDoc
->ApplyAttr( nCellCol
, nCellRow
, rFirstPos
.Tab(), aBorderItem
);
2310 for( ScHTMLTableIterator
aIter( mxNestedTables
.get() ); aIter
.is(); ++aIter
)
2311 aIter
->ApplyCellBorders( pDoc
, rFirstPos
);
2314 // ----------------------------------------------------------------------------
2316 bool ScHTMLTable::IsEmptyCell() const
2318 return mpCurrEntryList
&& mpCurrEntryList
->empty();
2321 bool ScHTMLTable::IsSpaceCharInfo( const ImportInfo
& rInfo
)
2323 return (rInfo
.nToken
== HTML_TEXTTOKEN
) && (rInfo
.aText
.Len() == 1) && (rInfo
.aText
.GetChar( 0 ) == ' ');
2326 ScHTMLTable::ScHTMLEntryPtr
ScHTMLTable::CreateEntry() const
2328 return ScHTMLEntryPtr( new ScHTMLEntry( GetCurrItemSet() ) );
2331 void ScHTMLTable::CreateNewEntry( const ImportInfo
& rInfo
)
2333 DBG_ASSERT( !mxCurrEntry
.get(), "ScHTMLTable::CreateNewEntry - old entry still present" );
2334 mxCurrEntry
= CreateEntry();
2335 mxCurrEntry
->aSel
= rInfo
.aSelection
;
2338 void ScHTMLTable::ImplPushEntryToList( ScHTMLEntryList
& rEntryList
, ScHTMLEntryPtr
& rxEntry
)
2340 // HTML entry list does not own the entries
2341 rEntryList
.push_back( rxEntry
.get() );
2342 // mrEEParseList (reference to member of ScEEParser) owns the entries
2343 mrEEParseList
.Insert( rxEntry
.release(), LIST_APPEND
);
2346 bool ScHTMLTable::PushEntry( ScHTMLEntryPtr
& rxEntry
)
2348 bool bPushed
= false;
2349 if( rxEntry
.get() && rxEntry
->HasContents() )
2351 if( mpCurrEntryList
)
2353 if( mbPushEmptyLine
)
2355 ScHTMLEntryPtr xEmptyEntry
= CreateEntry();
2356 ImplPushEntryToList( *mpCurrEntryList
, xEmptyEntry
);
2357 mbPushEmptyLine
= false;
2359 ImplPushEntryToList( *mpCurrEntryList
, rxEntry
);
2362 else if( mpParentTable
)
2364 bPushed
= mpParentTable
->PushEntry( rxEntry
);
2368 DBG_ERRORFILE( "ScHTMLTable::PushEntry - cannot push entry, no parent found" );
2374 bool ScHTMLTable::PushEntry( const ImportInfo
& rInfo
, bool bLastInCell
)
2376 DBG_ASSERT( mxCurrEntry
.get(), "ScHTMLTable::PushEntry - no current entry" );
2377 bool bPushed
= false;
2378 if( mxCurrEntry
.get() )
2380 mxCurrEntry
->AdjustEnd( rInfo
);
2381 mxCurrEntry
->Strip( mrEditEngine
);
2383 // import entry always, if it is the last in cell, and cell is still empty
2384 if( bLastInCell
&& IsEmptyCell() )
2386 mxCurrEntry
->SetImportAlways();
2387 // don't insert empty lines before single empty entries
2388 if( mxCurrEntry
->IsEmpty() )
2389 mbPushEmptyLine
= false;
2392 bPushed
= PushEntry( mxCurrEntry
);
2393 mxCurrEntry
.reset();
2398 bool ScHTMLTable::PushTableEntry( ScHTMLTableId nTableId
)
2400 DBG_ASSERT( nTableId
!= SC_HTML_GLOBAL_TABLE
, "ScHTMLTable::PushTableEntry - cannot push global table" );
2401 bool bPushed
= false;
2402 if( nTableId
!= SC_HTML_GLOBAL_TABLE
)
2404 ScHTMLEntryPtr
xEntry( new ScHTMLEntry( maTableItemSet
, nTableId
) );
2405 bPushed
= PushEntry( xEntry
);
2410 ScHTMLTable
* ScHTMLTable::GetExistingTable( ScHTMLTableId nTableId
) const
2412 ScHTMLTable
* pTable
= ((nTableId
!= SC_HTML_GLOBAL_TABLE
) && mxNestedTables
.get()) ?
2413 mxNestedTables
->FindTable( nTableId
, false ) : 0;
2414 DBG_ASSERT( pTable
|| (nTableId
== SC_HTML_GLOBAL_TABLE
), "ScHTMLTable::GetExistingTable - table not found" );
2418 ScHTMLTable
* ScHTMLTable::InsertNestedTable( const ImportInfo
& rInfo
, bool bPreFormText
)
2420 if( !mxNestedTables
.get() )
2421 mxNestedTables
.reset( new ScHTMLTableMap( *this ) );
2422 if( bPreFormText
) // enclose new preformatted table with empty lines
2423 InsertLeadingEmptyLine();
2424 return mxNestedTables
->CreateTable( rInfo
, bPreFormText
);
2427 void ScHTMLTable::InsertNewCell( const ScHTMLSize
& rSpanSize
)
2431 // find an unused cell
2432 while( (pRange
= maVMergedCells
.Find( maCurrCell
.MakeAddr() )) != 0 )
2433 maCurrCell
.mnCol
= pRange
->aEnd
.Col() + 1;
2434 mpCurrEntryList
= &maEntryMap
[ maCurrCell
];
2436 // try to find collisions, shrink existing ranges
2437 SCCOL nColEnd
= maCurrCell
.mnCol
+ rSpanSize
.mnCols
;
2438 for( ScAddress
aAddr( maCurrCell
.MakeAddr() ); aAddr
.Col() < nColEnd
; aAddr
.IncCol() )
2439 if( (pRange
= maVMergedCells
.Find( aAddr
)) != 0 )
2440 pRange
->aEnd
.SetRow( maCurrCell
.mnRow
- 1 );
2442 // insert the new range into the cell lists
2443 ScRange
aNewRange( maCurrCell
.MakeAddr() );
2444 aNewRange
.aEnd
.Move( rSpanSize
.mnCols
- 1, rSpanSize
.mnRows
- 1, 0 );
2445 if( rSpanSize
.mnCols
> 1 )
2447 maVMergedCells
.Append( aNewRange
);
2451 if( rSpanSize
.mnRows
> 1 )
2452 maHMergedCells
.Append( aNewRange
);
2453 maUsedCells
.Join( aNewRange
);
2456 // adjust table size
2457 maSize
.mnCols
= ::std::max
< SCCOL
>( maSize
.mnCols
, aNewRange
.aEnd
.Col() + 1 );
2458 maSize
.mnRows
= ::std::max
< SCROW
>( maSize
.mnRows
, aNewRange
.aEnd
.Row() + 1 );
2461 void ScHTMLTable::ImplRowOn()
2465 mxRowItemSet
.reset( new SfxItemSet( maTableItemSet
) );
2466 maCurrCell
.mnCol
= 0;
2471 void ScHTMLTable::ImplRowOff()
2477 mxRowItemSet
.reset();
2479 mbRowOn
= mbDataOn
= false;
2483 void ScHTMLTable::ImplDataOn( const ScHTMLSize
& rSpanSize
)
2489 mxDataItemSet
.reset( new SfxItemSet( *mxRowItemSet
) );
2490 InsertNewCell( rSpanSize
);
2492 mbPushEmptyLine
= false;
2495 void ScHTMLTable::ImplDataOff()
2499 mxDataItemSet
.reset();
2501 mpCurrEntryList
= 0;
2506 void ScHTMLTable::ProcessFormatOptions( SfxItemSet
& rItemSet
, const ImportInfo
& rInfo
)
2508 // special handling for table header cells
2509 if( rInfo
.nToken
== HTML_TABLEHEADER_ON
)
2511 rItemSet
.Put( SvxWeightItem( WEIGHT_BOLD
, ATTR_FONT_WEIGHT
) );
2512 rItemSet
.Put( SvxHorJustifyItem( SVX_HOR_JUSTIFY_CENTER
, ATTR_HOR_JUSTIFY
) );
2515 for( ScHTMLOptionIterator
aIter( rInfo
); aIter
.is(); ++aIter
)
2517 switch( aIter
->GetToken() )
2521 SvxCellHorJustify eVal
= SVX_HOR_JUSTIFY_STANDARD
;
2522 const String
& rOptVal
= aIter
->GetString();
2523 if( rOptVal
.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_AL_right
) )
2524 eVal
= SVX_HOR_JUSTIFY_RIGHT
;
2525 else if( rOptVal
.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_AL_center
) )
2526 eVal
= SVX_HOR_JUSTIFY_CENTER
;
2527 else if( rOptVal
.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_AL_left
) )
2528 eVal
= SVX_HOR_JUSTIFY_LEFT
;
2529 if( eVal
!= SVX_HOR_JUSTIFY_STANDARD
)
2530 rItemSet
.Put( SvxHorJustifyItem( eVal
, ATTR_HOR_JUSTIFY
) );
2536 SvxCellVerJustify eVal
= SVX_VER_JUSTIFY_STANDARD
;
2537 const String
& rOptVal
= aIter
->GetString();
2538 if( rOptVal
.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_VA_top
) )
2539 eVal
= SVX_VER_JUSTIFY_TOP
;
2540 else if( rOptVal
.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_VA_middle
) )
2541 eVal
= SVX_VER_JUSTIFY_CENTER
;
2542 else if( rOptVal
.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_VA_bottom
) )
2543 eVal
= SVX_VER_JUSTIFY_BOTTOM
;
2544 if( eVal
!= SVX_VER_JUSTIFY_STANDARD
)
2545 rItemSet
.Put( SvxVerJustifyItem( eVal
, ATTR_VER_JUSTIFY
) );
2549 case HTML_O_BGCOLOR
:
2552 aIter
->GetColor( aColor
);
2553 rItemSet
.Put( SvxBrushItem( aColor
, ATTR_BACKGROUND
) );
2560 void ScHTMLTable::SetDocSize( ScHTMLOrient eOrient
, SCCOLROW nCellPos
, SCCOLROW nSize
)
2562 DBG_ASSERT( nCellPos
>= 0, "ScHTMLTable::SetDocSize - unexpected negative position" );
2563 ScSizeVec
& rSizes
= maCumSizes
[ eOrient
];
2564 size_t nIndex
= static_cast< size_t >( nCellPos
);
2565 // expand with height/width == 1
2566 while( nIndex
>= rSizes
.size() )
2567 rSizes
.push_back( rSizes
.empty() ? 1 : (rSizes
.back() + 1) );
2568 // update size of passed position and all following
2569 SCsCOLROW nDiff
= nSize
- ((nIndex
== 0) ? rSizes
.front() : (rSizes
[ nIndex
] - rSizes
[ nIndex
- 1 ]));
2571 for( ScSizeVec::iterator aIt
= rSizes
.begin() + nIndex
, aEnd
= rSizes
.end(); aIt
!= aEnd
; ++aIt
)
2575 void ScHTMLTable::CalcNeededDocSize(
2576 ScHTMLOrient eOrient
, SCCOLROW nCellPos
, SCCOLROW nCellSpan
, SCCOLROW nRealDocSize
)
2578 SCCOLROW nDiffSize
= 0;
2579 // in merged columns/rows: reduce needed size by size of leading columns
2580 while( nCellSpan
> 1 )
2582 nDiffSize
+= GetDocSize( eOrient
, nCellPos
);
2586 // set remaining needed size to last column/row
2587 nRealDocSize
-= ::std::min
< SCCOLROW
>( nRealDocSize
- 1, nDiffSize
);
2588 SetDocSize( eOrient
, nCellPos
, nRealDocSize
);
2591 // ----------------------------------------------------------------------------
2593 void ScHTMLTable::FillEmptyCells()
2595 for( ScHTMLTableIterator
aIter( mxNestedTables
.get() ); aIter
.is(); ++aIter
)
2596 aIter
->FillEmptyCells();
2598 for( const ScRange
* pRange
= maVMergedCells
.First(); pRange
; pRange
= maVMergedCells
.Next() )
2599 maUsedCells
.Join( *pRange
);
2601 for( ScAddress aAddr
; aAddr
.Row() < maSize
.mnRows
; aAddr
.IncRow() )
2603 for( aAddr
.SetCol( 0 ); aAddr
.Col() < maSize
.mnCols
; aAddr
.IncCol() )
2605 if( !maUsedCells
.Find( aAddr
) )
2607 // create a range for the lock list (used to calc. cell span)
2608 ScRange
aRange( aAddr
);
2611 aRange
.aEnd
.IncCol();
2613 while( (aRange
.aEnd
.Col() < maSize
.mnCols
) && !maUsedCells
.Find( aRange
.aEnd
) );
2614 aRange
.aEnd
.IncCol( -1 );
2615 maUsedCells
.Join( aRange
);
2617 // insert a dummy entry
2618 ScHTMLEntryPtr xEntry
= CreateEntry();
2619 ImplPushEntryToList( maEntryMap
[ ScHTMLPos( aAddr
) ], xEntry
);
2625 void ScHTMLTable::RecalcDocSize()
2627 // recalc table sizes recursively from inner to outer
2628 for( ScHTMLTableIterator
aIter( mxNestedTables
.get() ); aIter
.is(); ++aIter
)
2629 aIter
->RecalcDocSize();
2631 /* Two passes: first calculates the sizes of single columns/rows, then
2632 the sizes of spanned columns/rows. This allows to fill nested tables
2633 into merged cells optimally. */
2634 static const sal_uInt16 PASS_SINGLE
= 0;
2635 static const sal_uInt16 PASS_SPANNED
= 1;
2636 for( sal_uInt16 nPass
= PASS_SINGLE
; nPass
<= PASS_SPANNED
; ++nPass
)
2638 // iterate through every table cell
2639 ScHTMLEntryMap::const_iterator aMapIterEnd
= maEntryMap
.end();
2640 for( ScHTMLEntryMap::const_iterator aMapIter
= maEntryMap
.begin(); aMapIter
!= aMapIterEnd
; ++aMapIter
)
2642 const ScHTMLPos
& rCellPos
= aMapIter
->first
;
2643 ScHTMLSize aCellSpan
= GetSpan( rCellPos
);
2645 const ScHTMLEntryList
& rEntryList
= aMapIter
->second
;
2646 ScHTMLEntryList::const_iterator aListIter
;
2647 ScHTMLEntryList::const_iterator aListIterEnd
= rEntryList
.end();
2649 // process the dimension of the current cell in this pass?
2650 // (pass is single and span is 1) or (pass is not single and span is not 1)
2651 bool bProcessColWidth
= ((nPass
== PASS_SINGLE
) == (aCellSpan
.mnCols
== 1));
2652 bool bProcessRowHeight
= ((nPass
== PASS_SINGLE
) == (aCellSpan
.mnRows
== 1));
2653 if( bProcessColWidth
|| bProcessRowHeight
)
2655 ScHTMLSize
aDocSize( 1, 0 ); // resulting size of the cell in document
2657 // expand the cell size for each cell parse entry
2658 for( aListIter
= rEntryList
.begin(); aListIter
!= aListIterEnd
; ++aListIter
)
2660 ScHTMLTable
* pTable
= GetExistingTable( (*aListIter
)->GetTableId() );
2661 // find entry with maximum width
2662 if( bProcessColWidth
&& pTable
)
2663 aDocSize
.mnCols
= ::std::max( aDocSize
.mnCols
, static_cast< SCCOL
>( pTable
->GetDocSize( tdCol
) ) );
2664 // add up height of each entry
2665 if( bProcessRowHeight
)
2666 aDocSize
.mnRows
+= pTable
? pTable
->GetDocSize( tdRow
) : 1;
2668 if( !aDocSize
.mnRows
)
2669 aDocSize
.mnRows
= 1;
2671 if( bProcessColWidth
)
2672 CalcNeededDocSize( tdCol
, rCellPos
.mnCol
, aCellSpan
.mnCols
, aDocSize
.mnCols
);
2673 if( bProcessRowHeight
)
2674 CalcNeededDocSize( tdRow
, rCellPos
.mnRow
, aCellSpan
.mnRows
, aDocSize
.mnRows
);
2680 void ScHTMLTable::RecalcDocPos( const ScHTMLPos
& rBasePos
)
2682 maDocBasePos
= rBasePos
;
2683 // after the previous assignment it is allowed to call GetDocPos() methods
2685 // iterate through every table cell
2686 ScHTMLEntryMap::iterator aMapIterEnd
= maEntryMap
.end();
2687 for( ScHTMLEntryMap::iterator aMapIter
= maEntryMap
.begin(); aMapIter
!= aMapIterEnd
; ++aMapIter
)
2689 // fixed doc position of the entire cell (first entry)
2690 const ScHTMLPos
aCellDocPos( GetDocPos( aMapIter
->first
) );
2691 // fixed doc size of the entire cell
2692 const ScHTMLSize
aCellDocSize( GetDocSize( aMapIter
->first
) );
2694 // running doc position for single entries
2695 ScHTMLPos
aEntryDocPos( aCellDocPos
);
2697 ScHTMLEntryList
& rEntryList
= aMapIter
->second
;
2698 ScHTMLEntry
* pEntry
= 0;
2699 ScHTMLEntryList::iterator aListIterEnd
= rEntryList
.end();
2700 for( ScHTMLEntryList::iterator aListIter
= rEntryList
.begin(); aListIter
!= aListIterEnd
; ++aListIter
)
2702 pEntry
= *aListIter
;
2703 if( ScHTMLTable
* pTable
= GetExistingTable( pEntry
->GetTableId() ) )
2705 pTable
->RecalcDocPos( aEntryDocPos
); // recalc nested table
2706 pEntry
->nCol
= SCCOL_MAX
;
2707 pEntry
->nRow
= SCROW_MAX
;
2708 SCROW nTableRows
= static_cast< SCROW
>( pTable
->GetDocSize( tdRow
) );
2710 // use this entry to pad empty space right of table
2711 if( mpParentTable
) // ... but not in global table
2713 SCCOL nStartCol
= aEntryDocPos
.mnCol
+ static_cast< SCCOL
>( pTable
->GetDocSize( tdCol
) );
2714 SCCOL nNextCol
= aEntryDocPos
.mnCol
+ aCellDocSize
.mnCols
;
2715 if( nStartCol
< nNextCol
)
2717 pEntry
->nCol
= nStartCol
;
2718 pEntry
->nRow
= aEntryDocPos
.mnRow
;
2719 pEntry
->nColOverlap
= nNextCol
- nStartCol
;
2720 pEntry
->nRowOverlap
= nTableRows
;
2723 aEntryDocPos
.mnRow
+= nTableRows
;
2727 pEntry
->nCol
= aEntryDocPos
.mnCol
;
2728 pEntry
->nRow
= aEntryDocPos
.mnRow
;
2729 if( mpParentTable
) // do not merge in global table
2730 pEntry
->nColOverlap
= aCellDocSize
.mnCols
;
2731 ++aEntryDocPos
.mnRow
;
2735 // pEntry points now to last entry.
2738 if( (pEntry
== rEntryList
.front()) && (pEntry
->GetTableId() == SC_HTML_NO_TABLE
) )
2740 // pEntry is the only entry in this cell - merge rows of cell with single non-table entry.
2741 pEntry
->nRowOverlap
= aCellDocSize
.mnRows
;
2745 // #111667# fill up incomplete entry lists
2746 SCROW nFirstUnusedRow
= aCellDocPos
.mnRow
+ aCellDocSize
.mnRows
;
2747 while( aEntryDocPos
.mnRow
< nFirstUnusedRow
)
2749 ScHTMLEntryPtr
xDummyEntry( new ScHTMLEntry( pEntry
->GetItemSet() ) );
2750 xDummyEntry
->nCol
= aEntryDocPos
.mnCol
;
2751 xDummyEntry
->nRow
= aEntryDocPos
.mnRow
;
2752 xDummyEntry
->nColOverlap
= aCellDocSize
.mnCols
;
2753 ImplPushEntryToList( rEntryList
, xDummyEntry
);
2754 ++aEntryDocPos
.mnRow
;
2761 // ============================================================================
2763 ScHTMLGlobalTable::ScHTMLGlobalTable( SfxItemPool
& rPool
, EditEngine
& rEditEngine
, ScEEParseList
& rEEParseList
, ScHTMLTableId
& rnUnusedId
) :
2764 ScHTMLTable( rPool
, rEditEngine
, rEEParseList
, rnUnusedId
)
2768 ScHTMLGlobalTable::~ScHTMLGlobalTable()
2772 void ScHTMLGlobalTable::Recalc()
2774 // Fills up empty cells with a dummy entry. */
2776 // recalc table sizes of all nested tables and this table
2778 // recalc document positions of all entries in this table and in nested tables
2779 RecalcDocPos( GetDocPos() );
2782 // ============================================================================
2784 ScHTMLQueryParser::ScHTMLQueryParser( EditEngine
* pEditEngine
, ScDocument
* pDoc
) :
2785 ScHTMLParser( pEditEngine
, pDoc
),
2786 mnUnusedId( SC_HTML_GLOBAL_TABLE
),
2789 mxGlobTable
.reset( new ScHTMLGlobalTable( *pPool
, *pEdit
, *pList
, mnUnusedId
) );
2790 mpCurrTable
= mxGlobTable
.get();
2793 ScHTMLQueryParser::~ScHTMLQueryParser()
2797 ULONG
ScHTMLQueryParser::Read( SvStream
& rStrm
, const String
& rBaseURL
)
2799 SvKeyValueIteratorRef xValues
;
2800 SvKeyValueIterator
* pAttributes
= 0;
2802 SfxObjectShell
* pObjSh
= mpDoc
->GetDocumentShell();
2803 if( pObjSh
&& pObjSh
->IsLoading() )
2805 pAttributes
= pObjSh
->GetHeaderAttributes();
2809 /* When not loading, set up fake HTTP headers to force the SfxHTMLParser
2810 to use UTF8 (used when pasting from clipboard) */
2811 const sal_Char
* pCharSet
= rtl_getBestMimeCharsetFromTextEncoding( RTL_TEXTENCODING_UTF8
);
2814 String aContentType
= String::CreateFromAscii( "text/html; charset=" );
2815 aContentType
.AppendAscii( pCharSet
);
2817 xValues
= new SvKeyValueIterator
;
2818 xValues
->Append( SvKeyValue( String::CreateFromAscii( OOO_STRING_SVTOOLS_HTML_META_content_type
), aContentType
) );
2819 pAttributes
= xValues
;
2823 Link aOldLink
= pEdit
->GetImportHdl();
2824 pEdit
->SetImportHdl( LINK( this, ScHTMLQueryParser
, HTMLImportHdl
) );
2825 ULONG nErr
= pEdit
->Read( rStrm
, rBaseURL
, EE_FORMAT_HTML
, pAttributes
);
2826 pEdit
->SetImportHdl( aOldLink
);
2828 mxGlobTable
->Recalc();
2829 nColMax
= static_cast< SCCOL
>( mxGlobTable
->GetDocSize( tdCol
) - 1 );
2830 nRowMax
= static_cast< SCROW
>( mxGlobTable
->GetDocSize( tdRow
) - 1 );
2835 const ScHTMLTable
* ScHTMLQueryParser::GetGlobalTable() const
2837 return mxGlobTable
.get();
2840 void ScHTMLQueryParser::ProcessToken( const ImportInfo
& rInfo
)
2842 switch( rInfo
.nToken
)
2844 // --- meta data ---
2845 case HTML_META
: MetaOn( rInfo
); break; // <meta>
2847 // --- title handling ---
2848 case HTML_TITLE_ON
: TitleOn( rInfo
); break; // <title>
2849 case HTML_TITLE_OFF
: TitleOff( rInfo
); break; // </title>
2851 // --- body handling ---
2852 case HTML_BODY_ON
: mpCurrTable
->BodyOn( rInfo
); break; // <body>
2853 case HTML_BODY_OFF
: mpCurrTable
->BodyOff( rInfo
); break; // </body>
2855 // --- insert text ---
2856 case HTML_TEXTTOKEN
: InsertText( rInfo
); break; // any text
2857 case HTML_LINEBREAK
: mpCurrTable
->BreakOn(); break; // <br>
2858 case HTML_HEAD1_ON
: // <h1>
2859 case HTML_HEAD2_ON
: // <h2>
2860 case HTML_HEAD3_ON
: // <h3>
2861 case HTML_HEAD4_ON
: // <h4>
2862 case HTML_HEAD5_ON
: // <h5>
2863 case HTML_HEAD6_ON
: // <h6>
2864 case HTML_PARABREAK_ON
: mpCurrTable
->HeadingOn(); break; // <p>
2866 // --- misc. contents ---
2867 case HTML_ANCHOR_ON
: mpCurrTable
->AnchorOn(); break; // <a>
2869 // --- table handling ---
2870 case HTML_TABLE_ON
: TableOn( rInfo
); break; // <table>
2871 case HTML_TABLE_OFF
: TableOff( rInfo
); break; // </table>
2872 case HTML_TABLEROW_ON
: mpCurrTable
->RowOn( rInfo
); break; // <tr>
2873 case HTML_TABLEROW_OFF
: mpCurrTable
->RowOff( rInfo
); break; // </tr>
2874 case HTML_TABLEHEADER_ON
: // <th>
2875 case HTML_TABLEDATA_ON
: mpCurrTable
->DataOn( rInfo
); break; // <td>
2876 case HTML_TABLEHEADER_OFF
: // </th>
2877 case HTML_TABLEDATA_OFF
: mpCurrTable
->DataOff( rInfo
); break; // </td>
2878 case HTML_PREFORMTXT_ON
: PreOn( rInfo
); break; // <pre>
2879 case HTML_PREFORMTXT_OFF
: PreOff( rInfo
); break; // </pre>
2881 // --- formatting ---
2882 case HTML_FONT_ON
: FontOn( rInfo
); break; // <font>
2884 case HTML_BIGPRINT_ON
: // <big>
2885 //! TODO: store current font size, use following size
2886 mpCurrTable
->PutItem( SvxFontHeightItem( maFontHeights
[ 3 ], 100, ATTR_FONT_HEIGHT
) );
2888 case HTML_SMALLPRINT_ON
: // <small>
2889 //! TODO: store current font size, use preceding size
2890 mpCurrTable
->PutItem( SvxFontHeightItem( maFontHeights
[ 0 ], 100, ATTR_FONT_HEIGHT
) );
2893 case HTML_BOLD_ON
: // <b>
2894 case HTML_STRONG_ON
: // <strong>
2895 mpCurrTable
->PutItem( SvxWeightItem( WEIGHT_BOLD
, ATTR_FONT_WEIGHT
) );
2898 case HTML_ITALIC_ON
: // <i>
2899 case HTML_EMPHASIS_ON
: // <em>
2900 case HTML_ADDRESS_ON
: // <address>
2901 case HTML_BLOCKQUOTE_ON
: // <blockquote>
2902 case HTML_BLOCKQUOTE30_ON
: // <bq>
2903 case HTML_CITIATION_ON
: // <cite>
2904 case HTML_VARIABLE_ON
: // <var>
2905 mpCurrTable
->PutItem( SvxPostureItem( ITALIC_NORMAL
, ATTR_FONT_POSTURE
) );
2908 case HTML_DEFINSTANCE_ON
: // <dfn>
2909 mpCurrTable
->PutItem( SvxWeightItem( WEIGHT_BOLD
, ATTR_FONT_WEIGHT
) );
2910 mpCurrTable
->PutItem( SvxPostureItem( ITALIC_NORMAL
, ATTR_FONT_POSTURE
) );
2913 case HTML_UNDERLINE_ON
: // <u>
2914 mpCurrTable
->PutItem( SvxUnderlineItem( UNDERLINE_SINGLE
, ATTR_FONT_UNDERLINE
) );
2919 void ScHTMLQueryParser::InsertText( const ImportInfo
& rInfo
)
2921 mpCurrTable
->PutText( rInfo
);
2923 maTitle
.Append( rInfo
.aText
);
2926 void ScHTMLQueryParser::FontOn( const ImportInfo
& rInfo
)
2928 for( ScHTMLOptionIterator
aIter( rInfo
); aIter
.is(); ++aIter
)
2930 switch( aIter
->GetToken() )
2934 const String
& rFace
= aIter
->GetString();
2936 xub_StrLen nPos
= 0;
2937 while( nPos
!= STRING_NOTFOUND
)
2939 // font list separator: VCL = ';' HTML = ','
2940 String aFName
= rFace
.GetToken( 0, ',', nPos
);
2941 aFName
.EraseLeadingAndTrailingChars();
2942 ScGlobal::AddToken( aFontName
, aFName
, ';' );
2944 if ( aFontName
.Len() )
2945 mpCurrTable
->PutItem( SvxFontItem( FAMILY_DONTKNOW
,
2946 aFontName
, EMPTY_STRING
, PITCH_DONTKNOW
,
2947 RTL_TEXTENCODING_DONTKNOW
, ATTR_FONT
) );
2952 sal_uInt32 nSize
= getLimitedValue
< sal_uInt32
>( aIter
->GetNumber(), 1, SC_HTML_FONTSIZES
);
2953 mpCurrTable
->PutItem( SvxFontHeightItem( maFontHeights
[ nSize
- 1 ], 100, ATTR_FONT_HEIGHT
) );
2959 aIter
->GetColor( aColor
);
2960 mpCurrTable
->PutItem( SvxColorItem( aColor
, ATTR_FONT_COLOR
) );
2967 void ScHTMLQueryParser::MetaOn( const ImportInfo
& rInfo
)
2969 if( mpDoc
->GetDocumentShell() )
2971 HTMLParser
* pParser
= static_cast< HTMLParser
* >( rInfo
.pParser
);
2973 uno::Reference
<document::XDocumentPropertiesSupplier
> xDPS(
2974 mpDoc
->GetDocumentShell()->GetModel(), uno::UNO_QUERY_THROW
);
2975 pParser
->ParseMetaOptions(
2976 xDPS
->getDocumentProperties(),
2977 mpDoc
->GetDocumentShell()->GetHeaderAttributes() );
2981 void ScHTMLQueryParser::TitleOn( const ImportInfo
& /*rInfo*/ )
2987 void ScHTMLQueryParser::TitleOff( const ImportInfo
& rInfo
)
2991 maTitle
.EraseLeadingAndTrailingChars();
2992 if( maTitle
.Len() && mpDoc
->GetDocumentShell() ) {
2993 uno::Reference
<document::XDocumentPropertiesSupplier
> xDPS(
2994 mpDoc
->GetDocumentShell()->GetModel(), uno::UNO_QUERY_THROW
);
2996 xDPS
->getDocumentProperties()->setTitle(maTitle
);
2998 InsertText( rInfo
);
3003 void ScHTMLQueryParser::TableOn( const ImportInfo
& rInfo
)
3005 mpCurrTable
= mpCurrTable
->TableOn( rInfo
);
3008 void ScHTMLQueryParser::TableOff( const ImportInfo
& rInfo
)
3010 mpCurrTable
= mpCurrTable
->TableOff( rInfo
);
3013 void ScHTMLQueryParser::PreOn( const ImportInfo
& rInfo
)
3015 mpCurrTable
= mpCurrTable
->PreOn( rInfo
);
3018 void ScHTMLQueryParser::PreOff( const ImportInfo
& rInfo
)
3020 mpCurrTable
= mpCurrTable
->PreOff( rInfo
);
3023 void ScHTMLQueryParser::CloseTable( const ImportInfo
& rInfo
)
3025 mpCurrTable
= mpCurrTable
->CloseTable( rInfo
);
3028 // ----------------------------------------------------------------------------
3030 IMPL_LINK( ScHTMLQueryParser
, HTMLImportHdl
, const ImportInfo
*, pInfo
)
3032 switch( pInfo
->eState
)
3037 case HTMLIMP_NEXTTOKEN
:
3038 case HTMLIMP_UNKNOWNATTR
:
3039 ProcessToken( *pInfo
);
3042 case HTMLIMP_INSERTPARA
:
3043 mpCurrTable
->InsertPara( *pInfo
);
3046 case HTMLIMP_SETATTR
:
3047 case HTMLIMP_INSERTTEXT
:
3048 case HTMLIMP_INSERTFIELD
:
3052 while( mpCurrTable
->GetTableId() != SC_HTML_GLOBAL_TABLE
)
3053 CloseTable( *pInfo
);
3057 DBG_ERRORFILE( "ScHTMLQueryParser::HTMLImportHdl - unknown ImportInfo::eState" );
3062 // ============================================================================