| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_editeng.hxx" |
| #include<rtl/ustring.hxx> |
| #include <tools/shl.hxx> |
| #include <vcl/wrkwin.hxx> |
| #include <vcl/svapp.hxx> |
| #include <vcl/msgbox.hxx> |
| #include <tools/debug.hxx> |
| #include <svtools/langtab.hxx> |
| |
| #ifndef __RSC |
| #include <tools/errinf.hxx> |
| #endif |
| #include <editeng/unolingu.hxx> |
| #include <linguistic/lngprops.hxx> |
| #include <com/sun/star/frame/XStorable.hpp> |
| |
| #include <map> |
| |
| #include <editeng/svxenum.hxx> |
| #include <editeng/splwrap.hxx> // Der Wrapper |
| #include <editeng/edtdlg.hxx> |
| #include <editeng/eerdll.hxx> |
| #include <editeng/editrids.hrc> |
| #include <editeng/editids.hrc> |
| #include <editeng/editerr.hxx> |
| |
| #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 |
| |
| |
| struct lt_LanguageType |
| { |
| bool operator()( LanguageType n1, LanguageType n2 ) const |
| { |
| return n1 < n2; |
| } |
| }; |
| |
| typedef std::map< LanguageType, sal_uInt16, lt_LanguageType > LangCheckState_map_t; |
| |
| static LangCheckState_map_t & GetLangCheckState() |
| { |
| static LangCheckState_map_t aLangCheckState; |
| return aLangCheckState; |
| } |
| |
| void SvxSpellWrapper::ShowLanguageErrors() |
| { |
| // display message boxes for languages not available for |
| // spellchecking or hyphenation |
| LangCheckState_map_t &rLCS = GetLangCheckState(); |
| LangCheckState_map_t::iterator aIt( rLCS.begin() ); |
| while (aIt != rLCS.end()) |
| { |
| LanguageType nLang = aIt->first; |
| sal_uInt16 nVal = aIt->second; |
| sal_uInt16 nTmpSpell = nVal & 0x00FF; |
| sal_uInt16 nTmpHyph = (nVal >> 8) & 0x00FF; |
| |
| if (SVX_LANG_MISSING_DO_WARN == nTmpSpell) |
| { |
| String aErr( SvtLanguageTable::GetLanguageString( nLang ) ); |
| ErrorHandler::HandleError( |
| *new StringErrorInfo( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS, aErr ) ); |
| nTmpSpell = SVX_LANG_MISSING; |
| } |
| if (SVX_LANG_MISSING_DO_WARN == nTmpHyph) |
| { |
| String aErr( SvtLanguageTable::GetLanguageString( nLang ) ); |
| ErrorHandler::HandleError( |
| *new StringErrorInfo( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS, aErr ) ); |
| nTmpHyph = SVX_LANG_MISSING; |
| } |
| |
| rLCS[ nLang ] = (nTmpHyph << 8) | nTmpSpell; |
| ++aIt; |
| } |
| |
| } |
| |
| 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 ), |
| mpTextObj( NULL), |
| bAllRight ( bIsAllRight ) |
| { |
| 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; |
| 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 ), |
| mpTextObj( NULL), |
| bAllRight ( sal_True ) |
| { |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| sal_Int16 SvxSpellWrapper::CheckSpellLang( |
| Reference< XSpellChecker1 > xSpell, sal_Int16 nLang) |
| { |
| LangCheckState_map_t &rLCS = GetLangCheckState(); |
| |
| LangCheckState_map_t::iterator aIt( rLCS.find( nLang ) ); |
| sal_uInt16 nVal = aIt == rLCS.end() ? SVX_LANG_NEED_CHECK : aIt->second; |
| |
| if (aIt == rLCS.end()) |
| rLCS[ 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[ nLang ] = nVal; |
| } |
| |
| return (sal_Int16) nVal; |
| } |
| |
| sal_Int16 SvxSpellWrapper::CheckHyphLang( |
| Reference< XHyphenator > xHyph, sal_Int16 nLang) |
| { |
| LangCheckState_map_t &rLCS = GetLangCheckState(); |
| |
| LangCheckState_map_t::iterator aIt( rLCS.find( nLang ) ); |
| sal_uInt16 nVal = aIt == rLCS.end() ? 0 : aIt->second; |
| |
| if (aIt == rLCS.end()) |
| rLCS[ 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[ nLang ] = 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 ) |
| { |
| Reference< XThesaurus > xThes( SvxGetThesaurus() ); |
| if (!xThes.is()) |
| { |
| InfoBox( pWin, EE_RESSTR( RID_SVXSTR_HMERR_THESAURUS ) ).Execute(); |
| return; |
| } |
| |
| WAIT_ON(); // while looking up for initial word |
| EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create(); |
| AbstractThesaurusDialog* pDlg = pFact->CreateThesaurusDialog( pWin, xThes, rWord, nLanguage ); |
| WAIT_OFF(); |
| if ( pDlg->Execute()== RET_OK ) |
| { |
| ChangeThesWord( pDlg->GetWord() ); |
| } |
| delete pDlg; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| 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()) |
| { |
| EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create(); |
| AbstractHyphenWordDialog* pDlg = pFact->CreateHyphenWordDialog( pWin, |
| xHyphWord->getWord(), |
| SvxLocaleToLanguage( xHyphWord->getLocale() ), |
| xHyph, this ); |
| pWin = pDlg->GetWindow(); |
| 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; |
| } |
| |
| 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, EditResId( nResId ) ); |
| 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< XDictionary > SvxSpellWrapper::GetAllRightDic() const |
| { |
| Reference< XDictionary > 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< XDictionary > xTmp( pDic[i], UNO_QUERY ); |
| if (xTmp.is()) |
| { |
| if ( xTmp->isActive() && |
| xTmp->getDictionaryType() != DictionaryType_NEGATIVE && |
| SvxLocaleToLanguage( xTmp->getLocale() ) == 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< XDictionary > 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< XDictionary > 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(); |
| } |
| |
| |
| |