LibreOffice Module sw (master)  1
txtedt.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <hintids.hxx>
21 #include <vcl/svapp.hxx>
22 #include <svl/itemiter.hxx>
23 #include <svl/languageoptions.hxx>
24 #include <editeng/splwrap.hxx>
25 #include <editeng/langitem.hxx>
26 #include <editeng/fontitem.hxx>
27 #include <editeng/hangulhanja.hxx>
29 #include <SwSmartTagMgr.hxx>
30 #include <o3tl/safeint.hxx>
31 #include <osl/diagnose.h>
32 #include <officecfg/Office/Writer.hxx>
34 #include <unotools/charclass.hxx>
35 #include <sal/log.hxx>
36 #include <swmodule.hxx>
37 #include <splargs.hxx>
38 #include <viewopt.hxx>
39 #include <acmplwrd.hxx>
40 #include <doc.hxx>
43 #include <docsh.hxx>
44 #include <txtfld.hxx>
45 #include <txatbase.hxx>
46 #include <charatr.hxx>
47 #include <pam.hxx>
48 #include <hints.hxx>
49 #include <ndtxt.hxx>
50 #include <txtfrm.hxx>
51 #include <SwGrammarMarkUp.hxx>
52 #include <rootfrm.hxx>
53 #include <swscanner.hxx>
54 
55 #include <breakit.hxx>
56 #include <UndoOverwrite.hxx>
57 #include <txatritr.hxx>
58 #include <redline.hxx>
59 #include <docary.hxx>
60 #include <scriptinfo.hxx>
61 #include <docstat.hxx>
62 #include <editsh.hxx>
63 #include <unotextmarkup.hxx>
64 #include <txtatr.hxx>
65 #include <fmtautofmt.hxx>
66 #include <istyleaccess.hxx>
67 #include <unicode/uchar.h>
69 
70 #include <com/sun/star/i18n/WordType.hpp>
71 #include <com/sun/star/i18n/ScriptType.hpp>
72 #include <com/sun/star/i18n/XBreakIterator.hpp>
73 
74 #include <vector>
75 #include <utility>
76 
77 #include <unotextrange.hxx>
78 
79 using namespace ::com::sun::star;
80 using namespace ::com::sun::star::frame;
81 using namespace ::com::sun::star::i18n;
82 using namespace ::com::sun::star::beans;
83 using namespace ::com::sun::star::uno;
84 using namespace ::com::sun::star::linguistic2;
85 using namespace ::com::sun::star::smarttags;
86 
87 namespace
88 {
89  void DetectAndMarkMissingDictionaries( SwDoc& rDoc,
90  const uno::Reference< XSpellChecker1 >& xSpell,
91  const LanguageType eActLang )
92  {
93  if( xSpell.is() && !xSpell->hasLanguage( eActLang.get() ) )
94  rDoc.SetMissingDictionaries( true );
95  else
96  rDoc.SetMissingDictionaries( false );
97  }
98 }
99 
101 {
102  SwWrongList* pWrong; // for spell checking
103  SwGrammarMarkUp* pGrammarCheck; // for grammar checking / proof reading
114 
116  pWrong ( nullptr ),
117  pGrammarCheck ( nullptr ),
118  pSmartTags ( nullptr ),
119  nNumberOfWords ( 0 ),
120  nNumberOfAsianWords ( 0 ),
121  nNumberOfChars ( 0 ),
122  nNumberOfCharsExcludingSpaces ( 0 ),
123  bWordCountDirty ( true ),
124  eWrongDirty ( SwTextNode::WrongState::TODO ),
125  bGrammarCheckDirty ( true ),
126  bSmartTagDirty ( true ),
127  bAutoComplDirty ( true ) {};
128 };
129 
130 /*
131  * This has basically the same function as SwScriptInfo::MaskHiddenRanges,
132  * only for deleted redlines
133  */
134 
135 static sal_Int32
136 lcl_MaskRedlines( const SwTextNode& rNode, OUStringBuffer& rText,
137  sal_Int32 nStt, sal_Int32 nEnd,
138  const sal_Unicode cChar )
139 {
140  sal_Int32 nNumOfMaskedRedlines = 0;
141 
142  const SwDoc& rDoc = rNode.GetDoc();
143 
144  for ( SwRedlineTable::size_type nAct = rDoc.getIDocumentRedlineAccess().GetRedlinePos( rNode, RedlineType::Any ); nAct < rDoc.getIDocumentRedlineAccess().GetRedlineTable().size(); ++nAct )
145  {
146  const SwRangeRedline* pRed = rDoc.getIDocumentRedlineAccess().GetRedlineTable()[ nAct ];
147 
148  if ( pRed->Start()->nNode > rNode.GetIndex() )
149  break;
150 
151  if( RedlineType::Delete == pRed->GetType() )
152  {
153  sal_Int32 nRedlineEnd;
154  sal_Int32 nRedlineStart;
155 
156  pRed->CalcStartEnd( rNode.GetIndex(), nRedlineStart, nRedlineEnd );
157 
158  if ( nRedlineEnd < nStt || nRedlineStart > nEnd )
159  continue;
160 
161  while ( nRedlineStart < nRedlineEnd && nRedlineStart < nEnd )
162  {
163  if (nRedlineStart >= nStt)
164  {
165  rText[nRedlineStart] = cChar;
166  ++nNumOfMaskedRedlines;
167  }
168  ++nRedlineStart;
169  }
170  }
171  }
172 
173  return nNumOfMaskedRedlines;
174 }
175 
179 static bool
180 lcl_MaskRedlinesAndHiddenText( const SwTextNode& rNode, OUStringBuffer& rText,
181  sal_Int32 nStt, sal_Int32 nEnd,
182  const sal_Unicode cChar = CH_TXTATR_INWORD )
183 {
184  sal_Int32 nRedlinesMasked = 0;
185  sal_Int32 nHiddenCharsMasked = 0;
186 
187  const SwDoc& rDoc = rNode.GetDoc();
189 
190  // If called from word count or from spell checking, deleted redlines
191  // should be masked:
192  if ( bShowChg )
193  {
194  nRedlinesMasked = lcl_MaskRedlines( rNode, rText, nStt, nEnd, cChar );
195  }
196 
197  const bool bHideHidden = !SW_MOD()->GetViewOption(rDoc.GetDocumentSettingManager().get(DocumentSettingId::HTML_MODE))->IsShowHiddenChar();
198 
199  // If called from word count, we want to mask the hidden ranges even
200  // if they are visible:
201  if ( bHideHidden )
202  {
203  nHiddenCharsMasked =
204  SwScriptInfo::MaskHiddenRanges( rNode, rText, nStt, nEnd, cChar );
205  }
206 
207  return (nRedlinesMasked > 0) || (nHiddenCharsMasked > 0);
208 }
209 
214  SwTextFrame & rTextFrame, SwTextNode & rNode,
215  sal_Int32 const nChgStart, sal_Int32 const nChgEnd)
216 {
217  TextFrameIndex const iChgStart(rTextFrame.MapModelToView(&rNode, nChgStart));
218  TextFrameIndex const iChgEnd(rTextFrame.MapModelToView(&rNode, nChgEnd));
219 
220  SwRect aRect = rTextFrame.GetPaintArea();
221  SwRect aTmp = rTextFrame.GetPaintArea();
222 
223  const SwTextFrame* pStartFrame = &rTextFrame;
224  while( pStartFrame->HasFollow() &&
225  iChgStart >= pStartFrame->GetFollow()->GetOffset())
226  pStartFrame = pStartFrame->GetFollow();
227  const SwTextFrame* pEndFrame = pStartFrame;
228  while( pEndFrame->HasFollow() &&
229  iChgEnd >= pEndFrame->GetFollow()->GetOffset())
230  pEndFrame = pEndFrame->GetFollow();
231 
232  bool bSameFrame = true;
233 
234  if( rTextFrame.HasFollow() )
235  {
236  if( pEndFrame != pStartFrame )
237  {
238  bSameFrame = false;
239  SwRect aStFrame( pStartFrame->GetPaintArea() );
240  {
241  SwRectFnSet aRectFnSet(pStartFrame);
242  aRectFnSet.SetLeft( aTmp, aRectFnSet.GetLeft(aStFrame) );
243  aRectFnSet.SetRight( aTmp, aRectFnSet.GetRight(aStFrame) );
244  aRectFnSet.SetBottom( aTmp, aRectFnSet.GetBottom(aStFrame) );
245  }
246  aStFrame = pEndFrame->GetPaintArea();
247  {
248  SwRectFnSet aRectFnSet(pEndFrame);
249  aRectFnSet.SetTop( aRect, aRectFnSet.GetTop(aStFrame) );
250  aRectFnSet.SetLeft( aRect, aRectFnSet.GetLeft(aStFrame) );
251  aRectFnSet.SetRight( aRect, aRectFnSet.GetRight(aStFrame) );
252  }
253  aRect.Union( aTmp );
254  while( true )
255  {
256  pStartFrame = pStartFrame->GetFollow();
257  if( pStartFrame == pEndFrame )
258  break;
259  aRect.Union( pStartFrame->GetPaintArea() );
260  }
261  }
262  }
263  if( bSameFrame )
264  {
265  SwRectFnSet aRectFnSet(pStartFrame);
266  if( aRectFnSet.GetTop(aTmp) == aRectFnSet.GetTop(aRect) )
267  aRectFnSet.SetLeft( aRect, aRectFnSet.GetLeft(aTmp) );
268  else
269  {
270  SwRect aStFrame( pStartFrame->GetPaintArea() );
271  aRectFnSet.SetLeft( aRect, aRectFnSet.GetLeft(aStFrame) );
272  aRectFnSet.SetRight( aRect, aRectFnSet.GetRight(aStFrame) );
273  aRectFnSet.SetTop( aRect, aRectFnSet.GetTop(aTmp) );
274  }
275 
276  if( aTmp.Height() > aRect.Height() )
277  aRect.Height( aTmp.Height() );
278  }
279 
280  return aRect;
281 }
282 
286 static bool lcl_HaveCommonAttributes( IStyleAccess& rStyleAccess,
287  const SfxItemSet* pSet1,
288  sal_uInt16 nWhichId,
289  const SfxItemSet& rSet2,
290  std::shared_ptr<SfxItemSet>& pStyleHandle )
291 {
292  bool bRet = false;
293 
294  std::unique_ptr<SfxItemSet> pNewSet;
295 
296  if ( !pSet1 )
297  {
298  OSL_ENSURE( nWhichId, "lcl_HaveCommonAttributes not used correctly" );
299  if ( SfxItemState::SET == rSet2.GetItemState( nWhichId, false ) )
300  {
301  pNewSet = rSet2.Clone();
302  pNewSet->ClearItem( nWhichId );
303  }
304  }
305  else if ( pSet1->Count() )
306  {
307  SfxItemIter aIter( *pSet1 );
308  const SfxPoolItem* pItem = aIter.GetCurItem();
309  do
310  {
311  if ( SfxItemState::SET == rSet2.GetItemState( pItem->Which(), false ) )
312  {
313  if ( !pNewSet )
314  pNewSet = rSet2.Clone();
315  pNewSet->ClearItem( pItem->Which() );
316  }
317 
318  pItem = aIter.NextItem();
319  } while (pItem);
320  }
321 
322  if ( pNewSet )
323  {
324  if ( pNewSet->Count() )
325  pStyleHandle = rStyleAccess.getAutomaticStyle( *pNewSet, IStyleAccess::AUTO_STYLE_CHAR );
326  bRet = true;
327  }
328 
329  return bRet;
330 }
331 
356  const SwIndex &rIdx,
357  const sal_Int32 nLen,
358  const sal_uInt16 nWhich,
359  const SfxItemSet* pSet,
360  const bool bInclRefToxMark,
361  const bool bExactRange )
362 {
363  if ( !GetpSwpHints() )
364  return;
365 
366  sal_Int32 nStt = rIdx.GetIndex();
367  sal_Int32 nEnd = nStt + nLen;
368  {
369  // enlarge range for the reset of text attributes in case of an overlapping input field
370  const SwTextInputField* pTextInputField = dynamic_cast<const SwTextInputField*>(GetTextAttrAt( nStt, RES_TXTATR_INPUTFIELD, PARENT ));
371  if ( pTextInputField == nullptr )
372  {
373  pTextInputField = dynamic_cast<const SwTextInputField*>(GetTextAttrAt(nEnd, RES_TXTATR_INPUTFIELD, PARENT ));
374  }
375  if ( pTextInputField != nullptr )
376  {
377  if ( nStt > pTextInputField->GetStart() )
378  {
379  nStt = pTextInputField->GetStart();
380  }
381  if ( nEnd < *(pTextInputField->End()) )
382  {
383  nEnd = *(pTextInputField->End());
384  }
385  }
386  }
387 
388  bool bChanged = false;
389 
390  // nMin and nMax initialized to maximum / minimum (inverse)
391  sal_Int32 nMin = m_Text.getLength();
392  sal_Int32 nMax = nStt;
393  const bool bNoLen = nMin == 0;
394 
395  // We have to remember the "new" attributes that have
396  // been introduced by splitting surrounding attributes (case 2,3,4).
397  std::vector<SwTextAttr *> newAttributes;
398  std::vector<SwTextAttr *> delAttributes;
399 
400  // iterate over attribute array until start of attribute is behind deletion range
401  m_pSwpHints->SortIfNeedBe(); // trigger sorting now, we don't want it during iteration
402  size_t i = 0;
403  sal_Int32 nAttrStart = sal_Int32();
404  SwTextAttr *pHt = nullptr;
405  while ( (i < m_pSwpHints->Count())
406  && ( ( ( nAttrStart = m_pSwpHints->GetWithoutResorting(i)->GetStart()) < nEnd )
407  || nLen==0 ) && !bExactRange)
408  {
409  pHt = m_pSwpHints->GetWithoutResorting(i);
410 
411  // attributes without end stay in!
412  // but consider <bInclRefToxMark> used by Undo
413  const sal_Int32* const pAttrEnd = pHt->GetEnd();
414  const bool bKeepAttrWithoutEnd =
415  pAttrEnd == nullptr
416  && ( !bInclRefToxMark
417  || ( RES_TXTATR_REFMARK != pHt->Which()
418  && RES_TXTATR_TOXMARK != pHt->Which()
419  && RES_TXTATR_META != pHt->Which()
420  && RES_TXTATR_METAFIELD != pHt->Which() ) );
421  if ( bKeepAttrWithoutEnd )
422  {
423 
424  i++;
425  continue;
426  }
427  // attributes with content stay in
428  if ( pHt->HasContent() )
429  {
430  ++i;
431  continue;
432  }
433 
434  // Default behavior is to process all attributes:
435  bool bSkipAttr = false;
436  std::shared_ptr<SfxItemSet> pStyleHandle;
437 
438  // 1. case: We want to reset only the attributes listed in pSet:
439  if ( pSet )
440  {
441  bSkipAttr = SfxItemState::SET != pSet->GetItemState( pHt->Which(), false );
442  if ( bSkipAttr && RES_TXTATR_AUTOFMT == pHt->Which() )
443  {
444  // if the current attribute is an autostyle, we have to check if the autostyle
445  // and pSet have any attributes in common. If so, pStyleHandle will contain
446  // a handle to AutoStyle / pSet:
447  bSkipAttr = !lcl_HaveCommonAttributes( getIDocumentStyleAccess(), pSet, 0, *static_cast<const SwFormatAutoFormat&>(pHt->GetAttr()).GetStyleHandle(), pStyleHandle );
448  }
449  }
450  else if ( nWhich )
451  {
452  // 2. case: We want to reset only the attributes with WhichId nWhich:
453  bSkipAttr = nWhich != pHt->Which();
454  if ( bSkipAttr && RES_TXTATR_AUTOFMT == pHt->Which() )
455  {
456  bSkipAttr = !lcl_HaveCommonAttributes( getIDocumentStyleAccess(), nullptr, nWhich, *static_cast<const SwFormatAutoFormat&>(pHt->GetAttr()).GetStyleHandle(), pStyleHandle );
457  }
458  }
459  else if ( !bInclRefToxMark )
460  {
461  // 3. case: Reset all attributes except from ref/toxmarks:
462  // skip hints with CH_TXTATR here
463  // (deleting those is ONLY allowed for UNDO!)
464  bSkipAttr = RES_TXTATR_REFMARK == pHt->Which()
465  || RES_TXTATR_TOXMARK == pHt->Which()
466  || RES_TXTATR_META == pHt->Which()
467  || RES_TXTATR_METAFIELD == pHt->Which();
468  }
469 
470  if ( bSkipAttr )
471  {
472  i++;
473  continue;
474  }
475 
476  if (nStt <= nAttrStart) // Case: 1,3,5
477  {
478  const sal_Int32 nAttrEnd = pAttrEnd != nullptr
479  ? *pAttrEnd
480  : nAttrStart;
481  if (nEnd > nAttrStart
482  || (nEnd == nAttrEnd && nEnd == nAttrStart)) // Case: 1,3
483  {
484  if ( nMin > nAttrStart )
485  nMin = nAttrStart;
486  if ( nMax < nAttrEnd )
487  nMax = nAttrEnd;
488  // If only a no-extent hint is deleted, no resorting is needed
489  bChanged = bChanged || nEnd > nAttrStart || bNoLen;
490  if (nAttrEnd <= nEnd) // Case: 1
491  {
492  delAttributes.push_back(pHt);
493 
494  if ( pStyleHandle )
495  {
496  SwTextAttr* pNew = MakeTextAttr( GetDoc(),
497  *pStyleHandle, nAttrStart, nAttrEnd );
498  newAttributes.push_back(pNew);
499  }
500  }
501  else // Case: 3
502  {
503  bChanged = true;
504  m_pSwpHints->NoteInHistory( pHt );
505  // UGLY: this may temporarily destroy the sorting!
506  pHt->SetStart(nEnd);
507  m_pSwpHints->NoteInHistory( pHt, true );
508 
509  if ( pStyleHandle && nAttrStart < nEnd )
510  {
511  SwTextAttr* pNew = MakeTextAttr( GetDoc(),
512  *pStyleHandle, nAttrStart, nEnd );
513  newAttributes.push_back(pNew);
514  }
515  }
516  }
517  }
518  else if (pAttrEnd != nullptr) // Case: 2,4,5
519  {
520  if (*pAttrEnd > nStt) // Case: 2,4
521  {
522  if (*pAttrEnd < nEnd) // Case: 2
523  {
524  if ( nMin > nAttrStart )
525  nMin = nAttrStart;
526  if ( nMax < *pAttrEnd )
527  nMax = *pAttrEnd;
528  bChanged = true;
529 
530  const sal_Int32 nAttrEnd = *pAttrEnd;
531 
532  m_pSwpHints->NoteInHistory( pHt );
533  // UGLY: this may temporarily destroy the sorting!
534  pHt->SetEnd(nStt);
535  m_pSwpHints->NoteInHistory( pHt, true );
536 
537  if ( pStyleHandle )
538  {
539  SwTextAttr* pNew = MakeTextAttr( GetDoc(),
540  *pStyleHandle, nStt, nAttrEnd );
541  newAttributes.push_back(pNew);
542  }
543  }
544  else if (nLen) // Case: 4
545  {
546  // for Length 0 both hints would be merged again by
547  // InsertHint, so leave them alone!
548  if ( nMin > nAttrStart )
549  nMin = nAttrStart;
550  if ( nMax < *pAttrEnd )
551  nMax = *pAttrEnd;
552  bChanged = true;
553  const sal_Int32 nTmpEnd = *pAttrEnd;
554  m_pSwpHints->NoteInHistory( pHt );
555  // UGLY: this may temporarily destroy the sorting!
556  pHt->SetEnd(nStt);
557  m_pSwpHints->NoteInHistory( pHt, true );
558 
559  if ( pStyleHandle && nStt < nEnd )
560  {
561  SwTextAttr* pNew = MakeTextAttr( GetDoc(),
562  *pStyleHandle, nStt, nEnd );
563  newAttributes.push_back(pNew);
564  }
565 
566  if( nEnd < nTmpEnd )
567  {
568  SwTextAttr* pNew = MakeTextAttr( GetDoc(),
569  pHt->GetAttr(), nEnd, nTmpEnd );
570  if ( pNew )
571  {
572  SwTextCharFormat* pCharFormat = dynamic_cast<SwTextCharFormat*>(pHt);
573  if ( pCharFormat )
574  static_txtattr_cast<SwTextCharFormat*>(pNew)->SetSortNumber(pCharFormat->GetSortNumber());
575 
576  newAttributes.push_back(pNew);
577  }
578  }
579  }
580  }
581  }
582  ++i;
583  }
584 
585  if (bExactRange)
586  {
587  // Only delete the hints which start at nStt and end at nEnd.
588  for (i = 0; i < m_pSwpHints->Count(); ++i)
589  {
590  SwTextAttr* pHint = m_pSwpHints->Get(i);
591  if ( (isTXTATR_WITHEND(pHint->Which()) && RES_TXTATR_AUTOFMT != pHint->Which())
592  || pHint->GetStart() != nStt)
593  continue;
594 
595  const sal_Int32* pHintEnd = pHint->GetEnd();
596  if (!pHintEnd || *pHintEnd != nEnd)
597  continue;
598 
599  delAttributes.push_back(pHint);
600  }
601  }
602 
603  if (bChanged && !delAttributes.empty())
604  { // Delete() calls GetStartOf() - requires sorted hints!
605  m_pSwpHints->Resort();
606  }
607 
608  // delay deleting the hints because it re-sorts the hints array
609  for (SwTextAttr *const pDel : delAttributes)
610  {
611  m_pSwpHints->Delete(pDel);
612  DestroyAttr(pDel);
613  }
614 
615  // delay inserting the hints because it re-sorts the hints array
616  for (SwTextAttr *const pNew : newAttributes)
617  {
619  }
620 
622 
623  if (!bChanged)
624  return;
625 
626  if ( HasHints() )
627  { // possibly sometimes Resort would be sufficient, but...
628  m_pSwpHints->MergePortions(*this);
629  }
630 
631  // TextFrame's respond to aHint, others to aNew
632  SwUpdateAttr aHint(
633  nMin,
634  nMax,
635  0);
636 
637  CallSwClientNotify(sw::LegacyModifyHint(nullptr, &aHint));
638  SwFormatChg aNew( GetFormatColl() );
639  CallSwClientNotify(sw::LegacyModifyHint(nullptr, &aNew));
640 }
641 
642 static sal_Int32 clipIndexBounds(const OUString &rStr, sal_Int32 nPos)
643 {
644  if (nPos < 0)
645  return 0;
646  if (nPos > rStr.getLength())
647  return rStr.getLength();
648  return nPos;
649 }
650 
651 // Return current word:
652 // Search from left to right, so find the word before nPos.
653 // Except if at the start of the paragraph, then return the first word.
654 // If the first word consists only of whitespace, return an empty string.
655 OUString SwTextFrame::GetCurWord(SwPosition const& rPos) const
656 {
658  SwTextNode *const pTextNode(rPos.nNode.GetNode().GetTextNode());
659  assert(pTextNode);
660  OUString const& rText(GetText());
661  assert(sal_Int32(nPos) <= rText.getLength()); // invalid index
662 
663  if (rText.isEmpty() || IsHiddenNow())
664  return OUString();
665 
666  assert(g_pBreakIt && g_pBreakIt->GetBreakIter().is());
667  const uno::Reference< XBreakIterator > &rxBreak = g_pBreakIt->GetBreakIter();
668  sal_Int16 nWordType = WordType::DICTIONARY_WORD;
669  lang::Locale aLocale( g_pBreakIt->GetLocale(pTextNode->GetLang(rPos.nContent.GetIndex())) );
670  Boundary aBndry =
671  rxBreak->getWordBoundary(rText, sal_Int32(nPos), aLocale, nWordType, true);
672 
673  // if no word was found use previous word (if any)
674  if (aBndry.startPos == aBndry.endPos)
675  {
676  aBndry = rxBreak->previousWord(rText, sal_Int32(nPos), aLocale, nWordType);
677  }
678 
679  // check if word was found and if it uses a symbol font, if so
680  // enforce returning an empty string
681  if (aBndry.endPos != aBndry.startPos
682  && IsSymbolAt(TextFrameIndex(aBndry.startPos)))
683  {
684  aBndry.endPos = aBndry.startPos;
685  }
686 
687  // can have -1 as start/end of bounds not found
688  aBndry.startPos = clipIndexBounds(rText, aBndry.startPos);
689  aBndry.endPos = clipIndexBounds(rText, aBndry.endPos);
690 
691  return rText.copy(aBndry.startPos,
692  aBndry.endPos - aBndry.startPos);
693 }
694 
695 SwScanner::SwScanner( const SwTextNode& rNd, const OUString& rText,
696  const LanguageType* pLang, const ModelToViewHelper& rConvMap,
697  sal_uInt16 nType, sal_Int32 nStart, sal_Int32 nEnd, bool bClp )
698  : SwScanner(
699  [&rNd](sal_Int32 const nBegin, sal_uInt16 const nScript, bool const bNoChar)
700  { return rNd.GetLang(nBegin, bNoChar ? 0 : 1, nScript); }
701  , rText, pLang, rConvMap, nType, nStart, nEnd, bClp)
702 {
703 }
704 
705 SwScanner::SwScanner(std::function<LanguageType(sal_Int32, sal_Int32, bool)> const& pGetLangOfChar,
706  const OUString& rText, const LanguageType* pLang,
707  const ModelToViewHelper& rConvMap, sal_uInt16 nType, sal_Int32 nStart,
708  sal_Int32 nEnd, bool bClp)
709  : m_pGetLangOfChar(pGetLangOfChar)
710  , m_aPreDashReplacementText(rText)
711  , m_pLanguage(pLang)
712  , m_ModelToView(rConvMap)
713  , m_nLength(0)
714  , m_nOverriddenDashCount(0)
715  , m_nWordType(nType)
716  , m_bClip(bClp)
717 {
718  m_nStartPos = m_nBegin = nStart;
719  m_nEndPos = nEnd;
720 
721  //MSWord f.e has special emdash and endash behaviour in that they break
722  //words for the purposes of word counting, while a hyphen etc. doesn't.
723 
724  //The default configuration treats emdash/endash as a word break, but
725  //additional ones can be added in under tools->options
726  if (m_nWordType == i18n::WordType::WORD_COUNT)
727  {
729  OUStringBuffer aBuf(m_aPreDashReplacementText);
730  for (sal_Int32 i = m_nStartPos; i < m_nEndPos; ++i)
731  {
732  if (i < 0)
733  continue;
734  sal_Unicode cChar = aBuf[i];
735  if (sDashes.indexOf(cChar) != -1)
736  {
737  aBuf[i] = ' ';
739  }
740  }
741  m_aText = aBuf.makeStringAndClear();
742  }
743  else
745 
746  assert(m_aPreDashReplacementText.getLength() == m_aText.getLength());
747 
748  if ( m_pLanguage )
749  {
751  }
752  else
753  {
754  ModelToViewHelper::ModelPosition aModelBeginPos =
756  m_aCurrentLang = m_pGetLangOfChar(aModelBeginPos.mnPos, 0, true);
757  }
758 }
759 
760 namespace
761 {
762  //fdo#45271 for Asian words count characters instead of words
763  sal_Int32 forceEachAsianCodePointToWord(const OUString &rText, sal_Int32 nBegin, sal_Int32 nLen)
764  {
765  if (nLen > 1)
766  {
767  const uno::Reference< XBreakIterator > &rxBreak = g_pBreakIt->GetBreakIter();
768 
769  sal_uInt16 nCurrScript = rxBreak->getScriptType( rText, nBegin );
770 
771  sal_Int32 indexUtf16 = nBegin;
772  rText.iterateCodePoints(&indexUtf16);
773 
774  //First character is Asian, consider it a word :-(
775  if (nCurrScript == i18n::ScriptType::ASIAN)
776  {
777  nLen = indexUtf16 - nBegin;
778  return nLen;
779  }
780 
781  //First character was not Asian, consider appearance of any Asian character
782  //to be the end of the word
783  while (indexUtf16 < nBegin + nLen)
784  {
785  nCurrScript = rxBreak->getScriptType( rText, indexUtf16 );
786  if (nCurrScript == i18n::ScriptType::ASIAN)
787  {
788  nLen = indexUtf16 - nBegin;
789  return nLen;
790  }
791  rText.iterateCodePoints(&indexUtf16);
792  }
793  }
794  return nLen;
795  }
796 }
797 
799 {
801  Boundary aBound;
802 
803  CharClass& rCC = GetAppCharClass();
804  LanguageTag aOldLanguageTag = rCC.getLanguageTag();
805 
806  while ( true )
807  {
808  // skip non-letter characters:
809  while (m_nBegin < m_aText.getLength())
810  {
811  if (m_nBegin >= 0 && !u_isspace(m_aText[m_nBegin]))
812  {
813  if ( !m_pLanguage )
814  {
815  const sal_uInt16 nNextScriptType = g_pBreakIt->GetBreakIter()->getScriptType( m_aText, m_nBegin );
816  ModelToViewHelper::ModelPosition aModelBeginPos =
818  m_aCurrentLang = m_pGetLangOfChar(aModelBeginPos.mnPos, nNextScriptType, false);
819  }
820 
821  if ( m_nWordType != i18n::WordType::WORD_COUNT )
822  {
824  if ( rCC.isLetterNumeric(OUString(m_aText[m_nBegin])) )
825  break;
826  }
827  else
828  break;
829  }
830  ++m_nBegin;
831  }
832 
833  if ( m_nBegin >= m_aText.getLength() || m_nBegin >= m_nEndPos )
834  return false;
835 
836  // get the word boundaries
837  aBound = g_pBreakIt->GetBreakIter()->getWordBoundary( m_aText, m_nBegin,
839  OSL_ENSURE( aBound.endPos >= aBound.startPos, "broken aBound result" );
840 
841  // we don't want to include preceding text
842  // to count words in text with mixed script punctuation correctly,
843  // but we want to include preceding symbols (eg. percent sign, section sign,
844  // degree sign defined by dict_word_hu to spell check their affixed forms).
845  if (m_nWordType == i18n::WordType::WORD_COUNT && aBound.startPos < m_nBegin)
846  aBound.startPos = m_nBegin;
847 
848  //no word boundaries could be found
849  if(aBound.endPos == aBound.startPos)
850  return false;
851 
852  //if a word before is found it has to be searched for the next
853  if(aBound.endPos == m_nBegin)
854  ++m_nBegin;
855  else
856  break;
857  } // end while( true )
858 
859  rCC.setLanguageTag( aOldLanguageTag );
860 
861  // #i89042, as discussed with HDU: don't evaluate script changes for word count. Use whole word.
862  if ( m_nWordType == i18n::WordType::WORD_COUNT )
863  {
864  m_nBegin = std::max(aBound.startPos, m_nBegin);
865  m_nLength = 0;
866  if (aBound.endPos > m_nBegin)
867  m_nLength = aBound.endPos - m_nBegin;
868  }
869  else
870  {
871  // we have to differentiate between these cases:
872  if ( aBound.startPos <= m_nBegin )
873  {
874  OSL_ENSURE( aBound.endPos >= m_nBegin, "Unexpected aBound result" );
875 
876  // restrict boundaries to script boundaries and nEndPos
877  const sal_uInt16 nCurrScript = g_pBreakIt->GetBreakIter()->getScriptType( m_aText, m_nBegin );
878  OUString aTmpWord = m_aText.copy( m_nBegin, aBound.endPos - m_nBegin );
879  const sal_Int32 nScriptEnd = m_nBegin +
880  g_pBreakIt->GetBreakIter()->endOfScript( aTmpWord, 0, nCurrScript );
881  const sal_Int32 nEnd = std::min( aBound.endPos, nScriptEnd );
882 
883  // restrict word start to last script change position
884  sal_Int32 nScriptBegin = 0;
885  if ( aBound.startPos < m_nBegin )
886  {
887  // search from nBegin backwards until the next script change
888  aTmpWord = m_aText.copy( aBound.startPos,
889  m_nBegin - aBound.startPos + 1 );
890  nScriptBegin = aBound.startPos +
891  g_pBreakIt->GetBreakIter()->beginOfScript( aTmpWord, m_nBegin - aBound.startPos,
892  nCurrScript );
893  }
894 
895  m_nBegin = std::max( aBound.startPos, nScriptBegin );
896  m_nLength = nEnd - m_nBegin;
897  }
898  else
899  {
900  const sal_uInt16 nCurrScript = g_pBreakIt->GetBreakIter()->getScriptType( m_aText, aBound.startPos );
901  OUString aTmpWord = m_aText.copy( aBound.startPos,
902  aBound.endPos - aBound.startPos );
903  const sal_Int32 nScriptEnd = aBound.startPos +
904  g_pBreakIt->GetBreakIter()->endOfScript( aTmpWord, 0, nCurrScript );
905  const sal_Int32 nEnd = std::min( aBound.endPos, nScriptEnd );
906  m_nBegin = aBound.startPos;
907  m_nLength = nEnd - m_nBegin;
908  }
909  }
910 
911  // optionally clip the result of getWordBoundaries:
912  if ( m_bClip )
913  {
914  aBound.startPos = std::max( aBound.startPos, m_nStartPos );
915  aBound.endPos = std::min( aBound.endPos, m_nEndPos );
916  if (aBound.endPos < aBound.startPos)
917  {
919  m_nLength = 0; // found word is outside of search interval
920  }
921  else
922  {
923  m_nBegin = aBound.startPos;
924  m_nLength = aBound.endPos - m_nBegin;
925  }
926  }
927 
928  if( ! m_nLength )
929  return false;
930 
931  if ( m_nWordType == i18n::WordType::WORD_COUNT )
932  m_nLength = forceEachAsianCodePointToWord(m_aText, m_nBegin, m_nLength);
933 
934  m_aWord = m_aPreDashReplacementText.copy( m_nBegin, m_nLength );
935 
936  return true;
937 }
938 
939 // Note: this is a clone of SwTextFrame::AutoSpell_, so keep them in sync when fixing things!
941 {
942  // modify string according to redline information and hidden text
943  const OUString aOldText( m_Text );
944  OUStringBuffer buf(m_Text);
945  const bool bRestoreString =
946  lcl_MaskRedlinesAndHiddenText(*this, buf, 0, m_Text.getLength());
947  if (bRestoreString)
948  { // ??? UGLY: is it really necessary to modify m_Text here?
949  m_Text = buf.makeStringAndClear();
950  }
951 
952  sal_Int32 nBegin = ( pArgs->pStartNode != this )
953  ? 0
954  : pArgs->pStartIdx->GetIndex();
955 
956  sal_Int32 nEnd = ( pArgs->pEndNode != this )
957  ? m_Text.getLength()
958  : pArgs->pEndIdx->GetIndex();
959 
960  pArgs->xSpellAlt = nullptr;
961 
962  // 4 cases:
963 
964  // 1. IsWrongDirty = 0 and GetWrong = 0
965  // Everything is checked and correct
966  // 2. IsWrongDirty = 0 and GetWrong = 1
967  // Everything is checked and errors are identified in the wrong list
968  // 3. IsWrongDirty = 1 and GetWrong = 0
969  // Nothing has been checked
970  // 4. IsWrongDirty = 1 and GetWrong = 1
971  // Text has been checked but there is an invalid range in the wrong list
972 
973  // Nothing has to be done for case 1.
974  if ( ( IsWrongDirty() || GetWrong() ) && m_Text.getLength() )
975  {
976  if (nBegin > m_Text.getLength())
977  {
978  nBegin = m_Text.getLength();
979  }
980  if (nEnd > m_Text.getLength())
981  {
982  nEnd = m_Text.getLength();
983  }
984 
985  if(!IsWrongDirty())
986  {
987  const sal_Int32 nTemp = GetWrong()->NextWrong( nBegin );
988  if(nTemp > nEnd)
989  {
990  // reset original text
991  if ( bRestoreString )
992  {
993  m_Text = aOldText;
994  }
995  return false;
996  }
997  if(nTemp > nBegin)
998  nBegin = nTemp;
999 
1000  }
1001 
1002  // In case 2. we pass the wrong list to the scanned, because only
1003  // the words in the wrong list have to be checked
1004  SwScanner aScanner( *this, m_Text, nullptr, ModelToViewHelper(),
1005  WordType::DICTIONARY_WORD,
1006  nBegin, nEnd );
1007  while( !pArgs->xSpellAlt.is() && aScanner.NextWord() )
1008  {
1009  const OUString& rWord = aScanner.GetWord();
1010 
1011  // get next language for next word, consider language attributes
1012  // within the word
1013  LanguageType eActLang = aScanner.GetCurrentLanguage();
1014  DetectAndMarkMissingDictionaries( GetTextNode()->GetDoc(), pArgs->xSpeller, eActLang );
1015 
1016  if( rWord.getLength() > 0 && LANGUAGE_NONE != eActLang )
1017  {
1018  if (pArgs->xSpeller.is())
1019  {
1020  SvxSpellWrapper::CheckSpellLang( pArgs->xSpeller, eActLang );
1021  pArgs->xSpellAlt = pArgs->xSpeller->spell( rWord, static_cast<sal_uInt16>(eActLang),
1022  Sequence< PropertyValue >() );
1023  }
1024  if( pArgs->xSpellAlt.is() )
1025  {
1026  if ( IsSymbolAt(aScanner.GetBegin()) ||
1027  // redlines can leave "in word" character within word,
1028  // we must remove them before spell checking
1029  // to avoid false alarm
1030  ( bRestoreString && pArgs->xSpeller->isValid( rWord.replaceAll(OUStringChar(CH_TXTATR_INWORD), ""),
1031  static_cast<sal_uInt16>(eActLang), Sequence< PropertyValue >() ) ) )
1032  {
1033  pArgs->xSpellAlt = nullptr;
1034  }
1035  else
1036  {
1037  // make sure the selection build later from the data
1038  // below does not include "in word" character to the
1039  // left and right in order to preserve those. Therefore
1040  // count those "in words" in order to modify the
1041  // selection accordingly.
1042  const sal_Unicode* pChar = rWord.getStr();
1043  sal_Int32 nLeft = 0;
1044  while (*pChar++ == CH_TXTATR_INWORD)
1045  ++nLeft;
1046  pChar = rWord.getLength() ? rWord.getStr() + rWord.getLength() - 1 : nullptr;
1047  sal_Int32 nRight = 0;
1048  while (pChar && *pChar-- == CH_TXTATR_INWORD)
1049  ++nRight;
1050 
1051  pArgs->pStartNode = this;
1052  pArgs->pEndNode = this;
1053  pArgs->pStartIdx->Assign(this, aScanner.GetEnd() - nRight );
1054  pArgs->pEndIdx->Assign(this, aScanner.GetBegin() + nLeft );
1055  }
1056  }
1057  }
1058  }
1059  }
1060 
1061  // reset original text
1062  if ( bRestoreString )
1063  {
1064  m_Text = aOldText;
1065  }
1066 
1067  return pArgs->xSpellAlt.is();
1068 }
1069 
1071  LanguageType nLang, sal_uInt16 nLangWhichId,
1072  const vcl::Font *pFont, sal_uInt16 nFontWhichId )
1073 {
1074  sal_uInt16 aRanges[] = {
1075  nLangWhichId, nLangWhichId,
1076  nFontWhichId, nFontWhichId,
1077  0, 0, 0 };
1078  if (!pFont)
1079  aRanges[2] = aRanges[3] = 0; // clear entries with font WhichId
1080 
1081  SwEditShell *pEditShell = GetDoc().GetEditShell();
1082  SfxItemSet aSet( pEditShell->GetAttrPool(), aRanges );
1083  aSet.Put( SvxLanguageItem( nLang, nLangWhichId ) );
1084 
1085  OSL_ENSURE( pFont, "target font missing?" );
1086  if (pFont)
1087  {
1088  SvxFontItem aFontItem = static_cast<const SvxFontItem&>( aSet.Get( nFontWhichId ) );
1089  aFontItem.SetFamilyName( pFont->GetFamilyName());
1090  aFontItem.SetFamily( pFont->GetFamilyType());
1091  aFontItem.SetStyleName( pFont->GetStyleName());
1092  aFontItem.SetPitch( pFont->GetPitch());
1093  aFontItem.SetCharSet( pFont->GetCharSet() );
1094  aSet.Put( aFontItem );
1095  }
1096 
1098  // SetAttr( aSet ); <- Does not set language attribute of empty paragraphs correctly,
1099  // <- because since there is no selection the flag to garbage
1100  // <- collect all attributes is set, and therefore attributes spanned
1101  // <- over empty selection are removed.
1102 
1103 }
1104 
1106 {
1107  // get range of text within node to be converted
1108  // (either all the text or the text within the selection
1109  // when the conversion was started)
1110  const sal_Int32 nTextBegin = ( rArgs.pStartNode == this )
1111  ? std::min(rArgs.pStartIdx->GetIndex(), m_Text.getLength())
1112  : 0;
1113 
1114  const sal_Int32 nTextEnd = ( rArgs.pEndNode == this )
1115  ? std::min(rArgs.pEndIdx->GetIndex(), m_Text.getLength())
1116  : m_Text.getLength();
1117 
1118  rArgs.aConvText.clear();
1119 
1120  // modify string according to redline information and hidden text
1121  const OUString aOldText( m_Text );
1122  OUStringBuffer buf(m_Text);
1123  const bool bRestoreString =
1124  lcl_MaskRedlinesAndHiddenText(*this, buf, 0, m_Text.getLength());
1125  if (bRestoreString)
1126  { // ??? UGLY: is it really necessary to modify m_Text here?
1127  m_Text = buf.makeStringAndClear();
1128  }
1129 
1130  bool bFound = false;
1131  sal_Int32 nBegin = nTextBegin;
1132  sal_Int32 nLen = 0;
1133  LanguageType nLangFound = LANGUAGE_NONE;
1134  if (m_Text.isEmpty())
1135  {
1137  {
1138  // create SwPaM with mark & point spanning empty paragraph
1139  //SwPaM aCurPaM( *this, *this, nBegin, nBegin + nLen ); <-- wrong c-tor, does sth different
1140  SwPaM aCurPaM( *this, 0 );
1141 
1142  SetLanguageAndFont( aCurPaM,
1145  }
1146  }
1147  else
1148  {
1149  SwLanguageIterator aIter( *this, nBegin );
1150 
1151  // Implicit changes require setting new attributes, which in turn destroys
1152  // the attribute sequence on that aIter iterates. We store the necessary
1153  // coordinates and apply those changes after iterating through the text.
1154  typedef std::pair<sal_Int32, sal_Int32> ImplicitChangesRange;
1155  std::vector<ImplicitChangesRange> aImplicitChanges;
1156 
1157  // find non zero length text portion of appropriate language
1158  do {
1159  nLangFound = aIter.GetLanguage();
1160  bool bLangOk = (nLangFound == rArgs.nConvSrcLang) ||
1163 
1164  sal_Int32 nChPos = aIter.GetChgPos();
1165  // the position at the end of the paragraph is COMPLETE_STRING and
1166  // thus must be cut to the end of the actual string.
1167  assert(nChPos != -1);
1168  if (nChPos == -1 || nChPos == COMPLETE_STRING)
1169  {
1170  nChPos = m_Text.getLength();
1171  }
1172 
1173  nLen = nChPos - nBegin;
1174  bFound = bLangOk && nLen > 0;
1175  if (!bFound)
1176  {
1177  // create SwPaM with mark & point spanning the attributed text
1178  //SwPaM aCurPaM( *this, *this, nBegin, nBegin + nLen ); <-- wrong c-tor, does sth different
1179  SwPaM aCurPaM( *this, nBegin );
1180  aCurPaM.SetMark();
1181  aCurPaM.GetPoint()->nContent = nBegin + nLen;
1182 
1183  // check script type of selected text
1184  SwEditShell *pEditShell = GetDoc().GetEditShell();
1185  pEditShell->Push(); // save current cursor on stack
1186  pEditShell->SetSelection( aCurPaM );
1187  bool bIsAsianScript = (SvtScriptType::ASIAN == pEditShell->GetScriptType());
1188  pEditShell->Pop(SwCursorShell::PopMode::DeleteCurrent); // restore cursor from stack
1189 
1190  if (!bIsAsianScript && rArgs.bAllowImplicitChangesForNotConvertibleText)
1191  {
1192  // Store for later use
1193  aImplicitChanges.emplace_back(nBegin, nBegin+nLen);
1194  }
1195  nBegin = nChPos; // start of next language portion
1196  }
1197  } while (!bFound && aIter.Next()); /* loop while nothing was found and still sth is left to be searched */
1198 
1199  // Apply implicit changes, if any, now that aIter is no longer used
1200  for (const auto& rImplicitChange : aImplicitChanges)
1201  {
1202  SwPaM aPaM( *this, rImplicitChange.first );
1203  aPaM.SetMark();
1204  aPaM.GetPoint()->nContent = rImplicitChange.second;
1206  }
1207 
1208  }
1209 
1210  // keep resulting text within selection / range of text to be converted
1211  if (nBegin < nTextBegin)
1212  nBegin = nTextBegin;
1213  if (nBegin + nLen > nTextEnd)
1214  nLen = nTextEnd - nBegin;
1215  bool bInSelection = nBegin < nTextEnd;
1216 
1217  if (bFound && bInSelection) // convertible text found within selection/range?
1218  {
1219  OSL_ENSURE( !m_Text.isEmpty(), "convertible text portion missing!" );
1220  rArgs.aConvText = m_Text.copy(nBegin, nLen);
1221  rArgs.nConvTextLang = nLangFound;
1222 
1223  // position where to start looking in next iteration (after current ends)
1224  rArgs.pStartNode = this;
1225  rArgs.pStartIdx->Assign(this, nBegin + nLen );
1226  // end position (when we have travelled over the whole document)
1227  rArgs.pEndNode = this;
1228  rArgs.pEndIdx->Assign(this, nBegin );
1229  }
1230 
1231  // restore original text
1232  if ( bRestoreString )
1233  {
1234  m_Text = aOldText;
1235  }
1236 
1237  return !rArgs.aConvText.isEmpty();
1238 }
1239 
1240 // Note: this is a clone of SwTextNode::Spell, so keep them in sync when fixing things!
1241 SwRect SwTextFrame::AutoSpell_(SwTextNode & rNode, sal_Int32 nActPos)
1242 {
1243  SwRect aRect;
1244  assert(sw::FrameContainsNode(*this, rNode.GetIndex()));
1245  SwTextNode *const pNode(&rNode);
1246  if (!nActPos)
1247  nActPos = COMPLETE_STRING;
1248 
1250 
1251  // modify string according to redline information and hidden text
1252  const OUString aOldText( pNode->GetText() );
1253  OUStringBuffer buf(pNode->m_Text);
1254  const bool bRestoreString =
1255  lcl_MaskRedlinesAndHiddenText(*pNode, buf, 0, pNode->GetText().getLength());
1256  if (bRestoreString)
1257  { // ??? UGLY: is it really necessary to modify m_Text here? just for GetLang()?
1258  pNode->m_Text = buf.makeStringAndClear();
1259  }
1260 
1261  // a change of data indicates that at least one word has been modified
1262 
1263  sal_Int32 nBegin = 0;
1264  sal_Int32 nEnd = pNode->GetText().getLength();
1265  sal_Int32 nInsertPos = 0;
1266  sal_Int32 nChgStart = COMPLETE_STRING;
1267  sal_Int32 nChgEnd = 0;
1268  sal_Int32 nInvStart = COMPLETE_STRING;
1269  sal_Int32 nInvEnd = 0;
1270 
1271  const bool bAddAutoCmpl = pNode->IsAutoCompleteWordDirty() &&
1273 
1274  if( pNode->GetWrong() )
1275  {
1276  nBegin = pNode->GetWrong()->GetBeginInv();
1277  if( COMPLETE_STRING != nBegin )
1278  {
1279  nEnd = std::max(pNode->GetWrong()->GetEndInv(), pNode->GetText().getLength());
1280  }
1281 
1282  // get word around nBegin, we start at nBegin - 1
1283  if ( COMPLETE_STRING != nBegin )
1284  {
1285  if ( nBegin )
1286  --nBegin;
1287 
1288  LanguageType eActLang = pNode->GetLang( nBegin );
1289  Boundary aBound =
1290  g_pBreakIt->GetBreakIter()->getWordBoundary( pNode->GetText(), nBegin,
1291  g_pBreakIt->GetLocale( eActLang ),
1292  WordType::DICTIONARY_WORD, true );
1293  nBegin = aBound.startPos;
1294  }
1295 
1296  // get the position in the wrong list
1297  nInsertPos = pNode->GetWrong()->GetWrongPos( nBegin );
1298 
1299  // sometimes we have to skip one entry
1300  if( nInsertPos < pNode->GetWrong()->Count() &&
1301  nBegin == pNode->GetWrong()->Pos( nInsertPos ) +
1302  pNode->GetWrong()->Len( nInsertPos ) )
1303  nInsertPos++;
1304  }
1305 
1306  bool bFresh = nBegin < nEnd;
1307  bool bPending(false);
1308 
1309  if( bFresh )
1310  {
1311  uno::Reference< XSpellChecker1 > xSpell( ::GetSpellChecker() );
1312  SwDoc& rDoc = pNode->GetDoc();
1313 
1314  SwScanner aScanner( *pNode, pNode->GetText(), nullptr, ModelToViewHelper(),
1315  WordType::DICTIONARY_WORD, nBegin, nEnd);
1316 
1317  while( aScanner.NextWord() )
1318  {
1319  const OUString& rWord = aScanner.GetWord();
1320  nBegin = aScanner.GetBegin();
1321  sal_Int32 nLen = aScanner.GetLen();
1322 
1323  // get next language for next word, consider language attributes
1324  // within the word
1325  LanguageType eActLang = aScanner.GetCurrentLanguage();
1326  DetectAndMarkMissingDictionaries( rDoc, xSpell, eActLang );
1327 
1328  bool bSpell = xSpell.is() && xSpell->hasLanguage( static_cast<sal_uInt16>(eActLang) );
1329  if( bSpell && !rWord.isEmpty() )
1330  {
1331  // check for: bAlter => xHyphWord.is()
1332  OSL_ENSURE(!bSpell || xSpell.is(), "NULL pointer");
1333  if( !xSpell->isValid( rWord, static_cast<sal_uInt16>(eActLang), Sequence< PropertyValue >() ) &&
1334  // redlines can leave "in word" character within word,
1335  // we must remove them before spell checking
1336  // to avoid false alarm
1337  (!bRestoreString || !xSpell->isValid( rWord.replaceAll(OUStringChar(CH_TXTATR_INWORD), ""),
1338  static_cast<sal_uInt16>(eActLang), Sequence< PropertyValue >() ) ) )
1339  {
1340  sal_Int32 nSmartTagStt = nBegin;
1341  sal_Int32 nDummy = 1;
1342  if ( !pNode->GetSmartTags() || !pNode->GetSmartTags()->InWrongWord( nSmartTagStt, nDummy ) )
1343  {
1344  if( !pNode->GetWrong() )
1345  {
1346  pNode->SetWrong( new SwWrongList( WRONGLIST_SPELL ) );
1347  pNode->GetWrong()->SetInvalid( 0, nEnd );
1348  }
1349  SwWrongList::FreshState const eState(pNode->GetWrong()->Fresh(
1350  nChgStart, nChgEnd, nBegin, nLen, nInsertPos, nActPos));
1351  switch (eState)
1352  {
1354  pNode->GetWrong()->Insert(OUString(), nullptr, nBegin, nLen, nInsertPos++);
1355  break;
1357  bPending = true;
1358  [[fallthrough]]; // to mark as invalid
1360  nInvStart = nBegin;
1361  nInvEnd = nBegin + nLen;
1362  break;
1363  }
1364  }
1365  }
1366  else if( bAddAutoCmpl && rACW.GetMinWordLen() <= rWord.getLength() )
1367  {
1368  rACW.InsertWord( rWord, rDoc );
1369  }
1370  }
1371  }
1372  }
1373 
1374  // reset original text
1375  // i63141 before calling GetCharRect(..) with formatting!
1376  if ( bRestoreString )
1377  {
1378  pNode->m_Text = aOldText;
1379  }
1380  if( pNode->GetWrong() )
1381  {
1382  if( bFresh )
1383  pNode->GetWrong()->Fresh( nChgStart, nChgEnd,
1384  nEnd, 0, nInsertPos, nActPos );
1385 
1386  // Calculate repaint area:
1387 
1388  if( nChgStart < nChgEnd )
1389  {
1390  aRect = lcl_CalculateRepaintRect(*this, rNode, nChgStart, nChgEnd);
1391 
1392  // fdo#71558 notify misspelled word to accessibility
1393  SwViewShell* pViewSh = getRootFrame() ? getRootFrame()->GetCurrShell() : nullptr;
1394  if( pViewSh )
1395  pViewSh->InvalidateAccessibleParaAttrs( *this );
1396  }
1397 
1398  pNode->GetWrong()->SetInvalid( nInvStart, nInvEnd );
1399  pNode->SetWrongDirty(
1400  (COMPLETE_STRING != pNode->GetWrong()->GetBeginInv())
1401  ? (bPending
1405  if( !pNode->GetWrong()->Count() && ! pNode->IsWrongDirty() )
1406  pNode->SetWrong( nullptr );
1407  }
1408  else
1410 
1411  if( bAddAutoCmpl )
1412  pNode->SetAutoCompleteWordDirty( false );
1413 
1414  return aRect;
1415 }
1416 
1427 {
1428  SwRect aRet;
1429 
1430  assert(sw::FrameContainsNode(*this, rNode.GetIndex()));
1431  SwTextNode *const pNode = &rNode;
1432  const OUString& rText = pNode->GetText();
1433 
1434  // Iterate over language portions
1435  SmartTagMgr& rSmartTagMgr = SwSmartTagMgr::Get();
1436 
1437  SwWrongList* pSmartTagList = pNode->GetSmartTags();
1438 
1439  sal_Int32 nBegin = 0;
1440  sal_Int32 nEnd = rText.getLength();
1441 
1442  if ( pSmartTagList )
1443  {
1444  if ( pSmartTagList->GetBeginInv() != COMPLETE_STRING )
1445  {
1446  nBegin = pSmartTagList->GetBeginInv();
1447  nEnd = std::min( pSmartTagList->GetEndInv(), rText.getLength() );
1448 
1449  if ( nBegin < nEnd )
1450  {
1451  const LanguageType aCurrLang = pNode->GetLang( nBegin );
1452  const css::lang::Locale aCurrLocale = g_pBreakIt->GetLocale( aCurrLang );
1453  nBegin = g_pBreakIt->GetBreakIter()->beginOfSentence( rText, nBegin, aCurrLocale );
1454  nEnd = g_pBreakIt->GetBreakIter()->endOfSentence(rText, nEnd, aCurrLocale);
1455  if (nEnd > rText.getLength() || nEnd < 0)
1456  nEnd = rText.getLength();
1457  }
1458  }
1459  }
1460 
1461  const sal_uInt16 nNumberOfEntries = pSmartTagList ? pSmartTagList->Count() : 0;
1462  sal_uInt16 nNumberOfRemovedEntries = 0;
1463  sal_uInt16 nNumberOfInsertedEntries = 0;
1464 
1465  // clear smart tag list between nBegin and nEnd:
1466  if ( 0 != nNumberOfEntries )
1467  {
1468  sal_Int32 nChgStart = COMPLETE_STRING;
1469  sal_Int32 nChgEnd = 0;
1470  const sal_uInt16 nCurrentIndex = pSmartTagList->GetWrongPos( nBegin );
1471  pSmartTagList->Fresh( nChgStart, nChgEnd, nBegin, nEnd - nBegin, nCurrentIndex, COMPLETE_STRING );
1472  nNumberOfRemovedEntries = nNumberOfEntries - pSmartTagList->Count();
1473  }
1474 
1475  if ( nBegin < nEnd )
1476  {
1477  // Expand the string:
1478  const ModelToViewHelper aConversionMap(*pNode, getRootFrame() /*TODO - replace or expand fields for smart tags?*/);
1479  const OUString& aExpandText = aConversionMap.getViewText();
1480 
1481  // Ownership ov ConversionMap is passed to SwXTextMarkup object!
1482  uno::Reference<text::XTextMarkup> const xTextMarkup =
1483  new SwXTextMarkup(pNode, aConversionMap);
1484 
1485  css::uno::Reference< css::frame::XController > xController = pNode->GetDoc().GetDocShell()->GetController();
1486 
1487  SwPosition start(*pNode, nBegin);
1488  SwPosition end (*pNode, nEnd);
1489  Reference< css::text::XTextRange > xRange = SwXTextRange::CreateXTextRange(pNode->GetDoc(), start, &end);
1490 
1491  rSmartTagMgr.RecognizeTextRange(xRange, xTextMarkup, xController);
1492 
1493  sal_Int32 nLangBegin = nBegin;
1494  sal_Int32 nLangEnd;
1495 
1496  // smart tag recognition has to be done for each language portion:
1497  SwLanguageIterator aIter( *pNode, nLangBegin );
1498 
1499  do
1500  {
1501  const LanguageType nLang = aIter.GetLanguage();
1502  const css::lang::Locale aLocale = g_pBreakIt->GetLocale( nLang );
1503  nLangEnd = std::min<sal_Int32>( nEnd, aIter.GetChgPos() );
1504 
1505  const sal_Int32 nExpandBegin = aConversionMap.ConvertToViewPosition( nLangBegin );
1506  const sal_Int32 nExpandEnd = aConversionMap.ConvertToViewPosition( nLangEnd );
1507 
1508  rSmartTagMgr.RecognizeString(aExpandText, xTextMarkup, xController, aLocale, nExpandBegin, nExpandEnd - nExpandBegin );
1509 
1510  nLangBegin = nLangEnd;
1511  }
1512  while ( aIter.Next() && nLangEnd < nEnd );
1513 
1514  pSmartTagList = pNode->GetSmartTags();
1515 
1516  const sal_uInt16 nNumberOfEntriesAfterRecognize = pSmartTagList ? pSmartTagList->Count() : 0;
1517  nNumberOfInsertedEntries = nNumberOfEntriesAfterRecognize - ( nNumberOfEntries - nNumberOfRemovedEntries );
1518  }
1519 
1520  if( pSmartTagList )
1521  {
1522  // Update WrongList stuff
1523  pSmartTagList->SetInvalid( COMPLETE_STRING, 0 );
1524  pNode->SetSmartTagDirty( COMPLETE_STRING != pSmartTagList->GetBeginInv() );
1525 
1526  if( !pSmartTagList->Count() && !pNode->IsSmartTagDirty() )
1527  pNode->SetSmartTags( nullptr );
1528 
1529  // Calculate repaint area:
1530  if ( nBegin < nEnd && ( 0 != nNumberOfRemovedEntries ||
1531  0 != nNumberOfInsertedEntries ) )
1532  {
1533  aRet = lcl_CalculateRepaintRect(*this, rNode, nBegin, nEnd);
1534  }
1535  }
1536  else
1537  pNode->SetSmartTagDirty( false );
1538 
1539  return aRet;
1540 }
1541 
1542 void SwTextFrame::CollectAutoCmplWrds(SwTextNode & rNode, sal_Int32 nActPos)
1543 {
1544  assert(sw::FrameContainsNode(*this, rNode.GetIndex())); (void) this;
1545  SwTextNode *const pNode(&rNode);
1546  if (!nActPos)
1547  nActPos = COMPLETE_STRING;
1548 
1549  SwDoc& rDoc = pNode->GetDoc();
1551 
1552  sal_Int32 nBegin = 0;
1553  sal_Int32 nEnd = pNode->GetText().getLength();
1554  sal_Int32 nLen;
1555  bool bACWDirty = false;
1556 
1557  if( nBegin < nEnd )
1558  {
1559  int nCnt = 200;
1560  SwScanner aScanner( *pNode, pNode->GetText(), nullptr, ModelToViewHelper(),
1561  WordType::DICTIONARY_WORD, nBegin, nEnd );
1562  while( aScanner.NextWord() )
1563  {
1564  nBegin = aScanner.GetBegin();
1565  nLen = aScanner.GetLen();
1566  if( rACW.GetMinWordLen() <= nLen )
1567  {
1568  const OUString& rWord = aScanner.GetWord();
1569 
1570  if( nActPos < nBegin || ( nBegin + nLen ) < nActPos )
1571  {
1572  if( rACW.GetMinWordLen() <= rWord.getLength() )
1573  rACW.InsertWord( rWord, rDoc );
1574  }
1575  else
1576  bACWDirty = true;
1577  }
1578  if( !--nCnt )
1579  {
1580  // don't wait for TIMER here, so we can finish big paragraphs
1581  if (Application::AnyInput(VCL_INPUT_ANY & VclInputFlags(~VclInputFlags::TIMER)))
1582  return;
1583  nCnt = 100;
1584  }
1585  }
1586  }
1587 
1588  if (!bACWDirty)
1589  pNode->SetAutoCompleteWordDirty( false );
1590 }
1591 
1593  SwTextFrame const& rFrame, SwTextNode const& rNode,
1594  SwInterHyphInfo const& rHyphInfo)
1595  : m_nStart(rFrame.MapModelToView(&rNode, rHyphInfo.m_nStart))
1596  , m_nEnd(rFrame.MapModelToView(&rNode, rHyphInfo.m_nEnd))
1597  , m_nWordStart(0)
1598  , m_nWordLen(0)
1599 {
1600 }
1601 
1603  SwTextNode const& rNode, SwInterHyphInfo & o_rHyphInfo)
1604 {
1605  std::pair<SwTextNode const*, sal_Int32> const wordStart(rFrame.MapViewToModel(m_nWordStart));
1606  std::pair<SwTextNode const*, sal_Int32> const wordEnd(rFrame.MapViewToModel(m_nWordStart+m_nWordLen));
1607  if (wordStart.first != &rNode || wordEnd.first != &rNode)
1608  { // not sure if this can happen since nStart/nEnd are in rNode
1609  SAL_WARN("sw.core", "UpdateTextNodeHyphInfo: outside of node");
1610  return;
1611  }
1612  o_rHyphInfo.m_nWordStart = wordStart.second;
1613  o_rHyphInfo.m_nWordLen = wordEnd.second - wordStart.second;
1614  o_rHyphInfo.SetHyphWord(m_xHyphWord);
1615 }
1616 
1619 {
1620  // shortcut: paragraph doesn't have a language set:
1622  && LanguageType(USHRT_MAX) == GetLang(0, m_Text.getLength()))
1623  {
1624  return false;
1625  }
1626 
1628  [&rHyphInf, this]() {
1629  std::pair<Point, bool> tmp;
1630  Point const*const pPoint = rHyphInf.GetCursorPos();
1631  if (pPoint)
1632  {
1633  tmp.first = *pPoint;
1634  tmp.second = true;
1635  }
1636  return static_cast<SwTextFrame*>(this->getLayoutFrame(
1637  this->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(),
1638  nullptr, pPoint ? &tmp : nullptr));
1639  });
1640  if (!pFrame)
1641  {
1642  // There was a comment here that claimed that the following assertion
1643  // shouldn't exist as it's triggered by "Trennung ueber Sonderbereiche",
1644  // (hyphenation across special sections?), whatever that means.
1645  OSL_ENSURE( pFrame, "!SwTextNode::Hyphenate: can't find any frame" );
1646  return false;
1647  }
1648  SwInterHyphInfoTextFrame aHyphInfo(*pFrame, *this, rHyphInf);
1649 
1650  pFrame = &(pFrame->GetFrameAtOfst( aHyphInfo.m_nStart ));
1651 
1652  while( pFrame )
1653  {
1654  if (pFrame->Hyphenate(aHyphInfo))
1655  {
1656  // The layout is not robust wrt. "direct formatting"
1657  // cf. layact.cxx, SwLayAction::TurboAction_(), if( !pCnt->IsValid() ...
1658  pFrame->SetCompletePaint();
1659  aHyphInfo.UpdateTextNodeHyphInfo(*pFrame, *this, rHyphInf);
1660  return true;
1661  }
1662  pFrame = pFrame->GetFollow();
1663  if( pFrame )
1664  {
1665  aHyphInfo.m_nEnd = aHyphInfo.m_nEnd - (pFrame->GetOffset() - aHyphInfo.m_nStart);
1666  aHyphInfo.m_nStart = pFrame->GetOffset();
1667  }
1668  }
1669  return false;
1670 }
1671 
1672 namespace
1673 {
1674  struct swTransliterationChgData
1675  {
1676  sal_Int32 nStart;
1677  sal_Int32 nLen;
1678  OUString sChanged;
1679  Sequence< sal_Int32 > aOffsets;
1680  };
1681 }
1682 
1683 // change text to Upper/Lower/Hiragana/Katakana/...
1686  sal_Int32 nStt, sal_Int32 nEnd,
1687  SwUndoTransliterate* pUndo, bool bUseRedlining )
1688 {
1689  if (nStt >= nEnd)
1690  return;
1691 
1692  // since we don't use Hiragana/Katakana or half-width/full-width transliterations here
1693  // it is fine to use ANYWORD_IGNOREWHITESPACES. (ANY_WORD btw is broken and will
1694  // occasionally miss words in consecutive sentences). Also with ANYWORD_IGNOREWHITESPACES
1695  // text like 'just-in-time' will be converted to 'Just-In-Time' which seems to be the
1696  // proper thing to do.
1697  const sal_Int16 nWordType = WordType::ANYWORD_IGNOREWHITESPACES;
1698 
1699  // In order to have less trouble with changing text size, e.g. because
1700  // of ligatures or German small sz being resolved, we need to process
1701  // the text replacements from end to start.
1702  // This way the offsets for the yet to be changed words will be
1703  // left unchanged by the already replaced text.
1704  // For this we temporarily save the changes to be done in this vector
1705  std::vector< swTransliterationChgData > aChanges;
1706  swTransliterationChgData aChgData;
1707 
1708  if (rTrans.getType() == TransliterationFlags::TITLE_CASE)
1709  {
1710  // for 'capitalize every word' we need to iterate over each word
1711 
1712  Boundary aSttBndry;
1713  Boundary aEndBndry;
1714  aSttBndry = g_pBreakIt->GetBreakIter()->getWordBoundary(
1715  GetText(), nStt,
1716  g_pBreakIt->GetLocale( GetLang( nStt ) ),
1717  nWordType,
1718  true /*prefer forward direction*/);
1719  aEndBndry = g_pBreakIt->GetBreakIter()->getWordBoundary(
1720  GetText(), nEnd,
1721  g_pBreakIt->GetLocale( GetLang( nEnd ) ),
1722  nWordType,
1723  false /*prefer backward direction*/);
1724 
1725  // prevent backtracking to the previous word if selection is at word boundary
1726  if (aSttBndry.endPos <= nStt)
1727  {
1728  aSttBndry = g_pBreakIt->GetBreakIter()->nextWord(
1729  GetText(), aSttBndry.endPos,
1730  g_pBreakIt->GetLocale( GetLang( aSttBndry.endPos ) ),
1731  nWordType);
1732  }
1733  // prevent advancing to the next word if selection is at word boundary
1734  if (aEndBndry.startPos >= nEnd)
1735  {
1736  aEndBndry = g_pBreakIt->GetBreakIter()->previousWord(
1737  GetText(), aEndBndry.startPos,
1738  g_pBreakIt->GetLocale( GetLang( aEndBndry.startPos ) ),
1739  nWordType);
1740  }
1741 
1742  Boundary aCurWordBndry( aSttBndry );
1743  while (aCurWordBndry.startPos <= aEndBndry.startPos)
1744  {
1745  nStt = aCurWordBndry.startPos;
1746  nEnd = aCurWordBndry.endPos;
1747  const sal_Int32 nLen = nEnd - nStt;
1748  OSL_ENSURE( nLen > 0, "invalid word length of 0" );
1749 
1750  Sequence <sal_Int32> aOffsets;
1751  OUString const sChgd( rTrans.transliterate(
1752  GetText(), GetLang(nStt), nStt, nLen, &aOffsets) );
1753 
1754  assert(nStt < m_Text.getLength());
1755  if (0 != rtl_ustr_shortenedCompare_WithLength(
1756  m_Text.getStr() + nStt, m_Text.getLength() - nStt,
1757  sChgd.getStr(), sChgd.getLength(), nLen))
1758  {
1759  aChgData.nStart = nStt;
1760  aChgData.nLen = nLen;
1761  aChgData.sChanged = sChgd;
1762  aChgData.aOffsets = aOffsets;
1763  aChanges.push_back( aChgData );
1764  }
1765 
1766  aCurWordBndry = g_pBreakIt->GetBreakIter()->nextWord(
1767  GetText(), nStt,
1768  g_pBreakIt->GetLocale(GetLang(nStt, 1)),
1769  nWordType);
1770  }
1771  }
1772  else if (rTrans.getType() == TransliterationFlags::SENTENCE_CASE)
1773  {
1774  // for 'sentence case' we need to iterate sentence by sentence
1775 
1776  sal_Int32 nLastStart = g_pBreakIt->GetBreakIter()->beginOfSentence(
1777  GetText(), nEnd,
1778  g_pBreakIt->GetLocale( GetLang( nEnd ) ) );
1779  sal_Int32 nLastEnd = g_pBreakIt->GetBreakIter()->endOfSentence(
1780  GetText(), nLastStart,
1781  g_pBreakIt->GetLocale( GetLang( nLastStart ) ) );
1782 
1783  // extend nStt, nEnd to the current sentence boundaries
1784  sal_Int32 nCurrentStart = g_pBreakIt->GetBreakIter()->beginOfSentence(
1785  GetText(), nStt,
1786  g_pBreakIt->GetLocale( GetLang( nStt ) ) );
1787  sal_Int32 nCurrentEnd = g_pBreakIt->GetBreakIter()->endOfSentence(
1788  GetText(), nCurrentStart,
1789  g_pBreakIt->GetLocale( GetLang( nCurrentStart ) ) );
1790 
1791  // prevent backtracking to the previous sentence if selection starts at end of a sentence
1792  if (nCurrentEnd <= nStt)
1793  {
1794  // now nCurrentStart is probably located on a non-letter word. (unless we
1795  // are in Asian text with no spaces...)
1796  // Thus to get the real sentence start we should locate the next real word,
1797  // that is one found by DICTIONARY_WORD
1798  i18n::Boundary aBndry = g_pBreakIt->GetBreakIter()->nextWord(
1799  GetText(), nCurrentEnd,
1800  g_pBreakIt->GetLocale( GetLang( nCurrentEnd ) ),
1801  i18n::WordType::DICTIONARY_WORD);
1802 
1803  // now get new current sentence boundaries
1804  nCurrentStart = g_pBreakIt->GetBreakIter()->beginOfSentence(
1805  GetText(), aBndry.startPos,
1806  g_pBreakIt->GetLocale( GetLang( aBndry.startPos) ) );
1807  nCurrentEnd = g_pBreakIt->GetBreakIter()->endOfSentence(
1808  GetText(), nCurrentStart,
1809  g_pBreakIt->GetLocale( GetLang( nCurrentStart) ) );
1810  }
1811  // prevent advancing to the next sentence if selection ends at start of a sentence
1812  if (nLastStart >= nEnd)
1813  {
1814  // now nCurrentStart is probably located on a non-letter word. (unless we
1815  // are in Asian text with no spaces...)
1816  // Thus to get the real sentence start we should locate the previous real word,
1817  // that is one found by DICTIONARY_WORD
1818  i18n::Boundary aBndry = g_pBreakIt->GetBreakIter()->previousWord(
1819  GetText(), nLastStart,
1820  g_pBreakIt->GetLocale( GetLang( nLastStart) ),
1821  i18n::WordType::DICTIONARY_WORD);
1822  nLastEnd = g_pBreakIt->GetBreakIter()->endOfSentence(
1823  GetText(), aBndry.startPos,
1824  g_pBreakIt->GetLocale( GetLang( aBndry.startPos) ) );
1825  if (nCurrentEnd > nLastEnd)
1826  nCurrentEnd = nLastEnd;
1827  }
1828 
1829  while (nCurrentStart < nLastEnd)
1830  {
1831  sal_Int32 nLen = nCurrentEnd - nCurrentStart;
1832  OSL_ENSURE( nLen > 0, "invalid word length of 0" );
1833 
1834  Sequence <sal_Int32> aOffsets;
1835  OUString const sChgd( rTrans.transliterate(GetText(),
1836  GetLang(nCurrentStart), nCurrentStart, nLen, &aOffsets) );
1837 
1838  assert(nStt < m_Text.getLength());
1839  if (0 != rtl_ustr_shortenedCompare_WithLength(
1840  m_Text.getStr() + nStt, m_Text.getLength() - nStt,
1841  sChgd.getStr(), sChgd.getLength(), nLen))
1842  {
1843  aChgData.nStart = nCurrentStart;
1844  aChgData.nLen = nLen;
1845  aChgData.sChanged = sChgd;
1846  aChgData.aOffsets = aOffsets;
1847  aChanges.push_back( aChgData );
1848  }
1849 
1850  Boundary aFirstWordBndry = g_pBreakIt->GetBreakIter()->nextWord(
1851  GetText(), nCurrentEnd,
1852  g_pBreakIt->GetLocale( GetLang( nCurrentEnd ) ),
1853  nWordType);
1854  nCurrentStart = aFirstWordBndry.startPos;
1855  nCurrentEnd = g_pBreakIt->GetBreakIter()->endOfSentence(
1856  GetText(), nCurrentStart,
1857  g_pBreakIt->GetLocale( GetLang( nCurrentStart ) ) );
1858  }
1859  }
1860  else
1861  {
1862  // here we may transliterate over complete language portions...
1863 
1864  std::unique_ptr<SwLanguageIterator> pIter;
1865  if( rTrans.needLanguageForTheMode() )
1866  pIter.reset(new SwLanguageIterator( *this, nStt ));
1867 
1868  sal_Int32 nEndPos = 0;
1870  do {
1871  if( pIter )
1872  {
1873  nLang = pIter->GetLanguage();
1874  nEndPos = pIter->GetChgPos();
1875  if( nEndPos > nEnd )
1876  nEndPos = nEnd;
1877  }
1878  else
1879  {
1880  nLang = LANGUAGE_SYSTEM;
1881  nEndPos = nEnd;
1882  }
1883  const sal_Int32 nLen = nEndPos - nStt;
1884 
1885  Sequence <sal_Int32> aOffsets;
1886  OUString const sChgd( rTrans.transliterate(
1887  m_Text, nLang, nStt, nLen, &aOffsets) );
1888 
1889  assert(nStt < m_Text.getLength());
1890  if (0 != rtl_ustr_shortenedCompare_WithLength(
1891  m_Text.getStr() + nStt, m_Text.getLength() - nStt,
1892  sChgd.getStr(), sChgd.getLength(), nLen))
1893  {
1894  aChgData.nStart = nStt;
1895  aChgData.nLen = nLen;
1896  aChgData.sChanged = sChgd;
1897  aChgData.aOffsets = aOffsets;
1898  aChanges.push_back( aChgData );
1899  }
1900 
1901  nStt = nEndPos;
1902  } while( nEndPos < nEnd && pIter && pIter->Next() );
1903  }
1904 
1905  if (aChanges.empty())
1906  return;
1907 
1908  // now apply the changes from end to start to leave the offsets of the
1909  // yet unchanged text parts remain the same.
1910  size_t nSum(0);
1911 
1912  for (size_t i = 0; i < aChanges.size(); ++i)
1913  { // check this here since AddChanges cannot be moved below
1914  // call to ReplaceTextOnly
1915  swTransliterationChgData & rData =
1916  aChanges[ aChanges.size() - 1 - i ];
1917  nSum += rData.sChanged.getLength() - rData.nLen;
1918  if (nSum > o3tl::make_unsigned(GetSpaceLeft()))
1919  {
1920  SAL_WARN("sw.core", "SwTextNode::ReplaceTextOnly: "
1921  "node text with insertion > node capacity.");
1922  return;
1923  }
1924 
1925  if ( bUseRedlining )
1926  {
1927  // create SwPaM with mark & point spanning the attributed text
1928  //SwPaM aCurPaM( *this, *this, nBegin, nBegin + nLen ); <-- wrong c-tor, does sth different
1929  SwPaM aCurPaM( *this, rData.nStart );
1930  aCurPaM.SetMark();
1931  aCurPaM.GetPoint()->nContent = rData.nStart + rData.nLen;
1932  // replace the changed words
1933  if ( aCurPaM.GetText() != rData.sChanged )
1934  GetDoc().getIDocumentContentOperations().ReplaceRange( aCurPaM, rData.sChanged, false );
1935  }
1936  else
1937  {
1938  if (pUndo)
1939  pUndo->AddChanges( *this, rData.nStart, rData.nLen, rData.aOffsets );
1940  ReplaceTextOnly( rData.nStart, rData.nLen, rData.sChanged, rData.aOffsets );
1941  }
1942  }
1943 }
1944 
1945 void SwTextNode::ReplaceTextOnly( sal_Int32 nPos, sal_Int32 nLen,
1946  const OUString & rText,
1947  const Sequence<sal_Int32>& rOffsets )
1948 {
1949  assert(rText.getLength() - nLen <= GetSpaceLeft());
1950 
1951  m_Text = m_Text.replaceAt(nPos, nLen, rText);
1952 
1953  sal_Int32 nTLen = rText.getLength();
1954  const sal_Int32* pOffsets = rOffsets.getConstArray();
1955  // now look for no 1-1 mapping -> move the indices!
1956  sal_Int32 nMyOff = nPos;
1957  for( sal_Int32 nI = 0; nI < nTLen; ++nI )
1958  {
1959  const sal_Int32 nOff = pOffsets[ nI ];
1960  if( nOff < nMyOff )
1961  {
1962  // something is inserted
1963  sal_Int32 nCnt = 1;
1964  while( nI + nCnt < nTLen && nOff == pOffsets[ nI + nCnt ] )
1965  ++nCnt;
1966 
1967  Update( SwIndex( this, nMyOff ), nCnt );
1968  nMyOff = nOff;
1969  //nMyOff -= nCnt;
1970  nI += nCnt - 1;
1971  }
1972  else if( nOff > nMyOff )
1973  {
1974  // something is deleted
1975  Update( SwIndex( this, nMyOff+1 ), nOff - nMyOff, true );
1976  nMyOff = nOff;
1977  }
1978  ++nMyOff;
1979  }
1980  if( nMyOff < nLen )
1981  // something is deleted at the end
1982  Update( SwIndex( this, nMyOff ), nLen - nMyOff, true );
1983 
1984  // notify the layout!
1985  SwDelText aDelHint( nPos, nTLen );
1986  CallSwClientNotify(sw::LegacyModifyHint(nullptr, &aDelHint));
1987 
1988  SwInsText aHint( nPos, nTLen );
1989  CallSwClientNotify(sw::LegacyModifyHint(nullptr, &aHint));
1990 }
1991 
1992 // the return values allows us to see if we did the heavy-
1993 // lifting required to actually break and count the words.
1995  sal_Int32 nStt, sal_Int32 nEnd ) const
1996 {
1997  if( nStt > nEnd )
1998  { // bad call
1999  return false;
2000  }
2001  if (IsInRedlines())
2002  { //not counting txtnodes used to hold deleted redline content
2003  return false;
2004  }
2005  bool bCountAll = ( (0 == nStt) && (GetText().getLength() == nEnd) );
2006  ++rStat.nAllPara; // #i93174#: count _all_ paragraphs
2007  if ( IsHidden() )
2008  { // not counting hidden paras
2009  return false;
2010  }
2011  // count words in numbering string if started at beginning of para:
2012  bool bCountNumbering = nStt == 0;
2013  bool bHasBullet = false, bHasNumbering = false;
2014  OUString sNumString;
2015  if (bCountNumbering)
2016  {
2017  sNumString = GetNumString();
2018  bHasNumbering = !sNumString.isEmpty();
2019  if (!bHasNumbering)
2020  bHasBullet = HasBullet();
2021  bCountNumbering = bHasNumbering || bHasBullet;
2022  }
2023 
2024  if( nStt == nEnd && !bCountNumbering)
2025  { // unnumbered empty node or empty selection
2026  if (bCountAll)
2027  {
2028  SetWordCountDirty( false ); // reset flag to speed up DoIdleJob
2029  }
2030  return false;
2031  }
2032 
2033  // count of non-empty paras
2034  ++rStat.nPara;
2035 
2036  // Shortcut when counting whole paragraph and current count is clean
2037  if ( bCountAll && !IsWordCountDirty() )
2038  {
2039  // accumulate into DocStat record to return the values
2041  {
2046  }
2047  return false;
2048  }
2049 
2050  // ConversionMap to expand fields, remove invisible and redline deleted text for scanner
2051  const ModelToViewHelper aConversionMap(*this,
2052  getIDocumentLayoutAccess().GetCurrentLayout(),
2054  const OUString& aExpandText = aConversionMap.getViewText();
2055 
2056  if (aExpandText.isEmpty() && !bCountNumbering)
2057  {
2058  if (bCountAll)
2059  {
2060  SetWordCountDirty( false ); // reset flag to speed up DoIdleJob
2061  }
2062  return false;
2063  }
2064 
2065  // map start and end points onto the ConversionMap
2066  const sal_Int32 nExpandBegin = aConversionMap.ConvertToViewPosition( nStt );
2067  const sal_Int32 nExpandEnd = aConversionMap.ConvertToViewPosition( nEnd );
2068 
2069  //do the count
2070  // all counts exclude hidden paras and hidden+redlined within para
2071  // definition of space/white chars in SwScanner (and BreakIter!)
2072  // uses both u_isspace and BreakIter getWordBoundary in SwScanner
2073  sal_uInt32 nTmpWords = 0; // count of all words
2074  sal_uInt32 nTmpAsianWords = 0; //count of all Asian codepoints
2075  sal_uInt32 nTmpChars = 0; // count of all chars
2076  sal_uInt32 nTmpCharsExcludingSpaces = 0; // all non-white chars
2077 
2078  // count words in masked and expanded text:
2079  if (!aExpandText.isEmpty())
2080  {
2082 
2083  // zero is NULL for pLanguage -----------v last param = true for clipping
2084  SwScanner aScanner( *this, aExpandText, nullptr, aConversionMap, i18n::WordType::WORD_COUNT,
2085  nExpandBegin, nExpandEnd, true );
2086 
2087  // used to filter out scanner returning almost empty strings (len=1; unichar=0x0001)
2088  const OUString aBreakWord( CH_TXTATR_BREAKWORD );
2089 
2090  while ( aScanner.NextWord() )
2091  {
2092  if( !aExpandText.match(aBreakWord, aScanner.GetBegin() ))
2093  {
2094  ++nTmpWords;
2095  const OUString &rWord = aScanner.GetWord();
2096  if (g_pBreakIt->GetBreakIter()->getScriptType(rWord, 0) == i18n::ScriptType::ASIAN)
2097  ++nTmpAsianWords;
2098  nTmpCharsExcludingSpaces += g_pBreakIt->getGraphemeCount(rWord);
2099  }
2100  }
2101 
2102  nTmpCharsExcludingSpaces += aScanner.getOverriddenDashCount();
2103 
2104  nTmpChars = g_pBreakIt->getGraphemeCount(aExpandText, nExpandBegin, nExpandEnd);
2105  }
2106 
2107  // no nTmpCharsExcludingSpaces adjust needed neither for blanked out MaskedChars
2108  // nor for mid-word selection - set scanner bClip = true at creation
2109 
2110  // count outline number label - ? no expansion into map
2111  // always counts all of number-ish label
2112  if (bHasNumbering) // count words in numbering string
2113  {
2114  LanguageType aLanguage = GetLang( 0 );
2115 
2116  SwScanner aScanner( *this, sNumString, &aLanguage, ModelToViewHelper(),
2117  i18n::WordType::WORD_COUNT, 0, sNumString.getLength(), true );
2118 
2119  while ( aScanner.NextWord() )
2120  {
2121  ++nTmpWords;
2122  const OUString &rWord = aScanner.GetWord();
2123  if (g_pBreakIt->GetBreakIter()->getScriptType(rWord, 0) == i18n::ScriptType::ASIAN)
2124  ++nTmpAsianWords;
2125  nTmpCharsExcludingSpaces += g_pBreakIt->getGraphemeCount(rWord);
2126  }
2127 
2128  nTmpCharsExcludingSpaces += aScanner.getOverriddenDashCount();
2129  nTmpChars += g_pBreakIt->getGraphemeCount(sNumString);
2130  }
2131  else if ( bHasBullet )
2132  {
2133  ++nTmpWords;
2134  ++nTmpChars;
2135  ++nTmpCharsExcludingSpaces;
2136  }
2137 
2138  // If counting the whole para then update cached values and mark clean
2139  if ( bCountAll )
2140  {
2141  if ( m_pParaIdleData_Impl )
2142  {
2143  m_pParaIdleData_Impl->nNumberOfWords = nTmpWords;
2144  m_pParaIdleData_Impl->nNumberOfAsianWords = nTmpAsianWords;
2145  m_pParaIdleData_Impl->nNumberOfChars = nTmpChars;
2146  m_pParaIdleData_Impl->nNumberOfCharsExcludingSpaces = nTmpCharsExcludingSpaces;
2147  }
2148  SetWordCountDirty( false );
2149  }
2150  // accumulate into DocStat record to return the values
2151  rStat.nWord += nTmpWords;
2152  rStat.nAsianWord += nTmpAsianWords;
2153  rStat.nChar += nTmpChars;
2154  rStat.nCharExcludingSpaces += nTmpCharsExcludingSpaces;
2155 
2156  return true;
2157 }
2158 
2159 // Paragraph statistics start -->
2160 
2162 {
2163  if ( bNew )
2164  {
2166  }
2167  else if ( m_pParaIdleData_Impl )
2168  {
2169  delete m_pParaIdleData_Impl->pWrong;
2172  delete m_pParaIdleData_Impl;
2173  m_pParaIdleData_Impl = nullptr;
2174  }
2175 }
2176 
2177 void SwTextNode::SetWrong( SwWrongList* pNew, bool bDelete )
2178 {
2179  if ( m_pParaIdleData_Impl )
2180  {
2181  if ( bDelete )
2182  {
2183  delete m_pParaIdleData_Impl->pWrong;
2184  }
2185  m_pParaIdleData_Impl->pWrong = pNew;
2186  }
2187 }
2188 
2190 {
2191  return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->pWrong : nullptr;
2192 }
2193 
2194 // #i71360#
2196 {
2197  return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->pWrong : nullptr;
2198 }
2199 
2201 {
2202  if ( m_pParaIdleData_Impl )
2203  {
2204  if ( bDelete )
2205  {
2207  }
2209  }
2210 }
2211 
2213 {
2215 }
2216 
2218 {
2219  return static_cast<SwWrongList const*>(const_cast<SwTextNode*>(this)->GetGrammarCheck());
2220 }
2221 
2222 void SwTextNode::SetSmartTags( SwWrongList* pNew, bool bDelete )
2223 {
2224  OSL_ENSURE( !pNew || SwSmartTagMgr::Get().IsSmartTagsEnabled(),
2225  "Weird - we have a smart tag list without any recognizers?" );
2226 
2227  if ( m_pParaIdleData_Impl )
2228  {
2229  if ( bDelete )
2230  {
2232  }
2234  }
2235 }
2236 
2238 {
2240 }
2241 
2243 {
2244  return const_cast<SwWrongList const*>(const_cast<SwTextNode*>(this)->GetSmartTags());
2245 }
2246 
2247 void SwTextNode::SetWordCountDirty( bool bNew ) const
2248 {
2249  if ( m_pParaIdleData_Impl )
2250  {
2252  }
2253 }
2254 
2256 {
2258 }
2259 
2261 {
2262  if ( m_pParaIdleData_Impl )
2263  {
2265  }
2266 }
2267 
2269 {
2271 }
2272 
2274 {
2276 }
2277 
2278 void SwTextNode::SetGrammarCheckDirty( bool bNew ) const
2279 {
2280  if ( m_pParaIdleData_Impl )
2281  {
2283  }
2284 }
2285 
2287 {
2289 }
2290 
2291 void SwTextNode::SetSmartTagDirty( bool bNew ) const
2292 {
2293  if ( m_pParaIdleData_Impl )
2294  {
2296  }
2297 }
2298 
2300 {
2302 }
2303 
2305 {
2306  if ( m_pParaIdleData_Impl )
2307  {
2309  }
2310 }
2311 
2313 {
2315 }
2316 
2317 // <-- Paragraph statistics end
2318 
2319 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
void SetWordCountDirty(bool bNew) const
Definition: txtedt.cxx:2247
sal_Int32 Pos(sal_uInt16 nIdx) const
Definition: wrong.hxx:318
void SetTop(SwRect &rRect, tools::Long nNew) const
Definition: frame.hxx:1382
void SetCharSet(rtl_TextEncoding _eEncoding)
const sal_Int32 m_nLength
OUString m_aWord
Definition: swscanner.hxx:35
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:157
virtual std::shared_ptr< SfxItemSet > getAutomaticStyle(const SfxItemSet &rSet, SwAutoStyleFamily eFamily, const OUString *pParentName=nullptr)=0
#define LANGUAGE_NONE
bool bAllowImplicitChangesForNotConvertibleText
Definition: splargs.hxx:72
tools::Long GetRight(const SwRect &rRect) const
Definition: frame.hxx:1376
sal_uLong GetIndex() const
Definition: node.hxx:291
bool InsertWord(const OUString &rWord, SwDoc &rDoc)
Definition: acmplwrd.cxx:219
SwInterHyphInfoTextFrame(SwTextFrame const &rFrame, SwTextNode const &rNode, SwInterHyphInfo const &rHyphInfo)
Definition: txtedt.cxx:1592
bool HasBullet() const
Returns if this text node has a bullet.
Definition: ndtxt.cxx:3103
void SetStyleName(const OUString &rStyleName)
SwGrammarMarkUp * pGrammarCheck
Definition: txtedt.cxx:103
SwScanner(const std::function< LanguageType(sal_Int32, sal_Int32, bool)> &pGetLangOfChar, const OUString &rText, const LanguageType *pLang, const ModelToViewHelper &rConvMap, sal_uInt16 nWordType, sal_Int32 nStart, sal_Int32 nEnd, bool bClip=false)
Marks a position in the document model.
Definition: pam.hxx:35
const OUString & GetFamilyName() const
constexpr TypedWhichId< SwFormatMeta > RES_TXTATR_METAFIELD(49)
sal_uLong nPara
paragraphs for document statistic: non-empty and non-hidden ones
Definition: docstat.hxx:32
const OUString & GetText() const
Definition: ndtxt.hxx:210
virtual bool get(DocumentSettingId id) const override
Return the specified document setting.
static SwAutoCompleteWord & GetAutoCompleteWords()
Definition: doc.hxx:1534
bool IsWrongDirty() const
Definition: txtedt.cxx:2273
SwDocShell * GetDocShell()
Definition: doc.hxx:1353
SwpHints * GetpSwpHints()
Definition: ndtxt.hxx:218
const OUString & GetStyleName() const
bool isTXTATR_WITHEND(const sal_uInt16 nWhich)
Definition: hintids.hxx:475
FreshState Fresh(sal_Int32 &rStart, sal_Int32 &rEnd, sal_Int32 nPos, sal_Int32 nLen, sal_uInt16 nIndex, sal_Int32 nCursorPos)
Remove given range of entries.
Definition: wrong.cxx:355
void InvalidateAccessibleParaAttrs(const SwTextFrame &rTextFrame)
invalidate attributes for paragraphs and paragraph's characters
Definition: viewsh.cxx:2508
constexpr TypedWhichId< SwFormatMeta > RES_TXTATR_META(48)
SwNodeIndex nNode
Definition: pam.hxx:37
void SetPitch(FontPitch _ePitch)
void SetCompletePaint() const
Definition: frame.hxx:990
virtual void InsertItemSet(const SwPaM &rRg, const SfxItemSet &, const SetAttrMode nFlags=SetAttrMode::DEFAULT, SwRootFrame const *pLayout=nullptr)=0
sal_Int32 GetSpaceLeft() const
Definition: ndtxt.hxx:862
virtual const sal_Int32 * GetEnd() const
end position
Definition: txatbase.cxx:48
sal_uIntPtr sal_uLong
void UpdateTextNodeHyphInfo(SwTextFrame const &rFrame, SwTextNode const &rNode, SwInterHyphInfo &o_rHyphInfo)
Definition: txtedt.cxx:1602
bool Spell(SwSpellArgs *)
Definition: txtedt.cxx:940
css::uno::Reference< css::linguistic2::XSpellChecker1 > xSpeller
Definition: splargs.hxx:88
sal_uInt16 m_nWordType
Definition: swscanner.hxx:46
Implementation of the css::text::XTextMarkup interface.
void SetStart(sal_Int32 n)
start position
Definition: txatbase.hxx:85
LanguageType GetLanguage(SfxItemSet const &aSet, sal_uInt16 nLangWhichId)
Definition: langhelper.cxx:390
static bool lcl_MaskRedlinesAndHiddenText(const SwTextNode &rNode, OUStringBuffer &rText, sal_Int32 nStt, sal_Int32 nEnd, const sal_Unicode cChar=CH_TXTATR_INWORD)
Used for spell checking.
Definition: txtedt.cxx:180
static bool IsAutoCompleteWords()
Definition: viewopt.cxx:333
SwContentFrame * getLayoutFrame(const SwRootFrame *, const SwPosition *pPos=nullptr, std::pair< Point, bool > const *pViewPosAndCalcFrame=nullptr) const
Definition: node.cxx:1212
Definition: doc.hxx:187
const LanguageTag & getLanguageTag() const
TransliterationFlags getType() const
bool HasFollow() const
Definition: flowfrm.hxx:165
SAL_DLLPRIVATE void SetLanguageAndFont(const SwPaM &rPaM, LanguageType nLang, sal_uInt16 nLangWhichId, const vcl::Font *pFont, sal_uInt16 nFontWhichId)
Definition: txtedt.cxx:1070
aBuf
void SetFamily(FontFamily _eFamily)
sal_uLong nChar
Definition: docstat.hxx:37
LanguageType GetCurrentLanguage() const
Definition: swscanner.hxx:70
const ContentProperties & rData
SwNode & GetNode() const
Definition: ndindex.hxx:119
void TryDeleteSwpHints()
Definition: ndtxt.hxx:831
bool IsSmartTagDirty() const
Definition: txtedt.cxx:2299
sal_uLong nNumberOfWords
Definition: txtedt.cxx:105
This struct defines a position in the model string.
Of course Writer needs its own rectangles.
Definition: swrect.hxx:35
sal_uInt16 Which() const
Definition: txatbase.hxx:114
sal_Int32 m_nStartPos
Definition: swscanner.hxx:40
const OUString & GetText() const
Returns the text portion we want to edit (for inline see underneath)
Definition: txtfrm.cxx:1285
SwTextAttr * GetTextAttrAt(sal_Int32 const nIndex, sal_uInt16 const nWhich, enum GetTextAttrMode const eMode=DEFAULT) const
get the innermost text attribute covering position nIndex.
Definition: ndtxt.cxx:1731
const vcl::Font * pTargetFont
Definition: splargs.hxx:70
IDocumentContentOperations const & getIDocumentContentOperations() const
Definition: doc.cxx:315
void SetSmartTags(SwWrongList *pNew, bool bDelete=true)
Definition: txtedt.cxx:2222
void SetGrammarCheckDirty(bool bNew) const
Definition: txtedt.cxx:2278
void CalcStartEnd(sal_uLong nNdIdx, sal_Int32 &rStart, sal_Int32 &rEnd) const
Calculates the intersection with text node number nNdIdx.
Definition: docredln.cxx:1303
sal_uLong nCharExcludingSpaces
Definition: docstat.hxx:38
const Point * GetCursorPos() const
Definition: splargs.hxx:131
sal_Int32 m_nWordStart
output: found word
Definition: splargs.hxx:121
FontFamily GetFamilyType()
VclInputFlags
static bool IsShowChanges(const RedlineFlags eM)
bool IsSymbolAt(sal_Int32 nBegin) const
in ndcopy.cxx
Definition: itratr.cxx:853
static LanguageType nLang
Definition: srtdlg.cxx:51
void SetFamilyName(const OUString &rFamilyName)
bool Hyphenate(SwInterHyphInfoTextFrame &rInf)
We format a Line for interactive hyphenation.
Definition: txthyph.cxx:58
size_type size() const
Definition: docary.hxx:266
bool IsHiddenNow() const
Hidden.
Definition: txtfrm.cxx:1352
tools::Long GetTop(const SwRect &rRect) const
Definition: frame.hxx:1373
OUString GetCurWord(SwPosition const &) const
Definition: txtedt.cxx:655
#define CH_TXTATR_BREAKWORD
Definition: hintids.hxx:169
SwRect GetPaintArea() const
|* The paintarea is the area, in which the content of a frame is allowed |* to be displayed...
Definition: ssfrm.cxx:589
sal_Int32 getGraphemeCount(const OUString &rStr, sal_Int32 nStart, sal_Int32 nEnd) const
Definition: breakit.cxx:157
bool isLetterNumeric(const OUString &rStr, sal_Int32 nPos) const
sal_uInt16 sal_Unicode
static sal_Int32 MaskHiddenRanges(const SwTextNode &rNode, OUStringBuffer &rText, const sal_Int32 nStt, const sal_Int32 nEnd, const sal_Unicode cChar)
Hidden text attribute handling.
Definition: porlay.cxx:1773
const SfxPoolItem * NextItem()
void SetBottom(SwRect &rRect, tools::Long nNew) const
Definition: frame.hxx:1383
bool IsInRedlines() const
Checks if this node is in redlines.
Definition: node.cxx:2109
#define CH_TXTATR_INWORD
Definition: hintids.hxx:170
Reference< XController > xController
SwIndex nContent
Definition: pam.hxx:38
TextFrameIndex m_nWordStart
output: found word
Definition: txtfrm.hxx:63
sal_Int32 ConvertToViewPosition(sal_Int32 nModelPos) const
Converts a model position into a view position.
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
A wrapper around SfxPoolItem to store the start position of (usually) a text portion, with an optional end.
Definition: txatbase.hxx:41
void DestroyAttr(SwTextAttr *pAttr)
Definition: thints.cxx:1163
bool bAutoComplDirty
auto complete list dirty
Definition: txtedt.cxx:113
SwBreakIt * g_pBreakIt
Definition: breakit.cxx:33
sal_Int32 GetStart() const
Definition: txatbase.hxx:86
sal_Int32 m_nEndPos
Definition: swscanner.hxx:41
sal_Int32 m_nOverriddenDashCount
Definition: swscanner.hxx:44
bool IsWordCountDirty() const
Definition: txtedt.cxx:2255
sal_Int32 m_nBegin
Definition: swscanner.hxx:42
constexpr TypedWhichId< SwFormatAutoFormat > RES_TXTATR_AUTOFMT(50)
sal_uLong nNumberOfChars
Definition: txtedt.cxx:107
bool needLanguageForTheMode() const
tools::Long GetLeft(const SwRect &rRect) const
Definition: frame.hxx:1375
void SetWrongDirty(WrongState eNew) const
Definition: txtedt.cxx:2260
static sal_Int16 CheckSpellLang(css::uno::Reference< css::linguistic2::XSpellChecker1 > const &xSpell, LanguageType nLang)
TextFrameIndex m_nEnd
Definition: txtfrm.hxx:61
std::function< LanguageType(sal_Int32, sal_Int32, bool)> m_pGetLangOfChar
Definition: swscanner.hxx:34
SwTextFrame * GetFollow()
Definition: txtfrm.hxx:852
TextFrameIndex GetOffset() const
Definition: txtfrm.hxx:435
SAL_DLLPRIVATE void InitSwParaStatistics(bool bNew)
Start: Data collected during idle time.
Definition: txtedt.cxx:2161
OUString GetText() const
Definition: pam.cxx:1076
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:136
void TransliterateText(utl::TransliterationWrapper &rTrans, sal_Int32 nStart, sal_Int32 nEnd, SwUndoTransliterate *pUndo, bool bUseRedlining=false)
change text to Upper/Lower/Hiragana/Katakana/...
Definition: txtedt.cxx:1684
sal_Int32 NextWrong(sal_Int32 nChk) const
Find next incorrectly selected position.
Definition: wrong.cxx:163
bool FrameContainsNode(SwContentFrame const &rFrame, sal_uLong nNodeIndex)
Definition: txtfrm.cxx:284
const SfxItemPool & GetAttrPool() const
Definition: viewsh.hxx:612
virtual SwRedlineTable::size_type GetRedlinePos(const SwNode &rNode, RedlineType nType) const =0
SwIndex * pStartIdx
Definition: splargs.hxx:39
LanguageType nConvTextLang
Definition: splargs.hxx:66
UNDERLYING_TYPE get() const
bool m_bClip
Definition: swscanner.hxx:47
void RstTextAttr(const SwIndex &rIdx, const sal_Int32 nLen, const sal_uInt16 nWhich=0, const SfxItemSet *pSet=nullptr, const bool bInclRefToxMark=false, const bool bExactRange=false)
delete all attributes.
Definition: txtedt.cxx:355
const OUString & getViewText() const
sal_uInt16 Count() const
Definition: wrong.hxx:323
SvtScriptType GetScriptType() const
returns the script type of the selection
Definition: edattr.cxx:673
TextFrameIndex MapModelToViewPos(SwPosition const &rPos) const
Definition: txtfrm.cxx:1259
sal_uLong nAsianWord
Definition: docstat.hxx:36
#define SW_MOD()
Definition: swmodule.hxx:256
FontPitch GetPitch()
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
SwWrongList * pSmartTags
Definition: txtedt.cxx:104
int i
void SetSmartTagDirty(bool bNew) const
Definition: txtedt.cxx:2291
const ModelToViewHelper m_ModelToView
Definition: swscanner.hxx:39
SwDoc & GetDoc()
Definition: node.hxx:212
const SwPosition * GetPoint() const
Definition: pam.hxx:207
void RecognizeTextRange(const css::uno::Reference< css::text::XTextRange > &rRange, const css::uno::Reference< css::text::XTextMarkup > &rMarkup, const css::uno::Reference< css::frame::XController > &rController) const
static bool AnyInput(VclInputFlags nType=VCL_INPUT_ANY)
SwIndex & Assign(SwIndexReg *, sal_Int32)
Definition: index.cxx:206
static SwSmartTagMgr & Get()
SwEditShell const * GetEditShell() const
Definition: doccorr.cxx:328
SwTextAttr * MakeTextAttr(SwDoc &rDoc, SfxPoolItem &rAttr, sal_Int32 const nStt, sal_Int32 const nEnd, CopyOrNewType const bIsCopy, SwTextNode *const pTextNode)
if COPY then pTextNode must be given!
Definition: thints.cxx:1016
#define LANGUAGE_SYSTEM
void Push()
store a copy of the current cursor on the cursor stack
Definition: crsrsh.cxx:2237
Count
bool HasContent() const
Definition: txatbase.hxx:110
TextFrameIndex MapModelToView(MergedPara const &, SwTextNode const *pNode, sal_Int32 nIndex)
Definition: txtfrm.cxx:1175
static bool IsChinese(LanguageType nLang)
vector_type::size_type size_type
Definition: docary.hxx:228
sal_uInt16 Count() const
sal_Int32 m_nWordLen
Definition: splargs.hxx:122
static bool lcl_HaveCommonAttributes(IStyleAccess &rStyleAccess, const SfxItemSet *pSet1, sal_uInt16 nWhichId, const SfxItemSet &rSet2, std::shared_ptr< SfxItemSet > &pStyleHandle)
Used for automatic styles.
Definition: txtedt.cxx:286
void SetAutoCompleteWordDirty(bool bNew) const
Definition: txtedt.cxx:2304
void SetRight(SwRect &rRect, tools::Long nNew) const
Definition: frame.hxx:1385
LanguageType nConvSrcLang
Definition: splargs.hxx:65
SwTextFrame & GetFrameAtOfst(TextFrameIndex nOfst)
Definition: frmcrsr.cxx:143
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
sal_Int32 Len(sal_uInt16 nIdx) const
Definition: wrong.hxx:313
Marks a character position inside a document model node.
Definition: index.hxx:33
void SetSelection(const SwPaM &rCursor)
Definition: crsrsh.cxx:3511
SwGrammarMarkUp * GetGrammarCheck()
Definition: txtedt.cxx:2212
const OUString m_aPreDashReplacementText
Definition: swscanner.hxx:36
bool Hyphenate(SwInterHyphInfo &rHyphInf)
Interactive hyphenation: we find TextFrame and call its CalcHyph.
Definition: txtedt.cxx:1618
void SetMissingDictionaries(bool bIsMissing)
Use to notify if the dictionary can be found for a single content portion (has to be called for all p...
Definition: doc.cxx:1822
css::uno::Reference< css::linguistic2::XHyphenatedWord > m_xHyphWord
output: hyphenated word
Definition: txtfrm.hxx:57
sal_uInt16 GetSortNumber() const
Definition: txtatr.hxx:49
SwWrongList * GetSmartTags()
Definition: txtedt.cxx:2237
virtual bool ReplaceRange(SwPaM &rPam, const OUString &rNewStr, const bool bRegExReplace)=0
Replace selected range in a TextNode with string.
LanguageType nConvTargetLang
Definition: splargs.hxx:69
T static_txtattr_cast(S *s)
Definition: txatbase.hxx:241
attention: NOHINTADJUST prevents MergePortions! when using this need to pay attention to ignore start...
sal_Int32 GetChgPos() const
Definition: txatritr.hxx:67
SwWrongList * pWrong
Definition: txtedt.cxx:102
std::pair< SwTextNode *, sal_Int32 > MapViewToModel(TextFrameIndex nIndex) const
map position in potentially merged text frame to SwPosition
Definition: txtfrm.cxx:1223
sal_uLong nNumberOfCharsExcludingSpaces
Definition: txtedt.cxx:108
sal_Int32 GetEndInv() const
Definition: wrong.hxx:289
enumrange< T >::Iterator end(enumrange< T >)
const SwPosition * Start() const
Definition: pam.hxx:212
EXPAND : (Start < nIndex <= End)
Definition: ndtxt.hxx:363
#define VCL_INPUT_ANY
const IDocumentLayoutAccess & getIDocumentLayoutAccess() const
Provides access to the document layout interface.
Definition: node.cxx:2097
void SetGrammarCheck(SwGrammarMarkUp *pNew, bool bDelete=true)
Definition: txtedt.cxx:2200
css::uno::Reference< css::i18n::XBreakIterator > const & GetBreakIter() const
Definition: breakit.hxx:62
void ReplaceTextOnly(sal_Int32 nPos, sal_Int32 nLen, const OUString &rText, const css::uno::Sequence< sal_Int32 > &rOffsets)
Definition: txtedt.cxx:1945
uno::Reference< linguistic2::XSpellChecker1 > GetSpellChecker()
Definition: swtypes.cxx:52
virtual void SetEnd(sal_Int32)
Definition: txatbase.cxx:53
const OUString & GetWord() const
Definition: swscanner.hxx:64
OUString aConvText
Definition: splargs.hxx:64
const css::lang::Locale & GetLocale(const LanguageType aLang)
Definition: breakit.hxx:67
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:79
SwTextNode::WrongState eWrongDirty
online spell checking needed/done?
Definition: txtedt.cxx:110
static sal_Int32 lcl_MaskRedlines(const SwTextNode &rNode, OUStringBuffer &rText, sal_Int32 nStt, sal_Int32 nEnd, const sal_Unicode cChar)
Definition: txtedt.cxx:136
css::uno::Reference< css::linguistic2::XSpellAlternatives > xSpellAlt
Definition: splargs.hxx:90
friend class SwIndex
Definition: index.hxx:108
IDocumentRedlineAccess const & getIDocumentRedlineAccess() const
Definition: doc.cxx:335
sal_Int32 GetBeginInv() const
Definition: wrong.hxx:288
void SetHyphWord(const css::uno::Reference< css::linguistic2::XHyphenatedWord > &rxHW)
Definition: splargs.hxx:135
SwRect AutoSpell_(SwTextNode &, sal_Int32)
Is called by DoIdleJob_() and ExecSpellPopup()
Definition: txtedt.cxx:1241
sal_Int32 m_nLength
Definition: swscanner.hxx:43
sal_uInt16 GetMinWordLen() const
Definition: acmplwrd.hxx:64
WrongState GetWrongDirty() const
Definition: txtedt.cxx:2268
css::uno::Reference< css::frame::XController > GetController()
Definition: docsh.cxx:1279
virtual std::unique_ptr< SfxItemSet > Clone(bool bItems=true, SfxItemPool *pToPool=nullptr) const
const o3tl::enumarray< SvxAdjust, unsigned short > aSvxToUnoAdjust USHRT_MAX
Definition: unosett.cxx:254
sal_uInt16 GetWrongPos(sal_Int32 nValue) const
Find the first position that is greater or equal to the given value.
Definition: wrong.cxx:190
SwParaIdleData_Impl * m_pParaIdleData_Impl
Definition: ndtxt.hxx:100
TextFrameIndex MapModelToView(SwTextNode const *pNode, sal_Int32 nIndex) const
Definition: txtfrm.cxx:1244
OUString transliterate(const OUString &rStr, sal_Int32 nStart, sal_Int32 nLen) const
sal_Int32 GetIndex() const
Definition: index.hxx:91
bool InWrongWord(sal_Int32 &rChk, sal_Int32 &rLn) const
If a word is incorrectly selected, this method returns begin and length of it.
Definition: wrong.cxx:102
void CollectAutoCmplWrds(SwTextNode &, sal_Int32)
Is called by DoIdleJob_()
Definition: txtedt.cxx:1542
constexpr TypedWhichId< SvxFontItem > RES_CHRATR_CJK_FONT(22)
::sw::DocumentSettingManager & GetDocumentSettingManager()
Definition: doc.cxx:186
LanguageType GetLang(const sal_Int32 nBegin, const sal_Int32 nLen=0, sal_uInt16 nScript=0) const
Definition: thints.cxx:3424
TextFrameIndex m_nStart
input: requested range to hyphenate
Definition: txtfrm.hxx:60
void SetWrong(SwWrongList *pNew, bool bDelete=true)
Definition: txtedt.cxx:2177
RedlineType GetType(sal_uInt16 nPos=0) const
Definition: docredln.cxx:1810
const sal_Int32 * End() const
Definition: txatbase.hxx:152
ModelPosition ConvertToModelPosition(sal_Int32 nViewPos) const
Converts a view position into a model position.
QPRO_FUNC_TYPE nType
SwRect SmartTagScan(SwTextNode &)
Is called by DoIdleJob_()
Definition: txtedt.cxx:1426
bool IsHidden() const
Definition: ndtxt.cxx:4563
SwWrongList * GetWrong()
Definition: txtedt.cxx:2189
constexpr TypedWhichId< SwTOXMark > RES_TXTATR_TOXMARK(47)
const char * pChar
sal_Int32 GetBegin() const
Definition: swscanner.hxx:66
bool IsAutoCompleteWordDirty() const
Definition: txtedt.cxx:2312
bool CountWords(SwDocStat &rStat, sal_Int32 nStart, sal_Int32 nEnd) const
count words in given range - returns true if we refreshed out count
Definition: txtedt.cxx:1994
const LanguageType * m_pLanguage
Definition: swscanner.hxx:38
constexpr TypedWhichId< SwFormatField > RES_TXTATR_INPUTFIELD(55)
a clone of SwInterHyphInfo, but with TextFrameIndex instead of node index
Definition: txtfrm.hxx:53
const SwAttrSet & GetSwAttrSet() const
Does node has already its own auto-attributes? Access to SwAttrSet.
Definition: node.hxx:718
virtual void CallSwClientNotify(const SfxHint &rHint) const override
Definition: calbck.cxx:324
void RecognizeString(const OUString &rText, const css::uno::Reference< css::text::XTextMarkup > &rMarkup, const css::uno::Reference< css::frame::XController > &rController, const css::lang::Locale &rLocale, sal_uInt32 nStart, sal_uInt32 nLen) const
bool InsertHint(SwTextAttr *const pAttr, const SetAttrMode nMode=SetAttrMode::DEFAULT)
Insert pAttr into hints array.
Definition: thints.cxx:1306
sal_uLong nNumberOfAsianWords
Definition: txtedt.cxx:106
OUString GetNumString(const bool _bInclPrefixAndSuffixStrings=true, const unsigned int _nRestrictToThisLevel=MAXLEVEL, SwRootFrame const *pLayout=nullptr) const
Returns outline of numbering string.
Definition: ndtxt.cxx:3121
const SfxPoolItem & GetAttr() const
Definition: txatbase.hxx:163
SwTextNode * pStartNode
Definition: splargs.hxx:38
LanguageType m_aCurrentLang
Definition: swscanner.hxx:45
tools::Long GetBottom(const SwRect &rRect) const
Definition: frame.hxx:1374
void setLanguageTag(const LanguageTag &rLanguageTag)
virtual RedlineFlags GetRedlineFlags() const =0
Query the currently set redline mode.
#define SAL_WARN(area, stream)
SwIndex * pEndIdx
Definition: splargs.hxx:41
void SetLeft(SwRect &rRect, tools::Long nNew) const
Definition: frame.hxx:1384
SwFormatColl * GetFormatColl() const
Definition: node.hxx:456
std::unique_ptr< SwpHints > m_pSwpHints
May be 0.
Definition: ndtxt.hxx:93
virtual void SetMark()
Unless this is called, the getter method of Mark will return Point.
Definition: pam.cxx:478
static sal_Int32 clipIndexBounds(const OUString &rStr, sal_Int32 nPos)
Definition: txtedt.cxx:642
SwTextFrame * SwHyphIterCacheLastTextFrame(SwTextNode const *pNode, const sw::Creator &create)
Definition: edlingu.cxx:585
constexpr TypedWhichId< SwFormatRefMark > RES_TXTATR_REFMARK(RES_TXTATR_WITHEND_BEGIN)
bool Pop(PopMode)
delete cursor
Definition: crsrsh.cxx:2259
sal_uLong nWord
Definition: docstat.hxx:35
static css::uno::Reference< css::text::XTextRange > CreateXTextRange(SwDoc &rDoc, const SwPosition &rPos, const SwPosition *const pMark)
Definition: unoobj2.cxx:1199
virtual const SwRedlineTable & GetRedlineTable() const =0
bool NextWord()
Definition: txtedt.cxx:798
sal_uLong nAllPara
all paragraphs, including empty/hidden ones
Definition: docstat.hxx:34
void Insert(sal_uInt16 nWhere, std::vector< SwWrongArea >::iterator startPos, std::vector< SwWrongArea >::iterator const &endPos)
Definition: wrong.cxx:537
static SwRect lcl_CalculateRepaintRect(SwTextFrame &rTextFrame, SwTextNode &rNode, sal_Int32 const nChgStart, sal_Int32 const nChgEnd)
Used for spell checking.
Definition: txtedt.cxx:213
SwViewShell * GetCurrShell() const
Definition: rootfrm.hxx:208
o3tl::strong_int< sal_Int32, struct Tag_TextFrameIndex > TextFrameIndex
Denotes a character index in a text frame at a layout level, after extent mapping from a text node at...
bool Convert(SwConversionArgs &)
Definition: txtedt.cxx:1105
TextFrameIndex m_nWordLen
Definition: txtfrm.hxx:64
CharClass & GetAppCharClass()
Definition: init.cxx:712
void Height(tools::Long nNew)
Definition: swrect.hxx:191
LanguageType GetLanguage() const
Definition: txatritr.hxx:68
SwTextNode * pEndNode
Definition: splargs.hxx:40
OUString m_Text
Definition: ndtxt.hxx:98
IStyleAccess & getIDocumentStyleAccess()
Provides access to the document automatic styles interface.
Definition: node.cxx:2107
const sal_Int32 COMPLETE_STRING
Definition: swtypes.hxx:61
sal_uInt16 Which() const
SwRootFrame * getRootFrame()
Definition: frame.hxx:677
constexpr TypedWhichId< SvxLanguageItem > RES_CHRATR_CJK_LANGUAGE(24)
virtual void Update(SwIndex const &rPos, const sal_Int32 nChangeLen, const bool bNegative=false, const bool bDelete=false) override
override SwIndexReg
Definition: ndtxt.cxx:1176
OUString m_aText
Definition: swscanner.hxx:37
void SetInvalid(sal_Int32 nBegin, sal_Int32 nEnd)
Definition: wrong.cxx:253
rtl_TextEncoding GetCharSet() const
sal_uInt16 nPos
const SfxPoolItem * GetCurItem() const
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:845
bool IsGrammarCheckDirty() const
Definition: txtedt.cxx:2286
bool HasHints() const
Definition: ndtxt.hxx:220
bool IsSymbolAt(TextFrameIndex) const
Definition: itratr.cxx:186
sal_Int32 GetEnd() const
Definition: swscanner.hxx:67
void AddChanges(SwTextNode &rTNd, sal_Int32 nStart, sal_Int32 nLen, css::uno::Sequence< sal_Int32 > const &rOffsets)
Definition: unovwr.cxx:382
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo