Bump for 3.6-28
[LibreOffice.git] / editeng / source / misc / splwrap.cxx
blobd564006ce90ff5b0bdc1150d00506e7486051425
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
29 #include<rtl/ustring.hxx>
30 #include <tools/shl.hxx>
31 #include <vcl/wrkwin.hxx>
32 #include <vcl/svapp.hxx>
33 #include <vcl/msgbox.hxx>
34 #include <svtools/langtab.hxx>
36 #ifndef __RSC
37 #include <tools/errinf.hxx>
38 #endif
39 #include <editeng/unolingu.hxx>
40 #include <linguistic/lngprops.hxx>
41 #include <com/sun/star/frame/XStorable.hpp>
43 #include <map>
45 #include <editeng/svxenum.hxx>
46 #include <editeng/splwrap.hxx>
47 #include <editeng/edtdlg.hxx>
48 #include <editeng/eerdll.hxx>
49 #include <editeng/editrids.hrc>
50 #include <editeng/editids.hrc>
51 #include <editeng/editerr.hxx>
53 #define WAIT_ON() if(pWin != NULL) { pWin->EnterWait(); }
55 #define WAIT_OFF() if(pWin != NULL) { pWin->LeaveWait(); }
57 using namespace ::com::sun::star;
58 using namespace ::com::sun::star::uno;
59 using namespace ::com::sun::star::beans;
60 using namespace ::com::sun::star::linguistic2;
63 // misc functions ---------------------------------------------
65 void SvxPrepareAutoCorrect( String &rOldText, String &rNewText )
67 // This function should be used to strip (or add) trailing '.' from
68 // the strings before passing them on to the autocorrect function in
69 // order that the autocorrect function will hopefully
70 // works properly with normal words and abbreviations (with trailing '.')
71 // independ of if they are at the end of the sentence or not.
73 // rOldText: text to be replaced
74 // rNewText: replacement text
76 xub_StrLen nOldLen = rOldText.Len(),
77 nNewLen = rNewText.Len();
78 if (nOldLen && nNewLen)
80 sal_Bool bOldHasDot = sal_Unicode( '.' ) == rOldText.GetChar( nOldLen - 1 ),
81 bNewHasDot = sal_Unicode( '.' ) == rNewText.GetChar( nNewLen - 1 );
82 if (bOldHasDot && !bNewHasDot
83 /*this is: !(bOldHasDot && bNewHasDot) && bOldHasDot*/)
84 rOldText.Erase( nOldLen - 1 );
88 #define SVX_LANG_NEED_CHECK 0
89 #define SVX_LANG_OK 1
90 #define SVX_LANG_MISSING 2
91 #define SVX_LANG_MISSING_DO_WARN 3
93 #define SVX_FLAGS_NEW
96 struct lt_LanguageType
98 bool operator()( LanguageType n1, LanguageType n2 ) const
100 return n1 < n2;
104 typedef std::map< LanguageType, sal_uInt16, lt_LanguageType > LangCheckState_map_t;
106 static LangCheckState_map_t & GetLangCheckState()
108 static LangCheckState_map_t aLangCheckState;
109 return aLangCheckState;
112 void SvxSpellWrapper::ShowLanguageErrors()
114 // display message boxes for languages not available for
115 // spellchecking or hyphenation
116 LangCheckState_map_t &rLCS = GetLangCheckState();
117 LangCheckState_map_t::iterator aIt( rLCS.begin() );
118 while (aIt != rLCS.end())
120 LanguageType nLang = aIt->first;
121 sal_uInt16 nVal = aIt->second;
122 sal_uInt16 nTmpSpell = nVal & 0x00FF;
123 sal_uInt16 nTmpHyph = (nVal >> 8) & 0x00FF;
125 if (SVX_LANG_MISSING_DO_WARN == nTmpSpell)
127 String aErr( SvtLanguageTable::GetLanguageString( nLang ) );
128 ErrorHandler::HandleError(
129 *new StringErrorInfo( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS, aErr ) );
130 nTmpSpell = SVX_LANG_MISSING;
132 if (SVX_LANG_MISSING_DO_WARN == nTmpHyph)
134 String aErr( SvtLanguageTable::GetLanguageString( nLang ) );
135 ErrorHandler::HandleError(
136 *new StringErrorInfo( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS, aErr ) );
137 nTmpHyph = SVX_LANG_MISSING;
140 rLCS[ nLang ] = (nTmpHyph << 8) | nTmpSpell;
141 ++aIt;
146 SvxSpellWrapper::~SvxSpellWrapper()
150 /*--------------------------------------------------------------------
151 * Description: Constructor, the test sequence is determined
153 * !bStart && !bOtherCntnt: BODY_END, BODY_START, OTHER
154 * !bStart && bOtherCntnt: OTHER, BODY
155 * bStart && !bOtherCntnt: BODY_END, OTHER
156 * bStart && bOtherCntnt: OTHER
158 --------------------------------------------------------------------*/
160 SvxSpellWrapper::SvxSpellWrapper( Window* pWn,
161 Reference< XSpellChecker1 > &xSpellChecker,
162 const sal_Bool bStart, const sal_Bool bIsAllRight,
163 const sal_Bool bOther, const sal_Bool bRevAllow ) :
165 pWin ( pWn ),
166 xSpell ( xSpellChecker ),
167 bOtherCntnt ( bOther ),
168 bDialog ( sal_False ),
169 bHyphen ( sal_False ),
170 bAuto ( sal_False ),
171 bStartChk ( bOther ),
172 bRevAllowed ( bRevAllow ),
173 bAllRight ( bIsAllRight )
175 Reference< beans::XPropertySet > xProp( SvxGetLinguPropertySet() );
176 sal_Bool bWrapReverse = xProp.is() ?
177 *(sal_Bool*)xProp->getPropertyValue(
178 ::rtl::OUString(UPN_IS_WRAP_REVERSE) ).getValue()
179 : sal_False;
180 bReverse = bRevAllow && bWrapReverse;
181 bStartDone = bOther || ( !bReverse && bStart );
182 bEndDone = bReverse && bStart && !bOther;
185 // -----------------------------------------------------------------------
187 SvxSpellWrapper::SvxSpellWrapper( Window* pWn,
188 Reference< XHyphenator > &xHyphenator,
189 const sal_Bool bStart, const sal_Bool bOther ) :
190 pWin ( pWn ),
191 xHyph ( xHyphenator ),
192 bOtherCntnt ( bOther ),
193 bDialog ( sal_False ),
194 bHyphen ( sal_False ),
195 bAuto ( sal_False ),
196 bReverse ( sal_False ),
197 bStartDone ( bOther || ( !bReverse && bStart ) ),
198 bEndDone ( bReverse && bStart && !bOther ),
199 bStartChk ( bOther ),
200 bRevAllowed ( sal_False ),
201 bAllRight ( sal_True )
205 // -----------------------------------------------------------------------
207 sal_Int16 SvxSpellWrapper::CheckSpellLang(
208 Reference< XSpellChecker1 > xSpell, sal_Int16 nLang)
210 LangCheckState_map_t &rLCS = GetLangCheckState();
212 LangCheckState_map_t::iterator aIt( rLCS.find( nLang ) );
213 sal_uInt16 nVal = aIt == rLCS.end() ? SVX_LANG_NEED_CHECK : aIt->second;
215 if (aIt == rLCS.end())
216 rLCS[ nLang ] = nVal;
218 if (SVX_LANG_NEED_CHECK == (nVal & 0x00FF))
220 sal_uInt16 nTmpVal = SVX_LANG_MISSING_DO_WARN;
221 if (xSpell.is() && xSpell->hasLanguage( nLang ))
222 nTmpVal = SVX_LANG_OK;
223 nVal &= 0xFF00;
224 nVal |= nTmpVal;
226 rLCS[ nLang ] = nVal;
229 return (sal_Int16) nVal;
232 sal_Int16 SvxSpellWrapper::CheckHyphLang(
233 Reference< XHyphenator > xHyph, sal_Int16 nLang)
235 LangCheckState_map_t &rLCS = GetLangCheckState();
237 LangCheckState_map_t::iterator aIt( rLCS.find( nLang ) );
238 sal_uInt16 nVal = aIt == rLCS.end() ? 0 : aIt->second;
240 if (aIt == rLCS.end())
241 rLCS[ nLang ] = nVal;
243 if (SVX_LANG_NEED_CHECK == ((nVal >> 8) & 0x00FF))
245 sal_uInt16 nTmpVal = SVX_LANG_MISSING_DO_WARN;
246 if (xHyph.is() && xHyph->hasLocale( SvxCreateLocale( nLang ) ))
247 nTmpVal = SVX_LANG_OK;
248 nVal &= 0x00FF;
249 nVal |= nTmpVal << 8;
251 rLCS[ nLang ] = nVal;
254 return (sal_Int16) nVal;
257 // -----------------------------------------------------------------------
260 void SvxSpellWrapper::SpellStart( SvxSpellArea /*eSpell*/ )
261 { // Here, the necessary preparations be made for SpellContinue in the
262 } // given area.
264 // -----------------------------------------------------------------------
267 sal_Bool SvxSpellWrapper::HasOtherCnt()
269 return sal_False; // Is there a special area?
272 // -----------------------------------------------------------------------
275 sal_Bool SvxSpellWrapper::SpellMore()
277 return sal_False; // Should additional documents be examined?
280 // -----------------------------------------------------------------------
283 void SvxSpellWrapper::SpellEnd()
284 { // Area is complete, tidy up if necessary
286 // display error for last language not found
287 ShowLanguageErrors();
290 // -----------------------------------------------------------------------
293 sal_Bool SvxSpellWrapper::SpellContinue()
295 return sal_False;
298 // -----------------------------------------------------------------------
300 void SvxSpellWrapper::AutoCorrect( const String&, const String& )
304 // -----------------------------------------------------------------------
307 void SvxSpellWrapper::ScrollArea()
308 { // Set Scroll area
311 // -----------------------------------------------------------------------
314 void SvxSpellWrapper::ChangeWord( const String&, const sal_uInt16 )
315 { // Insert Word
318 // -----------------------------------------------------------------------
321 String SvxSpellWrapper::GetThesWord()
323 // What word should be looked up?
324 return String();
327 // -----------------------------------------------------------------------
330 void SvxSpellWrapper::ChangeThesWord( const String& )
332 // replace word due to Thesaurus.
335 // -----------------------------------------------------------------------
337 void SvxSpellWrapper::StartThesaurus( const String &rWord, sal_uInt16 nLanguage )
339 Reference< XThesaurus > xThes( SvxGetThesaurus() );
340 if (!xThes.is())
342 InfoBox( pWin, EE_RESSTR( RID_SVXSTR_HMERR_THESAURUS ) ).Execute();
343 return;
346 WAIT_ON(); // while looking up for initial word
347 EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create();
348 AbstractThesaurusDialog* pDlg = pFact->CreateThesaurusDialog( pWin, xThes, rWord, nLanguage );
349 WAIT_OFF();
350 if ( pDlg->Execute()== RET_OK )
352 ChangeThesWord( pDlg->GetWord() );
354 delete pDlg;
357 // -----------------------------------------------------------------------
359 void SvxSpellWrapper::ReplaceAll( const String &, sal_Int16 )
360 { // Replace Word from the the Replace list
363 // -----------------------------------------------------------------------
366 void SvxSpellWrapper::SetLanguage( const sal_uInt16 )
367 { // Set Language
370 // -----------------------------------------------------------------------
373 void SvxSpellWrapper::InsertHyphen( const sal_uInt16 )
374 { // inserting and deleting Hyphae
377 // -----------------------------------------------------------------------
378 // Testing of the document areas in the order specified by the flags
381 void SvxSpellWrapper::SpellDocument( )
383 if ( bOtherCntnt )
385 bReverse = sal_False;
386 SpellStart( SVX_SPELL_OTHER );
388 else
390 bStartChk = bReverse;
391 SpellStart( bReverse ? SVX_SPELL_BODY_START : SVX_SPELL_BODY_END );
394 if ( FindSpellError() )
396 Reference< XSpellAlternatives > xAlt( GetLast(), UNO_QUERY );
397 Reference< XHyphenatedWord > xHyphWord( GetLast(), UNO_QUERY );
399 Window *pOld = pWin;
400 bDialog = sal_True;
401 if (xHyphWord.is())
403 EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create();
404 AbstractHyphenWordDialog* pDlg = pFact->CreateHyphenWordDialog( pWin,
405 xHyphWord->getWord(),
406 SvxLocaleToLanguage( xHyphWord->getLocale() ),
407 xHyph, this );
408 pWin = pDlg->GetWindow();
409 pDlg->Execute();
410 delete pDlg;
412 bDialog = sal_False;
413 pWin = pOld;
417 // -----------------------------------------------------------------------
418 // Select the next area
421 sal_Bool SvxSpellWrapper::SpellNext( )
423 Reference< beans::XPropertySet > xProp( SvxGetLinguPropertySet() );
424 sal_Bool bWrapReverse = xProp.is() ?
425 *(sal_Bool*)xProp->getPropertyValue(
426 ::rtl::OUString(UPN_IS_WRAP_REVERSE) ).getValue()
427 : sal_False;
428 sal_Bool bActRev = bRevAllowed && bWrapReverse;
430 // bActRev is the direction after Spell checking, bReverse is the one
431 // at the beginning.
432 if( bActRev == bReverse )
433 { // No change of direction, thus is the
434 if( bStartChk ) // desired area ( bStartChk )
435 bStartDone = sal_True; // completely processed.
436 else
437 bEndDone = sal_True;
439 else if( bReverse == bStartChk ) //For a change of direction, an area can
440 { // be processed during certain circumstances
441 if( bStartChk ) // If the firdt part is spell checked in backwards
442 bEndDone = sal_True; // and this is reversed in the process, then
443 else // then the end part is processed (and vice-versa).
444 bStartDone = sal_True;
447 bReverse = bActRev;
448 if( bOtherCntnt && bStartDone && bEndDone ) // Document has been fully checked?
450 if ( SpellMore() ) // spell check another document?
452 bOtherCntnt = sal_False;
453 bStartDone = !bReverse;
454 bEndDone = bReverse;
455 SpellStart( SVX_SPELL_BODY );
456 return sal_True;
458 return sal_False;
461 sal_Bool bGoOn = sal_False;
463 if ( bOtherCntnt )
465 bStartChk = sal_False;
466 SpellStart( SVX_SPELL_BODY );
467 bGoOn = sal_True;
469 else if ( bStartDone && bEndDone )
471 sal_Bool bIsSpellSpecial = xProp.is() ?
472 *(sal_Bool*)xProp->getPropertyValue(
473 ::rtl::OUString(UPN_IS_SPELL_SPECIAL) ).getValue()
474 : sal_False;
475 // Body area done, ask for special area
476 if( !IsHyphen() && bIsSpellSpecial && HasOtherCnt() )
478 SpellStart( SVX_SPELL_OTHER );
479 bOtherCntnt = bGoOn = sal_True;
481 else if ( SpellMore() ) // check another document?
483 bOtherCntnt = sal_False;
484 bStartDone = !bReverse;
485 bEndDone = bReverse;
486 SpellStart( SVX_SPELL_BODY );
487 return sal_True;
490 else
492 // a BODY_area done, ask for the other BODY_area
493 WAIT_OFF();
495 sal_uInt16 nResId = bReverse ? RID_SVXQB_BW_CONTINUE : RID_SVXQB_CONTINUE;
496 QueryBox aBox( pWin, EditResId( nResId ) );
497 if ( aBox.Execute() != RET_YES )
499 // sacrifice the other area if necessary ask for special area
500 WAIT_ON();
501 bStartDone = bEndDone = sal_True;
502 return SpellNext();
504 else
506 bStartChk = !bStartDone;
507 SpellStart( bStartChk ? SVX_SPELL_BODY_START : SVX_SPELL_BODY_END );
508 bGoOn = sal_True;
510 WAIT_ON();
512 return bGoOn;
515 // -----------------------------------------------------------------------
517 Reference< XDictionary > SvxSpellWrapper::GetAllRightDic() const
519 Reference< XDictionary > xDic;
521 Reference< XDictionaryList > xDicList( SvxGetDictionaryList() );
522 if (xDicList.is())
524 Sequence< Reference< XDictionary > > aDics( xDicList->getDictionaries() );
525 const Reference< XDictionary > *pDic = aDics.getConstArray();
526 sal_Int32 nCount = aDics.getLength();
528 sal_Int32 i = 0;
529 while (!xDic.is() && i < nCount)
531 Reference< XDictionary > xTmp( pDic[i], UNO_QUERY );
532 if (xTmp.is())
534 if ( xTmp->isActive() &&
535 xTmp->getDictionaryType() != DictionaryType_NEGATIVE &&
536 SvxLocaleToLanguage( xTmp->getLocale() ) == LANGUAGE_NONE )
538 Reference< frame::XStorable > xStor( xTmp, UNO_QUERY );
539 if (xStor.is() && xStor->hasLocation() && !xStor->isReadonly())
541 xDic = xTmp;
545 ++i;
548 if (!xDic.is())
550 xDic = SvxGetOrCreatePosDic( xDicList );
551 if (xDic.is())
552 xDic->setActive( sal_True );
556 return xDic;
559 // -----------------------------------------------------------------------
561 sal_Bool SvxSpellWrapper::FindSpellError()
563 ShowLanguageErrors();
565 Reference< XInterface > xRef;
567 WAIT_ON();
568 sal_Bool bSpell = sal_True;
570 Reference< XDictionary > xAllRightDic;
571 if (IsAllRight())
572 xAllRightDic = GetAllRightDic();
574 while ( bSpell )
576 SpellContinue();
578 Reference< XSpellAlternatives > xAlt( GetLast(), UNO_QUERY );
579 Reference< XHyphenatedWord > xHyphWord( GetLast(), UNO_QUERY );
581 if (xAlt.is())
583 if (IsAllRight() && xAllRightDic.is())
585 xAllRightDic->add( xAlt->getWord(), sal_False, ::rtl::OUString() );
587 else
589 // look up in ChangeAllList for misspelled word
590 Reference< XDictionary > xChangeAllList(
591 SvxGetChangeAllList(), UNO_QUERY );
592 Reference< XDictionaryEntry > xEntry;
593 if (xChangeAllList.is())
594 xEntry = xChangeAllList->getEntry( xAlt->getWord() );
596 if (xEntry.is())
598 // replace word without asking
599 ReplaceAll( xEntry->getReplacementText(),
600 SvxLocaleToLanguage( xAlt->getLocale() ) );
602 else
603 bSpell = sal_False;
606 else if (xHyphWord.is())
607 bSpell = sal_False;
608 else
610 SpellEnd();
611 bSpell = SpellNext();
614 WAIT_OFF();
615 return GetLast().is();
620 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */