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