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