bump product version to 4.1.6.2
[LibreOffice.git] / editeng / source / misc / splwrap.cxx
blob318998405c704e1dc4a277a4cc621e898a18cf77
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 <tools/shl.hxx>
22 #include <vcl/wrkwin.hxx>
23 #include <vcl/svapp.hxx>
24 #include <vcl/msgbox.hxx>
25 #include <svtools/langtab.hxx>
27 #ifndef __RSC
28 #include <tools/errinf.hxx>
29 #endif
30 #include <editeng/unolingu.hxx>
31 #include <linguistic/lngprops.hxx>
32 #include <com/sun/star/frame/XStorable.hpp>
34 #include <map>
36 #include <editeng/svxenum.hxx>
37 #include <editeng/splwrap.hxx>
38 #include <editeng/edtdlg.hxx>
39 #include <editeng/eerdll.hxx>
40 #include <editeng/editrids.hrc>
41 #include <editeng/editids.hrc>
42 #include <editeng/editerr.hxx>
44 #define WAIT_ON() if(pWin != NULL) { pWin->EnterWait(); }
46 #define WAIT_OFF() if(pWin != NULL) { pWin->LeaveWait(); }
48 using namespace ::com::sun::star;
49 using namespace ::com::sun::star::uno;
50 using namespace ::com::sun::star::beans;
51 using namespace ::com::sun::star::linguistic2;
54 // misc functions ---------------------------------------------
56 void SvxPrepareAutoCorrect( String &rOldText, String &rNewText )
58 // This function should be used to strip (or add) trailing '.' from
59 // the strings before passing them on to the autocorrect function in
60 // order that the autocorrect function will hopefully
61 // works properly with normal words and abbreviations (with trailing '.')
62 // independ of if they are at the end of the sentence or not.
64 // rOldText: text to be replaced
65 // rNewText: replacement text
67 xub_StrLen nOldLen = rOldText.Len(),
68 nNewLen = rNewText.Len();
69 if (nOldLen && nNewLen)
71 sal_Bool bOldHasDot = sal_Unicode( '.' ) == rOldText.GetChar( nOldLen - 1 ),
72 bNewHasDot = sal_Unicode( '.' ) == rNewText.GetChar( nNewLen - 1 );
73 if (bOldHasDot && !bNewHasDot
74 /*this is: !(bOldHasDot && bNewHasDot) && bOldHasDot*/)
75 rOldText.Erase( nOldLen - 1 );
79 #define SVX_LANG_NEED_CHECK 0
80 #define SVX_LANG_OK 1
81 #define SVX_LANG_MISSING 2
82 #define SVX_LANG_MISSING_DO_WARN 3
84 struct lt_LanguageType
86 bool operator()( LanguageType n1, LanguageType n2 ) const
88 return n1 < n2;
92 typedef std::map< LanguageType, sal_uInt16, lt_LanguageType > LangCheckState_map_t;
94 static LangCheckState_map_t & GetLangCheckState()
96 static LangCheckState_map_t aLangCheckState;
97 return aLangCheckState;
100 void SvxSpellWrapper::ShowLanguageErrors()
102 // display message boxes for languages not available for
103 // spellchecking or hyphenation
104 LangCheckState_map_t &rLCS = GetLangCheckState();
105 LangCheckState_map_t::iterator aIt( rLCS.begin() );
106 while (aIt != rLCS.end())
108 LanguageType nLang = aIt->first;
109 sal_uInt16 nVal = aIt->second;
110 sal_uInt16 nTmpSpell = nVal & 0x00FF;
111 sal_uInt16 nTmpHyph = (nVal >> 8) & 0x00FF;
113 if (SVX_LANG_MISSING_DO_WARN == nTmpSpell)
115 String aErr( SvtLanguageTable::GetLanguageString( nLang ) );
116 ErrorHandler::HandleError(
117 *new StringErrorInfo( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS, aErr ) );
118 nTmpSpell = SVX_LANG_MISSING;
120 if (SVX_LANG_MISSING_DO_WARN == nTmpHyph)
122 String aErr( SvtLanguageTable::GetLanguageString( nLang ) );
123 ErrorHandler::HandleError(
124 *new StringErrorInfo( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS, aErr ) );
125 nTmpHyph = SVX_LANG_MISSING;
128 rLCS[ nLang ] = (nTmpHyph << 8) | nTmpSpell;
129 ++aIt;
134 SvxSpellWrapper::~SvxSpellWrapper()
138 /*--------------------------------------------------------------------
139 * Description: Constructor, the test sequence is determined
141 * !bStart && !bOtherCntnt: BODY_END, BODY_START, OTHER
142 * !bStart && bOtherCntnt: OTHER, BODY
143 * bStart && !bOtherCntnt: BODY_END, OTHER
144 * bStart && bOtherCntnt: OTHER
146 --------------------------------------------------------------------*/
148 SvxSpellWrapper::SvxSpellWrapper( Window* pWn,
149 Reference< XSpellChecker1 > &xSpellChecker,
150 const sal_Bool bStart, const sal_Bool bIsAllRight,
151 const sal_Bool bOther, const sal_Bool bRevAllow ) :
153 pWin ( pWn ),
154 xSpell ( xSpellChecker ),
155 bOtherCntnt ( bOther ),
156 bDialog ( sal_False ),
157 bHyphen ( sal_False ),
158 bAuto ( sal_False ),
159 bStartChk ( bOther ),
160 bRevAllowed ( bRevAllow ),
161 bAllRight ( bIsAllRight )
163 Reference< linguistic2::XLinguProperties > xProp( SvxGetLinguPropertySet() );
164 sal_Bool bWrapReverse = xProp.is() ? xProp->getIsWrapReverse() : sal_False;
165 bReverse = bRevAllow && bWrapReverse;
166 bStartDone = bOther || ( !bReverse && bStart );
167 bEndDone = bReverse && bStart && !bOther;
170 // -----------------------------------------------------------------------
172 SvxSpellWrapper::SvxSpellWrapper( Window* pWn,
173 Reference< XHyphenator > &xHyphenator,
174 const sal_Bool bStart, const sal_Bool bOther ) :
175 pWin ( pWn ),
176 xHyph ( xHyphenator ),
177 bOtherCntnt ( bOther ),
178 bDialog ( sal_False ),
179 bHyphen ( sal_False ),
180 bAuto ( sal_False ),
181 bReverse ( sal_False ),
182 bStartDone ( bOther || ( !bReverse && bStart ) ),
183 bEndDone ( bReverse && bStart && !bOther ),
184 bStartChk ( bOther ),
185 bRevAllowed ( sal_False ),
186 bAllRight ( sal_True )
190 // -----------------------------------------------------------------------
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( nLang ).getLocale() ))
232 nTmpVal = SVX_LANG_OK;
233 nVal &= 0x00FF;
234 nVal |= nTmpVal << 8;
236 rLCS[ nLang ] = nVal;
239 return (sal_Int16) nVal;
242 // -----------------------------------------------------------------------
245 void SvxSpellWrapper::SpellStart( SvxSpellArea /*eSpell*/ )
246 { // Here, the necessary preparations be made for SpellContinue in the
247 } // given area.
249 // -----------------------------------------------------------------------
252 sal_Bool SvxSpellWrapper::HasOtherCnt()
254 return sal_False; // Is there a special area?
257 // -----------------------------------------------------------------------
260 sal_Bool SvxSpellWrapper::SpellMore()
262 return sal_False; // Should additional documents be examined?
265 // -----------------------------------------------------------------------
268 void SvxSpellWrapper::SpellEnd()
269 { // Area is complete, tidy up if necessary
271 // display error for last language not found
272 ShowLanguageErrors();
275 // -----------------------------------------------------------------------
278 sal_Bool SvxSpellWrapper::SpellContinue()
280 return sal_False;
283 // -----------------------------------------------------------------------
285 void SvxSpellWrapper::AutoCorrect( const String&, const String& )
289 // -----------------------------------------------------------------------
292 void SvxSpellWrapper::ScrollArea()
293 { // Set Scroll area
296 // -----------------------------------------------------------------------
299 void SvxSpellWrapper::ChangeWord( const String&, const sal_uInt16 )
300 { // Insert Word
303 // -----------------------------------------------------------------------
306 void SvxSpellWrapper::ChangeThesWord( const String& )
308 // replace word due to Thesaurus.
311 // -----------------------------------------------------------------------
313 void SvxSpellWrapper::StartThesaurus( const String &rWord, sal_uInt16 nLanguage )
315 Reference< XThesaurus > xThes( SvxGetThesaurus() );
316 if (!xThes.is())
318 InfoBox( pWin, EE_RESSTR( RID_SVXSTR_HMERR_THESAURUS ) ).Execute();
319 return;
322 WAIT_ON(); // while looking up for initial word
323 EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create();
324 AbstractThesaurusDialog* pDlg = pFact->CreateThesaurusDialog( pWin, xThes, rWord, nLanguage );
325 WAIT_OFF();
326 if ( pDlg->Execute()== RET_OK )
328 ChangeThesWord( pDlg->GetWord() );
330 delete pDlg;
333 // -----------------------------------------------------------------------
335 void SvxSpellWrapper::ReplaceAll( const String &, sal_Int16 )
336 { // Replace Word from the Replace list
339 // -----------------------------------------------------------------------
342 void SvxSpellWrapper::SetLanguage( const sal_uInt16 )
343 { // Set Language
346 // -----------------------------------------------------------------------
349 void SvxSpellWrapper::InsertHyphen( const sal_uInt16 )
350 { // inserting and deleting Hyphae
353 // -----------------------------------------------------------------------
354 // Testing of the document areas in the order specified by the flags
357 void SvxSpellWrapper::SpellDocument( )
359 if ( bOtherCntnt )
361 bReverse = sal_False;
362 SpellStart( SVX_SPELL_OTHER );
364 else
366 bStartChk = bReverse;
367 SpellStart( bReverse ? SVX_SPELL_BODY_START : SVX_SPELL_BODY_END );
370 if ( FindSpellError() )
372 Reference< XSpellAlternatives > xAlt( GetLast(), UNO_QUERY );
373 Reference< XHyphenatedWord > xHyphWord( GetLast(), UNO_QUERY );
375 Window *pOld = pWin;
376 bDialog = sal_True;
377 if (xHyphWord.is())
379 EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create();
380 AbstractHyphenWordDialog* pDlg = pFact->CreateHyphenWordDialog( pWin,
381 xHyphWord->getWord(),
382 LanguageTag( xHyphWord->getLocale() ).getLanguageType(),
383 xHyph, this );
384 pWin = pDlg->GetWindow();
385 pDlg->Execute();
386 delete pDlg;
388 bDialog = sal_False;
389 pWin = pOld;
393 // -----------------------------------------------------------------------
394 // Select the next area
397 sal_Bool SvxSpellWrapper::SpellNext( )
399 Reference< linguistic2::XLinguProperties > xProp( SvxGetLinguPropertySet() );
400 sal_Bool bWrapReverse = xProp.is() ? xProp->getIsWrapReverse() : sal_False;
401 sal_Bool bActRev = bRevAllowed && bWrapReverse;
403 // bActRev is the direction after Spell checking, bReverse is the one
404 // at the beginning.
405 if( bActRev == bReverse )
406 { // No change of direction, thus is the
407 if( bStartChk ) // desired area ( bStartChk )
408 bStartDone = sal_True; // completely processed.
409 else
410 bEndDone = sal_True;
412 else if( bReverse == bStartChk ) //For a change of direction, an area can
413 { // be processed during certain circumstances
414 if( bStartChk ) // If the firdt part is spell checked in backwards
415 bEndDone = sal_True; // and this is reversed in the process, then
416 else // then the end part is processed (and vice-versa).
417 bStartDone = sal_True;
420 bReverse = bActRev;
421 if( bOtherCntnt && bStartDone && bEndDone ) // Document has been fully checked?
423 if ( SpellMore() ) // spell check another document?
425 bOtherCntnt = sal_False;
426 bStartDone = !bReverse;
427 bEndDone = bReverse;
428 SpellStart( SVX_SPELL_BODY );
429 return sal_True;
431 return sal_False;
434 sal_Bool bGoOn = sal_False;
436 if ( bOtherCntnt )
438 bStartChk = sal_False;
439 SpellStart( SVX_SPELL_BODY );
440 bGoOn = sal_True;
442 else if ( bStartDone && bEndDone )
444 sal_Bool bIsSpellSpecial = xProp.is() ? xProp->getIsSpellSpecial() : sal_False;
445 // Body area done, ask for special area
446 if( !IsHyphen() && bIsSpellSpecial && HasOtherCnt() )
448 SpellStart( SVX_SPELL_OTHER );
449 bOtherCntnt = bGoOn = sal_True;
451 else if ( SpellMore() ) // check another document?
453 bOtherCntnt = sal_False;
454 bStartDone = !bReverse;
455 bEndDone = bReverse;
456 SpellStart( SVX_SPELL_BODY );
457 return sal_True;
460 else
462 // a BODY_area done, ask for the other BODY_area
463 WAIT_OFF();
465 sal_uInt16 nResId = bReverse ? RID_SVXQB_BW_CONTINUE : RID_SVXQB_CONTINUE;
466 QueryBox aBox( pWin, EditResId( nResId ) );
467 if ( aBox.Execute() != RET_YES )
469 // sacrifice the other area if necessary ask for special area
470 WAIT_ON();
471 bStartDone = bEndDone = sal_True;
472 return SpellNext();
474 else
476 bStartChk = !bStartDone;
477 SpellStart( bStartChk ? SVX_SPELL_BODY_START : SVX_SPELL_BODY_END );
478 bGoOn = sal_True;
480 WAIT_ON();
482 return bGoOn;
485 // -----------------------------------------------------------------------
487 Reference< XDictionary > SvxSpellWrapper::GetAllRightDic() const
489 Reference< XDictionary > xDic;
491 Reference< XSearchableDictionaryList > xDicList( SvxGetDictionaryList() );
492 if (xDicList.is())
494 Sequence< Reference< XDictionary > > aDics( xDicList->getDictionaries() );
495 const Reference< XDictionary > *pDic = aDics.getConstArray();
496 sal_Int32 nCount = aDics.getLength();
498 sal_Int32 i = 0;
499 while (!xDic.is() && i < nCount)
501 Reference< XDictionary > xTmp( pDic[i], UNO_QUERY );
502 if (xTmp.is())
504 if ( xTmp->isActive() &&
505 xTmp->getDictionaryType() != DictionaryType_NEGATIVE &&
506 LanguageTag( xTmp->getLocale() ).getLanguageType() == LANGUAGE_NONE )
508 Reference< frame::XStorable > xStor( xTmp, UNO_QUERY );
509 if (xStor.is() && xStor->hasLocation() && !xStor->isReadonly())
511 xDic = xTmp;
515 ++i;
518 if (!xDic.is())
520 xDic = SvxGetOrCreatePosDic( xDicList );
521 if (xDic.is())
522 xDic->setActive( sal_True );
526 return xDic;
529 // -----------------------------------------------------------------------
531 sal_Bool SvxSpellWrapper::FindSpellError()
533 ShowLanguageErrors();
535 Reference< XInterface > xRef;
537 WAIT_ON();
538 sal_Bool bSpell = sal_True;
540 Reference< XDictionary > xAllRightDic;
541 if (IsAllRight())
542 xAllRightDic = GetAllRightDic();
544 while ( bSpell )
546 SpellContinue();
548 Reference< XSpellAlternatives > xAlt( GetLast(), UNO_QUERY );
549 Reference< XHyphenatedWord > xHyphWord( GetLast(), UNO_QUERY );
551 if (xAlt.is())
553 if (IsAllRight() && xAllRightDic.is())
555 xAllRightDic->add( xAlt->getWord(), sal_False, OUString() );
557 else
559 // look up in ChangeAllList for misspelled word
560 Reference< XDictionary > xChangeAllList(
561 SvxGetChangeAllList(), UNO_QUERY );
562 Reference< XDictionaryEntry > xEntry;
563 if (xChangeAllList.is())
564 xEntry = xChangeAllList->getEntry( xAlt->getWord() );
566 if (xEntry.is())
568 // replace word without asking
569 ReplaceAll( xEntry->getReplacementText(),
570 LanguageTag( xAlt->getLocale() ).getLanguageType() );
572 else
573 bSpell = sal_False;
576 else if (xHyphWord.is())
577 bSpell = sal_False;
578 else
580 SpellEnd();
581 bSpell = SpellNext();
584 WAIT_OFF();
585 return GetLast().is();
590 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */