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