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