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