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