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