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