xref: /AOO41X/main/editeng/source/misc/splwrap.cxx (revision 8809db7a87f97847b57a57f4cd2b0104b2b83182)
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 
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 {
98     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 
106 static LangCheckState_map_t & GetLangCheckState()
107 {
108     static LangCheckState_map_t aLangCheckState;
109     return aLangCheckState;
110 }
111 
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 
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 
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     bOtherCntnt ( bOther ),
168     bDialog     ( sal_False ),
169     bHyphen     ( sal_False ),
170     bAuto       ( sal_False ),
171     bStartChk   ( bOther ),
172     bRevAllowed ( bRevAllow ),
173     bAllRight   ( bIsAllRight )
174 {
175     Reference< beans::XPropertySet >  xProp( SvxGetLinguPropertySet() );
176     sal_Bool bWrapReverse = xProp.is() ?
177         *(sal_Bool*)xProp->getPropertyValue(
178             ::rtl::OUString::createFromAscii(UPN_IS_WRAP_REVERSE) ).getValue()
179         : sal_False;
180     bReverse = bRevAllow && bWrapReverse;
181     bStartDone = bOther || ( !bReverse && bStart );
182     bEndDone   = bReverse && bStart && !bOther;
183 }
184 
185 // -----------------------------------------------------------------------
186 
187 SvxSpellWrapper::SvxSpellWrapper( Window* pWn,
188         Reference< XHyphenator >  &xHyphenator,
189         const sal_Bool bStart, const sal_Bool bOther ) :
190     pWin        ( pWn ),
191     xHyph       ( xHyphenator ),
192     bOtherCntnt ( bOther ),
193     bDialog     ( sal_False ),
194     bHyphen     ( sal_False ),
195     bAuto       ( sal_False ),
196     bReverse    ( sal_False ),
197     bStartDone  ( bOther || ( !bReverse && bStart ) ),
198     bEndDone    ( bReverse && bStart && !bOther ),
199     bStartChk   ( bOther ),
200     bRevAllowed ( sal_False ),
201     bAllRight   ( sal_True )
202 {
203 }
204 
205 // -----------------------------------------------------------------------
206 
207 sal_Int16 SvxSpellWrapper::CheckSpellLang(
208         Reference< XSpellChecker1 > xSpell, sal_Int16 nLang)
209 {
210     LangCheckState_map_t &rLCS = GetLangCheckState();
211 
212     LangCheckState_map_t::iterator aIt( rLCS.find( nLang ) );
213     sal_uInt16 nVal = aIt == rLCS.end() ? SVX_LANG_NEED_CHECK : aIt->second;
214 
215     if (aIt == rLCS.end())
216         rLCS[ nLang ] = nVal;
217 
218     if (SVX_LANG_NEED_CHECK == (nVal & 0x00FF))
219     {
220         sal_uInt16 nTmpVal = SVX_LANG_MISSING_DO_WARN;
221         if (xSpell.is()  &&  xSpell->hasLanguage( nLang ))
222             nTmpVal = SVX_LANG_OK;
223         nVal &= 0xFF00;
224         nVal |= nTmpVal;
225 
226         rLCS[ nLang ] = nVal;
227     }
228 
229     return (sal_Int16) nVal;
230 }
231 
232 sal_Int16 SvxSpellWrapper::CheckHyphLang(
233         Reference< XHyphenator >  xHyph, sal_Int16 nLang)
234 {
235     LangCheckState_map_t &rLCS = GetLangCheckState();
236 
237     LangCheckState_map_t::iterator aIt( rLCS.find( nLang ) );
238     sal_uInt16 nVal = aIt == rLCS.end() ? 0 : aIt->second;
239 
240     if (aIt == rLCS.end())
241         rLCS[ nLang ] = nVal;
242 
243     if (SVX_LANG_NEED_CHECK == ((nVal >> 8) & 0x00FF))
244     {
245         sal_uInt16 nTmpVal = SVX_LANG_MISSING_DO_WARN;
246         if (xHyph.is()  &&  xHyph->hasLocale( SvxCreateLocale( nLang ) ))
247             nTmpVal = SVX_LANG_OK;
248         nVal &= 0x00FF;
249         nVal |= nTmpVal << 8;
250 
251         rLCS[ nLang ] = nVal;
252     }
253 
254     return (sal_Int16) nVal;
255 }
256 
257 // -----------------------------------------------------------------------
258 
259 
260 void SvxSpellWrapper::SpellStart( SvxSpellArea /*eSpell*/ )
261 {   // Hier muessen die notwendigen Vorbereitungen fuer SpellContinue
262 }   // im uebergebenen Bereich getroffen werden.
263 
264 // -----------------------------------------------------------------------
265 
266 
267 sal_Bool SvxSpellWrapper::HasOtherCnt()
268 {
269     return sal_False; // Gibt es ueberhaupt einen Sonderbereich?
270 }
271 
272 // -----------------------------------------------------------------------
273 
274 
275 sal_Bool SvxSpellWrapper::SpellMore()
276 {
277     return sal_False; // Sollen weitere Dokumente geprueft werden?
278 }
279 
280 // -----------------------------------------------------------------------
281 
282 
283 void SvxSpellWrapper::SpellEnd()
284 {   // Bereich ist abgeschlossen, ggf. Aufraeumen
285 
286     // display error for last language not found
287     ShowLanguageErrors();
288 }
289 
290 // -----------------------------------------------------------------------
291 
292 
293 sal_Bool SvxSpellWrapper::SpellContinue()
294 {
295     return sal_False;
296 }
297 
298 // -----------------------------------------------------------------------
299 
300 void SvxSpellWrapper::AutoCorrect( const String&, const String& )
301 {
302 }
303 
304 // -----------------------------------------------------------------------
305 
306 
307 void SvxSpellWrapper::ScrollArea()
308 {   // Scrollarea einstellen
309 }
310 
311 // -----------------------------------------------------------------------
312 
313 
314 void SvxSpellWrapper::ChangeWord( const String&, const sal_uInt16 )
315 {   // Wort ersetzen
316 }
317 
318 // -----------------------------------------------------------------------
319 
320 
321 String SvxSpellWrapper::GetThesWord()
322 {
323     // Welches Wort soll nachgeschlagen werden?
324     return String();
325 }
326 
327 // -----------------------------------------------------------------------
328 
329 
330 void SvxSpellWrapper::ChangeThesWord( const String& )
331 {
332     // Wort wg. Thesaurus ersetzen
333 }
334 
335 // -----------------------------------------------------------------------
336 
337 void SvxSpellWrapper::StartThesaurus( const String &rWord, sal_uInt16 nLanguage )
338 {
339     Reference< XThesaurus >  xThes( SvxGetThesaurus() );
340     if (!xThes.is())
341     {
342         InfoBox( pWin, EE_RESSTR( RID_SVXSTR_HMERR_THESAURUS ) ).Execute();
343         return;
344     }
345 
346     WAIT_ON();  // while looking up for initial word
347     EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create();
348     AbstractThesaurusDialog* pDlg = pFact->CreateThesaurusDialog( pWin, xThes, rWord, nLanguage );
349     WAIT_OFF();
350     if ( pDlg->Execute()== RET_OK )
351     {
352         ChangeThesWord( pDlg->GetWord() );
353     }
354     delete pDlg;
355 }
356 
357 // -----------------------------------------------------------------------
358 
359 void SvxSpellWrapper::ReplaceAll( const String &, sal_Int16 )
360 {   // Wort aus der Replace-Liste ersetzen
361 }
362 
363 // -----------------------------------------------------------------------
364 
365 
366 void SvxSpellWrapper::SetLanguage( const sal_uInt16 )
367 {   // Sprache aendern
368 }
369 
370 // -----------------------------------------------------------------------
371 
372 
373 void SvxSpellWrapper::InsertHyphen( const sal_uInt16 )
374 {   // Hyphen einfuegen bzw. loeschen
375 }
376 
377 // -----------------------------------------------------------------------
378 // Pruefung der Dokumentbereiche in der durch die Flags angegebenen Reihenfolge
379 
380 
381 void SvxSpellWrapper::SpellDocument( )
382 {
383     if ( bOtherCntnt )
384     {
385         bReverse = sal_False;
386         SpellStart( SVX_SPELL_OTHER );
387     }
388     else
389     {
390         bStartChk = bReverse;
391         SpellStart( bReverse ? SVX_SPELL_BODY_START : SVX_SPELL_BODY_END );
392     }
393 
394     if ( FindSpellError() )
395     {
396         Reference< XSpellAlternatives >     xAlt( GetLast(), UNO_QUERY );
397         Reference< XHyphenatedWord >        xHyphWord( GetLast(), UNO_QUERY );
398 
399         Window *pOld = pWin;
400         bDialog = sal_True;
401         if (xHyphWord.is())
402         {
403             EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create();
404             AbstractHyphenWordDialog* pDlg = pFact->CreateHyphenWordDialog( pWin,
405                             xHyphWord->getWord(),
406                             SvxLocaleToLanguage( xHyphWord->getLocale() ),
407                             xHyph, this );
408             pWin = pDlg->GetWindow();
409             pDlg->Execute();
410             delete pDlg;
411         }
412         bDialog = sal_False;
413         pWin = pOld;
414     };
415 }
416 
417 // -----------------------------------------------------------------------
418 // Naechsten Bereich auswaehlen
419 
420 
421 sal_Bool SvxSpellWrapper::SpellNext( )
422 {
423     Reference< beans::XPropertySet >  xProp( SvxGetLinguPropertySet() );
424     sal_Bool bWrapReverse = xProp.is() ?
425             *(sal_Bool*)xProp->getPropertyValue(
426                 ::rtl::OUString::createFromAscii(UPN_IS_WRAP_REVERSE) ).getValue()
427             : sal_False;
428     sal_Bool bActRev = bRevAllowed && bWrapReverse;
429 
430     // bActRev ist die Richtung nach dem Spellen, bReverse die am Anfang.
431     if( bActRev == bReverse )
432     {                           // Keine Richtungsaenderung, also ist
433         if( bStartChk )         // der gewuenschte Bereich ( bStartChk )
434             bStartDone = sal_True;  // vollstaendig abgearbeitet.
435         else
436             bEndDone = sal_True;
437     }
438     else if( bReverse == bStartChk ) // Bei einer Richtungsaenderung kann
439     {                          // u.U. auch ein Bereich abgearbeitet sein.
440         if( bStartChk )        // Sollte der vordere Teil rueckwaerts gespellt
441             bEndDone = sal_True;   // werden und wir kehren unterwegs um, so ist
442         else                   // der hintere Teil abgearbeitet (und umgekehrt).
443             bStartDone = sal_True;
444     }
445 
446     bReverse = bActRev;
447     if( bOtherCntnt && bStartDone && bEndDone ) // Dokument komplett geprueft?
448     {
449         if ( SpellMore() )  // ein weiteres Dokument pruefen?
450         {
451             bOtherCntnt = sal_False;
452             bStartDone = !bReverse;
453             bEndDone  = bReverse;
454             SpellStart( SVX_SPELL_BODY );
455             return sal_True;
456         }
457         return sal_False;
458     }
459 
460     sal_Bool bGoOn = sal_False;
461 
462     if ( bOtherCntnt )
463     {
464         bStartChk = sal_False;
465         SpellStart( SVX_SPELL_BODY );
466         bGoOn = sal_True;
467     }
468     else if ( bStartDone && bEndDone )
469     {
470         sal_Bool bIsSpellSpecial = xProp.is() ?
471             *(sal_Bool*)xProp->getPropertyValue(
472                 ::rtl::OUString::createFromAscii(UPN_IS_SPELL_SPECIAL) ).getValue()
473             : sal_False;
474         // Bodybereich erledigt, Frage nach Sonderbereich
475         if( !IsHyphen() && bIsSpellSpecial && HasOtherCnt() )
476         {
477             SpellStart( SVX_SPELL_OTHER );
478             bOtherCntnt = bGoOn = sal_True;
479         }
480         else if ( SpellMore() )  // ein weiteres Dokument pruefen?
481         {
482             bOtherCntnt = sal_False;
483             bStartDone = !bReverse;
484             bEndDone  = bReverse;
485             SpellStart( SVX_SPELL_BODY );
486             return sal_True;
487         }
488     }
489     else
490     {
491         // Ein BODY_Bereich erledigt, Frage nach dem anderen BODY_Bereich
492         WAIT_OFF();
493 
494 // Sobald im Dialog das DontWrapAround gesetzt werden kann, kann der
495 // folgende #ifdef-Zweig aktiviert werden ...
496 #ifdef USED
497         sal_Bool bDontWrapAround = IsHyphen() ?
498             pSpell->GetOptions() & DONT_WRAPAROUND :
499             pSpell->GetHyphOptions() & HYPH_DONT_WRAPAROUND;
500         if( bDontWrapAround )
501 #else
502         sal_uInt16 nResId = bReverse ? RID_SVXQB_BW_CONTINUE : RID_SVXQB_CONTINUE;
503         QueryBox aBox( pWin, EditResId( nResId ) );
504         if ( aBox.Execute() != RET_YES )
505 #endif
506 
507         {
508             // Verzicht auf den anderen Bereich, ggf. Frage nach Sonderbereich
509             WAIT_ON();
510             bStartDone = bEndDone = sal_True;
511             return SpellNext();
512         }
513         else
514         {
515             bStartChk = !bStartDone;
516             SpellStart( bStartChk ? SVX_SPELL_BODY_START : SVX_SPELL_BODY_END );
517             bGoOn = sal_True;
518         }
519         WAIT_ON();
520     }
521     return bGoOn;
522 }
523 
524 // -----------------------------------------------------------------------
525 
526 Reference< XDictionary >  SvxSpellWrapper::GetAllRightDic() const
527 {
528     Reference< XDictionary >  xDic;
529 
530     Reference< XDictionaryList >  xDicList( SvxGetDictionaryList() );
531     if (xDicList.is())
532     {
533         Sequence< Reference< XDictionary >  > aDics( xDicList->getDictionaries() );
534         const Reference< XDictionary >  *pDic = aDics.getConstArray();
535         sal_Int32 nCount = aDics.getLength();
536 
537         sal_Int32 i = 0;
538         while (!xDic.is()  &&  i < nCount)
539         {
540             Reference< XDictionary >  xTmp( pDic[i], UNO_QUERY );
541             if (xTmp.is())
542             {
543                 if ( xTmp->isActive() &&
544                      xTmp->getDictionaryType() != DictionaryType_NEGATIVE &&
545                      SvxLocaleToLanguage( xTmp->getLocale() ) == LANGUAGE_NONE )
546                 {
547                     Reference< frame::XStorable >  xStor( xTmp, UNO_QUERY );
548                     if (xStor.is() && xStor->hasLocation() && !xStor->isReadonly())
549                     {
550                         xDic = xTmp;
551                     }
552                 }
553             }
554             ++i;
555         }
556 
557         if (!xDic.is())
558         {
559             xDic = SvxGetOrCreatePosDic( xDicList );
560             if (xDic.is())
561                 xDic->setActive( sal_True );
562         }
563     }
564 
565     return xDic;
566 }
567 
568 // -----------------------------------------------------------------------
569 
570 sal_Bool SvxSpellWrapper::FindSpellError()
571 {
572     ShowLanguageErrors();
573 
574     Reference< XInterface >     xRef;
575 
576     WAIT_ON();
577     sal_Bool bSpell = sal_True;
578 
579     Reference< XDictionary >  xAllRightDic;
580     if (IsAllRight())
581         xAllRightDic = GetAllRightDic();
582 
583     while ( bSpell )
584     {
585         SpellContinue();
586 
587         Reference< XSpellAlternatives >     xAlt( GetLast(), UNO_QUERY );
588         Reference< XHyphenatedWord >        xHyphWord( GetLast(), UNO_QUERY );
589 
590         if (xAlt.is())
591         {
592             if (IsAllRight() && xAllRightDic.is())
593             {
594                 xAllRightDic->add( xAlt->getWord(), sal_False, ::rtl::OUString() );
595             }
596             else
597             {
598                 // look up in ChangeAllList for misspelled word
599                 Reference< XDictionary >    xChangeAllList(
600                         SvxGetChangeAllList(), UNO_QUERY );
601                 Reference< XDictionaryEntry >   xEntry;
602                 if (xChangeAllList.is())
603                     xEntry = xChangeAllList->getEntry( xAlt->getWord() );
604 
605                 if (xEntry.is())
606                 {
607                     // replace word without asking
608                     ReplaceAll( xEntry->getReplacementText(),
609                                 SvxLocaleToLanguage( xAlt->getLocale() ) );
610                 }
611                 else
612                     bSpell = sal_False;
613             }
614         }
615         else if (xHyphWord.is())
616             bSpell = sal_False;
617         else
618         {
619             SpellEnd();
620             bSpell = SpellNext();
621         }
622     }
623     WAIT_OFF();
624     return GetLast().is();
625 }
626 
627 
628 
629