xref: /trunk/main/editeng/source/misc/splwrap.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_editeng.hxx"
30 #include<rtl/ustring.hxx>
31 #include <tools/shl.hxx>
32 #include <vcl/wrkwin.hxx>
33 #include <vcl/svapp.hxx>
34 #include <vcl/msgbox.hxx>
35 #include <tools/debug.hxx>
36 #include <svtools/langtab.hxx>
37 
38 #ifndef __RSC
39 #include <tools/errinf.hxx>
40 #endif
41 #include <editeng/unolingu.hxx>
42 #include <linguistic/lngprops.hxx>
43 #include <com/sun/star/frame/XStorable.hpp>
44 
45 #include <map>
46 
47 #include <editeng/svxenum.hxx>
48 #include <editeng/splwrap.hxx>      // Der Wrapper
49 #include <editeng/edtdlg.hxx>
50 #include <editeng/eerdll.hxx>
51 #include <editeng/editrids.hrc>
52 #include <editeng/editids.hrc>
53 #include <editeng/editerr.hxx>
54 
55 #define WAIT_ON() if(pWin != NULL) { pWin->EnterWait(); }
56 
57 #define WAIT_OFF() if(pWin != NULL) { pWin->LeaveWait(); }
58 
59 using namespace ::com::sun::star;
60 using namespace ::com::sun::star::uno;
61 using namespace ::com::sun::star::beans;
62 using namespace ::com::sun::star::linguistic2;
63 
64 
65 // misc functions ---------------------------------------------
66 
67 void SvxPrepareAutoCorrect( String &rOldText, String &rNewText )
68 {
69     // This function should be used to strip (or add) trailing '.' from
70     // the strings before passing them on to the autocorrect function in
71     // order that the autocorrect function will hopefully
72     // works properly with normal words and abbreviations (with trailing '.')
73     // independ of if they are at the end of the sentence or not.
74     //
75     // rOldText: text to be replaced
76     // rNewText: replacement text
77 
78     xub_StrLen  nOldLen = rOldText.Len(),
79                 nNewLen = rNewText.Len();
80     if (nOldLen && nNewLen)
81     {
82         sal_Bool bOldHasDot = sal_Unicode( '.' ) == rOldText.GetChar( nOldLen - 1 ),
83              bNewHasDot = sal_Unicode( '.' ) == rNewText.GetChar( nNewLen - 1 );
84         if (bOldHasDot && !bNewHasDot
85             /*this is: !(bOldHasDot && bNewHasDot) && bOldHasDot*/)
86             rOldText.Erase( nOldLen - 1 );
87     }
88 }
89 
90 // -----------------------------------------------------------------------
91 
92 #define SVX_LANG_NEED_CHECK         0
93 #define SVX_LANG_OK                 1
94 #define SVX_LANG_MISSING            2
95 #define SVX_LANG_MISSING_DO_WARN    3
96 
97 #define SVX_FLAGS_NEW
98 
99 
100 struct lt_LanguageType
101 {
102     bool operator()( LanguageType n1, LanguageType n2 ) const
103     {
104         return n1 < n2;
105     }
106 };
107 
108 typedef std::map< LanguageType, sal_uInt16, lt_LanguageType >   LangCheckState_map_t;
109 
110 static LangCheckState_map_t & GetLangCheckState()
111 {
112     static LangCheckState_map_t aLangCheckState;
113     return aLangCheckState;
114 }
115 
116 void SvxSpellWrapper::ShowLanguageErrors()
117 {
118     // display message boxes for languages not available for
119     // spellchecking or hyphenation
120     LangCheckState_map_t &rLCS = GetLangCheckState();
121     LangCheckState_map_t::iterator aIt( rLCS.begin() );
122     while (aIt != rLCS.end())
123     {
124         LanguageType nLang = aIt->first;
125         sal_uInt16   nVal  = aIt->second;
126         sal_uInt16 nTmpSpell = nVal & 0x00FF;
127         sal_uInt16 nTmpHyph  = (nVal >> 8) & 0x00FF;
128 
129         if (SVX_LANG_MISSING_DO_WARN == nTmpSpell)
130         {
131             String aErr( SvtLanguageTable::GetLanguageString( nLang ) );
132             ErrorHandler::HandleError(
133                 *new StringErrorInfo( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS, aErr ) );
134             nTmpSpell = SVX_LANG_MISSING;
135         }
136         if (SVX_LANG_MISSING_DO_WARN == nTmpHyph)
137         {
138             String aErr( SvtLanguageTable::GetLanguageString( nLang ) );
139             ErrorHandler::HandleError(
140                 *new StringErrorInfo( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS, aErr ) );
141             nTmpHyph = SVX_LANG_MISSING;
142         }
143 
144         rLCS[ nLang ] = (nTmpHyph << 8) | nTmpSpell;
145         ++aIt;
146     }
147 
148 }
149 
150 SvxSpellWrapper::~SvxSpellWrapper()
151 {
152 }
153 
154 /*--------------------------------------------------------------------
155  *  Beschreibung: Ctor, die Pruefreihenfolge wird festgelegt
156  *
157  *  !bStart && !bOtherCntnt:    BODY_END,   BODY_START, OTHER
158  *  !bStart && bOtherCntnt:     OTHER,      BODY
159  *  bStart && !bOtherCntnt:     BODY_END,   OTHER
160  *  bStart && bOtherCntnt:      OTHER
161  *
162  --------------------------------------------------------------------*/
163 
164 SvxSpellWrapper::SvxSpellWrapper( Window* pWn,
165     Reference< XSpellChecker1 >  &xSpellChecker,
166     const sal_Bool bStart, const sal_Bool bIsAllRight,
167     const sal_Bool bOther, const sal_Bool bRevAllow ) :
168 
169     pWin        ( pWn ),
170     xSpell      ( xSpellChecker ),
171     bOtherCntnt ( bOther ),
172     bDialog     ( sal_False ),
173     bHyphen     ( sal_False ),
174     bAuto       ( sal_False ),
175     bStartChk   ( bOther ),
176     bRevAllowed ( bRevAllow ),
177     bAllRight   ( bIsAllRight )
178 {
179     Reference< beans::XPropertySet >  xProp( SvxGetLinguPropertySet() );
180     sal_Bool bWrapReverse = xProp.is() ?
181         *(sal_Bool*)xProp->getPropertyValue(
182             ::rtl::OUString::createFromAscii(UPN_IS_WRAP_REVERSE) ).getValue()
183         : sal_False;
184     bReverse = bRevAllow && bWrapReverse;
185     bStartDone = bOther || ( !bReverse && bStart );
186     bEndDone   = bReverse && bStart && !bOther;
187 }
188 
189 // -----------------------------------------------------------------------
190 
191 SvxSpellWrapper::SvxSpellWrapper( Window* pWn,
192         Reference< XHyphenator >  &xHyphenator,
193         const sal_Bool bStart, const sal_Bool bOther ) :
194     pWin        ( pWn ),
195     xHyph       ( xHyphenator ),
196     bOtherCntnt ( bOther ),
197     bDialog     ( sal_False ),
198     bHyphen     ( sal_False ),
199     bAuto       ( sal_False ),
200     bReverse    ( sal_False ),
201     bStartDone  ( bOther || ( !bReverse && bStart ) ),
202     bEndDone    ( bReverse && bStart && !bOther ),
203     bStartChk   ( bOther ),
204     bRevAllowed ( sal_False ),
205     bAllRight   ( sal_True )
206 {
207 }
208 
209 // -----------------------------------------------------------------------
210 
211 sal_Int16 SvxSpellWrapper::CheckSpellLang(
212         Reference< XSpellChecker1 > xSpell, sal_Int16 nLang)
213 {
214     LangCheckState_map_t &rLCS = GetLangCheckState();
215 
216     LangCheckState_map_t::iterator aIt( rLCS.find( nLang ) );
217     sal_uInt16 nVal = aIt == rLCS.end() ? SVX_LANG_NEED_CHECK : aIt->second;
218 
219     if (aIt == rLCS.end())
220         rLCS[ nLang ] = nVal;
221 
222     if (SVX_LANG_NEED_CHECK == (nVal & 0x00FF))
223     {
224         sal_uInt16 nTmpVal = SVX_LANG_MISSING_DO_WARN;
225         if (xSpell.is()  &&  xSpell->hasLanguage( nLang ))
226             nTmpVal = SVX_LANG_OK;
227         nVal &= 0xFF00;
228         nVal |= nTmpVal;
229 
230         rLCS[ nLang ] = nVal;
231     }
232 
233     return (sal_Int16) nVal;
234 }
235 
236 sal_Int16 SvxSpellWrapper::CheckHyphLang(
237         Reference< XHyphenator >  xHyph, sal_Int16 nLang)
238 {
239     LangCheckState_map_t &rLCS = GetLangCheckState();
240 
241     LangCheckState_map_t::iterator aIt( rLCS.find( nLang ) );
242     sal_uInt16 nVal = aIt == rLCS.end() ? 0 : aIt->second;
243 
244     if (aIt == rLCS.end())
245         rLCS[ nLang ] = nVal;
246 
247     if (SVX_LANG_NEED_CHECK == ((nVal >> 8) & 0x00FF))
248     {
249         sal_uInt16 nTmpVal = SVX_LANG_MISSING_DO_WARN;
250         if (xHyph.is()  &&  xHyph->hasLocale( SvxCreateLocale( nLang ) ))
251             nTmpVal = SVX_LANG_OK;
252         nVal &= 0x00FF;
253         nVal |= nTmpVal << 8;
254 
255         rLCS[ nLang ] = nVal;
256     }
257 
258     return (sal_Int16) nVal;
259 }
260 
261 // -----------------------------------------------------------------------
262 
263 
264 void SvxSpellWrapper::SpellStart( SvxSpellArea /*eSpell*/ )
265 {   // Hier muessen die notwendigen Vorbereitungen fuer SpellContinue
266 }   // im uebergebenen Bereich getroffen werden.
267 
268 // -----------------------------------------------------------------------
269 
270 
271 sal_Bool SvxSpellWrapper::HasOtherCnt()
272 {
273     return sal_False; // Gibt es ueberhaupt einen Sonderbereich?
274 }
275 
276 // -----------------------------------------------------------------------
277 
278 
279 sal_Bool SvxSpellWrapper::SpellMore()
280 {
281     return sal_False; // Sollen weitere Dokumente geprueft werden?
282 }
283 
284 // -----------------------------------------------------------------------
285 
286 
287 void SvxSpellWrapper::SpellEnd()
288 {   // Bereich ist abgeschlossen, ggf. Aufraeumen
289 
290     // display error for last language not found
291     ShowLanguageErrors();
292 }
293 
294 // -----------------------------------------------------------------------
295 
296 
297 sal_Bool SvxSpellWrapper::SpellContinue()
298 {
299     return sal_False;
300 }
301 
302 // -----------------------------------------------------------------------
303 
304 void SvxSpellWrapper::AutoCorrect( const String&, const String& )
305 {
306 }
307 
308 // -----------------------------------------------------------------------
309 
310 
311 void SvxSpellWrapper::ScrollArea()
312 {   // Scrollarea einstellen
313 }
314 
315 // -----------------------------------------------------------------------
316 
317 
318 void SvxSpellWrapper::ChangeWord( const String&, const sal_uInt16 )
319 {   // Wort ersetzen
320 }
321 
322 // -----------------------------------------------------------------------
323 
324 
325 String SvxSpellWrapper::GetThesWord()
326 {
327     // Welches Wort soll nachgeschlagen werden?
328     return String();
329 }
330 
331 // -----------------------------------------------------------------------
332 
333 
334 void SvxSpellWrapper::ChangeThesWord( const String& )
335 {
336     // Wort wg. Thesaurus ersetzen
337 }
338 
339 // -----------------------------------------------------------------------
340 
341 void SvxSpellWrapper::StartThesaurus( const String &rWord, sal_uInt16 nLanguage )
342 {
343     Reference< XThesaurus >  xThes( SvxGetThesaurus() );
344     if (!xThes.is())
345     {
346         InfoBox( pWin, EE_RESSTR( RID_SVXSTR_HMERR_THESAURUS ) ).Execute();
347         return;
348     }
349 
350     WAIT_ON();  // while looking up for initial word
351     EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create();
352     AbstractThesaurusDialog* pDlg = pFact->CreateThesaurusDialog( pWin, xThes, rWord, nLanguage );
353     WAIT_OFF();
354     if ( pDlg->Execute()== RET_OK )
355     {
356         ChangeThesWord( pDlg->GetWord() );
357     }
358     delete pDlg;
359 }
360 
361 // -----------------------------------------------------------------------
362 
363 void SvxSpellWrapper::ReplaceAll( const String &, sal_Int16 )
364 {   // Wort aus der Replace-Liste ersetzen
365 }
366 
367 // -----------------------------------------------------------------------
368 
369 
370 void SvxSpellWrapper::SetLanguage( const sal_uInt16 )
371 {   // Sprache aendern
372 }
373 
374 // -----------------------------------------------------------------------
375 
376 
377 void SvxSpellWrapper::InsertHyphen( const sal_uInt16 )
378 {   // Hyphen einfuegen bzw. loeschen
379 }
380 
381 // -----------------------------------------------------------------------
382 // Pruefung der Dokumentbereiche in der durch die Flags angegebenen Reihenfolge
383 
384 
385 void SvxSpellWrapper::SpellDocument( )
386 {
387     if ( bOtherCntnt )
388     {
389         bReverse = sal_False;
390         SpellStart( SVX_SPELL_OTHER );
391     }
392     else
393     {
394         bStartChk = bReverse;
395         SpellStart( bReverse ? SVX_SPELL_BODY_START : SVX_SPELL_BODY_END );
396     }
397 
398     if ( FindSpellError() )
399     {
400         Reference< XSpellAlternatives >     xAlt( GetLast(), UNO_QUERY );
401         Reference< XHyphenatedWord >        xHyphWord( GetLast(), UNO_QUERY );
402 
403         Window *pOld = pWin;
404         bDialog = sal_True;
405         if (xHyphWord.is())
406         {
407             EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create();
408             AbstractHyphenWordDialog* pDlg = pFact->CreateHyphenWordDialog( pWin,
409                             xHyphWord->getWord(),
410                             SvxLocaleToLanguage( xHyphWord->getLocale() ),
411                             xHyph, this );
412             pWin = pDlg->GetWindow();
413             pDlg->Execute();
414             delete pDlg;
415         }
416         bDialog = sal_False;
417         pWin = pOld;
418     };
419 }
420 
421 // -----------------------------------------------------------------------
422 // Naechsten Bereich auswaehlen
423 
424 
425 sal_Bool SvxSpellWrapper::SpellNext( )
426 {
427     Reference< beans::XPropertySet >  xProp( SvxGetLinguPropertySet() );
428     sal_Bool bWrapReverse = xProp.is() ?
429             *(sal_Bool*)xProp->getPropertyValue(
430                 ::rtl::OUString::createFromAscii(UPN_IS_WRAP_REVERSE) ).getValue()
431             : sal_False;
432     sal_Bool bActRev = bRevAllowed && bWrapReverse;
433 
434     // bActRev ist die Richtung nach dem Spellen, bReverse die am Anfang.
435     if( bActRev == bReverse )
436     {                           // Keine Richtungsaenderung, also ist
437         if( bStartChk )         // der gewuenschte Bereich ( bStartChk )
438             bStartDone = sal_True;  // vollstaendig abgearbeitet.
439         else
440             bEndDone = sal_True;
441     }
442     else if( bReverse == bStartChk ) // Bei einer Richtungsaenderung kann
443     {                          // u.U. auch ein Bereich abgearbeitet sein.
444         if( bStartChk )        // Sollte der vordere Teil rueckwaerts gespellt
445             bEndDone = sal_True;   // werden und wir kehren unterwegs um, so ist
446         else                   // der hintere Teil abgearbeitet (und umgekehrt).
447             bStartDone = sal_True;
448     }
449 
450     bReverse = bActRev;
451     if( bOtherCntnt && bStartDone && bEndDone ) // Dokument komplett geprueft?
452     {
453         if ( SpellMore() )  // ein weiteres Dokument pruefen?
454         {
455             bOtherCntnt = sal_False;
456             bStartDone = !bReverse;
457             bEndDone  = bReverse;
458             SpellStart( SVX_SPELL_BODY );
459             return sal_True;
460         }
461         return sal_False;
462     }
463 
464     sal_Bool bGoOn = sal_False;
465 
466     if ( bOtherCntnt )
467     {
468         bStartChk = sal_False;
469         SpellStart( SVX_SPELL_BODY );
470         bGoOn = sal_True;
471     }
472     else if ( bStartDone && bEndDone )
473     {
474         sal_Bool bIsSpellSpecial = xProp.is() ?
475             *(sal_Bool*)xProp->getPropertyValue(
476                 ::rtl::OUString::createFromAscii(UPN_IS_SPELL_SPECIAL) ).getValue()
477             : sal_False;
478         // Bodybereich erledigt, Frage nach Sonderbereich
479         if( !IsHyphen() && bIsSpellSpecial && HasOtherCnt() )
480         {
481             SpellStart( SVX_SPELL_OTHER );
482             bOtherCntnt = bGoOn = sal_True;
483         }
484         else if ( SpellMore() )  // ein weiteres Dokument pruefen?
485         {
486             bOtherCntnt = sal_False;
487             bStartDone = !bReverse;
488             bEndDone  = bReverse;
489             SpellStart( SVX_SPELL_BODY );
490             return sal_True;
491         }
492     }
493     else
494     {
495         // Ein BODY_Bereich erledigt, Frage nach dem anderen BODY_Bereich
496         WAIT_OFF();
497 
498 // Sobald im Dialog das DontWrapAround gesetzt werden kann, kann der
499 // folgende #ifdef-Zweig aktiviert werden ...
500 #ifdef USED
501         sal_Bool bDontWrapAround = IsHyphen() ?
502             pSpell->GetOptions() & DONT_WRAPAROUND :
503             pSpell->GetHyphOptions() & HYPH_DONT_WRAPAROUND;
504         if( bDontWrapAround )
505 #else
506         sal_uInt16 nResId = bReverse ? RID_SVXQB_BW_CONTINUE : RID_SVXQB_CONTINUE;
507         QueryBox aBox( pWin, EditResId( nResId ) );
508         if ( aBox.Execute() != RET_YES )
509 #endif
510 
511         {
512             // Verzicht auf den anderen Bereich, ggf. Frage nach Sonderbereich
513             WAIT_ON();
514             bStartDone = bEndDone = sal_True;
515             return SpellNext();
516         }
517         else
518         {
519             bStartChk = !bStartDone;
520             SpellStart( bStartChk ? SVX_SPELL_BODY_START : SVX_SPELL_BODY_END );
521             bGoOn = sal_True;
522         }
523         WAIT_ON();
524     }
525     return bGoOn;
526 }
527 
528 // -----------------------------------------------------------------------
529 
530 Reference< XDictionary >  SvxSpellWrapper::GetAllRightDic() const
531 {
532     Reference< XDictionary >  xDic;
533 
534     Reference< XDictionaryList >  xDicList( SvxGetDictionaryList() );
535     if (xDicList.is())
536     {
537         Sequence< Reference< XDictionary >  > aDics( xDicList->getDictionaries() );
538         const Reference< XDictionary >  *pDic = aDics.getConstArray();
539         sal_Int32 nCount = aDics.getLength();
540 
541         sal_Int32 i = 0;
542         while (!xDic.is()  &&  i < nCount)
543         {
544             Reference< XDictionary >  xTmp( pDic[i], UNO_QUERY );
545             if (xTmp.is())
546             {
547                 if ( xTmp->isActive() &&
548                      xTmp->getDictionaryType() != DictionaryType_NEGATIVE &&
549                      SvxLocaleToLanguage( xTmp->getLocale() ) == LANGUAGE_NONE )
550                 {
551                     Reference< frame::XStorable >  xStor( xTmp, UNO_QUERY );
552                     if (xStor.is() && xStor->hasLocation() && !xStor->isReadonly())
553                     {
554                         xDic = xTmp;
555                     }
556                 }
557             }
558             ++i;
559         }
560 
561         if (!xDic.is())
562         {
563             xDic = SvxGetOrCreatePosDic( xDicList );
564             if (xDic.is())
565                 xDic->setActive( sal_True );
566         }
567     }
568 
569     return xDic;
570 }
571 
572 // -----------------------------------------------------------------------
573 
574 sal_Bool SvxSpellWrapper::FindSpellError()
575 {
576     ShowLanguageErrors();
577 
578     Reference< XInterface >     xRef;
579 
580     WAIT_ON();
581     sal_Bool bSpell = sal_True;
582 
583     Reference< XDictionary >  xAllRightDic;
584     if (IsAllRight())
585         xAllRightDic = GetAllRightDic();
586 
587     while ( bSpell )
588     {
589         SpellContinue();
590 
591         Reference< XSpellAlternatives >     xAlt( GetLast(), UNO_QUERY );
592         Reference< XHyphenatedWord >        xHyphWord( GetLast(), UNO_QUERY );
593 
594         if (xAlt.is())
595         {
596             if (IsAllRight() && xAllRightDic.is())
597             {
598                 xAllRightDic->add( xAlt->getWord(), sal_False, ::rtl::OUString() );
599             }
600             else
601             {
602                 // look up in ChangeAllList for misspelled word
603                 Reference< XDictionary >    xChangeAllList(
604                         SvxGetChangeAllList(), UNO_QUERY );
605                 Reference< XDictionaryEntry >   xEntry;
606                 if (xChangeAllList.is())
607                     xEntry = xChangeAllList->getEntry( xAlt->getWord() );
608 
609                 if (xEntry.is())
610                 {
611                     // replace word without asking
612                     ReplaceAll( xEntry->getReplacementText(),
613                                 SvxLocaleToLanguage( xAlt->getLocale() ) );
614                 }
615                 else
616                     bSpell = sal_False;
617             }
618         }
619         else if (xHyphWord.is())
620             bSpell = sal_False;
621         else
622         {
623             SpellEnd();
624             bSpell = SpellNext();
625         }
626     }
627     WAIT_OFF();
628     return GetLast().is();
629 }
630 
631 
632 
633