1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_wasm_strip.h>
22 #include <rtl/ustring.hxx>
23 #include <i18nlangtag/languagetag.hxx>
24 #include <vcl/svapp.hxx>
25 #include <vcl/weld.hxx>
26 #include <svtools/langtab.hxx>
28 #include <vcl/errinf.hxx>
29 #include <editeng/unolingu.hxx>
30 #include <com/sun/star/frame/XStorable.hpp>
31 #include <com/sun/star/linguistic2/XLinguProperties.hpp>
32 #include <com/sun/star/linguistic2/XSpellChecker1.hpp>
33 #include <com/sun/star/linguistic2/XHyphenator.hpp>
34 #include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp>
35 #include <com/sun/star/linguistic2/XDictionary.hpp>
37 #include <editeng/svxenum.hxx>
38 #include <editeng/splwrap.hxx>
39 #include <editeng/edtdlg.hxx>
40 #include <editeng/eerdll.hxx>
41 #include <editeng/editrids.hrc>
42 #include <editeng/editerr.hxx>
47 using namespace ::com::sun::star
;
48 using namespace ::com::sun::star::uno
;
49 using namespace ::com::sun::star::linguistic2
;
52 // misc functions ---------------------------------------------
54 void SvxPrepareAutoCorrect( OUString
&rOldText
, std::u16string_view rNewText
)
56 // This function should be used to strip (or add) trailing '.' from
57 // the strings before passing them on to the autocorrect function in
58 // order that the autocorrect function will hopefully
59 // works properly with normal words and abbreviations (with trailing '.')
60 // independent of if they are at the end of the sentence or not.
62 // rOldText: text to be replaced
63 // rNewText: replacement text
65 sal_Int32 nOldLen
= rOldText
.getLength();
66 sal_Int32 nNewLen
= rNewText
.size();
67 if (nOldLen
&& nNewLen
)
69 bool bOldHasDot
= '.' == rOldText
[ nOldLen
- 1 ],
70 bNewHasDot
= '.' == rNewText
[ nNewLen
- 1 ];
71 if (bOldHasDot
&& !bNewHasDot
72 /*this is: !(bOldHasDot && bNewHasDot) && bOldHasDot*/)
73 rOldText
= rOldText
.copy( 0, nOldLen
- 1 );
77 #define SVX_LANG_NEED_CHECK 0
79 #define SVX_LANG_MISSING 2
80 #define SVX_LANG_MISSING_DO_WARN 3
82 typedef std::map
< LanguageType
, sal_uInt16
> LangCheckState_map_t
;
84 static LangCheckState_map_t
& GetLangCheckState()
86 static LangCheckState_map_t aLangCheckState
;
87 return aLangCheckState
;
90 void SvxSpellWrapper::ShowLanguageErrors()
92 // display message boxes for languages not available for
93 // spellchecking or hyphenation
94 LangCheckState_map_t
&rLCS
= GetLangCheckState();
95 for (auto const& elem
: rLCS
)
97 LanguageType nLang
= elem
.first
;
98 sal_uInt16 nVal
= elem
.second
;
99 sal_uInt16 nTmpSpell
= nVal
& 0x00FF;
100 sal_uInt16 nTmpHyph
= (nVal
>> 8) & 0x00FF;
102 if (SVX_LANG_MISSING_DO_WARN
== nTmpSpell
)
104 OUString
aErr( SvtLanguageTable::GetLanguageString( nLang
) );
105 ErrorHandler::HandleError(
106 ErrCodeMsg( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS
, aErr
) );
107 nTmpSpell
= SVX_LANG_MISSING
;
109 if (SVX_LANG_MISSING_DO_WARN
== nTmpHyph
)
111 OUString
aErr( SvtLanguageTable::GetLanguageString( nLang
) );
112 ErrorHandler::HandleError(
113 ErrCodeMsg( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS
, aErr
) );
114 nTmpHyph
= SVX_LANG_MISSING
;
117 rLCS
[ nLang
] = (nTmpHyph
<< 8) | nTmpSpell
;
122 SvxSpellWrapper::~SvxSpellWrapper()
126 /*--------------------------------------------------------------------
127 * Description: Constructor, the test sequence is determined
129 * !bStart && !bOtherCntnt: BODY_END, BODY_START, OTHER
130 * !bStart && bOtherCntnt: OTHER, BODY
131 * bStart && !bOtherCntnt: BODY_END, OTHER
132 * bStart && bOtherCntnt: OTHER
134 --------------------------------------------------------------------*/
136 SvxSpellWrapper::SvxSpellWrapper( weld::Widget
* pWn
,
137 const bool bStart
, const bool bIsAllRight
) :
140 bOtherCntnt ( false ),
142 bRevAllowed ( true ),
143 bAllRight ( bIsAllRight
)
145 Reference
< linguistic2::XLinguProperties
> xProp( LinguMgr::GetLinguPropertySet() );
146 bool bWrapReverse
= xProp
.is() && xProp
->getIsWrapReverse();
147 bReverse
= bWrapReverse
;
148 bStartDone
= !bReverse
&& bStart
;
149 bEndDone
= bReverse
&& bStart
;
153 SvxSpellWrapper::SvxSpellWrapper( weld::Widget
* pWn
,
154 Reference
< XHyphenator
> const &xHyphenator
,
155 const bool bStart
, const bool bOther
) :
157 xHyph ( xHyphenator
),
158 bOtherCntnt ( bOther
),
160 bStartDone ( bOther
|| bStart
),
162 bStartChk ( bOther
),
163 bRevAllowed ( false ),
169 sal_Int16
SvxSpellWrapper::CheckSpellLang(
170 Reference
< XSpellChecker1
> const & xSpell
, LanguageType nLang
)
172 LangCheckState_map_t
&rLCS
= GetLangCheckState();
174 LangCheckState_map_t::iterator
aIt( rLCS
.find( nLang
) );
175 sal_uInt16 nVal
= aIt
== rLCS
.end() ? SVX_LANG_NEED_CHECK
: aIt
->second
;
177 if (aIt
== rLCS
.end())
178 rLCS
[ nLang
] = nVal
;
180 if (SVX_LANG_NEED_CHECK
== (nVal
& 0x00FF))
182 sal_uInt16 nTmpVal
= SVX_LANG_MISSING_DO_WARN
;
183 if (xSpell
.is() && xSpell
->hasLanguage( static_cast<sal_uInt16
>(nLang
) ))
184 nTmpVal
= SVX_LANG_OK
;
188 rLCS
[ nLang
] = nVal
;
191 return static_cast<sal_Int16
>(nVal
);
194 sal_Int16
SvxSpellWrapper::CheckHyphLang(
195 Reference
< XHyphenator
> const & xHyph
, LanguageType nLang
)
197 LangCheckState_map_t
&rLCS
= GetLangCheckState();
199 LangCheckState_map_t::iterator
aIt( rLCS
.find( nLang
) );
200 sal_uInt16 nVal
= aIt
== rLCS
.end() ? 0 : aIt
->second
;
202 if (aIt
== rLCS
.end())
203 rLCS
[ nLang
] = nVal
;
205 if (SVX_LANG_NEED_CHECK
== ((nVal
>> 8) & 0x00FF))
207 sal_uInt16 nTmpVal
= SVX_LANG_MISSING_DO_WARN
;
208 if (xHyph
.is() && xHyph
->hasLocale( LanguageTag::convertToLocale( nLang
) ))
209 nTmpVal
= SVX_LANG_OK
;
211 nVal
|= nTmpVal
<< 8;
213 rLCS
[ nLang
] = nVal
;
216 return static_cast<sal_Int16
>(nVal
);
220 void SvxSpellWrapper::SpellStart( SvxSpellArea
/*eSpell*/ )
221 { // Here, the necessary preparations be made for SpellContinue in the
225 bool SvxSpellWrapper::SpellMore()
227 return false; // Should additional documents be examined?
231 void SvxSpellWrapper::SpellEnd()
232 { // Area is complete, tidy up if necessary
234 // display error for last language not found
235 ShowLanguageErrors();
238 void SvxSpellWrapper::SpellContinue()
242 void SvxSpellWrapper::ReplaceAll( const OUString
& )
243 { // Replace Word from the Replace list
246 void SvxSpellWrapper::InsertHyphen( const sal_Int32
)
247 { // inserting and deleting Hyphen
250 // Testing of the document areas in the order specified by the flags
251 void SvxSpellWrapper::SpellDocument( )
253 #if ENABLE_WASM_STRIP_HUNSPELL
259 SpellStart( SvxSpellArea::Other
);
263 bStartChk
= bReverse
;
264 SpellStart( bReverse
? SvxSpellArea::BodyStart
: SvxSpellArea::BodyEnd
);
267 if ( !FindSpellError() )
270 Reference
< XHyphenatedWord
> xHyphWord( GetLast(), UNO_QUERY
);
274 EditAbstractDialogFactory
* pFact
= EditAbstractDialogFactory::Create();
275 ScopedVclPtr
<AbstractHyphenWordDialog
> pDlg(pFact
->CreateHyphenWordDialog(
277 xHyphWord
->getWord(),
278 LanguageTag( xHyphWord
->getLocale() ).getLanguageType(),
286 // Select the next area
289 bool SvxSpellWrapper::SpellNext( )
291 Reference
< linguistic2::XLinguProperties
> xProp( LinguMgr::GetLinguPropertySet() );
292 bool bWrapReverse
= xProp
.is() && xProp
->getIsWrapReverse();
293 bool bActRev
= bRevAllowed
&& bWrapReverse
;
295 // bActRev is the direction after Spell checking, bReverse is the one
297 if( bActRev
== bReverse
)
298 { // No change of direction, thus is the
299 if( bStartChk
) // desired area ( bStartChk )
300 bStartDone
= true; // completely processed.
304 else if( bReverse
== bStartChk
) //For a change of direction, an area can
305 { // be processed during certain circumstances
306 if( bStartChk
) // If the first part is spell checked in backwards
307 bEndDone
= true; // and this is reversed in the process, then
308 else // then the end part is processed (and vice-versa).
313 if( bOtherCntnt
&& bStartDone
&& bEndDone
) // Document has been fully checked?
315 if ( SpellMore() ) // spell check another document?
318 bStartDone
= !bReverse
;
320 SpellStart( SvxSpellArea::Body
);
331 SpellStart( SvxSpellArea::Body
);
334 else if ( bStartDone
&& bEndDone
)
336 if ( SpellMore() ) // check another document?
339 bStartDone
= !bReverse
;
341 SpellStart( SvxSpellArea::Body
);
347 // a BODY_area done, ask for the other BODY_area
350 TranslateId pResId
= bReverse
? RID_SVXSTR_QUERY_BW_CONTINUE
: RID_SVXSTR_QUERY_CONTINUE
;
351 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(pWin
,
352 VclMessageType::Question
, VclButtonsType::YesNo
,
354 if (xBox
->run() != RET_YES
)
356 // sacrifice the other area if necessary ask for special area
357 xWait
.reset(new weld::WaitObject(pWin
));
358 bStartDone
= bEndDone
= true;
363 bStartChk
= !bStartDone
;
364 SpellStart( bStartChk
? SvxSpellArea::BodyStart
: SvxSpellArea::BodyEnd
);
367 xWait
.reset(new weld::WaitObject(pWin
));
373 Reference
< XDictionary
> SvxSpellWrapper::GetAllRightDic()
375 Reference
< XDictionary
> xDic
;
377 Reference
< XSearchableDictionaryList
> xDicList( LinguMgr::GetDictionaryList() );
380 Sequence
< Reference
< XDictionary
> > aDics( xDicList
->getDictionaries() );
381 const Reference
< XDictionary
> *pDic
= aDics
.getConstArray();
382 sal_Int32 nCount
= aDics
.getLength();
385 while (!xDic
.is() && i
< nCount
)
387 Reference
< XDictionary
> xTmp
= pDic
[i
];
390 if ( xTmp
->isActive() &&
391 xTmp
->getDictionaryType() != DictionaryType_NEGATIVE
&&
392 LanguageTag( xTmp
->getLocale() ).getLanguageType() == LANGUAGE_NONE
)
394 Reference
< frame::XStorable
> xStor( xTmp
, UNO_QUERY
);
395 if (xStor
.is() && xStor
->hasLocation() && !xStor
->isReadonly())
397 xDic
= std::move(xTmp
);
406 xDic
= LinguMgr::GetStandardDic();
408 xDic
->setActive( true );
416 bool SvxSpellWrapper::FindSpellError()
418 ShowLanguageErrors();
420 xWait
.reset(new weld::WaitObject(pWin
));
423 Reference
< XDictionary
> xAllRightDic
;
425 xAllRightDic
= GetAllRightDic();
431 Reference
< XSpellAlternatives
> xAlt( GetLast(), UNO_QUERY
);
432 Reference
< XHyphenatedWord
> xHyphWord( GetLast(), UNO_QUERY
);
436 if (IsAllRight() && xAllRightDic
.is())
438 xAllRightDic
->add( xAlt
->getWord(), false, OUString() );
442 // look up in ChangeAllList for misspelled word
443 Reference
< XDictionary
> xChangeAllList
=
444 LinguMgr::GetChangeAllList();
445 Reference
< XDictionaryEntry
> xEntry
;
446 if (xChangeAllList
.is())
447 xEntry
= xChangeAllList
->getEntry( xAlt
->getWord() );
451 // replace word without asking
452 ReplaceAll( xEntry
->getReplacementText() );
458 else if (xHyphWord
.is())
463 bSpell
= SpellNext();
467 return GetLast().is();
471 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */