xref: /aoo42x/main/editeng/source/misc/splwrap.cxx (revision 190118d0)
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