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>
37 #include <tools/errinf.hxx>
39 #include <editeng/unolingu.hxx>
40 #include <linguistic/lngprops.hxx>
41 #include <com/sun/star/frame/XStorable.hpp>
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
90 #define SVX_LANG_MISSING 2
91 #define SVX_LANG_MISSING_DO_WARN 3
96 struct lt_LanguageType
98 bool operator()( LanguageType n1
, LanguageType n2
) const
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
;
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
) :
166 xSpell ( xSpellChecker
),
167 bOtherCntnt ( bOther
),
168 bDialog ( sal_False
),
169 bHyphen ( 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()
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
) :
191 xHyph ( xHyphenator
),
192 bOtherCntnt ( bOther
),
193 bDialog ( sal_False
),
194 bHyphen ( 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
;
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
;
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
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()
298 // -----------------------------------------------------------------------
300 void SvxSpellWrapper::AutoCorrect( const String
&, const String
& )
304 // -----------------------------------------------------------------------
307 void SvxSpellWrapper::ScrollArea()
311 // -----------------------------------------------------------------------
314 void SvxSpellWrapper::ChangeWord( const String
&, const sal_uInt16
)
318 // -----------------------------------------------------------------------
321 String
SvxSpellWrapper::GetThesWord()
323 // What word should be looked up?
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() );
342 InfoBox( pWin
, EE_RESSTR( RID_SVXSTR_HMERR_THESAURUS
) ).Execute();
346 WAIT_ON(); // while looking up for initial word
347 EditAbstractDialogFactory
* pFact
= EditAbstractDialogFactory::Create();
348 AbstractThesaurusDialog
* pDlg
= pFact
->CreateThesaurusDialog( pWin
, xThes
, rWord
, nLanguage
);
350 if ( pDlg
->Execute()== RET_OK
)
352 ChangeThesWord( pDlg
->GetWord() );
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
)
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( )
385 bReverse
= sal_False
;
386 SpellStart( SVX_SPELL_OTHER
);
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
);
403 EditAbstractDialogFactory
* pFact
= EditAbstractDialogFactory::Create();
404 AbstractHyphenWordDialog
* pDlg
= pFact
->CreateHyphenWordDialog( pWin
,
405 xHyphWord
->getWord(),
406 SvxLocaleToLanguage( xHyphWord
->getLocale() ),
408 pWin
= pDlg
->GetWindow();
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()
428 sal_Bool bActRev
= bRevAllowed
&& bWrapReverse
;
430 // bActRev is the direction after Spell checking, bReverse is the one
432 if( bActRev
== bReverse
)
433 { // No change of direction, thus is the
434 if( bStartChk
) // desired area ( bStartChk )
435 bStartDone
= sal_True
; // completely processed.
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
;
448 if( bOtherCntnt
&& bStartDone
&& bEndDone
) // Document has been fully checked?
450 if ( SpellMore() ) // spell check another document?
452 bOtherCntnt
= sal_False
;
453 bStartDone
= !bReverse
;
455 SpellStart( SVX_SPELL_BODY
);
461 sal_Bool bGoOn
= sal_False
;
465 bStartChk
= sal_False
;
466 SpellStart( SVX_SPELL_BODY
);
469 else if ( bStartDone
&& bEndDone
)
471 sal_Bool bIsSpellSpecial
= xProp
.is() ?
472 *(sal_Bool
*)xProp
->getPropertyValue(
473 ::rtl::OUString(UPN_IS_SPELL_SPECIAL
) ).getValue()
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
;
486 SpellStart( SVX_SPELL_BODY
);
492 // a BODY_area done, ask for the other BODY_area
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
501 bStartDone
= bEndDone
= sal_True
;
506 bStartChk
= !bStartDone
;
507 SpellStart( bStartChk
? SVX_SPELL_BODY_START
: SVX_SPELL_BODY_END
);
515 // -----------------------------------------------------------------------
517 Reference
< XDictionary
> SvxSpellWrapper::GetAllRightDic() const
519 Reference
< XDictionary
> xDic
;
521 Reference
< XDictionaryList
> xDicList( SvxGetDictionaryList() );
524 Sequence
< Reference
< XDictionary
> > aDics( xDicList
->getDictionaries() );
525 const Reference
< XDictionary
> *pDic
= aDics
.getConstArray();
526 sal_Int32 nCount
= aDics
.getLength();
529 while (!xDic
.is() && i
< nCount
)
531 Reference
< XDictionary
> xTmp( pDic
[i
], UNO_QUERY
);
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())
550 xDic
= SvxGetOrCreatePosDic( xDicList
);
552 xDic
->setActive( sal_True
);
559 // -----------------------------------------------------------------------
561 sal_Bool
SvxSpellWrapper::FindSpellError()
563 ShowLanguageErrors();
565 Reference
< XInterface
> xRef
;
568 sal_Bool bSpell
= sal_True
;
570 Reference
< XDictionary
> xAllRightDic
;
572 xAllRightDic
= GetAllRightDic();
578 Reference
< XSpellAlternatives
> xAlt( GetLast(), UNO_QUERY
);
579 Reference
< XHyphenatedWord
> xHyphWord( GetLast(), UNO_QUERY
);
583 if (IsAllRight() && xAllRightDic
.is())
585 xAllRightDic
->add( xAlt
->getWord(), sal_False
, ::rtl::OUString() );
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() );
598 // replace word without asking
599 ReplaceAll( xEntry
->getReplacementText(),
600 SvxLocaleToLanguage( xAlt
->getLocale() ) );
606 else if (xHyphWord
.is())
611 bSpell
= SpellNext();
615 return GetLast().is();
620 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */