blob: 4e14fdabe345417c75f723935f12a36fe7ce84f9 [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"
#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
#include <com/sun/star/document/XDocumentProperties.hpp>
#include <com/sun/star/i18n/ScriptType.hpp>
#include <sfx2/sfx.hrc>
#include <svx/svxids.hrc>
#ifdef DBG_UTIL
#include <stdlib.h>
#endif
#include <hintids.hxx>
#define _SVSTDARR_STRINGS
#include <svl/svstdarr.hxx>
#include <svl/stritem.hxx>
#include <svtools/imap.hxx>
#include <svtools/htmltokn.h>
#include <svtools/htmlkywd.hxx>
#include <svtools/ctrltool.hxx>
#include <unotools/pathoptions.hxx>
#include <vcl/svapp.hxx>
#include <vcl/wrkwin.hxx>
#include <sfx2/fcontnr.hxx>
#include <sfx2/docfile.hxx>
#include <svtools/htmlcfg.hxx>
#include <sfx2/linkmgr.hxx>
#include <editeng/kernitem.hxx>
#include <editeng/boxitem.hxx>
#include <editeng/fhgtitem.hxx>
#include <editeng/brkitem.hxx>
#include <editeng/postitem.hxx>
#include <editeng/wghtitem.hxx>
#include <editeng/crsditem.hxx>
#include <editeng/udlnitem.hxx>
#include <editeng/escpitem.hxx>
#include <editeng/blnkitem.hxx>
#include <editeng/ulspitem.hxx>
#include <editeng/colritem.hxx>
#include <editeng/fontitem.hxx>
#include <editeng/adjitem.hxx>
#include <editeng/lrspitem.hxx>
#include <editeng/protitem.hxx>
#include <editeng/flstitem.hxx>
#include <frmatr.hxx>
#include <charatr.hxx>
#include <fmtfld.hxx>
#include <fmtpdsc.hxx>
#include <txtfld.hxx>
#include <fmtanchr.hxx>
#include <fmtsrnd.hxx>
#include <fmtfsize.hxx>
#include <fmtclds.hxx>
#include <fchrfmt.hxx>
#include <fmtinfmt.hxx>
#include <docary.hxx>
#include <docstat.hxx>
#include <doc.hxx>
#include <IDocumentUndoRedo.hxx>
#include <pam.hxx>
#include <ndtxt.hxx>
#include <mdiexp.hxx> // ...Percent()
#include <expfld.hxx>
#include <poolfmt.hxx>
#include <pagedesc.hxx>
#include <IMark.hxx> // fuer SwBookmark ...
#include <docsh.hxx>
#include <editsh.hxx> // fuer Start/EndAction
#include <docufld.hxx>
#include <swcss1.hxx>
#include <htmlvsh.hxx>
#include <fltini.hxx>
#include <htmltbl.hxx>
#include <htmlnum.hxx>
#include <swhtml.hxx>
#include <linkenum.hxx>
#include <breakit.hxx>
#include <SwAppletImpl.hxx>
#include <sfx2/viewfrm.hxx>
#include <statstr.hrc> // ResId fuer Statusleiste
#include <swerror.h>
#define FONTSIZE_MASK 7
#define FONTCOLOR_MASK (1<<15)
#define FONT_MASK (1<<14)
#define HTML_ESC_PROP 80
#define HTML_ESC_SUPER DFLT_ESC_SUPER
#define HTML_ESC_SUB DFLT_ESC_SUB
#define HTML_SPTYPE_NONE 0
#define HTML_SPTYPE_BLOCK 1
#define HTML_SPTYPE_HORI 2
#define HTML_SPTYPE_VERT 3
#ifndef TOOLS_CONSTASCII_STRINGPARAM
#define TOOLS_CONSTASCII_STRINGPARAM( constAsciiStr ) constAsciiStr, sizeof( constAsciiStr )-1
#endif
using namespace ::com::sun::star;
// <P ALIGN=xxx>, <Hn ALIGN=xxx>, <TD ALIGN=xxx> usw.
HTMLOptionEnum __FAR_DATA aHTMLPAlignTable[] =
{
{ OOO_STRING_SVTOOLS_HTML_AL_left, SVX_ADJUST_LEFT },
{ OOO_STRING_SVTOOLS_HTML_AL_center, SVX_ADJUST_CENTER },
{ OOO_STRING_SVTOOLS_HTML_AL_middle, SVX_ADJUST_CENTER }, // Netscape
{ OOO_STRING_SVTOOLS_HTML_AL_right, SVX_ADJUST_RIGHT },
{ OOO_STRING_SVTOOLS_HTML_AL_justify, SVX_ADJUST_BLOCK },
{ OOO_STRING_SVTOOLS_HTML_AL_char, SVX_ADJUST_LEFT },
{ 0, 0 }
};
// <SPACER TYPE=...>
static HTMLOptionEnum __FAR_DATA aHTMLSpacerTypeTable[] =
{
{ OOO_STRING_SVTOOLS_HTML_SPTYPE_block, HTML_SPTYPE_BLOCK },
{ OOO_STRING_SVTOOLS_HTML_SPTYPE_horizontal, HTML_SPTYPE_HORI },
{ OOO_STRING_SVTOOLS_HTML_SPTYPE_vertical, HTML_SPTYPE_VERT },
{ 0, 0 }
};
SV_IMPL_PTRARR( _HTMLAttrs, _HTMLAttrPtr )
HTMLReader::HTMLReader()
{
bTmplBrowseMode = sal_True;
}
String HTMLReader::GetTemplateName() const
{
String sTemplate(
String::CreateFromAscii(TOOLS_CONSTASCII_STRINGPARAM("internal")) );
sTemplate += INET_PATH_TOKEN;
sTemplate.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM("html") );
String sTemplateWithoutExt( sTemplate );
#ifndef MAC_WITHOUT_EXT
// --> OD 2005-01-26 - first search for OpenDocument Writer/Web template
sTemplate.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM(".oth") );
// <--
#endif
SvtPathOptions aPathOpt;
// OpenDocument Writer/Web template (extension .oth)
sal_Bool bSet = aPathOpt.SearchFile( sTemplate, SvtPathOptions::PATH_TEMPLATE );
#ifndef MAC_WITHOUT_EXT
if( !bSet )
{
// 6.0 (extension .stw)
sTemplate = sTemplateWithoutExt;
// --> OD 2005-01-26 - no OpenDocument Writer/Web template found.
// search for OpenOffice.org Writer/Web template
sTemplate.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM(".stw") );
// <--
bSet = aPathOpt.SearchFile( sTemplate, SvtPathOptions::PATH_TEMPLATE );
}
#endif
if( !bSet )
{
sTemplate.Erase();
ASSERT( !this,
"Die html.vor befindet sich nicht mehr im definierten Directory!");
}
return sTemplate;
}
int HTMLReader::SetStrmStgPtr()
{
ASSERT( pMedium, "Wo ist das Medium??" );
if( pMedium->IsRemote() || !pMedium->IsStorage() )
{
pStrm = pMedium->GetInStream();
return sal_True;
}
return sal_False;
}
// Aufruf fuer die allg. Reader-Schnittstelle
sal_uLong HTMLReader::Read( SwDoc &rDoc, const String& rBaseURL, SwPaM &rPam, const String & rName )
{
if( !pStrm )
{
ASSERT( pStrm, "HTML-Read ohne Stream" );
return ERR_SWG_READ_ERROR;
}
if( !bInsertMode )
{
Reader::SetNoOutlineNum( rDoc );
Reader::ResetFrmFmts( rDoc );
// Die HTML-Seitenvorlage setzen, wenn des kein HTML-Dokument ist,
// sonst ist sie schon gesetzt.
if( !rDoc.get(IDocumentSettingAccess::HTML_MODE) )
{
rDoc.InsertPoolItem( rPam, SwFmtPageDesc(
rDoc.GetPageDescFromPool( RES_POOLPAGE_HTML, false )), 0 );
}
}
// damit keiner das Doc klaut!
rDoc.acquire();
sal_uLong nRet = 0;
SvParserRef xParser = new SwHTMLParser( &rDoc, rPam, *pStrm,
rName, rBaseURL, !bInsertMode, pMedium,
IsReadUTF8(),
bIgnoreHTMLComments );
SvParserState eState = xParser->CallParser();
if( SVPAR_PENDING == eState )
pStrm->ResetError();
else if( SVPAR_ACCEPTED != eState )
{
String sErr( String::CreateFromInt32((sal_Int32)xParser->GetLineNr()));
sErr += ',';
sErr += String::CreateFromInt32((sal_Int32)xParser->GetLinePos());
// den Stream als Fehlernummer Transporter benutzen
nRet = *new StringErrorInfo( ERR_FORMAT_ROWCOL, sErr,
ERRCODE_BUTTON_OK | ERRCODE_MSG_ERROR );
}
return nRet;
}
/* */
SwHTMLParser::SwHTMLParser( SwDoc* pD, const SwPaM& rCrsr, SvStream& rIn,
const String& rPath,
const String& rBaseURL,
int bReadNewDoc,
SfxMedium* pMed, sal_Bool bReadUTF8,
sal_Bool bNoHTMLComments )
: SfxHTMLParser( rIn, static_cast< sal_Bool >(bReadNewDoc), pMed ),
SwClient( 0 ),
aPathToFile( rPath ),
sBaseURL( rBaseURL ),
pAppletImpl( 0 ),
pCSS1Parser( 0 ),
pNumRuleInfo( new SwHTMLNumRuleInfo ),
pPendStack( 0 ),
pDoc( pD ),
pActionViewShell( 0 ),
pSttNdIdx( 0 ),
pTable(0),
pFormImpl( 0 ),
pMarquee( 0 ),
pField( 0 ),
pImageMap( 0 ),
pImageMaps( 0 ),
pFootEndNoteImpl( 0 ),
nScriptStartLineNr( 0 ),
nBaseFontStMin( 0 ),
nFontStMin( 0 ),
nDefListDeep( 0 ),
nFontStHeadStart( 0 ),
nSBModuleCnt( 0 ),
nMissingImgMaps( 0 ),
nParaCnt( 5 ),
// --> OD 2007-10-26 #i83625#
nContextStMin( 0 ),
nContextStAttrMin( 0 ),
// <--
nOpenParaToken( 0 ),
eJumpTo( JUMPTO_NONE ),
#ifdef DBG_UTIL
nContinue( 0 ),
#endif
eParaAdjust( SVX_ADJUST_END ),
bDocInitalized( sal_False ),
bSetModEnabled( sal_False ),
bInFloatingFrame( sal_False ),
bInField( sal_False ),
bCallNextToken( sal_False ),
bIgnoreRawData( sal_False ),
bNoParSpace( sal_False ),
bInNoEmbed( sal_False ),
bInTitle( sal_False ),
bUpdateDocStat( sal_False ),
bFixSelectWidth( sal_False ),
bFixSelectHeight( sal_False ),
bTextArea( sal_False ),
bSelect( sal_False ),
bInFootEndNoteAnchor( sal_False ),
bInFootEndNoteSymbol( sal_False ),
// bIgnoreHTMLComments( bNoHTMLComments )
bIgnoreHTMLComments( bNoHTMLComments ),
bRemoveHidden( sal_False ),
pTempViewFrame(0)
{
nEventId = 0;
bUpperSpace = bViewCreated = bChkJumpMark =
bSetCrsr = sal_False;
eScriptLang = HTML_SL_UNKNOWN;
bAnyStarBasic = sal_True;
pPam = new SwPaM( *rCrsr.GetPoint() );
memset( &aAttrTab, 0, sizeof( _HTMLAttrTable ));
// Die Font-Groessen 1-7 aus der INI-Datei lesen
SvxHtmlOptions* pHtmlOptions = SvxHtmlOptions::Get();
aFontHeights[0] = pHtmlOptions->GetFontSize( 0 ) * 20;
aFontHeights[1] = pHtmlOptions->GetFontSize( 1 ) * 20;
aFontHeights[2] = pHtmlOptions->GetFontSize( 2 ) * 20;
aFontHeights[3] = pHtmlOptions->GetFontSize( 3 ) * 20;
aFontHeights[4] = pHtmlOptions->GetFontSize( 4 ) * 20;
aFontHeights[5] = pHtmlOptions->GetFontSize( 5 ) * 20;
aFontHeights[6] = pHtmlOptions->GetFontSize( 6 ) * 20;
bKeepUnknown = pHtmlOptions->IsImportUnknown();
if(bReadNewDoc)
{
SvxFontHeightItem aFontHeight(aFontHeights[2], 100, RES_CHRATR_FONTSIZE);
pDoc->SetDefault( aFontHeight );
aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE );
pDoc->SetDefault( aFontHeight );
aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE );
pDoc->SetDefault( aFontHeight );
}
// Waehrend des Imports in den HTML-Modus schalten, damit die
// richrigen Vorlagen angelegt werden
bOldIsHTMLMode = pDoc->get(IDocumentSettingAccess::HTML_MODE);
pDoc->set(IDocumentSettingAccess::HTML_MODE, true);
pCSS1Parser = new SwCSS1Parser( pDoc, aFontHeights, sBaseURL, IsNewDoc() );
pCSS1Parser->SetIgnoreFontFamily( pHtmlOptions->IsIgnoreFontFamily() );
if( bReadUTF8 )
{
SetSrcEncoding( RTL_TEXTENCODING_UTF8 );
}
else
{
SwDocShell *pDocSh = pDoc->GetDocShell();
SvKeyValueIterator *pHeaderAttrs =
pDocSh->GetHeaderAttributes();
if( pHeaderAttrs )
SetEncodingByHTTPHeader( pHeaderAttrs );
}
pCSS1Parser->SetDfltEncoding( gsl_getSystemTextEncoding() );
// Timer nur bei ganz normalen Dokumenten aufsetzen!
SwDocShell* pDocSh = pDoc->GetDocShell();
if( pDocSh )
{
bViewCreated = sal_True; // nicht, synchron laden
// es ist ein Sprungziel vorgegeben.
if( pMed )
{
sJmpMark = pMed->GetURLObject().GetMark();
if( sJmpMark.Len() )
{
eJumpTo = JUMPTO_MARK;
String sCmp;
xub_StrLen nLastPos, nPos = 0;
while( STRING_NOTFOUND != ( nLastPos =
sJmpMark.Search( cMarkSeperator, nPos + 1 )) )
nPos = nLastPos;
if( nPos && ( sCmp = sJmpMark.Copy( nPos + 1 ) ).
EraseAllChars().Len() )
{
sCmp.ToLowerAscii();
if( sCmp.EqualsAscii( pMarkToRegion ) )
eJumpTo = JUMPTO_REGION;
else if( sCmp.EqualsAscii( pMarkToTable ) )
eJumpTo = JUMPTO_TABLE;
else if( sCmp.EqualsAscii( pMarkToGraphic ) )
eJumpTo = JUMPTO_GRAPHIC;
else if( sCmp.EqualsAscii( pMarkToOutline ) ||
sCmp.EqualsAscii( pMarkToText ) ||
sCmp.EqualsAscii( pMarkToFrame ) )
eJumpTo = JUMPTO_NONE; // das ist nichts gueltiges!
else
// ansonsten ist das ein normaler (Book)Mark
nPos = STRING_LEN;
}
else
nPos = STRING_LEN;
sJmpMark.Erase( nPos );
if( !sJmpMark.Len() )
eJumpTo = JUMPTO_NONE;
}
}
}
}
__EXPORT SwHTMLParser::~SwHTMLParser()
{
#ifdef DBG_UTIL
ASSERT( !nContinue, "DTOR im Continue - Das geht schief!!!" );
#endif
sal_Bool bAsync = pDoc->IsInLoadAsynchron();
pDoc->SetInLoadAsynchron( sal_False );
pDoc->set(IDocumentSettingAccess::HTML_MODE, bOldIsHTMLMode);
if( pDoc->GetDocShell() && nEventId )
Application::RemoveUserEvent( nEventId );
// das DocumentDetected kann ggfs. die DocShells loeschen, darum nochmals
// abfragen
if( pDoc->GetDocShell() )
{
// Gelinkte Bereiche updaten
sal_uInt16 nLinkMode = pDoc->getLinkUpdateMode( true );
if( nLinkMode != NEVER && bAsync &&
SFX_CREATE_MODE_INTERNAL!=pDoc->GetDocShell()->GetCreateMode() )
pDoc->GetLinkManager().UpdateAllLinks( nLinkMode == MANUAL,
sal_True, sal_False );
if ( pDoc->GetDocShell()->IsLoading() )
{
// --> OD 2006-11-07 #i59688#
pDoc->GetDocShell()->LoadingFinished();
}
}
delete pSttNdIdx;
if( aSetAttrTab.Count() )
{
ASSERT( !aSetAttrTab.Count(),"Es stehen noch Attribute auf dem Stack" );
aSetAttrTab.DeleteAndDestroy( 0, aSetAttrTab.Count() );
}
delete pPam;
delete pCSS1Parser;
delete pNumRuleInfo;
DeleteFormImpl();
DeleteFootEndNoteImpl();
ASSERT( !pTable, "Es existiert noch eine offene Tabelle" );
delete pImageMaps;
//delete pTable;
ASSERT( !pPendStack,
"SwHTMLParser::~SwHTMLParser: Hier sollte es keinen Pending-Stack mehr geben" );
while( pPendStack )
{
SwPendingStack* pTmp = pPendStack;
pPendStack = pPendStack->pNext;
delete pTmp->pData;
delete pTmp;
}
if( !pDoc->release() )
{
// keiner will mehr das Doc haben, also weg damit
delete pDoc;
pDoc = NULL;
}
if ( pTempViewFrame )
{
pTempViewFrame->DoClose();
// the temporary view frame is hidden, so the hidden flag might need to be removed
if ( bRemoveHidden && pDoc && pDoc->GetDocShell() && pDoc->GetDocShell()->GetMedium() )
pDoc->GetDocShell()->GetMedium()->GetItemSet()->ClearItem( SID_HIDDEN );
}
}
IMPL_LINK( SwHTMLParser, AsyncCallback, void*, /*pVoid*/ )
{
nEventId=0;
// --> FME 2005-08-18 #i47907# If the document has already been destructed,
// the parser should be aware of this:
if( ( pDoc->GetDocShell() && pDoc->GetDocShell()->IsAbortingImport() )
|| 1 == pDoc->getReferenceCount() )
{
// wurde der Import vom SFX abgebrochen?
eState = SVPAR_ERROR;
}
// <--
GetAsynchCallLink().Call(0);
return 0;
}
SvParserState __EXPORT SwHTMLParser::CallParser()
{
// einen temporaeren Index anlegen, auf Pos 0 so wird er nicht bewegt!
pSttNdIdx = new SwNodeIndex( pDoc->GetNodes() );
if( !IsNewDoc() ) // in ein Dokument einfuegen ?
{
const SwPosition* pPos = pPam->GetPoint();
pDoc->SplitNode( *pPos, false );
*pSttNdIdx = pPos->nNode.GetIndex()-1;
pDoc->SplitNode( *pPos, false );
SwPaM aInsertionRangePam( *pPos );
pPam->Move( fnMoveBackward );
// #106634# split any redline over the insertion point
aInsertionRangePam.SetMark();
*aInsertionRangePam.GetPoint() = *pPam->GetPoint();
aInsertionRangePam.Move( fnMoveBackward );
pDoc->SplitRedline( aInsertionRangePam );
pDoc->SetTxtFmtColl( *pPam,
pCSS1Parser->GetTxtCollFromPool( RES_POOLCOLL_STANDARD ));
}
if( GetMedium() )
{
if( !bViewCreated )
{
nEventId = Application::PostUserEvent( LINK( this, SwHTMLParser, AsyncCallback ), 0 );
}
else
{
bViewCreated = sal_True;
nEventId = 0;
}
}
// Laufbalken anzeigen
else if( !GetMedium() || !GetMedium()->IsRemote() )
{
rInput.Seek(STREAM_SEEK_TO_END);
rInput.ResetError();
::StartProgress( STR_STATSTR_W4WREAD, 0, rInput.Tell(),
pDoc->GetDocShell() );
rInput.Seek(STREAM_SEEK_TO_BEGIN);
rInput.ResetError();
}
SwPageDesc& rDesc = pDoc->_GetPageDesc( 0 );
rDesc.Add( this );
SvParserState eRet = HTMLParser::CallParser();
return eRet;
}
void __EXPORT SwHTMLParser::Continue( int nToken )
{
#ifdef DBG_UTIL
ASSERT( !nContinue, "Continue im Continue - Das sollte doch nicht sein, oder?" );
nContinue++;
#endif
// Wenn der Import (vom SFX) abgebrochen wurde, wird ein Fehler
// gesetzt aber trotzdem noch weiter gemacht, damit vernuenftig
// aufgeraeumt wird.
ASSERT( SVPAR_ERROR!=eState,
"SwHTMLParser::Continue: bereits ein Fehler gesetzt" );
if( pDoc->GetDocShell() && pDoc->GetDocShell()->IsAbortingImport() )
eState = SVPAR_ERROR;
// Die ViewShell vom Dokument holen, merken und als aktuelle setzen.
ViewShell *pInitVSh = CallStartAction();
if( SVPAR_ERROR != eState && GetMedium() && !bViewCreated )
{
// Beim ersten Aufruf erstmal returnen, Doc anzeigen
// und auf Timer Callback warten.
// An dieser Stelle wurde im CallParser gerade mal ein Zeichen
// gelesen und ein SaveState(0) gerufen.
eState = SVPAR_PENDING;
bViewCreated = sal_True;
pDoc->SetInLoadAsynchron( sal_True );
#ifdef DBG_UTIL
nContinue--;
#endif
return;
}
bSetModEnabled = sal_False;
if( pDoc->GetDocShell() &&
0 != (bSetModEnabled = pDoc->GetDocShell()->IsEnableSetModified()) )
{
pDoc->GetDocShell()->EnableSetModified( sal_False );
}
// waehrend des einlesens kein OLE-Modified rufen
Link aOLELink( pDoc->GetOle2Link() );
pDoc->SetOle2Link( Link() );
sal_Bool bModified = pDoc->IsModified();
bool const bWasUndo = pDoc->GetIDocumentUndoRedo().DoesUndo();
pDoc->GetIDocumentUndoRedo().DoUndo(false);
// Wenn der Import abgebrochen wird, kein Continue mehr rufen.
// Falls ein Pending-Stack existiert aber durch einen Aufruf
// von NextToken dafuer sorgen, dass der Pending-Stack noch
// beendet wird.
if( SVPAR_ERROR == eState )
{
ASSERT( !pPendStack || pPendStack->nToken,
"SwHTMLParser::Continue: Pending-Stack ohne Token" );
if( pPendStack && pPendStack->nToken )
NextToken( pPendStack->nToken );
ASSERT( !pPendStack,
"SwHTMLParser::Continue: Es gibt wieder einen Pend-Stack" );
}
else
{
HTMLParser::Continue( pPendStack ? pPendStack->nToken : nToken );
}
// Laufbalken wieder abschalten
EndProgress( pDoc->GetDocShell() );
sal_Bool bLFStripped = sal_False;
if( SVPAR_PENDING != GetStatus() )
{
// noch die letzten Attribute setzen
{
if( aScriptSource.Len() )
{
SwScriptFieldType *pType =
(SwScriptFieldType*)pDoc->GetSysFldType( RES_SCRIPTFLD );
SwScriptField aFld( pType, aScriptType, aScriptSource,
sal_False );
InsertAttr( SwFmtFld( aFld ) );
}
if( pAppletImpl )
{
if( pAppletImpl->GetApplet().is() )
EndApplet();
else
EndObject();
}
// ggf. ein noch vorhandes LF hinter dem letzen Absatz entfernen
if( IsNewDoc() )
bLFStripped = StripTrailingLF() > 0;
// noch offene Nummerierungen beenden.
while( GetNumInfo().GetNumRule() )
EndNumBulList();
ASSERT( !nContextStMin, "Es gibt geschuetzte Kontexte" );
nContextStMin = 0;
while( aContexts.Count() )
{
_HTMLAttrContext *pCntxt = PopContext();
if( pCntxt )
{
EndContext( pCntxt );
delete pCntxt;
}
}
if( aParaAttrs.Count() )
aParaAttrs.Remove( 0, aParaAttrs.Count() );
SetAttr( sal_False );
// Noch die erst verzoegert gesetzten Styles setzen
pCSS1Parser->SetDelayedStyles();
}
// den Start wieder korrigieren
if( !IsNewDoc() && pSttNdIdx->GetIndex() )
{
SwTxtNode* pTxtNode = pSttNdIdx->GetNode().GetTxtNode();
SwNodeIndex aNxtIdx( *pSttNdIdx );
if( pTxtNode && pTxtNode->CanJoinNext( &aNxtIdx ))
{
xub_StrLen nStt = pTxtNode->GetTxt().Len();
// wenn der Cursor noch in dem Node steht, dann setze in an das Ende
if( pPam->GetPoint()->nNode == aNxtIdx )
{
pPam->GetPoint()->nNode = *pSttNdIdx;
pPam->GetPoint()->nContent.Assign( pTxtNode, nStt );
}
#ifdef DBG_UTIL
// !!! sollte nicht moeglich sein, oder ??
ASSERT( pSttNdIdx->GetIndex()+1 != pPam->GetBound( sal_True ).nNode.GetIndex(),
"Pam.Bound1 steht noch im Node" );
ASSERT( pSttNdIdx->GetIndex()+1 != pPam->GetBound( sal_False ).nNode.GetIndex(),
"Pam.Bound2 steht noch im Node" );
if( pSttNdIdx->GetIndex()+1 == pPam->GetBound( sal_True ).nNode.GetIndex() )
{
xub_StrLen nCntPos = pPam->GetBound( sal_True ).nContent.GetIndex();
pPam->GetBound( sal_True ).nContent.Assign( pTxtNode,
pTxtNode->GetTxt().Len() + nCntPos );
}
if( pSttNdIdx->GetIndex()+1 == pPam->GetBound( sal_False ).nNode.GetIndex() )
{
xub_StrLen nCntPos = pPam->GetBound( sal_False ).nContent.GetIndex();
pPam->GetBound( sal_False ).nContent.Assign( pTxtNode,
pTxtNode->GetTxt().Len() + nCntPos );
}
#endif
// Zeichen Attribute beibehalten!
SwTxtNode* pDelNd = aNxtIdx.GetNode().GetTxtNode();
if( pTxtNode->GetTxt().Len() )
pDelNd->FmtToTxtAttr( pTxtNode );
else
pTxtNode->ChgFmtColl( pDelNd->GetTxtColl() );
pTxtNode->JoinNext();
}
}
}
if( SVPAR_ACCEPTED == eState )
{
if( nMissingImgMaps )
{
// es fehlen noch ein paar Image-Map zuordungen.
// vielleicht sind die Image-Maps ja jetzt da?
ConnectImageMaps();
}
// jetzt noch den letzten ueberfluessigen Absatz loeschen
SwPosition* pPos = pPam->GetPoint();
if( !pPos->nContent.GetIndex() && !bLFStripped )
{
SwTxtNode* pAktNd;
sal_uLong nNodeIdx = pPos->nNode.GetIndex();
sal_Bool bHasFlysOrMarks =
HasCurrentParaFlys() || HasCurrentParaBookmarks( sal_True );
if( IsNewDoc() )
{
const SwNode *pPrev = pDoc->GetNodes()[nNodeIdx -1];
if( !pPam->GetPoint()->nContent.GetIndex() &&
( pPrev->IsCntntNode() ||
(pPrev->IsEndNode() &&
pPrev->StartOfSectionNode()->IsSectionNode()) ) )
{
SwCntntNode* pCNd = pPam->GetCntntNode();
if( pCNd && pCNd->StartOfSectionIndex()+2 <
pCNd->EndOfSectionIndex() && !bHasFlysOrMarks )
{
ViewShell *pVSh = CheckActionViewShell();
SwCrsrShell *pCrsrSh = pVSh && pVSh->ISA(SwCrsrShell)
? static_cast < SwCrsrShell * >( pVSh )
: 0;
if( pCrsrSh &&
pCrsrSh->GetCrsr()->GetPoint()
->nNode.GetIndex() == nNodeIdx )
{
pCrsrSh->MovePara(fnParaPrev, fnParaEnd );
pCrsrSh->SetMark();
pCrsrSh->ClearMark();
}
pPam->GetBound(sal_True).nContent.Assign( 0, 0 );
pPam->GetBound(sal_False).nContent.Assign( 0, 0 );
pDoc->GetNodes().Delete( pPam->GetPoint()->nNode );
}
}
}
else if( 0 != ( pAktNd = pDoc->GetNodes()[ nNodeIdx ]->GetTxtNode()) && !bHasFlysOrMarks )
{
if( pAktNd->CanJoinNext( &pPos->nNode ))
{
SwTxtNode* pNextNd = pPos->nNode.GetNode().GetTxtNode();
pPos->nContent.Assign( pNextNd, 0 );
pPam->SetMark(); pPam->DeleteMark();
pNextNd->JoinPrev();
}
else if( !pAktNd->GetTxt().Len() )
{
pPos->nContent.Assign( 0, 0 );
pPam->SetMark(); pPam->DeleteMark();
pDoc->GetNodes().Delete( pPos->nNode, 1 );
pPam->Move( fnMoveBackward );
}
}
}
// nun noch das SplitNode vom Anfang aufheben
else if( !IsNewDoc() )
{
if( pPos->nContent.GetIndex() ) // dann gabs am Ende kein <P>,
pPam->Move( fnMoveForward, fnGoNode ); // als zum naechsten Node
SwTxtNode* pTxtNode = pPos->nNode.GetNode().GetTxtNode();
SwNodeIndex aPrvIdx( pPos->nNode );
if( pTxtNode && pTxtNode->CanJoinPrev( &aPrvIdx ) &&
*pSttNdIdx <= aPrvIdx )
{
// eigentlich muss hier ein JoinNext erfolgen, aber alle Cursor
// usw. sind im pTxtNode angemeldet, so dass der bestehen
// bleiben MUSS.
// Absatz in Zeichen-Attribute umwandeln, aus dem Prev die
// Absatzattribute und die Vorlage uebernehmen!
SwTxtNode* pPrev = aPrvIdx.GetNode().GetTxtNode();
pTxtNode->ChgFmtColl( pPrev->GetTxtColl() );
pTxtNode->FmtToTxtAttr( pPrev );
pTxtNode->ResetAllAttr();
if( pPrev->HasSwAttrSet() )
pTxtNode->SetAttr( *pPrev->GetpSwAttrSet() );
if( &pPam->GetBound(sal_True).nNode.GetNode() == pPrev )
pPam->GetBound(sal_True).nContent.Assign( pTxtNode, 0 );
if( &pPam->GetBound(sal_False).nNode.GetNode() == pPrev )
pPam->GetBound(sal_False).nContent.Assign( pTxtNode, 0 );
pTxtNode->JoinPrev();
}
}
// und noch die DocumentInfo aufbereiten
if( IsNewDoc() )
{
SwDocShell *pDocShell(pDoc->GetDocShell());
DBG_ASSERT(pDocShell, "no SwDocShell");
if (pDocShell) {
uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
pDocShell->GetModel(), uno::UNO_QUERY_THROW);
uno::Reference<document::XDocumentProperties> xDocProps(
xDPS->getDocumentProperties());
DBG_ASSERT(xDocProps.is(), "DocumentProperties is null");
if ( xDocProps.is() && (xDocProps->getAutoloadSecs() > 0) &&
xDocProps->getAutoloadURL().equalsAscii("") )
{
xDocProps->setAutoloadURL(aPathToFile);
}
}
}
if( bUpdateDocStat )
{
SwDocStat aStat( pDoc->GetDocStat() );
pDoc->UpdateDocStat( aStat );
}
}
if( SVPAR_PENDING != GetStatus() )
delete pSttNdIdx, pSttNdIdx = 0;
// sollte der Parser der Letzte sein, der das Doc haelt, dann braucht
// man hier auch nichts mehr tun, Doc wird gleich zerstoert!
if( 1 < pDoc->getReferenceCount() )
{
if( bWasUndo )
{
pDoc->GetIDocumentUndoRedo().DelAllUndoObj();
pDoc->GetIDocumentUndoRedo().DoUndo(true);
}
else if( !pInitVSh )
{
// Wenn zu Beginn des Continue keine Shell vorhanden war,
// kann trotzdem mitlerweile eine angelegt worden sein.
// In dieses Fall stimmt das bWasUndo-Flag nicht und
// wir muessen das Undo noch anschalten.
ViewShell *pTmpVSh = CheckActionViewShell();
if( pTmpVSh )
{
pDoc->GetIDocumentUndoRedo().DoUndo(true);
}
}
pDoc->SetOle2Link( aOLELink );
if( !bModified )
pDoc->ResetModified();
if( bSetModEnabled && pDoc->GetDocShell() )
{
pDoc->GetDocShell()->EnableSetModified( sal_True );
bSetModEnabled = sal_False; // this is unnecessary here
}
}
// Wenn die Dokuemnt-ViewShell noch existiert und eine Action
// offen ist (muss bei Abbruch nicht sein), die Action beenden,
// uns von der Shell abmelden und schliesslich die alte Shell
// wieder rekonstruieren.
CallEndAction( sal_True );
#ifdef DBG_UTIL
nContinue--;
#endif
}
void SwHTMLParser::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew )
{
switch( pOld ? pOld->Which() : pNew ? pNew->Which() : 0 )
{
case RES_OBJECTDYING:
if( ((SwPtrMsgPoolItem *)pOld)->pObject == GetRegisteredIn() )
{
// dann uns selbst beenden
GetRegisteredInNonConst()->Remove( this );
ReleaseRef(); // ansonsten sind wir fertig!
}
break;
}
}
void SwHTMLParser::DocumentDetected()
{
ASSERT( !bDocInitalized, "DocumentDetected mehrfach aufgerufen" );
bDocInitalized = sal_True;
if( IsNewDoc() )
{
if( IsInHeader() )
FinishHeader( sal_True );
CallEndAction( sal_True, sal_True );
pDoc->GetIDocumentUndoRedo().DoUndo(false);
// Durch das DocumentDetected wurde im allgemeinen eine
// ViewShell angelegt. Es kann aber auch sein, dass sie
// erst spaeter angelegt wird, naemlich dann, wenn die UI
// gecaptured ist.
CallStartAction();
}
}
// wird fuer jedes Token gerufen, das in CallParser erkannt wird
void __EXPORT SwHTMLParser::NextToken( int nToken )
{
if( ( pDoc->GetDocShell() && pDoc->GetDocShell()->IsAbortingImport() )
|| 1 == pDoc->getReferenceCount() )
{
// wurde der Import vom SFX abgebrochen? Wenn ein Pending-Stack
// existiert den noch aufraumen
eState = SVPAR_ERROR;
ASSERT( !pPendStack || pPendStack->nToken,
"SwHTMLParser::NextToken: Pending-Stack ohne Token" );
if( 1 == pDoc->getReferenceCount() || !pPendStack )
return ;
}
#ifdef DBG_UTIL
if( pPendStack )
{
switch( nToken )
{
// Tabellen werden ueber rekusive Methodenaufrufe gelesen
case HTML_TABLE_ON:
// Bei CSS-Deklarationen muss evtl. noch auf das
// Ende eines File-Downloads gewartet werden.
case HTML_LINK:
// Bei Controls muss evtl. noch die Groesse gesetzt werden.
case HTML_INPUT:
case HTML_TEXTAREA_ON:
case HTML_SELECT_ON:
case HTML_SELECT_OFF:
break;
default:
ASSERT( !pPendStack, "Unbekanntes Token fuer Pending-Stack" );
break;
}
}
#endif
// Die folgeneden Spezialfaelle muessen vor der Filter-Detection behandelt
// werden, denn der Inhalt des Titels, etc. wird auch in Netcape nicht
// zur Filter-Detection herangezogen.
if( !pPendStack )
{
if( bInTitle )
{
switch( nToken )
{
case HTML_TITLE_OFF:
if( IsNewDoc() && sTitle.Len() )
{
if( pDoc->GetDocShell() ) {
uno::Reference<document::XDocumentPropertiesSupplier>
xDPS(pDoc->GetDocShell()->GetModel(),
uno::UNO_QUERY_THROW);
uno::Reference<document::XDocumentProperties> xDocProps(
xDPS->getDocumentProperties());
DBG_ASSERT(xDocProps.is(), "no DocumentProperties");
if (xDocProps.is()) {
xDocProps->setTitle(sTitle);
}
pDoc->GetDocShell()->SetTitle( sTitle );
}
}
bInTitle = sal_False;
sTitle.Erase();
break;
case HTML_NONBREAKSPACE:
sTitle += ' ';
break;
case HTML_SOFTHYPH:
sTitle += '-';
break;
case HTML_TEXTTOKEN:
sTitle += aToken;
break;
default:
sTitle += '<';
if( (HTML_TOKEN_ONOFF & nToken) && (1 & nToken) )
sTitle += '/';
sTitle += sSaveToken;
if( aToken.Len() )
{
sTitle += ' ';
sTitle += aToken;
}
sTitle += '>';
break;
}
return;
}
}
// Wenn wir noch nicht wissen, was fuer ein Dokument wir vor uns haben,
// versuchen wir das erstmal rauszufinden. Das muss fuer Controls in
// Fall vor dem Einfuegen des Controls passieren, weil beim Einfuegen
// bereits eine View benoetigt wird.
if( !bDocInitalized )
DocumentDetected();
sal_Bool bGetIDOption = sal_False, bInsertUnknown = sal_False;
sal_Bool bUpperSpaceSave = bUpperSpace;
bUpperSpace = sal_False;
// Die folgenden Speziallfaelle muessen oder koennen nach der
// Filter-Detection erfolgen.
if( !pPendStack )
{
if( bInFloatingFrame )
{
// <SCRIPT> wird hier (von uns) ignoriert, weil es auch in
// Applets ignoriert wird!
if( HTML_IFRAME_OFF == nToken )
{
bCallNextToken = sal_False;
EndFloatingFrame();
}
return;
}
else if( bInNoEmbed )
{
switch( nToken )
{
case HTML_NOEMBED_OFF:
aContents.ConvertLineEnd();
InsertComment( aContents, OOO_STRING_SVTOOLS_HTML_noembed );
aContents.Erase();
bCallNextToken = sal_False;
bInNoEmbed = sal_False;
break;
case HTML_RAWDATA:
InsertCommentText( OOO_STRING_SVTOOLS_HTML_noembed );
break;
default:
ASSERT( !this, "SwHTMLParser::NextToken: ungueltiges Tag" );
break;
}
return;
}
else if( pAppletImpl )
{
// in einem Applet interessieren uns (erstmal) nur <PARAM>-Tags
// und das </APPLET>.
// <SCRIPT> wird hier (von Netscape) ignoriert!
switch( nToken )
{
case HTML_APPLET_OFF:
bCallNextToken = sal_False;
EndApplet();
break;
case HTML_OBJECT_OFF:
bCallNextToken = sal_False;
EndObject();
break;
case HTML_PARAM:
InsertParam();
break;
}
return;
}
else if( bTextArea )
{
// in einer TextArea wird alles bis zum </TEXTAREA> als Text
// eingefuegt
// <SCRIPT> wird hier (von Netscape) ignoriert!
switch( nToken )
{
case HTML_TEXTAREA_OFF:
bCallNextToken = sal_False;
EndTextArea();
break;
default:
InsertTextAreaText( static_cast< sal_uInt16 >(nToken) );
break;
}
return;
}
else if( bSelect )
{
// MUSS nach bNoScript kommen!
switch( nToken )
{
case HTML_SELECT_OFF:
bCallNextToken = sal_False;
EndSelect();
return;
case HTML_OPTION:
InsertSelectOption();
return;
case HTML_TEXTTOKEN:
InsertSelectText();
return;
case HTML_INPUT:
case HTML_SCRIPT_ON:
case HTML_SCRIPT_OFF:
case HTML_NOSCRIPT_ON:
case HTML_NOSCRIPT_OFF:
case HTML_RAWDATA:
// im normalen switch bahandeln
break;
default:
// ignorieren
return;
}
}
else if( pMarquee )
{
// in einer TextArea wird alles bis zum </TEXTAREA> als Text
// eingefuegt
// Die <SCRIPT>-Tags werden vom MS-IE ignoriert, von uns das
// geasmte Script
switch( nToken )
{
case HTML_MARQUEE_OFF:
bCallNextToken = sal_False;
EndMarquee();
break;
case HTML_TEXTTOKEN:
InsertMarqueeText();
break;
}
return;
}
else if( bInField )
{
switch( nToken )
{
case HTML_SDFIELD_OFF:
bCallNextToken = sal_False;
EndField();
break;
case HTML_TEXTTOKEN:
InsertFieldText();
break;
}
return;
}
else if( bInFootEndNoteAnchor || bInFootEndNoteSymbol )
{
switch( nToken )
{
case HTML_ANCHOR_OFF:
EndAnchor();
bCallNextToken = sal_False;
break;
case HTML_TEXTTOKEN:
InsertFootEndNoteText();
break;
}
return;
}
else if( aUnknownToken.Len() )
{
// Unbekannte Token im Header werden nur durch ein passendes
// End-Token, </HEAD> oder <BODY> wieder beendet. Darin wird Text
// ignoriert.
switch( nToken )
{
case HTML_UNKNOWNCONTROL_OFF:
if( aUnknownToken.CompareTo(sSaveToken) != COMPARE_EQUAL )
return;
case HTML_FRAMESET_ON:
case HTML_HEAD_OFF:
case HTML_BODY_ON:
case HTML_IMAGE: // Warum auch immer Netscape das tut.
aUnknownToken.Erase();
break;
case HTML_TEXTTOKEN:
return;
default:
break;
}
}
}
switch( nToken )
{
case HTML_BODY_ON:
if( aStyleSource.Len() )
{
pCSS1Parser->ParseStyleSheet( aStyleSource );
aStyleSource.Erase();
}
if( IsNewDoc() )
{
InsertBodyOptions();
// Falls es eine Vorlage fuer die erste oder rechte Seite gibt,
// setzen wir die hier.
const SwPageDesc *pPageDesc = 0;
if( pCSS1Parser->IsSetFirstPageDesc() )
pPageDesc = pCSS1Parser->GetFirstPageDesc();
else if( pCSS1Parser->IsSetRightPageDesc() )
pPageDesc = pCSS1Parser->GetRightPageDesc();
if( pPageDesc )
{
pDoc->InsertPoolItem( *pPam, SwFmtPageDesc( pPageDesc ), 0 );
}
}
break;
case HTML_LINK:
InsertLink();
break;
case HTML_BASE:
{
const HTMLOptions *pHTMLOptions = GetOptions();
for( sal_uInt16 i = pHTMLOptions->Count(); i; )
{
const HTMLOption *pOption = (*pHTMLOptions)[ --i ];
switch( pOption->GetToken() )
{
case HTML_O_HREF:
sBaseURL = pOption->GetString();
break;
case HTML_O_TARGET:
if( IsNewDoc() )
{
SwDocShell *pDocShell(pDoc->GetDocShell());
DBG_ASSERT(pDocShell, "no SwDocShell");
if (pDocShell) {
uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
pDocShell->GetModel(), uno::UNO_QUERY_THROW);
uno::Reference<document::XDocumentProperties>
xDocProps(xDPS->getDocumentProperties());
DBG_ASSERT(xDocProps.is(),"no DocumentProperties");
if (xDocProps.is()) {
xDocProps->setDefaultTarget(
pOption->GetString());
}
}
}
break;
}
}
}
break;
case HTML_META:
{
SvKeyValueIterator *pHTTPHeader = 0;
if( IsNewDoc() )
{
SwDocShell *pDocSh = pDoc->GetDocShell();
if( pDocSh )
pHTTPHeader = pDocSh->GetHeaderAttributes();
}
SwDocShell *pDocShell(pDoc->GetDocShell());
DBG_ASSERT(pDocShell, "no SwDocShell");
if (pDocShell)
{
uno::Reference<document::XDocumentProperties> xDocProps;
if (IsNewDoc())
{
const uno::Reference<document::XDocumentPropertiesSupplier>
xDPS( pDocShell->GetModel(), uno::UNO_QUERY_THROW );
xDocProps = xDPS->getDocumentProperties();
DBG_ASSERT(xDocProps.is(), "DocumentProperties is null");
}
ParseMetaOptions( xDocProps, pHTTPHeader );
}
}
break;
case HTML_TITLE_ON:
bInTitle = sal_True;
break;
case HTML_SCRIPT_ON:
NewScript();
break;
case HTML_SCRIPT_OFF:
EndScript();
break;
case HTML_NOSCRIPT_ON:
case HTML_NOSCRIPT_OFF:
bInsertUnknown = sal_True;
break;
case HTML_STYLE_ON:
NewStyle();
break;
case HTML_STYLE_OFF:
EndStyle();
break;
case HTML_RAWDATA:
if( !bIgnoreRawData )
{
if( IsReadScript() )
{
AddScriptSource();
}
else if( IsReadStyle() )
{
if( aStyleSource.Len() )
aStyleSource += '\n';
aStyleSource += aToken;
}
}
break;
case HTML_OBJECT_ON:
#ifdef SOLAR_JAVA
NewObject();
bCallNextToken = pAppletImpl!=0 && pTable!=0;
#endif
break;
case HTML_APPLET_ON:
#ifdef SOLAR_JAVA
InsertApplet();
bCallNextToken = pAppletImpl!=0 && pTable!=0;
#endif
break;
case HTML_IFRAME_ON:
InsertFloatingFrame();
bCallNextToken = bInFloatingFrame && pTable!=0;
break;
case HTML_LINEBREAK:
if( !IsReadPRE() )
{
InsertLineBreak();
break;
}
else
bGetIDOption = sal_True;
// <BR>s in <PRE> aehneln echten LFs, deshalb kein break
case HTML_NEWPARA:
// CR in PRE/LISTING/XMP
{
if( HTML_NEWPARA==nToken ||
pPam->GetPoint()->nContent.GetIndex() )
{
AppendTxtNode(); // lf gibts hier nicht, deshalb unkritisch
SetTxtCollAttrs();
}
// Laufbalkenanzeige
if( !GetMedium() || !GetMedium()->IsRemote() )
::SetProgressState( rInput.Tell(), pDoc->GetDocShell() );
}
break;
case HTML_NONBREAKSPACE:
pDoc->InsertString( *pPam, CHAR_HARDBLANK );
break;
case HTML_SOFTHYPH:
pDoc->InsertString( *pPam, CHAR_SOFTHYPHEN );
break;
case HTML_LINEFEEDCHAR:
if( pPam->GetPoint()->nContent.GetIndex() )
AppendTxtNode();
if( !pTable && !pDoc->IsInHeaderFooter( pPam->GetPoint()->nNode ) )
{
NewAttr( &aAttrTab.pBreak, SvxFmtBreakItem(SVX_BREAK_PAGE_BEFORE, RES_BREAK) );
EndAttr( aAttrTab.pBreak, 0, sal_False );
}
break;
case HTML_TEXTTOKEN:
// dann fuege den String ein, ohne das Attribute am Ende
// aufgespannt werden.
if( aToken.Len() && ' '==aToken.GetChar(0) && !IsReadPRE() )
{
xub_StrLen nPos = pPam->GetPoint()->nContent.GetIndex();
if( nPos )
{
const String& rText =
pPam->GetPoint()->nNode.GetNode().GetTxtNode()->GetTxt();
sal_Unicode cLast = rText.GetChar(--nPos);
if( ' ' == cLast || '\x0a' == cLast)
aToken.Erase(0,1);
}
else
aToken.Erase(0,1);
if( !aToken.Len() )
{
bUpperSpace = bUpperSpaceSave;
break;
}
}
if( aToken.Len() )
{
if( !bDocInitalized )
DocumentDetected();
pDoc->InsertString( *pPam, aToken );
// wenn es noch vorlaefige Absatz-Attribute gibt, der Absatz aber
// nicht leer ist, dann sind die Absatz-Attribute entgueltig.
if( aParaAttrs.Count() )
aParaAttrs.Remove( 0, aParaAttrs.Count() );
SetAttr();
}
break;
case HTML_HORZRULE:
InsertHorzRule();
break;
case HTML_IMAGE:
InsertImage();
// sollte der Parser der Letzte sein, der das Doc haelt, dann kann
// man hier abbrechen und einen Fehler setzen.
if( 1 == pDoc->getReferenceCount() )
{
eState = SVPAR_ERROR;
}
break;
case HTML_SPACER:
InsertSpacer();
break;
case HTML_EMBED:
InsertEmbed();
break;
case HTML_NOEMBED_ON:
bInNoEmbed = sal_True;
bCallNextToken = pTable!=0;
ReadRawData( OOO_STRING_SVTOOLS_HTML_noembed );
break;
case HTML_DEFLIST_ON:
if( nOpenParaToken )
EndPara();
NewDefList();
break;
case HTML_DEFLIST_OFF:
if( nOpenParaToken )
EndPara();
EndDefListItem( 0, sal_False, 1==nDefListDeep );
EndDefList();
break;
case HTML_DD_ON:
case HTML_DT_ON:
if( nOpenParaToken )
EndPara();
EndDefListItem( 0, sal_False );// <DD>/<DT> beenden und keine Vorl. setzen
NewDefListItem( nToken );
break;
case HTML_DD_OFF:
case HTML_DT_OFF:
// siehe HTML_LI_OFF
// eigentlich muesste man ein DD/DT jetzt beenden. Da aber sowhl
// Netscape als auch Microsoft das nicht tun, machen wir das eben
// auch nicht.
EndDefListItem( nToken, sal_False );
break;
// Bereiche
case HTML_DIVISION_ON:
case HTML_CENTER_ON:
if( nOpenParaToken )
{
if( IsReadPRE() )
nOpenParaToken = 0;
else
EndPara();
}
NewDivision( nToken );
break;
case HTML_DIVISION_OFF:
case HTML_CENTER_OFF:
if( nOpenParaToken )
{
if( IsReadPRE() )
nOpenParaToken = 0;
else
EndPara();
}
EndDivision( nToken );
break;
case HTML_MULTICOL_ON:
if( nOpenParaToken )
EndPara();
NewMultiCol();
break;
case HTML_MULTICOL_OFF:
if( nOpenParaToken )
EndPara();
EndTag( HTML_MULTICOL_ON );
break;
case HTML_MARQUEE_ON:
NewMarquee();
bCallNextToken = pMarquee!=0 && pTable!=0;
break;
case HTML_FORM_ON:
NewForm();
break;
case HTML_FORM_OFF:
EndForm();
break;
// Vorlagen:
case HTML_PARABREAK_ON:
if( nOpenParaToken )
EndPara( sal_True );
NewPara();
break;
case HTML_PARABREAK_OFF:
EndPara( sal_True );
break;
case HTML_ADDRESS_ON:
if( nOpenParaToken )
EndPara();
NewTxtFmtColl( HTML_ADDRESS_ON, RES_POOLCOLL_SENDADRESS );
break;
case HTML_ADDRESS_OFF:
if( nOpenParaToken )
EndPara();
EndTxtFmtColl( HTML_ADDRESS_OFF );
break;
case HTML_BLOCKQUOTE_ON:
case HTML_BLOCKQUOTE30_ON:
if( nOpenParaToken )
EndPara();
NewTxtFmtColl( HTML_BLOCKQUOTE_ON, RES_POOLCOLL_HTML_BLOCKQUOTE );
break;
case HTML_BLOCKQUOTE_OFF:
case HTML_BLOCKQUOTE30_OFF:
if( nOpenParaToken )
EndPara();
EndTxtFmtColl( HTML_BLOCKQUOTE_ON );
break;
case HTML_PREFORMTXT_ON:
case HTML_LISTING_ON:
case HTML_XMP_ON:
if( nOpenParaToken )
EndPara();
NewTxtFmtColl( nToken, RES_POOLCOLL_HTML_PRE );
break;
case HTML_PREFORMTXT_OFF:
bNoParSpace = sal_True; // der letzte PRE-Absatz muss einen Zeilenabstand bekommen
EndTxtFmtColl( HTML_PREFORMTXT_OFF );
break;
case HTML_LISTING_OFF:
case HTML_XMP_OFF:
EndTxtFmtColl( nToken );
break;
case HTML_HEAD1_ON:
case HTML_HEAD2_ON:
case HTML_HEAD3_ON:
case HTML_HEAD4_ON:
case HTML_HEAD5_ON:
case HTML_HEAD6_ON:
if( nOpenParaToken )
{
if( IsReadPRE() )
nOpenParaToken = 0;
else
EndPara();
}
NewHeading( nToken );
break;
case HTML_HEAD1_OFF:
case HTML_HEAD2_OFF:
case HTML_HEAD3_OFF:
case HTML_HEAD4_OFF:
case HTML_HEAD5_OFF:
case HTML_HEAD6_OFF:
EndHeading();
break;
case HTML_TABLE_ON:
if( pPendStack )
BuildTable( SVX_ADJUST_END );
else
{
if( nOpenParaToken )
EndPara();
ASSERT( !pTable, "Tabelle in Tabelle darf hier nicht vorkommen" );
if( !pTable && (IsNewDoc() || !pPam->GetNode()->FindTableNode()) &&
(pPam->GetPoint()->nNode.GetIndex() >
pDoc->GetNodes().GetEndOfExtras().GetIndex() ||
!pPam->GetNode()->FindFootnoteStartNode() ) )
{
if ( nParaCnt < 5 )
Show(); // bis hierhin schon mal anzeigen
SvxAdjust eAdjust = aAttrTab.pAdjust
? ((const SvxAdjustItem&)aAttrTab.pAdjust->GetItem()).
GetAdjust()
: SVX_ADJUST_END;
BuildTable( eAdjust );
}
else
bInsertUnknown = bKeepUnknown;
}
break;
// Listen
case HTML_DIRLIST_ON:
case HTML_MENULIST_ON:
case HTML_ORDERLIST_ON:
case HTML_UNORDERLIST_ON:
if( nOpenParaToken )
EndPara();
NewNumBulList( nToken );
break;
case HTML_DIRLIST_OFF:
case HTML_MENULIST_OFF:
case HTML_ORDERLIST_OFF:
case HTML_UNORDERLIST_OFF:
if( nOpenParaToken )
EndPara();
EndNumBulListItem( 0, sal_True, GetNumInfo().GetDepth()==1 );
EndNumBulList( nToken );
break;
case HTML_LI_ON:
case HTML_LISTHEADER_ON:
if( nOpenParaToken &&
(pPam->GetPoint()->nContent.GetIndex()
|| HTML_PARABREAK_ON==nOpenParaToken) )
{
// nure bei <P><LI> den Absatz beenden, aber nicht bei <DD><LI>
EndPara();
}
EndNumBulListItem( 0, sal_False );// <LI>/<LH> beenden und keine Vorl. setzen
NewNumBulListItem( nToken );
break;
case HTML_LI_OFF:
case HTML_LISTHEADER_OFF:
EndNumBulListItem( nToken, sal_False );
break;
// Attribute :
case HTML_ITALIC_ON:
{
SvxPostureItem aPosture( ITALIC_NORMAL, RES_CHRATR_POSTURE );
SvxPostureItem aPostureCJK( ITALIC_NORMAL, RES_CHRATR_CJK_POSTURE );
SvxPostureItem aPostureCTL( ITALIC_NORMAL, RES_CHRATR_CTL_POSTURE );
NewStdAttr( HTML_ITALIC_ON,
&aAttrTab.pItalic, aPosture,
&aAttrTab.pItalicCJK, &aPostureCJK,
&aAttrTab.pItalicCTL, &aPostureCTL );
}
break;
case HTML_BOLD_ON:
{
SvxWeightItem aWeight( WEIGHT_BOLD, RES_CHRATR_WEIGHT );
SvxWeightItem aWeightCJK( WEIGHT_BOLD, RES_CHRATR_CJK_WEIGHT );
SvxWeightItem aWeightCTL( WEIGHT_BOLD, RES_CHRATR_CTL_WEIGHT );
NewStdAttr( HTML_BOLD_ON,
&aAttrTab.pBold, aWeight,
&aAttrTab.pBoldCJK, &aWeightCJK,
&aAttrTab.pBoldCTL, &aWeightCTL );
}
break;
case HTML_STRIKE_ON:
case HTML_STRIKETHROUGH_ON:
{
NewStdAttr( HTML_STRIKE_ON, &aAttrTab.pStrike,
SvxCrossedOutItem(STRIKEOUT_SINGLE, RES_CHRATR_CROSSEDOUT) );
}
break;
case HTML_UNDERLINE_ON:
{
NewStdAttr( HTML_UNDERLINE_ON, &aAttrTab.pUnderline,
SvxUnderlineItem(UNDERLINE_SINGLE, RES_CHRATR_UNDERLINE) );
}
break;
case HTML_SUPERSCRIPT_ON:
{
NewStdAttr( HTML_SUPERSCRIPT_ON, &aAttrTab.pEscapement,
SvxEscapementItem(HTML_ESC_SUPER,HTML_ESC_PROP, RES_CHRATR_ESCAPEMENT) );
}
break;
case HTML_SUBSCRIPT_ON:
{
NewStdAttr( HTML_SUBSCRIPT_ON, &aAttrTab.pEscapement,
SvxEscapementItem(HTML_ESC_SUB,HTML_ESC_PROP, RES_CHRATR_ESCAPEMENT) );
}
break;
case HTML_BLINK_ON:
{
NewStdAttr( HTML_BLINK_ON, &aAttrTab.pBlink,
SvxBlinkItem( sal_True, RES_CHRATR_BLINK ) );
}
break;
case HTML_SPAN_ON:
NewStdAttr( HTML_SPAN_ON );
break;
case HTML_ITALIC_OFF:
case HTML_BOLD_OFF:
case HTML_STRIKE_OFF:
case HTML_UNDERLINE_OFF:
case HTML_SUPERSCRIPT_OFF:
case HTML_SUBSCRIPT_OFF:
case HTML_BLINK_OFF:
case HTML_SPAN_OFF:
EndTag( nToken );
break;
case HTML_STRIKETHROUGH_OFF:
EndTag( HTML_STRIKE_OFF );
break;
case HTML_BASEFONT_ON:
NewBasefontAttr();
break;
case HTML_BASEFONT_OFF:
EndBasefontAttr();
break;
case HTML_FONT_ON:
case HTML_BIGPRINT_ON:
case HTML_SMALLPRINT_ON:
NewFontAttr( nToken );
break;
case HTML_FONT_OFF:
case HTML_BIGPRINT_OFF:
case HTML_SMALLPRINT_OFF:
EndFontAttr( nToken );
break;
case HTML_EMPHASIS_ON:
case HTML_CITIATION_ON:
case HTML_STRONG_ON:
case HTML_CODE_ON:
case HTML_SAMPLE_ON:
case HTML_KEYBOARD_ON:
case HTML_VARIABLE_ON:
case HTML_DEFINSTANCE_ON:
case HTML_SHORTQUOTE_ON:
case HTML_LANGUAGE_ON:
case HTML_AUTHOR_ON:
case HTML_PERSON_ON:
case HTML_ACRONYM_ON:
case HTML_ABBREVIATION_ON:
case HTML_INSERTEDTEXT_ON:
case HTML_DELETEDTEXT_ON:
case HTML_TELETYPE_ON:
NewCharFmt( nToken );
break;
case HTML_SDFIELD_ON:
NewField();
bCallNextToken = bInField && pTable!=0;
break;
case HTML_EMPHASIS_OFF:
case HTML_CITIATION_OFF:
case HTML_STRONG_OFF:
case HTML_CODE_OFF:
case HTML_SAMPLE_OFF:
case HTML_KEYBOARD_OFF:
case HTML_VARIABLE_OFF:
case HTML_DEFINSTANCE_OFF:
case HTML_SHORTQUOTE_OFF:
case HTML_LANGUAGE_OFF:
case HTML_AUTHOR_OFF:
case HTML_PERSON_OFF:
case HTML_ACRONYM_OFF:
case HTML_ABBREVIATION_OFF:
case HTML_INSERTEDTEXT_OFF:
case HTML_DELETEDTEXT_OFF:
case HTML_TELETYPE_OFF:
EndTag( nToken );
break;
case HTML_HEAD_OFF:
if( aStyleSource.Len() )
{
pCSS1Parser->ParseStyleSheet( aStyleSource );
aStyleSource.Erase();
}
break;
case HTML_DOCTYPE:
case HTML_BODY_OFF:
case HTML_HTML_OFF:
case HTML_HEAD_ON:
case HTML_TITLE_OFF:
break; // nicht weiter auswerten, oder???
case HTML_HTML_ON:
{
const HTMLOptions *pHTMLOptions = GetOptions();
for( sal_uInt16 i = pHTMLOptions->Count(); i; )
{
const HTMLOption *pOption = (*pHTMLOptions)[ --i ];
if( HTML_O_DIR == pOption->GetToken() )
{
const String& rDir = pOption->GetString();
SfxItemSet aItemSet( pDoc->GetAttrPool(),
pCSS1Parser->GetWhichMap() );
SvxCSS1PropertyInfo aPropInfo;
String aDummy;
ParseStyleOptions( aDummy, aDummy, aDummy, aItemSet,
aPropInfo, 0, &rDir );
pCSS1Parser->SetPageDescAttrs( 0, &aItemSet );
break;
}
}
}
break;
case HTML_INPUT:
InsertInput();
break;
case HTML_TEXTAREA_ON:
NewTextArea();
bCallNextToken = bTextArea && pTable!=0;
break;
case HTML_SELECT_ON:
NewSelect();
bCallNextToken = bSelect && pTable!=0;
break;
case HTML_ANCHOR_ON:
NewAnchor();
break;
case HTML_ANCHOR_OFF:
EndAnchor();
break;
case HTML_COMMENT:
if( ( aToken.Len() > 5 ) && ( ! bIgnoreHTMLComments ) )
{
// als Post-It einfuegen
// MIB 8.12.2000: If there are no space characters right behind
// the <!-- and on front of the -->, leave the comment untouched.
if( ' ' == aToken.GetChar( 3 ) &&
' ' == aToken.GetChar( aToken.Len()-3 ) )
{
String aComment( aToken.Copy( 3, aToken.Len()-5 ) );
aComment.EraseLeadingChars().EraseTrailingChars();
InsertComment( aComment );
}
else
{
String aComment( '<' );
(aComment += aToken) += '>';
InsertComment( aComment );
}
}
break;
case HTML_MAP_ON:
// Image Maps werden asynchron gelesen: Zunaechst wird nur eine
// ImageMap angelegt. Die Bereiche kommen spaeter. Trozdem wird
// die ImageMap schon in das IMap-Array eingetragen, denn sie
// koennte ja schon verwendet werden.
pImageMap = new ImageMap;
if( ParseMapOptions( pImageMap) )
{
if( !pImageMaps )
pImageMaps = new ImageMaps;
pImageMaps->Insert( pImageMap, pImageMaps->Count() );
}
else
{
delete pImageMap;
pImageMap = 0;
}
break;
case HTML_MAP_OFF:
// jetzt gibt es keine ImageMap mehr (IMap nicht Loeschen, denn
// die stckt ja schon in dem Array!)
pImageMap = 0;
break;
case HTML_AREA:
if( pImageMap )
ParseAreaOptions( pImageMap, sBaseURL, SFX_EVENT_MOUSEOVER_OBJECT,
SFX_EVENT_MOUSEOUT_OBJECT );
break;
case HTML_FRAMESET_ON:
bInsertUnknown = bKeepUnknown;
break;
case HTML_NOFRAMES_ON:
if( IsInHeader() )
FinishHeader( sal_True );
bInsertUnknown = bKeepUnknown;
break;
case HTML_UNKNOWNCONTROL_ON:
// Im Header muss der Inhalt von unbekannten Token ignoriert werden,
// es sei denn, das Token faengt mit einem '!' an.
if( IsInHeader() && !IsReadPRE() && !aUnknownToken.Len() &&
sSaveToken.Len() && '!' != sSaveToken.GetChar(0) &&
'%' != sSaveToken.GetChar(0) )
aUnknownToken = sSaveToken;
// kein break
default:
bInsertUnknown = bKeepUnknown;
break;
}
if( bGetIDOption )
InsertIDOption();
if( bInsertUnknown )
{
String aComment(
String::CreateFromAscii(TOOLS_CONSTASCII_STRINGPARAM("HTML: <")) );
if( (HTML_TOKEN_ONOFF & nToken) != 0 && (1 & nToken) != 0 )
aComment += '/';
aComment += sSaveToken;
if( aToken.Len() )
{
UnescapeToken();
(aComment += ' ') += aToken;
}
aComment += '>';
InsertComment( aComment );
}
// wenn es noch vorlaefige Absatz-Attribute gibt, der Absatz aber
// nicht leer ist, dann sind die Absatz-Attribute entgueltig.
if( aParaAttrs.Count() && pPam->GetPoint()->nContent.GetIndex() )
aParaAttrs.Remove( 0, aParaAttrs.Count() );
}
/* */
extern sal_Bool lcl_css1atr_equalFontItems( const SfxPoolItem& r1, const SfxPoolItem& r2 );
void lcl_swhtml_getItemInfo( const _HTMLAttr& rAttr,
sal_Bool& rScriptDependent, sal_Bool& rFont,
sal_uInt16& rScriptType )
{
sal_uInt16 nWhich = rAttr.GetItem().Which();
switch( nWhich )
{
case RES_CHRATR_FONT:
rFont = sal_True;
case RES_CHRATR_FONTSIZE:
case RES_CHRATR_LANGUAGE:
case RES_CHRATR_POSTURE:
case RES_CHRATR_WEIGHT:
rScriptType = i18n::ScriptType::LATIN;
rScriptDependent = sal_True;
break;
case RES_CHRATR_CJK_FONT:
rFont = sal_True;
case RES_CHRATR_CJK_FONTSIZE:
case RES_CHRATR_CJK_LANGUAGE:
case RES_CHRATR_CJK_POSTURE:
case RES_CHRATR_CJK_WEIGHT:
rScriptType = i18n::ScriptType::ASIAN;
rScriptDependent = sal_True;
break;
case RES_CHRATR_CTL_FONT:
rFont = sal_True;
case RES_CHRATR_CTL_FONTSIZE:
case RES_CHRATR_CTL_LANGUAGE:
case RES_CHRATR_CTL_POSTURE:
case RES_CHRATR_CTL_WEIGHT:
rScriptType = i18n::ScriptType::COMPLEX;
rScriptDependent = sal_True;
break;
default:
rScriptDependent = sal_False;
rFont = sal_False;
break;
}
}
sal_Bool SwHTMLParser::AppendTxtNode( SwHTMLAppendMode eMode, sal_Bool bUpdateNum )
{
// Ein harter Zeilen-Umbruch am Ende muss immer entfernt werden.
// Einen zweiten ersetzen wir durch einen Absatz-Abstand.
xub_StrLen nLFStripped = StripTrailingLF();
if( (AM_NOSPACE==eMode || AM_SOFTNOSPACE==eMode) && nLFStripped > 1 )
eMode = AM_SPACE;
// die harten Attribute an diesem Absatz werden nie mehr ungueltig
if( aParaAttrs.Count() )
aParaAttrs.Remove( 0, aParaAttrs.Count() );
if( AM_SPACE==eMode || AM_NOSPACE==eMode )
{
SwTxtNode *pTxtNode =
pPam->GetPoint()->nNode.GetNode().GetTxtNode();
const SvxULSpaceItem& rULSpace =
(const SvxULSpaceItem&)pTxtNode->SwCntntNode::GetAttr( RES_UL_SPACE );
sal_Bool bChange = AM_NOSPACE==eMode ? rULSpace.GetLower() > 0
: rULSpace.GetLower() == 0;
if( bChange )
{
const SvxULSpaceItem& rCollULSpace =
pTxtNode->GetAnyFmtColl().GetULSpace();
sal_Bool bMayReset = AM_NOSPACE==eMode ? rCollULSpace.GetLower() == 0
: rCollULSpace.GetLower() > 0;
if( bMayReset &&
rCollULSpace.GetUpper() == rULSpace.GetUpper() )
{
pTxtNode->ResetAttr( RES_UL_SPACE );
}
else
{
pTxtNode->SetAttr(
SvxULSpaceItem( rULSpace.GetUpper(),
AM_NOSPACE==eMode ? 0 : HTML_PARSPACE, RES_UL_SPACE ) );
}
}
}
bNoParSpace = AM_NOSPACE==eMode || AM_SOFTNOSPACE==eMode;
SwPosition aOldPos( *pPam->GetPoint() );
sal_Bool bRet = pDoc->AppendTxtNode( *pPam->GetPoint() );
// Zeichen-Attribute aufspalten und ggf keine setzen, die ueber den
// ganzen Absatz gesetzt sind
const SwNodeIndex& rEndIdx = aOldPos.nNode;
xub_StrLen nEndCnt = aOldPos.nContent.GetIndex();
const SwPosition& rPos = *pPam->GetPoint();
_HTMLAttr** pTbl = (_HTMLAttr**)&aAttrTab;
for( sal_uInt16 nCnt = sizeof( _HTMLAttrTable ) / sizeof( _HTMLAttr* );
nCnt--; ++pTbl )
{
_HTMLAttr *pAttr = *pTbl;
if( pAttr && pAttr->GetItem().Which() < RES_PARATR_BEGIN )
{
sal_Bool bWholePara = sal_False;
while( pAttr )
{
_HTMLAttr *pNext = pAttr->GetNext();
if( pAttr->GetSttParaIdx() < rEndIdx.GetIndex() ||
(!bWholePara &&
pAttr->GetSttPara() == rEndIdx &&
pAttr->GetSttCnt() != nEndCnt) )
{
bWholePara =
pAttr->GetSttPara() == rEndIdx &&
pAttr->GetSttCnt() == 0;
xub_StrLen nStt = pAttr->nSttCntnt;
sal_Bool bScript = sal_False, bFont = sal_False;
sal_uInt16 nScriptItem;
sal_Bool bInsert = sal_True;
lcl_swhtml_getItemInfo( *pAttr, bScript, bFont,
nScriptItem );
// den besehrigen Teil setzen
if( bInsert && bScript )
{
const SwTxtNode *pTxtNd =
pAttr->GetSttPara().GetNode().GetTxtNode();
ASSERT( pTxtNd, "No text node" );
if( pTxtNd )
{
const String& rText = pTxtNd->GetTxt();
sal_uInt16 nScriptTxt =
pBreakIt->GetBreakIter()->getScriptType(
rText, pAttr->GetSttCnt() );
xub_StrLen nScriptEnd = (xub_StrLen)pBreakIt->GetBreakIter()
->endOfScript( rText, nStt, nScriptTxt );
while( nScriptEnd < nEndCnt )
{
if( nScriptItem == nScriptTxt )
{
_HTMLAttr *pSetAttr =
pAttr->Clone( rEndIdx, nScriptEnd );
pSetAttr->nSttCntnt = nStt;
pSetAttr->ClearPrev();
if( !pNext || bWholePara )
{
sal_uInt16 nTmp = pSetAttr->bInsAtStart ? 0
: aSetAttrTab.Count();
aSetAttrTab.Insert( pSetAttr, nTmp );
}
else
pNext->InsertPrev( pSetAttr );
}
nStt = nScriptEnd;
nScriptTxt = pBreakIt->GetBreakIter()->getScriptType(
rText, nStt );
nScriptEnd = (xub_StrLen)pBreakIt->GetBreakIter()
->endOfScript( rText, nStt, nScriptTxt );
}
bInsert = nScriptItem == nScriptTxt;
}
}
if( bInsert )
{
_HTMLAttr *pSetAttr =
pAttr->Clone( rEndIdx, nEndCnt );
pSetAttr->nSttCntnt = nStt;
// Wenn das Attribut den gesamten Absatz umspannt, werden
// alle auesseren Attribute nicht mehr beachtet. Deshalb
// darf es auch nicht in die Prev-Liste eines ausseren
// Attributs eingetragen werden, denn dieses wird ja
// erstmal nicht gesetzt. Das fuehrt zu verschiebenungen,
// wenn Felder ins Rennen kommen (siehe #51020#)
if( !pNext || bWholePara )
{
sal_uInt16 nTmp = pSetAttr->bInsAtStart ? 0
: aSetAttrTab.Count();
aSetAttrTab.Insert( pSetAttr, nTmp );
}
else
pNext->InsertPrev( pSetAttr );
}
else
{
_HTMLAttr *pPrev = pAttr->GetPrev();
if( pPrev )
{
// Die Previous-Attribute muessen trotzdem gesetzt werden.
if( !pNext || bWholePara )
{
sal_uInt16 nTmp = pPrev->bInsAtStart ? 0 : aSetAttrTab.Count();
aSetAttrTab.Insert( pPrev, nTmp );
}
else
pNext->InsertPrev( pPrev );
}
}
pAttr->ClearPrev();
}
pAttr->SetStart( rPos );
pAttr = pNext;
}
}
}
if( bUpdateNum )
{
if( GetNumInfo().GetDepth() )
{
sal_uInt8 nLvl = GetNumInfo().GetLevel();
SetNodeNum( nLvl, false );
}
else
pPam->GetNode()->GetTxtNode()->ResetAttr( RES_PARATR_NUMRULE );
}
// Attrubute im Absatz davor sollte man jetzt setzen (wegen JavaScript)
SetAttr();
// Now it is time to get rid of all script dependent hints that are
// equal to the settings in the style
SwTxtNode *pTxtNd = rEndIdx.GetNode().GetTxtNode();
ASSERT( pTxtNd, "There is the txt node" );
sal_uInt16 nCntAttr = (pTxtNd && pTxtNd->GetpSwpHints())
? pTxtNd->GetSwpHints().Count() : 0;
if( nCntAttr )
{
// These are the end position of all script depenent hints.
// If we find a hint that starts before the current end position,
// we have to set it. If we finf a hint that start behind or at
// that position, we have to take the hint's value into account.
// If it is equal to the style, or in fact the paragarph's value
// for that hint, the hint is removed. Otherwise it's end position
// is remembered.
xub_StrLen aEndPos[15] =
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
SwpHints& rHints = pTxtNd->GetSwpHints();
for( sal_uInt16 i=0; i < nCntAttr; i++ )
{
SwTxtAttr *pHt = rHints.GetTextHint( i );
sal_uInt16 nWhich = pHt->Which();
sal_Int16 nIdx = -1;
if( RES_CHRATR_CJK_FONT <= nWhich &&
nWhich <= RES_CHRATR_CTL_WEIGHT )
{
nIdx = static_cast< sal_uInt16 >(nWhich - RES_CHRATR_CJK_FONT + 5);
}
else switch( nWhich )
{
case RES_CHRATR_FONT: nIdx = 0; break;
case RES_CHRATR_FONTSIZE: nIdx = 1; break;
case RES_CHRATR_LANGUAGE: nIdx = 2; break;
case RES_CHRATR_POSTURE: nIdx = 3; break;
case RES_CHRATR_WEIGHT: nIdx = 4; break;
}
if( nIdx != -1 )
{
xub_StrLen nStt = *pHt->GetStart();
if( nStt >= aEndPos[nIdx] )
{
sal_Bool bFont = (nIdx % 5) == 0;
const SfxPoolItem& rItem =
((const SwCntntNode *)pTxtNd)->GetAttr( nWhich );
if( bFont ? lcl_css1atr_equalFontItems(rItem,pHt->GetAttr())
: rItem == pHt->GetAttr() )
{
// The hint is the same as set in the paragraph and
// therfor, it can be deleted
// CAUTION!!! This WILL delete the hint and it MAY
// also delete the SwpHints!!! To avoid any trouble
// we leave the loop immediately if this is the last
// hint.
pTxtNd->DeleteAttribute( pHt );
if( 1 == nCntAttr )
break;
i--;
nCntAttr--;
}
else
{
// The hint is deifferent. Therfor all hints within that
// hint have to be ignored.
aEndPos[nIdx] = pHt->GetEnd() ? *pHt->GetEnd() : nStt;
}
}
else
{
// The hint starts before another one ends.
// The hint in this case is not deleted
ASSERT( pHt->GetEnd() && *pHt->GetEnd() <= aEndPos[nIdx],
"hints aren't nested properly!" );
}
}
}
}
if( !pTable && !--nParaCnt )
Show();
return bRet;
}
void SwHTMLParser::AddParSpace()
{
if( !bNoParSpace )
return;
bNoParSpace = sal_False;
sal_uLong nNdIdx = pPam->GetPoint()->nNode.GetIndex() - 1;
SwTxtNode *pTxtNode = pDoc->GetNodes()[nNdIdx]->GetTxtNode();
if( !pTxtNode )
return;
SvxULSpaceItem rULSpace =
(const SvxULSpaceItem&)pTxtNode->SwCntntNode::GetAttr( RES_UL_SPACE );
if( !rULSpace.GetLower() )
{
const SvxULSpaceItem& rCollULSpace =
pTxtNode->GetAnyFmtColl().GetULSpace();
if( rCollULSpace.GetLower() &&
rCollULSpace.GetUpper() == rULSpace.GetUpper() )
{
pTxtNode->ResetAttr( RES_UL_SPACE );
}
else
{
pTxtNode->SetAttr(
SvxULSpaceItem( rULSpace.GetUpper(), HTML_PARSPACE, RES_UL_SPACE ) );
}
}
}
void SwHTMLParser::Show()
{
// Hier wird
// - ein EndAction gerufen, damit formatiert wird
// - ein Reschedule gerufen,
// - die eiegen View-Shell wieder gesetzt
// - und Start-Action gerufen
ASSERT( SVPAR_WORKING==eState, "Show nicht im Working-State - Das kann ins Auge gehen" );
ViewShell *pOldVSh = CallEndAction();
GetpApp()->Reschedule();
if( ( pDoc->GetDocShell() && pDoc->GetDocShell()->IsAbortingImport() )
|| 1 == pDoc->getReferenceCount() )
{
// wurde der Import vom SFX abgebrochen?
eState = SVPAR_ERROR;
}
// Die ViewShell nochmal holen, denn sie koennte im Reschedule
// zerstoert wirden sein.
ViewShell *pVSh = CallStartAction( pOldVSh );
// ist der aktuelle Node nicht mehr sichtbar, dann benutzen wir
// eine groessere Schrittweite
if( pVSh )
{
nParaCnt = (pPam->GetPoint()->nNode.GetNode().IsInVisibleArea(pVSh))
? 5 : 50;
}
}
void SwHTMLParser::ShowStatline()
{
// Hier wird
// - ein Reschedule gerufen, damit gescrollt werden kann
// - die eiegen View-Shell wieder gesetzt
// - ein Start/End-Action gerufen, wenn gescrollt wurde.
ASSERT( SVPAR_WORKING==eState, "ShowStatLine nicht im Working-State - Das kann ins Auge gehen" );
// Laufbalkenanzeige
if( !GetMedium() || !GetMedium()->IsRemote() )
{
::SetProgressState( rInput.Tell(), pDoc->GetDocShell() );
CheckActionViewShell();
}
else
{
GetpApp()->Reschedule();
if( ( pDoc->GetDocShell() && pDoc->GetDocShell()->IsAbortingImport() )
|| 1 == pDoc->getReferenceCount() )
// wurde der Import vom SFX abgebrochen?
eState = SVPAR_ERROR;
ViewShell *pVSh = CheckActionViewShell();
if( pVSh && pVSh->HasInvalidRect() )
{
CallEndAction( sal_False, sal_False );
CallStartAction( pVSh, sal_False );
}
}
}
ViewShell *SwHTMLParser::CallStartAction( ViewShell *pVSh, sal_Bool bChkPtr )
{
ASSERT( !pActionViewShell, "CallStartAction: ViewShell schon gesetzt" );
if( !pVSh || bChkPtr )
{
#ifdef DBG_UTIL
ViewShell *pOldVSh = pVSh;
#endif
pDoc->GetEditShell( &pVSh );
ASSERT( !pVSh || !pOldVSh || pOldVSh == pVSh, "CallStartAction: Wer hat die ViewShell ausgetauscht?" );
#ifdef DBG_UTIL
if( pOldVSh && !pVSh )
pVSh = 0;
#endif
}
pActionViewShell = pVSh;
if( pActionViewShell )
{
if( pActionViewShell->ISA( SwEditShell ) )
((SwEditShell*)pActionViewShell)->StartAction();
else
pActionViewShell->StartAction();
}
return pActionViewShell;
}
ViewShell *SwHTMLParser::CallEndAction( sal_Bool bChkAction, sal_Bool bChkPtr )
{
if( bChkPtr )
{
ViewShell *pVSh = 0;
pDoc->GetEditShell( &pVSh );
ASSERT( !pVSh || pActionViewShell == pVSh,
"CallEndAction: Wer hat die ViewShell ausgetauscht?" );
#if OSL_DEBUG_LEVEL > 1
if( pActionViewShell && !pVSh )
pVSh = 0;
#endif
if( pVSh != pActionViewShell )
pActionViewShell = 0;
}
if( !pActionViewShell || (bChkAction && !pActionViewShell->ActionPend()) )
return pActionViewShell;
if( bSetCrsr )
{
// an allen CrsrEditShells die Cursor auf den Doc-Anfang setzen
ViewShell *pSh = pActionViewShell;
do {
if( pSh->IsA( TYPE( SwCrsrShell ) ) )
((SwCrsrShell*)pSh)->SttEndDoc(sal_True);
pSh = (ViewShell *)pSh->GetNext();
} while( pSh != pActionViewShell );
bSetCrsr = sal_False;
}
if( pActionViewShell->ISA( SwEditShell ) )
{
//Schon gescrollt?, dann dafuer sorgen, dass die View sich nicht bewegt!
const sal_Bool bOldLock = pActionViewShell->IsViewLocked();
pActionViewShell->LockView( sal_True );
const sal_Bool bOldEndActionByVirDev = pActionViewShell->IsEndActionByVirDev();
pActionViewShell->SetEndActionByVirDev( sal_True );;
((SwEditShell*)pActionViewShell)->EndAction();
pActionViewShell->SetEndActionByVirDev( bOldEndActionByVirDev );
pActionViewShell->LockView( bOldLock );
// bChkJumpMark ist nur gesetzt, wenn das Object auch gefunden wurde
if( bChkJumpMark )
{
const Point aVisSttPos( DOCUMENTBORDER, DOCUMENTBORDER );
if( GetMedium() && aVisSttPos == pActionViewShell->VisArea().Pos() )
::JumpToSwMark( pActionViewShell,
GetMedium()->GetURLObject().GetMark() );
bChkJumpMark = sal_False;
}
}
else
pActionViewShell->EndAction();
// sollte der Parser der Letzte sein, der das Doc haelt, dann kann
// man hier abbrechen und einen Fehler setzen.
if( 1 == pDoc->getReferenceCount() )
{
eState = SVPAR_ERROR;
}
ViewShell *pVSh = pActionViewShell;
pActionViewShell = 0;
return pVSh;
}
ViewShell *SwHTMLParser::CheckActionViewShell()
{
ViewShell *pVSh = 0;
pDoc->GetEditShell( &pVSh );
ASSERT( !pVSh || pActionViewShell == pVSh,
"CheckActionViewShell: Wer hat die ViewShell ausgetauscht?" );
#if OSL_DEBUG_LEVEL > 1
if( pActionViewShell && !pVSh )
pVSh = 0;
#endif
if( pVSh != pActionViewShell )
pActionViewShell = 0;
return pActionViewShell;
}
/* */
void SwHTMLParser::_SetAttr( sal_Bool bChkEnd, sal_Bool bBeforeTable,
_HTMLAttrs *pPostIts )
{
SwPaM* pAttrPam = new SwPaM( *pPam->GetPoint() );
const SwNodeIndex& rEndIdx = pPam->GetPoint()->nNode;
xub_StrLen nEndCnt = pPam->GetPoint()->nContent.GetIndex();
_HTMLAttr* pAttr;
SwCntntNode* pCNd;
sal_uInt16 n;
_HTMLAttrs aFields( 5, 5 );
for( n = aSetAttrTab.Count(); n; )
{
pAttr = aSetAttrTab[ --n ];
sal_uInt16 nWhich = pAttr->pItem->Which();
sal_uLong nEndParaIdx = pAttr->GetEndParaIdx();
sal_Bool bSetAttr;
if( bChkEnd )
{
// fix #42192#: Zechen-Attribute mit Ende moeglich frueh,
// also noch im aktuellen Absatz setzen (wegen JavaScript
// und diversen Chats). das darf man aber nicht fuer Attribute,
// die ueber den ganzen Absatz aufgspannt werden sollen, weil
// sie aus Absatzvorlgen stammen, die nicht gesetzt werden
// koennen. Weil die Attribute mit SETATTR_DONTREPLACE
// eingefuegt werden, sollte man sie auch anchtraeglich
// noch setzen koennen.
bSetAttr = ( nEndParaIdx < rEndIdx.GetIndex() &&
(RES_LR_SPACE != nWhich || !GetNumInfo().GetNumRule()) ) ||
( !pAttr->IsLikePara() &&
nEndParaIdx == rEndIdx.GetIndex() &&
pAttr->GetEndCnt() < nEndCnt &&
(isCHRATR(nWhich) || isTXTATR_WITHEND(nWhich)) ) ||
( bBeforeTable &&
nEndParaIdx == rEndIdx.GetIndex() &&
!pAttr->GetEndCnt() );
}
else
{
// Attribiute im Content-Bereich duerfen nicht gesetzt
// werden, wenn wir in einem Sonderbereich stehen, aber
// umgekekehrt schon.
sal_uLong nEndOfIcons = pDoc->GetNodes().GetEndOfExtras().GetIndex();
bSetAttr = nEndParaIdx < rEndIdx.GetIndex() ||
rEndIdx.GetIndex() > nEndOfIcons ||
nEndParaIdx <= nEndOfIcons;
}
if( bSetAttr )
{
// Das Attribute darf nicht in der liste der vorlaeufigen
// Absatz-Attribute stehen, weil es sonst geloescht wurde.
sal_uInt16 ii = aParaAttrs.Count();
while( ii-- )
{
ASSERT( pAttr != aParaAttrs[ii],
"SetAttr: Attribut duerfte noch nicht gesetzt werden" );
aParaAttrs.Remove( ii );
}
// dann also setzen
aSetAttrTab.Remove( n, 1 );
while( pAttr )
{
_HTMLAttr *pPrev = pAttr->GetPrev();
if( !pAttr->bValid )
{
// ungueltige Attribute koennen gloescht werden
delete pAttr;
pAttr = pPrev;
continue; //break;
}
pCNd = pAttr->nSttPara.GetNode().GetCntntNode();
if( !pCNd )
{
// durch die elende Loescherei von Nodes kann auch mal
// ein Index auf einen End-Node zeigen :-(
if ( (pAttr->GetSttPara() == pAttr->GetEndPara()) &&
!isTXTATR_NOEND(nWhich) )
{
// wenn der End-Index auch auf den Node zeigt
// brauchen wir auch kein Attribut mehr zu setzen,
// es sei denn, es ist ein Text-Attribut.
delete pAttr;
pAttr = pPrev;
continue; //break;
}
pCNd = pDoc->GetNodes().GoNext( &(pAttr->nSttPara) );
if( pCNd )
pAttr->nSttCntnt = 0;
else
{
ASSERT( !this, "SetAttr: GoNext() failed!" );
delete pAttr;
pAttr = pPrev;
continue; // break;
}
}
pAttrPam->GetPoint()->nNode = pAttr->nSttPara;
// durch das Loeschen von BRs kann der Start-Index
// auch mal hinter das Ende des Textes zeigen
if( pAttr->nSttCntnt > pCNd->Len() )
pAttr->nSttCntnt = pCNd->Len();
pAttrPam->GetPoint()->nContent.Assign( pCNd, pAttr->nSttCntnt );
pAttrPam->SetMark();
if ( (pAttr->GetSttPara() != pAttr->GetEndPara()) &&
!isTXTATR_NOEND(nWhich) )
{
pCNd = pAttr->nEndPara.GetNode().GetCntntNode();
if( !pCNd )
{
pCNd = pDoc->GetNodes().GoPrevious( &(pAttr->nEndPara) );
if( pCNd )
pAttr->nEndCntnt = pCNd->Len();
else
{
ASSERT( !this, "SetAttr: GoPrevious() failed!" );
pAttrPam->DeleteMark();
delete pAttr;
pAttr = pPrev;
continue; // break;
}
}
pAttrPam->GetPoint()->nNode = pAttr->nEndPara;
}
else if( pAttr->IsLikePara() )
{
pAttr->nEndCntnt = pCNd->Len();
}
// durch das Loeschen von BRs kann der End-Index
// auch mal hinter das Ende des Textes zeigen
if( pAttr->nEndCntnt > pCNd->Len() )
pAttr->nEndCntnt = pCNd->Len();
pAttrPam->GetPoint()->nContent.Assign( pCNd, pAttr->nEndCntnt );
if( bBeforeTable &&
pAttrPam->GetPoint()->nNode.GetIndex() ==
rEndIdx.GetIndex() )
{
// wenn wir vor dem Einfuegen einer Tabelle stehen
// und das Attribut im aktuellen Node beendet wird,
// muessen wir es im Node davor beenden oder wegschmeissen,
// wenn es erst in dem Node beginnt
if( nWhich != RES_BREAK && nWhich != RES_PAGEDESC &&
!isTXTATR_NOEND(nWhich) )
{
if( pAttrPam->GetMark()->nNode.GetIndex() !=
rEndIdx.GetIndex() )
{
ASSERT( !pAttrPam->GetPoint()->nContent.GetIndex(),
"Content-Position vor Tabelle nicht 0???" );
pAttrPam->Move( fnMoveBackward );
}
else
{
pAttrPam->DeleteMark();
delete pAttr;
pAttr = pPrev;
continue;
}
}
}
switch( nWhich )
{
case RES_FLTR_BOOKMARK: // insert bookmark
{
const String sName( ((SfxStringItem*)pAttr->pItem)->GetValue() );
IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
IDocumentMarkAccess::const_iterator_t ppBkmk = pMarkAccess->findMark( sName );
if( ppBkmk != pMarkAccess->getAllMarksEnd() &&
ppBkmk->get()->GetMarkStart() == *pAttrPam->GetPoint() )
break; // do not generate duplicates on this position
pAttrPam->DeleteMark();
const ::sw::mark::IMark* const pNewMark = pMarkAccess->makeMark(
*pAttrPam,
sName,
IDocumentMarkAccess::BOOKMARK );
// jump to bookmark
if( JUMPTO_MARK == eJumpTo && pNewMark->GetName() == ::rtl::OUString(sJmpMark) )
{
bChkJumpMark = sal_True;
eJumpTo = JUMPTO_NONE;
}
}
break;
case RES_TXTATR_FIELD:
case RES_TXTATR_ANNOTATION:
case RES_TXTATR_INPUTFIELD:
{
sal_uInt16 nFldWhich =
pPostIts
? ((const SwFmtFld *)pAttr->pItem)->GetField()->GetTyp()->Which()
: 0;
if( pPostIts && (RES_POSTITFLD == nFldWhich ||
RES_SCRIPTFLD == nFldWhich) )
{
pPostIts->Insert( pAttr, 0 );
}
else
{
aFields.Insert( pAttr, aFields.Count() );
}
}
pAttrPam->DeleteMark();
pAttr = pPrev;
continue;
case RES_LR_SPACE:
if( pAttrPam->GetPoint()->nNode.GetIndex() ==
pAttrPam->GetMark()->nNode.GetIndex() &&
pCNd )
{
// wegen Numerierungen dieses Attribut direkt
// am Node setzen
pCNd->SetAttr( *pAttr->pItem );
break;
}
ASSERT( !this,
"LRSpace ueber mehrere Absaetze gesetzt!" );
// kein break (hier sollen wir trotzdem nie hinkommen;
default:
// ggfs. ein Bookmark anspringen
if( RES_TXTATR_INETFMT == nWhich &&
JUMPTO_MARK == eJumpTo &&
sJmpMark == ((SwFmtINetFmt*)pAttr->pItem)->GetName() )
{
bChkJumpMark = sal_True;
eJumpTo = JUMPTO_NONE;
}
pDoc->InsertPoolItem( *pAttrPam, *pAttr->pItem, nsSetAttrMode::SETATTR_DONTREPLACE );
}
pAttrPam->DeleteMark();
delete pAttr;
pAttr = pPrev;
}
}
}
for( n = aMoveFlyFrms.Count(); n; )
{
SwFrmFmt *pFrmFmt = aMoveFlyFrms[ --n ];
const SwFmtAnchor& rAnchor = pFrmFmt->GetAnchor();
ASSERT( FLY_AT_PARA == rAnchor.GetAnchorId(),
"Nur Auto-Rahmen brauchen eine Spezialbehandlung" );
const SwPosition *pFlyPos = rAnchor.GetCntntAnchor();
sal_uLong nFlyParaIdx = pFlyPos->nNode.GetIndex();
sal_Bool bMoveFly;
if( bChkEnd )
{
bMoveFly = nFlyParaIdx < rEndIdx.GetIndex() ||
( nFlyParaIdx == rEndIdx.GetIndex() &&
aMoveFlyCnts[n] < nEndCnt );
}
else
{
sal_uLong nEndOfIcons = pDoc->GetNodes().GetEndOfExtras().GetIndex();
bMoveFly = nFlyParaIdx < rEndIdx.GetIndex() ||
rEndIdx.GetIndex() > nEndOfIcons ||
nFlyParaIdx <= nEndOfIcons;
}
if( bMoveFly )
{
pFrmFmt->DelFrms();
*pAttrPam->GetPoint() = *pFlyPos;
pAttrPam->GetPoint()->nContent.Assign( pAttrPam->GetCntntNode(),
aMoveFlyCnts[n] );
SwFmtAnchor aAnchor( rAnchor );
aAnchor.SetType( FLY_AT_CHAR );
aAnchor.SetAnchor( pAttrPam->GetPoint() );
pFrmFmt->SetFmtAttr( aAnchor );
const SwFmtHoriOrient& rHoriOri = pFrmFmt->GetHoriOrient();
if( text::HoriOrientation::LEFT == rHoriOri.GetHoriOrient() )
{
SwFmtHoriOrient aHoriOri( rHoriOri );
aHoriOri.SetRelationOrient( text::RelOrientation::CHAR );
pFrmFmt->SetFmtAttr( aHoriOri );
}
const SwFmtVertOrient& rVertOri = pFrmFmt->GetVertOrient();
if( text::VertOrientation::TOP == rVertOri.GetVertOrient() )
{
SwFmtVertOrient aVertOri( rVertOri );
aVertOri.SetRelationOrient( text::RelOrientation::CHAR );
pFrmFmt->SetFmtAttr( aVertOri );
}
pFrmFmt->MakeFrms();
aMoveFlyFrms.Remove( n, 1 );
aMoveFlyCnts.erase( aMoveFlyCnts.begin() + n );
}
}
while( aFields.Count() )
{
pAttr = aFields[0];
pCNd = pAttr->nSttPara.GetNode().GetCntntNode();
pAttrPam->GetPoint()->nNode = pAttr->nSttPara;
pAttrPam->GetPoint()->nContent.Assign( pCNd, pAttr->nSttCntnt );
if( bBeforeTable &&
pAttrPam->GetPoint()->nNode.GetIndex() == rEndIdx.GetIndex() )
{
ASSERT( !bBeforeTable, "Aha, der Fall tritt also doch ein" );
ASSERT( !pAttrPam->GetPoint()->nContent.GetIndex(),
"Content-Position vor Tabelle nicht 0???" );
// !!!
pAttrPam->Move( fnMoveBackward );
}
pDoc->InsertPoolItem( *pAttrPam, *pAttr->pItem, 0 );
aFields.Remove( 0, 1 );
delete pAttr;
}
delete pAttrPam;
}
void SwHTMLParser::NewAttr( _HTMLAttr **ppAttr, const SfxPoolItem& rItem )
{
// Font-Hoehen und -Farben- sowie Escapement-Attribute duerfen nicht
// zusammengefasst werden. Sie werden deshalb in einer Liste gespeichert,
// in der das zuletzt aufgespannte Attribut vorne steht und der Count
// immer 1 ist. Fuer alle anderen Attribute wird der Count einfach
// hochgezaehlt.
if( *ppAttr )
{
_HTMLAttr *pAttr = new _HTMLAttr( *pPam->GetPoint(), rItem,
ppAttr );
pAttr->InsertNext( *ppAttr );
(*ppAttr) = pAttr;
}
else
(*ppAttr) = new _HTMLAttr( *pPam->GetPoint(), rItem, ppAttr );
}
void SwHTMLParser::EndAttr( _HTMLAttr* pAttr, _HTMLAttr **ppDepAttr,
sal_Bool bChkEmpty )
{
ASSERT( !ppDepAttr, "SwHTMLParser::EndAttr: ppDepAttr-Feature ungetestet?" );
// Der Listenkopf ist im Attribut gespeichert
_HTMLAttr **ppHead = pAttr->ppHead;
ASSERT( ppHead, "keinen Attributs-Listenkopf gefunden!" );
// die aktuelle Psoition als Ende-Position merken
const SwNodeIndex* pEndIdx = &pPam->GetPoint()->nNode;
xub_StrLen nEndCnt = pPam->GetPoint()->nContent.GetIndex();
// WIrd das zueltzt gestartete oder ein frueher gestartetes Attribut
// beendet?
_HTMLAttr *pLast = 0;
if( ppHead && pAttr != *ppHead )
{
// Es wird nicht das zuletzt gestartete Attribut beendet
// Dann suche wir das unmittelbar danach gestartete Attribut, das
// ja ebenfalls noch nicht beendet wurde (sonst stuende es nicht
// mehr in der Liste
pLast = *ppHead;
while( pLast && pLast->GetNext() != pAttr )
pLast = pLast->GetNext();
ASSERT( pLast, "Attribut nicht in eigener Liste gefunden!" );
// das Attribut nicht an der PaM-Psoition beenden, sondern da,
// wo das danch gestartete Attribut anfing???
//pEndIdx = &pPrev->GetSttPara();
//nEndCnt = pPrev->GetSttCnt();
}
sal_Bool bMoveBack = sal_False;
sal_uInt16 nWhich = pAttr->pItem->Which();
if( /*!pLast &&*/ !nEndCnt && RES_PARATR_BEGIN <= nWhich &&
*pEndIdx != pAttr->GetSttPara() )
{
// dann eine Cntntnt Position zurueck!
bMoveBack = pPam->Move( fnMoveBackward );
nEndCnt = pPam->GetPoint()->nContent.GetIndex();
}
// nun das Attrubut beenden
_HTMLAttr *pNext = pAttr->GetNext();
sal_Bool bInsert;
sal_uInt16 nScriptItem = 0;
sal_Bool bScript = sal_False, bFont = sal_False;
// ein Bereich ??
if( !bChkEmpty || (RES_PARATR_BEGIN <= nWhich && bMoveBack) ||
RES_PAGEDESC == nWhich || RES_BREAK == nWhich ||
*pEndIdx != pAttr->GetSttPara() ||
nEndCnt != pAttr->GetSttCnt() )
{
bInsert = sal_True;
// We do some optimization for script depenedent attribtes here.
if( *pEndIdx == pAttr->GetSttPara() )
{
lcl_swhtml_getItemInfo( *pAttr, bScript, bFont, nScriptItem );
}
}
else
{
bInsert = sal_False;
}
if( bInsert && bScript )
{
const SwTxtNode *pTxtNd = pAttr->GetSttPara().GetNode()
.GetTxtNode();
ASSERT( pTxtNd, "No text node" );
const String& rText = pTxtNd->GetTxt();
sal_uInt16 nScriptTxt = pBreakIt->GetBreakIter()->getScriptType(
rText, pAttr->GetSttCnt() );
xub_StrLen nScriptEnd = (xub_StrLen)pBreakIt->GetBreakIter()
->endOfScript( rText, pAttr->GetSttCnt(), nScriptTxt );
while( nScriptEnd < nEndCnt )
{
if( nScriptItem == nScriptTxt )
{
_HTMLAttr *pSetAttr = pAttr->Clone( *pEndIdx, nScriptEnd );
pSetAttr->ClearPrev();
if( pNext )
pNext->InsertPrev( pSetAttr );
else
{
sal_uInt16 nTmp = pSetAttr->bInsAtStart ? 0
: aSetAttrTab.Count();
aSetAttrTab.Insert( pSetAttr, nTmp );
}
}
pAttr->nSttCntnt = nScriptEnd;
nScriptTxt = pBreakIt->GetBreakIter()->getScriptType(
rText, nScriptEnd );
nScriptEnd = (xub_StrLen)pBreakIt->GetBreakIter()
->endOfScript( rText, nScriptEnd, nScriptTxt );
}
bInsert = nScriptItem == nScriptTxt;
}
if( bInsert )
{
pAttr->nEndPara = *pEndIdx;
pAttr->nEndCntnt = nEndCnt;
pAttr->bInsAtStart = RES_TXTATR_INETFMT != nWhich &&
RES_TXTATR_CHARFMT != nWhich;
if( !pNext )
{
// keine offenen Attribute dieses Typs mehr da,
// dann koennen alle gesetzt werden, es sei denn
// sie haengen noch von einem anderen Attribut ab,
// dann werden sie dort angehaengt
if( ppDepAttr && *ppDepAttr )
(*ppDepAttr)->InsertPrev( pAttr );
else
{
sal_uInt16 nTmp = pAttr->bInsAtStart ? 0 : aSetAttrTab.Count();
aSetAttrTab.Insert( pAttr, nTmp );
}
}
else
{
// es gibt noch andere offene Attribute des Typs,
// daher muss das Setzen zurueckgestellt werden.
// das aktuelle Attribut wird deshalb hinten an die
// Previous-Liste des Nachfolgers angehaengt
pNext->InsertPrev( pAttr );
}
}
else
{
// dann nicht einfuegen, sondern Loeschen. Durch das "tuerken" von
// Vorlagen durch harte Attributierung koennen sich auch mal andere
// leere Attribute in der Prev-Liste befinden, die dann trotzdem
// gesetzt werden muessen
_HTMLAttr *pPrev = pAttr->GetPrev();
delete pAttr;
if( pPrev )
{
// Die Previous-Attribute muessen trotzdem gesetzt werden.
if( pNext )
pNext->InsertPrev( pPrev );
else
{
sal_uInt16 nTmp = pPrev->bInsAtStart ? 0 : aSetAttrTab.Count();
aSetAttrTab.Insert( pPrev, nTmp );
}
}
}
// wenn das erste Attribut der Liste gesetzt wurde muss noch der
// Listenkopf korrigiert werden.
if( pLast )
pLast->pNext = pNext;
else if( ppHead )
*ppHead = pNext;
if( bMoveBack )
pPam->Move( fnMoveForward );
}
void SwHTMLParser::DeleteAttr( _HTMLAttr* pAttr )
{
// Hier darf es keine vorlauefigen Absatz-Attribute geben, den die
// koennten jetzt gesetzt werden und dann sind die Zeiger ungueltig!!!
ASSERT( !aParaAttrs.Count(),
"Hoechste Gefahr: Es gibt noch nicht-endgueltige Absatz-Attribute" );
if( aParaAttrs.Count() )
aParaAttrs.Remove( 0, aParaAttrs.Count() );
// Der Listenkopf ist im Attribut gespeichert
_HTMLAttr **ppHead = pAttr->ppHead;
ASSERT( ppHead, "keinen Attributs-Listenkopf gefunden!" );
// Wird das zueltzt gestartete oder ein frueher gestartetes Attribut
// entfernt?
_HTMLAttr *pLast = 0;
if( ppHead && pAttr != *ppHead )
{
// Es wird nicht das zuletzt gestartete Attribut beendet
// Dann suche wir das unmittelbar danach gestartete Attribut, das
// ja ebenfalls noch nicht beendet wurde (sonst stuende es nicht
// mehr in der Liste
pLast = *ppHead;
while( pLast && pLast->GetNext() != pAttr )
pLast = pLast->GetNext();
ASSERT( pLast, "Attribut nicht in eigener Liste gefunden!" );
}
// nun das Attrubut entfernen
_HTMLAttr *pNext = pAttr->GetNext();
_HTMLAttr *pPrev = pAttr->GetPrev();
delete pAttr;
if( pPrev )
{
// Die Previous-Attribute muessen trotzdem gesetzt werden.
if( pNext )
pNext->InsertPrev( pPrev );
else
{
sal_uInt16 nTmp = pPrev->bInsAtStart ? 0 : aSetAttrTab.Count();
aSetAttrTab.Insert( pPrev, nTmp );
}
}
// wenn das erste Attribut der Liste entfernt wurde muss noch der
// Listenkopf korrigiert werden.
if( pLast )
pLast->pNext = pNext;
else if( ppHead )
*ppHead = pNext;
}
void SwHTMLParser::SaveAttrTab( _HTMLAttrTable& rNewAttrTab )
{
// Hier darf es keine vorlauefigen Absatz-Attribute geben, den die
// koennten jetzt gesetzt werden und dann sind die Zeiger ungueltig!!!
ASSERT( !aParaAttrs.Count(),
"Hoechste Gefahr: Es gibt noch nicht-endgueltige Absatz-Attribute" );
if( aParaAttrs.Count() )
aParaAttrs.Remove( 0, aParaAttrs.Count() );
_HTMLAttr** pTbl = (_HTMLAttr**)&aAttrTab;
_HTMLAttr** pSaveTbl = (_HTMLAttr**)&rNewAttrTab;
for( sal_uInt16 nCnt = sizeof( _HTMLAttrTable ) / sizeof( _HTMLAttr* );
nCnt--; (++pTbl, ++pSaveTbl) )
{
*pSaveTbl = *pTbl;
_HTMLAttr *pAttr = *pSaveTbl;
while( pAttr )
{
pAttr->SetHead( pSaveTbl );
pAttr = pAttr->GetNext();
}
*pTbl = 0;
}
}
void SwHTMLParser::SplitAttrTab( _HTMLAttrTable& rNewAttrTab,
sal_Bool bMoveEndBack )
{
// Hier darf es keine vorlauefigen Absatz-Attribute geben, den die
// koennten jetzt gesetzt werden und dann sind die Zeiger ungueltig!!!
ASSERT( !aParaAttrs.Count(),
"Hoechste Gefahr: Es gibt noch nicht-endgueltige Absatz-Attribute" );
if( aParaAttrs.Count() )
aParaAttrs.Remove( 0, aParaAttrs.Count() );
const SwNodeIndex& nSttIdx = pPam->GetPoint()->nNode;
SwNodeIndex nEndIdx( nSttIdx );
// alle noch offenen Attribute beenden und hinter der Tabelle
// neu aufspannen
_HTMLAttr** pTbl = (_HTMLAttr**)&aAttrTab;
_HTMLAttr** pSaveTbl = (_HTMLAttr**)&rNewAttrTab;
sal_Bool bSetAttr = sal_True;
xub_StrLen nSttCnt = pPam->GetPoint()->nContent.GetIndex();
xub_StrLen nEndCnt = nSttCnt;
if( bMoveEndBack )
{
sal_uLong nOldEnd = nEndIdx.GetIndex();
sal_uLong nTmpIdx;
if( ( nTmpIdx = pDoc->GetNodes().GetEndOfExtras().GetIndex()) >= nOldEnd ||
( nTmpIdx = pDoc->GetNodes().GetEndOfAutotext().GetIndex()) >= nOldEnd )
{
nTmpIdx = pDoc->GetNodes().GetEndOfInserts().GetIndex();
}
SwCntntNode* pCNd = pDoc->GetNodes().GoPrevious(&nEndIdx);
// keine Attribute setzen, wenn der PaM aus dem Content-Bereich
// herausgeschoben wurde.
bSetAttr = pCNd && nTmpIdx < nEndIdx.GetIndex();
nEndCnt = (bSetAttr ? pCNd->Len() : 0);
}
for( sal_uInt16 nCnt = sizeof( _HTMLAttrTable ) / sizeof( _HTMLAttr* );
nCnt--; (++pTbl, ++pSaveTbl) )
{
_HTMLAttr *pAttr = *pTbl;
*pSaveTbl = 0;
while( pAttr )
{
_HTMLAttr *pNext = pAttr->GetNext();
_HTMLAttr *pPrev = pAttr->GetPrev();
if( bSetAttr &&
( pAttr->GetSttParaIdx() < nEndIdx.GetIndex() ||
(pAttr->GetSttPara() == nEndIdx &&
pAttr->GetSttCnt() != nEndCnt) ) )
{
// das Attribut muss vor der Liste gesetzt werden. Da wir
// das Original noch brauchen, weil Zeiger auf das Attribut
// noch in den Kontexten existieren, muessen wir es clonen.
// Die Next-Liste geht dabei verloren, aber die
// Previous-Liste bleibt erhalten
_HTMLAttr *pSetAttr = pAttr->Clone( nEndIdx, nEndCnt );
if( pNext )
pNext->InsertPrev( pSetAttr );
else
{
sal_uInt16 nTmp = pSetAttr->bInsAtStart ? 0
: aSetAttrTab.Count();
aSetAttrTab.Insert( pSetAttr, nTmp );
}
}
else if( pPrev )
{
// Wenn das Attribut nicht gesetzt vor der Tabelle
// gesetzt werden muss, muessen der Previous-Attribute
// trotzdem gesetzt werden.
if( pNext )
pNext->InsertPrev( pPrev );
else
{
sal_uInt16 nTmp = pPrev->bInsAtStart ? 0 : aSetAttrTab.Count();
aSetAttrTab.Insert( pPrev, nTmp );
}
}
// den Start des Attributs neu setzen und die Verkettungen
// aufbrechen
pAttr->Reset( nSttIdx, nSttCnt, pSaveTbl );
if( *pSaveTbl )
{
_HTMLAttr *pSAttr = *pSaveTbl;
while( pSAttr->GetNext() )
pSAttr = pSAttr->GetNext();
pSAttr->InsertNext( pAttr );
}
else
*pSaveTbl = pAttr;
pAttr = pNext;
}
*pTbl = 0;
}
}
void SwHTMLParser::RestoreAttrTab( const _HTMLAttrTable& rNewAttrTab,
sal_Bool bSetNewStart )
{
// Hier darf es keine vorlauefigen Absatz-Attribute geben, den die
// koennten jetzt gesetzt werden und dann sind die Zeiger ungueltig!!!
ASSERT( !aParaAttrs.Count(),
"Hoechste Gefahr: Es gibt noch nicht-endgueltige Absatz-Attribute" );
if( aParaAttrs.Count() )
aParaAttrs.Remove( 0, aParaAttrs.Count() );
_HTMLAttr** pTbl = (_HTMLAttr**)&aAttrTab;
_HTMLAttr** pSaveTbl = (_HTMLAttr**)&rNewAttrTab;
for( sal_uInt16 nCnt = sizeof( _HTMLAttrTable ) / sizeof( _HTMLAttr* );
nCnt--; (++pTbl, ++pSaveTbl) )
{
ASSERT( !*pTbl, "Die Attribut-Tabelle ist nicht leer!" );
const SwPosition *pPos = pPam->GetPoint();
const SwNodeIndex& rSttPara = pPos->nNode;
xub_StrLen nSttCnt = pPos->nContent.GetIndex();
*pTbl = *pSaveTbl;
_HTMLAttr *pAttr = *pTbl;
while( pAttr )
{
ASSERT( !pAttr->GetPrev() || !pAttr->GetPrev()->ppHead,
"Previous-Attribut hat noch einen Header" );
pAttr->SetHead( pTbl );
if( bSetNewStart )
{
pAttr->nSttPara = rSttPara;
pAttr->nEndPara = rSttPara;
pAttr->nSttCntnt = nSttCnt;
pAttr->nEndCntnt = nSttCnt;
}
pAttr = pAttr->GetNext();
}
*pSaveTbl = 0;
}
}
void SwHTMLParser::InsertAttr( const SfxPoolItem& rItem, sal_Bool bLikePara,
sal_Bool bInsAtStart )
{
_HTMLAttr* pTmp = new _HTMLAttr( *pPam->GetPoint(),
rItem );
if( bLikePara )
pTmp->SetLikePara();
sal_uInt16 nTmp = bInsAtStart ? 0 : aSetAttrTab.Count();
aSetAttrTab.Insert( pTmp, nTmp );
}
void SwHTMLParser::InsertAttrs( _HTMLAttrs& rAttrs )
{
while( rAttrs.Count() )
{
_HTMLAttr *pAttr = rAttrs[0];
InsertAttr( pAttr->GetItem() );
rAttrs.Remove( 0, 1 );
delete pAttr;
}
}
/* */
void SwHTMLParser::NewStdAttr( int nToken )
{
String aId, aStyle, aClass, aLang, aDir;
const HTMLOptions *pHTMLOptions = GetOptions();
for( sal_uInt16 i = pHTMLOptions->Count(); i; )
{
const HTMLOption *pOption = (*pHTMLOptions)[--i];
switch( pOption->GetToken() )
{
case HTML_O_ID:
aId = pOption->GetString();
break;
case HTML_O_STYLE:
aStyle = pOption->GetString();
break;
case HTML_O_CLASS:
aClass = pOption->GetString();
break;
case HTML_O_LANG:
aLang = pOption->GetString();
break;
case HTML_O_DIR:
aDir = pOption->GetString();
break;
}
}
// 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( HTML_SPAN_ON != nToken || !aClass.Len() ||
!CreateContainer( aClass, aItemSet, aPropInfo, pCntxt ) )
DoPositioning( aItemSet, aPropInfo, pCntxt );
InsertAttrs( aItemSet, aPropInfo, pCntxt, sal_True );
}
}
// den Kontext merken
PushContext( pCntxt );
}
void SwHTMLParser::NewStdAttr( int nToken,
_HTMLAttr **ppAttr, const SfxPoolItem & rItem,
_HTMLAttr **ppAttr2, const SfxPoolItem *pItem2,
_HTMLAttr **ppAttr3, const SfxPoolItem *pItem3 )
{
String aId, aStyle, aClass, aLang, aDir;
const HTMLOptions *pHTMLOptions = GetOptions();
for( sal_uInt16 i = pHTMLOptions->Count(); i; )
{
const HTMLOption *pOption = (*pHTMLOptions)[--i];
switch( pOption->GetToken() )
{
case HTML_O_ID:
aId = pOption->GetString();
break;
case HTML_O_STYLE:
aStyle = pOption->GetString();
break;
case HTML_O_CLASS:
aClass = pOption->GetString();
break;
case HTML_O_LANG:
aLang = pOption->GetString();
break;
case HTML_O_DIR:
aDir = pOption->GetString();
break;
}
}
// 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;
aItemSet.Put( rItem );
if( pItem2 )
aItemSet.Put( *pItem2 );
if( pItem3 )
aItemSet.Put( *pItem3 );
if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) )
DoPositioning( aItemSet, aPropInfo, pCntxt );
InsertAttrs( aItemSet, aPropInfo, pCntxt, sal_True );
}
else
{
InsertAttr( ppAttr ,rItem, pCntxt );
if( pItem2 )
{
ASSERT( ppAttr2, "missing table entry for item2" );
InsertAttr( ppAttr2, *pItem2, pCntxt );
}
if( pItem3 )
{
ASSERT( ppAttr3, "missing table entry for item3" );
InsertAttr( ppAttr3, *pItem3, pCntxt );
}
}
// den Kontext merken
PushContext( pCntxt );
}
void SwHTMLParser::EndTag( int nToken )
{
// den Kontext holen
_HTMLAttrContext *pCntxt = PopContext( static_cast< sal_uInt16 >(nToken & ~1) );
if( pCntxt )
{
// und ggf. die Attribute beenden
EndContext( pCntxt );
delete pCntxt;
}
}
void SwHTMLParser::NewBasefontAttr()
{
String aId, aStyle, aClass, aLang, aDir;
sal_uInt16 nSize = 3;
const HTMLOptions *pHTMLOptions = GetOptions();
for( sal_uInt16 i = pHTMLOptions->Count(); i; )
{
const HTMLOption *pOption = (*pHTMLOptions)[--i];
switch( pOption->GetToken() )
{
case HTML_O_SIZE:
nSize = (sal_uInt16)pOption->GetNumber();
break;
case HTML_O_ID:
aId = pOption->GetString();
break;
case HTML_O_STYLE:
aStyle = pOption->GetString();
break;
case HTML_O_CLASS:
aClass = pOption->GetString();
break;
case HTML_O_LANG:
aLang = pOption->GetString();
break;
case HTML_O_DIR:
aDir = pOption->GetString();
break;
}
}
if( nSize < 1 )
nSize = 1;
if( nSize > 7 )
nSize = 7;
// einen neuen Kontext anlegen
_HTMLAttrContext *pCntxt = new _HTMLAttrContext( HTML_BASEFONT_ON );
// Styles parsen
if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) )
{
SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() );
SvxCSS1PropertyInfo aPropInfo;
SvxFontHeightItem aFontHeight( aFontHeights[nSize-1], 100, RES_CHRATR_FONTSIZE );
aItemSet.Put( aFontHeight );
aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE );
aItemSet.Put( aFontHeight );
aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE );
aItemSet.Put( aFontHeight );
if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) )
DoPositioning( aItemSet, aPropInfo, pCntxt );
InsertAttrs( aItemSet, aPropInfo, pCntxt, sal_True );
}
else
{
SvxFontHeightItem aFontHeight( aFontHeights[nSize-1], 100, RES_CHRATR_FONTSIZE );
InsertAttr( &aAttrTab.pFontHeight, aFontHeight, pCntxt );
aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE );
InsertAttr( &aAttrTab.pFontHeightCJK, aFontHeight, pCntxt );
aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE );
InsertAttr( &aAttrTab.pFontHeightCTL, aFontHeight, pCntxt );
}
// den Kontext merken
PushContext( pCntxt );
// die Font-Size merken
aBaseFontStack.Insert( nSize, aBaseFontStack.Count() );
}
void SwHTMLParser::EndBasefontAttr()
{
EndTag( HTML_BASEFONT_ON );
// Stack-Unterlauf in Tabellen vermeiden
if( aBaseFontStack.Count() > nBaseFontStMin )
aBaseFontStack.Remove( aBaseFontStack.Count()-1, 1 );
}
void SwHTMLParser::NewFontAttr( int nToken )
{
sal_uInt16 nBaseSize =
( aBaseFontStack.Count() > nBaseFontStMin
? (aBaseFontStack[aBaseFontStack.Count()-1] & FONTSIZE_MASK)
: 3 );
sal_uInt16 nFontSize =
( aFontStack.Count() > nFontStMin
? (aFontStack[aFontStack.Count()-1] & FONTSIZE_MASK)
: nBaseSize );
String aFace, aId, aStyle, aClass, aLang, aDir;
Color aColor;
sal_uLong nFontHeight = 0; // tatsaechlich einzustellende Font-Hoehe
sal_uInt16 nSize = 0; // Fontgroesse in Netscape-Notation (1-7)
sal_Bool bColor = sal_False;
const HTMLOptions *pHTMLOptions = GetOptions();
for( sal_uInt16 i = pHTMLOptions->Count(); i; )
{
const HTMLOption *pOption = (*pHTMLOptions)[--i];
switch( pOption->GetToken() )
{
case HTML_O_SIZE:
if( HTML_FONT_ON==nToken && pOption->GetString().Len() )
{
sal_Int32 nSSize;
if( '+' == pOption->GetString().GetChar(0) ||
'-' == pOption->GetString().GetChar(0) )
nSSize = nBaseSize + pOption->GetSNumber();
else
nSSize = (sal_Int32)pOption->GetNumber();
if( nSSize < 1 )
nSSize = 1;
else if( nSSize > 7 )
nSSize = 7;
nSize = (sal_uInt16)nSSize;
nFontHeight = aFontHeights[nSize-1];
}
break;
case HTML_O_COLOR:
if( HTML_FONT_ON==nToken )
{
pOption->GetColor( aColor );
bColor = sal_True;
}
break;
case HTML_O_FACE:
if( HTML_FONT_ON==nToken )
aFace = pOption->GetString();
break;
case HTML_O_ID:
aId = pOption->GetString();
break;
case HTML_O_STYLE:
aStyle = pOption->GetString();
break;
case HTML_O_CLASS:
aClass = pOption->GetString();
break;
case HTML_O_LANG:
aLang = pOption->GetString();
break;
case HTML_O_DIR:
aDir = pOption->GetString();
break;
}
}
if( HTML_FONT_ON != nToken )
{
// HTML_BIGPRINT_ON oder HTML_SMALLPRINT_ON
// in Ueberschriften bestimmt die aktuelle Ueberschrift
// die Font-Hoehe und nicht BASEFONT
sal_uInt16 nPoolId = GetCurrFmtColl()->GetPoolFmtId();
if( (nPoolId>=RES_POOLCOLL_HEADLINE1 &&
nPoolId<=RES_POOLCOLL_HEADLINE6) )
{
// wenn die Schriftgroesse in der Ueberschrift noch
// nicht veraendert ist, die aus der Vorlage nehmen
if( nFontStHeadStart==aFontStack.Count() )
nFontSize = static_cast< sal_uInt16 >(6 - (nPoolId - RES_POOLCOLL_HEADLINE1));
}
else
nPoolId = 0;
if( HTML_BIGPRINT_ON == nToken )
nSize = ( nFontSize<7 ? nFontSize+1 : 7 );
else
nSize = ( nFontSize>1 ? nFontSize-1 : 1 );
// in Ueberschriften wird die neue Fonthoehe wenn moeglich aus
// den Vorlagen geholt.
if( nPoolId && nSize>=1 && nSize <=6 )
nFontHeight =
pCSS1Parser->GetTxtCollFromPool(
RES_POOLCOLL_HEADLINE1+6-nSize )->GetSize().GetHeight();
else
nFontHeight = aFontHeights[nSize-1];
}
ASSERT( !nSize == !nFontHeight, "HTML-Font-Size != Font-Height" );
String aFontName, aStyleName;
FontFamily eFamily = FAMILY_DONTKNOW; // Family und Pitch,
FontPitch ePitch = PITCH_DONTKNOW; // falls nicht gefunden
rtl_TextEncoding eEnc = gsl_getSystemTextEncoding();
if( aFace.Len() && !pCSS1Parser->IsIgnoreFontFamily() )
{
const FontList *pFList = 0;
SwDocShell *pDocSh = pDoc->GetDocShell();
if( pDocSh )
{
const SvxFontListItem *pFListItem =
(const SvxFontListItem *)pDocSh->GetItem(SID_ATTR_CHAR_FONTLIST);
if( pFListItem )
pFList = pFListItem->GetFontList();
}
sal_Bool bFound = sal_False;
xub_StrLen nStrPos = 0;
while( nStrPos!=STRING_NOTFOUND )
{
String aFName = aFace.GetToken( 0, ',', nStrPos );
aFName.EraseTrailingChars().EraseLeadingChars();
if( aFName.Len() )
{
if( !bFound && pFList )
{
sal_Handle hFont = pFList->GetFirstFontInfo( aFName );
if( 0 != hFont )
{
const FontInfo& rFInfo = pFList->GetFontInfo( hFont );
if( RTL_TEXTENCODING_DONTKNOW != rFInfo.GetCharSet() )
{
bFound = sal_True;
if( RTL_TEXTENCODING_SYMBOL == rFInfo.GetCharSet() )
eEnc = RTL_TEXTENCODING_SYMBOL;
}
}
}
if( aFontName.Len() )
aFontName += ';';
aFontName += aFName;
}
}
}
// 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( nFontHeight )
{
SvxFontHeightItem aFontHeight( nFontHeight, 100, RES_CHRATR_FONTSIZE );
aItemSet.Put( aFontHeight );
aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE );
aItemSet.Put( aFontHeight );
aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE );
aItemSet.Put( aFontHeight );
}
if( bColor )
aItemSet.Put( SvxColorItem(aColor, RES_CHRATR_COLOR) );
if( aFontName.Len() )
{
SvxFontItem aFont( eFamily, aFontName, aStyleName, ePitch, eEnc, RES_CHRATR_FONT );
aItemSet.Put( aFont );
aFont.SetWhich( RES_CHRATR_CJK_FONT );
aItemSet.Put( aFont );
aFont.SetWhich( RES_CHRATR_CTL_FONT );
aItemSet.Put( aFont );
}
if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) )
DoPositioning( aItemSet, aPropInfo, pCntxt );
InsertAttrs( aItemSet, aPropInfo, pCntxt, sal_True );
}
else
{
if( nFontHeight )
{
SvxFontHeightItem aFontHeight( nFontHeight, 100, RES_CHRATR_FONTSIZE );
InsertAttr( &aAttrTab.pFontHeight, aFontHeight, pCntxt );
aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE );
InsertAttr( &aAttrTab.pFontHeightCJK, aFontHeight, pCntxt );
aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE );
InsertAttr( &aAttrTab.pFontHeightCTL, aFontHeight, pCntxt );
}
if( bColor )
InsertAttr( &aAttrTab.pFontColor, SvxColorItem(aColor, RES_CHRATR_COLOR), pCntxt );
if( aFontName.Len() )
{
SvxFontItem aFont( eFamily, aFontName, aStyleName, ePitch, eEnc, RES_CHRATR_FONT );
InsertAttr( &aAttrTab.pFont, aFont, pCntxt );
aFont.SetWhich( RES_CHRATR_CJK_FONT );
InsertAttr( &aAttrTab.pFontCJK, aFont, pCntxt );
aFont.SetWhich( RES_CHRATR_CTL_FONT );
InsertAttr( &aAttrTab.pFontCTL, aFont, pCntxt );
}
}
// den Kontext merken
PushContext( pCntxt );
aFontStack.Insert( nSize, aFontStack.Count() );
}
void SwHTMLParser::EndFontAttr( int nToken )
{
EndTag( nToken );
// Stack-Unterlauf in Tabellen vermeiden
if( aFontStack.Count() > nFontStMin )
aFontStack.Remove( aFontStack.Count()-1, 1 );
}
/* */
void SwHTMLParser::NewPara()
{
if( pPam->GetPoint()->nContent.GetIndex() )
AppendTxtNode( AM_SPACE );
else
AddParSpace();
eParaAdjust = SVX_ADJUST_END;
String aId, aStyle, aClass, aLang, aDir;
const HTMLOptions *pHTMLOptions = GetOptions();
for( sal_uInt16 i = pHTMLOptions->Count(); i; )
{
const HTMLOption *pOption = (*pHTMLOptions)[--i];
switch( pOption->GetToken() )
{
case HTML_O_ID:
aId = pOption->GetString();
break;
case HTML_O_ALIGN:
eParaAdjust = (SvxAdjust)pOption->GetEnum( aHTMLPAlignTable, static_cast< sal_uInt16 >(eParaAdjust) );
break;
case HTML_O_STYLE:
aStyle = pOption->GetString();
break;
case HTML_O_CLASS:
aClass = pOption->GetString();
break;
case HTML_O_LANG:
aLang = pOption->GetString();
break;
case HTML_O_DIR:
aDir = pOption->GetString();
break;
}
}
// einen neuen Kontext anlegen
_HTMLAttrContext *pCntxt =
aClass.Len() ? new _HTMLAttrContext( HTML_PARABREAK_ON,
RES_POOLCOLL_TEXT, aClass )
: new _HTMLAttrContext( HTML_PARABREAK_ON );
// Styles parsen (Class nicht beruecksichtigen. Das geht nur, solange
// keine der CSS1-Properties der Klasse hart formatiert werden muss!!!)
if( HasStyleOptions( aStyle, aId, aEmptyStr, &aLang, &aDir ) )
{
SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() );
SvxCSS1PropertyInfo aPropInfo;
if( ParseStyleOptions( aStyle, aId, aEmptyStr, aItemSet, aPropInfo, &aLang, &aDir ) )
{
ASSERT( !aClass.Len() || !pCSS1Parser->GetClass( aClass ),
"Class wird nicht beruecksichtigt" );
DoPositioning( aItemSet, aPropInfo, pCntxt );
InsertAttrs( aItemSet, aPropInfo, pCntxt );
}
}
if( SVX_ADJUST_END != eParaAdjust )
InsertAttr( &aAttrTab.pAdjust, SvxAdjustItem(eParaAdjust, RES_PARATR_ADJUST), pCntxt );
// und auf den Stack packen
PushContext( pCntxt );
// die aktuelle Vorlage oder deren Attribute setzen
SetTxtCollAttrs( aClass.Len() ? pCntxt : 0 );
// Laufbalkenanzeige
ShowStatline();
ASSERT( !nOpenParaToken, "Jetzt geht ein offenes Absatz-Element verloren" );
nOpenParaToken = HTML_PARABREAK_ON;
}
void SwHTMLParser::EndPara( sal_Bool bReal )
{
if( HTML_LI_ON==nOpenParaToken && pTable )
{
#ifdef DBG_UTIL
const SwNumRule *pNumRule = pPam->GetNode()->GetTxtNode()->GetNumRule();
#endif
ASSERT( pNumRule, "Wo ist die Numrule geblieben" );
}
// leere Absaetze werden von Netscape uebersprungen, von uns jetzt auch
if( bReal )
{
if( pPam->GetPoint()->nContent.GetIndex() )
AppendTxtNode( AM_SPACE );
else
AddParSpace();
}
// wenn ein DD oder DT offen war, handelt es sich um eine
// implizite Def-Liste, die jetzt beendet werden muss
if( (nOpenParaToken==HTML_DT_ON || nOpenParaToken==HTML_DD_ON) &&
nDefListDeep)
{
nDefListDeep--;
}
// den Kontext vom Stack holen. Er kann auch von einer implizit
// geoeffneten Definitionsliste kommen
_HTMLAttrContext *pCntxt =
PopContext( static_cast< sal_uInt16 >(nOpenParaToken ? (nOpenParaToken & ~1)
: HTML_PARABREAK_ON) );
// Attribute beenden
if( pCntxt )
{
EndContext( pCntxt );
SetAttr(); // Absatz-Atts wegen JavaScript moeglichst schnell setzen
delete pCntxt;
}
// und die bisherige Vorlage neu setzen
if( bReal )
SetTxtCollAttrs();
nOpenParaToken = 0;
}
void SwHTMLParser::NewHeading( int nToken )
{
eParaAdjust = SVX_ADJUST_END;
String aId, aStyle, aClass, aLang, aDir;
const HTMLOptions *pHTMLOptions = GetOptions();
for( sal_uInt16 i = pHTMLOptions->Count(); i; )
{
const HTMLOption *pOption = (*pHTMLOptions)[--i];
switch( pOption->GetToken() )
{
case HTML_O_ID:
aId = pOption->GetString();
break;
case HTML_O_ALIGN:
eParaAdjust = (SvxAdjust)pOption->GetEnum( aHTMLPAlignTable, static_cast< sal_uInt16 >(eParaAdjust) );
break;
case HTML_O_STYLE:
aStyle = pOption->GetString();
break;
case HTML_O_CLASS:
aClass = pOption->GetString();
break;
case HTML_O_LANG:
aLang = pOption->GetString();
break;
case HTML_O_DIR:
aDir = pOption->GetString();
break;
}
}
// einen neuen Absatz aufmachen
if( pPam->GetPoint()->nContent.GetIndex() )
AppendTxtNode( AM_SPACE );
else
AddParSpace();
// die passende Vorlage suchen
sal_uInt16 nTxtColl;
switch( nToken )
{
case HTML_HEAD1_ON: nTxtColl = RES_POOLCOLL_HEADLINE1; break;
case HTML_HEAD2_ON: nTxtColl = RES_POOLCOLL_HEADLINE2; break;
case HTML_HEAD3_ON: nTxtColl = RES_POOLCOLL_HEADLINE3; break;
case HTML_HEAD4_ON: nTxtColl = RES_POOLCOLL_HEADLINE4; break;
case HTML_HEAD5_ON: nTxtColl = RES_POOLCOLL_HEADLINE5; break;
case HTML_HEAD6_ON: nTxtColl = RES_POOLCOLL_HEADLINE6; break;
default: nTxtColl = RES_POOLCOLL_STANDARD; break;
}
// den Kontext anlegen
_HTMLAttrContext *pCntxt = new _HTMLAttrContext( static_cast< sal_uInt16 >(nToken), nTxtColl, aClass );
// Styles parsen (zu Class siehe auch NewPara)
if( HasStyleOptions( aStyle, aId, aEmptyStr, &aLang, &aDir ) )
{
SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() );
SvxCSS1PropertyInfo aPropInfo;
if( ParseStyleOptions( aStyle, aId, aEmptyStr, aItemSet, aPropInfo, &aLang, &aDir ) )
{
ASSERT( !aClass.Len() || !pCSS1Parser->GetClass( aClass ),
"Class wird nicht beruecksichtigt" );
DoPositioning( aItemSet, aPropInfo, pCntxt );
InsertAttrs( aItemSet, aPropInfo, pCntxt );
}
}
if( SVX_ADJUST_END != eParaAdjust )
InsertAttr( &aAttrTab.pAdjust, SvxAdjustItem(eParaAdjust, RES_PARATR_ADJUST), pCntxt );
// udn auf den Stack packen
PushContext( pCntxt );
// und die Vorlage oder deren Attribute setzen
SetTxtCollAttrs( pCntxt );
nFontStHeadStart = aFontStack.Count();
// Laufbalkenanzeige
ShowStatline();
}
void SwHTMLParser::EndHeading()
{
// einen neuen Absatz aufmachen
if( pPam->GetPoint()->nContent.GetIndex() )
AppendTxtNode( AM_SPACE );
else
AddParSpace();
// Kontext zu dem Token suchen und vom Stack holen
_HTMLAttrContext *pCntxt = 0;
sal_uInt16 nPos = aContexts.Count();
while( !pCntxt && nPos>nContextStMin )
{
switch( aContexts[--nPos]->GetToken() )
{
case HTML_HEAD1_ON:
case HTML_HEAD2_ON:
case HTML_HEAD3_ON:
case HTML_HEAD4_ON:
case HTML_HEAD5_ON:
case HTML_HEAD6_ON:
pCntxt = aContexts[nPos];
aContexts.Remove( nPos, 1 );
break;
}
}
// und noch Attribute beenden
if( pCntxt )
{
EndContext( pCntxt );
SetAttr(); // Absatz-Atts wegen JavaScript moeglichst schnell setzen
delete pCntxt;
}
// die bisherige Vorlage neu setzen
SetTxtCollAttrs();
nFontStHeadStart = nFontStMin;
}
/* */
void SwHTMLParser::NewTxtFmtColl( int nToken, sal_uInt16 nColl )
{
String aId, aStyle, aClass, aLang, aDir;
const HTMLOptions *pHTMLOptions = GetOptions();
for( sal_uInt16 i = pHTMLOptions->Count(); i; )
{
const HTMLOption *pOption = (*pHTMLOptions)[--i];
switch( pOption->GetToken() )
{
case HTML_O_ID:
aId = pOption->GetString();
break;
case HTML_O_STYLE:
aStyle = pOption->GetString();
break;
case HTML_O_CLASS:
aClass = pOption->GetString();
break;
case HTML_O_LANG:
aLang = pOption->GetString();
break;
case HTML_O_DIR:
aDir = pOption->GetString();
break;
}
}
// einen neuen Absatz aufmachen
SwHTMLAppendMode eMode = AM_NORMAL;
switch( nToken )
{
case HTML_LISTING_ON:
case HTML_XMP_ON:
// Diese beiden Tags werden jetzt auf die PRE-Vorlage gemappt.
// Fuer dem Fall, dass ein CLASS angegeben ist, loeschen wir
// es damit wir nicht die CLASS der PRE-Vorlage bekommen.
aClass = aEmptyStr;
case HTML_BLOCKQUOTE_ON:
case HTML_BLOCKQUOTE30_ON:
case HTML_PREFORMTXT_ON:
eMode = AM_SPACE;
break;
case HTML_ADDRESS_ON:
eMode = AM_NOSPACE; // ADDRESS kann auf einen <P> ohne </P> folgen
break;
case HTML_DT_ON:
case HTML_DD_ON:
eMode = AM_SOFTNOSPACE;
break;
default:
ASSERT( !this, "unbekannte Vorlage" );
break;
}
if( pPam->GetPoint()->nContent.GetIndex() )
AppendTxtNode( eMode );
else if( AM_SPACE==eMode )
AddParSpace();
// ... und in einem Kontext merken
_HTMLAttrContext *pCntxt = new _HTMLAttrContext( static_cast< sal_uInt16 >(nToken), nColl, aClass );
// Styles parsen (zu Class siehe auch NewPara)
if( HasStyleOptions( aStyle, aId, aEmptyStr, &aLang, &aDir ) )
{
SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() );
SvxCSS1PropertyInfo aPropInfo;
if( ParseStyleOptions( aStyle, aId, aEmptyStr, aItemSet, aPropInfo, &aLang, &aDir ) )
{
ASSERT( !aClass.Len() || !pCSS1Parser->GetClass( aClass ),
"Class wird nicht beruecksichtigt" );
DoPositioning( aItemSet, aPropInfo, pCntxt );
InsertAttrs( aItemSet, aPropInfo, pCntxt );
}
}
PushContext( pCntxt );
// die neue Vorlage setzen
SetTxtCollAttrs( pCntxt );
// Laufbalkenanzeige aktualisieren
ShowStatline();
}
void SwHTMLParser::EndTxtFmtColl( int nToken )
{
SwHTMLAppendMode eMode = AM_NORMAL;
switch( nToken & ~1 )
{
case HTML_BLOCKQUOTE_ON:
case HTML_BLOCKQUOTE30_ON:
case HTML_PREFORMTXT_ON:
case HTML_LISTING_ON:
case HTML_XMP_ON:
eMode = AM_SPACE;
break;
case HTML_ADDRESS_ON:
case HTML_DT_ON:
case HTML_DD_ON:
eMode = AM_SOFTNOSPACE;
break;
default:
ASSERT( !this, "unbekannte Vorlage" );
break;
}
if( pPam->GetPoint()->nContent.GetIndex() )
AppendTxtNode( eMode );
else if( AM_SPACE==eMode )
AddParSpace();
// den aktuellen Kontext vom Stack holen
_HTMLAttrContext *pCntxt = PopContext( static_cast< sal_uInt16 >(nToken & ~1) );
// und noch Attribute beenden
if( pCntxt )
{
EndContext( pCntxt );
SetAttr(); // Absatz-Atts wegen JavaScript moeglichst schnell setzen
delete pCntxt;
}
// und die bisherige Vorlage setzen
SetTxtCollAttrs();
}
/* */
void SwHTMLParser::NewDefList()
{
String aId, aStyle, aClass, aLang, aDir;
const HTMLOptions *pHTMLOptions = GetOptions();
for( sal_uInt16 i = pHTMLOptions->Count(); i; )
{
const HTMLOption *pOption = (*pHTMLOptions)[--i];
switch( pOption->GetToken() )
{
case HTML_O_ID:
aId = pOption->GetString();
break;
case HTML_O_STYLE:
aStyle = pOption->GetString();
break;
case HTML_O_CLASS:
aClass = pOption->GetString();
break;
case HTML_O_LANG:
aLang = pOption->GetString();
break;
case HTML_O_DIR:
aDir = pOption->GetString();
break;
}
}
// einen neuen Absatz aufmachen
sal_Bool bSpace = (GetNumInfo().GetDepth() + nDefListDeep) == 0;
if( pPam->GetPoint()->nContent.GetIndex() )
AppendTxtNode( bSpace ? AM_SPACE : AM_SOFTNOSPACE );
else if( bSpace )
AddParSpace();
// ein Level mehr
nDefListDeep++;
sal_Bool bInDD = sal_False, bNotInDD = sal_False;
sal_uInt16 nPos = aContexts.Count();
while( !bInDD && !bNotInDD && nPos>nContextStMin )
{
sal_uInt16 nCntxtToken = aContexts[--nPos]->GetToken();
switch( nCntxtToken )
{
case HTML_DEFLIST_ON:
case HTML_DIRLIST_ON:
case HTML_MENULIST_ON:
case HTML_ORDERLIST_ON:
case HTML_UNORDERLIST_ON:
bNotInDD = sal_True;
break;
case HTML_DD_ON:
bInDD = sal_True;
break;
}
}
// ... und in einem Kontext merken
_HTMLAttrContext *pCntxt = new _HTMLAttrContext( HTML_DEFLIST_ON );
// darin auch die Raender merken
sal_uInt16 nLeft=0, nRight=0;
short nIndent=0;
GetMarginsFromContext( nLeft, nRight, nIndent );
// Die Einrueckung, die sich schon aus einem DL-ergibt, entspricht der
// eines DT auf dem aktuellen Level, und die entspricht der eines
// DD auf dem Level davor. Fue einen Level >=2 muss also ein DD-Abstand
// hinzugefuegt werden
if( !bInDD && nDefListDeep > 1 )
{
// und den der DT-Vorlage des aktuellen Levels
SvxLRSpaceItem rLRSpace =
pCSS1Parser->GetTxtFmtColl( RES_POOLCOLL_HTML_DD, aEmptyStr )
->GetLRSpace();
nLeft = nLeft + static_cast< sal_uInt16 >(rLRSpace.GetTxtLeft());
}
pCntxt->SetMargins( nLeft, nRight, nIndent );
// 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 Attribute der neuen Vorlage setzen
if( nDefListDeep > 1 )
SetTxtCollAttrs( pCntxt );
}
void SwHTMLParser::EndDefList()
{
sal_Bool bSpace = (GetNumInfo().GetDepth() + nDefListDeep) == 1;
if( pPam->GetPoint()->nContent.GetIndex() )
AppendTxtNode( bSpace ? AM_SPACE : AM_SOFTNOSPACE );
else if( bSpace )
AddParSpace();
// ein Level weniger
if( nDefListDeep > 0 )
nDefListDeep--;
// den aktuellen Kontext vom Stack holen
_HTMLAttrContext *pCntxt = PopContext( HTML_DEFLIST_ON );
// und noch Attribute beenden
if( pCntxt )
{
EndContext( pCntxt );
SetAttr(); // Absatz-Atts wegen JavaScript moeglichst schnell setzen
delete pCntxt;
}
// und Vorlage setzen
SetTxtCollAttrs();
}
void SwHTMLParser::NewDefListItem( int nToken )
{
// festellen, ob das DD/DT in einer DL vorkommt
sal_Bool bInDefList = sal_False, bNotInDefList = sal_False;
sal_uInt16 nPos = aContexts.Count();
while( !bInDefList && !bNotInDefList && nPos>nContextStMin )
{
sal_uInt16 nCntxtToken = aContexts[--nPos]->GetToken();
switch( nCntxtToken )
{
case HTML_DEFLIST_ON:
bInDefList = sal_True;
break;
case HTML_DIRLIST_ON:
case HTML_MENULIST_ON:
case HTML_ORDERLIST_ON:
case HTML_UNORDERLIST_ON:
bNotInDefList = sal_True;
break;
}
}
// wenn nicht, implizit eine neue DL aufmachen
if( !bInDefList )
{
nDefListDeep++;
ASSERT( !nOpenParaToken,
"Jetzt geht ein offenes Absatz-Element verloren" );
nOpenParaToken = static_cast< sal_uInt16 >(nToken);
}
NewTxtFmtColl( nToken, static_cast< sal_uInt16 >(nToken==HTML_DD_ON ? RES_POOLCOLL_HTML_DD
: RES_POOLCOLL_HTML_DT) );
}
void SwHTMLParser::EndDefListItem( int nToken, sal_Bool bSetColl,
sal_Bool /*bLastPara*/ )
{
// einen neuen Absatz aufmachen
if( !nToken && pPam->GetPoint()->nContent.GetIndex() )
AppendTxtNode( AM_SOFTNOSPACE );
// Kontext zu dem Token suchen und vom Stack holen
nToken &= ~1;
_HTMLAttrContext *pCntxt = 0;
sal_uInt16 nPos = aContexts.Count();
while( !pCntxt && nPos>nContextStMin )
{
sal_uInt16 nCntxtToken = aContexts[--nPos]->GetToken();
switch( nCntxtToken )
{
case HTML_DD_ON:
case HTML_DT_ON:
if( !nToken || nToken == nCntxtToken )
{
pCntxt = aContexts[nPos];
aContexts.Remove( nPos, 1 );
}
break;
case HTML_DEFLIST_ON:
// keine DD/DT ausserhalb der aktuelen DefListe betrachten
case HTML_DIRLIST_ON:
case HTML_MENULIST_ON:
case HTML_ORDERLIST_ON:
case HTML_UNORDERLIST_ON:
// und auch nicht ausserhalb einer anderen Liste
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();
}
/* */
sal_Bool SwHTMLParser::HasCurrentParaFlys( sal_Bool bNoSurroundOnly,
sal_Bool bSurroundOnly ) const
{
// bNoSurroundOnly: Der Absatz enthaelt mindestens einen Rahmen
// ohne Umlauf
// bSurroundOnly: Der Absatz enthaelt mindestens einen Rahmen
// mit Umlauf aber keinen ohne Umlauf
// sonst: Der Absatz enthaelt irgendeinen Rahmen
SwNodeIndex& rNodeIdx = pPam->GetPoint()->nNode;
const SwSpzFrmFmts& rFrmFmtTbl = *pDoc->GetSpzFrmFmts();
sal_Bool bFound = sal_False;
for ( sal_uInt16 i=0; i<rFrmFmtTbl.Count(); i++ )
{
SwFrmFmt *const pFmt = rFrmFmtTbl[i];
SwFmtAnchor const*const pAnchor = &pFmt->GetAnchor();
// Ein Rahmen wurde gefunden, wenn
// - er absatzgebunden ist, und
// - im aktuellen Absatz verankert ist, und
// - jeder absatzgebunene Rahmen zaehlt, oder
// - (nur Rahmen oder umlauf zaehlen und ) der Rahmen keinen
// Umlauf besitzt
SwPosition const*const pAPos = pAnchor->GetCntntAnchor();
if (pAPos &&
((FLY_AT_PARA == pAnchor->GetAnchorId()) ||
(FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
pAPos->nNode == rNodeIdx )
{
if( !(bNoSurroundOnly || bSurroundOnly) )
{
bFound = sal_True;
break;
}
else
{
// fix #42282#: Wenn Rahmen mit Umlauf gesucht sind,
// auch keine mit Durchlauf beachten. Dabei handelt es
// sich (noch) um HIDDEN-Controls, und denen weicht man
// besser auch nicht aus.
SwSurround eSurround = pFmt->GetSurround().GetSurround();
if( bNoSurroundOnly )
{
if( SURROUND_NONE==eSurround )
{
bFound = sal_True;
break;
}
}
if( bSurroundOnly )
{
if( SURROUND_NONE==eSurround )
{
bFound = sal_False;
break;
}
else if( SURROUND_THROUGHT!=eSurround )
{
bFound = sal_True;
// weitersuchen: Es koennten ja noch welche ohne
// Umlauf kommen ...
}
}
}
}
}
return bFound;
}
/* */
// die speziellen Methoden zum Einfuegen von Objecten
const SwFmtColl *SwHTMLParser::GetCurrFmtColl() const
{
const SwCntntNode* pCNd = pPam->GetCntntNode();
return &pCNd->GetAnyFmtColl();
}
void SwHTMLParser::SetTxtCollAttrs( _HTMLAttrContext *pContext )
{
SwTxtFmtColl *pCollToSet = 0; // die zu setzende Vorlage
SfxItemSet *pItemSet = 0; // der Set fuer harte Attrs
sal_uInt16 nTopColl = pContext ? pContext->GetTxtFmtColl() : 0;
const String& rTopClass = pContext ? pContext->GetClass() : (const String&) aEmptyStr;
sal_uInt16 nDfltColl = RES_POOLCOLL_TEXT;
sal_Bool bInPRE=sal_False; // etwas Kontext Info
sal_uInt16 nLeftMargin = 0, nRightMargin = 0; // die Einzuege und
short nFirstLineIndent = 0; // Abstaende
sal_uInt16 i;
for( i = nContextStAttrMin; i < aContexts.Count(); i++ )
{
const _HTMLAttrContext *pCntxt = aContexts[i];
sal_uInt16 nColl = pCntxt->GetTxtFmtColl();
if( nColl )
{
// Es gibt eine Vorlage, die zu setzen ist. Dann
// muss zunaechst einmal entschieden werden,
// ob die Vorlage auch gesetzt werden kann
sal_Bool bSetThis = sal_True;
switch( nColl )
{
case sal_uInt16(RES_POOLCOLL_HTML_PRE):
bInPRE = sal_True;
break;
case sal_uInt16(RES_POOLCOLL_TEXT):
// <TD><P CLASS=xxx> muss TD.xxx werden
if( nDfltColl==RES_POOLCOLL_TABLE ||
nDfltColl==RES_POOLCOLL_TABLE_HDLN )
nColl = nDfltColl;
break;
case sal_uInt16(RES_POOLCOLL_HTML_HR):
// <HR> auch in <PRE> als Vorlage setzen, sonst kann man sie
// nicht mehr exportieren
break;
default:
if( bInPRE )
bSetThis = sal_False;
break;
}
SwTxtFmtColl *pNewColl =
pCSS1Parser->GetTxtFmtColl( nColl, pCntxt->GetClass() );
if( bSetThis )
{
// wenn jetzt eine andere Vorlage gesetzt werden soll als
// bisher, muss die bishere Vorlage durch harte Attributierung
// ersetzt werden
if( pCollToSet )
{
// die Attribute, die die bisherige Vorlage setzt
// hart einfuegen
if( !pItemSet )
pItemSet = new SfxItemSet( pCollToSet->GetAttrSet() );
else
{
const SfxItemSet& rCollSet = pCollToSet->GetAttrSet();
SfxItemSet aItemSet( *rCollSet.GetPool(),
rCollSet.GetRanges() );
aItemSet.Set( rCollSet );
pItemSet->Put( aItemSet );
}
// aber die Attribute, die aktuelle Vorlage setzt
// entfernen, weil sie sonst spaeter ueberschrieben
// werden
pItemSet->Differentiate( pNewColl->GetAttrSet() );
}
pCollToSet = pNewColl;
}
else
{
// hart Attributieren
if( !pItemSet )
pItemSet = new SfxItemSet( pNewColl->GetAttrSet() );
else
{
const SfxItemSet& rCollSet = pNewColl->GetAttrSet();
SfxItemSet aItemSet( *rCollSet.GetPool(),
rCollSet.GetRanges() );
aItemSet.Set( rCollSet );
pItemSet->Put( aItemSet );
}
}
}
else
{
// vielliecht gibt es ja eine Default-Vorlage?
nColl = pCntxt->GetDfltTxtFmtColl();
if( nColl )
nDfltColl = nColl;
}
// ggf. neue Absatz-Einzuege holen
if( pCntxt->IsLRSpaceChanged() )
{
sal_uInt16 nLeft=0, nRight=0;
pCntxt->GetMargins( nLeft, nRight, nFirstLineIndent );
nLeftMargin = nLeft;
nRightMargin = nRight;
}
}
// wenn im aktuellen Kontext eine neue Vorlage gesetzt werden soll,
// muessen deren Absatz-Abstaende noch in den Kontext eingetragen werden
if( pContext && nTopColl )
{
// <TD><P CLASS=xxx> muss TD.xxx werden
if( nTopColl==RES_POOLCOLL_TEXT &&
(nDfltColl==RES_POOLCOLL_TABLE ||
nDfltColl==RES_POOLCOLL_TABLE_HDLN) )
nTopColl = nDfltColl;
const SwTxtFmtColl *pTopColl =
pCSS1Parser->GetTxtFmtColl( nTopColl, rTopClass );
const SfxItemSet& rItemSet = pTopColl->GetAttrSet();
const SfxPoolItem *pItem;
if( SFX_ITEM_SET == rItemSet.GetItemState(RES_LR_SPACE,sal_True, &pItem) )
{
const SvxLRSpaceItem *pLRItem =
(const SvxLRSpaceItem *)pItem;
sal_Int32 nLeft = pLRItem->GetTxtLeft();
sal_Int32 nRight = pLRItem->GetRight();
nFirstLineIndent = pLRItem->GetTxtFirstLineOfst();
// In Definitions-Listen enthalten die Abstaende auch die der
// vorhergehenden Level
if( RES_POOLCOLL_HTML_DD == nTopColl )
{
const SvxLRSpaceItem& rDTLRSpace = pCSS1Parser
->GetTxtFmtColl( RES_POOLCOLL_HTML_DT, aEmptyStr )
->GetLRSpace();
nLeft -= rDTLRSpace.GetTxtLeft();
nRight -= rDTLRSpace.GetRight();
}
else if( RES_POOLCOLL_HTML_DT == nTopColl )
{
nLeft = 0;
nRight = 0;
}
// die Absatz-Abstaende addieren sich
nLeftMargin = nLeftMargin + static_cast< sal_uInt16 >(nLeft);
nRightMargin = nRightMargin + static_cast< sal_uInt16 >(nRight);
pContext->SetMargins( nLeftMargin, nRightMargin,
nFirstLineIndent );
}
if( SFX_ITEM_SET == rItemSet.GetItemState(RES_UL_SPACE,sal_True, &pItem) )
{
const SvxULSpaceItem *pULItem =
(const SvxULSpaceItem *)pItem;
pContext->SetULSpace( pULItem->GetUpper(), pULItem->GetLower() );
}
}
// wenn gar keine Vorlage im Kontext gesetzt ist, Textkoerper nehmen
if( !pCollToSet )
{
pCollToSet = pCSS1Parser->GetTxtCollFromPool( nDfltColl );
const SvxLRSpaceItem& rLRItem = pCollToSet->GetLRSpace();
if( !nLeftMargin )
nLeftMargin = static_cast< sal_uInt16 >(rLRItem.GetTxtLeft());
if( !nRightMargin )
nRightMargin = static_cast< sal_uInt16 >(rLRItem.GetRight());
if( !nFirstLineIndent )
nFirstLineIndent = rLRItem.GetTxtFirstLineOfst();
}
// bisherige harte Attributierung des Absatzes entfernen
if( aParaAttrs.Count() )
{
for( i=0; i<aParaAttrs.Count(); i++ )
aParaAttrs[i]->Invalidate();
aParaAttrs.Remove( 0, aParaAttrs.Count() );
}
// Die Vorlage setzen
pDoc->SetTxtFmtColl( *pPam, pCollToSet );
// ggf. noch den Absatz-Einzug korrigieren
const SvxLRSpaceItem& rLRItem = pCollToSet->GetLRSpace();
sal_Bool bSetLRSpace;
bSetLRSpace = nLeftMargin != rLRItem.GetTxtLeft() ||
nFirstLineIndent != rLRItem.GetTxtFirstLineOfst() ||
nRightMargin != rLRItem.GetRight();
if( bSetLRSpace )
{
SvxLRSpaceItem aLRItem( rLRItem );
aLRItem.SetTxtLeft( nLeftMargin );
aLRItem.SetRight( nRightMargin );
aLRItem.SetTxtFirstLineOfst( nFirstLineIndent );
if( pItemSet )
pItemSet->Put( aLRItem );
else
{
NewAttr( &aAttrTab.pLRSpace, aLRItem );
aAttrTab.pLRSpace->SetLikePara();
aParaAttrs.Insert( aAttrTab.pLRSpace, aParaAttrs.Count() );
EndAttr( aAttrTab.pLRSpace, 0, sal_False );
}
}
// und nun noch die Attribute setzen
if( pItemSet )
{
InsertParaAttrs( *pItemSet );
delete pItemSet;
}
}
/* */
void SwHTMLParser::NewCharFmt( int nToken )
{
String aId, aStyle, aClass, aLang, aDir;
const HTMLOptions *pHTMLOptions = GetOptions();
for( sal_uInt16 i = pHTMLOptions->Count(); i; )
{
const HTMLOption *pOption = (*pHTMLOptions)[--i];
switch( pOption->GetToken() )
{
case HTML_O_ID:
aId = pOption->GetString();
break;
case HTML_O_STYLE:
aStyle = pOption->GetString();
break;
case HTML_O_CLASS:
aClass = pOption->GetString();
break;
case HTML_O_LANG:
aLang = pOption->GetString();
break;
case HTML_O_DIR:
aDir = pOption->GetString();
break;
}
}
// einen neuen Kontext anlegen
_HTMLAttrContext *pCntxt = new _HTMLAttrContext( static_cast< sal_uInt16 >(nToken) );
// die Vorlage setzen und im Kontext merken
SwCharFmt* pCFmt = pCSS1Parser->GetChrFmt( static_cast< sal_uInt16 >(nToken), aClass );
ASSERT( pCFmt, "keine Zeichenvorlage zu Token gefunden" );
// Styles parsen (zu Class siehe auch NewPara)
if( HasStyleOptions( aStyle, aId, aEmptyStr, &aLang, &aDir ) )
{
SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() );
SvxCSS1PropertyInfo aPropInfo;
if( ParseStyleOptions( aStyle, aId, aEmptyStr, aItemSet, aPropInfo, &aLang, &aDir ) )
{
ASSERT( !aClass.Len() || !pCSS1Parser->GetClass( aClass ),
"Class wird nicht beruecksichtigt" );
DoPositioning( aItemSet, aPropInfo, pCntxt );
InsertAttrs( aItemSet, aPropInfo, pCntxt, sal_True );
}
}
// Zeichen-Vorlagen werden in einem eigenen Stack gehalten und
// koennen nie durch Styles eingefuegt werden. Das Attribut ist deshalb
// auch gar nicht im CSS1-Which-Range enthalten
if( pCFmt )
InsertAttr( &aAttrTab.pCharFmts, SwFmtCharFmt( pCFmt ), pCntxt );
// den Kontext merken
PushContext( pCntxt );
}
/* */
void SwHTMLParser::InsertSpacer()
{
// und es ggf. durch die Optionen veraendern
String aId;
sal_Int16 eVertOri = text::VertOrientation::TOP;
sal_Int16 eHoriOri = text::HoriOrientation::NONE;
Size aSize( 0, 0);
long nSize = 0;
sal_Bool bPrcWidth = sal_False;
sal_Bool bPrcHeight = sal_False;
sal_uInt16 nType = HTML_SPTYPE_HORI;
const HTMLOptions *pHTMLOptions = GetOptions();
for( sal_uInt16 i = pHTMLOptions->Count(); i; )
{
const HTMLOption *pOption = (*pHTMLOptions)[--i];
switch( pOption->GetToken() )
{
case HTML_O_ID:
aId = pOption->GetString();
break;
case HTML_O_TYPE:
pOption->GetEnum( nType, aHTMLSpacerTypeTable );
break;
case HTML_O_ALIGN:
eVertOri =
pOption->GetEnum( aHTMLImgVAlignTable,
eVertOri );
eHoriOri =
pOption->GetEnum( aHTMLImgHAlignTable,
eHoriOri );
break;
case HTML_O_WIDTH:
// erstmal nur als Pixelwerte merken!
bPrcWidth = (pOption->GetString().Search('%') != STRING_NOTFOUND);
aSize.Width() = (long)pOption->GetNumber();
break;
case HTML_O_HEIGHT:
// erstmal nur als Pixelwerte merken!
bPrcHeight = (pOption->GetString().Search('%') != STRING_NOTFOUND);
aSize.Height() = (long)pOption->GetNumber();
break;
case HTML_O_SIZE:
// erstmal nur als Pixelwerte merken!
nSize = pOption->GetNumber();
break;
}
}
switch( nType )
{
case HTML_SPTYPE_BLOCK:
{
// einen leeren Textrahmen anlegen
// den Itemset holen
SfxItemSet aFrmSet( pDoc->GetAttrPool(),
RES_FRMATR_BEGIN, RES_FRMATR_END-1 );
if( !IsNewDoc() )
Reader::ResetFrmFmtAttrs( aFrmSet );
// den Anker und die Ausrichtung setzen
SetAnchorAndAdjustment( eVertOri, eHoriOri, aFrmSet );
// und noch die Groesse des Rahmens
Size aDfltSz( MINFLY, MINFLY );
Size aSpace( 0, 0 );
SfxItemSet aDummyItemSet( pDoc->GetAttrPool(),
pCSS1Parser->GetWhichMap() );
SvxCSS1PropertyInfo aDummyPropInfo;
SetFixSize( aSize, aDfltSz, bPrcWidth, bPrcHeight,
aDummyItemSet, aDummyPropInfo, aFrmSet );
SetSpace( aSpace, aDummyItemSet, aDummyPropInfo, aFrmSet );
// den Inhalt schuetzen
SvxProtectItem aProtectItem( RES_PROTECT) ;
aProtectItem.SetCntntProtect( sal_True );
aFrmSet.Put( aProtectItem );
// der Rahmen anlegen
RndStdIds eAnchorId =
((const SwFmtAnchor &)aFrmSet.Get(RES_ANCHOR)).GetAnchorId();
SwFrmFmt *pFlyFmt = pDoc->MakeFlySection( eAnchorId,
pPam->GetPoint(), &aFrmSet );
// Ggf Frames anlegen und auto-geb. Rahmen registrieren
RegisterFlyFrm( pFlyFmt );
}
break;
case HTML_SPTYPE_VERT:
if( nSize > 0 )
{
if( nSize && Application::GetDefaultDevice() )
{
nSize = Application::GetDefaultDevice()
->PixelToLogic( Size(0,nSize),
MapMode(MAP_TWIP) ).Height();
}
// einen Absatz-Abstand setzen
SwTxtNode *pTxtNode = 0;
if( !pPam->GetPoint()->nContent.GetIndex() )
{
// den unteren Absatz-Abstand des vorherigen Nodes aendern,
// wenn moeglich
SetAttr(); // noch offene Absatz-Attribute setzen
pTxtNode = pDoc->GetNodes()[pPam->GetPoint()->nNode.GetIndex()-1]
->GetTxtNode();
// Wenn der Abstz davor kein Txtenode ist, dann wird jetzt
// ein leere Absatz angelegt, der eh schon eine Zeilenhoehe
// Abstand erzeugt.
if( !pTxtNode )
nSize = nSize>HTML_PARSPACE ? nSize-HTML_PARSPACE : 0;
}
if( pTxtNode )
{
SvxULSpaceItem aULSpace( (const SvxULSpaceItem&)pTxtNode
->SwCntntNode::GetAttr( RES_UL_SPACE ) );
aULSpace.SetLower( aULSpace.GetLower() + (sal_uInt16)nSize );
pTxtNode->SetAttr( aULSpace );
}
else
{
NewAttr( &aAttrTab.pULSpace, SvxULSpaceItem( 0, (sal_uInt16)nSize, RES_UL_SPACE ) );
EndAttr( aAttrTab.pULSpace, 0, sal_False );
AppendTxtNode(); // nicht am Abstand drehen!
}
}
break;
case HTML_SPTYPE_HORI:
if( nSize > 0 )
{
// wenn der Absatz noch leer ist, einen Erstzeilen-Einzug
// setzen, sondern Sperrschrift ueber einem Space aufspannen
if( nSize && Application::GetDefaultDevice() )
{
nSize = Application::GetDefaultDevice()
->PixelToLogic( Size(nSize,0),
MapMode(MAP_TWIP) ).Width();
}
if( !pPam->GetPoint()->nContent.GetIndex() )
{
sal_uInt16 nLeft=0, nRight=0;
short nIndent = 0;
GetMarginsFromContextWithNumBul( nLeft, nRight, nIndent );
nIndent = nIndent + (short)nSize;
SvxLRSpaceItem aLRItem( RES_LR_SPACE );
aLRItem.SetTxtLeft( nLeft );
aLRItem.SetRight( nRight );
aLRItem.SetTxtFirstLineOfst( nIndent );
NewAttr( &aAttrTab.pLRSpace, aLRItem );
EndAttr( aAttrTab.pLRSpace, 0, sal_False );
}
else
{
NewAttr( &aAttrTab.pKerning, SvxKerningItem( (short)nSize, RES_CHRATR_KERNING ) );
String aTmp( ' ' );
pDoc->InsertString( *pPam, aTmp );
EndAttr( aAttrTab.pKerning );
}
}
}
}
sal_uInt16 SwHTMLParser::ToTwips( sal_uInt16 nPixel ) const
{
if( nPixel && Application::GetDefaultDevice() )
{
long nTwips = Application::GetDefaultDevice()->PixelToLogic(
Size( nPixel, nPixel ), MapMode( MAP_TWIP ) ).Width();
return nTwips <= USHRT_MAX ? (sal_uInt16)nTwips : USHRT_MAX;
}
else
return nPixel;
}
SwTwips SwHTMLParser::GetCurrentBrowseWidth()
{
const SwTwips nWidth = SwHTMLTableLayout::GetBrowseWidth( *pDoc );
if( nWidth )
return nWidth;
if( !aHTMLPageSize.Width() )
{
const SwFrmFmt& rPgFmt = pCSS1Parser->GetMasterPageDesc()->GetMaster();
const SwFmtFrmSize& rSz = rPgFmt.GetFrmSize();
const SvxLRSpaceItem& rLR = rPgFmt.GetLRSpace();
const SvxULSpaceItem& rUL = rPgFmt.GetULSpace();
const SwFmtCol& rCol = rPgFmt.GetCol();
aHTMLPageSize.Width() = rSz.GetWidth() - rLR.GetLeft() - rLR.GetRight();
aHTMLPageSize.Height() = rSz.GetHeight() - rUL.GetUpper() - rUL.GetLower();
if( 1 < rCol.GetNumCols() )
aHTMLPageSize.Width() /= rCol.GetNumCols();
}
return aHTMLPageSize.Width();
}
/* */
void SwHTMLParser::InsertIDOption()
{
String aId;
const HTMLOptions *pHTMLOptions = GetOptions();
for( sal_uInt16 i = pHTMLOptions->Count(); i; )
{
const HTMLOption *pOption = (*pHTMLOptions)[--i];
if( HTML_O_ID==pOption->GetToken() )
{
aId = pOption->GetString();
break;
}
}
if( aId.Len() )
InsertBookmark( aId );
}
/* */
void SwHTMLParser::InsertLineBreak()
{
// <BR CLEAR=xxx> wird wie folgt behandelt:
// 1.) Es werden nur nur absatzgebundene Rahmen betrachtet, die
// im aktuellen Absatz verankert sind.
// 2.) Fuer linksbuendig ausgerichtete Rahmen wird bei CLEAR=LEFT
// oder ALL und auf rechtsbuendige ausgerichtete Rahmen bei
// CLEAR=RIGHT oder ALL der Durchlauf wie folgt geaendert:
// 3.) Wenn der Absatz keinen Text enthaelt, bekommt der Rahmen keinen
// Umlauf
// 4.) sonst erhaelt ein links ausgerichteter Rahmen eine rechten
// "nur Anker" Umlauf und recht rechst ausg. Rahmen einen linken
// "nur Anker" Umlauf.
// 5.) wenn in einem nicht-leeren Absatz der Umlauf eines Rahmens
// geaendert wird, wird ein neuer Absatz aufgemacht
// 6.) Wenn von keinem Rahmen der Umlauf geaendert wird, wird ein
// harter Zeilenumbruch eingefuegt
String aId, aStyle, aClass; // die ID der Bookmark
sal_Bool bClearLeft = sal_False, bClearRight = sal_False;
sal_Bool bCleared = sal_False; // wurde ein CLEAR ausgefuehrt?
// dann holen wir mal die Optionen
const HTMLOptions *pHTMLOptions = GetOptions();
for( sal_uInt16 i = pHTMLOptions->Count(); i; )
{
const HTMLOption *pOption = (*pHTMLOptions)[--i];
switch( pOption->GetToken() )
{
case HTML_O_CLEAR:
{
const String &aClear = pOption->GetString();
if( aClear.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_AL_all ) )
{
bClearLeft = sal_True;
bClearRight = sal_True;
}
else if( aClear.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_AL_left ) )
bClearLeft = sal_True;
else if( aClear.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_AL_right ) )
bClearRight = sal_True;
}
break;
case HTML_O_ID:
aId = pOption->GetString();
break;
case HTML_O_STYLE:
aStyle = pOption->GetString();
break;
case HTML_O_CLASS:
aClass = pOption->GetString();
break;
}
}
// CLEAR wird nur fuer den aktuellen Absaetz unterstuetzt
if( bClearLeft || bClearRight )
{
SwNodeIndex& rNodeIdx = pPam->GetPoint()->nNode;
SwTxtNode* pTxtNd = rNodeIdx.GetNode().GetTxtNode();
if( pTxtNd )
{
const SwSpzFrmFmts& rFrmFmtTbl = *pDoc->GetSpzFrmFmts();
for( sal_uInt16 i=0; i<rFrmFmtTbl.Count(); i++ )
{
SwFrmFmt *const pFmt = rFrmFmtTbl[i];
SwFmtAnchor const*const pAnchor = &pFmt->GetAnchor();
SwPosition const*const pAPos = pAnchor->GetCntntAnchor();
if (pAPos &&
((FLY_AT_PARA == pAnchor->GetAnchorId()) ||
(FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
pAPos->nNode == rNodeIdx &&
pFmt->GetSurround().GetSurround() != SURROUND_NONE )
{
sal_Int16 eHori = RES_DRAWFRMFMT == pFmt->Which()
? text::HoriOrientation::LEFT
: pFmt->GetHoriOrient().GetHoriOrient();
SwSurround eSurround = SURROUND_PARALLEL;
if( pPam->GetPoint()->nContent.GetIndex() )
{
if( bClearLeft && text::HoriOrientation::LEFT==eHori )
eSurround = SURROUND_RIGHT;
else if( bClearRight && text::HoriOrientation::RIGHT==eHori )
eSurround = SURROUND_LEFT;
}
else if( (bClearLeft && text::HoriOrientation::LEFT==eHori) ||
(bClearRight && text::HoriOrientation::RIGHT==eHori) )
{
eSurround = SURROUND_NONE;
}
if( SURROUND_PARALLEL != eSurround )
{
SwFmtSurround aSurround( eSurround );
if( SURROUND_NONE != eSurround )
aSurround.SetAnchorOnly( sal_True );
pFmt->SetFmtAttr( aSurround );
bCleared = sal_True;
}
} // Anker ist nicht im Node
} // Schleife ueber Fly-Frames
} // kein Text-Node
} // kein CLEAR
// Styles parsen
SvxFmtBreakItem aBreakItem( SVX_BREAK_NONE, RES_BREAK );
sal_Bool bBreakItem = sal_False;
if( HasStyleOptions( aStyle, aId, aClass ) )
{
SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() );
SvxCSS1PropertyInfo aPropInfo;
if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo ) )
{
if( pCSS1Parser->SetFmtBreak( aItemSet, aPropInfo ) )
{
aBreakItem = (const SvxFmtBreakItem &)aItemSet.Get( RES_BREAK );
bBreakItem = sal_True;
}
if( aPropInfo.aId.Len() )
InsertBookmark( aPropInfo.aId );
}
}
if( bBreakItem && SVX_BREAK_PAGE_AFTER==aBreakItem.GetBreak() )
{
NewAttr( &aAttrTab.pBreak, aBreakItem );
EndAttr( aAttrTab.pBreak, 0, sal_False );
}
if( !bCleared && !bBreakItem )
{
// wenn kein CLEAR ausgefuehrt werden sollte oder konnte, wird
// ein Zeilenumbruch eingef?gt
String sTmp( (sal_Unicode)0x0a ); // make the Mac happy :-)
pDoc->InsertString( *pPam, sTmp );
}
else if( pPam->GetPoint()->nContent.GetIndex() )
{
// wenn ein Claer in einem nicht-leeren Absatz ausgefuehrt wurde,
// muss anschliessen ein neuer Absatz aufgemacht werden
// MIB 21.02.97: Eigentlich muesste man hier den unteren Absatz-
// Absatnd auf 0 drehen. Das geht aber bei sowas wie <BR ..><P>
// schief (>Netacpe). Deshalb lassen wir das erstmal.
AppendTxtNode( AM_NOSPACE );
}
if( bBreakItem && SVX_BREAK_PAGE_BEFORE==aBreakItem.GetBreak() )
{
NewAttr( &aAttrTab.pBreak, aBreakItem );
EndAttr( aAttrTab.pBreak, 0, sal_False );
}
}
void SwHTMLParser::InsertHorzRule()
{
sal_uInt16 nSize = 0;
sal_uInt16 nWidth = 0;
SvxAdjust eAdjust = SVX_ADJUST_END;
sal_Bool bPrcWidth = sal_False;
sal_Bool bNoShade = sal_False;
sal_Bool bColor = sal_False;
Color aColor;
String aId;
// dann holen wir mal die Optionen
const HTMLOptions *pHTMLOptions = GetOptions();
for( sal_uInt16 i = pHTMLOptions->Count(); i; )
{
const HTMLOption *pOption = (*pHTMLOptions)[--i];
switch( pOption->GetToken() )
{
case HTML_O_ID:
aId = pOption->GetString();
break;
case HTML_O_SIZE:
nSize = (sal_uInt16)pOption->GetNumber();
break;
case HTML_O_WIDTH:
bPrcWidth = (pOption->GetString().Search('%') != STRING_NOTFOUND);
nWidth = (sal_uInt16)pOption->GetNumber();
if( bPrcWidth && nWidth>=100 )
{
// 100%-Linien sind der default-Fall (keine Attrs neotig)
nWidth = 0;
bPrcWidth = sal_False;
}
break;
case HTML_O_ALIGN:
eAdjust =
(SvxAdjust)pOption->GetEnum( aHTMLPAlignTable, static_cast< sal_uInt16 >(eAdjust) );
break;
case HTML_O_NOSHADE:
bNoShade = sal_True;
break;
case HTML_O_COLOR:
pOption->GetColor( aColor );
bColor = sal_True;
break;
}
}
if( pPam->GetPoint()->nContent.GetIndex() )
AppendTxtNode( AM_NOSPACE );
if( nOpenParaToken )
EndPara();
AppendTxtNode();
pPam->Move( fnMoveBackward );
// ... und in einem Kontext merken
_HTMLAttrContext *pCntxt =
new _HTMLAttrContext( HTML_HORZRULE, RES_POOLCOLL_HTML_HR, aEmptyStr );
PushContext( pCntxt );
// die neue Vorlage setzen
SetTxtCollAttrs( pCntxt );
// die harten Attribute an diesem Absatz werden nie mehr ungueltig
if( aParaAttrs.Count() )
aParaAttrs.Remove( 0, aParaAttrs.Count() );
if( nSize>0 || bColor || bNoShade )
{
// Farbe und/oder Breite der Linie setzen
if( !bColor )
aColor.SetColor( COL_GRAY );
SvxBorderLine aBorderLine( &aColor );
if( nSize )
{
long nPWidth = 0;
long nPHeight = (long)nSize;
SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
SvxCSS1Parser::SetBorderWidth( aBorderLine, (sal_uInt16)nPHeight,
!bNoShade );
}
else if( bNoShade )
{
aBorderLine.SetOutWidth( DEF_LINE_WIDTH_2 );
}
else
{
aBorderLine.SetOutWidth( DEF_DOUBLE_LINE0_OUT );
aBorderLine.SetInWidth( DEF_DOUBLE_LINE0_IN );
aBorderLine.SetDistance( DEF_DOUBLE_LINE0_DIST );
}
SvxBoxItem aBoxItem(RES_BOX);
aBoxItem.SetLine( &aBorderLine, BOX_LINE_BOTTOM );
_HTMLAttr* pTmp = new _HTMLAttr( *pPam->GetPoint(), aBoxItem );
aSetAttrTab.Insert( pTmp, aSetAttrTab.Count() );
}
if( nWidth )
{
// Wenn wir in keiner Tabelle sind, wird die Breitenangabe durch
// Absatz-Einzuege "getuerkt". In einer Tabelle macht das wenig
// Sinn. Um zu Vermeiden, dass die Linie bei der Breitenberechnung
// beruecksichtigt wird, bekommt sie aber trotzdem entsprechendes
// LRSpace-Item verpasst.
#ifdef FIX41370
const SwFmtColl *pColl = GetCurrFmtColl();
SvxLRSpaceItem aLRItem( pColl->GetLRSpace() );
#endif
if( !pTable )
{
// Laenge und Ausrichtung der Linie ueber Absatz-Einzuege "tuerken"
long nBrowseWidth = GetCurrentBrowseWidth();
nWidth = bPrcWidth ? (sal_uInt16)((nWidth*nBrowseWidth) / 100)
: ToTwips( (sal_uInt16)nBrowseWidth );
if( nWidth < MINLAY )
nWidth = MINLAY;
if( (long)nWidth < nBrowseWidth )
{
#ifndef FIX41370
const SwFmtColl *pColl = GetCurrFmtColl();
SvxLRSpaceItem aLRItem( pColl->GetLRSpace() );
#endif
long nDist = nBrowseWidth - nWidth;
switch( eAdjust )
{
case SVX_ADJUST_RIGHT:
aLRItem.SetTxtLeft( (sal_uInt16)nDist );
break;
case SVX_ADJUST_LEFT:
aLRItem.SetRight( (sal_uInt16)nDist );
break;
case SVX_ADJUST_CENTER:
default:
nDist /= 2;
aLRItem.SetTxtLeft( (sal_uInt16)nDist );
aLRItem.SetRight( (sal_uInt16)nDist );
break;
}
#ifndef FIX41370
_HTMLAttr* pTmp = new _HTMLAttr( *pPam->GetPoint(), aLRItem );
aSetAttrTab.Insert( pTmp, aSetAttrTab.Count() );
#endif
}
}
#ifdef FIX41370
_HTMLAttr* pTmp = new _HTMLAttr( *pPam->GetPoint(), aLRItem );
aSetAttrTab.Insert( pTmp, aSetAttrTab.Count() );
#endif
}
// Bookmarks koennen nicht in Hyperlinks eingefueht werden
if( aId.Len() )
InsertBookmark( aId );
// den aktuellen Kontext vom Stack holen
_HTMLAttrContext *pPoppedContext = PopContext( HTML_HORZRULE );
ASSERT( pPoppedContext==pCntxt, "wo kommt denn da ein HR-Kontext her?" );
delete pPoppedContext;
pPam->Move( fnMoveForward );
// und im Absatz danach die dort aktuelle Vorlage setzen
SetTxtCollAttrs();
}
void SwHTMLParser::ParseMoreMetaOptions()
{
String aName, aContent;
sal_Bool bHTTPEquiv = sal_False;
const HTMLOptions *pHTMLOptions = GetOptions();
for( sal_uInt16 i = pHTMLOptions->Count(); i; )
{
const HTMLOption *pOption = (*pHTMLOptions)[ --i ];
switch( pOption->GetToken() )
{
case HTML_O_NAME:
aName = pOption->GetString();
bHTTPEquiv = sal_False;
break;
case HTML_O_HTTPEQUIV:
aName = pOption->GetString();
bHTTPEquiv = sal_True;
break;
case HTML_O_CONTENT:
aContent = pOption->GetString();
break;
}
}
// Hier wird es etwas tricky: Wir wissen genau, da? die Dok-Info
// nicht geaendert wurde. Deshalb genuegt es, auf Generator und
// auf refresh abzufragen, um noch nicht verarbeitete Token zu finden,
// denn das sind die einzigen, die die Dok-Info nicht modifizieren.
if( aName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_META_generator ) ||
aName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_META_refresh ) ||
aName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_META_content_type ) ||
aName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_META_content_script_type ) )
return;
aContent.EraseAllChars( _CR );
aContent.EraseAllChars( _LF );
if( aName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_META_sdendnote ) )
{
FillEndNoteInfo( aContent );
return;
}
if( aName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_META_sdfootnote ) )
{
FillFootNoteInfo( aContent );
return;
}
String sText( String::CreateFromAscii(TOOLS_CONSTASCII_STRINGPARAM("HTML: <")) );
sText.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM(OOO_STRING_SVTOOLS_HTML_meta) );
sText.Append( ' ' );
if( bHTTPEquiv )
sText.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM(OOO_STRING_SVTOOLS_HTML_O_httpequiv) );
else
sText.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM(OOO_STRING_SVTOOLS_HTML_O_name) );
sText.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM("=\"") );
sText.Append( aName );
sText.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM("\" ") );
sText.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM(OOO_STRING_SVTOOLS_HTML_O_content) );
sText.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM("=\"") );
sText.Append( aContent );
sText.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM("\">") );
SwPostItField aPostItFld(
(SwPostItFieldType*)pDoc->GetSysFldType( RES_POSTITFLD ),
sText,
aEmptyStr,
aEmptyStr,
aEmptyStr,
DateTime() );
SwFmtFld aFmtFld( aPostItFld );
InsertAttr( aFmtFld );
}
/* */
_HTMLAttr::_HTMLAttr( const SwPosition& rPos, const SfxPoolItem& rItem,
_HTMLAttr **ppHd ) :
nSttPara( rPos.nNode ),
nEndPara( rPos.nNode ),
nSttCntnt( rPos.nContent.GetIndex() ),
nEndCntnt(rPos.nContent.GetIndex() ),
bInsAtStart( sal_True ),
bLikePara( sal_False ),
bValid( sal_True ),
nCount( 1 ),
pNext( 0 ),
pPrev( 0 ),
ppHead( ppHd )
{
pItem = rItem.Clone();
}
_HTMLAttr::_HTMLAttr( const _HTMLAttr &rAttr, const SwNodeIndex &rEndPara,
sal_uInt16 nEndCnt, _HTMLAttr **ppHd ) :
nSttPara( rAttr.nSttPara ),
nEndPara( rEndPara ),
nSttCntnt( rAttr.nSttCntnt ),
nEndCntnt( nEndCnt ),
bInsAtStart( rAttr.bInsAtStart ),
bLikePara( rAttr.bLikePara ),
bValid( rAttr.bValid ),
nCount( rAttr.nCount ),
pNext( 0 ),
pPrev( 0 ),
ppHead( ppHd )
{
pItem = rAttr.pItem->Clone();
}
_HTMLAttr::~_HTMLAttr()
{
delete pItem;
}
_HTMLAttr *_HTMLAttr::Clone( const SwNodeIndex& rEndPara, sal_uInt16 nEndCnt ) const
{
// das Attribut mit der alten Start-Position neu anlegen
_HTMLAttr *pNew = new _HTMLAttr( *this, rEndPara, nEndCnt, ppHead );
// die Previous-Liste muss uebernommen werden, die Next-Liste nicht!
pNew->pPrev = pPrev;
return pNew;
}
void _HTMLAttr::Reset( const SwNodeIndex& rSttPara, sal_uInt16 nSttCnt,
_HTMLAttr **ppHd )
{
// den Anfang (und das Ende) neu setzen
nSttPara = rSttPara;
nSttCntnt = nSttCnt;
nEndPara = rSttPara;
nEndCntnt = nSttCnt;
// den Head korrigieren und die Verkettungen aufheben
pNext = 0;
pPrev = 0;
ppHead = ppHd;
}
void _HTMLAttr::InsertPrev( _HTMLAttr *pPrv )
{
ASSERT( !pPrv->pNext || pPrv->pNext == this,
"_HTMLAttr::InsertPrev: pNext falsch" );
pPrv->pNext = 0;
ASSERT( 0 == pPrv->ppHead || ppHead == pPrv->ppHead,
"_HTMLAttr::InsertPrev: ppHead falsch" );
pPrv->ppHead = 0;
_HTMLAttr *pAttr = this;
while( pAttr->GetPrev() )
pAttr = pAttr->GetPrev();
pAttr->pPrev = pPrv;
}
bool SwHTMLParser::ParseMetaOptions(
const uno::Reference<document::XDocumentProperties> & i_xDocProps,
SvKeyValueIterator *i_pHeader )
{
// always call base ParseMetaOptions, it sets the encoding (#i96700#)
bool ret( HTMLParser::ParseMetaOptions(i_xDocProps, i_pHeader) );
if (!ret && IsNewDoc())
{
ParseMoreMetaOptions();
}
return ret;
}
// override so we can parse DOCINFO field subtypes INFO[1-4]
void SwHTMLParser::AddMetaUserDefined( ::rtl::OUString const & i_rMetaName )
{
// unless we already have 4 names, append the argument to m_InfoNames
::rtl::OUString* pName // the first empty string in m_InfoNames
(!m_InfoNames[0].getLength() ? &m_InfoNames[0] :
(!m_InfoNames[1].getLength() ? &m_InfoNames[1] :
(!m_InfoNames[2].getLength() ? &m_InfoNames[2] :
(!m_InfoNames[3].getLength() ? &m_InfoNames[3] : 0 ))));
if (pName)
{
(*pName) = i_rMetaName;
}
}