1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: splwrap.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
33 #include<rtl/ustring.hxx>
34 #include <tools/shl.hxx>
35 #include <vcl/wrkwin.hxx>
36 #include <vcl/svapp.hxx>
37 #include <vcl/msgbox.hxx>
38 #include <tools/debug.hxx>
41 #include <tools/errinf.hxx>
44 #include <dlgutil.hxx>
45 #include <unolingu.hxx>
46 #include <sfx2/sfxuno.hxx>
47 #include <linguistic/lngprops.hxx>
48 #include <com/sun/star/frame/XStorable.hpp>
52 #include <svx/svxenum.hxx>
53 #include "hyphen.hxx" // Der HyphenDialog
54 #include <svx/splwrap.hxx> // Der Wrapper
55 #include <svx/thesdlg.hxx> // ThesaurusDlg
56 #include <svx/dialmgr.hxx>
58 #include <svx/dialogs.hrc>
61 #define WAIT_ON() if(pWin != NULL) { pWin->EnterWait(); }
63 #define WAIT_OFF() if(pWin != NULL) { pWin->LeaveWait(); }
65 using namespace ::com::sun::star
;
66 using namespace ::com::sun::star::uno
;
67 using namespace ::com::sun::star::beans
;
68 using namespace ::com::sun::star::linguistic2
;
71 // misc functions ---------------------------------------------
73 void SvxPrepareAutoCorrect( String
&rOldText
, String
&rNewText
)
75 // This function should be used to strip (or add) trailing '.' from
76 // the strings before passing them on to the autocorrect function in
77 // order that the autocorrect function will hopefully
78 // works properly with normal words and abbreviations (with trailing '.')
79 // independ of if they are at the end of the sentence or not.
81 // rOldText: text to be replaced
82 // rNewText: replacement text
84 xub_StrLen nOldLen
= rOldText
.Len(),
85 nNewLen
= rNewText
.Len();
86 if (nOldLen
&& nNewLen
)
88 sal_Bool bOldHasDot
= sal_Unicode( '.' ) == rOldText
.GetChar( nOldLen
- 1 ),
89 bNewHasDot
= sal_Unicode( '.' ) == rNewText
.GetChar( nNewLen
- 1 );
90 if (bOldHasDot
&& !bNewHasDot
91 /*this is: !(bOldHasDot && bNewHasDot) && bOldHasDot*/)
92 rOldText
.Erase( nOldLen
- 1 );
96 // -----------------------------------------------------------------------
98 #define SVX_LANG_NEED_CHECK 0
100 #define SVX_LANG_MISSING 2
101 #define SVX_LANG_MISSING_DO_WARN 3
103 #define SVX_FLAGS_NEW
106 struct lt_LanguageType
108 bool operator()( LanguageType n1
, LanguageType n2
) const
114 typedef std::map
< LanguageType
, USHORT
, lt_LanguageType
> LangCheckState_map_t
;
116 static LangCheckState_map_t
& GetLangCheckState()
118 static LangCheckState_map_t aLangCheckState
;
119 return aLangCheckState
;
122 void SvxSpellWrapper::ShowLanguageErrors()
124 // display message boxes for languages not available for
125 // spellchecking or hyphenation
126 LangCheckState_map_t
&rLCS
= GetLangCheckState();
127 LangCheckState_map_t::iterator
aIt( rLCS
.begin() );
128 while (aIt
!= rLCS
.end())
130 LanguageType nLang
= aIt
->first
;
131 sal_uInt16 nVal
= aIt
->second
;
132 sal_uInt16 nTmpSpell
= nVal
& 0x00FF;
133 sal_uInt16 nTmpHyph
= (nVal
>> 8) & 0x00FF;
135 if (SVX_LANG_MISSING_DO_WARN
== nTmpSpell
)
137 String
aErr( ::GetLanguageString( nLang
) );
138 ErrorHandler::HandleError(
139 *new StringErrorInfo( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS
, aErr
) );
140 nTmpSpell
= SVX_LANG_MISSING
;
142 if (SVX_LANG_MISSING_DO_WARN
== nTmpHyph
)
144 String
aErr( ::GetLanguageString( nLang
) );
145 ErrorHandler::HandleError(
146 *new StringErrorInfo( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS
, aErr
) );
147 nTmpHyph
= SVX_LANG_MISSING
;
150 rLCS
[ nLang
] = (nTmpHyph
<< 8) | nTmpSpell
;
156 SvxSpellWrapper::~SvxSpellWrapper()
160 /*--------------------------------------------------------------------
161 * Beschreibung: Ctor, die Pruefreihenfolge wird festgelegt
163 * !bStart && !bOtherCntnt: BODY_END, BODY_START, OTHER
164 * !bStart && bOtherCntnt: OTHER, BODY
165 * bStart && !bOtherCntnt: BODY_END, OTHER
166 * bStart && bOtherCntnt: OTHER
168 --------------------------------------------------------------------*/
170 SvxSpellWrapper::SvxSpellWrapper( Window
* pWn
,
171 Reference
< XSpellChecker1
> &xSpellChecker
,
172 const sal_Bool bStart
, const sal_Bool bIsAllRight
,
173 const sal_Bool bOther
, const sal_Bool bRevAllow
) :
176 xSpell ( xSpellChecker
),
177 bOtherCntnt ( bOther
),
178 bDialog ( sal_False
),
179 bHyphen ( sal_False
),
181 bStartChk ( bOther
),
182 bRevAllowed ( bRevAllow
),
183 bAllRight ( bIsAllRight
)
185 Reference
< beans::XPropertySet
> xProp( SvxGetLinguPropertySet() );
186 sal_Bool bWrapReverse
= xProp
.is() ?
187 *(sal_Bool
*)xProp
->getPropertyValue(
188 ::rtl::OUString::createFromAscii(UPN_IS_WRAP_REVERSE
) ).getValue()
190 bReverse
= bRevAllow
&& bWrapReverse
;
191 bStartDone
= bOther
|| ( !bReverse
&& bStart
);
192 bEndDone
= bReverse
&& bStart
&& !bOther
;
195 // -----------------------------------------------------------------------
197 SvxSpellWrapper::SvxSpellWrapper( Window
* pWn
,
198 Reference
< XHyphenator
> &xHyphenator
,
199 const sal_Bool bStart
, const sal_Bool bOther
) :
201 xHyph ( xHyphenator
),
202 bOtherCntnt ( bOther
),
203 bDialog ( sal_False
),
204 bHyphen ( sal_False
),
206 bReverse ( sal_False
),
207 bStartDone ( bOther
|| ( !bReverse
&& bStart
) ),
208 bEndDone ( bReverse
&& bStart
&& !bOther
),
209 bStartChk ( bOther
),
210 bRevAllowed ( sal_False
),
211 bAllRight ( sal_True
)
215 // -----------------------------------------------------------------------
217 sal_Int16
SvxSpellWrapper::CheckSpellLang(
218 Reference
< XSpellChecker1
> xSpell
, sal_Int16 nLang
)
220 LangCheckState_map_t
&rLCS
= GetLangCheckState();
222 LangCheckState_map_t::iterator
aIt( rLCS
.find( nLang
) );
223 sal_uInt16 nVal
= aIt
== rLCS
.end() ? SVX_LANG_NEED_CHECK
: aIt
->second
;
225 if (aIt
== rLCS
.end())
226 rLCS
[ nLang
] = nVal
;
228 if (SVX_LANG_NEED_CHECK
== (nVal
& 0x00FF))
230 sal_uInt16 nTmpVal
= SVX_LANG_MISSING_DO_WARN
;
231 if (xSpell
.is() && xSpell
->hasLanguage( nLang
))
232 nTmpVal
= SVX_LANG_OK
;
236 rLCS
[ nLang
] = nVal
;
239 return (sal_Int16
) nVal
;
242 sal_Int16
SvxSpellWrapper::CheckHyphLang(
243 Reference
< XHyphenator
> xHyph
, sal_Int16 nLang
)
245 LangCheckState_map_t
&rLCS
= GetLangCheckState();
247 LangCheckState_map_t::iterator
aIt( rLCS
.find( nLang
) );
248 sal_uInt16 nVal
= aIt
== rLCS
.end() ? 0 : aIt
->second
;
250 if (aIt
== rLCS
.end())
251 rLCS
[ nLang
] = nVal
;
253 if (SVX_LANG_NEED_CHECK
== ((nVal
>> 8) & 0x00FF))
255 sal_uInt16 nTmpVal
= SVX_LANG_MISSING_DO_WARN
;
256 if (xHyph
.is() && xHyph
->hasLocale( SvxCreateLocale( nLang
) ))
257 nTmpVal
= SVX_LANG_OK
;
259 nVal
|= nTmpVal
<< 8;
261 rLCS
[ nLang
] = nVal
;
264 return (sal_Int16
) nVal
;
267 // -----------------------------------------------------------------------
270 void SvxSpellWrapper::SpellStart( SvxSpellArea
/*eSpell*/ )
271 { // Hier muessen die notwendigen Vorbereitungen fuer SpellContinue
272 } // im uebergebenen Bereich getroffen werden.
274 // -----------------------------------------------------------------------
277 sal_Bool
SvxSpellWrapper::HasOtherCnt()
279 return sal_False
; // Gibt es ueberhaupt einen Sonderbereich?
282 // -----------------------------------------------------------------------
285 sal_Bool
SvxSpellWrapper::SpellMore()
287 return sal_False
; // Sollen weitere Dokumente geprueft werden?
290 // -----------------------------------------------------------------------
293 void SvxSpellWrapper::SpellEnd()
294 { // Bereich ist abgeschlossen, ggf. Aufraeumen
296 // display error for last language not found
297 ShowLanguageErrors();
300 // -----------------------------------------------------------------------
303 sal_Bool
SvxSpellWrapper::SpellContinue()
308 // -----------------------------------------------------------------------
310 void SvxSpellWrapper::AutoCorrect( const String
&, const String
& )
314 // -----------------------------------------------------------------------
317 void SvxSpellWrapper::ScrollArea()
318 { // Scrollarea einstellen
321 // -----------------------------------------------------------------------
324 void SvxSpellWrapper::ChangeWord( const String
&, const sal_uInt16
)
328 // -----------------------------------------------------------------------
331 String
SvxSpellWrapper::GetThesWord()
333 // Welches Wort soll nachgeschlagen werden?
337 // -----------------------------------------------------------------------
340 void SvxSpellWrapper::ChangeThesWord( const String
& )
342 // Wort wg. Thesaurus ersetzen
345 // -----------------------------------------------------------------------
347 void SvxSpellWrapper::StartThesaurus( const String
&rWord
, sal_uInt16 nLanguage
)
350 String
sErr( SVX_RES( RID_SVXSTR_HMERR_THESAURUS
) );
352 Reference
< XThesaurus
> xThes( SvxGetThesaurus() );
355 InfoBox( pWin
, sErr
).Execute();
359 WAIT_ON(); // while looking up for initial word
360 SvxThesaurusDialog
aDlg(pWin
, xThes
, rWord
, nLanguage
);
363 if ( aDlg
.Execute()== RET_OK
)
365 ChangeThesWord( aDlg
.GetWord() );
370 // -----------------------------------------------------------------------
372 void SvxSpellWrapper::ReplaceAll( const String
&, sal_Int16
)
373 { // Wort aus der Replace-Liste ersetzen
376 // -----------------------------------------------------------------------
379 void SvxSpellWrapper::SetLanguage( const sal_uInt16
)
383 // -----------------------------------------------------------------------
386 void SvxSpellWrapper::InsertHyphen( const sal_uInt16
)
387 { // Hyphen einfuegen bzw. loeschen
390 // -----------------------------------------------------------------------
391 // Pruefung der Dokumentbereiche in der durch die Flags angegebenen Reihenfolge
394 void SvxSpellWrapper::SpellDocument( )
398 bReverse
= sal_False
;
399 SpellStart( SVX_SPELL_OTHER
);
403 bStartChk
= bReverse
;
404 SpellStart( bReverse
? SVX_SPELL_BODY_START
: SVX_SPELL_BODY_END
);
407 if ( FindSpellError() )
409 Reference
< XSpellAlternatives
> xAlt( GetLast(), UNO_QUERY
);
410 Reference
< XHyphenatedWord
> xHyphWord( GetLast(), UNO_QUERY
);
416 DBG_ASSERT(xHyphWord
.is(), "NULL pointer");
417 SvxHyphenWordDialog
* pDlg
=
418 new SvxHyphenWordDialog( xHyphWord
->getWord(),
419 SvxLocaleToLanguage( xHyphWord
->getLocale() ),
430 // -----------------------------------------------------------------------
431 // Naechsten Bereich auswaehlen
434 sal_Bool
SvxSpellWrapper::SpellNext( )
436 Reference
< beans::XPropertySet
> xProp( SvxGetLinguPropertySet() );
437 sal_Bool bWrapReverse
= xProp
.is() ?
438 *(sal_Bool
*)xProp
->getPropertyValue(
439 ::rtl::OUString::createFromAscii(UPN_IS_WRAP_REVERSE
) ).getValue()
441 sal_Bool bActRev
= bRevAllowed
&& bWrapReverse
;
443 // bActRev ist die Richtung nach dem Spellen, bReverse die am Anfang.
444 if( bActRev
== bReverse
)
445 { // Keine Richtungsaenderung, also ist
446 if( bStartChk
) // der gewuenschte Bereich ( bStartChk )
447 bStartDone
= sal_True
; // vollstaendig abgearbeitet.
451 else if( bReverse
== bStartChk
) // Bei einer Richtungsaenderung kann
452 { // u.U. auch ein Bereich abgearbeitet sein.
453 if( bStartChk
) // Sollte der vordere Teil rueckwaerts gespellt
454 bEndDone
= sal_True
; // werden und wir kehren unterwegs um, so ist
455 else // der hintere Teil abgearbeitet (und umgekehrt).
456 bStartDone
= sal_True
;
460 if( bOtherCntnt
&& bStartDone
&& bEndDone
) // Dokument komplett geprueft?
462 if ( SpellMore() ) // ein weiteres Dokument pruefen?
464 bOtherCntnt
= sal_False
;
465 bStartDone
= !bReverse
;
467 SpellStart( SVX_SPELL_BODY
);
473 ResMgr
& rMgr
= DIALOG_MGR();
474 sal_Bool bGoOn
= sal_False
;
478 bStartChk
= sal_False
;
479 SpellStart( SVX_SPELL_BODY
);
482 else if ( bStartDone
&& bEndDone
)
484 sal_Bool bIsSpellSpecial
= xProp
.is() ?
485 *(sal_Bool
*)xProp
->getPropertyValue(
486 ::rtl::OUString::createFromAscii(UPN_IS_SPELL_SPECIAL
) ).getValue()
488 // Bodybereich erledigt, Frage nach Sonderbereich
489 if( !IsHyphen() && bIsSpellSpecial
&& HasOtherCnt() )
491 SpellStart( SVX_SPELL_OTHER
);
492 bOtherCntnt
= bGoOn
= sal_True
;
494 else if ( SpellMore() ) // ein weiteres Dokument pruefen?
496 bOtherCntnt
= sal_False
;
497 bStartDone
= !bReverse
;
499 SpellStart( SVX_SPELL_BODY
);
505 // Ein BODY_Bereich erledigt, Frage nach dem anderen BODY_Bereich
508 // Sobald im Dialog das DontWrapAround gesetzt werden kann, kann der
509 // folgende #ifdef-Zweig aktiviert werden ...
511 sal_Bool bDontWrapAround
= IsHyphen() ?
512 pSpell
->GetOptions() & DONT_WRAPAROUND
:
513 pSpell
->GetHyphOptions() & HYPH_DONT_WRAPAROUND
;
514 if( bDontWrapAround
)
516 sal_uInt16 nResId
= bReverse
? RID_SVXQB_BW_CONTINUE
: RID_SVXQB_CONTINUE
;
517 QueryBox
aBox( pWin
, ResId( nResId
, rMgr
) );
518 if ( aBox
.Execute() != RET_YES
)
522 // Verzicht auf den anderen Bereich, ggf. Frage nach Sonderbereich
524 bStartDone
= bEndDone
= sal_True
;
529 bStartChk
= !bStartDone
;
530 SpellStart( bStartChk
? SVX_SPELL_BODY_START
: SVX_SPELL_BODY_END
);
538 // -----------------------------------------------------------------------
540 Reference
< XDictionary
> SvxSpellWrapper::GetAllRightDic() const
542 Reference
< XDictionary
> xDic
;
544 Reference
< XDictionaryList
> xDicList( SvxGetDictionaryList() );
547 Sequence
< Reference
< XDictionary
> > aDics( xDicList
->getDictionaries() );
548 const Reference
< XDictionary
> *pDic
= aDics
.getConstArray();
549 sal_Int32 nCount
= aDics
.getLength();
552 while (!xDic
.is() && i
< nCount
)
554 Reference
< XDictionary
> xTmp( pDic
[i
], UNO_QUERY
);
557 if ( xTmp
->isActive() &&
558 xTmp
->getDictionaryType() != DictionaryType_NEGATIVE
&&
559 SvxLocaleToLanguage( xTmp
->getLocale() ) == LANGUAGE_NONE
)
561 Reference
< frame::XStorable
> xStor( xTmp
, UNO_QUERY
);
562 if (xStor
.is() && xStor
->hasLocation() && !xStor
->isReadonly())
573 xDic
= SvxGetOrCreatePosDic( xDicList
);
575 xDic
->setActive( sal_True
);
582 // -----------------------------------------------------------------------
584 sal_Bool
SvxSpellWrapper::FindSpellError()
586 ShowLanguageErrors();
588 Reference
< XInterface
> xRef
;
591 sal_Bool bSpell
= sal_True
;
593 Reference
< XDictionary
> xAllRightDic
;
595 xAllRightDic
= GetAllRightDic();
601 Reference
< XSpellAlternatives
> xAlt( GetLast(), UNO_QUERY
);
602 Reference
< XHyphenatedWord
> xHyphWord( GetLast(), UNO_QUERY
);
606 if (IsAllRight() && xAllRightDic
.is())
608 xAllRightDic
->add( xAlt
->getWord(), sal_False
, ::rtl::OUString() );
612 // look up in ChangeAllList for misspelled word
613 Reference
< XDictionary
> xChangeAllList(
614 SvxGetChangeAllList(), UNO_QUERY
);
615 Reference
< XDictionaryEntry
> xEntry
;
616 if (xChangeAllList
.is())
617 xEntry
= xChangeAllList
->getEntry( xAlt
->getWord() );
621 // replace word without asking
622 ReplaceAll( xEntry
->getReplacementText(),
623 SvxLocaleToLanguage( xAlt
->getLocale() ) );
629 else if (xHyphWord
.is())
634 bSpell
= SpellNext();
638 return GetLast().is();