diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.com> | 2014-03-15 14:07:30 +0100 |
---|---|---|
committer | Tomaž Vajngerl <tomaz.vajngerl@collabora.com> | 2014-04-06 22:02:06 +0200 |
commit | 08c28193ca9e2dfd507d6048ee3c2a6ceebcb84d (patch) | |
tree | c45f313bcac9c9f4ab41a165e8253516f3c2ea7e /sw | |
parent | 7007e3952d6bb74bf8c6722df23ee746f773c72c (diff) |
sw html: split htmlnum to reader, writer and common part
Change-Id: Id6c733f6bf752f06e81b3924418f11babefc3c66
Diffstat (limited to 'sw')
-rw-r--r-- | sw/Library_sw.mk | 2 | ||||
-rw-r--r-- | sw/source/filter/html/htmlnum.cxx | 873 | ||||
-rw-r--r-- | sw/source/filter/html/htmlnum.hxx | 5 | ||||
-rw-r--r-- | sw/source/filter/html/htmlnumreader.cxx | 618 | ||||
-rw-r--r-- | sw/source/filter/html/htmlnumwriter.cxx | 315 |
5 files changed, 942 insertions, 871 deletions
diff --git a/sw/Library_sw.mk b/sw/Library_sw.mk index 0b222621da93..c1ad6ca1757e 100644 --- a/sw/Library_sw.mk +++ b/sw/Library_sw.mk @@ -495,6 +495,8 @@ $(eval $(call gb_Library_add_exception_objects,sw,\ sw/source/filter/html/htmlftn \ sw/source/filter/html/htmlgrin \ sw/source/filter/html/htmlnum \ + sw/source/filter/html/htmlnumreader \ + sw/source/filter/html/htmlnumwriter \ sw/source/filter/html/htmlplug \ sw/source/filter/html/htmlsect \ sw/source/filter/html/htmltab \ diff --git a/sw/source/filter/html/htmlnum.cxx b/sw/source/filter/html/htmlnum.cxx index 2864d740b0c1..10d5b8249298 100644 --- a/sw/source/filter/html/htmlnum.cxx +++ b/sw/source/filter/html/htmlnum.cxx @@ -17,46 +17,9 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ -#include <com/sun/star/style/NumberingType.hpp> -#include <hintids.hxx> -#include <svtools/htmltokn.h> -#include <svtools/htmlkywd.hxx> -#include <svtools/htmlout.hxx> -#include <svl/urihelper.hxx> -#include <editeng/brushitem.hxx> -#include <editeng/lrspitem.hxx> -#include <vcl/svapp.hxx> -#include <vcl/wrkwin.hxx> -#include <numrule.hxx> -#include <doc.hxx> -#include <docary.hxx> -#include <poolfmt.hxx> -#include <ndtxt.hxx> -#include <paratr.hxx> - #include "htmlnum.hxx" -#include "swcss1.hxx" -#include "swhtml.hxx" -#include "wrthtml.hxx" - -#include <SwNodeNum.hxx> -#include <rtl/strbuf.hxx> - -using namespace ::com::sun::star; - -// TODO: Unicode: Are these characters the correct ones? -#define HTML_BULLETCHAR_DISC (0xe008) -#define HTML_BULLETCHAR_CIRCLE (0xe009) -#define HTML_BULLETCHAR_SQUARE (0xe00b) - -// <UL TYPE=...> -static HTMLOptionEnum aHTMLULTypeTable[] = -{ - { OOO_STRING_SVTOOLS_HTML_ULTYPE_disc, HTML_BULLETCHAR_DISC }, - { OOO_STRING_SVTOOLS_HTML_ULTYPE_circle, HTML_BULLETCHAR_CIRCLE }, - { OOO_STRING_SVTOOLS_HTML_ULTYPE_square, HTML_BULLETCHAR_SQUARE }, - { 0, 0 } -}; +#include <ndtxt.hxx> +#include <doc.hxx> void SwHTMLNumRuleInfo::Set( const SwTxtNode& rTxtNd ) { @@ -82,836 +45,4 @@ void SwHTMLNumRuleInfo::Set( const SwTxtNode& rTxtNd ) } } -void SwHTMLParser::NewNumBulList( int nToken ) -{ - SwHTMLNumRuleInfo& rInfo = GetNumInfo(); - - // Erstmal einen neuen Absatz aufmachen - sal_Bool bSpace = (rInfo.GetDepth() + nDefListDeep) == 0; - if( pPam->GetPoint()->nContent.GetIndex() ) - AppendTxtNode( bSpace ? AM_SPACE : AM_NOSPACE, sal_False ); - else if( bSpace ) - AddParSpace(); - - // Die Numerierung-Ebene erhoehen - rInfo.IncDepth(); - sal_uInt8 nLevel = (sal_uInt8)( (rInfo.GetDepth() <= MAXLEVEL ? rInfo.GetDepth() - : MAXLEVEL) - 1 ); - - // ggf. ein Regelwerk anlegen - if( !rInfo.GetNumRule() ) - { - sal_uInt16 nPos = pDoc->MakeNumRule( pDoc->GetUniqueNumRuleName() ); - rInfo.SetNumRule( pDoc->GetNumRuleTbl()[nPos] ); - } - - // das Format anpassen, falls es fuer den Level noch nicht - // geschehen ist! - sal_Bool bNewNumFmt = rInfo.GetNumRule()->GetNumFmt( nLevel ) == 0; - sal_Bool bChangeNumFmt = sal_False; - - // das default Numerierungsformat erstellen - SwNumFmt aNumFmt( rInfo.GetNumRule()->Get(nLevel) ); - rInfo.SetNodeStartValue( nLevel ); - if( bNewNumFmt ) - { - sal_uInt16 nChrFmtPoolId = 0; - if( HTML_ORDERLIST_ON == nToken ) - { - aNumFmt.SetNumberingType(SVX_NUM_ARABIC); - nChrFmtPoolId = RES_POOLCHR_NUM_LEVEL; - } - else - { - // Wir setzen hier eine Zeichenvorlage, weil die UI das auch - // so macht. Dadurch wurd immer auch eine 9pt-Schrift - // eingestellt, was in Netscape nicht der Fall ist. Bisher hat - // das noch niemanden gestoert. - // #i63395# - Only apply user defined default bullet font - if ( numfunc::IsDefBulletFontUserDefined() ) - { - aNumFmt.SetBulletFont( &numfunc::GetDefBulletFont() ); - } - aNumFmt.SetNumberingType(SVX_NUM_CHAR_SPECIAL); - aNumFmt.SetBulletChar( cBulletChar ); // das Bulletzeichen !! - nChrFmtPoolId = RES_POOLCHR_BUL_LEVEL; - } - - sal_uInt16 nAbsLSpace = HTML_NUMBUL_MARGINLEFT; - - short nFirstLineIndent = HTML_NUMBUL_INDENT; - if( nLevel > 0 ) - { - const SwNumFmt& rPrevNumFmt = rInfo.GetNumRule()->Get( nLevel-1 ); - nAbsLSpace = nAbsLSpace + rPrevNumFmt.GetAbsLSpace(); - nFirstLineIndent = rPrevNumFmt.GetFirstLineOffset(); - } - aNumFmt.SetAbsLSpace( nAbsLSpace ); - aNumFmt.SetFirstLineOffset( nFirstLineIndent ); - aNumFmt.SetCharFmt( pCSS1Parser->GetCharFmtFromPool(nChrFmtPoolId) ); - - bChangeNumFmt = sal_True; - } - else if( 1 != aNumFmt.GetStart() ) - { - // Wenn die Ebene schon mal benutzt wurde, muss der Start-Wert - // ggf. hart am Absatz gesetzt werden. - rInfo.SetNodeStartValue( nLevel, 1 ); - } - - // und es ggf. durch die Optionen veraendern - OUString aId, aStyle, aClass, aLang, aDir; - OUString aBulletSrc; - sal_Int16 eVertOri = text::VertOrientation::NONE; - sal_uInt16 nWidth=USHRT_MAX, nHeight=USHRT_MAX; - const HTMLOptions& rHTMLOptions = GetOptions(); - for (size_t i = rHTMLOptions.size(); i; ) - { - const HTMLOption& rOption = rHTMLOptions[--i]; - switch( rOption.GetToken() ) - { - case HTML_O_ID: - aId = rOption.GetString(); - break; - case HTML_O_TYPE: - if( bNewNumFmt && !rOption.GetString().isEmpty() ) - { - switch( nToken ) - { - case HTML_ORDERLIST_ON: - bChangeNumFmt = sal_True; - switch( rOption.GetString()[0] ) - { - case 'A': aNumFmt.SetNumberingType(SVX_NUM_CHARS_UPPER_LETTER); break; - case 'a': aNumFmt.SetNumberingType(SVX_NUM_CHARS_LOWER_LETTER); break; - case 'I': aNumFmt.SetNumberingType(SVX_NUM_ROMAN_UPPER); break; - case 'i': aNumFmt.SetNumberingType(SVX_NUM_ROMAN_LOWER); break; - default: bChangeNumFmt = sal_False; - } - break; - - case HTML_UNORDERLIST_ON: - aNumFmt.SetBulletChar( (sal_Unicode)rOption.GetEnum( - aHTMLULTypeTable,aNumFmt.GetBulletChar() ) ); - bChangeNumFmt = sal_True; - break; - } - } - break; - case HTML_O_START: - { - sal_uInt16 nStart = (sal_uInt16)rOption.GetNumber(); - if( bNewNumFmt ) - { - aNumFmt.SetStart( nStart ); - bChangeNumFmt = sal_True; - } - else - { - rInfo.SetNodeStartValue( nLevel, nStart ); - } - } - break; - case HTML_O_STYLE: - aStyle = rOption.GetString(); - break; - case HTML_O_CLASS: - aClass = rOption.GetString(); - break; - case HTML_O_LANG: - aLang = rOption.GetString(); - break; - case HTML_O_DIR: - aDir = rOption.GetString(); - break; - case HTML_O_SRC: - if( bNewNumFmt ) - { - aBulletSrc = rOption.GetString(); - if( !InternalImgToPrivateURL(aBulletSrc) ) - aBulletSrc = URIHelper::SmartRel2Abs( INetURLObject( sBaseURL ), aBulletSrc, Link(), false ); - } - break; - case HTML_O_WIDTH: - nWidth = (sal_uInt16)rOption.GetNumber(); - break; - case HTML_O_HEIGHT: - nHeight = (sal_uInt16)rOption.GetNumber(); - break; - case HTML_O_ALIGN: - eVertOri = - (sal_Int16)rOption.GetEnum( aHTMLImgVAlignTable, - static_cast< sal_uInt16 >(eVertOri) ); - break; - } - } - - if( !aBulletSrc.isEmpty() ) - { - // Eine Bullet-Liste mit Grafiken - aNumFmt.SetNumberingType(SVX_NUM_BITMAP); - - // Die Grafik als Brush anlegen - SvxBrushItem aBrushItem( RES_BACKGROUND ); - aBrushItem.SetGraphicLink( aBulletSrc ); - aBrushItem.SetGraphicPos( GPOS_AREA ); - - // Die Groesse nur beachten, wenn Breite und Hoehe vorhanden sind - Size aTwipSz( nWidth, nHeight), *pTwipSz=0; - if( nWidth!=USHRT_MAX && nHeight!=USHRT_MAX ) - { - aTwipSz = - Application::GetDefaultDevice()->PixelToLogic( aTwipSz, - MapMode(MAP_TWIP) ); - pTwipSz = &aTwipSz; - } - - // Die Ausrichtung auch nur beachten, wenn eine Ausrichtung - // angegeben wurde - aNumFmt.SetGraphicBrush( &aBrushItem, pTwipSz, - text::VertOrientation::NONE!=eVertOri ? &eVertOri : 0); - - // Und noch die Grafik merken, um sie in den Absaetzen nicht - // einzufuegen - aBulletGrfs[nLevel] = aBulletSrc; - bChangeNumFmt = sal_True; - } - else - aBulletGrfs[nLevel] = ""; - - // den aktuellen Absatz erst einmal nicht numerieren - { - sal_uInt8 nLvl = nLevel; - SetNodeNum( nLvl, false ); - } - - // einen neuen Kontext anlegen - _HTMLAttrContext *pCntxt = new _HTMLAttrContext( static_cast< sal_uInt16 >(nToken) ); - - // Styles parsen - if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) ) - { - SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); - SvxCSS1PropertyInfo aPropInfo; - - if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) ) - { - if( bNewNumFmt ) - { - if( aPropInfo.bLeftMargin ) - { - // Der Der Default-Einzug wurde schon eingefuegt. - sal_uInt16 nAbsLSpace = - aNumFmt.GetAbsLSpace() - HTML_NUMBUL_MARGINLEFT; - if( aPropInfo.nLeftMargin < 0 && - nAbsLSpace < -aPropInfo.nLeftMargin ) - nAbsLSpace = 0U; - else if( aPropInfo.nLeftMargin > USHRT_MAX || - (long)nAbsLSpace + - aPropInfo.nLeftMargin > USHRT_MAX ) - nAbsLSpace = USHRT_MAX; - else - nAbsLSpace = nAbsLSpace + (sal_uInt16)aPropInfo.nLeftMargin; - - aNumFmt.SetAbsLSpace( nAbsLSpace ); - bChangeNumFmt = sal_True; - } - if( aPropInfo.bTextIndent ) - { - short nTextIndent = - ((const SvxLRSpaceItem &)aItemSet.Get( RES_LR_SPACE )) - .GetTxtFirstLineOfst(); - aNumFmt.SetFirstLineOffset( nTextIndent ); - bChangeNumFmt = sal_True; - } - } - aPropInfo.bLeftMargin = aPropInfo.bTextIndent = sal_False; - if( !aPropInfo.bRightMargin ) - aItemSet.ClearItem( RES_LR_SPACE ); - - // #i89812# - Perform change to list style before calling <DoPositioning(..)>, - // because <DoPositioning(..)> may open a new context and thus may - // clear the <SwHTMLNumRuleInfo> instance hold by local variable <rInfo>. - if( bChangeNumFmt ) - { - rInfo.GetNumRule()->Set( nLevel, aNumFmt ); - pDoc->ChgNumRuleFmts( *rInfo.GetNumRule() ); - bChangeNumFmt = sal_False; - } - - DoPositioning( aItemSet, aPropInfo, pCntxt ); - - InsertAttrs( aItemSet, aPropInfo, pCntxt ); - } - } - - if( bChangeNumFmt ) - { - rInfo.GetNumRule()->Set( nLevel, aNumFmt ); - pDoc->ChgNumRuleFmts( *rInfo.GetNumRule() ); - } - - PushContext( pCntxt ); - - // die Attribute der neuen Vorlage setzen - SetTxtCollAttrs( pCntxt ); -} - -void SwHTMLParser::EndNumBulList( int nToken ) -{ - SwHTMLNumRuleInfo& rInfo = GetNumInfo(); - - // Ein neuer Absatz muss aufgemacht werden, wenn - // - der aktuelle nicht leer ist, also Text oder absatzgebundene Objekte - // enthaelt. - // - der aktuelle Absatz numeriert ist. - sal_Bool bAppend = pPam->GetPoint()->nContent.GetIndex() > 0; - if( !bAppend ) - { - SwTxtNode* pTxtNode = pPam->GetNode()->GetTxtNode(); - - bAppend = (pTxtNode && ! pTxtNode->IsOutline() && pTxtNode->IsCountedInList()) || - - HasCurrentParaFlys(); - } - - sal_Bool bSpace = (rInfo.GetDepth() + nDefListDeep) == 1; - if( bAppend ) - AppendTxtNode( bSpace ? AM_SPACE : AM_NOSPACE, sal_False ); - else if( bSpace ) - AddParSpace(); - - // den aktuellen Kontext vom Stack holen - _HTMLAttrContext *pCntxt = nToken!=0 ? PopContext( static_cast< sal_uInt16 >(nToken & ~1) ) : 0; - - // Keine Liste aufgrund eines Tokens beenden, wenn der Kontext - // nie angelgt wurde oder nicht beendet werden darf. - if( rInfo.GetDepth()>0 && (!nToken || pCntxt) ) - { - rInfo.DecDepth(); - if( !rInfo.GetDepth() ) // wars der letze Level ? - { - // Die noch nicht angepassten Formate werden jetzt noch - // angepasst, damit es sich besser Editieren laesst. - const SwNumFmt *pRefNumFmt = 0; - sal_Bool bChanged = sal_False; - for( sal_uInt16 i=0; i<MAXLEVEL; i++ ) - { - const SwNumFmt *pNumFmt = rInfo.GetNumRule()->GetNumFmt(i); - if( pNumFmt ) - { - pRefNumFmt = pNumFmt; - } - else if( pRefNumFmt ) - { - SwNumFmt aNumFmt( rInfo.GetNumRule()->Get(i) ); - aNumFmt.SetNumberingType(pRefNumFmt->GetNumberingType() != SVX_NUM_BITMAP - ? pRefNumFmt->GetNumberingType() : style::NumberingType::CHAR_SPECIAL); - if( SVX_NUM_CHAR_SPECIAL == aNumFmt.GetNumberingType() ) - { - // #i63395# - Only apply user defined default bullet font - if ( numfunc::IsDefBulletFontUserDefined() ) - { - aNumFmt.SetBulletFont( &numfunc::GetDefBulletFont() ); - } - aNumFmt.SetBulletChar( cBulletChar ); - } - aNumFmt.SetAbsLSpace( (i+1) * HTML_NUMBUL_MARGINLEFT ); - aNumFmt.SetFirstLineOffset( HTML_NUMBUL_INDENT ); - aNumFmt.SetCharFmt( pRefNumFmt->GetCharFmt() ); - rInfo.GetNumRule()->Set( i, aNumFmt ); - bChanged = sal_True; - } - } - if( bChanged ) - pDoc->ChgNumRuleFmts( *rInfo.GetNumRule() ); - - // Beim letzen Append wurde das NumRule-Item und das - // NodeNum-Objekt mit kopiert. Beides muessen wir noch - // loeschen. Das ResetAttr loescht das NodeNum-Objekt mit! - pPam->GetNode()->GetTxtNode()->ResetAttr( RES_PARATR_NUMRULE ); - - rInfo.Clear(); - } - else - { - // the next paragraph not numbered first - SetNodeNum( rInfo.GetLevel(), false ); - } - } - - // und noch Attribute beenden - sal_Bool bSetAttrs = sal_False; - if( pCntxt ) - { - EndContext( pCntxt ); - delete pCntxt; - bSetAttrs = sal_True; - } - - if( nToken ) - SetTxtCollAttrs(); - - if( bSetAttrs ) - SetAttr(); // Absatz-Atts wegen JavaScript moeglichst schnell setzen - -} - -void SwHTMLParser::NewNumBulListItem( int nToken ) -{ - sal_uInt8 nLevel = GetNumInfo().GetLevel(); - OUString aId, aStyle, aClass, aLang, aDir; - sal_uInt16 nStart = HTML_LISTHEADER_ON != nToken - ? GetNumInfo().GetNodeStartValue( nLevel ) - : USHRT_MAX; - if( USHRT_MAX != nStart ) - GetNumInfo().SetNodeStartValue( nLevel ); - - const HTMLOptions& rHTMLOptions = GetOptions(); - for (size_t i = rHTMLOptions.size(); i; ) - { - const HTMLOption& rOption = rHTMLOptions[--i]; - switch( rOption.GetToken() ) - { - case HTML_O_VALUE: - nStart = (sal_uInt16)rOption.GetNumber(); - break; - case HTML_O_ID: - aId = rOption.GetString(); - break; - case HTML_O_STYLE: - aStyle = rOption.GetString(); - break; - case HTML_O_CLASS: - aClass = rOption.GetString(); - break; - case HTML_O_LANG: - aLang = rOption.GetString(); - break; - case HTML_O_DIR: - aDir = rOption.GetString(); - break; - } - } - - // einen neuen Absatz aufmachen - if( pPam->GetPoint()->nContent.GetIndex() ) - AppendTxtNode( AM_NOSPACE, sal_False ); - bNoParSpace = false; // In <LI> wird kein Abstand eingefuegt! - - const bool bCountedInList( HTML_LISTHEADER_ON==nToken ? false : true ); - - _HTMLAttrContext *pCntxt = new _HTMLAttrContext( static_cast< sal_uInt16 >(nToken) ); - - OUString aNumRuleName; - if( GetNumInfo().GetNumRule() ) - { - aNumRuleName = GetNumInfo().GetNumRule()->GetName(); - } - else - { - aNumRuleName = pDoc->GetUniqueNumRuleName(); - SwNumRule aNumRule( aNumRuleName, - SvxNumberFormat::LABEL_WIDTH_AND_POSITION ); - SwNumFmt aNumFmt( aNumRule.Get( 0 ) ); - // #i63395# - Only apply user defined default bullet font - if ( numfunc::IsDefBulletFontUserDefined() ) - { - aNumFmt.SetBulletFont( &numfunc::GetDefBulletFont() ); - } - aNumFmt.SetNumberingType(SVX_NUM_CHAR_SPECIAL); - aNumFmt.SetBulletChar( cBulletChar ); // das Bulletzeichen !! - aNumFmt.SetCharFmt( pCSS1Parser->GetCharFmtFromPool(RES_POOLCHR_BUL_LEVEL) ); - aNumFmt.SetLSpace( (sal_uInt16)(-HTML_NUMBUL_INDENT) ); - aNumFmt.SetFirstLineOffset( HTML_NUMBUL_INDENT ); - aNumRule.Set( 0, aNumFmt ); - - pDoc->MakeNumRule( aNumRuleName, &aNumRule ); - - OSL_ENSURE( !nOpenParaToken, - "Jetzt geht ein offenes Absatz-Element verloren" ); - // Wir tun so, als ob wir in einem Absatz sind. Dann wird - // beim naechsten Absatz wenigstens die Numerierung - // weggeschmissen, die nach dem naechsten AppendTxtNode uebernommen - // wird. - nOpenParaToken = static_cast< sal_uInt16 >(nToken); - } - - SwTxtNode* pTxtNode = pPam->GetNode()->GetTxtNode(); - ((SwCntntNode *)pTxtNode)->SetAttr( SwNumRuleItem(aNumRuleName) ); - pTxtNode->SetAttrListLevel(nLevel); - // #i57656# - <IsCounted()> state of text node has to be adjusted accordingly. - if ( nLevel < MAXLEVEL ) - { - pTxtNode->SetCountedInList( bCountedInList ); - } - // #i57919# - // correction of refactoring done by cws swnumtree - // - <nStart> contains the start value, if the numbering has to be restarted - // at this text node. Value <USHRT_MAX> indicates, that numbering isn't - // restarted at this text node - if ( nStart != USHRT_MAX ) - { - pTxtNode->SetListRestart( true ); - pTxtNode->SetAttrListRestartValue( nStart ); - } - - if( GetNumInfo().GetNumRule() ) - GetNumInfo().GetNumRule()->SetInvalidRule( sal_True ); - - // Styles parsen - if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) ) - { - SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); - SvxCSS1PropertyInfo aPropInfo; - - if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) ) - { - DoPositioning( aItemSet, aPropInfo, pCntxt ); - InsertAttrs( aItemSet, aPropInfo, pCntxt ); - } - } - - PushContext( pCntxt ); - - // die neue Vorlage setzen - SetTxtCollAttrs( pCntxt ); - - // Laufbalkenanzeige aktualisieren - ShowStatline(); -} - -void SwHTMLParser::EndNumBulListItem( int nToken, sal_Bool bSetColl, - sal_Bool /*bLastPara*/ ) -{ - // einen neuen Absatz aufmachen - if( !nToken && pPam->GetPoint()->nContent.GetIndex() ) - AppendTxtNode( AM_NOSPACE ); - - // Kontext zu dem Token suchen und vom Stack holen - _HTMLAttrContext *pCntxt = 0; - sal_uInt16 nPos = aContexts.size(); - nToken &= ~1; - while( !pCntxt && nPos>nContextStMin ) - { - sal_uInt16 nCntxtToken = aContexts[--nPos]->GetToken(); - switch( nCntxtToken ) - { - case HTML_LI_ON: - case HTML_LISTHEADER_ON: - if( !nToken || nToken == nCntxtToken ) - { - pCntxt = aContexts[nPos]; - aContexts.erase( aContexts.begin() + nPos ); - } - break; - case HTML_ORDERLIST_ON: - case HTML_UNORDERLIST_ON: - case HTML_MENULIST_ON: - case HTML_DIRLIST_ON: - // keine LI/LH ausserhalb der aktuellen Liste betrachten - nPos = nContextStMin; - break; - } - } - - // und noch Attribute beenden - if( pCntxt ) - { - EndContext( pCntxt ); - SetAttr(); // Absatz-Atts wegen JavaScript moeglichst schnell setzen - delete pCntxt; - } - - // und die bisherige Vorlage setzen - if( bSetColl ) - SetTxtCollAttrs(); -} - -void SwHTMLParser::SetNodeNum( sal_uInt8 nLevel, bool bCountedInList ) -{ - SwTxtNode* pTxtNode = pPam->GetNode()->GetTxtNode(); - OSL_ENSURE( pTxtNode, "Kein Text-Node an PaM-Position" ); - - OSL_ENSURE( GetNumInfo().GetNumRule(), "Kein Numerierungs-Regel" ); - const OUString& rName = GetNumInfo().GetNumRule()->GetName(); - ((SwCntntNode *)pTxtNode)->SetAttr( SwNumRuleItem(rName) ); - - pTxtNode->SetAttrListLevel( nLevel ); - pTxtNode->SetCountedInList( bCountedInList ); - - // NumRule invalidieren, weil sie durch ein EndAction bereits - // auf valid geschaltet worden sein kann. - GetNumInfo().GetNumRule()->SetInvalidRule( sal_False ); -} - -void SwHTMLWriter::FillNextNumInfo() -{ - pNextNumRuleInfo = 0; - - sal_uLong nPos = pCurPam->GetPoint()->nNode.GetIndex() + 1; - - bool bTable = false; - do - { - const SwNode* pNd = pDoc->GetNodes()[nPos]; - if( pNd->IsTxtNode() ) - { - // Der naechste wird als naechstes ausgegeben. - pNextNumRuleInfo = new SwHTMLNumRuleInfo( *pNd->GetTxtNode() ); - - // Vor einer Tabelle behalten wir erst einmal die alte Ebene bei, - // wenn die gleiche Numerierung hinter der Tabelle - // fortgesetzt wird und dort nicht von vorne numeriert - // wird. Die Tabelle wird ann beim Import so weit eingeruckt, - // wie es der Num-Ebene entspricht. - if( bTable && - pNextNumRuleInfo->GetNumRule()==GetNumInfo().GetNumRule() && - !pNextNumRuleInfo->IsRestart() ) - { - pNextNumRuleInfo->SetDepth( GetNumInfo().GetDepth() ); - } - } - else if( pNd->IsTableNode() ) - { - // Eine Tabelle wird uebersprungen, also den Node - // hinter der Tabelle betrachten. - nPos = pNd->EndOfSectionIndex() + 1; - bTable = true; - } - else - { - // In allen anderen Faellen ist die Numerierung erstmal - // zu Ende. - pNextNumRuleInfo = new SwHTMLNumRuleInfo; - } - } - while( !pNextNumRuleInfo ); -} - -void SwHTMLWriter::ClearNextNumInfo() -{ - delete pNextNumRuleInfo; - pNextNumRuleInfo = 0; -} - -Writer& OutHTML_NumBulListStart( SwHTMLWriter& rWrt, - const SwHTMLNumRuleInfo& rInfo ) -{ - SwHTMLNumRuleInfo& rPrevInfo = rWrt.GetNumInfo(); - sal_Bool bSameRule = rPrevInfo.GetNumRule() == rInfo.GetNumRule(); - if( bSameRule && rPrevInfo.GetDepth() >= rInfo.GetDepth() && - !rInfo.IsRestart() ) - { - return rWrt; - } - - sal_Bool bStartValue = sal_False; - if( !bSameRule && rInfo.GetDepth() ) - { - OUString aName( rInfo.GetNumRule()->GetName() ); - if( 0 != rWrt.aNumRuleNames.count( aName ) ) - { - // The rule has been applied before - sal_Int16 eType = rInfo.GetNumRule() - ->Get( rInfo.GetDepth()-1 ).GetNumberingType(); - if( SVX_NUM_CHAR_SPECIAL != eType && SVX_NUM_BITMAP != eType ) - { - // If it's a numbering rule, the current number should be - // exported as start value, but only if there are no nodes - // within the numbering that have a lower level - bStartValue = sal_True; - if( rInfo.GetDepth() > 1 ) - { - sal_uLong nPos = - rWrt.pCurPam->GetPoint()->nNode.GetIndex() + 1; - do - { - const SwNode* pNd = rWrt.pDoc->GetNodes()[nPos]; - if( pNd->IsTxtNode() ) - { - const SwTxtNode *pTxtNd = pNd->GetTxtNode(); - if( !pTxtNd->GetNumRule() ) - { - // node isn't numbered => check completed - break; - } - - OSL_ENSURE(! pTxtNd->IsOutline(), - "outline not expected"); - - if( pTxtNd->GetActualListLevel() + 1 < - rInfo.GetDepth() ) - { - // node is numbered, but level is lower - // => check completed - bStartValue = sal_False; - break; - } - nPos++; - } - else if( pNd->IsTableNode() ) - { - // skip table - nPos = pNd->EndOfSectionIndex() + 1; - } - else - { - // end node or sections start node -> check - // completed - break; - } - } - while( true ); - } - } - } - else - { - rWrt.aNumRuleNames.insert( aName ); - } - } - - OSL_ENSURE( rWrt.nLastParaToken == 0, - "<PRE> wurde nicht vor <OL> beendet." ); - sal_uInt16 nPrevDepth = - (bSameRule && !rInfo.IsRestart()) ? rPrevInfo.GetDepth() : 0; - - for( sal_uInt16 i=nPrevDepth; i<rInfo.GetDepth(); i++ ) - { - rWrt.OutNewLine(); // <OL>/<UL> in eine neue Zeile - - rWrt.aBulletGrfs[i] = ""; - OStringBuffer sOut; - sOut.append('<'); - const SwNumFmt& rNumFmt = rInfo.GetNumRule()->Get( i ); - sal_Int16 eType = rNumFmt.GetNumberingType(); - if( SVX_NUM_CHAR_SPECIAL == eType ) - { - // Aufzaehlungs-Liste: <OL> - sOut.append(OOO_STRING_SVTOOLS_HTML_unorderlist); - - // den Typ ueber das Bullet-Zeichen bestimmen - const sal_Char *pStr = 0; - switch( rNumFmt.GetBulletChar() ) - { - case HTML_BULLETCHAR_DISC: - pStr = OOO_STRING_SVTOOLS_HTML_ULTYPE_disc; - break; - case HTML_BULLETCHAR_CIRCLE: - pStr = OOO_STRING_SVTOOLS_HTML_ULTYPE_circle; - break; - case HTML_BULLETCHAR_SQUARE: - pStr = OOO_STRING_SVTOOLS_HTML_ULTYPE_square; - break; - } - - if( pStr ) - { - sOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_type). - append("=\"").append(pStr).append("\""); - } - } - else if( SVX_NUM_BITMAP == eType ) - { - // Unordered list: <UL> - sOut.append(OOO_STRING_SVTOOLS_HTML_unorderlist); - rWrt.Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() ); - OutHTML_BulletImage( rWrt, - 0, - rNumFmt.GetBrush() ); - } - else - { - // Ordered list: <OL> - sOut.append(OOO_STRING_SVTOOLS_HTML_orderlist); - - // den Typ ueber das Format bestimmen - sal_Char cType = 0; - switch( eType ) - { - case SVX_NUM_CHARS_UPPER_LETTER: cType = 'A'; break; - case SVX_NUM_CHARS_LOWER_LETTER: cType = 'a'; break; - case SVX_NUM_ROMAN_UPPER: cType = 'I'; break; - case SVX_NUM_ROMAN_LOWER: cType = 'i'; break; - } - if( cType ) - { - sOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_type). - append("=\"").append(cType).append("\""); - } - - sal_uInt16 nStartVal = rNumFmt.GetStart(); - if( bStartValue && 1 == nStartVal && i == rInfo.GetDepth()-1 ) - { - // #i51089 - TUNING# - if ( rWrt.pCurPam->GetNode()->GetTxtNode()->GetNum() ) - { - nStartVal = static_cast< sal_uInt16 >( rWrt.pCurPam->GetNode() - ->GetTxtNode()->GetNumberVector()[i] ); - } - else - { - OSL_FAIL( "<OutHTML_NumBulListStart(..) - text node has no number." ); - } - } - if( nStartVal != 1 ) - { - sOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_start). - append("=\"").append(static_cast<sal_Int32>(nStartVal)).append("\""); - } - } - - if (!sOut.isEmpty()) - rWrt.Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() ); - - if( rWrt.bCfgOutStyles ) - OutCSS1_NumBulListStyleOpt( rWrt, *rInfo.GetNumRule(), (sal_uInt8)i ); - - rWrt.Strm().WriteChar( '>' ); - - rWrt.IncIndentLevel(); // Inhalt von <OL> einruecken - } - - return rWrt; -} - -Writer& OutHTML_NumBulListEnd( SwHTMLWriter& rWrt, - const SwHTMLNumRuleInfo& rNextInfo ) -{ - SwHTMLNumRuleInfo& rInfo = rWrt.GetNumInfo(); - sal_Bool bSameRule = rNextInfo.GetNumRule() == rInfo.GetNumRule(); - if( bSameRule && rNextInfo.GetDepth() >= rInfo.GetDepth() && - !rNextInfo.IsRestart() ) - { - return rWrt; - } - - OSL_ENSURE( rWrt.nLastParaToken == 0, - "<PRE> wurde nicht vor </OL> beendet." ); - sal_uInt16 nNextDepth = - (bSameRule && !rNextInfo.IsRestart()) ? rNextInfo.GetDepth() : 0; - - // MIB 23.7.97: Die Schleife muss doch rueckwaerts durchlaufen - // werden, weil die Reihenfolge von </OL>/</UL> stimmen muss - for( sal_uInt16 i=rInfo.GetDepth(); i>nNextDepth; i-- ) - { - rWrt.DecIndentLevel(); // Inhalt von <OL> einruecken - if( rWrt.bLFPossible ) - rWrt.OutNewLine(); // </OL>/</UL> in eine neue Zeile - - // es wird also eine Liste angefangen oder beendet: - sal_Int16 eType = rInfo.GetNumRule()->Get( i-1 ).GetNumberingType(); - const sal_Char *pStr; - if( SVX_NUM_CHAR_SPECIAL == eType || SVX_NUM_BITMAP == eType) - pStr = OOO_STRING_SVTOOLS_HTML_unorderlist; - else - pStr = OOO_STRING_SVTOOLS_HTML_orderlist; - HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), pStr, false ); - rWrt.bLFPossible = sal_True; - } - - return rWrt; -} - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/filter/html/htmlnum.hxx b/sw/source/filter/html/htmlnum.hxx index 4f64ac9be5e1..b5a97c477a89 100644 --- a/sw/source/filter/html/htmlnum.hxx +++ b/sw/source/filter/html/htmlnum.hxx @@ -28,6 +28,11 @@ class SwTxtNode; class SwNumRule; +// TODO: Unicode: Are these characters the correct ones? +#define HTML_BULLETCHAR_DISC (0xe008) +#define HTML_BULLETCHAR_CIRCLE (0xe009) +#define HTML_BULLETCHAR_SQUARE (0xe00b) + class SwHTMLNumRuleInfo { sal_uInt16 aNumStarts[MAXLEVEL]; diff --git a/sw/source/filter/html/htmlnumreader.cxx b/sw/source/filter/html/htmlnumreader.cxx new file mode 100644 index 000000000000..235ed2ef97f2 --- /dev/null +++ b/sw/source/filter/html/htmlnumreader.cxx @@ -0,0 +1,618 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/style/NumberingType.hpp> +#include <hintids.hxx> +#include <svtools/htmltokn.h> +#include <svtools/htmlkywd.hxx> +#include <svtools/htmlout.hxx> +#include <svl/urihelper.hxx> +#include <editeng/brushitem.hxx> +#include <editeng/lrspitem.hxx> +#include <vcl/svapp.hxx> +#include <vcl/wrkwin.hxx> +#include <numrule.hxx> +#include <doc.hxx> +#include <docary.hxx> +#include <poolfmt.hxx> +#include <ndtxt.hxx> +#include <paratr.hxx> + +#include "htmlnum.hxx" +#include "swcss1.hxx" +#include "swhtml.hxx" + +#include <SwNodeNum.hxx> + +using namespace css; + +// <UL TYPE=...> +static HTMLOptionEnum aHTMLULTypeTable[] = +{ + { OOO_STRING_SVTOOLS_HTML_ULTYPE_disc, HTML_BULLETCHAR_DISC }, + { OOO_STRING_SVTOOLS_HTML_ULTYPE_circle, HTML_BULLETCHAR_CIRCLE }, + { OOO_STRING_SVTOOLS_HTML_ULTYPE_square, HTML_BULLETCHAR_SQUARE }, + { 0, 0 } +}; + + +void SwHTMLParser::NewNumBulList( int nToken ) +{ + SwHTMLNumRuleInfo& rInfo = GetNumInfo(); + + // Erstmal einen neuen Absatz aufmachen + sal_Bool bSpace = (rInfo.GetDepth() + nDefListDeep) == 0; + if( pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( bSpace ? AM_SPACE : AM_NOSPACE, sal_False ); + else if( bSpace ) + AddParSpace(); + + // Die Numerierung-Ebene erhoehen + rInfo.IncDepth(); + sal_uInt8 nLevel = (sal_uInt8)( (rInfo.GetDepth() <= MAXLEVEL ? rInfo.GetDepth() + : MAXLEVEL) - 1 ); + + // ggf. ein Regelwerk anlegen + if( !rInfo.GetNumRule() ) + { + sal_uInt16 nPos = pDoc->MakeNumRule( pDoc->GetUniqueNumRuleName() ); + rInfo.SetNumRule( pDoc->GetNumRuleTbl()[nPos] ); + } + + // das Format anpassen, falls es fuer den Level noch nicht + // geschehen ist! + sal_Bool bNewNumFmt = rInfo.GetNumRule()->GetNumFmt( nLevel ) == 0; + sal_Bool bChangeNumFmt = sal_False; + + // das default Numerierungsformat erstellen + SwNumFmt aNumFmt( rInfo.GetNumRule()->Get(nLevel) ); + rInfo.SetNodeStartValue( nLevel ); + if( bNewNumFmt ) + { + sal_uInt16 nChrFmtPoolId = 0; + if( HTML_ORDERLIST_ON == nToken ) + { + aNumFmt.SetNumberingType(SVX_NUM_ARABIC); + nChrFmtPoolId = RES_POOLCHR_NUM_LEVEL; + } + else + { + // Wir setzen hier eine Zeichenvorlage, weil die UI das auch + // so macht. Dadurch wurd immer auch eine 9pt-Schrift + // eingestellt, was in Netscape nicht der Fall ist. Bisher hat + // das noch niemanden gestoert. + // #i63395# - Only apply user defined default bullet font + if ( numfunc::IsDefBulletFontUserDefined() ) + { + aNumFmt.SetBulletFont( &numfunc::GetDefBulletFont() ); + } + aNumFmt.SetNumberingType(SVX_NUM_CHAR_SPECIAL); + aNumFmt.SetBulletChar( cBulletChar ); // das Bulletzeichen !! + nChrFmtPoolId = RES_POOLCHR_BUL_LEVEL; + } + + sal_uInt16 nAbsLSpace = HTML_NUMBUL_MARGINLEFT; + + short nFirstLineIndent = HTML_NUMBUL_INDENT; + if( nLevel > 0 ) + { + const SwNumFmt& rPrevNumFmt = rInfo.GetNumRule()->Get( nLevel-1 ); + nAbsLSpace = nAbsLSpace + rPrevNumFmt.GetAbsLSpace(); + nFirstLineIndent = rPrevNumFmt.GetFirstLineOffset(); + } + aNumFmt.SetAbsLSpace( nAbsLSpace ); + aNumFmt.SetFirstLineOffset( nFirstLineIndent ); + aNumFmt.SetCharFmt( pCSS1Parser->GetCharFmtFromPool(nChrFmtPoolId) ); + + bChangeNumFmt = sal_True; + } + else if( 1 != aNumFmt.GetStart() ) + { + // Wenn die Ebene schon mal benutzt wurde, muss der Start-Wert + // ggf. hart am Absatz gesetzt werden. + rInfo.SetNodeStartValue( nLevel, 1 ); + } + + // und es ggf. durch die Optionen veraendern + OUString aId, aStyle, aClass, aLang, aDir; + OUString aBulletSrc; + sal_Int16 eVertOri = text::VertOrientation::NONE; + sal_uInt16 nWidth=USHRT_MAX, nHeight=USHRT_MAX; + const HTMLOptions& rHTMLOptions = GetOptions(); + for (size_t i = rHTMLOptions.size(); i; ) + { + const HTMLOption& rOption = rHTMLOptions[--i]; + switch( rOption.GetToken() ) + { + case HTML_O_ID: + aId = rOption.GetString(); + break; + case HTML_O_TYPE: + if( bNewNumFmt && !rOption.GetString().isEmpty() ) + { + switch( nToken ) + { + case HTML_ORDERLIST_ON: + bChangeNumFmt = sal_True; + switch( rOption.GetString()[0] ) + { + case 'A': aNumFmt.SetNumberingType(SVX_NUM_CHARS_UPPER_LETTER); break; + case 'a': aNumFmt.SetNumberingType(SVX_NUM_CHARS_LOWER_LETTER); break; + case 'I': aNumFmt.SetNumberingType(SVX_NUM_ROMAN_UPPER); break; + case 'i': aNumFmt.SetNumberingType(SVX_NUM_ROMAN_LOWER); break; + default: bChangeNumFmt = sal_False; + } + break; + + case HTML_UNORDERLIST_ON: + aNumFmt.SetBulletChar( (sal_Unicode)rOption.GetEnum( + aHTMLULTypeTable,aNumFmt.GetBulletChar() ) ); + bChangeNumFmt = sal_True; + break; + } + } + break; + case HTML_O_START: + { + sal_uInt16 nStart = (sal_uInt16)rOption.GetNumber(); + if( bNewNumFmt ) + { + aNumFmt.SetStart( nStart ); + bChangeNumFmt = sal_True; + } + else + { + rInfo.SetNodeStartValue( nLevel, nStart ); + } + } + break; + case HTML_O_STYLE: + aStyle = rOption.GetString(); + break; + case HTML_O_CLASS: + aClass = rOption.GetString(); + break; + case HTML_O_LANG: + aLang = rOption.GetString(); + break; + case HTML_O_DIR: + aDir = rOption.GetString(); + break; + case HTML_O_SRC: + if( bNewNumFmt ) + { + aBulletSrc = rOption.GetString(); + if( !InternalImgToPrivateURL(aBulletSrc) ) + aBulletSrc = URIHelper::SmartRel2Abs( INetURLObject( sBaseURL ), aBulletSrc, Link(), false ); + } + break; + case HTML_O_WIDTH: + nWidth = (sal_uInt16)rOption.GetNumber(); + break; + case HTML_O_HEIGHT: + nHeight = (sal_uInt16)rOption.GetNumber(); + break; + case HTML_O_ALIGN: + eVertOri = + (sal_Int16)rOption.GetEnum( aHTMLImgVAlignTable, + static_cast< sal_uInt16 >(eVertOri) ); + break; + } + } + + if( !aBulletSrc.isEmpty() ) + { + // Eine Bullet-Liste mit Grafiken + aNumFmt.SetNumberingType(SVX_NUM_BITMAP); + + // Die Grafik als Brush anlegen + SvxBrushItem aBrushItem( RES_BACKGROUND ); + aBrushItem.SetGraphicLink( aBulletSrc ); + aBrushItem.SetGraphicPos( GPOS_AREA ); + + // Die Groesse nur beachten, wenn Breite und Hoehe vorhanden sind + Size aTwipSz( nWidth, nHeight), *pTwipSz=0; + if( nWidth!=USHRT_MAX && nHeight!=USHRT_MAX ) + { + aTwipSz = + Application::GetDefaultDevice()->PixelToLogic( aTwipSz, + MapMode(MAP_TWIP) ); + pTwipSz = &aTwipSz; + } + + // Die Ausrichtung auch nur beachten, wenn eine Ausrichtung + // angegeben wurde + aNumFmt.SetGraphicBrush( &aBrushItem, pTwipSz, + text::VertOrientation::NONE!=eVertOri ? &eVertOri : 0); + + // Und noch die Grafik merken, um sie in den Absaetzen nicht + // einzufuegen + aBulletGrfs[nLevel] = aBulletSrc; + bChangeNumFmt = sal_True; + } + else + aBulletGrfs[nLevel] = ""; + + // den aktuellen Absatz erst einmal nicht numerieren + { + sal_uInt8 nLvl = nLevel; + SetNodeNum( nLvl, false ); + } + + // einen neuen Kontext anlegen + _HTMLAttrContext *pCntxt = new _HTMLAttrContext( static_cast< sal_uInt16 >(nToken) ); + + // Styles parsen + if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) ) + { + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + + if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) ) + { + if( bNewNumFmt ) + { + if( aPropInfo.bLeftMargin ) + { + // Der Der Default-Einzug wurde schon eingefuegt. + sal_uInt16 nAbsLSpace = + aNumFmt.GetAbsLSpace() - HTML_NUMBUL_MARGINLEFT; + if( aPropInfo.nLeftMargin < 0 && + nAbsLSpace < -aPropInfo.nLeftMargin ) + nAbsLSpace = 0U; + else if( aPropInfo.nLeftMargin > USHRT_MAX || + (long)nAbsLSpace + + aPropInfo.nLeftMargin > USHRT_MAX ) + nAbsLSpace = USHRT_MAX; + else + nAbsLSpace = nAbsLSpace + (sal_uInt16)aPropInfo.nLeftMargin; + + aNumFmt.SetAbsLSpace( nAbsLSpace ); + bChangeNumFmt = sal_True; + } + if( aPropInfo.bTextIndent ) + { + short nTextIndent = + ((const SvxLRSpaceItem &)aItemSet.Get( RES_LR_SPACE )) + .GetTxtFirstLineOfst(); + aNumFmt.SetFirstLineOffset( nTextIndent ); + bChangeNumFmt = sal_True; + } + } + aPropInfo.bLeftMargin = aPropInfo.bTextIndent = sal_False; + if( !aPropInfo.bRightMargin ) + aItemSet.ClearItem( RES_LR_SPACE ); + + // #i89812# - Perform change to list style before calling <DoPositioning(..)>, + // because <DoPositioning(..)> may open a new context and thus may + // clear the <SwHTMLNumRuleInfo> instance hold by local variable <rInfo>. + if( bChangeNumFmt ) + { + rInfo.GetNumRule()->Set( nLevel, aNumFmt ); + pDoc->ChgNumRuleFmts( *rInfo.GetNumRule() ); + bChangeNumFmt = sal_False; + } + + DoPositioning( aItemSet, aPropInfo, pCntxt ); + + InsertAttrs( aItemSet, aPropInfo, pCntxt ); + } + } + + if( bChangeNumFmt ) + { + rInfo.GetNumRule()->Set( nLevel, aNumFmt ); + pDoc->ChgNumRuleFmts( *rInfo.GetNumRule() ); + } + + PushContext( pCntxt ); + + // die Attribute der neuen Vorlage setzen + SetTxtCollAttrs( pCntxt ); +} + +void SwHTMLParser::EndNumBulList( int nToken ) +{ + SwHTMLNumRuleInfo& rInfo = GetNumInfo(); + + // Ein neuer Absatz muss aufgemacht werden, wenn + // - der aktuelle nicht leer ist, also Text oder absatzgebundene Objekte + // enthaelt. + // - der aktuelle Absatz numeriert ist. + sal_Bool bAppend = pPam->GetPoint()->nContent.GetIndex() > 0; + if( !bAppend ) + { + SwTxtNode* pTxtNode = pPam->GetNode()->GetTxtNode(); + + bAppend = (pTxtNode && ! pTxtNode->IsOutline() && pTxtNode->IsCountedInList()) || + + HasCurrentParaFlys(); + } + + sal_Bool bSpace = (rInfo.GetDepth() + nDefListDeep) == 1; + if( bAppend ) + AppendTxtNode( bSpace ? AM_SPACE : AM_NOSPACE, sal_False ); + else if( bSpace ) + AddParSpace(); + + // den aktuellen Kontext vom Stack holen + _HTMLAttrContext *pCntxt = nToken!=0 ? PopContext( static_cast< sal_uInt16 >(nToken & ~1) ) : 0; + + // Keine Liste aufgrund eines Tokens beenden, wenn der Kontext + // nie angelgt wurde oder nicht beendet werden darf. + if( rInfo.GetDepth()>0 && (!nToken || pCntxt) ) + { + rInfo.DecDepth(); + if( !rInfo.GetDepth() ) // wars der letze Level ? + { + // Die noch nicht angepassten Formate werden jetzt noch + // angepasst, damit es sich besser Editieren laesst. + const SwNumFmt *pRefNumFmt = 0; + sal_Bool bChanged = sal_False; + for( sal_uInt16 i=0; i<MAXLEVEL; i++ ) + { + const SwNumFmt *pNumFmt = rInfo.GetNumRule()->GetNumFmt(i); + if( pNumFmt ) + { + pRefNumFmt = pNumFmt; + } + else if( pRefNumFmt ) + { + SwNumFmt aNumFmt( rInfo.GetNumRule()->Get(i) ); + aNumFmt.SetNumberingType(pRefNumFmt->GetNumberingType() != SVX_NUM_BITMAP + ? pRefNumFmt->GetNumberingType() : style::NumberingType::CHAR_SPECIAL); + if( SVX_NUM_CHAR_SPECIAL == aNumFmt.GetNumberingType() ) + { + // #i63395# - Only apply user defined default bullet font + if ( numfunc::IsDefBulletFontUserDefined() ) + { + aNumFmt.SetBulletFont( &numfunc::GetDefBulletFont() ); + } + aNumFmt.SetBulletChar( cBulletChar ); + } + aNumFmt.SetAbsLSpace( (i+1) * HTML_NUMBUL_MARGINLEFT ); + aNumFmt.SetFirstLineOffset( HTML_NUMBUL_INDENT ); + aNumFmt.SetCharFmt( pRefNumFmt->GetCharFmt() ); + rInfo.GetNumRule()->Set( i, aNumFmt ); + bChanged = sal_True; + } + } + if( bChanged ) + pDoc->ChgNumRuleFmts( *rInfo.GetNumRule() ); + + // Beim letzen Append wurde das NumRule-Item und das + // NodeNum-Objekt mit kopiert. Beides muessen wir noch + // loeschen. Das ResetAttr loescht das NodeNum-Objekt mit! + pPam->GetNode()->GetTxtNode()->ResetAttr( RES_PARATR_NUMRULE ); + + rInfo.Clear(); + } + else + { + // the next paragraph not numbered first + SetNodeNum( rInfo.GetLevel(), false ); + } + } + + // und noch Attribute beenden + sal_Bool bSetAttrs = sal_False; + if( pCntxt ) + { + EndContext( pCntxt ); + delete pCntxt; + bSetAttrs = sal_True; + } + + if( nToken ) + SetTxtCollAttrs(); + + if( bSetAttrs ) + SetAttr(); // Absatz-Atts wegen JavaScript moeglichst schnell setzen + +} + +void SwHTMLParser::NewNumBulListItem( int nToken ) +{ + sal_uInt8 nLevel = GetNumInfo().GetLevel(); + OUString aId, aStyle, aClass, aLang, aDir; + sal_uInt16 nStart = HTML_LISTHEADER_ON != nToken + ? GetNumInfo().GetNodeStartValue( nLevel ) + : USHRT_MAX; + if( USHRT_MAX != nStart ) + GetNumInfo().SetNodeStartValue( nLevel ); + + const HTMLOptions& rHTMLOptions = GetOptions(); + for (size_t i = rHTMLOptions.size(); i; ) + { + const HTMLOption& rOption = rHTMLOptions[--i]; + switch( rOption.GetToken() ) + { + case HTML_O_VALUE: + nStart = (sal_uInt16)rOption.GetNumber(); + break; + case HTML_O_ID: + aId = rOption.GetString(); + break; + case HTML_O_STYLE: + aStyle = rOption.GetString(); + break; + case HTML_O_CLASS: + aClass = rOption.GetString(); + break; + case HTML_O_LANG: + aLang = rOption.GetString(); + break; + case HTML_O_DIR: + aDir = rOption.GetString(); + break; + } + } + + // einen neuen Absatz aufmachen + if( pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( AM_NOSPACE, sal_False ); + bNoParSpace = false; // In <LI> wird kein Abstand eingefuegt! + + const bool bCountedInList( HTML_LISTHEADER_ON==nToken ? false : true ); + + _HTMLAttrContext *pCntxt = new _HTMLAttrContext( static_cast< sal_uInt16 >(nToken) ); + + OUString aNumRuleName; + if( GetNumInfo().GetNumRule() ) + { + aNumRuleName = GetNumInfo().GetNumRule()->GetName(); + } + else + { + aNumRuleName = pDoc->GetUniqueNumRuleName(); + SwNumRule aNumRule( aNumRuleName, + SvxNumberFormat::LABEL_WIDTH_AND_POSITION ); + SwNumFmt aNumFmt( aNumRule.Get( 0 ) ); + // #i63395# - Only apply user defined default bullet font + if ( numfunc::IsDefBulletFontUserDefined() ) + { + aNumFmt.SetBulletFont( &numfunc::GetDefBulletFont() ); + } + aNumFmt.SetNumberingType(SVX_NUM_CHAR_SPECIAL); + aNumFmt.SetBulletChar( cBulletChar ); // das Bulletzeichen !! + aNumFmt.SetCharFmt( pCSS1Parser->GetCharFmtFromPool(RES_POOLCHR_BUL_LEVEL) ); + aNumFmt.SetLSpace( (sal_uInt16)(-HTML_NUMBUL_INDENT) ); + aNumFmt.SetFirstLineOffset( HTML_NUMBUL_INDENT ); + aNumRule.Set( 0, aNumFmt ); + + pDoc->MakeNumRule( aNumRuleName, &aNumRule ); + + OSL_ENSURE( !nOpenParaToken, + "Jetzt geht ein offenes Absatz-Element verloren" ); + // Wir tun so, als ob wir in einem Absatz sind. Dann wird + // beim naechsten Absatz wenigstens die Numerierung + // weggeschmissen, die nach dem naechsten AppendTxtNode uebernommen + // wird. + nOpenParaToken = static_cast< sal_uInt16 >(nToken); + } + + SwTxtNode* pTxtNode = pPam->GetNode()->GetTxtNode(); + ((SwCntntNode *)pTxtNode)->SetAttr( SwNumRuleItem(aNumRuleName) ); + pTxtNode->SetAttrListLevel(nLevel); + // #i57656# - <IsCounted()> state of text node has to be adjusted accordingly. + if ( nLevel < MAXLEVEL ) + { + pTxtNode->SetCountedInList( bCountedInList ); + } + // #i57919# + // correction of refactoring done by cws swnumtree + // - <nStart> contains the start value, if the numbering has to be restarted + // at this text node. Value <USHRT_MAX> indicates, that numbering isn't + // restarted at this text node + if ( nStart != USHRT_MAX ) + { + pTxtNode->SetListRestart( true ); + pTxtNode->SetAttrListRestartValue( nStart ); + } + + if( GetNumInfo().GetNumRule() ) + GetNumInfo().GetNumRule()->SetInvalidRule( sal_True ); + + // Styles parsen + if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) ) + { + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + + if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) ) + { + DoPositioning( aItemSet, aPropInfo, pCntxt ); + InsertAttrs( aItemSet, aPropInfo, pCntxt ); + } + } + + PushContext( pCntxt ); + + // die neue Vorlage setzen + SetTxtCollAttrs( pCntxt ); + + // Laufbalkenanzeige aktualisieren + ShowStatline(); +} + +void SwHTMLParser::EndNumBulListItem( int nToken, sal_Bool bSetColl, + sal_Bool /*bLastPara*/ ) +{ + // einen neuen Absatz aufmachen + if( !nToken && pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( AM_NOSPACE ); + + // Kontext zu dem Token suchen und vom Stack holen + _HTMLAttrContext *pCntxt = 0; + sal_uInt16 nPos = aContexts.size(); + nToken &= ~1; + while( !pCntxt && nPos>nContextStMin ) + { + sal_uInt16 nCntxtToken = aContexts[--nPos]->GetToken(); + switch( nCntxtToken ) + { + case HTML_LI_ON: + case HTML_LISTHEADER_ON: + if( !nToken || nToken == nCntxtToken ) + { + pCntxt = aContexts[nPos]; + aContexts.erase( aContexts.begin() + nPos ); + } + break; + case HTML_ORDERLIST_ON: + case HTML_UNORDERLIST_ON: + case HTML_MENULIST_ON: + case HTML_DIRLIST_ON: + // keine LI/LH ausserhalb der aktuellen Liste betrachten + nPos = nContextStMin; + break; + } + } + + // und noch Attribute beenden + if( pCntxt ) + { + EndContext( pCntxt ); + SetAttr(); // Absatz-Atts wegen JavaScript moeglichst schnell setzen + delete pCntxt; + } + + // und die bisherige Vorlage setzen + if( bSetColl ) + SetTxtCollAttrs(); +} + +void SwHTMLParser::SetNodeNum( sal_uInt8 nLevel, bool bCountedInList ) +{ + SwTxtNode* pTxtNode = pPam->GetNode()->GetTxtNode(); + OSL_ENSURE( pTxtNode, "Kein Text-Node an PaM-Position" ); + + OSL_ENSURE( GetNumInfo().GetNumRule(), "Kein Numerierungs-Regel" ); + const OUString& rName = GetNumInfo().GetNumRule()->GetName(); + ((SwCntntNode *)pTxtNode)->SetAttr( SwNumRuleItem(rName) ); + + pTxtNode->SetAttrListLevel( nLevel ); + pTxtNode->SetCountedInList( bCountedInList ); + + // NumRule invalidieren, weil sie durch ein EndAction bereits + // auf valid geschaltet worden sein kann. + GetNumInfo().GetNumRule()->SetInvalidRule( sal_False ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/filter/html/htmlnumwriter.cxx b/sw/source/filter/html/htmlnumwriter.cxx new file mode 100644 index 000000000000..0191dfb783ba --- /dev/null +++ b/sw/source/filter/html/htmlnumwriter.cxx @@ -0,0 +1,315 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/style/NumberingType.hpp> +#include <hintids.hxx> +#include <svtools/htmltokn.h> +#include <svtools/htmlkywd.hxx> +#include <svtools/htmlout.hxx> +#include <svl/urihelper.hxx> +#include <editeng/brushitem.hxx> +#include <editeng/lrspitem.hxx> +#include <vcl/svapp.hxx> +#include <vcl/wrkwin.hxx> +#include <numrule.hxx> +#include <doc.hxx> +#include <docary.hxx> +#include <poolfmt.hxx> +#include <ndtxt.hxx> +#include <paratr.hxx> + +#include "htmlnum.hxx" +#include "wrthtml.hxx" + +#include <SwNodeNum.hxx> +#include <rtl/strbuf.hxx> + +using namespace css; + + +void SwHTMLWriter::FillNextNumInfo() +{ + pNextNumRuleInfo = 0; + + sal_uLong nPos = pCurPam->GetPoint()->nNode.GetIndex() + 1; + + bool bTable = false; + do + { + const SwNode* pNd = pDoc->GetNodes()[nPos]; + if( pNd->IsTxtNode() ) + { + // Der naechste wird als naechstes ausgegeben. + pNextNumRuleInfo = new SwHTMLNumRuleInfo( *pNd->GetTxtNode() ); + + // Vor einer Tabelle behalten wir erst einmal die alte Ebene bei, + // wenn die gleiche Numerierung hinter der Tabelle + // fortgesetzt wird und dort nicht von vorne numeriert + // wird. Die Tabelle wird ann beim Import so weit eingeruckt, + // wie es der Num-Ebene entspricht. + if( bTable && + pNextNumRuleInfo->GetNumRule()==GetNumInfo().GetNumRule() && + !pNextNumRuleInfo->IsRestart() ) + { + pNextNumRuleInfo->SetDepth( GetNumInfo().GetDepth() ); + } + } + else if( pNd->IsTableNode() ) + { + // Eine Tabelle wird uebersprungen, also den Node + // hinter der Tabelle betrachten. + nPos = pNd->EndOfSectionIndex() + 1; + bTable = true; + } + else + { + // In allen anderen Faellen ist die Numerierung erstmal + // zu Ende. + pNextNumRuleInfo = new SwHTMLNumRuleInfo; + } + } + while( !pNextNumRuleInfo ); +} + +void SwHTMLWriter::ClearNextNumInfo() +{ + delete pNextNumRuleInfo; + pNextNumRuleInfo = 0; +} + +Writer& OutHTML_NumBulListStart( SwHTMLWriter& rWrt, + const SwHTMLNumRuleInfo& rInfo ) +{ + SwHTMLNumRuleInfo& rPrevInfo = rWrt.GetNumInfo(); + sal_Bool bSameRule = rPrevInfo.GetNumRule() == rInfo.GetNumRule(); + if( bSameRule && rPrevInfo.GetDepth() >= rInfo.GetDepth() && + !rInfo.IsRestart() ) + { + return rWrt; + } + + sal_Bool bStartValue = sal_False; + if( !bSameRule && rInfo.GetDepth() ) + { + OUString aName( rInfo.GetNumRule()->GetName() ); + if( 0 != rWrt.aNumRuleNames.count( aName ) ) + { + // The rule has been applied before + sal_Int16 eType = rInfo.GetNumRule() + ->Get( rInfo.GetDepth()-1 ).GetNumberingType(); + if( SVX_NUM_CHAR_SPECIAL != eType && SVX_NUM_BITMAP != eType ) + { + // If it's a numbering rule, the current number should be + // exported as start value, but only if there are no nodes + // within the numbering that have a lower level + bStartValue = sal_True; + if( rInfo.GetDepth() > 1 ) + { + sal_uLong nPos = + rWrt.pCurPam->GetPoint()->nNode.GetIndex() + 1; + do + { + const SwNode* pNd = rWrt.pDoc->GetNodes()[nPos]; + if( pNd->IsTxtNode() ) + { + const SwTxtNode *pTxtNd = pNd->GetTxtNode(); + if( !pTxtNd->GetNumRule() ) + { + // node isn't numbered => check completed + break; + } + + OSL_ENSURE(! pTxtNd->IsOutline(), + "outline not expected"); + + if( pTxtNd->GetActualListLevel() + 1 < + rInfo.GetDepth() ) + { + // node is numbered, but level is lower + // => check completed + bStartValue = sal_False; + break; + } + nPos++; + } + else if( pNd->IsTableNode() ) + { + // skip table + nPos = pNd->EndOfSectionIndex() + 1; + } + else + { + // end node or sections start node -> check + // completed + break; + } + } + while( true ); + } + } + } + else + { + rWrt.aNumRuleNames.insert( aName ); + } + } + + OSL_ENSURE( rWrt.nLastParaToken == 0, + "<PRE> wurde nicht vor <OL> beendet." ); + sal_uInt16 nPrevDepth = + (bSameRule && !rInfo.IsRestart()) ? rPrevInfo.GetDepth() : 0; + + for( sal_uInt16 i=nPrevDepth; i<rInfo.GetDepth(); i++ ) + { + rWrt.OutNewLine(); // <OL>/<UL> in eine neue Zeile + + rWrt.aBulletGrfs[i] = ""; + OStringBuffer sOut; + sOut.append('<'); + const SwNumFmt& rNumFmt = rInfo.GetNumRule()->Get( i ); + sal_Int16 eType = rNumFmt.GetNumberingType(); + if( SVX_NUM_CHAR_SPECIAL == eType ) + { + // Aufzaehlungs-Liste: <OL> + sOut.append(OOO_STRING_SVTOOLS_HTML_unorderlist); + + // den Typ ueber das Bullet-Zeichen bestimmen + const sal_Char *pStr = 0; + switch( rNumFmt.GetBulletChar() ) + { + case HTML_BULLETCHAR_DISC: + pStr = OOO_STRING_SVTOOLS_HTML_ULTYPE_disc; + break; + case HTML_BULLETCHAR_CIRCLE: + pStr = OOO_STRING_SVTOOLS_HTML_ULTYPE_circle; + break; + case HTML_BULLETCHAR_SQUARE: + pStr = OOO_STRING_SVTOOLS_HTML_ULTYPE_square; + break; + } + + if( pStr ) + { + sOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_type). + append("=\"").append(pStr).append("\""); + } + } + else if( SVX_NUM_BITMAP == eType ) + { + // Unordered list: <UL> + sOut.append(OOO_STRING_SVTOOLS_HTML_unorderlist); + rWrt.Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() ); + OutHTML_BulletImage( rWrt, + 0, + rNumFmt.GetBrush() ); + } + else + { + // Ordered list: <OL> + sOut.append(OOO_STRING_SVTOOLS_HTML_orderlist); + + // den Typ ueber das Format bestimmen + sal_Char cType = 0; + switch( eType ) + { + case SVX_NUM_CHARS_UPPER_LETTER: cType = 'A'; break; + case SVX_NUM_CHARS_LOWER_LETTER: cType = 'a'; break; + case SVX_NUM_ROMAN_UPPER: cType = 'I'; break; + case SVX_NUM_ROMAN_LOWER: cType = 'i'; break; + } + if( cType ) + { + sOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_type). + append("=\"").append(cType).append("\""); + } + + sal_uInt16 nStartVal = rNumFmt.GetStart(); + if( bStartValue && 1 == nStartVal && i == rInfo.GetDepth()-1 ) + { + // #i51089 - TUNING# + if ( rWrt.pCurPam->GetNode()->GetTxtNode()->GetNum() ) + { + nStartVal = static_cast< sal_uInt16 >( rWrt.pCurPam->GetNode() + ->GetTxtNode()->GetNumberVector()[i] ); + } + else + { + OSL_FAIL( "<OutHTML_NumBulListStart(..) - text node has no number." ); + } + } + if( nStartVal != 1 ) + { + sOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_start). + append("=\"").append(static_cast<sal_Int32>(nStartVal)).append("\""); + } + } + + if (!sOut.isEmpty()) + rWrt.Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() ); + + if( rWrt.bCfgOutStyles ) + OutCSS1_NumBulListStyleOpt( rWrt, *rInfo.GetNumRule(), (sal_uInt8)i ); + + rWrt.Strm().WriteChar( '>' ); + + rWrt.IncIndentLevel(); // Inhalt von <OL> einruecken + } + + return rWrt; +} + +Writer& OutHTML_NumBulListEnd( SwHTMLWriter& rWrt, + const SwHTMLNumRuleInfo& rNextInfo ) +{ + SwHTMLNumRuleInfo& rInfo = rWrt.GetNumInfo(); + sal_Bool bSameRule = rNextInfo.GetNumRule() == rInfo.GetNumRule(); + if( bSameRule && rNextInfo.GetDepth() >= rInfo.GetDepth() && + !rNextInfo.IsRestart() ) + { + return rWrt; + } + + OSL_ENSURE( rWrt.nLastParaToken == 0, + "<PRE> wurde nicht vor </OL> beendet." ); + sal_uInt16 nNextDepth = + (bSameRule && !rNextInfo.IsRestart()) ? rNextInfo.GetDepth() : 0; + + // MIB 23.7.97: Die Schleife muss doch rueckwaerts durchlaufen + // werden, weil die Reihenfolge von </OL>/</UL> stimmen muss + for( sal_uInt16 i=rInfo.GetDepth(); i>nNextDepth; i-- ) + { + rWrt.DecIndentLevel(); // Inhalt von <OL> einruecken + if( rWrt.bLFPossible ) + rWrt.OutNewLine(); // </OL>/</UL> in eine neue Zeile + + // es wird also eine Liste angefangen oder beendet: + sal_Int16 eType = rInfo.GetNumRule()->Get( i-1 ).GetNumberingType(); + const sal_Char *pStr; + if( SVX_NUM_CHAR_SPECIAL == eType || SVX_NUM_BITMAP == eType) + pStr = OOO_STRING_SVTOOLS_HTML_unorderlist; + else + pStr = OOO_STRING_SVTOOLS_HTML_orderlist; + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), pStr, false ); + rWrt.bLFPossible = sal_True; + } + + return rWrt; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |