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