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