1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
28 #include <tools/errinf.hxx>
30 #include <editeng/unolingu.hxx>
31 #include <linguistic/lngprops.hxx>
32 #include <com/sun/star/frame/XStorable.hpp>
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
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
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
;
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
) :
154 xSpell ( xSpellChecker
),
155 bOtherCntnt ( bOther
),
156 bDialog ( sal_False
),
157 bHyphen ( 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
) :
176 xHyph ( xHyphenator
),
177 bOtherCntnt ( bOther
),
178 bDialog ( sal_False
),
179 bHyphen ( 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
;
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
;
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
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()
283 // -----------------------------------------------------------------------
285 void SvxSpellWrapper::AutoCorrect( const String
&, const String
& )
289 // -----------------------------------------------------------------------
292 void SvxSpellWrapper::ScrollArea()
296 // -----------------------------------------------------------------------
299 void SvxSpellWrapper::ChangeWord( const String
&, const sal_uInt16
)
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() );
318 InfoBox( pWin
, EE_RESSTR( RID_SVXSTR_HMERR_THESAURUS
) ).Execute();
322 WAIT_ON(); // while looking up for initial word
323 EditAbstractDialogFactory
* pFact
= EditAbstractDialogFactory::Create();
324 AbstractThesaurusDialog
* pDlg
= pFact
->CreateThesaurusDialog( pWin
, xThes
, rWord
, nLanguage
);
326 if ( pDlg
->Execute()== RET_OK
)
328 ChangeThesWord( pDlg
->GetWord() );
333 // -----------------------------------------------------------------------
335 void SvxSpellWrapper::ReplaceAll( const String
&, sal_Int16
)
336 { // Replace Word from the Replace list
339 // -----------------------------------------------------------------------
342 void SvxSpellWrapper::SetLanguage( const sal_uInt16
)
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( )
361 bReverse
= sal_False
;
362 SpellStart( SVX_SPELL_OTHER
);
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
);
379 EditAbstractDialogFactory
* pFact
= EditAbstractDialogFactory::Create();
380 AbstractHyphenWordDialog
* pDlg
= pFact
->CreateHyphenWordDialog( pWin
,
381 xHyphWord
->getWord(),
382 LanguageTag( xHyphWord
->getLocale() ).getLanguageType(),
384 pWin
= pDlg
->GetWindow();
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
405 if( bActRev
== bReverse
)
406 { // No change of direction, thus is the
407 if( bStartChk
) // desired area ( bStartChk )
408 bStartDone
= sal_True
; // completely processed.
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
;
421 if( bOtherCntnt
&& bStartDone
&& bEndDone
) // Document has been fully checked?
423 if ( SpellMore() ) // spell check another document?
425 bOtherCntnt
= sal_False
;
426 bStartDone
= !bReverse
;
428 SpellStart( SVX_SPELL_BODY
);
434 sal_Bool bGoOn
= sal_False
;
438 bStartChk
= sal_False
;
439 SpellStart( SVX_SPELL_BODY
);
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
;
456 SpellStart( SVX_SPELL_BODY
);
462 // a BODY_area done, ask for the other BODY_area
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
471 bStartDone
= bEndDone
= sal_True
;
476 bStartChk
= !bStartDone
;
477 SpellStart( bStartChk
? SVX_SPELL_BODY_START
: SVX_SPELL_BODY_END
);
485 // -----------------------------------------------------------------------
487 Reference
< XDictionary
> SvxSpellWrapper::GetAllRightDic() const
489 Reference
< XDictionary
> xDic
;
491 Reference
< XSearchableDictionaryList
> xDicList( SvxGetDictionaryList() );
494 Sequence
< Reference
< XDictionary
> > aDics( xDicList
->getDictionaries() );
495 const Reference
< XDictionary
> *pDic
= aDics
.getConstArray();
496 sal_Int32 nCount
= aDics
.getLength();
499 while (!xDic
.is() && i
< nCount
)
501 Reference
< XDictionary
> xTmp( pDic
[i
], UNO_QUERY
);
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())
520 xDic
= SvxGetOrCreatePosDic( xDicList
);
522 xDic
->setActive( sal_True
);
529 // -----------------------------------------------------------------------
531 sal_Bool
SvxSpellWrapper::FindSpellError()
533 ShowLanguageErrors();
535 Reference
< XInterface
> xRef
;
538 sal_Bool bSpell
= sal_True
;
540 Reference
< XDictionary
> xAllRightDic
;
542 xAllRightDic
= GetAllRightDic();
548 Reference
< XSpellAlternatives
> xAlt( GetLast(), UNO_QUERY
);
549 Reference
< XHyphenatedWord
> xHyphWord( GetLast(), UNO_QUERY
);
553 if (IsAllRight() && xAllRightDic
.is())
555 xAllRightDic
->add( xAlt
->getWord(), sal_False
, OUString() );
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() );
568 // replace word without asking
569 ReplaceAll( xEntry
->getReplacementText(),
570 LanguageTag( xAlt
->getLocale() ).getLanguageType() );
576 else if (xHyphWord
.is())
581 bSpell
= SpellNext();
585 return GetLast().is();
590 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */