nss: upgrade to release 3.73
[LibreOffice.git] / editeng / source / misc / splwrap.cxx
blobfe6704b9513f688287c33941a6f1d528d7fcd28f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <rtl/ustring.hxx>
21 #include <i18nlangtag/languagetag.hxx>
22 #include <vcl/svapp.hxx>
23 #include <vcl/weld.hxx>
24 #include <svtools/langtab.hxx>
26 #include <vcl/errinf.hxx>
27 #include <editeng/unolingu.hxx>
28 #include <com/sun/star/frame/XStorable.hpp>
29 #include <com/sun/star/linguistic2/XLinguProperties.hpp>
30 #include <com/sun/star/linguistic2/XSpellChecker1.hpp>
31 #include <com/sun/star/linguistic2/XHyphenator.hpp>
32 #include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp>
33 #include <com/sun/star/linguistic2/XDictionary.hpp>
35 #include <editeng/svxenum.hxx>
36 #include <editeng/splwrap.hxx>
37 #include <editeng/edtdlg.hxx>
38 #include <editeng/eerdll.hxx>
39 #include <editeng/editrids.hrc>
40 #include <editeng/editerr.hxx>
42 #include <map>
43 #include <memory>
45 using namespace ::com::sun::star;
46 using namespace ::com::sun::star::uno;
47 using namespace ::com::sun::star::beans;
48 using namespace ::com::sun::star::linguistic2;
51 // misc functions ---------------------------------------------
53 void SvxPrepareAutoCorrect( OUString &rOldText, const OUString &rNewText )
55 // This function should be used to strip (or add) trailing '.' from
56 // the strings before passing them on to the autocorrect function in
57 // order that the autocorrect function will hopefully
58 // works properly with normal words and abbreviations (with trailing '.')
59 // independent of if they are at the end of the sentence or not.
61 // rOldText: text to be replaced
62 // rNewText: replacement text
64 sal_Int32 nOldLen = rOldText.getLength();
65 sal_Int32 nNewLen = rNewText.getLength();
66 if (nOldLen && nNewLen)
68 bool bOldHasDot = '.' == rOldText[ nOldLen - 1 ],
69 bNewHasDot = '.' == rNewText[ nNewLen - 1 ];
70 if (bOldHasDot && !bNewHasDot
71 /*this is: !(bOldHasDot && bNewHasDot) && bOldHasDot*/)
72 rOldText = rOldText.copy( 0, nOldLen - 1 );
76 #define SVX_LANG_NEED_CHECK 0
77 #define SVX_LANG_OK 1
78 #define SVX_LANG_MISSING 2
79 #define SVX_LANG_MISSING_DO_WARN 3
81 typedef std::map< LanguageType, sal_uInt16 > LangCheckState_map_t;
83 static LangCheckState_map_t & GetLangCheckState()
85 static LangCheckState_map_t aLangCheckState;
86 return aLangCheckState;
89 void SvxSpellWrapper::ShowLanguageErrors()
91 // display message boxes for languages not available for
92 // spellchecking or hyphenation
93 LangCheckState_map_t &rLCS = GetLangCheckState();
94 for (auto const& elem : rLCS)
96 LanguageType nLang = elem.first;
97 sal_uInt16 nVal = elem.second;
98 sal_uInt16 nTmpSpell = nVal & 0x00FF;
99 sal_uInt16 nTmpHyph = (nVal >> 8) & 0x00FF;
101 if (SVX_LANG_MISSING_DO_WARN == nTmpSpell)
103 OUString aErr( SvtLanguageTable::GetLanguageString( nLang ) );
104 ErrorHandler::HandleError(
105 *new StringErrorInfo( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS, aErr ) );
106 nTmpSpell = SVX_LANG_MISSING;
108 if (SVX_LANG_MISSING_DO_WARN == nTmpHyph)
110 OUString aErr( SvtLanguageTable::GetLanguageString( nLang ) );
111 ErrorHandler::HandleError(
112 *new StringErrorInfo( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS, aErr ) );
113 nTmpHyph = SVX_LANG_MISSING;
116 rLCS[ nLang ] = (nTmpHyph << 8) | nTmpSpell;
121 SvxSpellWrapper::~SvxSpellWrapper()
125 /*--------------------------------------------------------------------
126 * Description: Constructor, the test sequence is determined
128 * !bStart && !bOtherCntnt: BODY_END, BODY_START, OTHER
129 * !bStart && bOtherCntnt: OTHER, BODY
130 * bStart && !bOtherCntnt: BODY_END, OTHER
131 * bStart && bOtherCntnt: OTHER
133 --------------------------------------------------------------------*/
135 SvxSpellWrapper::SvxSpellWrapper( weld::Window* pWn,
136 const bool bStart, const bool bIsAllRight ) :
138 pWin ( pWn ),
139 bOtherCntnt ( false ),
140 bStartChk ( false ),
141 bRevAllowed ( true ),
142 bAllRight ( bIsAllRight )
144 Reference< linguistic2::XLinguProperties > xProp( LinguMgr::GetLinguPropertySet() );
145 bool bWrapReverse = xProp.is() && xProp->getIsWrapReverse();
146 bReverse = bWrapReverse;
147 bStartDone = !bReverse && bStart;
148 bEndDone = bReverse && bStart;
152 SvxSpellWrapper::SvxSpellWrapper( weld::Window* pWn,
153 Reference< XHyphenator > const &xHyphenator,
154 const bool bStart, const bool bOther ) :
155 pWin ( pWn ),
156 xHyph ( xHyphenator ),
157 bOtherCntnt ( bOther ),
158 bReverse ( false ),
159 bStartDone ( bOther || bStart ),
160 bEndDone ( false ),
161 bStartChk ( bOther ),
162 bRevAllowed ( false ),
163 bAllRight ( true )
168 sal_Int16 SvxSpellWrapper::CheckSpellLang(
169 Reference< XSpellChecker1 > const & xSpell, LanguageType nLang)
171 LangCheckState_map_t &rLCS = GetLangCheckState();
173 LangCheckState_map_t::iterator aIt( rLCS.find( nLang ) );
174 sal_uInt16 nVal = aIt == rLCS.end() ? SVX_LANG_NEED_CHECK : aIt->second;
176 if (aIt == rLCS.end())
177 rLCS[ nLang ] = nVal;
179 if (SVX_LANG_NEED_CHECK == (nVal & 0x00FF))
181 sal_uInt16 nTmpVal = SVX_LANG_MISSING_DO_WARN;
182 if (xSpell.is() && xSpell->hasLanguage( static_cast<sal_uInt16>(nLang) ))
183 nTmpVal = SVX_LANG_OK;
184 nVal &= 0xFF00;
185 nVal |= nTmpVal;
187 rLCS[ nLang ] = nVal;
190 return static_cast<sal_Int16>(nVal);
193 sal_Int16 SvxSpellWrapper::CheckHyphLang(
194 Reference< XHyphenator > const & xHyph, LanguageType nLang)
196 LangCheckState_map_t &rLCS = GetLangCheckState();
198 LangCheckState_map_t::iterator aIt( rLCS.find( nLang ) );
199 sal_uInt16 nVal = aIt == rLCS.end() ? 0 : aIt->second;
201 if (aIt == rLCS.end())
202 rLCS[ nLang ] = nVal;
204 if (SVX_LANG_NEED_CHECK == ((nVal >> 8) & 0x00FF))
206 sal_uInt16 nTmpVal = SVX_LANG_MISSING_DO_WARN;
207 if (xHyph.is() && xHyph->hasLocale( LanguageTag::convertToLocale( nLang ) ))
208 nTmpVal = SVX_LANG_OK;
209 nVal &= 0x00FF;
210 nVal |= nTmpVal << 8;
212 rLCS[ nLang ] = nVal;
215 return static_cast<sal_Int16>(nVal);
219 void SvxSpellWrapper::SpellStart( SvxSpellArea /*eSpell*/ )
220 { // Here, the necessary preparations be made for SpellContinue in the
221 } // given area.
224 bool SvxSpellWrapper::SpellMore()
226 return false; // Should additional documents be examined?
230 void SvxSpellWrapper::SpellEnd()
231 { // Area is complete, tidy up if necessary
233 // display error for last language not found
234 ShowLanguageErrors();
237 void SvxSpellWrapper::SpellContinue()
241 void SvxSpellWrapper::ReplaceAll( const OUString & )
242 { // Replace Word from the Replace list
245 void SvxSpellWrapper::InsertHyphen( const sal_Int32 )
246 { // inserting and deleting Hyphen
249 // Testing of the document areas in the order specified by the flags
250 void SvxSpellWrapper::SpellDocument( )
252 if ( bOtherCntnt )
254 bReverse = false;
255 SpellStart( SvxSpellArea::Other );
257 else
259 bStartChk = bReverse;
260 SpellStart( bReverse ? SvxSpellArea::BodyStart : SvxSpellArea::BodyEnd );
263 if ( !FindSpellError() )
264 return;
266 Reference< XHyphenatedWord > xHyphWord( GetLast(), UNO_QUERY );
268 if (xHyphWord.is())
270 EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create();
271 ScopedVclPtr<AbstractHyphenWordDialog> pDlg(pFact->CreateHyphenWordDialog(
272 pWin,
273 xHyphWord->getWord(),
274 LanguageTag( xHyphWord->getLocale() ).getLanguageType(),
275 xHyph, this ));
276 pDlg->Execute();
281 // Select the next area
284 bool SvxSpellWrapper::SpellNext( )
286 Reference< linguistic2::XLinguProperties > xProp( LinguMgr::GetLinguPropertySet() );
287 bool bWrapReverse = xProp.is() && xProp->getIsWrapReverse();
288 bool bActRev = bRevAllowed && bWrapReverse;
290 // bActRev is the direction after Spell checking, bReverse is the one
291 // at the beginning.
292 if( bActRev == bReverse )
293 { // No change of direction, thus is the
294 if( bStartChk ) // desired area ( bStartChk )
295 bStartDone = true; // completely processed.
296 else
297 bEndDone = true;
299 else if( bReverse == bStartChk ) //For a change of direction, an area can
300 { // be processed during certain circumstances
301 if( bStartChk ) // If the first part is spell checked in backwards
302 bEndDone = true; // and this is reversed in the process, then
303 else // then the end part is processed (and vice-versa).
304 bStartDone = true;
307 bReverse = bActRev;
308 if( bOtherCntnt && bStartDone && bEndDone ) // Document has been fully checked?
310 if ( SpellMore() ) // spell check another document?
312 bOtherCntnt = false;
313 bStartDone = !bReverse;
314 bEndDone = bReverse;
315 SpellStart( SvxSpellArea::Body );
316 return true;
318 return false;
321 bool bGoOn = false;
323 if ( bOtherCntnt )
325 bStartChk = false;
326 SpellStart( SvxSpellArea::Body );
327 bGoOn = true;
329 else if ( bStartDone && bEndDone )
331 if ( SpellMore() ) // check another document?
333 bOtherCntnt = false;
334 bStartDone = !bReverse;
335 bEndDone = bReverse;
336 SpellStart( SvxSpellArea::Body );
337 return true;
340 else
342 // a BODY_area done, ask for the other BODY_area
343 xWait.reset();
345 const char* pResId = bReverse ? RID_SVXSTR_QUERY_BW_CONTINUE : RID_SVXSTR_QUERY_CONTINUE;
346 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pWin,
347 VclMessageType::Question, VclButtonsType::YesNo,
348 EditResId(pResId)));
349 if (xBox->run() != RET_YES)
351 // sacrifice the other area if necessary ask for special area
352 xWait.reset(new weld::WaitObject(pWin));
353 bStartDone = bEndDone = true;
354 return SpellNext();
356 else
358 bStartChk = !bStartDone;
359 SpellStart( bStartChk ? SvxSpellArea::BodyStart : SvxSpellArea::BodyEnd );
360 bGoOn = true;
362 xWait.reset(new weld::WaitObject(pWin));
364 return bGoOn;
368 Reference< XDictionary > SvxSpellWrapper::GetAllRightDic()
370 Reference< XDictionary > xDic;
372 Reference< XSearchableDictionaryList > xDicList( LinguMgr::GetDictionaryList() );
373 if (xDicList.is())
375 Sequence< Reference< XDictionary > > aDics( xDicList->getDictionaries() );
376 const Reference< XDictionary > *pDic = aDics.getConstArray();
377 sal_Int32 nCount = aDics.getLength();
379 sal_Int32 i = 0;
380 while (!xDic.is() && i < nCount)
382 Reference< XDictionary > xTmp = pDic[i];
383 if (xTmp.is())
385 if ( xTmp->isActive() &&
386 xTmp->getDictionaryType() != DictionaryType_NEGATIVE &&
387 LanguageTag( xTmp->getLocale() ).getLanguageType() == LANGUAGE_NONE )
389 Reference< frame::XStorable > xStor( xTmp, UNO_QUERY );
390 if (xStor.is() && xStor->hasLocation() && !xStor->isReadonly())
392 xDic = xTmp;
396 ++i;
399 if (!xDic.is())
401 xDic = LinguMgr::GetStandardDic();
402 if (xDic.is())
403 xDic->setActive( true );
407 return xDic;
411 bool SvxSpellWrapper::FindSpellError()
413 ShowLanguageErrors();
415 xWait.reset(new weld::WaitObject(pWin));
416 bool bSpell = true;
418 Reference< XDictionary > xAllRightDic;
419 if (IsAllRight())
420 xAllRightDic = GetAllRightDic();
422 while ( bSpell )
424 SpellContinue();
426 Reference< XSpellAlternatives > xAlt( GetLast(), UNO_QUERY );
427 Reference< XHyphenatedWord > xHyphWord( GetLast(), UNO_QUERY );
429 if (xAlt.is())
431 if (IsAllRight() && xAllRightDic.is())
433 xAllRightDic->add( xAlt->getWord(), false, OUString() );
435 else
437 // look up in ChangeAllList for misspelled word
438 Reference< XDictionary > xChangeAllList =
439 LinguMgr::GetChangeAllList();
440 Reference< XDictionaryEntry > xEntry;
441 if (xChangeAllList.is())
442 xEntry = xChangeAllList->getEntry( xAlt->getWord() );
444 if (xEntry.is())
446 // replace word without asking
447 ReplaceAll( xEntry->getReplacementText() );
449 else
450 bSpell = false;
453 else if (xHyphWord.is())
454 bSpell = false;
455 else
457 SpellEnd();
458 bSpell = SpellNext();
461 xWait.reset();
462 return GetLast().is();
466 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */