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>
36#include <editeng/langitem.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
59using namespace ::svx;
60using namespace ::com::sun::star;
61using namespace ::com::sun::star::uno;
62using namespace ::com::sun::star::beans;
63using namespace ::com::sun::star::linguistic2;
64
65namespace {
66
67class 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
76public:
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
103struct SpellContentPosition
104{
105 sal_Int32 nLeft;
106 sal_Int32 nRight;
107};
108
109}
110
111typedef std::vector<SpellContentPosition> SpellContentPositions;
112
113namespace {
114
115class 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);
130public:
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
147class SwConvIter : public SwLinguIter
148{
149 SwConversionArgs& m_rArgs;
150
151public:
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
162class 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
172public:
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
194static SwSpellIter* g_pSpellIter = nullptr;
195static SwConvIter* g_pConvIter = nullptr;
196static SwHyphIter* g_pHyphIter = nullptr;
197
198SwLinguIter::SwLinguIter()
199 : m_pSh(nullptr)
200 , m_nCursorCount(0)
201{
202 // TODO missing: ensurance of re-entrance, OSL_ENSURE( etc.
203}
204
205void 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
263void 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
285void 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()
299uno::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
355void SwConvIter::Start( SwEditShell *pShell, SwDocPositions eStart,
356 SwDocPositions eEnd )
357{
358 if( GetSh() )
359 return;
360 Start_( pShell, eStart, eEnd );
361}
362
363uno::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
423bool 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
430void 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
442void 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
458void SwHyphIter::End()
459{
460 if( !GetSh() )
461 return;
462 GetSh()->GetViewOptions()->SetIdle(m_bOldIdle);
463 End_();
464}
465
466uno::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
523void 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()->SetContent( pCursor->End()->GetContentIndex() );
533 pCursor->SetMark();
534}
535
536void SwHyphIter::DelSoftHyph( SwPaM &rPam )
537{
538 const SwPosition* pStt = rPam.Start();
539 const sal_Int32 nStart = pStt->GetContentIndex();
540 const sal_Int32 nEnd = rPam.End()->GetContentIndex();
541 SwTextNode *pNode = pStt->GetNode().GetTextNode();
542 pNode->DelSoftHyph( nStart, nEnd );
543}
544
545void 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 auto [pSttPos, pEndPos] = pCursor->StartEnd(); // SwPosition*
554
555 const sal_Int32 nLastHyphLen = GetEnd()->GetContentIndex() -
556 pSttPos->GetContentIndex();
557
558 if( pSttPos->GetNode() != pEndPos->GetNode() || !nLastHyphLen )
559 {
560 OSL_ENSURE( pSttPos->GetNode() == pEndPos->GetNode(),
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->AdjustContent( +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
581namespace sw {
582
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 = GetCursor();
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
670void 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.
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 }
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
780uno::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.
803 uno::Reference< uno::XInterface > xRet;
804 g_pHyphIter->Continue( pPageCnt, pPageSt ) >>= xRet;
806
807 if( xRet.is() )
808 g_pHyphIter->ShowSelection();
809
810 return xRet;
811}
812
817void 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.
830 g_pHyphIter->Ignore();
832
833 g_pHyphIter->ShowSelection();
834}
835
836void 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 SwNode const& rNode(GetCursor()->GetPoint()->GetNode());
842 Push();
843 LeftMargin();
844 const sal_Int32 nLineStart = &rNode == &GetCursor()->GetPoint()->GetNode()
846 : 0;
847 RightMargin();
848 const sal_Int32 nLineEnd = &rNode == &GetCursor()->GetPoint()->GetNode()
850 : rNode.GetTextNode()->Len();
852
853 // make sure the selection build later from the data below does
854 // not "in word" character to the left and right in order to
855 // preserve those. Therefore count those "in words" in order to
856 // modify the selection accordingly.
857 const sal_Unicode* pChar = aText.getStr();
858 sal_Int32 nLeft = 0;
859 while (*pChar++ == CH_TXTATR_INWORD)
860 ++nLeft;
861 pChar = aText.getLength() ? aText.getStr() + aText.getLength() - 1 : nullptr;
862 sal_Int32 nRight = 0;
863 while (pChar && *pChar-- == CH_TXTATR_INWORD)
864 ++nRight;
865
866 aPos.SetContent( nBegin + nLeft );
867 SwPaM* pCursor = GetCursor();
868 *pCursor->GetPoint() = aPos;
869 pCursor->SetMark();
870 ExtendSelection( true, nLen - nLeft - nRight );
871 // don't determine the rectangle in the current line
872 const sal_Int32 nWordStart = (nBegin + nLeft) < nLineStart ? nLineStart : nBegin + nLeft;
873 // take one less than the line end - otherwise the next line would be calculated
874 const sal_Int32 nWordEnd = (nBegin + nLen - nLeft - nRight) > nLineEnd
875 ? nLineEnd : (nBegin + nLen - nLeft - nRight);
876 Push();
877 pCursor->DeleteMark();
878 SwPosition& rPtPos = *GetCursor()->GetPoint();
879 rPtPos.SetContent(nWordStart);
880 SwRect aStartRect;
881 SwCursorMoveState aState;
882 aState.m_bRealWidth = true;
883 SwContentNode* pContentNode = pCursor->GetPointContentNode();
884 std::pair<Point, bool> tmp;
885 if (pPt)
886 {
887 tmp.first = *pPt;
888 tmp.second = false;
889 }
890 SwContentFrame *const pContentFrame = pContentNode->getLayoutFrame(GetLayout(), pCursor->GetPoint(), pPt ? &tmp : nullptr);
891
892 pContentFrame->GetCharRect( aStartRect, *pCursor->GetPoint(), &aState );
893 rPtPos.SetContent(nWordEnd - 1);
894 SwRect aEndRect;
895 pContentFrame->GetCharRect( aEndRect, *pCursor->GetPoint(),&aState );
896 rSelectRect = aStartRect.Union( aEndRect );
898}
899
908uno::Reference< XSpellAlternatives >
909 SwEditShell::GetCorrection( const Point* pPt, SwRect& rSelectRect )
910{
911 uno::Reference< XSpellAlternatives > xSpellAlt;
912
913 if( IsTableMode() )
914 return nullptr;
915 SwPaM* pCursor = GetCursor();
916 SwPosition aPos( *pCursor->GetPoint() );
918 SwTextNode *pNode = nullptr;
919 SwWrongList *pWrong = nullptr;
920 if (pPt && GetLayout()->GetModelPositionForViewPoint( &aPos, *const_cast<Point*>(pPt), &eTmpState ))
921 pNode = aPos.GetNode().GetTextNode();
922 if (nullptr == pNode)
923 pNode = pCursor->GetPointNode().GetTextNode();
924 if (nullptr != pNode)
925 pWrong = pNode->GetWrong();
926 if (nullptr != pWrong && !pNode->IsInProtectSect())
927 {
928 sal_Int32 nBegin = aPos.GetContentIndex();
929 sal_Int32 nLen = 1;
930 if (pWrong->InWrongWord(nBegin, nLen) && !pNode->IsSymbolAt(nBegin))
931 {
932 const OUString aText(pNode->GetText().copy(nBegin, nLen));
933 // TODO: this doesn't handle fieldmarks properly
934 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, std::move(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.GetNode().GetTextNode();
993 if (nullptr == pNode)
994 pNode = pCursor->GetPointNode().GetTextNode();
995 if (nullptr != pNode)
996 pWrong = pNode->GetGrammarCheck();
997 if (nullptr != pWrong && !pNode->IsInProtectSect())
998 {
999 sal_Int32 nBegin = aPos.GetContentIndex();
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, std::move(aPos), nBegin, nLen, pPt, rSelectRect );
1045 }
1046 }
1047 }
1048
1049 return bRes;
1050}
1051
1052bool 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
1075static 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
1091void 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()->SetContent( aCurrentOldPosition->nLeft );
1153 pCursor->GetMark()->SetContent( 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
1168 // if there is a comment inside the original word, don't delete it:
1169 // but keep it at the end of the replacement
1170 // TODO: keep all the comments with a recursive function
1171 sal_Int32 nCommentPos(pCursor->GetText().indexOf(OUStringChar(CH_TXTATR_INWORD)));
1172 if ( nCommentPos > -1 )
1173 {
1174 // delete the original word after the comment
1175 pCursor->GetPoint()->AdjustContent(nCommentPos + 1);
1176
1177 mxDoc->getIDocumentContentOperations().ReplaceRange(*pCursor, OUString(), false);
1178 // and select only the remaining part before the comment
1179 pCursor->GetPoint()->AdjustContent(-(nCommentPos + 1));
1180 pCursor->GetMark()->AdjustContent(-1);
1181 }
1182
1183 mxDoc->getIDocumentContentOperations().ReplaceRange(*pCursor, aCurrentNewPortion->sText, false);
1184 }
1185 else if(aCurrentNewPortion->eLanguage != aCurrentOldPortion->eLanguage)
1186 {
1187 // apply language
1188 SetAttrItem( SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId) );
1189 }
1190 else if( aCurrentNewPortion->bIgnoreThisError )
1191 {
1192 // add the 'ignore' markup to the TextNode's grammar ignore markup list
1193 IgnoreGrammarErrorAt( *pCursor );
1194 OSL_FAIL("TODO: add ignore mark to text node");
1195 }
1196 }
1197 while(aCurrentNewPortion != rNewPortions.begin());
1198 }
1199 else
1200 {
1201 OSL_ENSURE( !rLastPositions.empty(), "rLastPositions should not be empty here" );
1202
1203 // select the complete sentence
1204 SpellContentPositions::const_iterator aCurrentEndPosition = rLastPositions.end();
1205 --aCurrentEndPosition;
1206 SpellContentPositions::const_iterator aCurrentStartPosition = rLastPositions.begin();
1207 pCursor->GetPoint()->SetContent( aCurrentStartPosition->nLeft );
1208 pCursor->GetMark()->SetContent( aCurrentEndPosition->nRight );
1209
1210 // delete the sentence completely
1211 mxDoc->getIDocumentContentOperations().DeleteAndJoin(*pCursor);
1212 for(const auto& rCurrentNewPortion : rNewPortions)
1213 {
1214 // set the language attribute
1215 SvtScriptType nScriptType = GetScriptType();
1216 sal_uInt16 nLangWhichId = RES_CHRATR_LANGUAGE;
1217 switch(nScriptType)
1218 {
1219 case SvtScriptType::ASIAN : nLangWhichId = RES_CHRATR_CJK_LANGUAGE; break;
1220 case SvtScriptType::COMPLEX : nLangWhichId = RES_CHRATR_CTL_LANGUAGE; break;
1221 default: break;
1222 }
1223 SfxItemSet aSet(GetAttrPool(), nLangWhichId, nLangWhichId);
1224 GetCurAttr( aSet );
1225 const SvxLanguageItem& rLang = static_cast<const SvxLanguageItem& >(aSet.Get(nLangWhichId));
1226 if(rLang.GetLanguage() != rCurrentNewPortion.eLanguage)
1227 SetAttrItem( SvxLanguageItem(rCurrentNewPortion.eLanguage, nLangWhichId) );
1228 // insert the new string
1229 mxDoc->getIDocumentContentOperations().InsertString(*pCursor, rCurrentNewPortion.sText);
1230
1231 // set the cursor to the end of the inserted string
1232 *pCursor->Start() = *pCursor->End();
1233 }
1234 }
1235
1236 // restore cursor to the end of the sentence
1237 // (will work also if the sentence length has changed,
1238 // since cursors get updated automatically!)
1240
1241 // collapse cursor to the end of the modified sentence
1242 *pCursor->Start() = *pCursor->End();
1243 if (bRecheck)
1244 {
1245 // in grammar check the current sentence has to be checked again
1247 }
1248 // set continuation position for spell/grammar checking to the end of this sentence
1249 g_pSpellIter->SetCurr( new SwPosition(*pCursor->Start()) );
1250
1251 mxDoc->GetIDocumentUndoRedo().EndUndo( SwUndoId::UI_TEXT_CORRECTION, nullptr );
1252 EndAction();
1253
1254}
1259{
1260 SpellContentPositions aRedlines;
1261 SwDoc* pDoc = pSh->GetDoc();
1263 if ( bShowChg )
1264 {
1265 SwPaM *pCursor = pSh->GetCursor();
1266 const SwPosition* pStartPos = pCursor->Start();
1267 const SwTextNode* pTextNode = pCursor->GetPointNode().GetTextNode();
1268
1269 SwRedlineTable::size_type nAct = pDoc->getIDocumentRedlineAccess().GetRedlinePos( *pTextNode, RedlineType::Any );
1270 const sal_Int32 nStartIndex = pStartPos->GetContentIndex();
1271 for ( ; nAct < pDoc->getIDocumentRedlineAccess().GetRedlineTable().size(); nAct++ )
1272 {
1273 const SwRangeRedline* pRed = pDoc->getIDocumentRedlineAccess().GetRedlineTable()[ nAct ];
1274
1275 if ( pRed->Start()->GetNode() > *pTextNode )
1276 break;
1277
1278 if( RedlineType::Delete == pRed->GetType() )
1279 {
1280 sal_Int32 nStart_, nEnd_;
1281 pRed->CalcStartEnd( pTextNode->GetIndex(), nStart_, nEnd_ );
1282 sal_Int32 nStart = nStart_;
1283 sal_Int32 nEnd = nEnd_;
1284 if(nStart >= nStartIndex || nEnd >= nStartIndex)
1285 {
1286 SpellContentPosition aAdd;
1287 aAdd.nLeft = nStart;
1288 aAdd.nRight = nEnd;
1289 aRedlines.push_back(aAdd);
1290 }
1291 }
1292 }
1293 }
1294 return aRedlines;
1295}
1296
1298static void lcl_CutRedlines( SpellContentPositions& aDeletedRedlines, SwEditShell const * pSh )
1299{
1300 if(!aDeletedRedlines.empty())
1301 {
1302 SwPaM *pCursor = pSh->GetCursor();
1303 const SwPosition* pEndPos = pCursor->End();
1304 const sal_Int32 nEnd = pEndPos->GetContentIndex();
1305 while(!aDeletedRedlines.empty() &&
1306 aDeletedRedlines.back().nLeft > nEnd)
1307 {
1308 aDeletedRedlines.pop_back();
1309 }
1310 }
1311}
1312
1313static SpellContentPosition lcl_FindNextDeletedRedline(
1314 const SpellContentPositions& rDeletedRedlines,
1315 sal_Int32 nSearchFrom )
1316{
1317 SpellContentPosition aRet;
1318 aRet.nLeft = aRet.nRight = SAL_MAX_INT32;
1319 if(!rDeletedRedlines.empty())
1320 {
1321 auto aIter = std::find_if_not(rDeletedRedlines.begin(), rDeletedRedlines.end(),
1322 [nSearchFrom](const SpellContentPosition& rPos) { return rPos.nLeft < nSearchFrom; });
1323 if (aIter != rDeletedRedlines.end())
1324 aRet = *aIter;
1325 }
1326 return aRet;
1327}
1328
1329bool SwSpellIter::SpellSentence(svx::SpellPortions& rPortions, bool bIsGrammarCheck)
1330{
1331 bool bRet = false;
1332 m_aLastPortions.clear();
1333 m_aLastPositions.clear();
1334
1335 SwEditShell *pMySh = GetSh();
1336 if( !pMySh )
1337 return false;
1338
1339 OSL_ENSURE( GetEnd(), "SwSpellIter::SpellSentence without Start?");
1340
1341 uno::Reference< XSpellAlternatives > xSpellRet;
1342 linguistic2::ProofreadingResult aGrammarResult;
1343 bool bGoOn = true;
1344 bool bGrammarErrorFound = false;
1345 do {
1346 SwPaM *pCursor = pMySh->GetCursor();
1347 if ( !pCursor->HasMark() )
1348 pCursor->SetMark();
1349
1350 *pCursor->GetPoint() = *GetCurr();
1351 *pCursor->GetMark() = *GetEnd();
1352
1353 if (m_bBackToStartOfSentence)
1354 {
1355 pMySh->GoStartSentence();
1356 m_bBackToStartOfSentence = false;
1357 }
1358 uno::Any aSpellRet = pMySh->GetDoc()->Spell(*pCursor, m_xSpeller, nullptr, nullptr,
1359 bIsGrammarCheck, pMySh->GetLayout());
1360 aSpellRet >>= xSpellRet;
1361 aSpellRet >>= aGrammarResult;
1362 bGoOn = GetCursorCnt() > 1;
1363 bGrammarErrorFound = aGrammarResult.aErrors.hasElements();
1364 if( xSpellRet.is() || bGrammarErrorFound )
1365 {
1366 bGoOn = false;
1367 SwPosition* pNewPoint = new SwPosition( *pCursor->GetPoint() );
1368 SwPosition* pNewMark = new SwPosition( *pCursor->GetMark() );
1369
1370 SetCurr( pNewPoint );
1371 SetCurrX( pNewMark );
1372 }
1373 if( bGoOn )
1374 {
1376 pCursor = pMySh->GetCursor();
1377 if ( *pCursor->GetPoint() > *pCursor->GetMark() )
1378 pCursor->Exchange();
1379 SwPosition* pNew = new SwPosition( *pCursor->GetPoint() );
1380 SetStart( pNew );
1381 pNew = new SwPosition( *pCursor->GetMark() );
1382 SetEnd( pNew );
1383 pNew = new SwPosition( *GetStart() );
1384 SetCurr( pNew );
1385 pNew = new SwPosition( *pNew );
1386 SetCurrX( pNew );
1387 pCursor->SetMark();
1388 --GetCursorCnt();
1389 }
1390 } while ( bGoOn );
1391
1392 if(xSpellRet.is() || bGrammarErrorFound)
1393 {
1394 // an error has been found
1395 // To fill the spell portions the beginning of the sentence has to be found
1396 SwPaM *pCursor = pMySh->GetCursor();
1397 // set the mark to the right if necessary
1398 if ( *pCursor->GetPoint() > *pCursor->GetMark() )
1399 pCursor->Exchange();
1400 // the cursor has to be collapsed on the left to go to the start of the sentence - if sentence ends inside of the error
1401 pCursor->DeleteMark();
1402 pCursor->SetMark();
1403 bool bStartSent = pMySh->GoStartSentence();
1404 SpellContentPositions aDeletedRedlines = lcl_CollectDeletedRedlines(pMySh);
1405 if(bStartSent)
1406 {
1407 // create a portion from the start part
1408 AddPortion(nullptr, nullptr, aDeletedRedlines);
1409 }
1410 // Set the cursor to the error already found
1411 *pCursor->GetPoint() = *GetCurrX();
1412 *pCursor->GetMark() = *GetCurr();
1413 AddPortion(xSpellRet, &aGrammarResult, aDeletedRedlines);
1414
1415 // save the end position of the error to continue from here
1416 SwPosition aSaveStartPos = *pCursor->End();
1417 // determine the end of the current sentence
1418 if ( *pCursor->GetPoint() < *pCursor->GetMark() )
1419 pCursor->Exchange();
1420 // again collapse to start marking after the end of the error
1421 pCursor->DeleteMark();
1422 pCursor->SetMark();
1423
1424 pMySh->GoEndSentence();
1425 if( bGrammarErrorFound )
1426 {
1427 const ModelToViewHelper aConversionMap(static_cast<SwTextNode&>(pCursor->GetPointNode()), pMySh->GetLayout());
1428 const OUString& aExpandText = aConversionMap.getViewText();
1429 sal_Int32 nSentenceEnd =
1430 aConversionMap.ConvertToViewPosition( aGrammarResult.nBehindEndOfSentencePosition );
1431 // remove trailing space
1432 if( aExpandText[nSentenceEnd - 1] == ' ' )
1433 --nSentenceEnd;
1434 if( pCursor->End()->GetContentIndex() < nSentenceEnd )
1435 {
1436 pCursor->End()->SetContent(nSentenceEnd);
1437 }
1438 }
1439
1440 lcl_CutRedlines( aDeletedRedlines, pMySh );
1441 // save the 'global' end of the spellchecking
1442 const SwPosition aSaveEndPos = *GetEnd();
1443 // set the sentence end as 'local' end
1444 SetEnd( new SwPosition( *pCursor->End() ));
1445
1446 *pCursor->GetPoint() = aSaveStartPos;
1447 *pCursor->GetMark() = *GetEnd();
1448 // now the rest of the sentence has to be searched for errors
1449 // for each error the non-error text between the current and the last error has
1450 // to be added to the portions - if necessary broken into same-language-portions
1451 if( !bGrammarErrorFound ) //in grammar check there's only one error returned
1452 {
1453 do
1454 {
1455 xSpellRet = nullptr;
1456 // don't search for grammar errors here anymore!
1457 pMySh->GetDoc()->Spell(*pCursor, m_xSpeller, nullptr, nullptr, false,
1458 pMySh->GetLayout())
1459 >>= xSpellRet;
1460 if ( *pCursor->GetPoint() > *pCursor->GetMark() )
1461 pCursor->Exchange();
1462 SetCurr( new SwPosition( *pCursor->GetPoint() ));
1463 SetCurrX( new SwPosition( *pCursor->GetMark() ));
1464
1465 // if an error has been found go back to the text preceding the error
1466 if(xSpellRet.is())
1467 {
1468 *pCursor->GetPoint() = aSaveStartPos;
1469 *pCursor->GetMark() = *GetCurr();
1470 }
1471 // add the portion
1472 AddPortion(nullptr, nullptr, aDeletedRedlines);
1473
1474 if(xSpellRet.is())
1475 {
1476 *pCursor->GetPoint() = *GetCurr();
1477 *pCursor->GetMark() = *GetCurrX();
1478 AddPortion(xSpellRet, nullptr, aDeletedRedlines);
1479 // move the cursor to the end of the error string
1480 *pCursor->GetPoint() = *GetCurrX();
1481 // and save the end of the error as new start position
1482 aSaveStartPos = *GetCurrX();
1483 // and the end of the sentence
1484 *pCursor->GetMark() = *GetEnd();
1485 }
1486 // if the end of the sentence has already been reached then break here
1487 if(*GetCurrX() >= *GetEnd())
1488 break;
1489 }
1490 while(xSpellRet.is());
1491 }
1492 else
1493 {
1494 // go to the end of sentence as the grammar check returned it
1495 // at this time the Point is behind the grammar error
1496 // and the mark points to the sentence end as
1497 if ( *pCursor->GetPoint() < *pCursor->GetMark() )
1498 pCursor->Exchange();
1499 }
1500
1501 // the part between the last error and the end of the sentence has to be added
1502 *pMySh->GetCursor()->GetPoint() = *GetEnd();
1503 if(*GetCurrX() < *GetEnd())
1504 {
1505 AddPortion(nullptr, nullptr, aDeletedRedlines);
1506 }
1507 // set the shell cursor to the end of the sentence to prevent a visible selection
1508 *pCursor->GetMark() = *GetEnd();
1509 if( !bIsGrammarCheck )
1510 {
1511 // set the current position to the end of the sentence
1512 SetCurr( new SwPosition(*GetEnd()) );
1513 }
1514 // restore the 'global' end
1515 SetEnd( new SwPosition(aSaveEndPos) );
1516 rPortions = m_aLastPortions;
1517 bRet = true;
1518 }
1519 else
1520 {
1521 // if no error could be found the selection has to be corrected - at least if it's not in the body
1522 *pMySh->GetCursor()->GetPoint() = *GetEnd();
1523 pMySh->GetCursor()->DeleteMark();
1524 }
1525
1526 return bRet;
1527}
1528
1529void SwSpellIter::ToSentenceStart() { m_bBackToStartOfSentence = true; }
1530
1532{
1533 SvtScriptType nScriptType = rSh.GetScriptType();
1534 sal_uInt16 nLangWhichId = RES_CHRATR_LANGUAGE;
1535
1536 switch(nScriptType)
1537 {
1538 case SvtScriptType::ASIAN : nLangWhichId = RES_CHRATR_CJK_LANGUAGE; break;
1539 case SvtScriptType::COMPLEX : nLangWhichId = RES_CHRATR_CTL_LANGUAGE; break;
1540 default: break;
1541 }
1542 SfxItemSet aSet(rSh.GetAttrPool(), nLangWhichId, nLangWhichId);
1543 rSh.GetCurAttr( aSet );
1544 const SvxLanguageItem& rLang = static_cast<const SvxLanguageItem& >(aSet.Get(nLangWhichId));
1545 return rLang.GetLanguage();
1546}
1547
1549void SwSpellIter::CreatePortion(uno::Reference< XSpellAlternatives > const & xAlt,
1550 const linguistic2::ProofreadingResult* pGrammarResult,
1551 bool bIsField, bool bIsHidden)
1552{
1553 svx::SpellPortion aPortion;
1554 OUString sText;
1555 GetSh()->GetSelectedText( sText );
1556 if(sText.isEmpty())
1557 return;
1558
1559 // in case of redlined deletions the selection of an error is not the same as the _real_ word
1560 if(xAlt.is())
1561 aPortion.sText = xAlt->getWord();
1562 else if(pGrammarResult)
1563 {
1564 aPortion.bIsGrammarError = true;
1565 if(pGrammarResult->aErrors.hasElements())
1566 {
1567 aPortion.aGrammarError = pGrammarResult->aErrors[0];
1568 aPortion.sText = pGrammarResult->aText.copy( aPortion.aGrammarError.nErrorStart, aPortion.aGrammarError.nErrorLength );
1569 aPortion.xGrammarChecker = pGrammarResult->xProofreader;
1570 auto pProperty = std::find_if(std::cbegin(pGrammarResult->aProperties), std::cend(pGrammarResult->aProperties),
1571 [](const beans::PropertyValue& rProperty) { return rProperty.Name == "DialogTitle"; });
1572 if (pProperty != std::cend(pGrammarResult->aProperties))
1573 pProperty->Value >>= aPortion.sDialogTitle;
1574 }
1575 }
1576 else
1577 aPortion.sText = sText;
1578 aPortion.eLanguage = lcl_GetLanguage(*GetSh());
1579 aPortion.bIsField = bIsField;
1580 aPortion.bIsHidden = bIsHidden;
1581 aPortion.xAlternatives = xAlt;
1582 SpellContentPosition aPosition;
1583 SwPaM *pCursor = GetSh()->GetCursor();
1584 aPosition.nLeft = pCursor->Start()->GetContentIndex();
1585 aPosition.nRight = pCursor->End()->GetContentIndex();
1586 m_aLastPortions.push_back(aPortion);
1587 m_aLastPositions.push_back(aPosition);
1588}
1589
1590void SwSpellIter::AddPortion(uno::Reference< XSpellAlternatives > const & xAlt,
1591 const linguistic2::ProofreadingResult* pGrammarResult,
1592 const SpellContentPositions& rDeletedRedlines)
1593{
1594 SwEditShell *pMySh = GetSh();
1595 OUString sText;
1596 pMySh->GetSelectedText( sText );
1597 if(sText.isEmpty())
1598 return;
1599
1600 if(xAlt.is() || pGrammarResult != nullptr)
1601 {
1602 CreatePortion(xAlt, pGrammarResult, false, false);
1603 }
1604 else
1605 {
1606 SwPaM *pCursor = GetSh()->GetCursor();
1607 if ( *pCursor->GetPoint() > *pCursor->GetMark() )
1608 pCursor->Exchange();
1609 // save the start and end positions
1610 SwPosition aStart(*pCursor->GetPoint());
1611 SwPosition aEnd(*pCursor->GetMark());
1612 // iterate over the text to find changes in language
1613 // set the mark equal to the point
1614 *pCursor->GetMark() = aStart;
1615 SwTextNode* pTextNode = pCursor->GetPointNode().GetTextNode();
1616 LanguageType eStartLanguage = lcl_GetLanguage(*GetSh());
1617 SpellContentPosition aNextRedline = lcl_FindNextDeletedRedline(
1618 rDeletedRedlines, aStart.GetContentIndex() );
1619 if( aNextRedline.nLeft == aStart.GetContentIndex() )
1620 {
1621 // select until the end of the current redline
1622 const sal_Int32 nEnd = aEnd.GetContentIndex() < aNextRedline.nRight ?
1623 aEnd.GetContentIndex() : aNextRedline.nRight;
1624 pCursor->GetPoint()->SetContent( nEnd );
1625 CreatePortion(xAlt, pGrammarResult, false, true);
1626 aStart = *pCursor->End();
1627 // search for next redline
1628 aNextRedline = lcl_FindNextDeletedRedline(
1629 rDeletedRedlines, aStart.GetContentIndex() );
1630 }
1631 while(*pCursor->GetPoint() < aEnd)
1632 {
1633 // #125786 in table cell with fixed row height the cursor might not move forward
1634 if(!GetSh()->Right(1, SwCursorSkipMode::Cells))
1635 break;
1636
1637 bool bField = false;
1638 // read the character at the current position to check if it's a field
1639 sal_Unicode const cChar =
1640 pTextNode->GetText()[pCursor->GetMark()->GetContentIndex()];
1641 if( CH_TXTATR_BREAKWORD == cChar || CH_TXTATR_INWORD == cChar)
1642 {
1643 const SwTextAttr* pTextAttr = pTextNode->GetTextAttrForCharAt(
1644 pCursor->GetMark()->GetContentIndex() );
1645 const sal_uInt16 nWhich = pTextAttr
1646 ? pTextAttr->Which()
1648 switch (nWhich)
1649 {
1650 case RES_TXTATR_FIELD:
1652 case RES_TXTATR_FTN:
1653 case RES_TXTATR_FLYCNT:
1654 bField = true;
1655 break;
1656 }
1657 }
1658 else if (cChar == CH_TXT_ATR_FORMELEMENT)
1659 {
1660 SwPosition aPos(*pCursor->GetMark());
1661 bField = pMySh->GetDoc()->getIDocumentMarkAccess()->getDropDownFor(aPos);
1662 }
1663
1664 LanguageType eCurLanguage = lcl_GetLanguage(*GetSh());
1665 bool bRedline = aNextRedline.nLeft == pCursor->GetPoint()->GetContentIndex();
1666 // create a portion if the next character
1667 // - is a field,
1668 // - is at the beginning of a deleted redline
1669 // - has a different language
1670 if(bField || bRedline || eCurLanguage != eStartLanguage)
1671 {
1672 eStartLanguage = eCurLanguage;
1673 // go one step back - the cursor currently selects the first character
1674 // with a different language
1675 // in the case of redlining it's different
1676 if(eCurLanguage != eStartLanguage || bField)
1677 *pCursor->GetPoint() = *pCursor->GetMark();
1678 // set to the last start
1679 *pCursor->GetMark() = aStart;
1680 // create portion should only be called if a selection exists
1681 // there's no selection if there's a field at the beginning
1682 if(*pCursor->Start() != *pCursor->End())
1683 CreatePortion(xAlt, pGrammarResult, false, false);
1684 aStart = *pCursor->End();
1685 // now export the field - if there is any
1686 if(bField)
1687 {
1688 *pCursor->GetMark() = *pCursor->GetPoint();
1689 GetSh()->Right(1, SwCursorSkipMode::Cells);
1690 CreatePortion(xAlt, pGrammarResult, true, false);
1691 aStart = *pCursor->End();
1692 }
1693 }
1694 // if a redline start then create a portion for it
1695 if(bRedline)
1696 {
1697 *pCursor->GetMark() = *pCursor->GetPoint();
1698 // select until the end of the current redline
1699 const sal_Int32 nEnd = aEnd.GetContentIndex() < aNextRedline.nRight ?
1700 aEnd.GetContentIndex() : aNextRedline.nRight;
1701 pCursor->GetPoint()->SetContent( nEnd );
1702 CreatePortion(xAlt, pGrammarResult, false, true);
1703 aStart = *pCursor->End();
1704 // search for next redline
1705 aNextRedline = lcl_FindNextDeletedRedline(
1706 rDeletedRedlines, aStart.GetContentIndex() );
1707 }
1708 *pCursor->GetMark() = *pCursor->GetPoint();
1709 }
1710 pCursor->SetMark();
1711 *pCursor->GetMark() = aStart;
1712 CreatePortion(xAlt, pGrammarResult, false, false);
1713 }
1714}
1715
1717{
1718 SwTextNode *pNode;
1719 SwWrongList *pWrong;
1720 SwNodeIndex aIdx(rErrorPosition.Start()->GetNode());
1721 SwNodeIndex aEndIdx(rErrorPosition.Start()->GetNode());
1722 sal_Int32 nStart = rErrorPosition.Start()->GetContentIndex();
1723 sal_Int32 nEnd = COMPLETE_STRING;
1724 while( aIdx <= aEndIdx )
1725 {
1726 pNode = aIdx.GetNode().GetTextNode();
1727 if( pNode ) {
1728 if( aIdx == aEndIdx )
1729 nEnd = rErrorPosition.End()->GetContentIndex();
1730 pWrong = pNode->GetGrammarCheck();
1731 if( pWrong )
1732 pWrong->RemoveEntry( nStart, nEnd );
1733 pWrong = pNode->GetWrong();
1734 if( pWrong )
1735 pWrong->RemoveEntry( nStart, nEnd );
1737 }
1738 ++aIdx;
1739 nStart = 0;
1740 }
1741}
1742
1743/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual bool InsertString(const SwPaM &rRg, const OUString &, const SwInsertFlags nInsertMode=SwInsertFlags::EMPTYEXPAND)=0
Insert string into existing text node at position rRg.Point().
virtual ::sw::mark::IFieldmark * getDropDownFor(const SwPosition &pos) const =0
static bool IsShowChanges(const RedlineFlags eM)
virtual SwRedlineTable::size_type GetRedlinePos(const SwNode &rNode, RedlineType nType) const =0
virtual const SwRedlineTable & GetRedlineTable() const =0
virtual RedlineFlags GetRedlineFlags() const =0
Query the currently set redline mode.
const OUString & getViewText() const
sal_Int32 ConvertToViewPosition(sal_Int32 nModelPos) const
Converts a model position into a view position.
const SfxPoolItem & Get(sal_uInt16 nWhich, bool bSrchInParent=true) const
LanguageType GetLanguage() const
SwContentFrame is the layout for content nodes: a common base class for text (paragraph) and non-text...
Definition: cntfrm.hxx:59
SwContentFrame * getLayoutFrame(const SwRootFrame *, const SwPosition *pPos=nullptr, std::pair< Point, bool > const *pViewPosAndCalcFrame=nullptr) const
Definition: node.cxx:1223
bool Pop(PopMode, ::std::optional< SwCallLink > &roLink)
bool LeftMargin()
Definition: crsrsh.hxx:370
bool GoEndSentence()
Definition: crstrvl1.cxx:73
void Push()
store a copy of the current cursor on the cursor stack
Definition: crsrsh.cxx:2550
void StartAction()
Definition: crsrsh.cxx:226
const SwRect & GetCharRect() const
Definition: crsrsh.hxx:536
sal_uInt16 GetCursorCnt(bool bAll=true) const
Get the number of elements in the ring of cursors.
Definition: crsrsh.cxx:3055
bool HasSelection() const
Does the current cursor create a selection?
Definition: crsrsh.cxx:2838
bool RightMargin(bool bAPI=false)
Definition: crsrsh.hxx:371
SwCursor * GetCursor(bool bMakeTableCursor=true) const
Return pointer to the current shell cursor.
Definition: crsrsh.cxx:194
void TableCursorToCursor()
enter block mode, change normal cursor into block cursor
Definition: crsrsh.cxx:1182
bool ExtendSelection(bool bEnd=true, sal_Int32 nCount=1)
extend current SSelection by n characters
Definition: crsrsh.cxx:2944
SwMoveFnCollection const & MakeFindRange(SwDocPositions, SwDocPositions, SwPaM *) const
Definition: crsrsh.hxx:898
void EndAction(const bool bIdleEnd=false)
Definition: crsrsh.cxx:243
bool GoStartSentence()
Definition: crstrvl1.cxx:78
void ClearMark()
Definition: crsrsh.cxx:1225
void DestroyCursor()
transform TableCursor to normal cursor, nullify Tablemode
Definition: crsrsh.cxx:151
void KillPams()
Definition: crsrsh.cxx:1308
bool IsTableMode() const
Definition: crsrsh.hxx:668
void FillFindPos(SwDocPositions ePos, SwPosition &rPos) const
Definition: swcrsr.cxx:1102
Definition: doc.hxx:197
IDocumentContentOperations const & getIDocumentContentOperations() const
Definition: doc.cxx:329
IDocumentRedlineAccess const & getIDocumentRedlineAccess() const
Definition: doc.cxx:349
IDocumentMarkAccess * getIDocumentMarkAccess()
Definition: docbm.cxx:1890
css::uno::Reference< css::linguistic2::XHyphenatedWord > Hyphenate(SwPaM *pPam, const Point &rCursorPos, sal_uInt16 *pPageCnt, sal_uInt16 *pPageSt)
Definition: docedt.cxx:798
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:516
void SpellStart(SwDocPositions eStart, SwDocPositions eEnd, SwDocPositions eCurr, SwConversionArgs *pConvArgs=nullptr)
Functions used for spell checking and text conversion.
Definition: edlingu.cxx:633
static void PutSpellingToSentenceStart()
Make SpellIter start with the current sentence when called next time.
Definition: edlingu.cxx:1067
bool GetCurAttr(SfxItemSet &, const bool bMergeIndentValuesOfNumRule=false) const
Definition: edattr.cxx:171
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
void SetAttrItem(const SfxPoolItem &, SetAttrMode nFlags=SetAttrMode::DEFAULT, const bool bParagraphSetting=false)
Definition: edatmisc.cxx:98
void HandleCorrectionError(const OUString &aText, SwPosition aPos, sal_Int32 nBegin, sal_Int32 nLen, const Point *pPt, SwRect &rSelectRect)
Definition: edlingu.cxx:836
void SpellEnd(SwConversionArgs const *pConvArgs=nullptr, bool bRestoreSelection=true)
Restore selections.
Definition: edlingu.cxx:670
css::uno::Any SpellContinue(sal_uInt16 *pPageCnt, sal_uInt16 *pPageSt, SwConversionArgs const *pConvArgs)
Definition: edlingu.cxx:687
static bool HasConvIter()
Is text conversion active somewhere else?
Definition: edlingu.cxx:615
void ApplyChangedSentence(const svx::SpellPortions &rNewPortions, bool bRecheck)
Applies a changed sentence.
Definition: edlingu.cxx:1091
static void InsertSoftHyph(const sal_Int32 nHyphPos)
For Inserting SoftHyphen. Position is offset within the syllabificated word.
Definition: edlingu.cxx:817
SvtScriptType GetScriptType() const
returns the script type of the selection
Definition: edattr.cxx:662
bool SpellSentence(svx::SpellPortions &rToFill, bool bIsGrammarCheck)
Spells on a sentence basis - the SpellPortions are needed.
Definition: edlingu.cxx:1052
css::uno::Reference< css::linguistic2::XSpellAlternatives > GetCorrection(const Point *pPt, SwRect &rSelectRect)
Get a list of potential corrections for misspelled word.
Definition: edlingu.cxx:909
void HyphStart(SwDocPositions eStart, SwDocPositions eEnd)
Save selections.
Definition: edlingu.cxx:757
static void IgnoreGrammarErrorAt(SwPaM &rErrorPosition)
Definition: edlingu.cxx:1716
static void MoveContinuationPosToEndOfCheckedSentence()
Moves the continuation position to the end of the currently checked sentence.
Definition: edlingu.cxx:1081
css::uno::Reference< css::uno::XInterface > HyphContinue(sal_uInt16 *pPageCnt, sal_uInt16 *pPageSt)
Definition: edlingu.cxx:781
void HyphIgnore()
ignore hyphenation
Definition: edlingu.cxx:824
void GetSelectedText(OUString &rBuf, ParaBreakType nHndlParaBreak=ParaBreakType::ToBlank)
Query text within selection.
Definition: edglss.cxx:249
static bool HasLastSentenceGotGrammarChecked()
Check SwSpellIter data to see if the last sentence got grammar checked.
Definition: edlingu.cxx:597
void SetLinguRange(SwDocPositions eStart, SwDocPositions eEnd)
Definition: edlingu.cxx:625
void HyphEnd()
restore selections.
Definition: edlingu.cxx:768
static bool HasHyphIter()
Is hyphenation active somewhere else?
Definition: edlingu.cxx:620
virtual bool GetCharRect(SwRect &, const SwPosition &, SwCursorMoveState *=nullptr, bool bAllowFarAway=true) const
Definition: unusedf.cxx:72
sal_Int32 getSentenceEnd(sal_Int32 nPos)
sal_Int32 getSentenceStart(sal_Int32 nPos)
Marks a node in the document model.
Definition: ndindex.hxx:31
SwNode & GetNode() const
Definition: ndindex.hxx:123
Base class of the Writer document model elements.
Definition: node.hxx:98
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:901
SwNodeOffset GetIndex() const
Definition: node.hxx:312
bool IsInProtectSect() const
Is node in a protected area?
Definition: node.cxx:439
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:188
const SwPosition * GetMark() const
Definition: pam.hxx:255
SwNode & GetPointNode() const
Definition: pam.hxx:275
virtual void SetMark()
Unless this is called, the getter method of Mark will return Point.
Definition: pam.cxx:643
void Exchange()
Definition: pam.hxx:242
std::pair< const SwPosition *, const SwPosition * > StartEnd() const
Because sometimes the cost of the operator<= can add up.
Definition: pam.hxx:269
SwContentNode * GetPointContentNode() const
Definition: pam.hxx:279
const SwPosition * End() const
Definition: pam.hxx:263
SwPaM * GetNext()
Definition: pam.hxx:314
OUString GetText() const
Definition: pam.cxx:1305
void DeleteMark()
Definition: pam.hxx:232
const SwPosition * GetPoint() const
Definition: pam.hxx:253
const SwPosition * Start() const
Definition: pam.hxx:258
bool HasMark() const
A PaM marks a selection if Point and Mark are distinct positions.
Definition: pam.hxx:251
void CalcStartEnd(SwNodeOffset nNdIdx, sal_Int32 &rStart, sal_Int32 &rEnd) const
Calculates the intersection with text node number nNdIdx.
Definition: docredln.cxx:1470
RedlineType GetType(sal_uInt16 nPos=0) const
Definition: docredln.cxx:1975
Of course Writer needs its own rectangles.
Definition: swrect.hxx:35
SwRect & Union(const SwRect &rRect)
Definition: swrect.cxx:35
void Pos(const Point &rNew)
Definition: swrect.hxx:171
vector_type::size_type size_type
Definition: docary.hxx:223
sal_uInt16 GetPageNum() const
Definition: rootfrm.hxx:321
A wrapper around SfxPoolItem to store the start position of (usually) a text portion,...
Definition: txatbase.hxx:44
sal_uInt16 Which() const
Definition: txatbase.hxx:116
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:168
static void repaintTextFrames(const SwTextNode &rNode)
Repaint all text frames of the given text node.
Definition: txtfrm.cxx:4187
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:112
virtual sal_Int32 Len() const override
Definition: ndtxt.cxx:291
void DelSoftHyph(const sal_Int32 nStart, const sal_Int32 nEnd)
Definition: thints.cxx:1876
SwWrongList * GetWrong()
Definition: txtedt.cxx:2271
bool IsSymbolAt(sal_Int32 nBegin) const
in ndcopy.cxx
Definition: itratr.cxx:859
SwGrammarMarkUp * GetGrammarCheck()
Definition: txtedt.cxx:2297
const OUString & GetText() const
Definition: ndtxt.hxx:244
LanguageType GetLang(const sal_Int32 nBegin, const sal_Int32 nLen=0, sal_uInt16 nScript=0) const
Definition: thints.cxx:3474
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:3155
void SetIdle(bool b) const
Definition: viewopt.hxx:339
bool IsIdle() const
Definition: viewopt.hxx:332
const SwViewOption * GetViewOptions() const
Definition: viewsh.hxx:452
rtl::Reference< SwDoc > mxDoc
The document; never 0.
Definition: viewsh.hxx:199
SwRootFrame * GetLayout() const
Definition: viewsh.cxx:2163
sal_uInt16 mnStartAction
!= 0 if at least one Action is active.
Definition: viewsh.hxx:201
SwDoc * GetDoc() const
Definition: viewsh.hxx:308
const SfxItemPool & GetAttrPool() const
Definition: viewsh.hxx:648
void RemoveEntry(sal_Int32 nBegin, sal_Int32 nEnd)
Definition: wrong.cxx:586
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:103
@ SetOnlyText
stay with the cursor inside text
SwDocPositions
Definition: cshtyp.hxx:104
static void lcl_CutRedlines(SpellContentPositions &aDeletedRedlines, SwEditShell const *pSh)
remove the redline positions after the current selection
Definition: edlingu.cxx:1298
static SwConvIter * g_pConvIter
Definition: edlingu.cxx:195
static SwHyphIter * g_pHyphIter
Definition: edlingu.cxx:196
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:1258
static SpellContentPosition lcl_FindNextDeletedRedline(const SpellContentPositions &rDeletedRedlines, sal_Int32 nSearchFrom)
Definition: edlingu.cxx:1313
static sal_uInt32 lcl_CountRedlines(const svx::SpellPortions &rLastPortions)
Definition: edlingu.cxx:1075
std::vector< SpellContentPosition > SpellContentPositions
Definition: edlingu.cxx:111
static LanguageType lcl_GetLanguage(SwEditShell &rSh)
Definition: edlingu.cxx:1531
static SwSpellIter * g_pSpellIter
Definition: edlingu.cxx:194
#define CH_TXT_ATR_FORMELEMENT
Definition: hintids.hxx:181
constexpr TypedWhichId< SwFormatFootnote > RES_TXTATR_FTN(59)
constexpr TypedWhichId< SvxLanguageItem > RES_CHRATR_LANGUAGE(10)
constexpr TypedWhichId< SvxLanguageItem > RES_CHRATR_CTL_LANGUAGE(29)
constexpr TypedWhichId< SvxLanguageItem > RES_CHRATR_CJK_LANGUAGE(24)
constexpr TypedWhichId< SwFormatField > RES_TXTATR_ANNOTATION(60)
constexpr TypedWhichId< SwFormatField > RES_TXTATR_FIELD(RES_TXTATR_NOEND_BEGIN)
constexpr TypedWhichId< SwFormatFlyCnt > RES_TXTATR_FLYCNT(58)
#define CH_TXTATR_INWORD
Definition: hintids.hxx:175
constexpr sal_uInt16 RES_TXTATR_END(RES_TXTATR_NOEND_END)
#define CH_TXTATR_BREAKWORD
Definition: hintids.hxx:174
sal_Int64 n
SvtScriptType
constexpr OUStringLiteral UPN_MAX_NUMBER_OF_SUGGESTIONS
void StartProgress(TranslateId pMessResId, tools::Long nStartValue, tools::Long nEndValue, SwDocShell *pDocShell)
Definition: mainwn.cxx:52
ExpandMode
Some helpers for converting model strings to view strings.
@ ReplaceMode
do not expand to content, but replace with zwsp
@ HideFieldmarkCommands
sal_Int16 GetI18NScriptTypeOfLanguage(LanguageType nLang)
size
css::beans::PropertyValue makePropertyValue(const OUString &rName, T &&rValue)
css::uno::Reference< css::deployment::XPackageRegistry > create(css::uno::Reference< css::deployment::XPackageRegistry > const &xRootRegistry, OUString const &context, OUString const &cachePath, css::uno::Reference< css::uno::XComponentContext > const &xComponentContext)
int i
std::vector< SpellPortion > SpellPortions
Dialog to specify the properties of date form field.
SwTextFrame * SwHyphIterCacheLastTextFrame(SwTextNode const *pNode, const sw::Creator &create)
Definition: edlingu.cxx:584
std::function< SwTextFrame *()> Creator
Definition: splargs.hxx:144
SwContentNode * GetNode(SwPaM &rPam, bool &rbFirst, SwMoveFnCollection const &fnMove, bool const bInReadOnly, SwRootFrame const *const i_pLayout)
This function returns the next node in direction of search.
Definition: pam.cxx:1043
bool m_bRealWidth
Calculation of the width required.
Definition: crstate.hxx:149
Marks a position in the document model.
Definition: pam.hxx:38
SwNode & GetNode() const
Definition: pam.hxx:81
void SetContent(sal_Int32 nContentIndex)
Set content index, only valid to call this if the position points to a SwContentNode subclass.
Definition: pam.cxx:267
sal_Int32 GetContentIndex() const
Definition: pam.hxx:85
void AdjustContent(sal_Int32 nDelta)
Adjust content index, only valid to call this if the position points to a SwContentNode subclass.
Definition: pam.cxx:262
css::uno::Reference< css::linguistic2::XSpellAlternatives > xAlternatives
css::uno::Reference< css::linguistic2::XProofreader > xGrammarChecker
css::linguistic2::SingleProofreadingError aGrammarError
OUString sDialogTitle
LanguageType eLanguage
uno::Reference< linguistic2::XLinguProperties > GetLinguPropertySet()
Definition: swtypes.cxx:61
uno::Reference< linguistic2::XSpellChecker1 > GetSpellChecker()
Definition: swtypes.cxx:52
constexpr sal_Int32 COMPLETE_STRING
Definition: swtypes.hxx:57
@ UI_TEXT_CORRECTION
#define Start_(_nam)
#define End_(_nam)
Right
#define SAL_MAX_INT32
sal_uInt16 sal_Unicode
const char * pChar