bump product version to 5.0.4.1
[LibreOffice.git] / editeng / source / misc / splwrap.cxx
blobc5a81952fe38d4cc4ee898659f05820ee5eb33e5
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <rtl/ustring.hxx>
21 #include <vcl/wrkwin.hxx>
22 #include <vcl/svapp.hxx>
23 #include <vcl/layout.hxx>
24 #include <svtools/langtab.hxx>
26 #include <tools/errinf.hxx>
27 #include <editeng/unolingu.hxx>
28 #include <linguistic/lngprops.hxx>
29 #include <com/sun/star/frame/XStorable.hpp>
31 #include <map>
33 #include <editeng/svxenum.hxx>
34 #include <editeng/splwrap.hxx>
35 #include <editeng/edtdlg.hxx>
36 #include <editeng/eerdll.hxx>
37 #include <editeng/editrids.hrc>
38 #include <editeng/editids.hrc>
39 #include <editeng/editerr.hxx>
40 #include <boost/scoped_ptr.hpp>
42 #define WAIT_ON() if(pWin != nullptr) { pWin->EnterWait(); }
44 #define WAIT_OFF() if(pWin != nullptr) { pWin->LeaveWait(); }
46 using namespace ::com::sun::star;
47 using namespace ::com::sun::star::uno;
48 using namespace ::com::sun::star::beans;
49 using namespace ::com::sun::star::linguistic2;
52 // misc functions ---------------------------------------------
54 void SvxPrepareAutoCorrect( OUString &rOldText, const OUString &rNewText )
56 // This function should be used to strip (or add) trailing '.' from
57 // the strings before passing them on to the autocorrect function in
58 // order that the autocorrect function will hopefully
59 // works properly with normal words and abbreviations (with trailing '.')
60 // independ of if they are at the end of the sentence or not.
62 // rOldText: text to be replaced
63 // rNewText: replacement text
65 sal_Int32 nOldLen = rOldText.getLength();
66 sal_Int32 nNewLen = rNewText.getLength();
67 if (nOldLen && nNewLen)
69 bool bOldHasDot = '.' == rOldText[ nOldLen - 1 ],
70 bNewHasDot = '.' == rNewText[ nNewLen - 1 ];
71 if (bOldHasDot && !bNewHasDot
72 /*this is: !(bOldHasDot && bNewHasDot) && bOldHasDot*/)
73 rOldText = rOldText.copy( 0, nOldLen - 1 );
77 #define SVX_LANG_NEED_CHECK 0
78 #define SVX_LANG_OK 1
79 #define SVX_LANG_MISSING 2
80 #define SVX_LANG_MISSING_DO_WARN 3
82 struct lt_LanguageType
84 bool operator()( LanguageType n1, LanguageType n2 ) const
86 return n1 < n2;
90 typedef std::map< LanguageType, sal_uInt16, lt_LanguageType > LangCheckState_map_t;
92 static LangCheckState_map_t & GetLangCheckState()
94 static LangCheckState_map_t aLangCheckState;
95 return aLangCheckState;
98 void SvxSpellWrapper::ShowLanguageErrors()
100 // display message boxes for languages not available for
101 // spellchecking or hyphenation
102 LangCheckState_map_t &rLCS = GetLangCheckState();
103 LangCheckState_map_t::iterator aIt( rLCS.begin() );
104 while (aIt != rLCS.end())
106 LanguageType nLang = aIt->first;
107 sal_uInt16 nVal = aIt->second;
108 sal_uInt16 nTmpSpell = nVal & 0x00FF;
109 sal_uInt16 nTmpHyph = (nVal >> 8) & 0x00FF;
111 if (SVX_LANG_MISSING_DO_WARN == nTmpSpell)
113 OUString aErr( SvtLanguageTable::GetLanguageString( nLang ) );
114 ErrorHandler::HandleError(
115 *new StringErrorInfo( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS, aErr ) );
116 nTmpSpell = SVX_LANG_MISSING;
118 if (SVX_LANG_MISSING_DO_WARN == nTmpHyph)
120 OUString aErr( SvtLanguageTable::GetLanguageString( nLang ) );
121 ErrorHandler::HandleError(
122 *new StringErrorInfo( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS, aErr ) );
123 nTmpHyph = SVX_LANG_MISSING;
126 rLCS[ nLang ] = (nTmpHyph << 8) | nTmpSpell;
127 ++aIt;
132 SvxSpellWrapper::~SvxSpellWrapper()
136 /*--------------------------------------------------------------------
137 * Description: Constructor, the test sequence is determined
139 * !bStart && !bOtherCntnt: BODY_END, BODY_START, OTHER
140 * !bStart && bOtherCntnt: OTHER, BODY
141 * bStart && !bOtherCntnt: BODY_END, OTHER
142 * bStart && bOtherCntnt: OTHER
144 --------------------------------------------------------------------*/
146 SvxSpellWrapper::SvxSpellWrapper( vcl::Window* pWn,
147 Reference< XSpellChecker1 > &xSpellChecker,
148 const bool bStart, const bool bIsAllRight,
149 const bool bOther, const bool bRevAllow ) :
151 pWin ( pWn ),
152 xSpell ( xSpellChecker ),
153 mpTextObj( NULL),
154 bOtherCntnt ( bOther ),
155 bDialog ( false ),
156 bHyphen ( false ),
157 bAuto ( false ),
158 bStartChk ( bOther ),
159 bRevAllowed ( bRevAllow ),
160 bAllRight ( bIsAllRight )
162 Reference< linguistic2::XLinguProperties > xProp( SvxGetLinguPropertySet() );
163 bool bWrapReverse = xProp.is() && xProp->getIsWrapReverse();
164 bReverse = bRevAllow && bWrapReverse;
165 bStartDone = bOther || ( !bReverse && bStart );
166 bEndDone = bReverse && bStart && !bOther;
171 SvxSpellWrapper::SvxSpellWrapper( vcl::Window* pWn,
172 Reference< XHyphenator > &xHyphenator,
173 const bool bStart, const bool bOther ) :
174 pWin ( pWn ),
175 xHyph ( xHyphenator ),
176 mpTextObj( NULL),
177 bOtherCntnt ( bOther ),
178 bDialog ( false ),
179 bHyphen ( false ),
180 bAuto ( false ),
181 bReverse ( false ),
182 bStartDone ( bOther || ( !bReverse && bStart ) ),
183 bEndDone ( bReverse && bStart && !bOther ),
184 bStartChk ( bOther ),
185 bRevAllowed ( false ),
186 bAllRight ( true )
192 sal_Int16 SvxSpellWrapper::CheckSpellLang(
193 Reference< XSpellChecker1 > xSpell, sal_Int16 nLang)
195 LangCheckState_map_t &rLCS = GetLangCheckState();
197 LangCheckState_map_t::iterator aIt( rLCS.find( nLang ) );
198 sal_uInt16 nVal = aIt == rLCS.end() ? SVX_LANG_NEED_CHECK : aIt->second;
200 if (aIt == rLCS.end())
201 rLCS[ nLang ] = nVal;
203 if (SVX_LANG_NEED_CHECK == (nVal & 0x00FF))
205 sal_uInt16 nTmpVal = SVX_LANG_MISSING_DO_WARN;
206 if (xSpell.is() && xSpell->hasLanguage( nLang ))
207 nTmpVal = SVX_LANG_OK;
208 nVal &= 0xFF00;
209 nVal |= nTmpVal;
211 rLCS[ nLang ] = nVal;
214 return (sal_Int16) nVal;
217 sal_Int16 SvxSpellWrapper::CheckHyphLang(
218 Reference< XHyphenator > xHyph, sal_Int16 nLang)
220 LangCheckState_map_t &rLCS = GetLangCheckState();
222 LangCheckState_map_t::iterator aIt( rLCS.find( nLang ) );
223 sal_uInt16 nVal = aIt == rLCS.end() ? 0 : aIt->second;
225 if (aIt == rLCS.end())
226 rLCS[ nLang ] = nVal;
228 if (SVX_LANG_NEED_CHECK == ((nVal >> 8) & 0x00FF))
230 sal_uInt16 nTmpVal = SVX_LANG_MISSING_DO_WARN;
231 if (xHyph.is() && xHyph->hasLocale( LanguageTag::convertToLocale( nLang ) ))
232 nTmpVal = SVX_LANG_OK;
233 nVal &= 0x00FF;
234 nVal |= nTmpVal << 8;
236 rLCS[ nLang ] = nVal;
239 return (sal_Int16) nVal;
245 void SvxSpellWrapper::SpellStart( SvxSpellArea /*eSpell*/ )
246 { // Here, the necessary preparations be made for SpellContinue in the
247 } // given area.
252 bool SvxSpellWrapper::HasOtherCnt()
254 return false; // Is there a special area?
260 bool SvxSpellWrapper::SpellMore()
262 return false; // Should additional documents be examined?
268 void SvxSpellWrapper::SpellEnd()
269 { // Area is complete, tidy up if necessary
271 // display error for last language not found
272 ShowLanguageErrors();
275 bool SvxSpellWrapper::SpellContinue()
277 return false;
280 void SvxSpellWrapper::AutoCorrect( const OUString&, const OUString& )
284 void SvxSpellWrapper::ScrollArea()
285 { // Set Scroll area
288 void SvxSpellWrapper::ChangeWord( const OUString&, const sal_uInt16 )
289 { // Insert Word
292 void SvxSpellWrapper::ChangeThesWord( const OUString& )
294 // replace word due to Thesaurus.
297 void SvxSpellWrapper::ReplaceAll( const OUString &, sal_Int16 )
298 { // Replace Word from the Replace list
301 void SvxSpellWrapper::InsertHyphen( const sal_uInt16 )
302 { // inserting and deleting Hyphae
305 // Testing of the document areas in the order specified by the flags
306 void SvxSpellWrapper::SpellDocument( )
308 if ( bOtherCntnt )
310 bReverse = false;
311 SpellStart( SVX_SPELL_OTHER );
313 else
315 bStartChk = bReverse;
316 SpellStart( bReverse ? SVX_SPELL_BODY_START : SVX_SPELL_BODY_END );
319 if ( FindSpellError() )
321 Reference< XSpellAlternatives > xAlt( GetLast(), UNO_QUERY );
322 Reference< XHyphenatedWord > xHyphWord( GetLast(), UNO_QUERY );
324 vcl::Window *pOld = pWin;
325 bDialog = true;
326 if (xHyphWord.is())
328 EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create();
329 boost::scoped_ptr<AbstractHyphenWordDialog> pDlg(pFact->CreateHyphenWordDialog( pWin,
330 xHyphWord->getWord(),
331 LanguageTag( xHyphWord->getLocale() ).getLanguageType(),
332 xHyph, this ));
333 pWin = pDlg->GetWindow();
334 pDlg->Execute();
336 bDialog = false;
337 pWin = pOld;
342 // Select the next area
345 bool SvxSpellWrapper::SpellNext( )
347 Reference< linguistic2::XLinguProperties > xProp( SvxGetLinguPropertySet() );
348 bool bWrapReverse = xProp.is() && xProp->getIsWrapReverse();
349 bool bActRev = bRevAllowed && bWrapReverse;
351 // bActRev is the direction after Spell checking, bReverse is the one
352 // at the beginning.
353 if( bActRev == bReverse )
354 { // No change of direction, thus is the
355 if( bStartChk ) // desired area ( bStartChk )
356 bStartDone = true; // completely processed.
357 else
358 bEndDone = true;
360 else if( bReverse == bStartChk ) //For a change of direction, an area can
361 { // be processed during certain circumstances
362 if( bStartChk ) // If the firdt part is spell checked in backwards
363 bEndDone = true; // and this is reversed in the process, then
364 else // then the end part is processed (and vice-versa).
365 bStartDone = true;
368 bReverse = bActRev;
369 if( bOtherCntnt && bStartDone && bEndDone ) // Document has been fully checked?
371 if ( SpellMore() ) // spell check another document?
373 bOtherCntnt = false;
374 bStartDone = !bReverse;
375 bEndDone = bReverse;
376 SpellStart( SVX_SPELL_BODY );
377 return true;
379 return false;
382 bool bGoOn = false;
384 if ( bOtherCntnt )
386 bStartChk = false;
387 SpellStart( SVX_SPELL_BODY );
388 bGoOn = true;
390 else if ( bStartDone && bEndDone )
392 bool bIsSpellSpecial = xProp.is() && xProp->getIsSpellSpecial();
393 // Body area done, ask for special area
394 if( !IsHyphen() && bIsSpellSpecial && HasOtherCnt() )
396 SpellStart( SVX_SPELL_OTHER );
397 bOtherCntnt = bGoOn = true;
399 else if ( SpellMore() ) // check another document?
401 bOtherCntnt = false;
402 bStartDone = !bReverse;
403 bEndDone = bReverse;
404 SpellStart( SVX_SPELL_BODY );
405 return true;
408 else
410 // a BODY_area done, ask for the other BODY_area
411 WAIT_OFF();
413 sal_uInt16 nResId = bReverse ? RID_SVXSTR_QUERY_BW_CONTINUE : RID_SVXSTR_QUERY_CONTINUE;
414 ScopedVclPtrInstance< MessageDialog > aBox(pWin, EditResId(nResId), VCL_MESSAGE_QUESTION, VCL_BUTTONS_YES_NO);
415 if ( aBox->Execute() != RET_YES )
417 // sacrifice the other area if necessary ask for special area
418 WAIT_ON();
419 bStartDone = bEndDone = true;
420 return SpellNext();
422 else
424 bStartChk = !bStartDone;
425 SpellStart( bStartChk ? SVX_SPELL_BODY_START : SVX_SPELL_BODY_END );
426 bGoOn = true;
428 WAIT_ON();
430 return bGoOn;
435 Reference< XDictionary > SvxSpellWrapper::GetAllRightDic()
437 Reference< XDictionary > xDic;
439 Reference< XSearchableDictionaryList > xDicList( SvxGetDictionaryList() );
440 if (xDicList.is())
442 Sequence< Reference< XDictionary > > aDics( xDicList->getDictionaries() );
443 const Reference< XDictionary > *pDic = aDics.getConstArray();
444 sal_Int32 nCount = aDics.getLength();
446 sal_Int32 i = 0;
447 while (!xDic.is() && i < nCount)
449 Reference< XDictionary > xTmp( pDic[i], UNO_QUERY );
450 if (xTmp.is())
452 if ( xTmp->isActive() &&
453 xTmp->getDictionaryType() != DictionaryType_NEGATIVE &&
454 LanguageTag( xTmp->getLocale() ).getLanguageType() == LANGUAGE_NONE )
456 Reference< frame::XStorable > xStor( xTmp, UNO_QUERY );
457 if (xStor.is() && xStor->hasLocation() && !xStor->isReadonly())
459 xDic = xTmp;
463 ++i;
466 if (!xDic.is())
468 xDic = SvxGetOrCreatePosDic( xDicList );
469 if (xDic.is())
470 xDic->setActive( sal_True );
474 return xDic;
479 bool SvxSpellWrapper::FindSpellError()
481 ShowLanguageErrors();
483 Reference< XInterface > xRef;
485 WAIT_ON();
486 bool bSpell = true;
488 Reference< XDictionary > xAllRightDic;
489 if (IsAllRight())
490 xAllRightDic = GetAllRightDic();
492 while ( bSpell )
494 SpellContinue();
496 Reference< XSpellAlternatives > xAlt( GetLast(), UNO_QUERY );
497 Reference< XHyphenatedWord > xHyphWord( GetLast(), UNO_QUERY );
499 if (xAlt.is())
501 if (IsAllRight() && xAllRightDic.is())
503 xAllRightDic->add( xAlt->getWord(), sal_False, OUString() );
505 else
507 // look up in ChangeAllList for misspelled word
508 Reference< XDictionary > xChangeAllList(
509 SvxGetChangeAllList(), UNO_QUERY );
510 Reference< XDictionaryEntry > xEntry;
511 if (xChangeAllList.is())
512 xEntry = xChangeAllList->getEntry( xAlt->getWord() );
514 if (xEntry.is())
516 // replace word without asking
517 ReplaceAll( xEntry->getReplacementText(),
518 LanguageTag( xAlt->getLocale() ).getLanguageType() );
520 else
521 bSpell = false;
524 else if (xHyphWord.is())
525 bSpell = false;
526 else
528 SpellEnd();
529 bSpell = SpellNext();
532 WAIT_OFF();
533 return GetLast().is();
538 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */