tdf#130857 qt weld: Implement QtInstanceWidget::get_text_height
[LibreOffice.git] / editeng / source / misc / splwrap.cxx
blob8e3684606cfb3a788001811dc0e91c042bfc26b4
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 <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>
44 #include <map>
45 #include <memory>
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
78 #define SVX_LANG_OK 1
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 ) :
139 pWin ( pWn ),
140 bOtherCntnt ( false ),
141 bStartChk ( 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 ) :
156 pWin ( pWn ),
157 xHyph ( xHyphenator ),
158 bOtherCntnt ( bOther ),
159 bReverse ( false ),
160 bStartDone ( bOther || bStart ),
161 bEndDone ( false ),
162 bStartChk ( bOther ),
163 bRevAllowed ( false ),
164 bAllRight ( true )
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;
185 nVal &= 0xFF00;
186 nVal |= nTmpVal;
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;
210 nVal &= 0x00FF;
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
222 } // given area.
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
254 return;
255 #else
256 if ( bOtherCntnt )
258 bReverse = false;
259 SpellStart( SvxSpellArea::Other );
261 else
263 bStartChk = bReverse;
264 SpellStart( bReverse ? SvxSpellArea::BodyStart : SvxSpellArea::BodyEnd );
267 if ( !FindSpellError() )
268 return;
270 Reference< XHyphenatedWord > xHyphWord( GetLast(), UNO_QUERY );
272 if (xHyphWord.is())
274 EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create();
275 ScopedVclPtr<AbstractHyphenWordDialog> pDlg(pFact->CreateHyphenWordDialog(
276 pWin,
277 xHyphWord->getWord(),
278 LanguageTag( xHyphWord->getLocale() ).getLanguageType(),
279 xHyph, this ));
280 pDlg->Execute();
282 #endif
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
296 // at the beginning.
297 if( bActRev == bReverse )
298 { // No change of direction, thus is the
299 if( bStartChk ) // desired area ( bStartChk )
300 bStartDone = true; // completely processed.
301 else
302 bEndDone = true;
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).
309 bStartDone = true;
312 bReverse = bActRev;
313 if( bOtherCntnt && bStartDone && bEndDone ) // Document has been fully checked?
315 if ( SpellMore() ) // spell check another document?
317 bOtherCntnt = false;
318 bStartDone = !bReverse;
319 bEndDone = bReverse;
320 SpellStart( SvxSpellArea::Body );
321 return true;
323 return false;
326 bool bGoOn = false;
328 if ( bOtherCntnt )
330 bStartChk = false;
331 SpellStart( SvxSpellArea::Body );
332 bGoOn = true;
334 else if ( bStartDone && bEndDone )
336 if ( SpellMore() ) // check another document?
338 bOtherCntnt = false;
339 bStartDone = !bReverse;
340 bEndDone = bReverse;
341 SpellStart( SvxSpellArea::Body );
342 return true;
345 else
347 // a BODY_area done, ask for the other BODY_area
348 xWait.reset();
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,
353 EditResId(pResId)));
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;
359 return SpellNext();
361 else
363 bStartChk = !bStartDone;
364 SpellStart( bStartChk ? SvxSpellArea::BodyStart : SvxSpellArea::BodyEnd );
365 bGoOn = true;
367 xWait.reset(new weld::WaitObject(pWin));
369 return bGoOn;
373 Reference< XDictionary > SvxSpellWrapper::GetAllRightDic()
375 Reference< XDictionary > xDic;
377 Reference< XSearchableDictionaryList > xDicList( LinguMgr::GetDictionaryList() );
378 if (xDicList.is())
380 Sequence< Reference< XDictionary > > aDics( xDicList->getDictionaries() );
381 const Reference< XDictionary > *pDic = aDics.getConstArray();
382 sal_Int32 nCount = aDics.getLength();
384 sal_Int32 i = 0;
385 while (!xDic.is() && i < nCount)
387 Reference< XDictionary > xTmp = pDic[i];
388 if (xTmp.is())
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);
401 ++i;
404 if (!xDic.is())
406 xDic = LinguMgr::GetStandardDic();
407 if (xDic.is())
408 xDic->setActive( true );
412 return xDic;
416 bool SvxSpellWrapper::FindSpellError()
418 ShowLanguageErrors();
420 xWait.reset(new weld::WaitObject(pWin));
421 bool bSpell = true;
423 Reference< XDictionary > xAllRightDic;
424 if (IsAllRight())
425 xAllRightDic = GetAllRightDic();
427 while ( bSpell )
429 SpellContinue();
431 Reference< XSpellAlternatives > xAlt( GetLast(), UNO_QUERY );
432 Reference< XHyphenatedWord > xHyphWord( GetLast(), UNO_QUERY );
434 if (xAlt.is())
436 if (IsAllRight() && xAllRightDic.is())
438 xAllRightDic->add( xAlt->getWord(), false, OUString() );
440 else
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() );
449 if (xEntry.is())
451 // replace word without asking
452 ReplaceAll( xEntry->getReplacementText() );
454 else
455 bSpell = false;
458 else if (xHyphWord.is())
459 bSpell = false;
460 else
462 SpellEnd();
463 bSpell = SpellNext();
466 xWait.reset();
467 return GetLast().is();
471 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */