diff options
Diffstat (limited to 'editeng/source/editeng/impedit4.cxx')
-rw-r--r-- | editeng/source/editeng/impedit4.cxx | 2955 |
1 files changed, 2955 insertions, 0 deletions
diff --git a/editeng/source/editeng/impedit4.cxx b/editeng/source/editeng/impedit4.cxx new file mode 100644 index 000000000000..c45c6faf2b6a --- /dev/null +++ b/editeng/source/editeng/impedit4.cxx @@ -0,0 +1,2955 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> + +#include <svl/srchitem.hxx> +#include <editeng/lspcitem.hxx> +#include <editeng/adjitem.hxx> +#include <editeng/tstpitem.hxx> + +#include <eertfpar.hxx> +#include <editeng/editeng.hxx> +#include <impedit.hxx> +#include <editeng/editview.hxx> +#include <eehtml.hxx> +#include <editobj2.hxx> +#include <i18npool/lang.h> + +#include "editxml.hxx" + +#include <editeng/akrnitem.hxx> +#include <editeng/cntritem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/crsditem.hxx> +#include <editeng/escpitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/charreliefitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <editeng/emphitem.hxx> +#include <textconv.hxx> +#include <rtl/tencinfo.h> +#include <svtools/rtfout.hxx> +#include <edtspell.hxx> +#include <editeng/scripttypeitem.hxx> +#include <editeng/unolingu.hxx> +#include <linguistic/lngprops.hxx> +#include <com/sun/star/linguistic2/XThesaurus.hpp> +#include <com/sun/star/linguistic2/XMeaning.hpp> +#include <com/sun/star/i18n/ScriptType.hpp> +#include <unotools/transliterationwrapper.hxx> +#include <unotools/textsearch.hxx> +#include <comphelper/processfactory.hxx> +#include <vcl/help.hxx> +#include <svtools/rtfkeywd.hxx> +#include <editeng/edtdlg.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::linguistic2; + +void SwapUSHORTs( sal_uInt16& rX, sal_uInt16& rY ) +{ + sal_uInt16 n = rX; + rX = rY; + rY = n; +} + +EditPaM ImpEditEngine::Read( SvStream& rInput, const String& rBaseURL, EETextFormat eFormat, EditSelection aSel, SvKeyValueIterator* pHTTPHeaderAttrs ) +{ + sal_Bool _bUpdate = GetUpdateMode(); + SetUpdateMode( sal_False ); + EditPaM aPaM; + if ( eFormat == EE_FORMAT_TEXT ) + aPaM = ReadText( rInput, aSel ); + else if ( eFormat == EE_FORMAT_RTF ) + aPaM = ReadRTF( rInput, aSel ); + else if ( eFormat == EE_FORMAT_XML ) + aPaM = ReadXML( rInput, aSel ); + else if ( eFormat == EE_FORMAT_HTML ) + aPaM = ReadHTML( rInput, rBaseURL, aSel, pHTTPHeaderAttrs ); + else if ( eFormat == EE_FORMAT_BIN) + aPaM = ReadBin( rInput, aSel ); + else + { + DBG_ERROR( "Read: Unbekanntes Format" ); + } + + FormatFullDoc(); // reicht vielleicht auch ein einfaches Format? + SetUpdateMode( _bUpdate ); + + return aPaM; +} + +EditPaM ImpEditEngine::ReadText( SvStream& rInput, EditSelection aSel ) +{ + if ( aSel.HasRange() ) + aSel = ImpDeleteSelection( aSel ); + EditPaM aPaM = aSel.Max(); + + XubString aTmpStr, aStr; + sal_Bool bDone = rInput.ReadByteStringLine( aTmpStr ); + while ( bDone ) + { + aTmpStr.Erase( MAXCHARSINPARA ); + aPaM = ImpInsertText( EditSelection( aPaM, aPaM ), aTmpStr ); + aPaM = ImpInsertParaBreak( aPaM ); + bDone = rInput.ReadByteStringLine( aTmpStr ); + } + return aPaM; +} + +EditPaM ImpEditEngine::ReadXML( SvStream& rInput, EditSelection aSel ) +{ +#ifndef SVX_LIGHT + if ( aSel.HasRange() ) + aSel = ImpDeleteSelection( aSel ); + + ESelection aESel = CreateESel( aSel ); + + ::SvxReadXML( *GetEditEnginePtr(), rInput, aESel ); + + return aSel.Max(); +#else + return EditPaM(); +#endif +} + +EditPaM ImpEditEngine::ReadRTF( SvStream& rInput, EditSelection aSel ) +{ +#ifndef SVX_LIGHT + +#if defined (EDITDEBUG) && !defined( UNX ) + SvFileStream aRTFOut( String( RTL_CONSTASCII_USTRINGPARAM ( "d:\\rtf_in.rtf" ) ), STREAM_WRITE ); + aRTFOut << rInput; + aRTFOut.Close(); + rInput.Seek( 0 ); +#endif + if ( aSel.HasRange() ) + aSel = ImpDeleteSelection( aSel ); + +// sal_Bool bCharsBeforeInsertPos = ( aSel.Min().GetIndex() ) ? sal_True : sal_False; +// sal_Bool bCharsBehindInsertPos = ( aSel.Min().GetIndex() < aSel.Min().GetNode()->Len() ) ? sal_True : sal_False; + + // Der SvRTF-Parser erwartet, dass das Which-Mapping am uebergebenen Pool, + // nicht an einem Secondary haengt. + SfxItemPool* pPool = &aEditDoc.GetItemPool(); + while ( pPool->GetSecondaryPool() && !pPool->GetName().EqualsAscii( "EditEngineItemPool" ) ) + { + pPool = pPool->GetSecondaryPool(); + + } + DBG_ASSERT( pPool && pPool->GetName().EqualsAscii( "EditEngineItemPool" ), "ReadRTF: Kein EditEnginePool!" ); + + EditRTFParserRef xPrsr = new EditRTFParser( rInput, aSel, *pPool, this ); + SvParserState eState = xPrsr->CallParser(); + if ( ( eState != SVPAR_ACCEPTED ) && ( !rInput.GetError() ) ) + { + rInput.SetError( EE_READWRITE_WRONGFORMAT ); + return aSel.Min(); + } + return xPrsr->GetCurPaM(); +#else + return EditPaM(); +#endif +} + +EditPaM ImpEditEngine::ReadHTML( SvStream& rInput, const String& rBaseURL, EditSelection aSel, SvKeyValueIterator* pHTTPHeaderAttrs ) +{ +#ifndef SVX_LIGHT + + if ( aSel.HasRange() ) + aSel = ImpDeleteSelection( aSel ); + +// sal_Bool bCharsBeforeInsertPos = ( aSel.Min().GetIndex() ) ? sal_True : sal_False; +// sal_Bool bCharsBehindInsertPos = ( aSel.Min().GetIndex() < aSel.Min().GetNode()->Len() ) ? sal_True : sal_False; + + EditHTMLParserRef xPrsr = new EditHTMLParser( rInput, rBaseURL, pHTTPHeaderAttrs ); + SvParserState eState = xPrsr->CallParser( this, aSel.Max() ); + if ( ( eState != SVPAR_ACCEPTED ) && ( !rInput.GetError() ) ) + { + rInput.SetError( EE_READWRITE_WRONGFORMAT ); + return aSel.Min(); + } + return xPrsr->GetCurSelection().Max(); +#else + return EditPaM(); +#endif +} + +EditPaM ImpEditEngine::ReadBin( SvStream& rInput, EditSelection aSel ) +{ + // Einfach ein temporaeres TextObject missbrauchen... + EditTextObject* pObj = EditTextObject::Create( rInput, NULL ); + + EditPaM aLastPaM = aSel.Max(); + if ( pObj ) + aLastPaM = InsertText( *pObj, aSel ).Max(); + + delete pObj; + return aLastPaM; +} + +#ifndef SVX_LIGHT +void ImpEditEngine::Write( SvStream& rOutput, EETextFormat eFormat, EditSelection aSel ) +{ + if ( !rOutput.IsWritable() ) + rOutput.SetError( SVSTREAM_WRITE_ERROR ); + + if ( !rOutput.GetError() ) + { + if ( eFormat == EE_FORMAT_TEXT ) + WriteText( rOutput, aSel ); + else if ( eFormat == EE_FORMAT_RTF ) + WriteRTF( rOutput, aSel ); + else if ( eFormat == EE_FORMAT_XML ) + WriteXML( rOutput, aSel ); + else if ( eFormat == EE_FORMAT_HTML ) + WriteHTML( rOutput, aSel ); + else if ( eFormat == EE_FORMAT_BIN) + WriteBin( rOutput, aSel ); + else + { + DBG_ERROR( "Write: Unbekanntes Format" ); + } + } +} +#endif + +sal_uInt32 ImpEditEngine::WriteText( SvStream& rOutput, EditSelection aSel ) +{ + sal_uInt16 nStartNode, nEndNode; + sal_Bool bRange = aSel.HasRange(); + if ( bRange ) + { + aSel.Adjust( aEditDoc ); + nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() ); + nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() ); + } + else + { + nStartNode = 0; + nEndNode = aEditDoc.Count()-1; + } + + // ueber die Absaetze iterieren... + for ( sal_uInt16 nNode = nStartNode; nNode <= nEndNode; nNode++ ) + { + ContentNode* pNode = aEditDoc.GetObject( nNode ); + DBG_ASSERT( pNode, "Node nicht gefunden: Search&Replace" ); + + sal_uInt16 nStartPos = 0; + sal_uInt16 nEndPos = pNode->Len(); + if ( bRange ) + { + if ( nNode == nStartNode ) + nStartPos = aSel.Min().GetIndex(); + if ( nNode == nEndNode ) // kann auch == nStart sein! + nEndPos = aSel.Max().GetIndex(); + } + XubString aTmpStr = aEditDoc.GetParaAsString( pNode, nStartPos, nEndPos ); + rOutput.WriteByteStringLine( aTmpStr ); + } + + return rOutput.GetError(); +} + +sal_Bool ImpEditEngine::WriteItemListAsRTF( ItemList& rLst, SvStream& rOutput, sal_uInt16 nPara, sal_uInt16 nPos, + SvxFontTable& rFontTable, SvxColorList& rColorList ) +{ + const SfxPoolItem* pAttrItem = rLst.First(); + while ( pAttrItem ) + { + WriteItemAsRTF( *pAttrItem, rOutput, nPara, nPos,rFontTable, rColorList ); + pAttrItem = rLst.Next(); + } + return ( rLst.Count() ? sal_True : sal_False ); +} + +void lcl_FindValidAttribs( ItemList& rLst, ContentNode* pNode, sal_uInt16 nIndex, USHORT nScriptType ) +{ + sal_uInt16 nAttr = 0; + EditCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + while ( pAttr && ( pAttr->GetStart() <= nIndex ) ) + { + // Start wird in While ueberprueft... + if ( pAttr->GetEnd() > nIndex ) + { + if ( IsScriptItemValid( pAttr->GetItem()->Which(), nScriptType ) ) + rLst.Insert( pAttr->GetItem(), LIST_APPEND ); + } + nAttr++; + pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + } +} + +sal_uInt32 ImpEditEngine::WriteBin( SvStream& rOutput, EditSelection aSel, BOOL bStoreUnicodeStrings ) const +{ + BinTextObject* pObj = (BinTextObject*)CreateBinTextObject( aSel, NULL ); + pObj->StoreUnicodeStrings( bStoreUnicodeStrings ); + pObj->Store( rOutput ); + delete pObj; + return 0; +} + +#ifndef SVX_LIGHT +sal_uInt32 ImpEditEngine::WriteXML( SvStream& rOutput, EditSelection aSel ) +{ + ESelection aESel = CreateESel( aSel ); + + SvxWriteXML( *GetEditEnginePtr(), rOutput, aESel ); + + return 0; +} +#endif + +static sal_uInt16 getStylePos( const SfxStyles& rStyles, SfxStyleSheet* pSheet ) +{ + sal_uInt16 nNumber = 0; + SfxStyles::const_iterator iter( rStyles.begin() ); + while( iter != rStyles.end() ) + { + if( (*iter++).get() == pSheet ) + return nNumber; + ++nNumber; + } + return 0; +} + +sal_uInt32 ImpEditEngine::WriteRTF( SvStream& rOutput, EditSelection aSel ) +{ +#ifndef SVX_LIGHT + DBG_ASSERT( GetUpdateMode(), "WriteRTF bei UpdateMode = sal_False!" ); + CheckIdleFormatter(); + if ( !IsFormatted() ) + FormatDoc(); + + sal_uInt16 nStartNode, nEndNode; + aSel.Adjust( aEditDoc ); + + nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() ); + nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() ); + + // RTF-Vorspann... + rOutput << '{' ; + + rOutput << OOO_STRING_SVTOOLS_RTF_RTF; + + rOutput << OOO_STRING_SVTOOLS_RTF_ANSI; + rtl_TextEncoding eDestEnc = RTL_TEXTENCODING_MS_1252; + + // Fonttabelle erzeugen und rausschreiben... + SvxFontTable aFontTable; + // DefaultFont muss ganz vorne stehen, damit DEF-Font im RTF + aFontTable.Insert( 0, new SvxFontItem( (const SvxFontItem&)aEditDoc.GetItemPool().GetDefaultItem( EE_CHAR_FONTINFO ) ) ); + aFontTable.Insert( 1, new SvxFontItem( (const SvxFontItem&)aEditDoc.GetItemPool().GetDefaultItem( EE_CHAR_FONTINFO_CJK ) ) ); + aFontTable.Insert( 2, new SvxFontItem( (const SvxFontItem&)aEditDoc.GetItemPool().GetDefaultItem( EE_CHAR_FONTINFO_CTL ) ) ); + for ( USHORT nScriptType = 0; nScriptType < 3; nScriptType++ ) + { + USHORT nWhich = EE_CHAR_FONTINFO; + if ( nScriptType == 1 ) + nWhich = EE_CHAR_FONTINFO_CJK; + else if ( nScriptType == 2 ) + nWhich = EE_CHAR_FONTINFO_CTL; + + sal_uInt16 i = 0; + SvxFontItem* pFontItem = (SvxFontItem*)aEditDoc.GetItemPool().GetItem( nWhich, i ); + while ( pFontItem ) + { + bool bAlreadyExist = false; + ULONG nTestMax = nScriptType ? aFontTable.Count() : 1; + for ( ULONG nTest = 0; !bAlreadyExist && ( nTest < nTestMax ); nTest++ ) + { + bAlreadyExist = *aFontTable.Get( nTest ) == *pFontItem; + } + + if ( !bAlreadyExist ) + aFontTable.Insert( aFontTable.Count(), new SvxFontItem( *pFontItem ) ); + + pFontItem = (SvxFontItem*)aEditDoc.GetItemPool().GetItem( nWhich, ++i ); + } + } + + rOutput << endl << '{' << OOO_STRING_SVTOOLS_RTF_FONTTBL; + sal_uInt16 j; + for ( j = 0; j < aFontTable.Count(); j++ ) + { + SvxFontItem* pFontItem = aFontTable.Get( j ); + rOutput << '{'; + rOutput << OOO_STRING_SVTOOLS_RTF_F; + rOutput.WriteNumber( j ); + switch ( pFontItem->GetFamily() ) + { + case FAMILY_DONTKNOW: rOutput << OOO_STRING_SVTOOLS_RTF_FNIL; + break; + case FAMILY_DECORATIVE: rOutput << OOO_STRING_SVTOOLS_RTF_FDECOR; + break; + case FAMILY_MODERN: rOutput << OOO_STRING_SVTOOLS_RTF_FMODERN; + break; + case FAMILY_ROMAN: rOutput << OOO_STRING_SVTOOLS_RTF_FROMAN; + break; + case FAMILY_SCRIPT: rOutput << OOO_STRING_SVTOOLS_RTF_FSCRIPT; + break; + case FAMILY_SWISS: rOutput << OOO_STRING_SVTOOLS_RTF_FSWISS; + break; + default: + break; + } + rOutput << OOO_STRING_SVTOOLS_RTF_FPRQ; + sal_uInt16 nVal = 0; + switch( pFontItem->GetPitch() ) + { + case PITCH_FIXED: nVal = 1; break; + case PITCH_VARIABLE: nVal = 2; break; + default: + break; + } + rOutput.WriteNumber( nVal ); + + CharSet eChrSet = pFontItem->GetCharSet(); + DBG_ASSERT( eChrSet != 9, "SystemCharSet?!" ); + if( RTL_TEXTENCODING_DONTKNOW == eChrSet ) + eChrSet = gsl_getSystemTextEncoding(); + rOutput << OOO_STRING_SVTOOLS_RTF_FCHARSET; + rOutput.WriteNumber( rtl_getBestWindowsCharsetFromTextEncoding( eChrSet ) ); + + rOutput << ' '; + RTFOutFuncs::Out_String( rOutput, pFontItem->GetFamilyName(), eDestEnc ); + rOutput << ";}"; + } + rOutput << '}'; + rOutput << endl; + + // ColorList rausschreiben... + SvxColorList aColorList; + sal_uInt16 i = 0; + SvxColorItem* pColorItem = (SvxColorItem*)aEditDoc.GetItemPool().GetItem( EE_CHAR_COLOR, i ); + while ( pColorItem ) + { + USHORT nPos = i; + if ( pColorItem->GetValue() == COL_AUTO ) + nPos = 0; + aColorList.Insert( new SvxColorItem( *pColorItem ), nPos ); + pColorItem = (SvxColorItem*)aEditDoc.GetItemPool().GetItem( EE_CHAR_COLOR, ++i ); + } + aColorList.Insert( new SvxColorItem( (const SvxColorItem&)aEditDoc.GetItemPool().GetDefaultItem( EE_CHAR_COLOR) ), (sal_uInt32)i ); + + rOutput << '{' << OOO_STRING_SVTOOLS_RTF_COLORTBL; + for ( j = 0; j < aColorList.Count(); j++ ) + { + pColorItem = aColorList.GetObject( j ); + if ( !j || ( pColorItem->GetValue() != COL_AUTO ) ) + { + rOutput << OOO_STRING_SVTOOLS_RTF_RED; + rOutput.WriteNumber( pColorItem->GetValue().GetRed() ); + rOutput << OOO_STRING_SVTOOLS_RTF_GREEN; + rOutput.WriteNumber( pColorItem->GetValue().GetGreen() ); + rOutput << OOO_STRING_SVTOOLS_RTF_BLUE; + rOutput.WriteNumber( pColorItem->GetValue().GetBlue() ); + } + rOutput << ';'; + } + rOutput << '}'; + rOutput << endl; + + // StyleSheets... + if ( GetStyleSheetPool() ) + { + sal_uInt16 nStyles = (sal_uInt16)GetStyleSheetPool()->GetStyles().size(); + if ( nStyles ) + { + rOutput << '{' << OOO_STRING_SVTOOLS_RTF_STYLESHEET; + + for ( sal_uInt16 nStyle = 0; nStyle < nStyles; nStyle++ ) + { + + SfxStyleSheet* pStyle = (SfxStyleSheet*)GetStyleSheetPool()->GetStyles()[ nStyle ].get(); + + rOutput << endl << '{' << OOO_STRING_SVTOOLS_RTF_S; + sal_uInt16 nNumber = (sal_uInt16) (nStyle + 1); + rOutput.WriteNumber( nNumber ); + + // Attribute, auch aus Parent! + for ( sal_uInt16 nParAttr = EE_PARA_START; nParAttr <= EE_CHAR_END; nParAttr++ ) + { + if ( pStyle->GetItemSet().GetItemState( nParAttr ) == SFX_ITEM_ON ) + { + const SfxPoolItem& rItem = pStyle->GetItemSet().Get( nParAttr ); + WriteItemAsRTF( rItem, rOutput, 0, 0, aFontTable, aColorList ); + } + } + + // Parent...(nur wenn noetig) + if ( pStyle->GetParent().Len() && ( pStyle->GetParent() != pStyle->GetName() ) ) + { + SfxStyleSheet* pParent = (SfxStyleSheet*)GetStyleSheetPool()->Find( pStyle->GetParent(), pStyle->GetFamily() ); + DBG_ASSERT( pParent, "Parent nicht gefunden!" ); + rOutput << OOO_STRING_SVTOOLS_RTF_SBASEDON; + nNumber = (sal_uInt16) getStylePos( GetStyleSheetPool()->GetStyles(), pParent ) + 1; + rOutput.WriteNumber( nNumber ); + } + + // Folgevorlage...(immer) + SfxStyleSheet* pNext = pStyle; + if ( pStyle->GetFollow().Len() && ( pStyle->GetFollow() != pStyle->GetName() ) ) + pNext = (SfxStyleSheet*)GetStyleSheetPool()->Find( pStyle->GetFollow(), pStyle->GetFamily() ); + + DBG_ASSERT( pNext, "Naechsten nicht gefunden!" ); + rOutput << OOO_STRING_SVTOOLS_RTF_SNEXT; + nNumber = (sal_uInt16) getStylePos( GetStyleSheetPool()->GetStyles(), pNext ) + 1; + rOutput.WriteNumber( nNumber ); + + // Namen der Vorlage... + rOutput << " " << ByteString( pStyle->GetName(), eDestEnc ).GetBuffer(); + rOutput << ";}"; + } + rOutput << '}'; + rOutput << endl; + } + } + + // Die Pool-Defaults vorweg schreiben... + rOutput << '{' << OOO_STRING_SVTOOLS_RTF_IGNORE << "\\EditEnginePoolDefaults"; + for ( sal_uInt16 nPoolDefItem = EE_PARA_START; nPoolDefItem <= EE_CHAR_END; nPoolDefItem++) + { + const SfxPoolItem& rItem = aEditDoc.GetItemPool().GetDefaultItem( nPoolDefItem ); + WriteItemAsRTF( rItem, rOutput, 0, 0, aFontTable, aColorList ); + } + rOutput << '}' << endl; + + // Def-Hoehe vorweg, da sonst 12Pt + // Doch nicht, onst in jedem Absatz hart! + // SfxItemSet aTmpSet( GetEmptyItemSet() ); + // const SvxFontHeightItem& rDefFontHeight = (const SvxFontHeightItem&)aTmpSet.Get( EE_CHAR_FONTHEIGHT ); + // WriteItemAsRTF( rDefFontHeight, rOutput, aFontTable, aColorList ); + // rOutput << '{' << OOO_STRING_SVTOOLS_RTF_IGNORE << "\\EditEnginePoolDefaultHeight}" << endl; + + // DefTab: + MapMode aTwpMode( MAP_TWIP ); + sal_uInt16 nDefTabTwps = (sal_uInt16) GetRefDevice()->LogicToLogic( + Point( aEditDoc.GetDefTab(), 0 ), + &GetRefMapMode(), &aTwpMode ).X(); + rOutput << OOO_STRING_SVTOOLS_RTF_DEFTAB; + rOutput.WriteNumber( nDefTabTwps ); + rOutput << endl; + + // ueber die Absaetze iterieren... + rOutput << '{' << endl; + for ( sal_uInt16 nNode = nStartNode; nNode <= nEndNode; nNode++ ) + { + ContentNode* pNode = aEditDoc.SaveGetObject( nNode ); + DBG_ASSERT( pNode, "Node nicht gefunden: Search&Replace" ); + + // Die Absatzattribute vorweg... + sal_Bool bAttr = sal_False; + + // Vorlage ? + if ( pNode->GetStyleSheet() ) + { + // Nummer der Vorlage + rOutput << OOO_STRING_SVTOOLS_RTF_S; + sal_uInt16 nNumber = (sal_uInt16) getStylePos( GetStyleSheetPool()->GetStyles(), pNode->GetStyleSheet() ) + 1; + rOutput.WriteNumber( nNumber ); + + // Alle Attribute + // Attribute, auch aus Parent! + for ( sal_uInt16 nParAttr = EE_PARA_START; nParAttr <= EE_CHAR_END; nParAttr++ ) + { + if ( pNode->GetStyleSheet()->GetItemSet().GetItemState( nParAttr ) == SFX_ITEM_ON ) + { + const SfxPoolItem& rItem = pNode->GetStyleSheet()->GetItemSet().Get( nParAttr ); + WriteItemAsRTF( rItem, rOutput, nNode, 0, aFontTable, aColorList ); + bAttr = sal_True; + } + } + } + + for ( sal_uInt16 nParAttr = EE_PARA_START; nParAttr <= EE_CHAR_END; nParAttr++ ) + { +// const SfxPoolItem& rItem = pNode->GetContentAttribs().GetItem( nParAttr ); + // Jetzt, wo StyleSheet-Verarbeitung, nur noch harte Absatzattribute! + if ( pNode->GetContentAttribs().GetItems().GetItemState( nParAttr ) == SFX_ITEM_ON ) + { + const SfxPoolItem& rItem = pNode->GetContentAttribs().GetItems().Get( nParAttr ); + WriteItemAsRTF( rItem, rOutput, nNode, 0, aFontTable, aColorList ); + bAttr = sal_True; + } + } + if ( bAttr ) + rOutput << ' '; // Separator + + ItemList aAttribItems; + ParaPortion* pParaPortion = FindParaPortion( pNode ); + DBG_ASSERT( pParaPortion, "Portion nicht gefunden: WriteRTF" ); + + sal_uInt16 nIndex = 0; + sal_uInt16 nStartPos = 0; + sal_uInt16 nEndPos = pNode->Len(); + sal_uInt16 nStartPortion = 0; + sal_uInt16 nEndPortion = (sal_uInt16)pParaPortion->GetTextPortions().Count() - 1; + sal_Bool bFinishPortion = sal_False; + sal_uInt16 nPortionStart; + + if ( nNode == nStartNode ) + { + nStartPos = aSel.Min().GetIndex(); + nStartPortion = pParaPortion->GetTextPortions().FindPortion( nStartPos, nPortionStart ); + if ( nStartPos != 0 ) + { + aAttribItems.Clear(); + lcl_FindValidAttribs( aAttribItems, pNode, nStartPos, GetScriptType( EditPaM( pNode, 0 ) ) ); + if ( aAttribItems.Count() ) + { + // Diese Attribute duerfen nicht fuer den gesamten + // Absatz gelten: + rOutput << '{'; + WriteItemListAsRTF( aAttribItems, rOutput, nNode, nStartPos, aFontTable, aColorList ); + bFinishPortion = sal_True; + } + aAttribItems.Clear(); + } + } + if ( nNode == nEndNode ) // kann auch == nStart sein! + { + nEndPos = aSel.Max().GetIndex(); + nEndPortion = pParaPortion->GetTextPortions().FindPortion( nEndPos, nPortionStart ); + } + + EditCharAttrib* pNextFeature = pNode->GetCharAttribs().FindFeature( nIndex ); + // Bei 0 anfangen, damit der Index richtig ist... + + for ( sal_uInt16 n = 0; n <= nEndPortion; n++ ) + { + TextPortion* pTextPortion = pParaPortion->GetTextPortions().GetObject(n); + if ( n < nStartPortion ) + { + nIndex = nIndex + pTextPortion->GetLen(); + continue; + } + + if ( pNextFeature && ( pNextFeature->GetStart() == nIndex ) && ( pNextFeature->GetItem()->Which() != EE_FEATURE_FIELD ) ) + { + WriteItemAsRTF( *pNextFeature->GetItem(), rOutput, nNode, nIndex, aFontTable, aColorList ); + pNextFeature = pNode->GetCharAttribs().FindFeature( pNextFeature->GetStart() + 1 ); + } + else + { + aAttribItems.Clear(); + USHORT nScriptType = GetScriptType( EditPaM( pNode, nIndex+1 ) ); + if ( !n || IsScriptChange( EditPaM( pNode, nIndex ) ) ) + { + SfxItemSet aAttribs = GetAttribs( nNode, nIndex+1, nIndex+1 ); + aAttribItems.Insert( &aAttribs.Get( GetScriptItemId( EE_CHAR_FONTINFO, nScriptType ) ), LIST_APPEND ); + aAttribItems.Insert( &aAttribs.Get( GetScriptItemId( EE_CHAR_FONTHEIGHT, nScriptType ) ), LIST_APPEND ); + aAttribItems.Insert( &aAttribs.Get( GetScriptItemId( EE_CHAR_WEIGHT, nScriptType ) ), LIST_APPEND ); + aAttribItems.Insert( &aAttribs.Get( GetScriptItemId( EE_CHAR_ITALIC, nScriptType ) ), LIST_APPEND ); + aAttribItems.Insert( &aAttribs.Get( GetScriptItemId( EE_CHAR_LANGUAGE, nScriptType ) ), LIST_APPEND ); + } + // #96298# Insert hard attribs AFTER CJK attribs... + lcl_FindValidAttribs( aAttribItems, pNode, nIndex, nScriptType ); + + rOutput << '{'; + if ( WriteItemListAsRTF( aAttribItems, rOutput, nNode, nIndex, aFontTable, aColorList ) ) + rOutput << ' '; + + USHORT nS = nIndex; + USHORT nE = nIndex + pTextPortion->GetLen(); + if ( n == nStartPortion ) + nS = nStartPos; + if ( n == nEndPortion ) + nE = nEndPos; + + XubString aRTFStr = aEditDoc.GetParaAsString( pNode, nS, nE); + RTFOutFuncs::Out_String( rOutput, aRTFStr, eDestEnc ); + rOutput << '}'; + } + if ( bFinishPortion ) + { + rOutput << '}'; + bFinishPortion = sal_False; + } + + nIndex = nIndex + pTextPortion->GetLen(); + } + + rOutput << OOO_STRING_SVTOOLS_RTF_PAR << OOO_STRING_SVTOOLS_RTF_PARD << OOO_STRING_SVTOOLS_RTF_PLAIN;; + rOutput << endl; + } + // RTF-Nachspann... + rOutput << "}}"; // 1xKlammerung Absaetze, 1x Klammerung RTF-Dokument + rOutput.Flush(); + +#if defined (EDITDEBUG) && !defined( UNX ) + { + SvFileStream aStream( String( RTL_CONSTASCII_USTRINGPARAM ( "d:\\rtf_out.rtf" ) ), STREAM_WRITE|STREAM_TRUNC ); + ULONG nP = rOutput.Tell(); + rOutput.Seek( 0 ); + aStream << rOutput; + rOutput.Seek( nP ); + } +#endif + + return rOutput.GetError(); +#else + return 0; +#endif +} + + +void ImpEditEngine::WriteItemAsRTF( const SfxPoolItem& rItem, SvStream& rOutput, sal_uInt16 nPara, sal_uInt16 nPos, + SvxFontTable& rFontTable, SvxColorList& rColorList ) +{ + sal_uInt16 nWhich = rItem.Which(); + switch ( nWhich ) + { + case EE_PARA_WRITINGDIR: + { + const SvxFrameDirectionItem& rWritingMode = (const SvxFrameDirectionItem&)rItem; + if ( rWritingMode.GetValue() == FRMDIR_HORI_RIGHT_TOP ) + rOutput << "\\rtlpar"; + else + rOutput << "\\ltrpar"; + } + break; + case EE_PARA_OUTLLEVEL: + { + sal_Int16 nLevel = ((const SfxInt16Item&)rItem).GetValue(); + if( nLevel >= 0 ) + { + rOutput << "\\level"; + rOutput.WriteNumber( nLevel ); + } + } + break; + case EE_PARA_OUTLLRSPACE: + case EE_PARA_LRSPACE: + { +// const ContentNode *pNode = aEditDoc.GetObject( nPara ); + + rOutput << OOO_STRING_SVTOOLS_RTF_FI; + short nTxtFirst = ((const SvxLRSpaceItem&)rItem).GetTxtFirstLineOfst(); + nTxtFirst = (short)LogicToTwips( nTxtFirst ); + rOutput.WriteNumber( nTxtFirst ); + rOutput << OOO_STRING_SVTOOLS_RTF_LI; + sal_uInt16 nTxtLeft = static_cast< sal_uInt16 >(((const SvxLRSpaceItem&)rItem).GetTxtLeft()); + nTxtLeft = (sal_uInt16)LogicToTwips( nTxtLeft ); + rOutput.WriteNumber( nTxtLeft ); + rOutput << OOO_STRING_SVTOOLS_RTF_RI; + sal_uInt32 nTxtRight = ((const SvxLRSpaceItem&)rItem).GetRight(); + nTxtRight = LogicToTwips( nTxtRight); + rOutput.WriteNumber( nTxtRight ); + } + break; + case EE_PARA_ULSPACE: + { + rOutput << OOO_STRING_SVTOOLS_RTF_SB; + sal_uInt16 nUpper = ((const SvxULSpaceItem&)rItem).GetUpper(); + nUpper = (sal_uInt16)LogicToTwips( nUpper ); + rOutput.WriteNumber( nUpper ); + rOutput << OOO_STRING_SVTOOLS_RTF_SA; + sal_uInt16 nLower = ((const SvxULSpaceItem&)rItem).GetLower(); + nLower = (sal_uInt16)LogicToTwips( nLower ); + rOutput.WriteNumber( nLower ); + } + break; + case EE_PARA_SBL: + { + rOutput << OOO_STRING_SVTOOLS_RTF_SL; + long nVal = ((const SvxLineSpacingItem&)rItem).GetLineHeight(); + char cMult = '0'; + if ( ((const SvxLineSpacingItem&)rItem).GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP ) + { + // Woher kriege ich jetzt den Wert? + // Der SwRTF-Parser geht von einem 240er Font aus! + nVal = ((const SvxLineSpacingItem&)rItem).GetPropLineSpace(); + nVal *= 240; + nVal /= 100; + cMult = '1'; + } + rOutput.WriteNumber( nVal ); + rOutput << OOO_STRING_SVTOOLS_RTF_SLMULT << cMult; + } + break; + case EE_PARA_JUST: + { + SvxAdjust eJustification = ((const SvxAdjustItem&)rItem).GetAdjust(); + switch ( eJustification ) + { + case SVX_ADJUST_CENTER: rOutput << OOO_STRING_SVTOOLS_RTF_QC; + break; + case SVX_ADJUST_RIGHT: rOutput << OOO_STRING_SVTOOLS_RTF_QR; + break; + default: rOutput << OOO_STRING_SVTOOLS_RTF_QL; + break; + } + } + break; + case EE_PARA_TABS: + { + const SvxTabStopItem& rTabs = (const SvxTabStopItem&) rItem; + for ( sal_uInt16 i = 0; i < rTabs.Count(); i++ ) + { + const SvxTabStop& rTab = rTabs[i]; + rOutput << OOO_STRING_SVTOOLS_RTF_TX; + rOutput.WriteNumber( LogicToTwips( rTab.GetTabPos() ) ); + } + } + break; + case EE_CHAR_COLOR: + { + sal_uInt32 n = rColorList.GetId( (const SvxColorItem&)rItem ); + rOutput << OOO_STRING_SVTOOLS_RTF_CF; + rOutput.WriteNumber( n ); + } + break; + case EE_CHAR_FONTINFO: + case EE_CHAR_FONTINFO_CJK: + case EE_CHAR_FONTINFO_CTL: + { + sal_uInt32 n = rFontTable.GetId( (const SvxFontItem&)rItem ); + rOutput << OOO_STRING_SVTOOLS_RTF_F; + rOutput.WriteNumber( n ); + } + break; + case EE_CHAR_FONTHEIGHT: + case EE_CHAR_FONTHEIGHT_CJK: + case EE_CHAR_FONTHEIGHT_CTL: + { + rOutput << OOO_STRING_SVTOOLS_RTF_FS; + long nHeight = ((const SvxFontHeightItem&)rItem).GetHeight(); + nHeight = LogicToTwips( nHeight ); + // Twips => HalfPoints + nHeight /= 10; + rOutput.WriteNumber( nHeight ); + } + break; + case EE_CHAR_WEIGHT: + case EE_CHAR_WEIGHT_CJK: + case EE_CHAR_WEIGHT_CTL: + { + FontWeight e = ((const SvxWeightItem&)rItem).GetWeight(); + switch ( e ) + { + case WEIGHT_BOLD: rOutput << OOO_STRING_SVTOOLS_RTF_B; break; + default: rOutput << OOO_STRING_SVTOOLS_RTF_B << '0'; break; + } + } + break; + case EE_CHAR_UNDERLINE: + { + // muesste bei WordLineMode ggf. ulw werden, + // aber die Information fehlt hier + FontUnderline e = ((const SvxUnderlineItem&)rItem).GetLineStyle(); + switch ( e ) + { + case UNDERLINE_NONE: rOutput << OOO_STRING_SVTOOLS_RTF_ULNONE; break; + case UNDERLINE_SINGLE: rOutput << OOO_STRING_SVTOOLS_RTF_UL; break; + case UNDERLINE_DOUBLE: rOutput << OOO_STRING_SVTOOLS_RTF_ULDB; break; + case UNDERLINE_DOTTED: rOutput << OOO_STRING_SVTOOLS_RTF_ULD; break; + default: + break; + } + } + break; + case EE_CHAR_OVERLINE: + { + FontUnderline e = ((const SvxOverlineItem&)rItem).GetLineStyle(); + switch ( e ) + { + case UNDERLINE_NONE: rOutput << OOO_STRING_SVTOOLS_RTF_OLNONE; break; + case UNDERLINE_SINGLE: rOutput << OOO_STRING_SVTOOLS_RTF_OL; break; + case UNDERLINE_DOUBLE: rOutput << OOO_STRING_SVTOOLS_RTF_OLDB; break; + case UNDERLINE_DOTTED: rOutput << OOO_STRING_SVTOOLS_RTF_OLD; break; + default: + break; + } + } + break; + case EE_CHAR_STRIKEOUT: + { + FontStrikeout e = ((const SvxCrossedOutItem&)rItem).GetStrikeout(); + switch ( e ) + { + case STRIKEOUT_SINGLE: + case STRIKEOUT_DOUBLE: rOutput << OOO_STRING_SVTOOLS_RTF_STRIKE; break; + case STRIKEOUT_NONE: rOutput << OOO_STRING_SVTOOLS_RTF_STRIKE << '0'; break; + default: + break; + } + } + break; + case EE_CHAR_ITALIC: + case EE_CHAR_ITALIC_CJK: + case EE_CHAR_ITALIC_CTL: + { + FontItalic e = ((const SvxPostureItem&)rItem).GetPosture(); + switch ( e ) + { + case ITALIC_OBLIQUE: + case ITALIC_NORMAL: rOutput << OOO_STRING_SVTOOLS_RTF_I; break; + case ITALIC_NONE: rOutput << OOO_STRING_SVTOOLS_RTF_I << '0'; break; + default: + break; + } + } + break; + case EE_CHAR_OUTLINE: + { + rOutput << OOO_STRING_SVTOOLS_RTF_OUTL; + if ( ((const SvxContourItem&)rItem).GetValue() == 0 ) + rOutput << '0'; + } + break; + case EE_CHAR_RELIEF: + { + USHORT nRelief = ((const SvxCharReliefItem&)rItem).GetValue(); + if ( nRelief == RELIEF_EMBOSSED ) + rOutput << OOO_STRING_SVTOOLS_RTF_EMBO; + if ( nRelief == RELIEF_ENGRAVED ) + rOutput << OOO_STRING_SVTOOLS_RTF_IMPR; + } + break; + case EE_CHAR_EMPHASISMARK: + { + USHORT nMark = ((const SvxEmphasisMarkItem&)rItem).GetValue(); + if ( nMark == EMPHASISMARK_NONE ) + rOutput << OOO_STRING_SVTOOLS_RTF_ACCNONE; + else if ( nMark == EMPHASISMARK_SIDE_DOTS ) + rOutput << OOO_STRING_SVTOOLS_RTF_ACCCOMMA; + else + rOutput << OOO_STRING_SVTOOLS_RTF_ACCDOT; + } + break; + case EE_CHAR_SHADOW: + { + rOutput << OOO_STRING_SVTOOLS_RTF_SHAD; + if ( ((const SvxShadowedItem&)rItem).GetValue() == 0 ) + rOutput << '0'; + } + break; + case EE_FEATURE_TAB: + { + rOutput << OOO_STRING_SVTOOLS_RTF_TAB; + } + break; + case EE_FEATURE_LINEBR: + { + rOutput << OOO_STRING_SVTOOLS_RTF_SL; + } + break; + case EE_CHAR_KERNING: + { + rOutput << OOO_STRING_SVTOOLS_RTF_EXPNDTW; + rOutput.WriteNumber( LogicToTwips( + ((const SvxKerningItem&)rItem).GetValue() ) ); + } + break; + case EE_CHAR_PAIRKERNING: + { + rOutput << OOO_STRING_SVTOOLS_RTF_KERNING; + rOutput.WriteNumber( ((const SvxAutoKernItem&)rItem).GetValue() ? 1 : 0 ); + } + break; + case EE_CHAR_ESCAPEMENT: + { + SvxFont aFont; + ContentNode* pNode = aEditDoc.GetObject( nPara ); + SeekCursor( pNode, nPos, aFont ); + MapMode aPntMode( MAP_POINT ); + long nFontHeight = GetRefDevice()->LogicToLogic( + aFont.GetSize(), &GetRefMapMode(), &aPntMode ).Height(); + nFontHeight *=2; // HalfPoints + sal_uInt16 nProp = ((const SvxEscapementItem&)rItem).GetProp(); + sal_uInt16 nProp100 = nProp*100; // Fuer SWG-Token Prop in 100tel Prozent. + short nEsc = ((const SvxEscapementItem&)rItem).GetEsc(); + if ( nEsc == DFLT_ESC_AUTO_SUPER ) + { + nEsc = 100 - nProp; + nProp100++; // Eine 1 hinten bedeutet 'automatisch'. + } + else if ( nEsc == DFLT_ESC_AUTO_SUB ) + { + nEsc = sal::static_int_cast< short >( -( 100 - nProp ) ); + nProp100++; + } + // SWG: + if ( nEsc ) + rOutput << "{\\*\\updnprop" << ByteString::CreateFromInt32( nProp100 ).GetBuffer() << '}'; + long nUpDown = nFontHeight * Abs( nEsc ) / 100; + ByteString aUpDown = ByteString::CreateFromInt32( nUpDown ); + if ( nEsc < 0 ) + rOutput << OOO_STRING_SVTOOLS_RTF_DN << aUpDown.GetBuffer(); + else if ( nEsc > 0 ) + rOutput << OOO_STRING_SVTOOLS_RTF_UP << aUpDown.GetBuffer(); + } + break; + } +} + +sal_uInt32 ImpEditEngine::WriteHTML( SvStream&, EditSelection ) +{ + return 0; +} + + +EditTextObject* ImpEditEngine::CreateTextObject() +{ + EditSelection aCompleteSelection; + aCompleteSelection.Min() = aEditDoc.GetStartPaM(); + aCompleteSelection.Max() = aEditDoc.GetEndPaM(); + + return CreateTextObject( aCompleteSelection ); +} + +EditTextObject* ImpEditEngine::CreateTextObject( EditSelection aSel ) +{ + return CreateBinTextObject( aSel, GetEditTextObjectPool(), aStatus.AllowBigObjects(), nBigTextObjectStart ); +} + +EditTextObject* ImpEditEngine::CreateBinTextObject( EditSelection aSel, SfxItemPool* pPool, sal_Bool bAllowBigObjects, sal_uInt16 nBigObjectStart ) const +{ + BinTextObject* pTxtObj = new BinTextObject( pPool ); + pTxtObj->SetVertical( IsVertical() ); + MapUnit eMapUnit = (MapUnit)aEditDoc.GetItemPool().GetMetric( DEF_METRIC ); + pTxtObj->SetMetric( (sal_uInt16) eMapUnit ); + if ( pTxtObj->IsOwnerOfPool() ) + pTxtObj->GetPool()->SetDefaultMetric( (SfxMapUnit) eMapUnit ); + + sal_uInt16 nStartNode, nEndNode; + sal_uInt32 nTextPortions = 0; + + aSel.Adjust( aEditDoc ); + nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() ); + nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() ); + + sal_Bool bOnlyFullParagraphs = ( aSel.Min().GetIndex() || + ( aSel.Max().GetIndex() < aSel.Max().GetNode()->Len() ) ) ? + sal_False : sal_True; + + // Vorlagen werden nicht gespeichert! + // ( Nur Name und Familie, Vorlage selbst muss in App stehen! ) + + pTxtObj->SetScriptType( GetScriptType( aSel ) ); + + // ueber die Absaetze iterieren... + sal_uInt16 nNode; + for ( nNode = nStartNode; nNode <= nEndNode; nNode++ ) + { + ContentNode* pNode = aEditDoc.SaveGetObject( nNode ); + DBG_ASSERT( pNode, "Node nicht gefunden: Search&Replace" ); + + if ( bOnlyFullParagraphs ) + { + ParaPortion* pParaPortion = GetParaPortions()[nNode]; + nTextPortions += pParaPortion->GetTextPortions().Count(); + } + + sal_uInt16 nStartPos = 0; + sal_uInt16 nEndPos = pNode->Len(); + + sal_Bool bEmptyPara = nEndPos ? sal_False : sal_True; + + if ( ( nNode == nStartNode ) && !bOnlyFullParagraphs ) + nStartPos = aSel.Min().GetIndex(); + if ( ( nNode == nEndNode ) && !bOnlyFullParagraphs ) + nEndPos = aSel.Max().GetIndex(); + + + ContentInfo* pC = pTxtObj->CreateAndInsertContent(); + + // Die Absatzattribute... + pC->GetParaAttribs().Set( pNode->GetContentAttribs().GetItems() ); + + // Das StyleSheet... + if ( pNode->GetStyleSheet() ) + { + pC->GetStyle() = pNode->GetStyleSheet()->GetName(); + pC->GetFamily() = pNode->GetStyleSheet()->GetFamily(); + } + + // Der Text... + pC->GetText() = pNode->Copy( nStartPos, nEndPos-nStartPos ); + + // und die Attribute... + sal_uInt16 nAttr = 0; + EditCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + while ( pAttr ) + { + // In einem leeren Absatz die Attribute behalten! + if ( bEmptyPara || + ( ( pAttr->GetEnd() > nStartPos ) && ( pAttr->GetStart() < nEndPos ) ) ) + { + XEditAttribute* pX = pTxtObj->CreateAttrib( *pAttr->GetItem(), pAttr->GetStart(), pAttr->GetEnd() ); + // Evtl. korrigieren... + if ( ( nNode == nStartNode ) && ( nStartPos != 0 ) ) + { + pX->GetStart() = ( pX->GetStart() > nStartPos ) ? pX->GetStart()-nStartPos : 0; + pX->GetEnd() = pX->GetEnd() - nStartPos; + + } + if ( nNode == nEndNode ) + { + if ( pX->GetEnd() > (nEndPos-nStartPos) ) + pX->GetEnd() = nEndPos-nStartPos; + } + DBG_ASSERT( pX->GetEnd() <= (nEndPos-nStartPos), "CreateBinTextObject: Attribut zu lang!" ); + if ( !pX->GetLen() && !bEmptyPara ) + pTxtObj->DestroyAttrib( pX ); + else + pC->GetAttribs().Insert( pX, pC->GetAttribs().Count() ); + } + nAttr++; + pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + } + +#ifndef SVX_LIGHT + // ggf. Online-Spelling + if ( bAllowBigObjects && bOnlyFullParagraphs && pNode->GetWrongList() ) + pC->SetWrongList( pNode->GetWrongList()->Clone() ); +#endif // !SVX_LIGHT + + } + + // Bei grossen Textobjekten die PortionInfos merken: + // Schwelle rauf setzen, wenn Olli die Absaetze nicht mehr zerhackt! + if ( bAllowBigObjects && bOnlyFullParagraphs && IsFormatted() && GetUpdateMode() && ( nTextPortions >= nBigObjectStart ) ) + { + XParaPortionList* pXList = new XParaPortionList( GetRefDevice(), aPaperSize.Width() ); + pTxtObj->SetPortionInfo( pXList ); + for ( nNode = nStartNode; nNode <= nEndNode; nNode++ ) + { + ParaPortion* pParaPortion = GetParaPortions()[nNode]; + XParaPortion* pX = new XParaPortion; + pXList->Insert( pX, pXList->Count() ); + + pX->nHeight = pParaPortion->GetHeight(); + pX->nFirstLineOffset = pParaPortion->GetFirstLineOffset(); + + // Die TextPortions + sal_uInt16 nCount = pParaPortion->GetTextPortions().Count(); + sal_uInt16 n; + for ( n = 0; n < nCount; n++ ) + { + TextPortion* pTextPortion = pParaPortion->GetTextPortions()[n]; + TextPortion* pNew = new TextPortion( *pTextPortion ); + pX->aTextPortions.Insert( pNew, pX->aTextPortions.Count() ); + } + + // Die Zeilen + nCount = pParaPortion->GetLines().Count(); + for ( n = 0; n < nCount; n++ ) + { + EditLine* pLine = pParaPortion->GetLines()[n]; + EditLine* pNew = pLine->Clone(); + pX->aLines.Insert( pNew, pX->aLines.Count() ); + } +#ifdef DBG_UTIL + USHORT nTest; + int nTPLen = 0, nTxtLen = 0; + for ( nTest = pParaPortion->GetTextPortions().Count(); nTest; ) + nTPLen += pParaPortion->GetTextPortions().GetObject( --nTest )->GetLen(); + for ( nTest = pParaPortion->GetLines().Count(); nTest; ) + nTxtLen += pParaPortion->GetLines().GetObject( --nTest )->GetLen(); + DBG_ASSERT( ( nTPLen == pParaPortion->GetNode()->Len() ) && ( nTxtLen == pParaPortion->GetNode()->Len() ), "CreateBinTextObject: ParaPortion not completely formatted!" ); +#endif + } + } + return pTxtObj; +} + +void ImpEditEngine::SetText( const EditTextObject& rTextObject ) +{ + // Da Setzen eines TextObject ist nicht Undo-faehig! + ResetUndoManager(); + sal_Bool _bUpdate = GetUpdateMode(); + sal_Bool _bUndo = IsUndoEnabled(); + + SetText( XubString() ); + EditPaM aPaM = aEditDoc.GetStartPaM(); + + SetUpdateMode( sal_False ); + EnableUndo( sal_False ); + + InsertText( rTextObject, EditSelection( aPaM, aPaM ) ); + SetVertical( rTextObject.IsVertical() ); + +#ifndef SVX_LIGHT + DBG_ASSERT( !HasUndoManager() || !GetUndoManager().GetUndoActionCount(), "Woher kommt das Undo in SetText ?!" ); +#endif + SetUpdateMode( _bUpdate ); + EnableUndo( _bUndo ); +} + +EditSelection ImpEditEngine::InsertText( const EditTextObject& rTextObject, EditSelection aSel ) +{ + EnterBlockNotifications(); + aSel.Adjust( aEditDoc ); + if ( aSel.HasRange() ) + aSel = ImpDeleteSelection( aSel ); + EditSelection aNewSel = InsertBinTextObject( (BinTextObject&)rTextObject, aSel.Max() ); + LeaveBlockNotifications(); + return aNewSel; + + // MT 05/00: InsertBinTextObject direkt hier machen... +} + +EditSelection ImpEditEngine::InsertBinTextObject( BinTextObject& rTextObject, EditPaM aPaM ) +{ + // Optimieren: + // Kein GetPos undFindParaportion, sondern Index berechnen! + EditSelection aSel( aPaM, aPaM ); + DBG_ASSERT( !aSel.DbgIsBuggy( aEditDoc ), "InsertBibTextObject: Selektion kaput!(1)" ); + + sal_Bool bUsePortionInfo = sal_False; +// sal_Bool bFields = sal_False; + XParaPortionList* pPortionInfo = rTextObject.GetPortionInfo(); + + if ( pPortionInfo && ( (long)pPortionInfo->GetPaperWidth() == aPaperSize.Width() ) + && ( pPortionInfo->GetRefMapMode() == GetRefDevice()->GetMapMode() ) ) + { + if ( ( pPortionInfo->GetRefDevPtr() == (sal_uIntPtr)GetRefDevice() ) || + ( ( pPortionInfo->GetRefDevType() == OUTDEV_VIRDEV ) && + ( GetRefDevice()->GetOutDevType() == OUTDEV_VIRDEV ) ) ) + bUsePortionInfo = sal_True; + } + + sal_Bool bConvertItems = sal_False; + MapUnit eSourceUnit = MapUnit(), eDestUnit = MapUnit(); + if ( rTextObject.HasMetric() ) + { + eSourceUnit = (MapUnit)rTextObject.GetMetric(); + eDestUnit = (MapUnit)aEditDoc.GetItemPool().GetMetric( DEF_METRIC ); + if ( eSourceUnit != eDestUnit ) + bConvertItems = sal_True; + } + + sal_uInt16 nContents = rTextObject.GetContents().Count(); + sal_uInt16 nPara = aEditDoc.GetPos( aPaM.GetNode() ); + + for ( sal_uInt16 n = 0; n < nContents; n++, nPara++ ) + { + ContentInfo* pC = rTextObject.GetContents().GetObject( n ); + sal_Bool bNewContent = aPaM.GetNode()->Len() ? sal_False: sal_True; + sal_uInt16 nStartPos = aPaM.GetIndex(); + + aPaM = ImpFastInsertText( aPaM, pC->GetText() ); + + ParaPortion* pPortion = FindParaPortion( aPaM.GetNode() ); + DBG_ASSERT( pPortion, "Blinde Portion in FastInsertText" ); + pPortion->MarkInvalid( nStartPos, pC->GetText().Len() ); + + // Zeicheattribute... + sal_Bool bAllreadyHasAttribs = aPaM.GetNode()->GetCharAttribs().Count() ? sal_True : sal_False; + sal_uInt16 nNewAttribs = pC->GetAttribs().Count(); + if ( nNewAttribs ) + { + BOOL bUpdateFields = FALSE; + for ( sal_uInt16 nAttr = 0; nAttr < nNewAttribs; nAttr++ ) + { + XEditAttribute* pX = pC->GetAttribs().GetObject( nAttr ); + // Kann passieren wenn Absaetze >16K entstehen, dann wird einfach umgebrochen. + if ( pX->GetEnd() <= aPaM.GetNode()->Len() ) + { + if ( !bAllreadyHasAttribs || pX->IsFeature() ) + { + // Normale Attribute gehen dann schneller... + // Features duerfen nicht ueber EditDoc::InsertAttrib + // eingefuegt werden, sie sind bei FastInsertText schon im TextFluss + DBG_ASSERT( pX->GetEnd() <= aPaM.GetNode()->Len(), "InsertBinTextObject: Attribut zu gross!" ); + EditCharAttrib* pAttr; + if ( !bConvertItems ) + pAttr = MakeCharAttrib( aEditDoc.GetItemPool(), *(pX->GetItem()), pX->GetStart()+nStartPos, pX->GetEnd()+nStartPos ); + else + { + SfxPoolItem* pNew = pX->GetItem()->Clone(); + ConvertItem( *pNew, eSourceUnit, eDestUnit ); + pAttr = MakeCharAttrib( aEditDoc.GetItemPool(), *pNew, pX->GetStart()+nStartPos, pX->GetEnd()+nStartPos ); + delete pNew; + } + DBG_ASSERT( pAttr->GetEnd() <= aPaM.GetNode()->Len(), "InsertBinTextObject: Attribut passt nicht! (1)" ); + aPaM.GetNode()->GetCharAttribs().InsertAttrib( pAttr ); + if ( pAttr->Which() == EE_FEATURE_FIELD ) + bUpdateFields = TRUE; + } + else + { + DBG_ASSERT( pX->GetEnd()+nStartPos <= aPaM.GetNode()->Len(), "InsertBinTextObject: Attribut passt nicht! (2)" ); + // Tabs und andere Features koennen nicht ueber InsertAttrib eingefuegt werden: + aEditDoc.InsertAttrib( aPaM.GetNode(), pX->GetStart()+nStartPos, pX->GetEnd()+nStartPos, *pX->GetItem() ); + } + } + } + if ( bUpdateFields ) + UpdateFields(); + + // Sonst QuickFormat => Keine Attribute! + pPortion->MarkSelectionInvalid( nStartPos, pC->GetText().Len() ); + } + + DBG_ASSERT( CheckOrderedList( aPaM.GetNode()->GetCharAttribs().GetAttribs(), sal_True ), "InsertBinTextObject: Start-Liste verdreht" ); + + sal_Bool bParaAttribs = sal_False; + if ( bNewContent || ( ( n > 0 ) && ( n < (nContents-1) ) ) ) + { + bParaAttribs = sal_False; + // #101512# Don't overwrite level/style from existing paragraph in OutlineView + // MT 10/2002: Removed because of #103874#, handled in Outliner::EndPasteOrDropHdl now. +// if ( !aStatus.IsOutliner() || n ) + { + // nur dann Style und ParaAttribs, wenn neuer Absatz, oder + // komplett inneliegender... + bParaAttribs = pC->GetParaAttribs().Count() ? sal_True : sal_False; + if ( GetStyleSheetPool() && pC->GetStyle().Len() ) + { + SfxStyleSheet* pStyle = (SfxStyleSheet*)GetStyleSheetPool()->Find( pC->GetStyle(), pC->GetFamily() ); + DBG_ASSERT( pStyle, "InsertBinTextObject - Style not found!" ); + SetStyleSheet( nPara, pStyle ); + } + if ( !bConvertItems ) + SetParaAttribs( aEditDoc.GetPos( aPaM.GetNode() ), pC->GetParaAttribs() ); + else + { + SfxItemSet aAttribs( GetEmptyItemSet() ); + ConvertAndPutItems( aAttribs, pC->GetParaAttribs(), &eSourceUnit, &eDestUnit ); + SetParaAttribs( aEditDoc.GetPos( aPaM.GetNode() ), aAttribs ); + } + } + if ( bNewContent && bUsePortionInfo ) + { + XParaPortion* pXP = pPortionInfo->GetObject( n ); + DBG_ASSERT( pXP, "InsertBinTextObject: PortionInfo?" ); + ParaPortion* pParaPortion = GetParaPortions()[ nPara ]; + DBG_ASSERT( pParaPortion, "InsertBinTextObject: ParaPortion?" ); + pParaPortion->nHeight = pXP->nHeight; + pParaPortion->nFirstLineOffset = pXP->nFirstLineOffset; + pParaPortion->bForceRepaint = sal_True; + pParaPortion->SetValid(); // Nicht formatieren + + // Die TextPortions + pParaPortion->GetTextPortions().Reset(); + sal_uInt16 nCount = pXP->aTextPortions.Count(); + for ( sal_uInt16 _n = 0; _n < nCount; _n++ ) + { + TextPortion* pTextPortion = pXP->aTextPortions[_n]; + TextPortion* pNew = new TextPortion( *pTextPortion ); + pParaPortion->GetTextPortions().Insert( pNew, _n ); + } + + // Die Zeilen + pParaPortion->GetLines().Reset(); + nCount = pXP->aLines.Count(); + for ( sal_uInt16 m = 0; m < nCount; m++ ) + { + EditLine* pLine = pXP->aLines[m]; + EditLine* pNew = pLine->Clone(); + pNew->SetInvalid(); // neu Painten! + pParaPortion->GetLines().Insert( pNew, m ); + } +#ifdef DBG_UTIL + USHORT nTest; + int nTPLen = 0, nTxtLen = 0; + for ( nTest = pParaPortion->GetTextPortions().Count(); nTest; ) + nTPLen += pParaPortion->GetTextPortions().GetObject( --nTest )->GetLen(); + for ( nTest = pParaPortion->GetLines().Count(); nTest; ) + nTxtLen += pParaPortion->GetLines().GetObject( --nTest )->GetLen(); + DBG_ASSERT( ( nTPLen == pParaPortion->GetNode()->Len() ) && ( nTxtLen == pParaPortion->GetNode()->Len() ), "InsertBinTextObject: ParaPortion not completely formatted!" ); +#endif + } + } + if ( !bParaAttribs ) // DefFont wird bei FastInsertParagraph nicht berechnet + { + aPaM.GetNode()->GetCharAttribs().GetDefFont() = aEditDoc.GetDefFont(); + if ( aStatus.UseCharAttribs() ) + aPaM.GetNode()->CreateDefFont(); + } + +#ifndef SVX_LIGHT + if ( bNewContent && GetStatus().DoOnlineSpelling() && pC->GetWrongList() ) + { + aPaM.GetNode()->DestroyWrongList(); // otherwise MLK, if list exists... + aPaM.GetNode()->SetWrongList( pC->GetWrongList()->Clone() ); + } +#endif // !SVX_LIGHT + + // Zeilenumbruch, wenn weitere folgen... + if ( n < ( nContents-1) ) + { + if ( bNewContent ) + aPaM = ImpFastInsertParagraph( nPara+1 ); + else + aPaM = ImpInsertParaBreak( aPaM, sal_False ); + } + } + + aSel.Max() = aPaM; + DBG_ASSERT( !aSel.DbgIsBuggy( aEditDoc ), "InsertBibTextObject: Selektion kaput!(1)" ); + return aSel; +} + +LanguageType ImpEditEngine::GetLanguage( const EditPaM& rPaM, USHORT* pEndPos ) const +{ + short nScriptType = GetScriptType( rPaM, pEndPos ); // pEndPos will be valid now, pointing to ScriptChange or NodeLen + USHORT nLangId = GetScriptItemId( EE_CHAR_LANGUAGE, nScriptType ); + const SvxLanguageItem* pLangItem = &(const SvxLanguageItem&)rPaM.GetNode()->GetContentAttribs().GetItem( nLangId ); + EditCharAttrib* pAttr = rPaM.GetNode()->GetCharAttribs().FindAttrib( nLangId, rPaM.GetIndex() ); + if ( pAttr ) + pLangItem = (const SvxLanguageItem*)pAttr->GetItem(); + + if ( pEndPos && pAttr && ( pAttr->GetEnd() < *pEndPos ) ) + *pEndPos = pAttr->GetEnd(); + + return pLangItem->GetLanguage(); +} + +::com::sun::star::lang::Locale ImpEditEngine::GetLocale( const EditPaM& rPaM ) const +{ + return SvxCreateLocale( GetLanguage( rPaM ) ); +} + +Reference< XSpellChecker1 > ImpEditEngine::GetSpeller() +{ +#ifndef SVX_LIGHT + if ( !xSpeller.is() ) + xSpeller = SvxGetSpellChecker(); +#endif + return xSpeller; +} + +EESpellState ImpEditEngine::Spell( EditView* pEditView, sal_Bool bMultipleDoc ) +{ +#ifdef SVX_LIGHT + return EE_SPELL_NOSPELLER; +#else + + DBG_ASSERTWARNING( xSpeller.is(), "Kein Speller gesetzt!" ); + + if ( !xSpeller.is() ) + return EE_SPELL_NOSPELLER; + + aOnlineSpellTimer.Stop(); + + // Bei MultipleDoc immer von vorne/hinten... + if ( bMultipleDoc ) + { + pEditView->pImpEditView->SetEditSelection( aEditDoc.GetStartPaM() ); + } + + EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() ); + pSpellInfo = new SpellInfo; + pSpellInfo->bMultipleDoc = bMultipleDoc; + pSpellInfo->aSpellStart = CreateEPaM( SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ).Min() ); + + sal_Bool bIsStart = sal_False; + if ( bMultipleDoc ) + bIsStart = sal_True; // Immer von Vorne bzw. von hinten... + else if ( ( CreateEPaM( aEditDoc.GetStartPaM() ) == pSpellInfo->aSpellStart ) ) + bIsStart = sal_True; + + EditSpellWrapper* pWrp = new EditSpellWrapper( Application::GetDefDialogParent(), + xSpeller, bIsStart, sal_False, pEditView ); + pWrp->SpellDocument(); + delete pWrp; + + if ( !bMultipleDoc ) + { + pEditView->pImpEditView->DrawSelection(); + if ( aCurSel.Max().GetIndex() > aCurSel.Max().GetNode()->Len() ) + aCurSel.Max().GetIndex() = aCurSel.Max().GetNode()->Len(); + aCurSel.Min() = aCurSel.Max(); + pEditView->pImpEditView->SetEditSelection( aCurSel ); + pEditView->pImpEditView->DrawSelection(); + pEditView->ShowCursor( sal_True, sal_False ); + } + EESpellState eState = pSpellInfo->eState; + delete pSpellInfo; + pSpellInfo = 0; + return eState; +#endif +} + + +sal_Bool ImpEditEngine::HasConvertibleTextPortion( LanguageType nSrcLang ) +{ +#ifdef SVX_LIGHT + return sal_False; +#else + sal_Bool bHasConvTxt = sal_False; + + USHORT nParas = pEditEngine->GetParagraphCount(); + for (USHORT k = 0; k < nParas; ++k) + { + SvUShorts aPortions; + pEditEngine->GetPortions( k, aPortions ); + for ( USHORT nPos = 0; nPos < aPortions.Count(); ++nPos ) + { + USHORT nEnd = aPortions.GetObject( nPos ); + USHORT nStart = nPos > 0 ? aPortions.GetObject( nPos - 1 ) : 0; + + // if the paragraph is not empty we need to increase the index + // by one since the attribute of the character left to the + // specified position is evaluated. + if (nEnd > nStart) // empty para? + ++nStart; + LanguageType nLangFound = pEditEngine->GetLanguage( k, nStart ); +#ifdef DEBUG + lang::Locale aLocale( SvxCreateLocale( nLangFound ) ); +#endif + bHasConvTxt = (nSrcLang == nLangFound) || + (editeng::HangulHanjaConversion::IsChinese( nLangFound ) && + editeng::HangulHanjaConversion::IsChinese( nSrcLang )); + if (bHasConvTxt) + return bHasConvTxt; + } + } + +#endif + return bHasConvTxt; +} + + +void ImpEditEngine::Convert( EditView* pEditView, + LanguageType nSrcLang, LanguageType nDestLang, const Font *pDestFont, + INT32 nOptions, sal_Bool bIsInteractive, sal_Bool bMultipleDoc ) +{ + // modified version of ImpEditEngine::Spell + +#ifdef SVX_LIGHT +#else + + // Bei MultipleDoc immer von vorne/hinten... + if ( bMultipleDoc ) + pEditView->pImpEditView->SetEditSelection( aEditDoc.GetStartPaM() ); + + // + // initialize pConvInfo + // + EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() ); + aCurSel.Adjust( aEditDoc ); + pConvInfo = new ConvInfo; + pConvInfo->bMultipleDoc = bMultipleDoc; + pConvInfo->aConvStart = CreateEPaM( aCurSel.Min() ); + // + // if it is not just a selection and we are about to begin + // with the current conversion for the very first time + // we need to find the start of the current (initial) + // convertible unit in order for the text conversion to give + // the correct result for that. Since it is easier to obtain + // the start of the word we use that though. + if (!aCurSel.HasRange() && ImplGetBreakIterator().is()) + { + EditPaM aWordStartPaM( SelectWord( aCurSel, i18n::WordType::DICTIONARY_WORD ).Min() ); + + // since #118246 / #117803 still occurs if the cursor is placed + // between the two chinese characters to be converted (because both + // of them are words on their own!) using the word boundary here does + // not work. Thus since chinese conversion is not interactive we start + // at the begin of the paragraph to solve the problem, i.e. have the + // TextConversion service get those characters together in the same call. + USHORT nStartIdx = ( editeng::HangulHanjaConversion::IsChinese( nSrcLang ) ) ? + 0 : aWordStartPaM.GetIndex(); + pConvInfo->aConvStart.nIndex = nStartIdx; + } + // + pConvInfo->aConvContinue = pConvInfo->aConvStart; + + sal_Bool bIsStart = sal_False; + if ( bMultipleDoc ) + bIsStart = sal_True; // Immer von Vorne bzw. von hinten... + else if ( CreateEPaM( aEditDoc.GetStartPaM() ) == pConvInfo->aConvStart ) + bIsStart = sal_True; + + bImpConvertFirstCall = sal_True; // next ImpConvert call is the very first in this conversion turn + + Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory(); + TextConvWrapper aWrp( Application::GetDefDialogParent(), xMSF, + SvxCreateLocale( nSrcLang ), SvxCreateLocale( nDestLang ), + pDestFont, + nOptions, bIsInteractive, + bIsStart, pEditView ); + + // + //!! optimization does not work since when update mode is false + //!! the object is 'lying' about it portions, paragraphs, + //!! EndPaM... later on. + //!! Should not be a great problem since text boxes or cells in + //!! Calc usually have only a rather short text. + // + // disallow formatting, updating the view, ... while + // non-interactively converting the document. (saves time) + //if (!bIsInteractive) + // SetUpdateMode( FALSE ); + + aWrp.Convert(); + + //if (!bIsInteractive) + //SetUpdateMode( TRUE, 0, TRUE ); + + if ( !bMultipleDoc ) + { + pEditView->pImpEditView->DrawSelection(); + if ( aCurSel.Max().GetIndex() > aCurSel.Max().GetNode()->Len() ) + aCurSel.Max().GetIndex() = aCurSel.Max().GetNode()->Len(); + aCurSel.Min() = aCurSel.Max(); + pEditView->pImpEditView->SetEditSelection( aCurSel ); + pEditView->pImpEditView->DrawSelection(); + pEditView->ShowCursor( sal_True, sal_False ); + } + delete pConvInfo; + pConvInfo = 0; +#endif +} + + +void ImpEditEngine::SetLanguageAndFont( + const ESelection &rESel, + LanguageType nLang, USHORT nLangWhichId, + const Font *pFont, USHORT nFontWhichId ) +{ + ESelection aOldSel = pActiveView->GetSelection(); + pActiveView->SetSelection( rESel ); + + // set new language attribute + SfxItemSet aNewSet( pActiveView->GetEmptyItemSet() ); + aNewSet.Put( SvxLanguageItem( nLang, nLangWhichId ) ); + + // new font to be set? + DBG_ASSERT( pFont, "target font missing?" ); + if (pFont) + { + // set new font attribute + SvxFontItem aFontItem = (SvxFontItem&) aNewSet.Get( nFontWhichId ); + aFontItem.GetFamilyName() = pFont->GetName(); + aFontItem.GetFamily() = pFont->GetFamily(); + aFontItem.GetStyleName() = pFont->GetStyleName(); + aFontItem.GetPitch() = pFont->GetPitch(); + aFontItem.GetCharSet() = pFont->GetCharSet(); + aNewSet.Put( aFontItem ); + } + + // apply new attributes + pActiveView->SetAttribs( aNewSet ); + + pActiveView->SetSelection( aOldSel ); +} + + +void ImpEditEngine::ImpConvert( rtl::OUString &rConvTxt, LanguageType &rConvTxtLang, + EditView* pEditView, LanguageType nSrcLang, const ESelection &rConvRange, + sal_Bool bAllowImplicitChangesForNotConvertibleText, + LanguageType nTargetLang, const Font *pTargetFont ) +{ + // modified version of ImpEditEngine::ImpSpell + + // looks for next convertible text portion to be passed on to the wrapper + + String aRes; + LanguageType nResLang = LANGUAGE_NONE; + +#ifdef SVX_LIGHT + rConvTxt = rtl::OUString(); + rConvTxtLang = LANGUAGE_NONE; +#else + + /* ContentNode* pLastNode = */ aEditDoc.SaveGetObject( aEditDoc.Count()-1 ); + + EditPaM aPos( CreateEditPaM( pConvInfo->aConvContinue ) ); + EditSelection aCurSel = EditSelection( aPos, aPos ); + + String aWord; + + while (!aRes.Len()) + { + // empty paragraph found that needs to have language and font set? + if (bAllowImplicitChangesForNotConvertibleText && + !pEditEngine->GetText( pConvInfo->aConvContinue.nPara ).Len()) + { + USHORT nPara = pConvInfo->aConvContinue.nPara; + ESelection aESel( nPara, 0, nPara, 0 ); + // see comment for below same function call + SetLanguageAndFont( aESel, + nTargetLang, EE_CHAR_LANGUAGE_CJK, + pTargetFont, EE_CHAR_FONTINFO_CJK ); + } + + + if (pConvInfo->aConvContinue.nPara == pConvInfo->aConvTo.nPara && + pConvInfo->aConvContinue.nIndex >= pConvInfo->aConvTo.nIndex) + break; + +/* + // Bekannter (wahrscheinlicher) Bug: Wenn SpellToCurrent, muss + // Current bei jeder Ersetzung korrigiert werden, sonst passt + // das Ende evtl. nicht mehr genau... + if ( pConvInfo->bConvToEnd || pConvInfo->bMultipleDoc ) + { + if ( aCurSel.Max().GetNode() == pLastNode && + aCurSel.Max().GetIndex() >= pLastNode->Len() ) + break; + } +*/ + + USHORT nAttribStart = USHRT_MAX; + USHORT nAttribEnd = USHRT_MAX; + USHORT nCurPos = USHRT_MAX; + EPaM aCurStart = CreateEPaM( aCurSel.Min() ); + SvUShorts aPortions; + pEditEngine->GetPortions( (USHORT)aCurStart.nPara, aPortions ); + for ( USHORT nPos = 0; nPos < aPortions.Count(); ++nPos ) + { + USHORT nEnd = aPortions.GetObject( nPos ); + USHORT nStart = nPos > 0 ? aPortions.GetObject( nPos - 1 ) : 0; + + // the language attribute is obtained from the left character + // (like usually all other attributes) + // thus we usually have to add 1 in order to get the language + // of the text right to the cursor position + USHORT nLangIdx = nEnd > nStart ? nStart + 1 : nStart; + LanguageType nLangFound = pEditEngine->GetLanguage( aCurStart.nPara, nLangIdx ); +#ifdef DEBUG + lang::Locale aLocale( SvxCreateLocale( nLangFound ) ); +#endif + sal_Bool bLangOk = (nLangFound == nSrcLang) || + (editeng::HangulHanjaConversion::IsChinese( nLangFound ) && + editeng::HangulHanjaConversion::IsChinese( nSrcLang )); + + if (nAttribEnd != USHRT_MAX) // start already found? + { + DBG_ASSERT(nEnd >= aCurStart.nIndex, "error while scanning attributes (a)" ); + DBG_ASSERT(nEnd >= nAttribEnd, "error while scanning attributes (b)" ); + if (/*nEnd >= aCurStart.nIndex &&*/ nLangFound == nResLang) + nAttribEnd = nEnd; + else // language attrib has changed + break; + } + if (nAttribStart == USHRT_MAX && // start not yet found? + nEnd > aCurStart.nIndex && bLangOk) + { + nAttribStart = nStart; + nAttribEnd = nEnd; + nResLang = nLangFound; + } + //! the list of portions may have changed compared to the previous + //! call to this function (because of possibly changed language + //! attribute!) + //! But since we don't want to start in the already processed part + //! we clip the start accordingly. + if (nAttribStart < aCurStart.nIndex) + { + nAttribStart = aCurStart.nIndex; + } + + // check script type to the right of the start of the current portion + EditPaM aPaM( CreateEditPaM( EPaM(aCurStart.nPara, nLangIdx) ) ); + sal_Bool bIsAsianScript = (i18n::ScriptType::ASIAN == GetScriptType( aPaM )); + // not yet processed text part with for conversion + // not suitable language found that needs to be changed? + if (bAllowImplicitChangesForNotConvertibleText && + !bLangOk && !bIsAsianScript && nEnd > aCurStart.nIndex) + { + ESelection aESel( aCurStart.nPara, nStart, aCurStart.nPara, nEnd ); + // set language and font to target language and font of conversion + //! Now this especially includes all non convertible text e.g. + //! spaces, empty paragraphs and western text. + // This is in order for every *new* text entered at *any* position to + // have the correct language and font attributes set. + SetLanguageAndFont( aESel, + nTargetLang, EE_CHAR_LANGUAGE_CJK, + pTargetFont, EE_CHAR_FONTINFO_CJK ); + } + + nCurPos = nEnd; + } + + if (nAttribStart != USHRT_MAX && nAttribEnd != USHRT_MAX) + { + aCurSel.Min().SetIndex( nAttribStart ); + aCurSel.Max().SetIndex( nAttribEnd ); + } + else if (nCurPos != USHRT_MAX) + { + // set selection to end of scanned text + // (used to set the position where to continue from later on) + aCurSel.Min().SetIndex( nCurPos ); + aCurSel.Max().SetIndex( nCurPos ); + } + + if ( !pConvInfo->bConvToEnd ) + { + EPaM aEPaM( CreateEPaM( aCurSel.Min() ) ); + if ( !( aEPaM < pConvInfo->aConvTo ) ) + break; + } + + // clip selected word to the converted area + // (main use when conversion starts/ends **within** a word) + EditPaM aPaM( CreateEditPaM( pConvInfo->aConvStart ) ); + if (pConvInfo->bConvToEnd && + aCurSel.Min().GetNode() == aPaM.GetNode() && + aCurSel.Min().GetIndex() < aPaM.GetIndex()) + aCurSel.Min().SetIndex( aPaM.GetIndex() ); + aPaM = CreateEditPaM( pConvInfo->aConvContinue ); + if (aCurSel.Min().GetNode() == aPaM.GetNode() && + aCurSel.Min().GetIndex() < aPaM.GetIndex()) + aCurSel.Min().SetIndex( aPaM.GetIndex() ); + aPaM = CreateEditPaM( pConvInfo->aConvTo ); + if ((!pConvInfo->bConvToEnd || rConvRange.HasRange())&& + aCurSel.Max().GetNode() == aPaM.GetNode() && + aCurSel.Max().GetIndex() > aPaM.GetIndex()) + aCurSel.Max().SetIndex( aPaM.GetIndex() ); + + aWord = GetSelected( aCurSel ); + + if ( aWord.Len() > 0 /* && bLangOk */) + aRes = aWord; + + // move to next word/paragraph if necessary + if ( !aRes.Len() ) + aCurSel = WordRight( aCurSel.Min(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + + pConvInfo->aConvContinue = CreateEPaM( aCurSel.Max() ); + } + + pEditView->pImpEditView->DrawSelection(); + pEditView->pImpEditView->SetEditSelection( aCurSel ); + pEditView->pImpEditView->DrawSelection(); + pEditView->ShowCursor( sal_True, sal_False ); + + rConvTxt = aRes; + if (rConvTxt.getLength()) + rConvTxtLang = nResLang; +#endif +} + + +Reference< XSpellAlternatives > ImpEditEngine::ImpSpell( EditView* pEditView ) +{ +#ifdef SVX_LIGHT + return Reference< XSpellAlternatives >(); +#else + + DBG_ASSERT( xSpeller.is(), "Kein Speller gesetzt!" ); + + ContentNode* pLastNode = aEditDoc.SaveGetObject( (aEditDoc.Count()-1) ); + EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() ); + aCurSel.Min() = aCurSel.Max(); + + String aWord; + Reference< XSpellAlternatives > xSpellAlt; + Sequence< PropertyValue > aEmptySeq; + while (!xSpellAlt.is()) + { + + // Bekannter (wahrscheinlicher) Bug: Wenn SpellToCurrent, muss + // Current bei jeder Ersetzung korrigiert werden, sonst passt + // das Ende evtl. nicht mehr genau... + if ( pSpellInfo->bSpellToEnd || pSpellInfo->bMultipleDoc ) + { + if ( aCurSel.Max().GetNode() == pLastNode ) + { + if ( ( aCurSel.Max().GetIndex() >= pLastNode->Len() ) ) + break; + } + } + else if ( !pSpellInfo->bSpellToEnd ) + { + EPaM aEPaM( CreateEPaM( aCurSel.Max() ) ); + if ( !( aEPaM < pSpellInfo->aSpellTo ) ) + break; + } + + aCurSel = SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + aWord = GetSelected( aCurSel ); + + // Wenn Punkt dahinter, muss dieser mit uebergeben werden ! + // Falls Abkuerzung... + if ( aWord.Len() && ( aCurSel.Max().GetIndex() < aCurSel.Max().GetNode()->Len() ) ) + { + sal_Unicode cNext = aCurSel.Max().GetNode()->GetChar( aCurSel.Max().GetIndex() ); + if ( cNext == '.' ) + { + aCurSel.Max().GetIndex()++; + aWord += cNext; + } + } + + if ( aWord.Len() > 0 ) + { + LanguageType eLang = GetLanguage( aCurSel.Max() ); + SvxSpellWrapper::CheckSpellLang( xSpeller, eLang ); + xSpellAlt = xSpeller->spell( aWord, eLang, aEmptySeq ); + } + + if ( !xSpellAlt.is() ) + aCurSel = WordRight( aCurSel.Min(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + else + pSpellInfo->eState = EE_SPELL_ERRORFOUND; + } + + pEditView->pImpEditView->DrawSelection(); + pEditView->pImpEditView->SetEditSelection( aCurSel ); + pEditView->pImpEditView->DrawSelection(); + pEditView->ShowCursor( sal_True, sal_False ); + return xSpellAlt; +#endif +} +/*-- 13.10.2003 16:43:27--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void ImpEditEngine::EndSpelling() +{ + DELETEZ(pSpellInfo); +} +/*-- 13.10.2003 16:43:27--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void ImpEditEngine::StartSpelling(EditView& rEditView, sal_Bool bMultipleDoc) +{ + DBG_ASSERT(!pSpellInfo, "pSpellInfo already set?"); + pSpellInfo = new SpellInfo; + pSpellInfo->bMultipleDoc = bMultipleDoc; + rEditView.pImpEditView->SetEditSelection( aEditDoc.GetStartPaM() ); + EditSelection aCurSel( rEditView.pImpEditView->GetEditSelection() ); + pSpellInfo->aSpellStart = CreateEPaM( SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ).Min() ); +} +/*-- 13.10.2003 16:43:27--------------------------------------------------- + Search for the next wrong word within the given selection + -----------------------------------------------------------------------*/ +Reference< XSpellAlternatives > ImpEditEngine::ImpFindNextError(EditSelection& rSelection) +{ + /* ContentNode* pLastNode = */ aEditDoc.SaveGetObject( (aEditDoc.Count()-1) ); + EditSelection aCurSel( rSelection.Min() ); + + String aWord; + Reference< XSpellAlternatives > xSpellAlt; + Sequence< PropertyValue > aEmptySeq; + while (!xSpellAlt.is()) + { + //check if the end of the selection has been reached + { + EPaM aEPaM( CreateEPaM( aCurSel.Max() ) ); + if ( !( aEPaM < CreateEPaM( rSelection.Max()) ) ) + break; + } + + aCurSel = SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + aWord = GetSelected( aCurSel ); + + // Wenn Punkt dahinter, muss dieser mit uebergeben werden ! + // Falls Abkuerzung... + if ( aWord.Len() && ( aCurSel.Max().GetIndex() < aCurSel.Max().GetNode()->Len() ) ) + { + sal_Unicode cNext = aCurSel.Max().GetNode()->GetChar( aCurSel.Max().GetIndex() ); + if ( cNext == '.' ) + { + aCurSel.Max().GetIndex()++; + aWord += cNext; + } + } + + if ( aWord.Len() > 0 ) + xSpellAlt = xSpeller->spell( aWord, GetLanguage( aCurSel.Max() ), aEmptySeq ); + + if ( !xSpellAlt.is() ) + aCurSel = WordRight( aCurSel.Min(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + else + { + pSpellInfo->eState = EE_SPELL_ERRORFOUND; + rSelection = aCurSel; + } + } + return xSpellAlt; +} +/*-- 13.10.2003 16:43:27--------------------------------------------------- + + -----------------------------------------------------------------------*/ +bool ImpEditEngine::SpellSentence(EditView& rEditView, ::svx::SpellPortions& rToFill, bool /*bIsGrammarChecking*/ ) +{ +#ifdef SVX_LIGHT +#else + bool bRet = false; + //the pSpellInfo has to be created on demand + if(!pSpellInfo) + { + pSpellInfo = new SpellInfo; + pSpellInfo->bMultipleDoc = sal_True; + rEditView.pImpEditView->SetEditSelection( aEditDoc.GetStartPaM() ); + EditSelection aCurSel( rEditView.pImpEditView->GetEditSelection() ); + pSpellInfo->aSpellStart = CreateEPaM( SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ).Min() ); + } + DBG_ASSERT( xSpeller.is(), "Kein Speller gesetzt!" ); + pSpellInfo->aLastSpellPortions.clear(); + pSpellInfo->aLastSpellContentSelections.clear(); + rToFill.clear(); + EditSelection aCurSel( rEditView.pImpEditView->GetEditSelection() ); + //if no selection previously exists the range is extended to the end of the object + if(aCurSel.Min() == aCurSel.Max()) + { + ContentNode* pLastNode = aEditDoc.SaveGetObject( aEditDoc.Count()-1); + aCurSel.Max() = EditPaM(pLastNode, pLastNode->Len()); + } + Reference< XSpellAlternatives > xAlt = ImpFindNextError(aCurSel); + if(xAlt.is()) + { + bRet = true; + //find the sentence boundaries + EditSelection aSentencePaM = SelectSentence(aCurSel); + //make sure that the sentence is never smaller than the error range! + if(aSentencePaM.Max().GetIndex() < aCurSel.Max().GetIndex()) + aSentencePaM.Max() = aCurSel.Max(); + //add the portion preceeding the error + EditSelection aStartSelection(aSentencePaM.Min(), aCurSel.Min()); + if(aStartSelection.HasRange()) + AddPortionIterated(rEditView, aStartSelection, 0, rToFill); + //add the error portion + AddPortionIterated(rEditView, aCurSel, xAlt, rToFill); + //find the end of the sentence + //search for all errors in the rest of the sentence and add all the portions + do + { + EditSelection aNextSel = EditSelection(aCurSel.Max(), aSentencePaM.Max()); + xAlt = ImpFindNextError(aNextSel); + if(xAlt.is()) + { + //add the part between the previous and the current error + AddPortionIterated(rEditView, EditSelection(aCurSel.Max(), aNextSel.Min()), 0, rToFill); + //add the current error + AddPortionIterated(rEditView, aNextSel, xAlt, rToFill); + } + else + AddPortionIterated(rEditView, EditSelection(aCurSel.Max(), aSentencePaM.Max()), xAlt, rToFill); + aCurSel = aNextSel; + } + while( xAlt.is() ); + //set the selection to the end of the current sentence + rEditView.pImpEditView->SetEditSelection(aSentencePaM.Max()); + } +#endif + return bRet; +} + +/*-- 15.10.2003 16:09:12--------------------------------------------------- + adds one portion to the SpellPortions + -----------------------------------------------------------------------*/ +void ImpEditEngine::AddPortion( + const EditSelection rSel, + uno::Reference< XSpellAlternatives > xAlt, + ::svx::SpellPortions& rToFill, + bool bIsField) +{ +#ifdef SVX_LIGHT +#else + if(rSel.HasRange()) + { + svx::SpellPortion aPortion; + aPortion.sText = GetSelected( rSel ); + aPortion.eLanguage = GetLanguage( rSel.Min() ); + aPortion.xAlternatives = xAlt; + aPortion.bIsField = bIsField; + rToFill.push_back(aPortion); + + //save the spelled portions for later use + pSpellInfo->aLastSpellPortions.push_back(aPortion); + pSpellInfo->aLastSpellContentSelections.push_back(rSel); + + } +#endif +} + +/*-- 15.10.2003 16:07:47--------------------------------------------------- + adds one or more portions of text to the SpellPortions depending on language changes + -----------------------------------------------------------------------*/ +void ImpEditEngine::AddPortionIterated( + EditView& rEditView, + const EditSelection rSel, + Reference< XSpellAlternatives > xAlt, + ::svx::SpellPortions& rToFill) +{ +#ifdef SVX_LIGHT +#else + if(rSel.Min() != rSel.Max()) + { + if(xAlt.is()) + { + AddPortion(rSel, xAlt, rToFill, false); + } + else + { + //iterate and search for language attribute changes + //save the start and end positions + bool bTest = rSel.Min().GetIndex() <= rSel.Max().GetIndex(); + EditPaM aStart(bTest ? rSel.Min() : rSel.Max()); + EditPaM aEnd(bTest ? rSel.Max() : rSel.Min()); + //iterate over the text to find changes in language + //set the mark equal to the point + EditPaM aCursor(aStart); + rEditView.pImpEditView->SetEditSelection( aCursor ); + LanguageType eStartLanguage = GetLanguage( aCursor ); + //search for a field attribute at the beginning - only the end position + //of this field is kept to end a portion at that position + const EditCharAttrib* pFieldAttr = aCursor.GetNode()->GetCharAttribs(). + FindFeature( aCursor.GetIndex() ); + bool bIsField = pFieldAttr && + pFieldAttr->GetStart() == aCursor.GetIndex() && + pFieldAttr->GetStart() != pFieldAttr->GetEnd() && + pFieldAttr->Which() == EE_FEATURE_FIELD; + USHORT nEndField = bIsField ? pFieldAttr->GetEnd() : USHRT_MAX; + bool bIsEndField = false; + do + { + aCursor = CursorRight( aCursor); + //determine whether a field and has been reached + bIsEndField = nEndField == aCursor.GetIndex(); + //search for a new field attribute + EditCharAttrib* _pFieldAttr = aCursor.GetNode()->GetCharAttribs(). + FindFeature( aCursor.GetIndex() ); + bIsField = _pFieldAttr && + _pFieldAttr->GetStart() == aCursor.GetIndex() && + _pFieldAttr->GetStart() != _pFieldAttr->GetEnd() && + _pFieldAttr->Which() == EE_FEATURE_FIELD; + //on every new field move the end position + if(bIsField) + nEndField = bIsField ? _pFieldAttr->GetEnd() : USHRT_MAX; + + LanguageType eCurLanguage = GetLanguage( aCursor ); + if(eCurLanguage != eStartLanguage || bIsField || bIsEndField) + { + eStartLanguage = eCurLanguage; + //go one step back - the cursor currently selects the first character + //with a different language + //create a selection from start to the current Cursor + EditSelection aSelection(aStart, aCursor); + AddPortion(aSelection, xAlt, rToFill, bIsEndField); + aStart = aCursor; + } + } + while(aCursor.GetIndex() < aEnd.GetIndex()); + EditSelection aSelection(aStart, aCursor); + AddPortion(aSelection, xAlt, rToFill, bIsField); + } + } +#endif +} + +/*-- 13.10.2003 16:43:33--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void ImpEditEngine::ApplyChangedSentence(EditView& rEditView, const ::svx::SpellPortions& rNewPortions, bool /*bIsGrammarChecking*/ ) +{ +#ifdef SVX_LIGHT +#else + DBG_ASSERT(pSpellInfo, "pSpellInfo not initialized"); + if(pSpellInfo) + { + UndoActionStart( EDITUNDO_INSERT ); + if(pSpellInfo->aLastSpellPortions.size() == rNewPortions.size()) + { + //the simple case: the same number of elements on both sides + //each changed element has to be applied to the corresponding source element + svx::SpellPortions::const_iterator aCurrentNewPortion = rNewPortions.end(); + svx::SpellPortions::const_iterator aCurrentOldPortion = pSpellInfo->aLastSpellPortions.end(); + SpellContentSelections::const_iterator aCurrentOldPosition = pSpellInfo->aLastSpellContentSelections.end(); + bool bSetToEnd = false; + do + { + --aCurrentNewPortion; + --aCurrentOldPortion; + --aCurrentOldPosition; + //set the cursor to the end of the sentence - necessary to + //resume there at the next step + if(!bSetToEnd) + { + bSetToEnd = true; + rEditView.pImpEditView->SetEditSelection( aCurrentOldPosition->Max() ); + } + + USHORT nScriptType = GetI18NScriptTypeOfLanguage( aCurrentNewPortion->eLanguage ); +// LanguageType eTextLanguage = GetLanguage( aCurrentOldPosition->Min() ); + + USHORT nLangWhichId = EE_CHAR_LANGUAGE; + switch(nScriptType) + { + case SCRIPTTYPE_ASIAN : nLangWhichId = EE_CHAR_LANGUAGE_CJK; break; + case SCRIPTTYPE_COMPLEX : nLangWhichId = EE_CHAR_LANGUAGE_CTL; break; + } + if(aCurrentNewPortion->sText != aCurrentOldPortion->sText) + { + //change text and apply language + SfxItemSet aSet( aEditDoc.GetItemPool(), nLangWhichId, nLangWhichId); + aSet.Put(SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId)); + SetAttribs( *aCurrentOldPosition, aSet ); + ImpInsertText( *aCurrentOldPosition, aCurrentNewPortion->sText ); + } + else if(aCurrentNewPortion->eLanguage != aCurrentOldPortion->eLanguage) + { + //apply language + SfxItemSet aSet( aEditDoc.GetItemPool(), nLangWhichId, nLangWhichId); + aSet.Put(SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId)); + SetAttribs( *aCurrentOldPosition, aSet ); + } + if(aCurrentNewPortion == rNewPortions.begin()) + break; + } + while(aCurrentNewPortion != rNewPortions.begin()); + } + else + { + //select the complete sentence + SpellContentSelections::const_iterator aCurrentEndPosition = pSpellInfo->aLastSpellContentSelections.end(); + --aCurrentEndPosition; + SpellContentSelections::const_iterator aCurrentStartPosition = pSpellInfo->aLastSpellContentSelections.begin(); + EditSelection aAllSentence(aCurrentStartPosition->Min(), aCurrentEndPosition->Max()); + + //delete the sentence completely + ImpDeleteSelection( aAllSentence ); + svx::SpellPortions::const_iterator aCurrentNewPortion = rNewPortions.begin(); + EditPaM aCurrentPaM = aAllSentence.Min(); + while(aCurrentNewPortion != rNewPortions.end()) + { + //set the language attribute + LanguageType eCurLanguage = GetLanguage( aCurrentPaM ); + if(eCurLanguage != aCurrentNewPortion->eLanguage) + { + USHORT nScriptType = GetI18NScriptTypeOfLanguage( aCurrentNewPortion->eLanguage ); + USHORT nLangWhichId = EE_CHAR_LANGUAGE; + switch(nScriptType) + { + case SCRIPTTYPE_ASIAN : nLangWhichId = EE_CHAR_LANGUAGE_CJK; break; + case SCRIPTTYPE_COMPLEX : nLangWhichId = EE_CHAR_LANGUAGE_CTL; break; + } + SfxItemSet aSet( aEditDoc.GetItemPool(), nLangWhichId, nLangWhichId); + aSet.Put(SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId)); + SetAttribs( aCurrentPaM, aSet ); + } + //insert the new string and set the cursor to the end of the inserted string + aCurrentPaM = ImpInsertText( aCurrentPaM , aCurrentNewPortion->sText ); + ++aCurrentNewPortion; + } + } + UndoActionEnd( EDITUNDO_INSERT ); + } + FormatAndUpdate(); + aEditDoc.SetModified(TRUE); +#endif +} +/*-- 08.09.2008 11:33:02--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void ImpEditEngine::PutSpellingToSentenceStart( EditView& rEditView ) +{ +#ifdef SVX_LIGHT +#else + if( pSpellInfo && pSpellInfo->aLastSpellContentSelections.size() ) + { + rEditView.pImpEditView->SetEditSelection( pSpellInfo->aLastSpellContentSelections.begin()->Min() ); + } + +#endif +} + + +void ImpEditEngine::DoOnlineSpelling( ContentNode* pThisNodeOnly, sal_Bool bSpellAtCursorPos, sal_Bool bInteruptable ) +{ +#ifndef SVX_LIGHT + /* + Er wird ueber alle Absaetze iteriert, nur Absaetze mit invalidierter + WrongList werden geprueft... + + Es werden alle Woerter im invalidierten Bereich geprueft. + Ist ein Wort falsch, aber noch nicht in der WrongList, oder umgekehrt, + wird der Bereich des Wortes invalidiert + ( kein Invalidate, sondern wenn nur Uebergaenge von richtig=>falsch, + einfaches Paint, bei Uebergaengen von falsch=>richtig mit VDev + ueberplaetten ) + */ + + if ( !xSpeller.is() ) + return; + + EditPaM aCursorPos; + if( pActiveView && !bSpellAtCursorPos ) + { + DBG_CHKOBJ( pActiveView, EditView, 0 ); + aCursorPos = pActiveView->pImpEditView->GetEditSelection().Max(); + } + sal_Bool bRestartTimer = sal_False; + + ContentNode* pLastNode = aEditDoc.SaveGetObject( aEditDoc.Count() - 1 ); + sal_uInt16 nNodes = GetEditDoc().Count(); + sal_uInt16 nInvalids = 0; + Sequence< PropertyValue > aEmptySeq; + for ( sal_uInt16 n = 0; n < nNodes; n++ ) + { + ContentNode* pNode = GetEditDoc().GetObject( n ); + if ( pThisNodeOnly ) + pNode = pThisNodeOnly; + + if ( pNode->GetWrongList()->IsInvalid() ) + { + WrongList* pWrongList = pNode->GetWrongList(); + sal_uInt16 nInvStart = pWrongList->GetInvalidStart(); + sal_uInt16 nInvEnd = pWrongList->GetInvalidEnd(); + + sal_uInt16 nWrongs = 0; // Auch im Absatz mal die Kontrolle abgeben... +// sal_Bool bStop = sal_False; + + sal_uInt16 nPaintFrom = 0xFFFF, nPaintTo = 0; + sal_Bool bSimpleRepaint = sal_True; + + pWrongList->SetValid(); + + EditPaM aPaM( pNode, nInvStart ); + EditSelection aSel( aPaM, aPaM ); + while ( ( aSel.Max().GetNode() == pNode ) /* && !bStop */ ) + { + if ( ( aSel.Min().GetIndex() > nInvEnd ) + || ( ( aSel.Max().GetNode() == pLastNode ) && ( aSel.Max().GetIndex() >= pLastNode->Len() ) ) ) + break; // Dokument- oder Ungueltigkeitsbereich-Ende + + aSel = SelectWord( aSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + String aWord( GetSelected( aSel ) ); + // Wenn Punkt dahinter, muss dieser mit uebergeben werden ! + // Falls Abkuerzung... + sal_Bool bDottAdded = sal_False; + if ( aSel.Max().GetIndex() < aSel.Max().GetNode()->Len() ) + { + sal_Unicode cNext = aSel.Max().GetNode()->GetChar( aSel.Max().GetIndex() ); + if ( cNext == '.' ) + { + aSel.Max().GetIndex()++; + aWord += cNext; + bDottAdded = sal_True; + } + } + + + sal_Bool bChanged = sal_False; + if ( aWord.Len() > 0 ) + { + sal_uInt16 nWStart = aSel.Min().GetIndex(); + sal_uInt16 nWEnd= aSel.Max().GetIndex(); + if ( !xSpeller->isValid( aWord, GetLanguage( EditPaM( aSel.Min().GetNode(), nWStart+1 ) ), aEmptySeq ) ) + { + // Pruefen, ob schon richtig markiert... + nWrongs++; + // Nur bei SimpleRepaint stoppen, sonst zu oft VDev + // if ( ( nWrongs > 8 ) && bSimpleRepaint ) + // { + // bStop = sal_True; + // pWrongList->MarkInvalid( aSel.Max().GetIndex(), nInvEnd ); + // } + sal_uInt16 nXEnd = bDottAdded ? nWEnd -1 : nWEnd; + if ( !pWrongList->HasWrong( nWStart, nXEnd ) ) + { + // Wort als falsch markieren... + // Aber nur, wenn nicht an Cursor-Position... + sal_Bool bCursorPos = sal_False; + if ( aCursorPos.GetNode() == pNode ) + { + if ( ( nWStart <= aCursorPos.GetIndex() ) && nWEnd >= aCursorPos.GetIndex() ) + bCursorPos = sal_True; + } + if ( bCursorPos ) + { + // Dann weiter als ungueltig markieren... + pWrongList->GetInvalidStart() = nWStart; + pWrongList->GetInvalidEnd() = nWEnd; + bRestartTimer = sal_True; + } + else + { + // Es kann sein, dass die Wrongs in der Liste nicht + // genau ueber Woerter aufgespannt sind, weil die + // WordDelimiters beim Expandieren nicht ausgewrtet werden. + pWrongList->InsertWrong( nWStart, nXEnd, sal_True ); + bChanged = sal_True; + } + } + } + else + { + // Pruefen, ob nicht als als falsch markiert.... + if ( pWrongList->HasAnyWrong( nWStart, nWEnd ) ) + { + pWrongList->ClearWrongs( nWStart, nWEnd, pNode ); + bSimpleRepaint = sal_False; + bChanged = sal_True; + } + } + if ( bChanged ) + { + if ( nPaintFrom == 0xFFFF ) + nPaintFrom = nWStart; + nPaintTo = nWEnd; + } + } + + EditPaM aLastEnd( aSel.Max() ); + aSel = WordRight( aSel.Max(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + if ( bChanged && ( aSel.Min().GetNode() == pNode ) && + ( ( aSel.Min().GetIndex()-aLastEnd.GetIndex() > 1 ) ) ) + { + // Wenn zwei Worte durch mehr Zeichen als ein Blank getrennt + // sind, kann es passieren, dass beim Aufsplitten eines Wrongs + // der Start den zweiten Wortes vor dem tatsaechlich Wort liegt + pWrongList->ClearWrongs( aLastEnd.GetIndex(), aSel.Min().GetIndex(), pNode ); + } + } + + // Invalidieren? + if ( ( nPaintFrom != 0xFFFF ) ) + { + aStatus.GetStatusWord() |= EE_STAT_WRONGWORDCHANGED; + CallStatusHdl(); + + if ( aEditViews.Count() ) + { + // Bei SimpleRepaint wuerde ein uebermalen ohne VDev reichen, + // aber dann muesste ich ueber alle Views, Intersecten, + // Clippen, ... + // Lohnt wahrscheinlich nicht. + EditPaM aStartPaM( pNode, nPaintFrom ); + EditPaM aEndPaM( pNode, nPaintTo ); + Rectangle aStartCursor( PaMtoEditCursor( aStartPaM ) ); + Rectangle aEndCursor( PaMtoEditCursor( aEndPaM ) ); + DBG_ASSERT( aInvalidRec.IsEmpty(), "InvalidRect gesetzt!" ); + aInvalidRec.Left() = 0; + aInvalidRec.Right() = GetPaperSize().Width(); + aInvalidRec.Top() = aStartCursor.Top(); + aInvalidRec.Bottom() = aEndCursor.Bottom(); + if ( pActiveView && pActiveView->HasSelection() ) + { + // Dann darf nicht ueber VDev ausgegeben werden + UpdateViews( NULL ); + } + else if ( bSimpleRepaint ) + { + for ( sal_uInt16 nView = 0; nView < aEditViews.Count(); nView++ ) + { + EditView* pView = aEditViews[nView]; + Rectangle aClipRec( aInvalidRec ); + aClipRec.Intersection( pView->GetVisArea() ); + if ( !aClipRec.IsEmpty() ) + { + // in Fensterkoordinaten umwandeln.... + aClipRec.SetPos( pView->pImpEditView->GetWindowPos( aClipRec.TopLeft() ) ); + // Wenn Selektion, dann VDev... + Paint( pView->pImpEditView, aClipRec, pView->HasSelection() ); + } + } + } + else + { + UpdateViews( pActiveView ); + } + aInvalidRec = Rectangle(); + } + } + // Nach zwei korrigierten Nodes die Kontrolle abgeben... + nInvalids++; + if ( bInteruptable && ( nInvalids >= 2 ) ) + { + bRestartTimer = sal_True; + break; + } + } + + if ( pThisNodeOnly ) + break; + } + if ( bRestartTimer ) + aOnlineSpellTimer.Start(); +#endif // !SVX_LIGHT +} + + +EESpellState ImpEditEngine::HasSpellErrors() +{ + DBG_ASSERT( xSpeller.is(), "Kein Speller gesetzt!" ); + +#ifndef SVX_LIGHT + ContentNode* pLastNode = aEditDoc.SaveGetObject( aEditDoc.Count() - 1 ); + EditSelection aCurSel( aEditDoc.GetStartPaM() ); + + String aWord; + Reference< XSpellAlternatives > xSpellAlt; + Sequence< PropertyValue > aEmptySeq; + while ( !xSpellAlt.is() ) + { + if ( ( aCurSel.Max().GetNode() == pLastNode ) && + ( aCurSel.Max().GetIndex() >= pLastNode->Len() ) ) + { + return EE_SPELL_OK; + } + + aCurSel = SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + aWord = GetSelected( aCurSel ); + if ( aWord.Len() > 0 ) + { + LanguageType eLang = GetLanguage( aCurSel.Max() ); + SvxSpellWrapper::CheckSpellLang( xSpeller, eLang ); + xSpellAlt = xSpeller->spell( aWord, eLang, aEmptySeq ); + } + aCurSel = WordRight( aCurSel.Max(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + } +#endif + + return EE_SPELL_ERRORFOUND; +} + +EESpellState ImpEditEngine::StartThesaurus( EditView* pEditView ) +{ +#ifndef SVX_LIGHT + EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() ); + if ( !aCurSel.HasRange() ) + aCurSel = SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + String aWord( GetSelected( aCurSel ) ); + + Reference< XThesaurus > xThes( SvxGetThesaurus() ); + if (!xThes.is()) + return EE_SPELL_ERRORFOUND; + + EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create(); + AbstractThesaurusDialog* pDlg = pFact->CreateThesaurusDialog( pEditView->GetWindow(), xThes, aWord, GetLanguage( aCurSel.Max() ) ); + if ( pDlg->Execute() == RET_OK ) + { + // Wort ersetzen... + pEditView->pImpEditView->DrawSelection(); + pEditView->pImpEditView->SetEditSelection( aCurSel ); + pEditView->pImpEditView->DrawSelection(); + pEditView->InsertText( pDlg->GetWord() ); + pEditView->ShowCursor( sal_True, sal_False ); + } + + delete pDlg; + return EE_SPELL_OK; +#else + return EE_SPELL_NOSPELLER; +#endif +} + +sal_uInt16 ImpEditEngine::StartSearchAndReplace( EditView* pEditView, const SvxSearchItem& rSearchItem ) +{ + sal_uInt16 nFound = 0; + +#ifndef SVX_LIGHT + EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() ); + + // FIND_ALL ohne Mehrfachselektion nicht moeglich. + if ( ( rSearchItem.GetCommand() == SVX_SEARCHCMD_FIND ) || + ( rSearchItem.GetCommand() == SVX_SEARCHCMD_FIND_ALL ) ) + { + if ( Search( rSearchItem, pEditView ) ) + nFound++; + } + else if ( rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE ) + { + // Das Wort ist selektiert, wenn der Anwender die Selektion + // nicht zwischendurch manipuliert: + if ( aCurSel.HasRange() ) + { + pEditView->InsertText( rSearchItem.GetReplaceString() ); + nFound = 1; + } + else + if( Search( rSearchItem, pEditView ) ) + nFound = 1; + } + else if ( rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE_ALL ) + { + // Der Writer ersetzt alle, vorn Anfang bis Ende... + SvxSearchItem aTmpItem( rSearchItem ); + aTmpItem.SetBackward( sal_False ); + + pEditView->pImpEditView->DrawSelection(); + + aCurSel.Adjust( aEditDoc ); + EditPaM aStartPaM = aTmpItem.GetSelection() ? aCurSel.Min() : aEditDoc.GetStartPaM(); + EditSelection aFoundSel( aCurSel.Max() ); + sal_Bool bFound = ImpSearch( aTmpItem, aCurSel, aStartPaM, aFoundSel ); + if ( bFound ) + UndoActionStart( EDITUNDO_REPLACEALL ); + while ( bFound ) + { + nFound++; + aStartPaM = ImpInsertText( aFoundSel, rSearchItem.GetReplaceString() ); + bFound = ImpSearch( aTmpItem, aCurSel, aStartPaM, aFoundSel ); + } + if ( nFound ) + { + EditPaM aNewPaM( aFoundSel.Max() ); + if ( aNewPaM.GetIndex() > aNewPaM.GetNode()->Len() ) + aNewPaM.GetIndex() = aNewPaM.GetNode()->Len(); + pEditView->pImpEditView->SetEditSelection( aNewPaM ); + FormatAndUpdate( pEditView ); + UndoActionEnd( EDITUNDO_REPLACEALL ); + } + else + { + pEditView->pImpEditView->DrawSelection(); + pEditView->ShowCursor( sal_True, sal_False ); + } + } +#endif // !SVX_LIGHT + return nFound; +} + +BOOL ImpEditEngine::Search( const SvxSearchItem& rSearchItem, EditView* pEditView ) +{ + EditSelection aSel( pEditView->pImpEditView->GetEditSelection() ); + aSel.Adjust( aEditDoc ); + EditPaM aStartPaM( aSel.Max() ); + if ( rSearchItem.GetSelection() && !rSearchItem.GetBackward() ) + aStartPaM = aSel.Min(); + + EditSelection aFoundSel; + BOOL bFound = ImpSearch( rSearchItem, aSel, aStartPaM, aFoundSel ); + if ( bFound && ( aFoundSel == aSel ) ) // Bei Rueckwaetssuche + { + aStartPaM = aSel.Min(); + bFound = ImpSearch( rSearchItem, aSel, aStartPaM, aFoundSel ); + } + + pEditView->pImpEditView->DrawSelection(); + if ( bFound ) + { + // Erstmal das Min einstellen, damit das ganze Wort in den sichtbaren Bereich kommt. + pEditView->pImpEditView->SetEditSelection( aFoundSel.Min() ); + pEditView->ShowCursor( TRUE, FALSE ); + pEditView->pImpEditView->SetEditSelection( aFoundSel ); + } + else + pEditView->pImpEditView->SetEditSelection( aSel.Max() ); + + pEditView->pImpEditView->DrawSelection(); + pEditView->ShowCursor( TRUE, FALSE ); + return bFound; +} + +sal_Bool ImpEditEngine::ImpSearch( const SvxSearchItem& rSearchItem, + const EditSelection& rSearchSelection, const EditPaM& rStartPos, EditSelection& rFoundSel ) +{ +#ifndef SVX_LIGHT + util::SearchOptions aSearchOptions( rSearchItem.GetSearchOptions() ); + aSearchOptions.Locale = GetLocale( rStartPos ); + + sal_Bool bBack = rSearchItem.GetBackward(); + sal_Bool bSearchInSelection = rSearchItem.GetSelection(); + sal_uInt16 nStartNode = aEditDoc.GetPos( rStartPos.GetNode() ); + sal_uInt16 nEndNode; + if ( bSearchInSelection ) + { + nEndNode = aEditDoc.GetPos( bBack ? rSearchSelection.Min().GetNode() : rSearchSelection.Max().GetNode() ); + } + else + { + nEndNode = bBack ? 0 : aEditDoc.Count()-1; + } + + utl::TextSearch aSearcher( aSearchOptions ); + + // ueber die Absaetze iterieren... + for ( sal_uInt16 nNode = nStartNode; + bBack ? ( nNode >= nEndNode ) : ( nNode <= nEndNode) ; + bBack ? nNode-- : nNode++ ) + { + // Bei rueckwaertsuche, wenn nEndNode = 0: + if ( nNode >= 0xFFFF ) + return sal_False; + + ContentNode* pNode = aEditDoc.GetObject( nNode ); + + sal_uInt16 nStartPos = 0; + sal_uInt16 nEndPos = pNode->Len(); + if ( nNode == nStartNode ) + { + if ( bBack ) + nEndPos = rStartPos.GetIndex(); + else + nStartPos = rStartPos.GetIndex(); + } + if ( ( nNode == nEndNode ) && bSearchInSelection ) + { + if ( bBack ) + nStartPos = rSearchSelection.Min().GetIndex(); + else + nEndPos = rSearchSelection.Max().GetIndex(); + } + + // Suchen... + XubString aParaStr( GetEditDoc().GetParaAsString( pNode ) ); + bool bFound = false; + if ( bBack ) + { + SwapUSHORTs( nStartPos, nEndPos ); + bFound = aSearcher.SearchBkwrd( aParaStr, &nStartPos, &nEndPos); + } + else + bFound = aSearcher.SearchFrwrd( aParaStr, &nStartPos, &nEndPos); + + if ( bFound ) + { + rFoundSel.Min().SetNode( pNode ); + rFoundSel.Min().SetIndex( nStartPos ); + rFoundSel.Max().SetNode( pNode ); + rFoundSel.Max().SetIndex( nEndPos ); + return sal_True; + } + } +#endif // !SVX_LIGHT + return sal_False; +} + +sal_Bool ImpEditEngine::HasText( const SvxSearchItem& rSearchItem ) +{ +#ifndef SVX_LIGHT + SvxSearchItem aTmpItem( rSearchItem ); + aTmpItem.SetBackward( sal_False ); + aTmpItem.SetSelection( sal_False ); + + EditPaM aStartPaM( aEditDoc.GetStartPaM() ); + EditSelection aDummySel( aStartPaM ); + EditSelection aFoundSel; + return ImpSearch( aTmpItem, aDummySel, aStartPaM, aFoundSel ); +#else + return sal_False; +#endif +} + +void ImpEditEngine::SetAutoCompleteText( const String& rStr, sal_Bool bClearTipWindow ) +{ +#ifndef SVX_LIGHT + aAutoCompleteText = rStr; + if ( bClearTipWindow && pActiveView ) + Help::ShowQuickHelp( pActiveView->GetWindow(), Rectangle(), String(), 0 ); +#endif // !SVX_LIGHT +} + +EditSelection ImpEditEngine::TransliterateText( const EditSelection& rSelection, sal_Int32 nTransliterationMode ) +{ + EditSelection aSel( rSelection ); + aSel.Adjust( aEditDoc ); + + if ( !aSel.HasRange() ) + aSel = SelectWord( aSel ); + + EditSelection aNewSel( aSel ); + + USHORT nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() ); + USHORT nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() ); + + BOOL bChanges = FALSE; + BOOL bLenChanged = FALSE; + EditUndoTransliteration* pUndo = NULL; + + utl::TransliterationWrapper aTranslitarationWrapper( ::comphelper::getProcessServiceFactory(), nTransliterationMode ); + BOOL bConsiderLanguage = aTranslitarationWrapper.needLanguageForTheMode(); + + for ( USHORT nNode = nStartNode; nNode <= nEndNode; nNode++ ) + { + ContentNode* pNode = aEditDoc.GetObject( nNode ); + xub_StrLen nStartPos = 0; + xub_StrLen nEndPos = pNode->Len(); + if ( nNode == nStartNode ) + nStartPos = aSel.Min().GetIndex(); + if ( nNode == nEndNode ) // kann auch == nStart sein! + nEndPos = aSel.Max().GetIndex(); + + USHORT nCurrentStart = nStartPos; + USHORT nCurrentEnd = nEndPos; + sal_uInt16 nLanguage = LANGUAGE_SYSTEM; + + do + { + if ( bConsiderLanguage ) + { + nLanguage = GetLanguage( EditPaM( pNode, nCurrentStart+1 ), &nCurrentEnd ); + if ( nCurrentEnd > nEndPos ) + nCurrentEnd = nEndPos; + } + + xub_StrLen nLen = nCurrentEnd - nCurrentStart; + + Sequence <sal_Int32> aOffsets; + String aNewText( aTranslitarationWrapper.transliterate( *pNode, nLanguage, nCurrentStart, nLen, &aOffsets ) ); + + if( ( nLen != aNewText.Len() ) || !pNode->Equals( aNewText, nCurrentStart, nLen ) ) + { + bChanges = TRUE; + if ( nLen != aNewText.Len() ) + bLenChanged = TRUE; + +#ifndef SVX_LIGHT + // Create UndoAction on Demand.... + if ( !pUndo && IsUndoEnabled() && !IsInUndo() ) + { + ESelection aESel( CreateESel( aSel ) ); + pUndo = new EditUndoTransliteration( this, aESel, nTransliterationMode ); + + if ( ( nStartNode == nEndNode ) && !aSel.Min().GetNode()->GetCharAttribs().HasAttrib( aSel.Min().GetIndex(), aSel.Max().GetIndex() ) ) + pUndo->SetText( aSel.Min().GetNode()->Copy( aSel.Min().GetIndex(), aSel.Max().GetIndex()-aSel.Min().GetIndex() ) ); + else + pUndo->SetText( CreateBinTextObject( aSel, NULL ) ); + } +#endif + + // Change text without loosing the attributes + USHORT nCharsAfterTransliteration = + sal::static_int_cast< USHORT >(aOffsets.getLength()); + const sal_Int32* pOffsets = aOffsets.getConstArray(); + short nDiffs = 0; + for ( USHORT n = 0; n < nCharsAfterTransliteration; n++ ) + { + USHORT nCurrentPos = nCurrentStart+n; + sal_Int32 nDiff = (nCurrentPos-nDiffs) - pOffsets[n]; + + if ( !nDiff ) + { + DBG_ASSERT( nCurrentPos < pNode->Len(), "TransliterateText - String smaller than expected!" ); + pNode->SetChar( nCurrentPos, aNewText.GetChar(n) ); + } + else if ( nDiff < 0 ) + { + // Replace first char, delete the rest... + DBG_ASSERT( nCurrentPos < pNode->Len(), "TransliterateText - String smaller than expected!" ); + pNode->SetChar( nCurrentPos, aNewText.GetChar(n) ); + + DBG_ASSERT( (nCurrentPos+1) < pNode->Len(), "TransliterateText - String smaller than expected!" ); + GetEditDoc().RemoveChars( EditPaM( pNode, nCurrentPos+1 ), sal::static_int_cast< USHORT >(-nDiff) ); + } + else + { + DBG_ASSERT( nDiff == 1, "TransliterateText - Diff other than expected! But should work..." ); + GetEditDoc().InsertText( EditPaM( pNode, nCurrentPos ), aNewText.GetChar(n) ); + + } + nDiffs = sal::static_int_cast< short >(nDiffs + nDiff); + } + + if ( nNode == nEndNode ) + aNewSel.Max().GetIndex() = + aNewSel.Max().GetIndex() + nDiffs; + + ParaPortion* pParaPortion = GetParaPortions()[nNode]; + pParaPortion->MarkSelectionInvalid( nCurrentStart, std::max< USHORT >( nCurrentStart+nLen, nCurrentStart+aNewText.Len() ) ); + + } + nCurrentStart = nCurrentEnd; + } while( nCurrentEnd < nEndPos ); + } + +#ifndef SVX_LIGHT + if ( pUndo ) + { + ESelection aESel( CreateESel( aNewSel ) ); + pUndo->SetNewSelection( aESel ); + InsertUndo( pUndo ); + } +#endif + + if ( bChanges ) + { + TextModified(); + SetModifyFlag( sal_True ); + if ( bLenChanged ) + UpdateSelections(); + FormatAndUpdate(); + } + + return aNewSel; +} + +void ImpEditEngine::SetAsianCompressionMode( USHORT n ) +{ + if ( n != nAsianCompressionMode ) + { + nAsianCompressionMode = n; + if ( ImplHasText() ) + { + FormatFullDoc(); + UpdateViews(); + } + } +} + +void ImpEditEngine::SetKernAsianPunctuation( BOOL b ) +{ + if ( b != bKernAsianPunctuation ) + { + bKernAsianPunctuation = b; + if ( ImplHasText() ) + { + FormatFullDoc(); + UpdateViews(); + } + } +} + +void ImpEditEngine::SetAddExtLeading( BOOL bExtLeading ) +{ + if ( IsAddExtLeading() != bExtLeading ) + { + bAddExtLeading = bExtLeading; + if ( ImplHasText() ) + { + FormatFullDoc(); + UpdateViews(); + } + } +}; + + + +BOOL ImpEditEngine::ImplHasText() const +{ + return ( ( GetEditDoc().Count() > 1 ) || GetEditDoc().GetObject(0)->Len() ); +} + +long ImpEditEngine::LogicToTwips( long n ) +{ + Size aSz( n, 0 ); + MapMode aTwipsMode( MAP_TWIP ); + aSz = pRefDev->LogicToLogic( aSz, NULL, &aTwipsMode ); + return aSz.Width(); +} + + |