/************************************************************************* * * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: splwrap.cxx,v $ * * $Revision: 1.15 $ * * last change: $Author: hr $ $Date: 2007-06-27 17:39:28 $ * * The Contents of this file are made available subject to * the terms of GNU Lesser General Public License Version 2.1. * * * GNU Lesser General Public License Version 2.1 * ============================================= * Copyright 2005 by Sun Microsystems, Inc. * 901 San Antonio Road, Palo Alto, CA 94303, USA * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software Foundation. * * This library 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 for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_svx.hxx" #ifndef _RTL_USTRING_HXX_ #include #endif #ifndef _SHL_HXX #include #endif #ifndef _SV_WRKWIN_HXX #include #endif #ifndef _SV_SVAPP_HXX #include #endif #ifndef _SV_MSGBOX_HXX #include #endif #ifndef _TOOLS_DEBUG_HXX //autogen wg. DBG_ASSERT #include #endif #define _SVSTDARR_USHORTS #define _SVSTDARR_USHORTSSORT #ifndef _SVARRAY_HXX #include #endif #ifndef __RSC #include #endif #ifndef _SVXERR_HXX #include #endif #ifndef _SVX_DLGUTIL_HXX #include #endif #ifndef _UNO_LINGU_HXX #include #endif #ifndef _SFX_SFXUNO_HXX #include #endif #ifndef _LINGUISTIC_LNGPROPS_HHX_ #include #endif #ifndef _COM_SUN_STAR_FRAME_XSTORABLE_HPP_ #include #endif #ifndef _COM_SUN_STAR_LINGUISTIC2_XDICTIONARY1_HPP_ #include #endif #include #include "hyphen.hxx" // Der HyphenDialog #include // Der Wrapper #include // ThesaurusDlg #include #include //#define WAIT_ON() pWin->EnterWait() //#define WAIT_OFF() pWin->LeaveWait() #define WAIT_ON() if(pWin != NULL) { pWin->EnterWait(); } #define WAIT_OFF() if(pWin != NULL) { pWin->LeaveWait(); } using namespace ::com::sun::star; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::beans; using namespace ::com::sun::star::linguistic2; // misc functions --------------------------------------------- void SvxPrepareAutoCorrect( String &rOldText, String &rNewText ) { // This function should be used to strip (or add) trailing '.' from // the strings before passing them on to the autocorrect function in // order that the autocorrect function will hopefully // works properly with normal words and abbreviations (with trailing '.') // independ of if they are at the end of the sentence or not. // // rOldText: text to be replaced // rNewText: replacement text xub_StrLen nOldLen = rOldText.Len(), nNewLen = rNewText.Len(); if (nOldLen && nNewLen) { sal_Bool bOldHasDot = sal_Unicode( '.' ) == rOldText.GetChar( nOldLen - 1 ), bNewHasDot = sal_Unicode( '.' ) == rNewText.GetChar( nNewLen - 1 ); if (bOldHasDot && !bNewHasDot /*this is: !(bOldHasDot && bNewHasDot) && bOldHasDot*/) rOldText.Erase( nOldLen - 1 ); } } // ----------------------------------------------------------------------- #define SVX_LANG_NEED_CHECK 0 #define SVX_LANG_OK 1 #define SVX_LANG_MISSING 2 #define SVX_LANG_MISSING_DO_WARN 3 #define SVX_FLAGS_NEW class LangCheckState { SvUShortsSort aLang; SvUShorts aState; // lowerbyte spell values, // higherbyte hyph values public: LangCheckState(); USHORT GetCount() { return aLang.Count(); } inline USHORT GetLanguagePos( USHORT nLang ); inline USHORT GetLanguage( USHORT nPos ); inline USHORT GetState( USHORT nPos ); inline void SetState( USHORT nPos, USHORT nState ); inline USHORT InsertLangState( USHORT nLang, USHORT nState ); }; LangCheckState::LangCheckState() : aLang (16, 16), aState (16, 16) { } inline USHORT LangCheckState::GetLanguagePos( USHORT nLang ) { USHORT nPos; BOOL bFound = aLang.Seek_Entry( nLang, &nPos ); return bFound ? nPos : 0xFFFF; } inline USHORT LangCheckState::GetLanguage( USHORT nPos ) { DBG_ASSERT( nPos < aLang.Count(), "index out of range" ); return aLang.GetObject( nPos ); } inline USHORT LangCheckState::GetState( USHORT nPos ) { DBG_ASSERT( nPos < aState.Count(), "index out of range" ); return aState.GetObject( nPos ); } inline void LangCheckState::SetState( USHORT nPos, USHORT nState ) { DBG_ASSERT( nPos < aState.Count(), "index out of range" ); aState.Replace( nState , nPos ); } inline USHORT LangCheckState::InsertLangState( USHORT nLang, USHORT nState ) { DBG_ASSERT( aLang.Count() == aState.Count(), "array length mismatch" ); USHORT nPos = aLang.Count(); aLang .Insert( nLang, nPos ); aState.Insert( nState , nPos ); return nPos; } static LangCheckState & GetLangCheckState() { static LangCheckState aState; return aState; } void SvxSpellWrapper::ShowLanguageErrors() { // display message boxes for languages not available for // spellchecking or hyphenation LangCheckState &rLCS = GetLangCheckState(); sal_uInt16 nCount = rLCS.GetCount(); for (sal_uInt16 i = 0; i < nCount; ++i) { sal_Int16 nLang = (sal_Int16) rLCS.GetLanguage( i ); sal_uInt16 nVal = rLCS.GetState( i ); sal_uInt16 nTmpSpell = nVal & 0x00FF; sal_uInt16 nTmpHyph = (nVal >> 8) & 0x00FF; if (SVX_LANG_MISSING_DO_WARN == nTmpSpell) { String aErr( ::GetLanguageString( nLang ) ); ErrorHandler::HandleError( *new StringErrorInfo( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS, aErr ) ); nTmpSpell = SVX_LANG_MISSING; } if (SVX_LANG_MISSING_DO_WARN == nTmpHyph) { String aErr( ::GetLanguageString( nLang ) ); ErrorHandler::HandleError( *new StringErrorInfo( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS, aErr ) ); nTmpHyph = SVX_LANG_MISSING; } rLCS.SetState( i, (nTmpHyph << 8) | nTmpSpell ); } } SvxSpellWrapper::~SvxSpellWrapper() { } /*-------------------------------------------------------------------- * Beschreibung: Ctor, die Pruefreihenfolge wird festgelegt * * !bStart && !bOtherCntnt: BODY_END, BODY_START, OTHER * !bStart && bOtherCntnt: OTHER, BODY * bStart && !bOtherCntnt: BODY_END, OTHER * bStart && bOtherCntnt: OTHER * --------------------------------------------------------------------*/ SvxSpellWrapper::SvxSpellWrapper( Window* pWn, Reference< XSpellChecker1 > &xSpellChecker, const sal_Bool bStart, const sal_Bool bIsAllRight, const sal_Bool bOther, const sal_Bool bRevAllow ) : pWin ( pWn ), xSpell ( xSpellChecker ), bOtherCntnt ( bOther ), bDialog ( sal_False ), bHyphen ( sal_False ), bAuto ( sal_False ), bStartChk ( bOther ), bRevAllowed ( bRevAllow ) { Reference< beans::XPropertySet > xProp( SvxGetLinguPropertySet() ); sal_Bool bWrapReverse = xProp.is() ? *(sal_Bool*)xProp->getPropertyValue( ::rtl::OUString::createFromAscii(UPN_IS_WRAP_REVERSE) ).getValue() : sal_False; bReverse = bRevAllow && bWrapReverse; bAllRight = bIsAllRight; bStartDone = bOther || ( !bReverse && bStart ); bEndDone = bReverse && bStart && !bOther; } // ----------------------------------------------------------------------- SvxSpellWrapper::SvxSpellWrapper( Window* pWn, Reference< XHyphenator > &xHyphenator, const sal_Bool bStart, const sal_Bool bOther ) : pWin ( pWn ), xHyph ( xHyphenator ), bOtherCntnt ( bOther ), bDialog ( sal_False ), bHyphen ( sal_False ), bAuto ( sal_False ), bReverse ( sal_False ), bStartDone ( bOther || ( !bReverse && bStart ) ), bEndDone ( bReverse && bStart && !bOther ), bStartChk ( bOther ), bRevAllowed ( sal_False ) { } // ----------------------------------------------------------------------- sal_Int16 SvxSpellWrapper::CheckSpellLang( Reference< XSpellChecker1 > xSpell, sal_Int16 nLang) { LangCheckState &rLCS = GetLangCheckState(); USHORT nPos = rLCS.GetLanguagePos( nLang ); sal_uInt16 nVal = 0xFFFF != nPos ? rLCS.GetState( nPos ) : 0; if (0xFFFF == nPos) nPos = rLCS.InsertLangState( (sal_uInt16) nLang, nVal ); if (SVX_LANG_NEED_CHECK == (nVal & 0x00FF)) { sal_uInt16 nTmpVal = SVX_LANG_MISSING_DO_WARN; if (xSpell.is() && xSpell->hasLanguage( nLang )) nTmpVal = SVX_LANG_OK; nVal &= 0xFF00; nVal |= nTmpVal; rLCS.SetState( nPos, nVal ); } return (sal_Int16) nVal; } sal_Int16 SvxSpellWrapper::CheckHyphLang( Reference< XHyphenator > xHyph, sal_Int16 nLang) { LangCheckState &rLCS = GetLangCheckState(); USHORT nPos = rLCS.GetLanguagePos( nLang ); sal_uInt16 nVal = 0xFFFF != nPos ? rLCS.GetState( nPos ) : 0; if (0xFFFF == nPos) nPos = rLCS.InsertLangState( (sal_uInt16) nLang, nVal ); if (SVX_LANG_NEED_CHECK == ((nVal >> 8) & 0x00FF)) { sal_uInt16 nTmpVal = SVX_LANG_MISSING_DO_WARN; if (xHyph.is() && xHyph->hasLocale( SvxCreateLocale( nLang ) )) nTmpVal = SVX_LANG_OK; nVal &= 0x00FF; nVal |= nTmpVal << 8; rLCS.SetState( nPos, nVal ); } return (sal_Int16) nVal; } // ----------------------------------------------------------------------- void SvxSpellWrapper::SpellStart( SvxSpellArea /*eSpell*/ ) { // Hier muessen die notwendigen Vorbereitungen fuer SpellContinue } // im uebergebenen Bereich getroffen werden. // ----------------------------------------------------------------------- sal_Bool SvxSpellWrapper::HasOtherCnt() { return sal_False; // Gibt es ueberhaupt einen Sonderbereich? } // ----------------------------------------------------------------------- sal_Bool SvxSpellWrapper::SpellMore() { return sal_False; // Sollen weitere Dokumente geprueft werden? } // ----------------------------------------------------------------------- void SvxSpellWrapper::SpellEnd() { // Bereich ist abgeschlossen, ggf. Aufraeumen // display error for last language not found ShowLanguageErrors(); } // ----------------------------------------------------------------------- sal_Bool SvxSpellWrapper::SpellContinue() { return sal_False; } // ----------------------------------------------------------------------- void SvxSpellWrapper::AutoCorrect( const String&, const String& ) { } // ----------------------------------------------------------------------- void SvxSpellWrapper::ScrollArea() { // Scrollarea einstellen } // ----------------------------------------------------------------------- void SvxSpellWrapper::ChangeWord( const String&, const sal_uInt16 ) { // Wort ersetzen } // ----------------------------------------------------------------------- String SvxSpellWrapper::GetThesWord() { // Welches Wort soll nachgeschlagen werden? return String(); } // ----------------------------------------------------------------------- void SvxSpellWrapper::ChangeThesWord( const String& ) { // Wort wg. Thesaurus ersetzen } // ----------------------------------------------------------------------- void SvxSpellWrapper::StartThesaurus( const String &rWord, sal_uInt16 nLanguage ) { String sErr( SVX_RES( RID_SVXSTR_HMERR_THESAURUS ) ); Reference< XThesaurus > xThes( SvxGetThesaurus() ); if (!xThes.is()) { InfoBox( pWin, sErr ).Execute(); return; } WAIT_ON(); // while looking up for initial word SvxThesaurusDialog aDlg(pWin, xThes, rWord, nLanguage); WAIT_OFF(); if ( aDlg.Execute()== RET_OK ) { ChangeThesWord( aDlg.GetWord() ); } } // ----------------------------------------------------------------------- void SvxSpellWrapper::ReplaceAll( const String &, sal_Int16 ) { // Wort aus der Replace-Liste ersetzen } // ----------------------------------------------------------------------- void SvxSpellWrapper::SetLanguage( const sal_uInt16 ) { // Sprache aendern } // ----------------------------------------------------------------------- void SvxSpellWrapper::InsertHyphen( const sal_uInt16 ) { // Hyphen einfuegen bzw. loeschen } // ----------------------------------------------------------------------- // Pruefung der Dokumentbereiche in der durch die Flags angegebenen Reihenfolge void SvxSpellWrapper::SpellDocument( ) { if ( bOtherCntnt ) { bReverse = sal_False; SpellStart( SVX_SPELL_OTHER ); } else { bStartChk = bReverse; SpellStart( bReverse ? SVX_SPELL_BODY_START : SVX_SPELL_BODY_END ); } if ( FindSpellError() ) { Reference< XSpellAlternatives > xAlt( GetLast(), UNO_QUERY ); Reference< XHyphenatedWord > xHyphWord( GetLast(), UNO_QUERY ); Window *pOld = pWin; bDialog = sal_True; if (xHyphWord.is()) { DBG_ASSERT(xHyphWord.is(), "NULL pointer"); SvxHyphenWordDialog* pDlg = new SvxHyphenWordDialog( xHyphWord->getWord(), SvxLocaleToLanguage( xHyphWord->getLocale() ), pWin, xHyph, this ); pWin = pDlg; pDlg->Execute(); delete pDlg; } bDialog = sal_False; pWin = pOld; }; } // ----------------------------------------------------------------------- // Naechsten Bereich auswaehlen sal_Bool SvxSpellWrapper::SpellNext( ) { Reference< beans::XPropertySet > xProp( SvxGetLinguPropertySet() ); sal_Bool bWrapReverse = xProp.is() ? *(sal_Bool*)xProp->getPropertyValue( ::rtl::OUString::createFromAscii(UPN_IS_WRAP_REVERSE) ).getValue() : sal_False; sal_Bool bActRev = bRevAllowed && bWrapReverse; // bActRev ist die Richtung nach dem Spellen, bReverse die am Anfang. if( bActRev == bReverse ) { // Keine Richtungsaenderung, also ist if( bStartChk ) // der gewuenschte Bereich ( bStartChk ) bStartDone = sal_True; // vollstaendig abgearbeitet. else bEndDone = sal_True; } else if( bReverse == bStartChk ) // Bei einer Richtungsaenderung kann { // u.U. auch ein Bereich abgearbeitet sein. if( bStartChk ) // Sollte der vordere Teil rueckwaerts gespellt bEndDone = sal_True; // werden und wir kehren unterwegs um, so ist else // der hintere Teil abgearbeitet (und umgekehrt). bStartDone = sal_True; } bReverse = bActRev; if( bOtherCntnt && bStartDone && bEndDone ) // Dokument komplett geprueft? { if ( SpellMore() ) // ein weiteres Dokument pruefen? { bOtherCntnt = sal_False; bStartDone = !bReverse; bEndDone = bReverse; SpellStart( SVX_SPELL_BODY ); return sal_True; } return sal_False; } ResMgr& rMgr = DIALOG_MGR(); sal_Bool bGoOn = sal_False; if ( bOtherCntnt ) { bStartChk = sal_False; SpellStart( SVX_SPELL_BODY ); bGoOn = sal_True; } else if ( bStartDone && bEndDone ) { sal_Bool bIsSpellSpecial = xProp.is() ? *(sal_Bool*)xProp->getPropertyValue( ::rtl::OUString::createFromAscii(UPN_IS_SPELL_SPECIAL) ).getValue() : sal_False; // Bodybereich erledigt, Frage nach Sonderbereich if( !IsHyphen() && bIsSpellSpecial && HasOtherCnt() ) { SpellStart( SVX_SPELL_OTHER ); bOtherCntnt = bGoOn = sal_True; } else if ( SpellMore() ) // ein weiteres Dokument pruefen? { bOtherCntnt = sal_False; bStartDone = !bReverse; bEndDone = bReverse; SpellStart( SVX_SPELL_BODY ); return sal_True; } } else { // Ein BODY_Bereich erledigt, Frage nach dem anderen BODY_Bereich WAIT_OFF(); // Sobald im Dialog das DontWrapAround gesetzt werden kann, kann der // folgende #ifdef-Zweig aktiviert werden ... #ifdef USED sal_Bool bDontWrapAround = IsHyphen() ? pSpell->GetOptions() & DONT_WRAPAROUND : pSpell->GetHyphOptions() & HYPH_DONT_WRAPAROUND; if( bDontWrapAround ) #else sal_uInt16 nResId = bReverse ? RID_SVXQB_BW_CONTINUE : RID_SVXQB_CONTINUE; QueryBox aBox( pWin, ResId( nResId, rMgr ) ); if ( aBox.Execute() != RET_YES ) #endif { // Verzicht auf den anderen Bereich, ggf. Frage nach Sonderbereich WAIT_ON(); bStartDone = bEndDone = sal_True; return SpellNext(); } else { bStartChk = !bStartDone; SpellStart( bStartChk ? SVX_SPELL_BODY_START : SVX_SPELL_BODY_END ); bGoOn = sal_True; } WAIT_ON(); } return bGoOn; } // ----------------------------------------------------------------------- Reference< XDictionary1 > SvxSpellWrapper::GetAllRightDic() const { Reference< XDictionary1 > xDic; Reference< XDictionaryList > xDicList( SvxGetDictionaryList() ); if (xDicList.is()) { Sequence< Reference< XDictionary > > aDics( xDicList->getDictionaries() ); const Reference< XDictionary > *pDic = aDics.getConstArray(); sal_Int32 nCount = aDics.getLength(); sal_Int32 i = 0; while (!xDic.is() && i < nCount) { Reference< XDictionary1 > xTmp( pDic[i], UNO_QUERY ); if (xTmp.is()) { if ( xTmp->isActive() && xTmp->getDictionaryType() != DictionaryType_NEGATIVE && xTmp->getLanguage() == LANGUAGE_NONE ) { Reference< frame::XStorable > xStor( xTmp, UNO_QUERY ); if (xStor.is() && xStor->hasLocation() && !xStor->isReadonly()) { xDic = xTmp; } } } ++i; } if (!xDic.is()) { xDic = SvxGetOrCreatePosDic( xDicList ); if (xDic.is()) xDic->setActive( sal_True ); } } return xDic; } // ----------------------------------------------------------------------- sal_Bool SvxSpellWrapper::FindSpellError() { ShowLanguageErrors(); Reference< XInterface > xRef; WAIT_ON(); sal_Bool bSpell = sal_True; Reference< XDictionary1 > xAllRightDic; if (IsAllRight()) xAllRightDic = GetAllRightDic(); while ( bSpell ) { SpellContinue(); Reference< XSpellAlternatives > xAlt( GetLast(), UNO_QUERY ); Reference< XHyphenatedWord > xHyphWord( GetLast(), UNO_QUERY ); if (xAlt.is()) { if (IsAllRight() && xAllRightDic.is()) { xAllRightDic->add( xAlt->getWord(), sal_False, ::rtl::OUString() ); } else { // look up in ChangeAllList for misspelled word Reference< XDictionary1 > xChangeAllList( SvxGetChangeAllList(), UNO_QUERY ); Reference< XDictionaryEntry > xEntry; if (xChangeAllList.is()) xEntry = xChangeAllList->getEntry( xAlt->getWord() ); if (xEntry.is()) { // replace word without asking ReplaceAll( xEntry->getReplacementText(), SvxLocaleToLanguage( xAlt->getLocale() ) ); } else bSpell = sal_False; } } else if (xHyphWord.is()) bSpell = sal_False; else { SpellEnd(); bSpell = SpellNext(); } } WAIT_OFF(); return GetLast().is(); }