Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
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>
26 :
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>
33 :
34 : #include <map>
35 :
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>
43 :
44 : #define WAIT_ON() if(pWin != NULL) { pWin->EnterWait(); }
45 :
46 : #define WAIT_OFF() if(pWin != NULL) { pWin->LeaveWait(); }
47 :
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;
52 :
53 :
54 : // misc functions ---------------------------------------------
55 :
56 0 : void SvxPrepareAutoCorrect( OUString &rOldText, const OUString &rNewText )
57 : {
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.
63 : //
64 : // rOldText: text to be replaced
65 : // rNewText: replacement text
66 :
67 0 : sal_Int32 nOldLen = rOldText.getLength();
68 0 : sal_Int32 nNewLen = rNewText.getLength();
69 0 : if (nOldLen && nNewLen)
70 : {
71 0 : bool bOldHasDot = '.' == rOldText[ nOldLen - 1 ],
72 0 : bNewHasDot = '.' == rNewText[ nNewLen - 1 ];
73 0 : if (bOldHasDot && !bNewHasDot
74 : /*this is: !(bOldHasDot && bNewHasDot) && bOldHasDot*/)
75 0 : rOldText = rOldText.copy( 0, nOldLen - 1 );
76 : }
77 0 : }
78 :
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
83 :
84 : struct lt_LanguageType
85 : {
86 0 : bool operator()( LanguageType n1, LanguageType n2 ) const
87 : {
88 0 : return n1 < n2;
89 : }
90 : };
91 :
92 : typedef std::map< LanguageType, sal_uInt16, lt_LanguageType > LangCheckState_map_t;
93 :
94 0 : static LangCheckState_map_t & GetLangCheckState()
95 : {
96 0 : static LangCheckState_map_t aLangCheckState;
97 0 : return aLangCheckState;
98 : }
99 :
100 0 : void SvxSpellWrapper::ShowLanguageErrors()
101 : {
102 : // display message boxes for languages not available for
103 : // spellchecking or hyphenation
104 0 : LangCheckState_map_t &rLCS = GetLangCheckState();
105 0 : LangCheckState_map_t::iterator aIt( rLCS.begin() );
106 0 : while (aIt != rLCS.end())
107 : {
108 0 : LanguageType nLang = aIt->first;
109 0 : sal_uInt16 nVal = aIt->second;
110 0 : sal_uInt16 nTmpSpell = nVal & 0x00FF;
111 0 : sal_uInt16 nTmpHyph = (nVal >> 8) & 0x00FF;
112 :
113 0 : if (SVX_LANG_MISSING_DO_WARN == nTmpSpell)
114 : {
115 0 : OUString aErr( SvtLanguageTable::GetLanguageString( nLang ) );
116 : ErrorHandler::HandleError(
117 0 : *new StringErrorInfo( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS, aErr ) );
118 0 : nTmpSpell = SVX_LANG_MISSING;
119 : }
120 0 : if (SVX_LANG_MISSING_DO_WARN == nTmpHyph)
121 : {
122 0 : OUString aErr( SvtLanguageTable::GetLanguageString( nLang ) );
123 : ErrorHandler::HandleError(
124 0 : *new StringErrorInfo( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS, aErr ) );
125 0 : nTmpHyph = SVX_LANG_MISSING;
126 : }
127 :
128 0 : rLCS[ nLang ] = (nTmpHyph << 8) | nTmpSpell;
129 0 : ++aIt;
130 : }
131 :
132 0 : }
133 :
134 0 : SvxSpellWrapper::~SvxSpellWrapper()
135 : {
136 0 : }
137 :
138 : /*--------------------------------------------------------------------
139 : * Description: Constructor, the test sequence is determined
140 : *
141 : * !bStart && !bOtherCntnt: BODY_END, BODY_START, OTHER
142 : * !bStart && bOtherCntnt: OTHER, BODY
143 : * bStart && !bOtherCntnt: BODY_END, OTHER
144 : * bStart && bOtherCntnt: OTHER
145 : *
146 : --------------------------------------------------------------------*/
147 :
148 0 : SvxSpellWrapper::SvxSpellWrapper( Window* pWn,
149 : Reference< XSpellChecker1 > &xSpellChecker,
150 : const bool bStart, const bool bIsAllRight,
151 : const bool bOther, const bool bRevAllow ) :
152 :
153 : pWin ( pWn ),
154 : xSpell ( xSpellChecker ),
155 : mpTextObj( NULL),
156 : bOtherCntnt ( bOther ),
157 : bDialog ( false ),
158 : bHyphen ( false ),
159 : bAuto ( false ),
160 : bStartChk ( bOther ),
161 : bRevAllowed ( bRevAllow ),
162 0 : bAllRight ( bIsAllRight )
163 : {
164 0 : Reference< linguistic2::XLinguProperties > xProp( SvxGetLinguPropertySet() );
165 0 : bool bWrapReverse = xProp.is() && xProp->getIsWrapReverse();
166 0 : bReverse = bRevAllow && bWrapReverse;
167 0 : bStartDone = bOther || ( !bReverse && bStart );
168 0 : bEndDone = bReverse && bStart && !bOther;
169 0 : }
170 :
171 :
172 :
173 0 : SvxSpellWrapper::SvxSpellWrapper( Window* pWn,
174 : Reference< XHyphenator > &xHyphenator,
175 : const bool bStart, const bool bOther ) :
176 : pWin ( pWn ),
177 : xHyph ( xHyphenator ),
178 : mpTextObj( NULL),
179 : bOtherCntnt ( bOther ),
180 : bDialog ( false ),
181 : bHyphen ( false ),
182 : bAuto ( false ),
183 : bReverse ( false ),
184 0 : bStartDone ( bOther || ( !bReverse && bStart ) ),
185 0 : bEndDone ( bReverse && bStart && !bOther ),
186 : bStartChk ( bOther ),
187 : bRevAllowed ( false ),
188 0 : bAllRight ( true )
189 : {
190 0 : }
191 :
192 :
193 :
194 0 : sal_Int16 SvxSpellWrapper::CheckSpellLang(
195 : Reference< XSpellChecker1 > xSpell, sal_Int16 nLang)
196 : {
197 0 : LangCheckState_map_t &rLCS = GetLangCheckState();
198 :
199 0 : LangCheckState_map_t::iterator aIt( rLCS.find( nLang ) );
200 0 : sal_uInt16 nVal = aIt == rLCS.end() ? SVX_LANG_NEED_CHECK : aIt->second;
201 :
202 0 : if (aIt == rLCS.end())
203 0 : rLCS[ nLang ] = nVal;
204 :
205 0 : if (SVX_LANG_NEED_CHECK == (nVal & 0x00FF))
206 : {
207 0 : sal_uInt16 nTmpVal = SVX_LANG_MISSING_DO_WARN;
208 0 : if (xSpell.is() && xSpell->hasLanguage( nLang ))
209 0 : nTmpVal = SVX_LANG_OK;
210 0 : nVal &= 0xFF00;
211 0 : nVal |= nTmpVal;
212 :
213 0 : rLCS[ nLang ] = nVal;
214 : }
215 :
216 0 : return (sal_Int16) nVal;
217 : }
218 :
219 0 : sal_Int16 SvxSpellWrapper::CheckHyphLang(
220 : Reference< XHyphenator > xHyph, sal_Int16 nLang)
221 : {
222 0 : LangCheckState_map_t &rLCS = GetLangCheckState();
223 :
224 0 : LangCheckState_map_t::iterator aIt( rLCS.find( nLang ) );
225 0 : sal_uInt16 nVal = aIt == rLCS.end() ? 0 : aIt->second;
226 :
227 0 : if (aIt == rLCS.end())
228 0 : rLCS[ nLang ] = nVal;
229 :
230 0 : if (SVX_LANG_NEED_CHECK == ((nVal >> 8) & 0x00FF))
231 : {
232 0 : sal_uInt16 nTmpVal = SVX_LANG_MISSING_DO_WARN;
233 0 : if (xHyph.is() && xHyph->hasLocale( LanguageTag::convertToLocale( nLang ) ))
234 0 : nTmpVal = SVX_LANG_OK;
235 0 : nVal &= 0x00FF;
236 0 : nVal |= nTmpVal << 8;
237 :
238 0 : rLCS[ nLang ] = nVal;
239 : }
240 :
241 0 : return (sal_Int16) nVal;
242 : }
243 :
244 :
245 :
246 :
247 0 : void SvxSpellWrapper::SpellStart( SvxSpellArea /*eSpell*/ )
248 : { // Here, the necessary preparations be made for SpellContinue in the
249 0 : } // given area.
250 :
251 :
252 :
253 :
254 0 : bool SvxSpellWrapper::HasOtherCnt()
255 : {
256 0 : return false; // Is there a special area?
257 : }
258 :
259 :
260 :
261 :
262 0 : bool SvxSpellWrapper::SpellMore()
263 : {
264 0 : return false; // Should additional documents be examined?
265 : }
266 :
267 :
268 :
269 :
270 0 : void SvxSpellWrapper::SpellEnd()
271 : { // Area is complete, tidy up if necessary
272 :
273 : // display error for last language not found
274 0 : ShowLanguageErrors();
275 0 : }
276 :
277 :
278 :
279 :
280 0 : bool SvxSpellWrapper::SpellContinue()
281 : {
282 0 : return false;
283 : }
284 :
285 :
286 :
287 0 : void SvxSpellWrapper::AutoCorrect( const OUString&, const OUString& )
288 : {
289 0 : }
290 :
291 :
292 :
293 :
294 0 : void SvxSpellWrapper::ScrollArea()
295 : { // Set Scroll area
296 0 : }
297 :
298 :
299 :
300 :
301 0 : void SvxSpellWrapper::ChangeWord( const OUString&, const sal_uInt16 )
302 : { // Insert Word
303 0 : }
304 :
305 :
306 :
307 :
308 0 : void SvxSpellWrapper::ChangeThesWord( const OUString& )
309 : {
310 : // replace word due to Thesaurus.
311 0 : }
312 :
313 :
314 :
315 0 : void SvxSpellWrapper::StartThesaurus( const OUString &rWord, sal_uInt16 nLanguage )
316 : {
317 0 : Reference< XThesaurus > xThes( SvxGetThesaurus() );
318 0 : if (!xThes.is())
319 : {
320 0 : InfoBox( pWin, EE_RESSTR( RID_SVXSTR_HMERR_THESAURUS ) ).Execute();
321 0 : return;
322 : }
323 :
324 0 : WAIT_ON(); // while looking up for initial word
325 0 : EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create();
326 0 : AbstractThesaurusDialog* pDlg = pFact->CreateThesaurusDialog( pWin, xThes, rWord, nLanguage );
327 0 : WAIT_OFF();
328 0 : if ( pDlg->Execute()== RET_OK )
329 : {
330 0 : ChangeThesWord( pDlg->GetWord() );
331 : }
332 0 : delete pDlg;
333 : }
334 :
335 :
336 :
337 0 : void SvxSpellWrapper::ReplaceAll( const OUString &, sal_Int16 )
338 : { // Replace Word from the Replace list
339 0 : }
340 :
341 :
342 :
343 :
344 0 : void SvxSpellWrapper::SetLanguage( const sal_uInt16 )
345 : { // Set Language
346 0 : }
347 :
348 :
349 :
350 :
351 0 : void SvxSpellWrapper::InsertHyphen( const sal_uInt16 )
352 : { // inserting and deleting Hyphae
353 0 : }
354 :
355 :
356 : // Testing of the document areas in the order specified by the flags
357 :
358 :
359 0 : void SvxSpellWrapper::SpellDocument( )
360 : {
361 0 : if ( bOtherCntnt )
362 : {
363 0 : bReverse = false;
364 0 : SpellStart( SVX_SPELL_OTHER );
365 : }
366 : else
367 : {
368 0 : bStartChk = bReverse;
369 0 : SpellStart( bReverse ? SVX_SPELL_BODY_START : SVX_SPELL_BODY_END );
370 : }
371 :
372 0 : if ( FindSpellError() )
373 : {
374 0 : Reference< XSpellAlternatives > xAlt( GetLast(), UNO_QUERY );
375 0 : Reference< XHyphenatedWord > xHyphWord( GetLast(), UNO_QUERY );
376 :
377 0 : Window *pOld = pWin;
378 0 : bDialog = true;
379 0 : if (xHyphWord.is())
380 : {
381 0 : EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create();
382 : AbstractHyphenWordDialog* pDlg = pFact->CreateHyphenWordDialog( pWin,
383 0 : xHyphWord->getWord(),
384 0 : LanguageTag( xHyphWord->getLocale() ).getLanguageType(),
385 0 : xHyph, this );
386 0 : pWin = pDlg->GetWindow();
387 0 : pDlg->Execute();
388 0 : delete pDlg;
389 : }
390 0 : bDialog = false;
391 0 : pWin = pOld;
392 : };
393 0 : }
394 :
395 :
396 : // Select the next area
397 :
398 :
399 0 : bool SvxSpellWrapper::SpellNext( )
400 : {
401 0 : Reference< linguistic2::XLinguProperties > xProp( SvxGetLinguPropertySet() );
402 0 : bool bWrapReverse = xProp.is() && xProp->getIsWrapReverse();
403 0 : bool bActRev = bRevAllowed && bWrapReverse;
404 :
405 : // bActRev is the direction after Spell checking, bReverse is the one
406 : // at the beginning.
407 0 : if( bActRev == bReverse )
408 : { // No change of direction, thus is the
409 0 : if( bStartChk ) // desired area ( bStartChk )
410 0 : bStartDone = true; // completely processed.
411 : else
412 0 : bEndDone = true;
413 : }
414 0 : else if( bReverse == bStartChk ) //For a change of direction, an area can
415 : { // be processed during certain circumstances
416 0 : if( bStartChk ) // If the firdt part is spell checked in backwards
417 0 : bEndDone = true; // and this is reversed in the process, then
418 : else // then the end part is processed (and vice-versa).
419 0 : bStartDone = true;
420 : }
421 :
422 0 : bReverse = bActRev;
423 0 : if( bOtherCntnt && bStartDone && bEndDone ) // Document has been fully checked?
424 : {
425 0 : if ( SpellMore() ) // spell check another document?
426 : {
427 0 : bOtherCntnt = false;
428 0 : bStartDone = !bReverse;
429 0 : bEndDone = bReverse;
430 0 : SpellStart( SVX_SPELL_BODY );
431 0 : return true;
432 : }
433 0 : return false;
434 : }
435 :
436 0 : bool bGoOn = false;
437 :
438 0 : if ( bOtherCntnt )
439 : {
440 0 : bStartChk = false;
441 0 : SpellStart( SVX_SPELL_BODY );
442 0 : bGoOn = true;
443 : }
444 0 : else if ( bStartDone && bEndDone )
445 : {
446 0 : bool bIsSpellSpecial = xProp.is() && xProp->getIsSpellSpecial();
447 : // Body area done, ask for special area
448 0 : if( !IsHyphen() && bIsSpellSpecial && HasOtherCnt() )
449 : {
450 0 : SpellStart( SVX_SPELL_OTHER );
451 0 : bOtherCntnt = bGoOn = true;
452 : }
453 0 : else if ( SpellMore() ) // check another document?
454 : {
455 0 : bOtherCntnt = false;
456 0 : bStartDone = !bReverse;
457 0 : bEndDone = bReverse;
458 0 : SpellStart( SVX_SPELL_BODY );
459 0 : return true;
460 0 : }
461 : }
462 : else
463 : {
464 : // a BODY_area done, ask for the other BODY_area
465 0 : WAIT_OFF();
466 :
467 0 : sal_uInt16 nResId = bReverse ? RID_SVXQB_BW_CONTINUE : RID_SVXQB_CONTINUE;
468 0 : QueryBox aBox( pWin, EditResId( nResId ) );
469 0 : if ( aBox.Execute() != RET_YES )
470 : {
471 : // sacrifice the other area if necessary ask for special area
472 0 : WAIT_ON();
473 0 : bStartDone = bEndDone = true;
474 0 : return SpellNext();
475 : }
476 : else
477 : {
478 0 : bStartChk = !bStartDone;
479 0 : SpellStart( bStartChk ? SVX_SPELL_BODY_START : SVX_SPELL_BODY_END );
480 0 : bGoOn = true;
481 : }
482 0 : WAIT_ON();
483 : }
484 0 : return bGoOn;
485 : }
486 :
487 :
488 :
489 0 : Reference< XDictionary > SvxSpellWrapper::GetAllRightDic() const
490 : {
491 0 : Reference< XDictionary > xDic;
492 :
493 0 : Reference< XSearchableDictionaryList > xDicList( SvxGetDictionaryList() );
494 0 : if (xDicList.is())
495 : {
496 0 : Sequence< Reference< XDictionary > > aDics( xDicList->getDictionaries() );
497 0 : const Reference< XDictionary > *pDic = aDics.getConstArray();
498 0 : sal_Int32 nCount = aDics.getLength();
499 :
500 0 : sal_Int32 i = 0;
501 0 : while (!xDic.is() && i < nCount)
502 : {
503 0 : Reference< XDictionary > xTmp( pDic[i], UNO_QUERY );
504 0 : if (xTmp.is())
505 : {
506 0 : if ( xTmp->isActive() &&
507 0 : xTmp->getDictionaryType() != DictionaryType_NEGATIVE &&
508 0 : LanguageTag( xTmp->getLocale() ).getLanguageType() == LANGUAGE_NONE )
509 : {
510 0 : Reference< frame::XStorable > xStor( xTmp, UNO_QUERY );
511 0 : if (xStor.is() && xStor->hasLocation() && !xStor->isReadonly())
512 : {
513 0 : xDic = xTmp;
514 0 : }
515 : }
516 : }
517 0 : ++i;
518 0 : }
519 :
520 0 : if (!xDic.is())
521 : {
522 0 : xDic = SvxGetOrCreatePosDic( xDicList );
523 0 : if (xDic.is())
524 0 : xDic->setActive( sal_True );
525 0 : }
526 : }
527 :
528 0 : return xDic;
529 : }
530 :
531 :
532 :
533 0 : bool SvxSpellWrapper::FindSpellError()
534 : {
535 0 : ShowLanguageErrors();
536 :
537 0 : Reference< XInterface > xRef;
538 :
539 0 : WAIT_ON();
540 0 : bool bSpell = true;
541 :
542 0 : Reference< XDictionary > xAllRightDic;
543 0 : if (IsAllRight())
544 0 : xAllRightDic = GetAllRightDic();
545 :
546 0 : while ( bSpell )
547 : {
548 0 : SpellContinue();
549 :
550 0 : Reference< XSpellAlternatives > xAlt( GetLast(), UNO_QUERY );
551 0 : Reference< XHyphenatedWord > xHyphWord( GetLast(), UNO_QUERY );
552 :
553 0 : if (xAlt.is())
554 : {
555 0 : if (IsAllRight() && xAllRightDic.is())
556 : {
557 0 : xAllRightDic->add( xAlt->getWord(), sal_False, OUString() );
558 : }
559 : else
560 : {
561 : // look up in ChangeAllList for misspelled word
562 : Reference< XDictionary > xChangeAllList(
563 0 : SvxGetChangeAllList(), UNO_QUERY );
564 0 : Reference< XDictionaryEntry > xEntry;
565 0 : if (xChangeAllList.is())
566 0 : xEntry = xChangeAllList->getEntry( xAlt->getWord() );
567 :
568 0 : if (xEntry.is())
569 : {
570 : // replace word without asking
571 0 : ReplaceAll( xEntry->getReplacementText(),
572 0 : LanguageTag( xAlt->getLocale() ).getLanguageType() );
573 : }
574 : else
575 0 : bSpell = false;
576 : }
577 : }
578 0 : else if (xHyphWord.is())
579 0 : bSpell = false;
580 : else
581 : {
582 0 : SpellEnd();
583 0 : bSpell = SpellNext();
584 : }
585 0 : }
586 0 : WAIT_OFF();
587 0 : return GetLast().is();
588 : }
589 :
590 :
591 :
592 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|