LibreOffice Module sw (master)  1
edlingu.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 <com/sun/star/frame/XModel.hpp>
21 #include <com/sun/star/linguistic2/ProofreadingResult.hpp>
22 #include <com/sun/star/linguistic2/XProofreadingIterator.hpp>
23 #include <com/sun/star/linguistic2/XHyphenatedWord.hpp>
24 #include <com/sun/star/linguistic2/XLinguProperties.hpp>
25 #include <com/sun/star/text/XFlatParagraph.hpp>
26 #include <com/sun/star/i18n/ScriptType.hpp>
27 #include <com/sun/star/beans/XPropertySet.hpp>
28 #include <o3tl/any.hxx>
29 
30 #include <unoflatpara.hxx>
31 
32 #include <strings.hrc>
33 #include <hintids.hxx>
34 #include <unotools/linguprops.hxx>
35 #include <linguistic/lngprops.hxx>
36 #include <editeng/langitem.hxx>
38 #include <svl/languageoptions.hxx>
39 #include <editsh.hxx>
40 #include <doc.hxx>
41 #include <IDocumentUndoRedo.hxx>
43 #include <rootfrm.hxx>
44 #include <pam.hxx>
45 #include <swundo.hxx>
46 #include <ndtxt.hxx>
47 #include <viewopt.hxx>
48 #include <SwGrammarMarkUp.hxx>
49 #include <mdiexp.hxx>
50 #include <cntfrm.hxx>
51 #include <splargs.hxx>
52 #include <redline.hxx>
53 #include <docary.hxx>
54 #include <docsh.hxx>
55 #include <txatbase.hxx>
56 #include <txtfrm.hxx>
57 
58 using namespace ::svx;
59 using namespace ::com::sun::star;
60 using namespace ::com::sun::star::uno;
61 using namespace ::com::sun::star::beans;
62 using namespace ::com::sun::star::linguistic2;
63 
64 namespace {
65 
66 class SwLinguIter
67 {
68  SwEditShell *pSh;
69  std::unique_ptr<SwPosition> m_pStart;
70  std::unique_ptr<SwPosition> m_pEnd;
71  std::unique_ptr<SwPosition> m_pCurr;
72  std::unique_ptr<SwPosition> m_pCurrX;
73  sal_uInt16 nCursorCnt;
74 public:
75  SwLinguIter();
76 
77  SwEditShell *GetSh() { return pSh; }
78 
79  const SwPosition *GetEnd() const { return m_pEnd.get(); }
80  void SetEnd(SwPosition* pNew) { m_pEnd.reset(pNew); }
81 
82  const SwPosition *GetStart() const { return m_pStart.get(); }
83  void SetStart(SwPosition* pNew) { m_pStart.reset(pNew); }
84 
85  const SwPosition *GetCurr() const { return m_pCurr.get(); }
86  void SetCurr(SwPosition* pNew) { m_pCurr.reset(pNew); }
87 
88  const SwPosition *GetCurrX() const { return m_pCurrX.get(); }
89  void SetCurrX(SwPosition* pNew) { m_pCurrX.reset(pNew); }
90 
91  sal_uInt16& GetCursorCnt(){ return nCursorCnt; }
92 
93  // for the UI:
94  void Start_( SwEditShell *pSh, SwDocPositions eStart,
95  SwDocPositions eEnd );
96  void End_(bool bRestoreSelection = true);
97 };
98 
99 // #i18881# to be able to identify the positions of the changed words
100 // the content positions of each portion need to be saved
101 struct SpellContentPosition
102 {
103  sal_Int32 nLeft;
104  sal_Int32 nRight;
105 };
106 
107 }
108 
109 typedef std::vector<SpellContentPosition> SpellContentPositions;
110 
111 namespace {
112 
113 class SwSpellIter : public SwLinguIter
114 {
115  uno::Reference< XSpellChecker1 > xSpeller;
116  svx::SpellPortions aLastPortions;
117 
118  SpellContentPositions aLastPositions;
119  bool bBackToStartOfSentence;
120 
121  void CreatePortion(uno::Reference< XSpellAlternatives > const & xAlt,
122  linguistic2::ProofreadingResult* pGrammarResult,
123  bool bIsField, bool bIsHidden);
124 
125  void AddPortion(uno::Reference< XSpellAlternatives > const & xAlt,
126  linguistic2::ProofreadingResult* pGrammarResult,
127  const SpellContentPositions& rDeletedRedlines);
128 public:
129  SwSpellIter() :
130  bBackToStartOfSentence(false) {}
131 
132  void Start( SwEditShell *pSh, SwDocPositions eStart, SwDocPositions eEnd );
133 
134  uno::Any Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt );
135 
136  bool SpellSentence(svx::SpellPortions& rPortions, bool bIsGrammarCheck);
137  void ToSentenceStart();
138  const svx::SpellPortions& GetLastPortions() const { return aLastPortions;}
139  const SpellContentPositions& GetLastPositions() const {return aLastPositions;}
140 };
141 
143 class SwConvIter : public SwLinguIter
144 {
145  SwConversionArgs &rArgs;
146 public:
147  explicit SwConvIter(SwConversionArgs &rConvArgs)
148  : rArgs(rConvArgs)
149  {
150  }
151 
152  void Start( SwEditShell *pSh, SwDocPositions eStart, SwDocPositions eEnd );
153 
154  uno::Any Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt );
155 };
156 
157 class SwHyphIter : public SwLinguIter
158 {
159  // With that we save a GetFrame() in Hyphenate //TODO: does it actually matter?
160  const SwTextNode *m_pLastNode;
161  SwTextFrame *m_pLastFrame;
162  friend SwTextFrame * sw::SwHyphIterCacheLastTextFrame(SwTextNode const * pNode, const sw::Creator& rCreator);
163 
164  bool bOldIdle;
165  static void DelSoftHyph( SwPaM &rPam );
166 
167 public:
168  SwHyphIter() : m_pLastNode(nullptr), m_pLastFrame(nullptr), bOldIdle(false) {}
169 
170  void Start( SwEditShell *pSh, SwDocPositions eStart, SwDocPositions eEnd );
171  void End();
172 
173  void Ignore();
174 
175  uno::Any Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt );
176 
177  static bool IsAuto();
178  void InsertSoftHyph( const sal_Int32 nHyphPos );
179  void ShowSelection();
180 };
181 
182 }
183 
184 static SwSpellIter* g_pSpellIter = nullptr;
185 static SwConvIter* g_pConvIter = nullptr;
186 static SwHyphIter* g_pHyphIter = nullptr;
187 
188 SwLinguIter::SwLinguIter()
189  : pSh(nullptr)
190  , nCursorCnt(0)
191 {
192  // TODO missing: ensurance of re-entrance, OSL_ENSURE( etc.
193 }
194 
195 void SwLinguIter::Start_( SwEditShell *pShell, SwDocPositions eStart,
196  SwDocPositions eEnd )
197 {
198  // TODO missing: ensurance of re-entrance, locking
199  if( pSh )
200  return;
201 
202  bool bSetCurr;
203 
204  pSh = pShell;
205 
206  SET_CURR_SHELL( pSh );
207 
208  OSL_ENSURE(!m_pEnd, "SwLinguIter::Start_ without End?");
209 
210  SwPaM *pCursor = pSh->GetCursor();
211 
212  if( pShell->HasSelection() || pCursor != pCursor->GetNext() )
213  {
214  bSetCurr = nullptr != GetCurr();
215  nCursorCnt = pSh->GetCursorCnt();
216  if( pSh->IsTableMode() )
217  pSh->TableCursorToCursor();
218 
219  pSh->Push();
220  sal_uInt16 n;
221  for( n = 0; n < nCursorCnt; ++n )
222  {
223  pSh->Push();
224  pSh->DestroyCursor();
225  }
227  }
228  else
229  {
230  bSetCurr = false;
231  nCursorCnt = 1;
232  pSh->Push();
233  pSh->SetLinguRange( eStart, eEnd );
234  }
235 
236  pCursor = pSh->GetCursor();
237  if ( *pCursor->GetPoint() > *pCursor->GetMark() )
238  pCursor->Exchange();
239 
240  m_pStart.reset(new SwPosition(*pCursor->GetPoint()));
241  m_pEnd.reset(new SwPosition(*pCursor->GetMark()));
242  if( bSetCurr )
243  {
244  SwPosition* pNew = new SwPosition( *GetStart() );
245  SetCurr( pNew );
246  pNew = new SwPosition( *pNew );
247  SetCurrX( pNew );
248  }
249 
250  pCursor->SetMark();
251 }
252 
253 void SwLinguIter::End_(bool bRestoreSelection)
254 {
255  if( !pSh )
256  return;
257 
258  OSL_ENSURE(m_pEnd, "SwLinguIter::End_ without end?");
259  if(bRestoreSelection)
260  {
261  while( nCursorCnt-- )
263 
264  pSh->KillPams();
265  pSh->ClearMark();
266  }
267  m_pStart.reset();
268  m_pEnd.reset();
269  m_pCurr.reset();
270  m_pCurrX.reset();
271 
272  pSh = nullptr;
273 }
274 
275 void SwSpellIter::Start( SwEditShell *pShell, SwDocPositions eStart,
276  SwDocPositions eEnd )
277 {
278  if( GetSh() )
279  return;
280 
281  xSpeller = ::GetSpellChecker();
282  if ( xSpeller.is() )
283  Start_( pShell, eStart, eEnd );
284  aLastPortions.clear();
285  aLastPositions.clear();
286 }
287 
288 // This method is the origin of SwEditShell::SpellContinue()
289 uno::Any SwSpellIter::Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt )
290 {
294 
295  uno::Any aSpellRet;
296  SwEditShell *pMySh = GetSh();
297  if( !pMySh )
298  return aSpellRet;
299 
300  OSL_ENSURE( GetEnd(), "SwSpellIter::Continue without start?");
301 
302  uno::Reference< uno::XInterface > xSpellRet;
303  bool bGoOn = true;
304  do {
305  SwPaM *pCursor = pMySh->GetCursor();
306  if ( !pCursor->HasMark() )
307  pCursor->SetMark();
308 
309  *pMySh->GetCursor()->GetPoint() = *GetCurr();
310  *pMySh->GetCursor()->GetMark() = *GetEnd();
311  pMySh->GetDoc()->Spell(*pMySh->GetCursor(),
312  xSpeller, pPageCnt, pPageSt, false, pMySh->GetLayout()) >>= xSpellRet;
313  bGoOn = GetCursorCnt() > 1;
314  if( xSpellRet.is() )
315  {
316  bGoOn = false;
317  SwPosition* pNewPoint = new SwPosition( *pCursor->GetPoint() );
318  SwPosition* pNewMark = new SwPosition( *pCursor->GetMark() );
319  SetCurr( pNewPoint );
320  SetCurrX( pNewMark );
321  }
322  if( bGoOn )
323  {
325  pCursor = pMySh->GetCursor();
326  if ( *pCursor->GetPoint() > *pCursor->GetMark() )
327  pCursor->Exchange();
328  SwPosition* pNew = new SwPosition( *pCursor->GetPoint() );
329  SetStart( pNew );
330  pNew = new SwPosition( *pCursor->GetMark() );
331  SetEnd( pNew );
332  pNew = new SwPosition( *GetStart() );
333  SetCurr( pNew );
334  pNew = new SwPosition( *pNew );
335  SetCurrX( pNew );
336  pCursor->SetMark();
337  --GetCursorCnt();
338  }
339  }while ( bGoOn );
340  aSpellRet <<= xSpellRet;
341  return aSpellRet;
342 }
343 
344 void SwConvIter::Start( SwEditShell *pShell, SwDocPositions eStart,
345  SwDocPositions eEnd )
346 {
347  if( GetSh() )
348  return;
349  Start_( pShell, eStart, eEnd );
350 }
351 
352 uno::Any SwConvIter::Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt )
353 {
357 
358  uno::Any aConvRet( makeAny( OUString() ) );
359  SwEditShell *pMySh = GetSh();
360  if( !pMySh )
361  return aConvRet;
362 
363  OSL_ENSURE( GetEnd(), "SwConvIter::Continue() without Start?");
364 
365  OUString aConvText;
366  bool bGoOn = true;
367  do {
368  SwPaM *pCursor = pMySh->GetCursor();
369  if ( !pCursor->HasMark() )
370  pCursor->SetMark();
371 
372  *pMySh->GetCursor()->GetPoint() = *GetCurr();
373  *pMySh->GetCursor()->GetMark() = *GetEnd();
374 
375  // call function to find next text portion to be converted
376  uno::Reference< linguistic2::XSpellChecker1 > xEmpty;
377  pMySh->GetDoc()->Spell( *pMySh->GetCursor(),
378  xEmpty, pPageCnt, pPageSt, false, pMySh->GetLayout(), &rArgs) >>= aConvText;
379 
380  bGoOn = GetCursorCnt() > 1;
381  if( !aConvText.isEmpty() )
382  {
383  bGoOn = false;
384  SwPosition* pNewPoint = new SwPosition( *pCursor->GetPoint() );
385  SwPosition* pNewMark = new SwPosition( *pCursor->GetMark() );
386 
387  SetCurr( pNewPoint );
388  SetCurrX( pNewMark );
389  }
390  if( bGoOn )
391  {
393  pCursor = pMySh->GetCursor();
394  if ( *pCursor->GetPoint() > *pCursor->GetMark() )
395  pCursor->Exchange();
396  SwPosition* pNew = new SwPosition( *pCursor->GetPoint() );
397  SetStart( pNew );
398  pNew = new SwPosition( *pCursor->GetMark() );
399  SetEnd( pNew );
400  pNew = new SwPosition( *GetStart() );
401  SetCurr( pNew );
402  pNew = new SwPosition( *pNew );
403  SetCurrX( pNew );
404  pCursor->SetMark();
405  --GetCursorCnt();
406  }
407  }while ( bGoOn );
408  return makeAny( aConvText );
409 }
410 
411 bool SwHyphIter::IsAuto()
412 {
413  uno::Reference< beans::XPropertySet > xProp( ::GetLinguPropertySet() );
414  return xProp.is() && *o3tl::doAccess<bool>(xProp->getPropertyValue(
415  UPN_IS_HYPH_AUTO ));
416 }
417 
418 void SwHyphIter::ShowSelection()
419 {
420  SwEditShell *pMySh = GetSh();
421  if( pMySh )
422  {
423  pMySh->StartAction();
424  // Caution! Due to EndAction() formatting is started which can lead to the fact that new
425  // words are added to/set in the Hyphenator. Thus: save!
426  pMySh->EndAction();
427  }
428 }
429 
430 void SwHyphIter::Start( SwEditShell *pShell, SwDocPositions eStart, SwDocPositions eEnd )
431 {
432  // robust
433  if( GetSh() || GetEnd() )
434  {
435  OSL_ENSURE( !GetSh(), "SwHyphIter::Start: missing HyphEnd()" );
436  return;
437  }
438 
439  // nothing to do (at least not in the way as in the "else" part)
440  bOldIdle = pShell->GetViewOptions()->IsIdle();
441  pShell->GetViewOptions()->SetIdle( false );
442  Start_( pShell, eStart, eEnd );
443 }
444 
445 // restore selections
446 void SwHyphIter::End()
447 {
448  if( !GetSh() )
449  return;
450  GetSh()->GetViewOptions()->SetIdle( bOldIdle );
451  End_();
452 }
453 
454 uno::Any SwHyphIter::Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt )
455 {
456  uno::Any aHyphRet;
457  SwEditShell *pMySh = GetSh();
458  if( !pMySh )
459  return aHyphRet;
460 
461  const bool bAuto = IsAuto();
462  uno::Reference< XHyphenatedWord > xHyphWord;
463  bool bGoOn = false;
464  do {
465  SwPaM *pCursor;
466  do {
467  OSL_ENSURE( GetEnd(), "SwHyphIter::Continue without Start?" );
468  pCursor = pMySh->GetCursor();
469  if ( !pCursor->HasMark() )
470  pCursor->SetMark();
471  if ( *pCursor->GetPoint() < *pCursor->GetMark() )
472  {
473  pCursor->Exchange();
474  pCursor->SetMark();
475  }
476 
477  if ( *pCursor->End() <= *GetEnd() )
478  {
479  *pCursor->GetMark() = *GetEnd();
480 
481  // Do we need to break the word at the current cursor position?
482  const Point aCursorPos( pMySh->GetCharRect().Pos() );
483  xHyphWord = pMySh->GetDoc()->Hyphenate( pCursor, aCursorPos,
484  pPageCnt, pPageSt );
485  }
486 
487  if( bAuto && xHyphWord.is() )
488  {
489  SwEditShell::InsertSoftHyph( xHyphWord->getHyphenationPos() + 1);
490  }
491  } while( bAuto && xHyphWord.is() ); //end of do-while
492  bGoOn = !xHyphWord.is() && GetCursorCnt() > 1;
493 
494  if( bGoOn )
495  {
497  pCursor = pMySh->GetCursor();
498  if ( *pCursor->GetPoint() > *pCursor->GetMark() )
499  pCursor->Exchange();
500  SwPosition* pNew = new SwPosition(*pCursor->End());
501  SetEnd( pNew );
502  pCursor->SetMark();
503  --GetCursorCnt();
504  }
505  } while ( bGoOn );
506  aHyphRet <<= xHyphWord;
507  return aHyphRet;
508 }
509 
511 void SwHyphIter::Ignore()
512 {
513  SwEditShell *pMySh = GetSh();
514  SwPaM *pCursor = pMySh->GetCursor();
515 
516  // delete old SoftHyphen
517  DelSoftHyph( *pCursor );
518 
519  // and continue
520  pCursor->Start()->nContent = pCursor->End()->nContent;
521  pCursor->SetMark();
522 }
523 
524 void SwHyphIter::DelSoftHyph( SwPaM &rPam )
525 {
526  const SwPosition* pStt = rPam.Start();
527  const sal_Int32 nStart = pStt->nContent.GetIndex();
528  const sal_Int32 nEnd = rPam.End()->nContent.GetIndex();
529  SwTextNode *pNode = pStt->nNode.GetNode().GetTextNode();
530  pNode->DelSoftHyph( nStart, nEnd );
531 }
532 
533 void SwHyphIter::InsertSoftHyph( const sal_Int32 nHyphPos )
534 {
535  SwEditShell *pMySh = GetSh();
536  OSL_ENSURE( pMySh, "SwHyphIter::InsertSoftHyph: missing HyphStart()");
537  if( !pMySh )
538  return;
539 
540  SwPaM *pCursor = pMySh->GetCursor();
541  SwPosition* pSttPos = pCursor->Start();
542  SwPosition* pEndPos = pCursor->End();
543 
544  const sal_Int32 nLastHyphLen = GetEnd()->nContent.GetIndex() -
545  pSttPos->nContent.GetIndex();
546 
547  if( pSttPos->nNode != pEndPos->nNode || !nLastHyphLen )
548  {
549  OSL_ENSURE( pSttPos->nNode == pEndPos->nNode,
550  "SwHyphIter::InsertSoftHyph: node warp during hyphenation" );
551  OSL_ENSURE(nLastHyphLen, "SwHyphIter::InsertSoftHyph: missing HyphContinue()");
552  *pSttPos = *pEndPos;
553  return;
554  }
555 
556  pMySh->StartAction();
557  {
558  SwDoc *pDoc = pMySh->GetDoc();
559  DelSoftHyph( *pCursor );
560  pSttPos->nContent += nHyphPos;
561  SwPaM aRg( *pSttPos );
562  pDoc->getIDocumentContentOperations().InsertString( aRg, OUString(CHAR_SOFTHYPHEN) );
563  }
564  // revoke selection
565  pCursor->DeleteMark();
566  pMySh->EndAction();
567  pCursor->SetMark();
568 }
569 
570 namespace sw {
571 
572 SwTextFrame *
574 {
575  assert(g_pHyphIter);
576  if (pNode != g_pHyphIter->m_pLastNode || !g_pHyphIter->m_pLastFrame)
577  {
578  g_pHyphIter->m_pLastNode = pNode;
579  g_pHyphIter->m_pLastFrame = create();
580  }
581  return g_pHyphIter->m_pLastFrame;
582 }
583 
584 }
585 
587 {
588  bool bTextWasGrammarChecked = false;
589  if (g_pSpellIter)
590  {
591  svx::SpellPortions aLastPortions( g_pSpellIter->GetLastPortions() );
592  for (size_t i = 0; i < aLastPortions.size() && !bTextWasGrammarChecked; ++i)
593  {
594  // bIsGrammarError is also true if the text was only checked but no
595  // grammar error was found. (That is if a ProofreadingResult was obtained in
596  // SwDoc::Spell and in turn bIsGrammarError was set in SwSpellIter::CreatePortion)
597  if (aLastPortions[i].bIsGrammarError)
598  bTextWasGrammarChecked = true;
599  }
600  }
601  return bTextWasGrammarChecked;
602 }
603 
605 {
606  return nullptr != g_pConvIter;
607 }
608 
610 {
611  return nullptr != g_pHyphIter;
612 }
613 
615 {
616  SwPaM *pCursor = GetCursor();
617  MakeFindRange( eStart, eEnd, pCursor );
618  if( *pCursor->GetPoint() > *pCursor->GetMark() )
619  pCursor->Exchange();
620 }
621 
623  SwDocPositions eStart, SwDocPositions eEnd, SwDocPositions eCurr,
624  SwConversionArgs *pConvArgs )
625 {
626  SwLinguIter *pLinguIter = nullptr;
627 
628  // do not spell if interactive spelling is active elsewhere
629  if (!pConvArgs && !g_pSpellIter)
630  {
631  g_pSpellIter = new SwSpellIter;
632  pLinguIter = g_pSpellIter;
633  }
634  // do not do text conversion if it is active elsewhere
635  if (pConvArgs && !g_pConvIter)
636  {
637  g_pConvIter = new SwConvIter( *pConvArgs );
638  pLinguIter = g_pConvIter;
639  }
640 
641  if (pLinguIter)
642  {
643  SwCursor* pSwCursor = GetSwCursor();
644 
645  SwPosition *pTmp = new SwPosition( *pSwCursor->GetPoint() );
646  pSwCursor->FillFindPos( eCurr, *pTmp );
647  pLinguIter->SetCurr( pTmp );
648 
649  pTmp = new SwPosition( *pTmp );
650  pLinguIter->SetCurrX( pTmp );
651  }
652 
653  if (!pConvArgs && g_pSpellIter)
654  g_pSpellIter->Start( this, eStart, eEnd );
655  if (pConvArgs && g_pConvIter)
656  g_pConvIter->Start( this, eStart, eEnd );
657 }
658 
659 void SwEditShell::SpellEnd( SwConversionArgs const *pConvArgs, bool bRestoreSelection )
660 {
661  if (!pConvArgs && g_pSpellIter && g_pSpellIter->GetSh() == this)
662  {
663  g_pSpellIter->End_(bRestoreSelection);
664  delete g_pSpellIter;
665  g_pSpellIter = nullptr;
666  }
667  if (pConvArgs && g_pConvIter && g_pConvIter->GetSh() == this)
668  {
669  g_pConvIter->End_();
670  delete g_pConvIter;
671  g_pConvIter = nullptr;
672  }
673 }
674 
677  sal_uInt16* pPageCnt, sal_uInt16* pPageSt,
678  SwConversionArgs const *pConvArgs )
679 {
680  uno::Any aRes;
681 
682  if ((!pConvArgs && g_pSpellIter->GetSh() != this) ||
683  ( pConvArgs && g_pConvIter->GetSh() != this))
684  return aRes;
685 
686  if( pPageCnt && !*pPageCnt )
687  {
688  sal_uInt16 nEndPage = GetLayout()->GetPageNum();
689  nEndPage += nEndPage * 10 / 100;
690  *pPageCnt = nEndPage;
691  if( nEndPage )
692  ::StartProgress( STR_STATSTR_SPELL, 0, nEndPage, GetDoc()->GetDocShell() );
693  }
694 
695  OSL_ENSURE( pConvArgs || g_pSpellIter, "SpellIter missing" );
696  OSL_ENSURE( !pConvArgs || g_pConvIter, "ConvIter missing" );
697  //JP 18.07.95: prevent displaying selection on error messages. NO StartAction so that all
698  // Paints are also disabled.
699  ++mnStartAction;
700  OUString aRet;
701  uno::Reference< uno::XInterface > xRet;
702  if (pConvArgs)
703  {
704  g_pConvIter->Continue( pPageCnt, pPageSt ) >>= aRet;
705  aRes <<= aRet;
706  }
707  else
708  {
709  g_pSpellIter->Continue( pPageCnt, pPageSt ) >>= xRet;
710  aRes <<= xRet;
711  }
712  --mnStartAction;
713 
714  if( !aRet.isEmpty() || xRet.is() )
715  {
716  // then make awt::Selection again visible
717  StartAction();
718  EndAction();
719  }
720  return aRes;
721 }
722 
723 /* Interactive Hyphenation (BP 10.03.93)
724  *
725  * 1) HyphStart
726  * - Revoke all Selections
727  * - Save current Cursor
728  * - if no selections existent:
729  * - create new selection reaching until document end
730  * 2) HyphContinue
731  * - add nLastHyphLen onto SelectionStart
732  * - iterate over all selected areas
733  * - pDoc->Hyphenate() iterates over all Nodes of a selection
734  * - pTextNode->Hyphenate() calls SwTextFrame::Hyphenate of the EditShell
735  * - SwTextFrame:Hyphenate() iterates over all rows of the Pam
736  * - LineIter::Hyphenate() sets the Hyphenator and the Pam based on
737  * the to be separated word.
738  * - Returns true if there is a hyphenation and false if the Pam is processed.
739  * - If true, show the selected word and set nLastHyphLen.
740  * - If false, delete current selection and select next one. Returns HYPH_OK if no more.
741  * 3) InsertSoftHyph (might be called by UI if needed)
742  * - Place current cursor and add attribute.
743  * 4) HyphEnd
744  * - Restore old cursor, EndAction
745  */
747 {
748  // do not hyphenate if interactive hyphenation is active elsewhere
749  if (!g_pHyphIter)
750  {
751  g_pHyphIter = new SwHyphIter;
752  g_pHyphIter->Start( this, eStart, eEnd );
753  }
754 }
755 
758 {
759  assert(g_pHyphIter);
760  if (g_pHyphIter->GetSh() == this)
761  {
762  g_pHyphIter->End();
763  delete g_pHyphIter;
764  g_pHyphIter = nullptr;
765  }
766 }
767 
769 uno::Reference< uno::XInterface >
770  SwEditShell::HyphContinue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt )
771 {
772  assert(g_pHyphIter);
773  if (g_pHyphIter->GetSh() != this)
774  return nullptr;
775 
776  if( pPageCnt && !*pPageCnt && !*pPageSt )
777  {
778  sal_uInt16 nEndPage = GetLayout()->GetPageNum();
779  nEndPage += nEndPage * 10 / 100;
780  if( nEndPage > 14 )
781  {
782  *pPageCnt = nEndPage;
783  ::StartProgress( STR_STATSTR_HYPHEN, 0, nEndPage, GetDoc()->GetDocShell());
784  }
785  else // here we once and for all suppress StatLineStartPercent
786  *pPageSt = 1;
787  }
788 
789  //JP 18.07.95: prevent displaying selection on error messages. NO StartAction so that all
790  // Paints are also disabled.
791  ++mnStartAction;
792  uno::Reference< uno::XInterface > xRet;
793  g_pHyphIter->Continue( pPageCnt, pPageSt ) >>= xRet;
794  --mnStartAction;
795 
796  if( xRet.is() )
797  g_pHyphIter->ShowSelection();
798 
799  return xRet;
800 }
801 
806 void SwEditShell::InsertSoftHyph( const sal_Int32 nHyphPos )
807 {
808  assert(g_pHyphIter);
809  g_pHyphIter->InsertSoftHyph( nHyphPos );
810 }
811 
814 {
815  assert(g_pHyphIter);
816  //JP 18.07.95: prevent displaying selection on error messages. NO StartAction so that all
817  // Paints are also disabled.
818  ++mnStartAction;
819  g_pHyphIter->Ignore();
820  --mnStartAction;
821 
822  g_pHyphIter->ShowSelection();
823 }
824 
825 void SwEditShell::HandleCorrectionError(const OUString& aText, SwPosition aPos, sal_Int32 nBegin,
826  sal_Int32 nLen, const Point* pPt,
827  SwRect& rSelectRect)
828 {
829  // save the start and end positions of the line and the starting point
830  Push();
831  LeftMargin();
832  const sal_Int32 nLineStart = GetCursor()->GetPoint()->nContent.GetIndex();
833  RightMargin();
834  const sal_Int32 nLineEnd = GetCursor()->GetPoint()->nContent.GetIndex();
836 
837  // make sure the selection build later from the data below does
838  // not "in word" character to the left and right in order to
839  // preserve those. Therefore count those "in words" in order to
840  // modify the selection accordingly.
841  const sal_Unicode* pChar = aText.getStr();
842  sal_Int32 nLeft = 0;
843  while (*pChar++ == CH_TXTATR_INWORD)
844  ++nLeft;
845  pChar = aText.getLength() ? aText.getStr() + aText.getLength() - 1 : nullptr;
846  sal_Int32 nRight = 0;
847  while (pChar && *pChar-- == CH_TXTATR_INWORD)
848  ++nRight;
849 
850  aPos.nContent = nBegin + nLeft;
851  SwPaM* pCursor = GetCursor();
852  *pCursor->GetPoint() = aPos;
853  pCursor->SetMark();
854  ExtendSelection( true, nLen - nLeft - nRight );
855  // don't determine the rectangle in the current line
856  const sal_Int32 nWordStart = (nBegin + nLeft) < nLineStart ? nLineStart : nBegin + nLeft;
857  // take one less than the line end - otherwise the next line would be calculated
858  const sal_Int32 nWordEnd = (nBegin + nLen - nLeft - nRight) > nLineEnd
859  ? nLineEnd : (nBegin + nLen - nLeft - nRight);
860  Push();
861  pCursor->DeleteMark();
862  SwIndex& rContent = GetCursor()->GetPoint()->nContent;
863  rContent = nWordStart;
864  SwRect aStartRect;
865  SwCursorMoveState aState;
866  aState.m_bRealWidth = true;
867  SwContentNode* pContentNode = pCursor->GetContentNode();
868  std::pair<Point, bool> tmp;
869  if (pPt)
870  {
871  tmp.first = *pPt;
872  tmp.second = false;
873  }
874  SwContentFrame *const pContentFrame = pContentNode->getLayoutFrame(GetLayout(), pCursor->GetPoint(), pPt ? &tmp : nullptr);
875 
876  pContentFrame->GetCharRect( aStartRect, *pCursor->GetPoint(), &aState );
877  rContent = nWordEnd - 1;
878  SwRect aEndRect;
879  pContentFrame->GetCharRect( aEndRect, *pCursor->GetPoint(),&aState );
880  rSelectRect = aStartRect.Union( aEndRect );
882 }
883 
892 uno::Reference< XSpellAlternatives >
893  SwEditShell::GetCorrection( const Point* pPt, SwRect& rSelectRect )
894 {
895  uno::Reference< XSpellAlternatives > xSpellAlt;
896 
897  if( IsTableMode() )
898  return nullptr;
899  SwPaM* pCursor = GetCursor();
900  SwPosition aPos( *pCursor->GetPoint() );
902  SwTextNode *pNode = nullptr;
903  SwWrongList *pWrong = nullptr;
904  if (pPt && GetLayout()->GetModelPositionForViewPoint( &aPos, *const_cast<Point*>(pPt), &eTmpState ))
905  pNode = aPos.nNode.GetNode().GetTextNode();
906  if (nullptr == pNode)
907  pNode = pCursor->GetNode().GetTextNode();
908  if (nullptr != pNode)
909  pWrong = pNode->GetWrong();
910  if (nullptr != pWrong && !pNode->IsInProtectSect())
911  {
912  sal_Int32 nBegin = aPos.nContent.GetIndex();
913  sal_Int32 nLen = 1;
914  if (pWrong->InWrongWord(nBegin, nLen) && !pNode->IsSymbolAt(nBegin))
915  {
916  const OUString aText(pNode->GetText().copy(nBegin, nLen));
917  OUString aWord = aText.replaceAll(OUStringChar(CH_TXTATR_BREAKWORD), "")
918  .replaceAll(OUStringChar(CH_TXTATR_INWORD), "");
919 
920  uno::Reference< XSpellChecker1 > xSpell( ::GetSpellChecker() );
921  if( xSpell.is() )
922  {
923  LanguageType eActLang = pNode->GetLang( nBegin, nLen );
924  if( xSpell->hasLanguage( static_cast<sal_uInt16>(eActLang) ))
925  {
926  // restrict the maximal number of suggestions displayed
927  // in the context menu.
928  // Note: That could of course be done by clipping the
929  // resulting sequence but the current third party
930  // implementations result differs greatly if the number of
931  // suggestions to be returned gets changed. Statistically
932  // it gets much better if told to return e.g. only 7 strings
933  // than returning e.g. 16 suggestions and using only the
934  // first 7. Thus we hand down the value to use to that
935  // implementation here by providing an additional parameter.
936  Sequence< PropertyValue > aPropVals(1);
937  PropertyValue &rVal = aPropVals.getArray()[0];
938  rVal.Name = UPN_MAX_NUMBER_OF_SUGGESTIONS;
939  rVal.Value <<= sal_Int16(7);
940 
941  xSpellAlt = xSpell->spell( aWord, static_cast<sal_uInt16>(eActLang), aPropVals );
942  }
943  }
944 
945  if ( xSpellAlt.is() ) // error found?
946  {
947  HandleCorrectionError( aText, aPos, nBegin, nLen, pPt, rSelectRect );
948  }
949  }
950  }
951  return xSpellAlt;
952 }
953 
955  linguistic2::ProofreadingResult /*out*/ &rResult, // the complete result
956  sal_Int32 /*out*/ &rErrorPosInText, // offset of error position in string that was grammar checked...
957  sal_Int32 /*out*/ &rErrorIndexInResult, // index of error in rResult.aGrammarErrors
958  uno::Sequence< OUString > /*out*/ &rSuggestions, // suggestions to be used for the error found
959  const Point *pPt, SwRect &rSelectRect )
960 {
961  bool bRes = false;
962 
963  if( IsTableMode() )
964  return bRes;
965 
966  SwPaM* pCursor = GetCursor();
967  SwPosition aPos( *pCursor->GetPoint() );
969  SwTextNode *pNode = nullptr;
970  SwGrammarMarkUp *pWrong = nullptr;
971  if (pPt && GetLayout()->GetModelPositionForViewPoint( &aPos, *const_cast<Point*>(pPt), &eTmpState ))
972  pNode = aPos.nNode.GetNode().GetTextNode();
973  if (nullptr == pNode)
974  pNode = pCursor->GetNode().GetTextNode();
975  if (nullptr != pNode)
976  pWrong = pNode->GetGrammarCheck();
977  if (nullptr != pWrong && !pNode->IsInProtectSect())
978  {
979  sal_Int32 nBegin = aPos.nContent.GetIndex();
980  sal_Int32 nLen = 1;
981  if (pWrong->InWrongWord(nBegin, nLen))
982  {
983  const OUString aText(pNode->GetText().copy(nBegin, nLen));
984 
985  uno::Reference< linguistic2::XProofreadingIterator > xGCIterator( mxDoc->GetGCIterator() );
986  if (xGCIterator.is())
987  {
988  uno::Reference< lang::XComponent > xDoc = mxDoc->GetDocShell()->GetBaseModel();
989 
990  // Expand the string:
991  const ModelToViewHelper aConversionMap(*pNode, GetLayout());
992  const OUString& aExpandText = aConversionMap.getViewText();
993  // get XFlatParagraph to use...
994  uno::Reference< text::XFlatParagraph > xFlatPara = new SwXFlatParagraph( *pNode, aExpandText, aConversionMap );
995 
996  // get error position of cursor in XFlatParagraph
997  rErrorPosInText = aConversionMap.ConvertToViewPosition( nBegin );
998 
999  const sal_Int32 nStartOfSentence = aConversionMap.ConvertToViewPosition( pWrong->getSentenceStart( nBegin ) );
1000  const sal_Int32 nEndOfSentence = aConversionMap.ConvertToViewPosition( pWrong->getSentenceEnd( nBegin ) );
1001 
1002  rResult = xGCIterator->checkSentenceAtPosition(
1003  xDoc, xFlatPara, aExpandText, lang::Locale(), nStartOfSentence,
1004  nEndOfSentence == COMPLETE_STRING ? aExpandText.getLength() : nEndOfSentence,
1005  rErrorPosInText );
1006  bRes = true;
1007 
1008  // get suggestions to use for the specific error position
1009  rSuggestions.realloc( 0 );
1010  // return suggestions for first error that includes the given error position
1011  auto pError = std::find_if(rResult.aErrors.begin(), rResult.aErrors.end(),
1012  [rErrorPosInText, nLen](const linguistic2::SingleProofreadingError &rError) {
1013  return rError.nErrorStart <= rErrorPosInText
1014  && rErrorPosInText + nLen <= rError.nErrorStart + rError.nErrorLength; });
1015  if (pError != rResult.aErrors.end())
1016  {
1017  rSuggestions = pError->aSuggestions;
1018  rErrorIndexInResult = static_cast<sal_Int32>(std::distance(rResult.aErrors.begin(), pError));
1019  }
1020  }
1021 
1022  if (rResult.aErrors.hasElements()) // error found?
1023  {
1024  HandleCorrectionError( aText, aPos, nBegin, nLen, pPt, rSelectRect );
1025  }
1026  }
1027  }
1028 
1029  return bRes;
1030 }
1031 
1032 bool SwEditShell::SpellSentence(svx::SpellPortions& rPortions, bool bIsGrammarCheck)
1033 {
1034  OSL_ENSURE( g_pSpellIter, "SpellIter missing" );
1035  if (!g_pSpellIter)
1036  return false;
1037  bool bRet = g_pSpellIter->SpellSentence(rPortions, bIsGrammarCheck);
1038 
1039  // make Selection visible - this should simply move the
1040  // cursor to the end of the sentence
1041  StartAction();
1042  EndAction();
1043  return bRet;
1044 }
1045 
1048 {
1049  OSL_ENSURE( g_pSpellIter, "SpellIter missing" );
1050  if (!g_pSpellIter)
1051  return;
1052  g_pSpellIter->ToSentenceStart();
1053 }
1054 
1055 static sal_uInt32 lcl_CountRedlines(const svx::SpellPortions& rLastPortions)
1056 {
1057  return static_cast<sal_uInt32>(std::count_if(rLastPortions.begin(), rLastPortions.end(),
1058  [](const svx::SpellPortion& rPortion) { return rPortion.bIsHidden; }));
1059 }
1060 
1062 {
1063  // give hint that continuation position for spell/grammar checking is
1064  // at the end of this sentence
1065  if (g_pSpellIter)
1066  {
1067  g_pSpellIter->SetCurr( new SwPosition( *g_pSpellIter->GetCurrX() ) );
1068  }
1069 }
1070 
1071 void SwEditShell::ApplyChangedSentence(const svx::SpellPortions& rNewPortions, bool bRecheck)
1072 {
1073  // Note: rNewPortions.size() == 0 is valid and happens when the whole
1074  // sentence got removed in the dialog
1075 
1076  OSL_ENSURE( g_pSpellIter, "SpellIter missing" );
1077  if (!g_pSpellIter ||
1078  g_pSpellIter->GetLastPortions().empty()) // no portions -> no text to be changed
1079  return;
1080 
1081  const SpellPortions& rLastPortions = g_pSpellIter->GetLastPortions();
1082  const SpellContentPositions rLastPositions = g_pSpellIter->GetLastPositions();
1083  OSL_ENSURE(!rLastPortions.empty() &&
1084  rLastPortions.size() == rLastPositions.size(),
1085  "last vectors of spelling results are not set or not equal");
1086 
1087  // iterate over the new portions, beginning at the end to take advantage of the previously
1088  // saved content positions
1089 
1090  mxDoc->GetIDocumentUndoRedo().StartUndo( SwUndoId::UI_TEXT_CORRECTION, nullptr );
1091  StartAction();
1092 
1093  SwPaM *pCursor = GetCursor();
1094  // save cursor position (which should be at the end of the current sentence)
1095  // for later restoration
1096  Push();
1097 
1098  sal_uInt32 nRedlinePortions = lcl_CountRedlines(rLastPortions);
1099  if((rLastPortions.size() - nRedlinePortions) == rNewPortions.size())
1100  {
1101  OSL_ENSURE( !rNewPortions.empty(), "rNewPortions should not be empty here" );
1102  OSL_ENSURE( !rLastPortions.empty(), "rLastPortions should not be empty here" );
1103  OSL_ENSURE( !rLastPositions.empty(), "rLastPositions should not be empty here" );
1104 
1105  // the simple case: the same number of elements on both sides
1106  // each changed element has to be applied to the corresponding source element
1107  svx::SpellPortions::const_iterator aCurrentNewPortion = rNewPortions.end();
1108  SpellPortions::const_iterator aCurrentOldPortion = rLastPortions.end();
1109  SpellContentPositions::const_iterator aCurrentOldPosition = rLastPositions.end();
1110  do
1111  {
1112  --aCurrentNewPortion;
1113  --aCurrentOldPortion;
1114  --aCurrentOldPosition;
1115  //jump over redline portions
1116  while(aCurrentOldPortion->bIsHidden)
1117  {
1118  if (aCurrentOldPortion != rLastPortions.begin() &&
1119  aCurrentOldPosition != rLastPositions.begin())
1120  {
1121  --aCurrentOldPortion;
1122  --aCurrentOldPosition;
1123  }
1124  else
1125  {
1126  OSL_FAIL("ApplyChangedSentence: iterator positions broken" );
1127  break;
1128  }
1129  }
1130  if ( !pCursor->HasMark() )
1131  pCursor->SetMark();
1132  pCursor->GetPoint()->nContent = aCurrentOldPosition->nLeft;
1133  pCursor->GetMark()->nContent = aCurrentOldPosition->nRight;
1134  sal_uInt16 nScriptType = SvtLanguageOptions::GetI18NScriptTypeOfLanguage( aCurrentNewPortion->eLanguage );
1135  sal_uInt16 nLangWhichId = RES_CHRATR_LANGUAGE;
1136  switch(nScriptType)
1137  {
1138  case css::i18n::ScriptType::ASIAN : nLangWhichId = RES_CHRATR_CJK_LANGUAGE; break;
1139  case css::i18n::ScriptType::COMPLEX : nLangWhichId = RES_CHRATR_CTL_LANGUAGE; break;
1140  }
1141  if(aCurrentNewPortion->sText != aCurrentOldPortion->sText)
1142  {
1143  // change text ...
1144  mxDoc->getIDocumentContentOperations().DeleteAndJoin(*pCursor);
1145  // ... and apply language if necessary
1146  if(aCurrentNewPortion->eLanguage != aCurrentOldPortion->eLanguage)
1147  SetAttrItem( SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId) );
1148  mxDoc->getIDocumentContentOperations().InsertString(*pCursor, aCurrentNewPortion->sText);
1149  }
1150  else if(aCurrentNewPortion->eLanguage != aCurrentOldPortion->eLanguage)
1151  {
1152  // apply language
1153  SetAttrItem( SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId) );
1154  }
1155  else if( aCurrentNewPortion->bIgnoreThisError )
1156  {
1157  // add the 'ignore' markup to the TextNode's grammar ignore markup list
1158  IgnoreGrammarErrorAt( *pCursor );
1159  OSL_FAIL("TODO: add ignore mark to text node");
1160  }
1161  }
1162  while(aCurrentNewPortion != rNewPortions.begin());
1163  }
1164  else
1165  {
1166  OSL_ENSURE( !rLastPositions.empty(), "rLastPositions should not be empty here" );
1167 
1168  // select the complete sentence
1169  SpellContentPositions::const_iterator aCurrentEndPosition = rLastPositions.end();
1170  --aCurrentEndPosition;
1171  SpellContentPositions::const_iterator aCurrentStartPosition = rLastPositions.begin();
1172  pCursor->GetPoint()->nContent = aCurrentStartPosition->nLeft;
1173  pCursor->GetMark()->nContent = aCurrentEndPosition->nRight;
1174 
1175  // delete the sentence completely
1176  mxDoc->getIDocumentContentOperations().DeleteAndJoin(*pCursor);
1177  for(const auto& rCurrentNewPortion : rNewPortions)
1178  {
1179  // set the language attribute
1180  SvtScriptType nScriptType = GetScriptType();
1181  sal_uInt16 nLangWhichId = RES_CHRATR_LANGUAGE;
1182  switch(nScriptType)
1183  {
1184  case SvtScriptType::ASIAN : nLangWhichId = RES_CHRATR_CJK_LANGUAGE; break;
1185  case SvtScriptType::COMPLEX : nLangWhichId = RES_CHRATR_CTL_LANGUAGE; break;
1186  default: break;
1187  }
1188  SfxItemSet aSet(GetAttrPool(), {{nLangWhichId, nLangWhichId}});
1189  GetCurAttr( aSet );
1190  const SvxLanguageItem& rLang = static_cast<const SvxLanguageItem& >(aSet.Get(nLangWhichId));
1191  if(rLang.GetLanguage() != rCurrentNewPortion.eLanguage)
1192  SetAttrItem( SvxLanguageItem(rCurrentNewPortion.eLanguage, nLangWhichId) );
1193  // insert the new string
1194  mxDoc->getIDocumentContentOperations().InsertString(*pCursor, rCurrentNewPortion.sText);
1195 
1196  // set the cursor to the end of the inserted string
1197  *pCursor->Start() = *pCursor->End();
1198  }
1199  }
1200 
1201  // restore cursor to the end of the sentence
1202  // (will work also if the sentence length has changed,
1203  // since cursors get updated automatically!)
1205 
1206  // collapse cursor to the end of the modified sentence
1207  *pCursor->Start() = *pCursor->End();
1208  if (bRecheck)
1209  {
1210  // in grammar check the current sentence has to be checked again
1211  GoStartSentence();
1212  }
1213  // set continuation position for spell/grammar checking to the end of this sentence
1214  g_pSpellIter->SetCurr( new SwPosition(*pCursor->Start()) );
1215 
1216  mxDoc->GetIDocumentUndoRedo().EndUndo( SwUndoId::UI_TEXT_CORRECTION, nullptr );
1217  EndAction();
1218 
1219 }
1223 static SpellContentPositions lcl_CollectDeletedRedlines(SwEditShell const * pSh)
1224 {
1225  SpellContentPositions aRedlines;
1226  SwDoc* pDoc = pSh->GetDoc();
1228  if ( bShowChg )
1229  {
1230  SwPaM *pCursor = pSh->GetCursor();
1231  const SwPosition* pStartPos = pCursor->Start();
1232  const SwTextNode* pTextNode = pCursor->GetNode().GetTextNode();
1233 
1234  SwRedlineTable::size_type nAct = pDoc->getIDocumentRedlineAccess().GetRedlinePos( *pTextNode, RedlineType::Any );
1235  const sal_Int32 nStartIndex = pStartPos->nContent.GetIndex();
1236  for ( ; nAct < pDoc->getIDocumentRedlineAccess().GetRedlineTable().size(); nAct++ )
1237  {
1238  const SwRangeRedline* pRed = pDoc->getIDocumentRedlineAccess().GetRedlineTable()[ nAct ];
1239 
1240  if ( pRed->Start()->nNode > pTextNode->GetIndex() )
1241  break;
1242 
1243  if( RedlineType::Delete == pRed->GetType() )
1244  {
1245  sal_Int32 nStart_, nEnd_;
1246  pRed->CalcStartEnd( pTextNode->GetIndex(), nStart_, nEnd_ );
1247  sal_Int32 nStart = nStart_;
1248  sal_Int32 nEnd = nEnd_;
1249  if(nStart >= nStartIndex || nEnd >= nStartIndex)
1250  {
1251  SpellContentPosition aAdd;
1252  aAdd.nLeft = nStart;
1253  aAdd.nRight = nEnd;
1254  aRedlines.push_back(aAdd);
1255  }
1256  }
1257  }
1258  }
1259  return aRedlines;
1260 }
1261 
1263 static void lcl_CutRedlines( SpellContentPositions& aDeletedRedlines, SwEditShell const * pSh )
1264 {
1265  if(!aDeletedRedlines.empty())
1266  {
1267  SwPaM *pCursor = pSh->GetCursor();
1268  const SwPosition* pEndPos = pCursor->End();
1269  const sal_Int32 nEnd = pEndPos->nContent.GetIndex();
1270  while(!aDeletedRedlines.empty() &&
1271  aDeletedRedlines.back().nLeft > nEnd)
1272  {
1273  aDeletedRedlines.pop_back();
1274  }
1275  }
1276 }
1277 
1278 static SpellContentPosition lcl_FindNextDeletedRedline(
1279  const SpellContentPositions& rDeletedRedlines,
1280  sal_Int32 nSearchFrom )
1281 {
1282  SpellContentPosition aRet;
1283  aRet.nLeft = aRet.nRight = SAL_MAX_INT32;
1284  if(!rDeletedRedlines.empty())
1285  {
1286  auto aIter = std::find_if_not(rDeletedRedlines.begin(), rDeletedRedlines.end(),
1287  [nSearchFrom](const SpellContentPosition& rPos) { return rPos.nLeft < nSearchFrom; });
1288  if (aIter != rDeletedRedlines.end())
1289  aRet = *aIter;
1290  }
1291  return aRet;
1292 }
1293 
1294 bool SwSpellIter::SpellSentence(svx::SpellPortions& rPortions, bool bIsGrammarCheck)
1295 {
1296  bool bRet = false;
1297  aLastPortions.clear();
1298  aLastPositions.clear();
1299 
1300  SwEditShell *pMySh = GetSh();
1301  if( !pMySh )
1302  return false;
1303 
1304  OSL_ENSURE( GetEnd(), "SwSpellIter::SpellSentence without Start?");
1305 
1306  uno::Reference< XSpellAlternatives > xSpellRet;
1307  linguistic2::ProofreadingResult aGrammarResult;
1308  bool bGoOn = true;
1309  bool bGrammarErrorFound = false;
1310  do {
1311  SwPaM *pCursor = pMySh->GetCursor();
1312  if ( !pCursor->HasMark() )
1313  pCursor->SetMark();
1314 
1315  *pCursor->GetPoint() = *GetCurr();
1316  *pCursor->GetMark() = *GetEnd();
1317 
1318  if( bBackToStartOfSentence )
1319  {
1320  pMySh->GoStartSentence();
1321  bBackToStartOfSentence = false;
1322  }
1323  uno::Any aSpellRet =
1324  pMySh->GetDoc()->Spell(*pCursor,
1325  xSpeller, nullptr, nullptr, bIsGrammarCheck, pMySh->GetLayout());
1326  aSpellRet >>= xSpellRet;
1327  aSpellRet >>= aGrammarResult;
1328  bGoOn = GetCursorCnt() > 1;
1329  bGrammarErrorFound = aGrammarResult.aErrors.hasElements();
1330  if( xSpellRet.is() || bGrammarErrorFound )
1331  {
1332  bGoOn = false;
1333  SwPosition* pNewPoint = new SwPosition( *pCursor->GetPoint() );
1334  SwPosition* pNewMark = new SwPosition( *pCursor->GetMark() );
1335 
1336  SetCurr( pNewPoint );
1337  SetCurrX( pNewMark );
1338  }
1339  if( bGoOn )
1340  {
1342  pCursor = pMySh->GetCursor();
1343  if ( *pCursor->GetPoint() > *pCursor->GetMark() )
1344  pCursor->Exchange();
1345  SwPosition* pNew = new SwPosition( *pCursor->GetPoint() );
1346  SetStart( pNew );
1347  pNew = new SwPosition( *pCursor->GetMark() );
1348  SetEnd( pNew );
1349  pNew = new SwPosition( *GetStart() );
1350  SetCurr( pNew );
1351  pNew = new SwPosition( *pNew );
1352  SetCurrX( pNew );
1353  pCursor->SetMark();
1354  --GetCursorCnt();
1355  }
1356  } while ( bGoOn );
1357 
1358  if(xSpellRet.is() || bGrammarErrorFound)
1359  {
1360  // an error has been found
1361  // To fill the spell portions the beginning of the sentence has to be found
1362  SwPaM *pCursor = pMySh->GetCursor();
1363  // set the mark to the right if necessary
1364  if ( *pCursor->GetPoint() > *pCursor->GetMark() )
1365  pCursor->Exchange();
1366  // the cursor has to be collapsed on the left to go to the start of the sentence - if sentence ends inside of the error
1367  pCursor->DeleteMark();
1368  pCursor->SetMark();
1369  bool bStartSent = pMySh->GoStartSentence();
1370  SpellContentPositions aDeletedRedlines = lcl_CollectDeletedRedlines(pMySh);
1371  if(bStartSent)
1372  {
1373  // create a portion from the start part
1374  AddPortion(nullptr, nullptr, aDeletedRedlines);
1375  }
1376  // Set the cursor to the error already found
1377  *pCursor->GetPoint() = *GetCurrX();
1378  *pCursor->GetMark() = *GetCurr();
1379  AddPortion(xSpellRet, &aGrammarResult, aDeletedRedlines);
1380 
1381  // save the end position of the error to continue from here
1382  SwPosition aSaveStartPos = *pCursor->End();
1383  // determine the end of the current sentence
1384  if ( *pCursor->GetPoint() < *pCursor->GetMark() )
1385  pCursor->Exchange();
1386  // again collapse to start marking after the end of the error
1387  pCursor->DeleteMark();
1388  pCursor->SetMark();
1389 
1390  pMySh->GoEndSentence();
1391  if( bGrammarErrorFound )
1392  {
1393  const ModelToViewHelper aConversionMap(static_cast<SwTextNode&>(pCursor->GetNode()), pMySh->GetLayout());
1394  const OUString& aExpandText = aConversionMap.getViewText();
1395  sal_Int32 nSentenceEnd =
1396  aConversionMap.ConvertToViewPosition( aGrammarResult.nBehindEndOfSentencePosition );
1397  // remove trailing space
1398  if( aExpandText[nSentenceEnd - 1] == ' ' )
1399  --nSentenceEnd;
1400  if( pCursor->End()->nContent.GetIndex() < nSentenceEnd )
1401  {
1402  pCursor->End()->nContent.Assign(
1403  pCursor->End()->nNode.GetNode().GetContentNode(), nSentenceEnd);
1404  }
1405  }
1406 
1407  lcl_CutRedlines( aDeletedRedlines, pMySh );
1408  // save the 'global' end of the spellchecking
1409  const SwPosition aSaveEndPos = *GetEnd();
1410  // set the sentence end as 'local' end
1411  SetEnd( new SwPosition( *pCursor->End() ));
1412 
1413  *pCursor->GetPoint() = aSaveStartPos;
1414  *pCursor->GetMark() = *GetEnd();
1415  // now the rest of the sentence has to be searched for errors
1416  // for each error the non-error text between the current and the last error has
1417  // to be added to the portions - if necessary broken into same-language-portions
1418  if( !bGrammarErrorFound ) //in grammar check there's only one error returned
1419  {
1420  do
1421  {
1422  xSpellRet = nullptr;
1423  // don't search for grammar errors here anymore!
1424  pMySh->GetDoc()->Spell(*pCursor,
1425  xSpeller, nullptr, nullptr, false, pMySh->GetLayout()) >>= xSpellRet;
1426  if ( *pCursor->GetPoint() > *pCursor->GetMark() )
1427  pCursor->Exchange();
1428  SetCurr( new SwPosition( *pCursor->GetPoint() ));
1429  SetCurrX( new SwPosition( *pCursor->GetMark() ));
1430 
1431  // if an error has been found go back to the text preceding the error
1432  if(xSpellRet.is())
1433  {
1434  *pCursor->GetPoint() = aSaveStartPos;
1435  *pCursor->GetMark() = *GetCurr();
1436  }
1437  // add the portion
1438  AddPortion(nullptr, nullptr, aDeletedRedlines);
1439 
1440  if(xSpellRet.is())
1441  {
1442  *pCursor->GetPoint() = *GetCurr();
1443  *pCursor->GetMark() = *GetCurrX();
1444  AddPortion(xSpellRet, nullptr, aDeletedRedlines);
1445  // move the cursor to the end of the error string
1446  *pCursor->GetPoint() = *GetCurrX();
1447  // and save the end of the error as new start position
1448  aSaveStartPos = *GetCurrX();
1449  // and the end of the sentence
1450  *pCursor->GetMark() = *GetEnd();
1451  }
1452  // if the end of the sentence has already been reached then break here
1453  if(*GetCurrX() >= *GetEnd())
1454  break;
1455  }
1456  while(xSpellRet.is());
1457  }
1458  else
1459  {
1460  // go to the end of sentence as the grammar check returned it
1461  // at this time the Point is behind the grammar error
1462  // and the mark points to the sentence end as
1463  if ( *pCursor->GetPoint() < *pCursor->GetMark() )
1464  pCursor->Exchange();
1465  }
1466 
1467  // the part between the last error and the end of the sentence has to be added
1468  *pMySh->GetCursor()->GetPoint() = *GetEnd();
1469  if(*GetCurrX() < *GetEnd())
1470  {
1471  AddPortion(nullptr, nullptr, aDeletedRedlines);
1472  }
1473  // set the shell cursor to the end of the sentence to prevent a visible selection
1474  *pCursor->GetMark() = *GetEnd();
1475  if( !bIsGrammarCheck )
1476  {
1477  // set the current position to the end of the sentence
1478  SetCurr( new SwPosition(*GetEnd()) );
1479  }
1480  // restore the 'global' end
1481  SetEnd( new SwPosition(aSaveEndPos) );
1482  rPortions = aLastPortions;
1483  bRet = true;
1484  }
1485  else
1486  {
1487  // if no error could be found the selection has to be corrected - at least if it's not in the body
1488  *pMySh->GetCursor()->GetPoint() = *GetEnd();
1489  pMySh->GetCursor()->DeleteMark();
1490  }
1491 
1492  return bRet;
1493 }
1494 
1495 void SwSpellIter::ToSentenceStart()
1496 {
1497  bBackToStartOfSentence = true;
1498 }
1499 
1501 {
1502  SvtScriptType nScriptType = rSh.GetScriptType();
1503  sal_uInt16 nLangWhichId = RES_CHRATR_LANGUAGE;
1504 
1505  switch(nScriptType)
1506  {
1507  case SvtScriptType::ASIAN : nLangWhichId = RES_CHRATR_CJK_LANGUAGE; break;
1508  case SvtScriptType::COMPLEX : nLangWhichId = RES_CHRATR_CTL_LANGUAGE; break;
1509  default: break;
1510  }
1511  SfxItemSet aSet(rSh.GetAttrPool(), {{nLangWhichId, nLangWhichId}});
1512  rSh.GetCurAttr( aSet );
1513  const SvxLanguageItem& rLang = static_cast<const SvxLanguageItem& >(aSet.Get(nLangWhichId));
1514  return rLang.GetLanguage();
1515 }
1516 
1518 void SwSpellIter::CreatePortion(uno::Reference< XSpellAlternatives > const & xAlt,
1519  linguistic2::ProofreadingResult* pGrammarResult,
1520  bool bIsField, bool bIsHidden)
1521 {
1522  svx::SpellPortion aPortion;
1523  OUString sText;
1524  GetSh()->GetSelectedText( sText );
1525  if(sText.isEmpty())
1526  return;
1527 
1528  // in case of redlined deletions the selection of an error is not the same as the _real_ word
1529  if(xAlt.is())
1530  aPortion.sText = xAlt->getWord();
1531  else if(pGrammarResult)
1532  {
1533  aPortion.bIsGrammarError = true;
1534  if(pGrammarResult->aErrors.hasElements())
1535  {
1536  aPortion.aGrammarError = pGrammarResult->aErrors[0];
1537  aPortion.sText = pGrammarResult->aText.copy( aPortion.aGrammarError.nErrorStart, aPortion.aGrammarError.nErrorLength );
1538  aPortion.xGrammarChecker = pGrammarResult->xProofreader;
1539  auto pProperty = std::find_if(pGrammarResult->aProperties.begin(), pGrammarResult->aProperties.end(),
1540  [](const beans::PropertyValue& rProperty) { return rProperty.Name == "DialogTitle"; });
1541  if (pProperty != pGrammarResult->aProperties.end())
1542  pProperty->Value >>= aPortion.sDialogTitle;
1543  }
1544  }
1545  else
1546  aPortion.sText = sText;
1547  aPortion.eLanguage = lcl_GetLanguage(*GetSh());
1548  aPortion.bIsField = bIsField;
1549  aPortion.bIsHidden = bIsHidden;
1550  aPortion.xAlternatives = xAlt;
1551  SpellContentPosition aPosition;
1552  SwPaM *pCursor = GetSh()->GetCursor();
1553  aPosition.nLeft = pCursor->Start()->nContent.GetIndex();
1554  aPosition.nRight = pCursor->End()->nContent.GetIndex();
1555  aLastPortions.push_back(aPortion);
1556  aLastPositions.push_back(aPosition);
1557 
1558 }
1559 
1560 void SwSpellIter::AddPortion(uno::Reference< XSpellAlternatives > const & xAlt,
1561  linguistic2::ProofreadingResult* pGrammarResult,
1562  const SpellContentPositions& rDeletedRedlines)
1563 {
1564  SwEditShell *pMySh = GetSh();
1565  OUString sText;
1566  pMySh->GetSelectedText( sText );
1567  if(!sText.isEmpty())
1568  {
1569  if(xAlt.is() || pGrammarResult != nullptr)
1570  {
1571  CreatePortion(xAlt, pGrammarResult, false, false);
1572  }
1573  else
1574  {
1575  SwPaM *pCursor = GetSh()->GetCursor();
1576  if ( *pCursor->GetPoint() > *pCursor->GetMark() )
1577  pCursor->Exchange();
1578  // save the start and end positions
1579  SwPosition aStart(*pCursor->GetPoint());
1580  SwPosition aEnd(*pCursor->GetMark());
1581  // iterate over the text to find changes in language
1582  // set the mark equal to the point
1583  *pCursor->GetMark() = aStart;
1584  SwTextNode* pTextNode = pCursor->GetNode().GetTextNode();
1585  LanguageType eStartLanguage = lcl_GetLanguage(*GetSh());
1586  SpellContentPosition aNextRedline = lcl_FindNextDeletedRedline(
1587  rDeletedRedlines, aStart.nContent.GetIndex() );
1588  if( aNextRedline.nLeft == aStart.nContent.GetIndex() )
1589  {
1590  // select until the end of the current redline
1591  const sal_Int32 nEnd = aEnd.nContent.GetIndex() < aNextRedline.nRight ?
1592  aEnd.nContent.GetIndex() : aNextRedline.nRight;
1593  pCursor->GetPoint()->nContent.Assign( pTextNode, nEnd );
1594  CreatePortion(xAlt, pGrammarResult, false, true);
1595  aStart = *pCursor->End();
1596  // search for next redline
1597  aNextRedline = lcl_FindNextDeletedRedline(
1598  rDeletedRedlines, aStart.nContent.GetIndex() );
1599  }
1600  while(*pCursor->GetPoint() < aEnd)
1601  {
1602  // #125786 in table cell with fixed row height the cursor might not move forward
1603  if(!GetSh()->Right(1, CRSR_SKIP_CELLS))
1604  break;
1605 
1606  bool bField = false;
1607  // read the character at the current position to check if it's a field
1608  sal_Unicode const cChar =
1609  pTextNode->GetText()[pCursor->GetMark()->nContent.GetIndex()];
1610  if( CH_TXTATR_BREAKWORD == cChar || CH_TXTATR_INWORD == cChar)
1611  {
1612  const SwTextAttr* pTextAttr = pTextNode->GetTextAttrForCharAt(
1613  pCursor->GetMark()->nContent.GetIndex() );
1614  const sal_uInt16 nWhich = pTextAttr
1615  ? pTextAttr->Which()
1616  : RES_TXTATR_END;
1617  switch (nWhich)
1618  {
1619  case RES_TXTATR_FIELD:
1620  case RES_TXTATR_ANNOTATION:
1621  case RES_TXTATR_FTN:
1622  case RES_TXTATR_FLYCNT:
1623  bField = true;
1624  break;
1625  }
1626  }
1627  else if (cChar == CH_TXT_ATR_FORMELEMENT)
1628  {
1629  SwPosition aPos(*pCursor->GetMark());
1630  bField = pMySh->GetDoc()->getIDocumentMarkAccess()->getDropDownFor(aPos);
1631  }
1632 
1633  LanguageType eCurLanguage = lcl_GetLanguage(*GetSh());
1634  bool bRedline = aNextRedline.nLeft == pCursor->GetPoint()->nContent.GetIndex();
1635  // create a portion if the next character
1636  // - is a field,
1637  // - is at the beginning of a deleted redline
1638  // - has a different language
1639  if(bField || bRedline || eCurLanguage != eStartLanguage)
1640  {
1641  eStartLanguage = eCurLanguage;
1642  // go one step back - the cursor currently selects the first character
1643  // with a different language
1644  // in the case of redlining it's different
1645  if(eCurLanguage != eStartLanguage || bField)
1646  *pCursor->GetPoint() = *pCursor->GetMark();
1647  // set to the last start
1648  *pCursor->GetMark() = aStart;
1649  // create portion should only be called if a selection exists
1650  // there's no selection if there's a field at the beginning
1651  if(*pCursor->Start() != *pCursor->End())
1652  CreatePortion(xAlt, pGrammarResult, false, false);
1653  aStart = *pCursor->End();
1654  // now export the field - if there is any
1655  if(bField)
1656  {
1657  *pCursor->GetMark() = *pCursor->GetPoint();
1658  GetSh()->Right(1, CRSR_SKIP_CELLS);
1659  CreatePortion(xAlt, pGrammarResult, true, false);
1660  aStart = *pCursor->End();
1661  }
1662  }
1663  // if a redline start then create a portion for it
1664  if(bRedline)
1665  {
1666  *pCursor->GetMark() = *pCursor->GetPoint();
1667  // select until the end of the current redline
1668  const sal_Int32 nEnd = aEnd.nContent.GetIndex() < aNextRedline.nRight ?
1669  aEnd.nContent.GetIndex() : aNextRedline.nRight;
1670  pCursor->GetPoint()->nContent.Assign( pTextNode, nEnd );
1671  CreatePortion(xAlt, pGrammarResult, false, true);
1672  aStart = *pCursor->End();
1673  // search for next redline
1674  aNextRedline = lcl_FindNextDeletedRedline(
1675  rDeletedRedlines, aStart.nContent.GetIndex() );
1676  }
1677  *pCursor->GetMark() = *pCursor->GetPoint();
1678  }
1679  pCursor->SetMark();
1680  *pCursor->GetMark() = aStart;
1681  CreatePortion(xAlt, pGrammarResult, false, false);
1682  }
1683  }
1684 }
1685 
1687 {
1688  SwTextNode *pNode;
1689  SwWrongList *pWrong;
1690  SwNodeIndex aIdx = rErrorPosition.Start()->nNode;
1691  SwNodeIndex aEndIdx = rErrorPosition.Start()->nNode;
1692  sal_Int32 nStart = rErrorPosition.Start()->nContent.GetIndex();
1693  sal_Int32 nEnd = COMPLETE_STRING;
1694  while( aIdx <= aEndIdx )
1695  {
1696  pNode = aIdx.GetNode().GetTextNode();
1697  if( pNode ) {
1698  if( aIdx == aEndIdx )
1699  nEnd = rErrorPosition.End()->nContent.GetIndex();
1700  pWrong = pNode->GetGrammarCheck();
1701  if( pWrong )
1702  pWrong->RemoveEntry( nStart, nEnd );
1703  pWrong = pNode->GetWrong();
1704  if( pWrong )
1705  pWrong->RemoveEntry( nStart, nEnd );
1707  }
1708  ++aIdx;
1709  nStart = 0;
1710  }
1711 }
1712 
1713 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:151
void DeleteMark()
Definition: pam.hxx:177
void KillPams()
Definition: crsrsh.cxx:1019
sal_uLong GetIndex() const
Definition: node.hxx:282
std::function< SwTextFrame *()> Creator
Definition: splargs.hxx:148
SwNode & GetNode(bool bPoint=true) const
Definition: pam.hxx:223
Marks a position in the document model.
Definition: pam.hxx:35
void DelSoftHyph(const sal_Int32 nStart, const sal_Int32 nEnd)
Definition: thints.cxx:1780
void FillFindPos(SwDocPositions ePos, SwPosition &rPos) const
Definition: swcrsr.cxx:1094
SwRect & Union(const SwRect &rRect)
Definition: swrect.cxx:41
SwPaM * GetCursor(bool bMakeTableCursor=true) const
Return pointer to the current shell cursor.
Definition: crsrsh.cxx:188
const OUString & GetText() const
Definition: ndtxt.hxx:211
static bool HasConvIter()
Is text conversion active somewhere else?
Definition: edlingu.cxx:604
#define UPN_MAX_NUMBER_OF_SUGGESTIONS
css::uno::Any Spell(SwPaM &, css::uno::Reference< css::linguistic2::XSpellChecker1 > const &, sal_uInt16 *pPageCnt, sal_uInt16 *pPageSt, bool bGrammarCheck, SwRootFrame const *pLayout, SwConversionArgs *pConvArgs=nullptr) const
Operations on the content of the document e.g.
Definition: docedt.cxx:520
SwNodeIndex nNode
Definition: pam.hxx:37
bool IsTableMode() const
Definition: crsrsh.hxx:647
void GetSelectedText(OUString &rBuf, ParaBreakType nHndlParaBreak=ParaBreakType::ToBlank)
Query text within selection.
Definition: edglss.cxx:253
static void repaintTextFrames(const SwTextNode &rNode)
Repaint all text frames of the given text node.
Definition: txtfrm.cxx:4009
constexpr TypedWhichId< SvxLanguageItem > RES_CHRATR_LANGUAGE(10)
static bool HasLastSentenceGotGrammarChecked()
Check SwSpellIter data to see if the last sentence got grammar checked.
Definition: edlingu.cxx:586
const SwPosition * GetMark() const
Definition: pam.hxx:209
bool GoEndSentence()
Definition: crstrvl1.cxx:73
SwContentFrame * getLayoutFrame(const SwRootFrame *, const SwPosition *pPos=nullptr, std::pair< Point, bool > const *pViewPosAndCalcFrame=nullptr) const
Definition: node.cxx:1148
sal_Int64 n
bool SpellSentence(svx::SpellPortions &rToFill, bool bIsGrammarCheck)
Spells on a sentence basis - the SpellPortions are needed.
Definition: edlingu.cxx:1032
bool m_bRealWidth
Calculation of the width required.
Definition: crstate.hxx:149
SwCursor * GetSwCursor() const
Definition: crsrsh.hxx:872
Definition: doc.hxx:186
css::uno::Reference< css::linguistic2::XProofreader > xGrammarChecker
constexpr TypedWhichId< SwFormatFlyCnt > RES_TXTATR_FLYCNT(57)
SwNode & GetNode() const
Definition: ndindex.hxx:119
void DestroyCursor()
transform TableCursor to normal cursor, nullify Tablemode
Definition: crsrsh.cxx:145
void Pos(const Point &rNew)
Definition: swrect.hxx:169
IDocumentMarkAccess * getIDocumentMarkAccess()
Definition: docbm.cxx:1683
Dialog to specify the properties of date form field.
void HyphIgnore()
ignore hyphenation
Definition: edlingu.cxx:813
Of course Writer needs its own rectangles.
Definition: swrect.hxx:35
sal_uInt16 Which() const
Definition: txatbase.hxx:110
void ApplyChangedSentence(const svx::SpellPortions &rNewPortions, bool bRecheck)
Applies a changed sentence.
Definition: edlingu.cxx:1071
static bool HasHyphIter()
Is hyphenation active somewhere else?
Definition: edlingu.cxx:609
IDocumentContentOperations const & getIDocumentContentOperations() const
Definition: doc.cxx:314
virtual ::sw::mark::IFieldmark * getDropDownFor(const SwPosition &pos) const =0
uno::Reference< linguistic2::XLinguProperties > GetLinguPropertySet()
Definition: swtypes.cxx:60
void CalcStartEnd(sal_uLong nNdIdx, sal_Int32 &rStart, sal_Int32 &rEnd) const
Calculates the intersection with text node number nNdIdx.
Definition: docredln.cxx:1269
void RemoveEntry(sal_Int32 nBegin, sal_Int32 nEnd)
Definition: wrong.cxx:585
constexpr TypedWhichId< SwFormatField > RES_TXTATR_ANNOTATION(59)
#define CH_TXT_ATR_FORMELEMENT
Definition: hintids.hxx:177
static SwConvIter * g_pConvIter
Definition: edlingu.cxx:185
OUString sDialogTitle
bool HasSelection() const
Does the current cursor create a selection?
Definition: crsrsh.cxx:2500
static bool IsShowChanges(const RedlineFlags eM)
bool IsSymbolAt(sal_Int32 nBegin) const
in ndcopy.cxx
Definition: itratr.cxx:844
size_type size() const
Definition: docary.hxx:266
SwMoveFnCollection const & MakeFindRange(SwDocPositions, SwDocPositions, SwPaM *) const
Definition: crsrsh.hxx:866
SwDocPositions
Definition: cshtyp.hxx:103
SwContentNode * GetContentNode(bool bPoint=true) const
Definition: pam.hxx:229
bool GoStartSentence()
Definition: crstrvl1.cxx:78
SwTextAttr * GetTextAttrForCharAt(const sal_Int32 nIndex, const sal_uInt16 nWhich=RES_TXTATR_END) const
get the text attribute at position nIndex which owns the dummy character CH_TXTATR_* at that position...
Definition: ndtxt.cxx:3051
#define CH_TXTATR_BREAKWORD
Definition: hintids.hxx:170
sal_uInt16 sal_Unicode
void HyphStart(SwDocPositions eStart, SwDocPositions eEnd)
Save selections.
Definition: edlingu.cxx:746
static void InsertSoftHyph(const sal_Int32 nHyphPos)
For Inserting SoftHyphen. Position is offset within the syllabificated word.
Definition: edlingu.cxx:806
#define CH_TXTATR_INWORD
Definition: hintids.hxx:171
void StartProgress(const char *pMessResId, long nStartValue, long nEndValue, SwDocShell *pDocShell)
Definition: mainwn.cxx:52
rtl::Reference< SwDoc > mxDoc
The document; never 0.
Definition: viewsh.hxx:174
SwIndex nContent
Definition: pam.hxx:38
sal_Int32 ConvertToViewPosition(sal_Int32 nModelPos) const
Converts a model position into a view position.
constexpr TypedWhichId< SvxLanguageItem > RES_CHRATR_CTL_LANGUAGE(29)
css::uno::Reference< css::uno::XInterface > HyphContinue(sal_uInt16 *pPageCnt, sal_uInt16 *pPageSt)
Definition: edlingu.cxx:770
#define End_(_nam)
SwDoc * GetDoc() const
Definition: viewsh.hxx:284
constexpr TypedWhichId< SwFormatFootnote > RES_TXTATR_FTN(58)
SwPaM * GetNext()
Definition: pam.hxx:264
virtual bool GetCharRect(SwRect &, const SwPosition &, SwCursorMoveState *=nullptr, bool bAllowFarAway=true) const
Definition: unusedf.cxx:71
bool GetGrammarCorrection(css::linguistic2::ProofreadingResult &rResult, sal_Int32 &rErrorPosInText, sal_Int32 &rErrorIndexInResult, css::uno::Sequence< OUString > &rSuggestions, const Point *pPt, SwRect &rSelectRect)
Definition: edlingu.cxx:954
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:136
const SfxItemPool & GetAttrPool() const
Definition: viewsh.hxx:614
virtual SwRedlineTable::size_type GetRedlinePos(const SwNode &rNode, RedlineType nType) const =0
virtual bool InsertString(const SwPaM &rRg, const OUString &, const SwInsertFlags nInsertMode=SwInsertFlags::EMPTYEXPAND)=0
Insert string into existing text node at position rRg.Point().
bool LeftMargin()
Definition: crsrsh.hxx:359
constexpr TypedWhichId< SwFormatField > RES_TXTATR_FIELD(RES_TXTATR_NOEND_BEGIN)
SvtScriptType
const OUString & getViewText() const
SvtScriptType GetScriptType() const
returns the script type of the selection
Definition: edattr.cxx:666
#define SAL_MAX_INT32
void SpellEnd(SwConversionArgs const *pConvArgs=nullptr, bool bRestoreSelection=true)
Restore selections.
Definition: edlingu.cxx:659
int i
const SwPosition * GetPoint() const
Definition: pam.hxx:207
void EndAction(const bool bIdleEnd=false, const bool DoSetPosX=false)
Definition: crsrsh.cxx:238
SwIndex & Assign(SwIndexReg *, sal_Int32)
Definition: index.cxx:206
void Push()
store a copy of the current cursor on the cursor stack
Definition: crsrsh.cxx:2235
void Exchange()
Definition: pam.cxx:489
void SetAttrItem(const SfxPoolItem &, SetAttrMode nFlags=SetAttrMode::DEFAULT, const bool bParagraphSetting=false)
Definition: edatmisc.cxx:112
bool IsIdle() const
Definition: viewopt.hxx:204
SwContentNode * GetContentNode()
Definition: node.hxx:615
css::uno::Reference< css::linguistic2::XSpellAlternatives > GetCorrection(const Point *pPt, SwRect &rSelectRect)
Get a list of potential corrections for misspelled word.
Definition: edlingu.cxx:893
vector_type::size_type size_type
Definition: docary.hxx:228
bool HasMark() const
A PaM marks a selection if Point and Mark are distinct positions.
Definition: pam.hxx:205
css::uno::Any SpellContinue(sal_uInt16 *pPageCnt, sal_uInt16 *pPageSt, SwConversionArgs const *pConvArgs)
Definition: edlingu.cxx:676
static sal_Int16 GetI18NScriptTypeOfLanguage(LanguageType nLang)
bool RightMargin(bool bAPI=false)
Definition: crsrsh.hxx:360
Marks a character position inside a document model node.
Definition: index.hxx:37
SwGrammarMarkUp * GetGrammarCheck()
Definition: txtedt.cxx:2181
#define SET_CURR_SHELL(shell)
Definition: swtypes.hxx:101
sal_uInt16 GetCursorCnt(bool bAll=true) const
Get the number of elements in the ring of cursors.
Definition: crsrsh.cxx:2714
Marks a node in the document model.
Definition: ndindex.hxx:31
static LanguageType lcl_GetLanguage(SwEditShell &rSh)
Definition: edlingu.cxx:1500
static SpellContentPositions lcl_CollectDeletedRedlines(SwEditShell const *pSh)
Collect all deleted redlines of the current text node beginning at the start of the cursor position...
Definition: edlingu.cxx:1223
void TableCursorToCursor()
enter block mode, change normal cursor into block cursor
Definition: crsrsh.cxx:893
stay with the cursor inside text
const SwPosition * Start() const
Definition: pam.hxx:212
void HandleCorrectionError(const OUString &aText, SwPosition aPos, sal_Int32 nBegin, sal_Int32 nLen, const Point *pPt, SwRect &rSelectRect)
Definition: edlingu.cxx:825
static void MoveContinuationPosToEndOfCheckedSentence()
Moves the continuation position to the end of the currently checked sentence.
Definition: edlingu.cxx:1061
bool IsInProtectSect() const
Is node in a protected area?
Definition: node.cxx:409
void SetLinguRange(SwDocPositions eStart, SwDocPositions eEnd)
Definition: edlingu.cxx:614
void StartAction()
Definition: crsrsh.cxx:221
const sal_uInt16 CRSR_SKIP_CELLS
Definition: swcrsr.hxx:64
static SwSpellIter * g_pSpellIter
Definition: edlingu.cxx:184
sal_Int32 getSentenceStart(sal_Int32 nPos)
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:80
LanguageType GetLanguage() const
IDocumentRedlineAccess const & getIDocumentRedlineAccess() const
Definition: doc.cxx:334
constexpr sal_uInt16 RES_TXTATR_END(RES_TXTATR_NOEND_END)
const SwViewOption * GetViewOptions() const
Definition: viewsh.hxx:426
bool ExtendSelection(bool bEnd=true, sal_Int32 nCount=1)
extend current SSelection by n characters
Definition: crsrsh.cxx:2603
void SetIdle(bool b) const
Definition: viewopt.hxx:211
std::vector< SpellContentPosition > SpellContentPositions
Definition: edlingu.cxx:109
css::uno::Reference< css::linguistic2::XSpellAlternatives > xAlternatives
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
static SwHyphIter * g_pHyphIter
Definition: edlingu.cxx:186
const SwPosition * End() const
Definition: pam.hxx:217
uno::Reference< linguistic2::XSpellChecker1 > GetSpellChecker()
Definition: swtypes.cxx:45
static void IgnoreGrammarErrorAt(SwPaM &rErrorPosition)
Definition: edlingu.cxx:1686
void SpellStart(SwDocPositions eStart, SwDocPositions eEnd, SwDocPositions eCurr, SwConversionArgs *pConvArgs=nullptr)
Functions used for spell checking and text conversion.
Definition: edlingu.cxx:622
LanguageType GetLang(const sal_Int32 nBegin, const sal_Int32 nLen=0, sal_uInt16 nScript=0) const
Definition: thints.cxx:3402
const SwRect & GetCharRect() const
Definition: crsrsh.hxx:520
RedlineType GetType(sal_uInt16 nPos=0) const
Definition: docredln.cxx:1733
void HyphEnd()
restore selections.
Definition: edlingu.cxx:757
static SpellContentPosition lcl_FindNextDeletedRedline(const SpellContentPositions &rDeletedRedlines, sal_Int32 nSearchFrom)
Definition: edlingu.cxx:1278
SwWrongList * GetWrong()
Definition: txtedt.cxx:2158
const char * pChar
void ClearMark()
Definition: crsrsh.cxx:936
bool GetCurAttr(SfxItemSet &, const bool bMergeIndentValuesOfNumRule=false) const
Definition: edattr.cxx:176
static sal_uInt32 lcl_CountRedlines(const svx::SpellPortions &rLastPortions)
Definition: edlingu.cxx:1055
sal_Int32 getSentenceEnd(sal_Int32 nPos)
css::linguistic2::SingleProofreadingError aGrammarError
LanguageType eLanguage
virtual RedlineFlags GetRedlineFlags() const =0
Query the currently set redline mode.
static void PutSpellingToSentenceStart()
Make SpellIter start with the current sentence when called next time.
Definition: edlingu.cxx:1047
std::vector< SpellPortion > SpellPortions
virtual void SetMark()
Unless this is called, the getter method of Mark will return Point.
Definition: pam.cxx:475
SwTextFrame * SwHyphIterCacheLastTextFrame(SwTextNode const *pNode, const sw::Creator &create)
Definition: edlingu.cxx:573
bool Pop(PopMode)
delete cursor
Definition: crsrsh.cxx:2257
static void lcl_CutRedlines(SpellContentPositions &aDeletedRedlines, SwEditShell const *pSh)
remove the redline positions after the current selection
Definition: edlingu.cxx:1263
virtual const SwRedlineTable & GetRedlineTable() const =0
SwRootFrame * GetLayout() const
Definition: viewsh.cxx:2069
sal_uInt16 GetPageNum() const
Definition: rootfrm.hxx:307
#define Start_(_nam)
sal_uInt16 mnStartAction
!= 0 if at least one Action is active.
Definition: viewsh.hxx:176
const sal_Int32 COMPLETE_STRING
Definition: swtypes.hxx:61
constexpr TypedWhichId< SvxLanguageItem > RES_CHRATR_CJK_LANGUAGE(24)
css::uno::Reference< css::linguistic2::XHyphenatedWord > Hyphenate(SwPaM *pPam, const Point &rCursorPos, sal_uInt16 *pPageCnt, sal_uInt16 *pPageSt)
Definition: docedt.cxx:816
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:836
css::uno::Any SAL_CALL makeAny(const SharedUNOComponent< INTERFACE, COMPONENT > &value)