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()->nContent = pCursor->End()->nContent;
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->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
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.nContent = 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 SwContentIndex& rContent = GetCursor()->GetPoint()->nContent;
879 rContent = 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 rContent = 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()->nContent = aCurrentOldPosition->nLeft;
1153 pCursor->GetMark()->nContent = aCurrentOldPosition->nRight;
1154 sal_uInt16 nScriptType = SvtLanguageOptions::GetI18NScriptTypeOfLanguage( aCurrentNewPortion->eLanguage );
1155 sal_uInt16 nLangWhichId = RES_CHRATR_LANGUAGE;
1156 switch(nScriptType)
1157 {
1158 case css::i18n::ScriptType::ASIAN : nLangWhichId = RES_CHRATR_CJK_LANGUAGE; break;
1159 case css::i18n::ScriptType::COMPLEX : nLangWhichId = RES_CHRATR_CTL_LANGUAGE; break;
1160 }
1161 if(aCurrentNewPortion->sText != aCurrentOldPortion->sText)
1162 {
1163 // change text ...
1164 // ... and apply language if necessary
1165 if(aCurrentNewPortion->eLanguage != aCurrentOldPortion->eLanguage)
1166 SetAttrItem( SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId) );
1167 mxDoc->getIDocumentContentOperations().ReplaceRange(*pCursor, aCurrentNewPortion->sText, false);
1168 }
1169 else if(aCurrentNewPortion->eLanguage != aCurrentOldPortion->eLanguage)
1170 {
1171 // apply language
1172 SetAttrItem( SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId) );
1173 }
1174 else if( aCurrentNewPortion->bIgnoreThisError )
1175 {
1176 // add the 'ignore' markup to the TextNode's grammar ignore markup list
1177 IgnoreGrammarErrorAt( *pCursor );
1178 OSL_FAIL("TODO: add ignore mark to text node");
1179 }
1180 }
1181 while(aCurrentNewPortion != rNewPortions.begin());
1182 }
1183 else
1184 {
1185 OSL_ENSURE( !rLastPositions.empty(), "rLastPositions should not be empty here" );
1186
1187 // select the complete sentence
1188 SpellContentPositions::const_iterator aCurrentEndPosition = rLastPositions.end();
1189 --aCurrentEndPosition;
1190 SpellContentPositions::const_iterator aCurrentStartPosition = rLastPositions.begin();
1191 pCursor->GetPoint()->nContent = aCurrentStartPosition->nLeft;
1192 pCursor->GetMark()->nContent = aCurrentEndPosition->nRight;
1193
1194 // delete the sentence completely
1195 mxDoc->getIDocumentContentOperations().DeleteAndJoin(*pCursor);
1196 for(const auto& rCurrentNewPortion : rNewPortions)
1197 {
1198 // set the language attribute
1199 SvtScriptType nScriptType = GetScriptType();
1200 sal_uInt16 nLangWhichId = RES_CHRATR_LANGUAGE;
1201 switch(nScriptType)
1202 {
1203 case SvtScriptType::ASIAN : nLangWhichId = RES_CHRATR_CJK_LANGUAGE; break;
1204 case SvtScriptType::COMPLEX : nLangWhichId = RES_CHRATR_CTL_LANGUAGE; break;
1205 default: break;
1206 }
1207 SfxItemSet aSet(GetAttrPool(), nLangWhichId, nLangWhichId);
1208 GetCurAttr( aSet );
1209 const SvxLanguageItem& rLang = static_cast<const SvxLanguageItem& >(aSet.Get(nLangWhichId));
1210 if(rLang.GetLanguage() != rCurrentNewPortion.eLanguage)
1211 SetAttrItem( SvxLanguageItem(rCurrentNewPortion.eLanguage, nLangWhichId) );
1212 // insert the new string
1213 mxDoc->getIDocumentContentOperations().InsertString(*pCursor, rCurrentNewPortion.sText);
1214
1215 // set the cursor to the end of the inserted string
1216 *pCursor->Start() = *pCursor->End();
1217 }
1218 }
1219
1220 // restore cursor to the end of the sentence
1221 // (will work also if the sentence length has changed,
1222 // since cursors get updated automatically!)
1224
1225 // collapse cursor to the end of the modified sentence
1226 *pCursor->Start() = *pCursor->End();
1227 if (bRecheck)
1228 {
1229 // in grammar check the current sentence has to be checked again
1231 }
1232 // set continuation position for spell/grammar checking to the end of this sentence
1233 g_pSpellIter->SetCurr( new SwPosition(*pCursor->Start()) );
1234
1235 mxDoc->GetIDocumentUndoRedo().EndUndo( SwUndoId::UI_TEXT_CORRECTION, nullptr );
1236 EndAction();
1237
1238}
1243{
1244 SpellContentPositions aRedlines;
1245 SwDoc* pDoc = pSh->GetDoc();
1247 if ( bShowChg )
1248 {
1249 SwPaM *pCursor = pSh->GetCursor();
1250 const SwPosition* pStartPos = pCursor->Start();
1251 const SwTextNode* pTextNode = pCursor->GetPointNode().GetTextNode();
1252
1253 SwRedlineTable::size_type nAct = pDoc->getIDocumentRedlineAccess().GetRedlinePos( *pTextNode, RedlineType::Any );
1254 const sal_Int32 nStartIndex = pStartPos->GetContentIndex();
1255 for ( ; nAct < pDoc->getIDocumentRedlineAccess().GetRedlineTable().size(); nAct++ )
1256 {
1257 const SwRangeRedline* pRed = pDoc->getIDocumentRedlineAccess().GetRedlineTable()[ nAct ];
1258
1259 if ( pRed->Start()->GetNode() > *pTextNode )
1260 break;
1261
1262 if( RedlineType::Delete == pRed->GetType() )
1263 {
1264 sal_Int32 nStart_, nEnd_;
1265 pRed->CalcStartEnd( pTextNode->GetIndex(), nStart_, nEnd_ );
1266 sal_Int32 nStart = nStart_;
1267 sal_Int32 nEnd = nEnd_;
1268 if(nStart >= nStartIndex || nEnd >= nStartIndex)
1269 {
1270 SpellContentPosition aAdd;
1271 aAdd.nLeft = nStart;
1272 aAdd.nRight = nEnd;
1273 aRedlines.push_back(aAdd);
1274 }
1275 }
1276 }
1277 }
1278 return aRedlines;
1279}
1280
1282static void lcl_CutRedlines( SpellContentPositions& aDeletedRedlines, SwEditShell const * pSh )
1283{
1284 if(!aDeletedRedlines.empty())
1285 {
1286 SwPaM *pCursor = pSh->GetCursor();
1287 const SwPosition* pEndPos = pCursor->End();
1288 const sal_Int32 nEnd = pEndPos->GetContentIndex();
1289 while(!aDeletedRedlines.empty() &&
1290 aDeletedRedlines.back().nLeft > nEnd)
1291 {
1292 aDeletedRedlines.pop_back();
1293 }
1294 }
1295}
1296
1297static SpellContentPosition lcl_FindNextDeletedRedline(
1298 const SpellContentPositions& rDeletedRedlines,
1299 sal_Int32 nSearchFrom )
1300{
1301 SpellContentPosition aRet;
1302 aRet.nLeft = aRet.nRight = SAL_MAX_INT32;
1303 if(!rDeletedRedlines.empty())
1304 {
1305 auto aIter = std::find_if_not(rDeletedRedlines.begin(), rDeletedRedlines.end(),
1306 [nSearchFrom](const SpellContentPosition& rPos) { return rPos.nLeft < nSearchFrom; });
1307 if (aIter != rDeletedRedlines.end())
1308 aRet = *aIter;
1309 }
1310 return aRet;
1311}
1312
1313bool SwSpellIter::SpellSentence(svx::SpellPortions& rPortions, bool bIsGrammarCheck)
1314{
1315 bool bRet = false;
1316 m_aLastPortions.clear();
1317 m_aLastPositions.clear();
1318
1319 SwEditShell *pMySh = GetSh();
1320 if( !pMySh )
1321 return false;
1322
1323 OSL_ENSURE( GetEnd(), "SwSpellIter::SpellSentence without Start?");
1324
1325 uno::Reference< XSpellAlternatives > xSpellRet;
1326 linguistic2::ProofreadingResult aGrammarResult;
1327 bool bGoOn = true;
1328 bool bGrammarErrorFound = false;
1329 do {
1330 SwPaM *pCursor = pMySh->GetCursor();
1331 if ( !pCursor->HasMark() )
1332 pCursor->SetMark();
1333
1334 *pCursor->GetPoint() = *GetCurr();
1335 *pCursor->GetMark() = *GetEnd();
1336
1337 if (m_bBackToStartOfSentence)
1338 {
1339 pMySh->GoStartSentence();
1340 m_bBackToStartOfSentence = false;
1341 }
1342 uno::Any aSpellRet = pMySh->GetDoc()->Spell(*pCursor, m_xSpeller, nullptr, nullptr,
1343 bIsGrammarCheck, pMySh->GetLayout());
1344 aSpellRet >>= xSpellRet;
1345 aSpellRet >>= aGrammarResult;
1346 bGoOn = GetCursorCnt() > 1;
1347 bGrammarErrorFound = aGrammarResult.aErrors.hasElements();
1348 if( xSpellRet.is() || bGrammarErrorFound )
1349 {
1350 bGoOn = false;
1351 SwPosition* pNewPoint = new SwPosition( *pCursor->GetPoint() );
1352 SwPosition* pNewMark = new SwPosition( *pCursor->GetMark() );
1353
1354 SetCurr( pNewPoint );
1355 SetCurrX( pNewMark );
1356 }
1357 if( bGoOn )
1358 {
1360 pCursor = pMySh->GetCursor();
1361 if ( *pCursor->GetPoint() > *pCursor->GetMark() )
1362 pCursor->Exchange();
1363 SwPosition* pNew = new SwPosition( *pCursor->GetPoint() );
1364 SetStart( pNew );
1365 pNew = new SwPosition( *pCursor->GetMark() );
1366 SetEnd( pNew );
1367 pNew = new SwPosition( *GetStart() );
1368 SetCurr( pNew );
1369 pNew = new SwPosition( *pNew );
1370 SetCurrX( pNew );
1371 pCursor->SetMark();
1372 --GetCursorCnt();
1373 }
1374 } while ( bGoOn );
1375
1376 if(xSpellRet.is() || bGrammarErrorFound)
1377 {
1378 // an error has been found
1379 // To fill the spell portions the beginning of the sentence has to be found
1380 SwPaM *pCursor = pMySh->GetCursor();
1381 // set the mark to the right if necessary
1382 if ( *pCursor->GetPoint() > *pCursor->GetMark() )
1383 pCursor->Exchange();
1384 // the cursor has to be collapsed on the left to go to the start of the sentence - if sentence ends inside of the error
1385 pCursor->DeleteMark();
1386 pCursor->SetMark();
1387 bool bStartSent = pMySh->GoStartSentence();
1388 SpellContentPositions aDeletedRedlines = lcl_CollectDeletedRedlines(pMySh);
1389 if(bStartSent)
1390 {
1391 // create a portion from the start part
1392 AddPortion(nullptr, nullptr, aDeletedRedlines);
1393 }
1394 // Set the cursor to the error already found
1395 *pCursor->GetPoint() = *GetCurrX();
1396 *pCursor->GetMark() = *GetCurr();
1397 AddPortion(xSpellRet, &aGrammarResult, aDeletedRedlines);
1398
1399 // save the end position of the error to continue from here
1400 SwPosition aSaveStartPos = *pCursor->End();
1401 // determine the end of the current sentence
1402 if ( *pCursor->GetPoint() < *pCursor->GetMark() )
1403 pCursor->Exchange();
1404 // again collapse to start marking after the end of the error
1405 pCursor->DeleteMark();
1406 pCursor->SetMark();
1407
1408 pMySh->GoEndSentence();
1409 if( bGrammarErrorFound )
1410 {
1411 const ModelToViewHelper aConversionMap(static_cast<SwTextNode&>(pCursor->GetPointNode()), pMySh->GetLayout());
1412 const OUString& aExpandText = aConversionMap.getViewText();
1413 sal_Int32 nSentenceEnd =
1414 aConversionMap.ConvertToViewPosition( aGrammarResult.nBehindEndOfSentencePosition );
1415 // remove trailing space
1416 if( aExpandText[nSentenceEnd - 1] == ' ' )
1417 --nSentenceEnd;
1418 if( pCursor->End()->GetContentIndex() < nSentenceEnd )
1419 {
1420 pCursor->End()->nContent.Assign(
1421 pCursor->End()->GetNode().GetContentNode(), nSentenceEnd);
1422 }
1423 }
1424
1425 lcl_CutRedlines( aDeletedRedlines, pMySh );
1426 // save the 'global' end of the spellchecking
1427 const SwPosition aSaveEndPos = *GetEnd();
1428 // set the sentence end as 'local' end
1429 SetEnd( new SwPosition( *pCursor->End() ));
1430
1431 *pCursor->GetPoint() = aSaveStartPos;
1432 *pCursor->GetMark() = *GetEnd();
1433 // now the rest of the sentence has to be searched for errors
1434 // for each error the non-error text between the current and the last error has
1435 // to be added to the portions - if necessary broken into same-language-portions
1436 if( !bGrammarErrorFound ) //in grammar check there's only one error returned
1437 {
1438 do
1439 {
1440 xSpellRet = nullptr;
1441 // don't search for grammar errors here anymore!
1442 pMySh->GetDoc()->Spell(*pCursor, m_xSpeller, nullptr, nullptr, false,
1443 pMySh->GetLayout())
1444 >>= xSpellRet;
1445 if ( *pCursor->GetPoint() > *pCursor->GetMark() )
1446 pCursor->Exchange();
1447 SetCurr( new SwPosition( *pCursor->GetPoint() ));
1448 SetCurrX( new SwPosition( *pCursor->GetMark() ));
1449
1450 // if an error has been found go back to the text preceding the error
1451 if(xSpellRet.is())
1452 {
1453 *pCursor->GetPoint() = aSaveStartPos;
1454 *pCursor->GetMark() = *GetCurr();
1455 }
1456 // add the portion
1457 AddPortion(nullptr, nullptr, aDeletedRedlines);
1458
1459 if(xSpellRet.is())
1460 {
1461 *pCursor->GetPoint() = *GetCurr();
1462 *pCursor->GetMark() = *GetCurrX();
1463 AddPortion(xSpellRet, nullptr, aDeletedRedlines);
1464 // move the cursor to the end of the error string
1465 *pCursor->GetPoint() = *GetCurrX();
1466 // and save the end of the error as new start position
1467 aSaveStartPos = *GetCurrX();
1468 // and the end of the sentence
1469 *pCursor->GetMark() = *GetEnd();
1470 }
1471 // if the end of the sentence has already been reached then break here
1472 if(*GetCurrX() >= *GetEnd())
1473 break;
1474 }
1475 while(xSpellRet.is());
1476 }
1477 else
1478 {
1479 // go to the end of sentence as the grammar check returned it
1480 // at this time the Point is behind the grammar error
1481 // and the mark points to the sentence end as
1482 if ( *pCursor->GetPoint() < *pCursor->GetMark() )
1483 pCursor->Exchange();
1484 }
1485
1486 // the part between the last error and the end of the sentence has to be added
1487 *pMySh->GetCursor()->GetPoint() = *GetEnd();
1488 if(*GetCurrX() < *GetEnd())
1489 {
1490 AddPortion(nullptr, nullptr, aDeletedRedlines);
1491 }
1492 // set the shell cursor to the end of the sentence to prevent a visible selection
1493 *pCursor->GetMark() = *GetEnd();
1494 if( !bIsGrammarCheck )
1495 {
1496 // set the current position to the end of the sentence
1497 SetCurr( new SwPosition(*GetEnd()) );
1498 }
1499 // restore the 'global' end
1500 SetEnd( new SwPosition(aSaveEndPos) );
1501 rPortions = m_aLastPortions;
1502 bRet = true;
1503 }
1504 else
1505 {
1506 // if no error could be found the selection has to be corrected - at least if it's not in the body
1507 *pMySh->GetCursor()->GetPoint() = *GetEnd();
1508 pMySh->GetCursor()->DeleteMark();
1509 }
1510
1511 return bRet;
1512}
1513
1514void SwSpellIter::ToSentenceStart() { m_bBackToStartOfSentence = true; }
1515
1517{
1518 SvtScriptType nScriptType = rSh.GetScriptType();
1519 sal_uInt16 nLangWhichId = RES_CHRATR_LANGUAGE;
1520
1521 switch(nScriptType)
1522 {
1523 case SvtScriptType::ASIAN : nLangWhichId = RES_CHRATR_CJK_LANGUAGE; break;
1524 case SvtScriptType::COMPLEX : nLangWhichId = RES_CHRATR_CTL_LANGUAGE; break;
1525 default: break;
1526 }
1527 SfxItemSet aSet(rSh.GetAttrPool(), nLangWhichId, nLangWhichId);
1528 rSh.GetCurAttr( aSet );
1529 const SvxLanguageItem& rLang = static_cast<const SvxLanguageItem& >(aSet.Get(nLangWhichId));
1530 return rLang.GetLanguage();
1531}
1532
1534void SwSpellIter::CreatePortion(uno::Reference< XSpellAlternatives > const & xAlt,
1535 const linguistic2::ProofreadingResult* pGrammarResult,
1536 bool bIsField, bool bIsHidden)
1537{
1538 svx::SpellPortion aPortion;
1539 OUString sText;
1540 GetSh()->GetSelectedText( sText );
1541 if(sText.isEmpty())
1542 return;
1543
1544 // in case of redlined deletions the selection of an error is not the same as the _real_ word
1545 if(xAlt.is())
1546 aPortion.sText = xAlt->getWord();
1547 else if(pGrammarResult)
1548 {
1549 aPortion.bIsGrammarError = true;
1550 if(pGrammarResult->aErrors.hasElements())
1551 {
1552 aPortion.aGrammarError = pGrammarResult->aErrors[0];
1553 aPortion.sText = pGrammarResult->aText.copy( aPortion.aGrammarError.nErrorStart, aPortion.aGrammarError.nErrorLength );
1554 aPortion.xGrammarChecker = pGrammarResult->xProofreader;
1555 auto pProperty = std::find_if(std::cbegin(pGrammarResult->aProperties), std::cend(pGrammarResult->aProperties),
1556 [](const beans::PropertyValue& rProperty) { return rProperty.Name == "DialogTitle"; });
1557 if (pProperty != std::cend(pGrammarResult->aProperties))
1558 pProperty->Value >>= aPortion.sDialogTitle;
1559 }
1560 }
1561 else
1562 aPortion.sText = sText;
1563 aPortion.eLanguage = lcl_GetLanguage(*GetSh());
1564 aPortion.bIsField = bIsField;
1565 aPortion.bIsHidden = bIsHidden;
1566 aPortion.xAlternatives = xAlt;
1567 SpellContentPosition aPosition;
1568 SwPaM *pCursor = GetSh()->GetCursor();
1569 aPosition.nLeft = pCursor->Start()->GetContentIndex();
1570 aPosition.nRight = pCursor->End()->GetContentIndex();
1571 m_aLastPortions.push_back(aPortion);
1572 m_aLastPositions.push_back(aPosition);
1573}
1574
1575void SwSpellIter::AddPortion(uno::Reference< XSpellAlternatives > const & xAlt,
1576 const linguistic2::ProofreadingResult* pGrammarResult,
1577 const SpellContentPositions& rDeletedRedlines)
1578{
1579 SwEditShell *pMySh = GetSh();
1580 OUString sText;
1581 pMySh->GetSelectedText( sText );
1582 if(sText.isEmpty())
1583 return;
1584
1585 if(xAlt.is() || pGrammarResult != nullptr)
1586 {
1587 CreatePortion(xAlt, pGrammarResult, false, false);
1588 }
1589 else
1590 {
1591 SwPaM *pCursor = GetSh()->GetCursor();
1592 if ( *pCursor->GetPoint() > *pCursor->GetMark() )
1593 pCursor->Exchange();
1594 // save the start and end positions
1595 SwPosition aStart(*pCursor->GetPoint());
1596 SwPosition aEnd(*pCursor->GetMark());
1597 // iterate over the text to find changes in language
1598 // set the mark equal to the point
1599 *pCursor->GetMark() = aStart;
1600 SwTextNode* pTextNode = pCursor->GetPointNode().GetTextNode();
1601 LanguageType eStartLanguage = lcl_GetLanguage(*GetSh());
1602 SpellContentPosition aNextRedline = lcl_FindNextDeletedRedline(
1603 rDeletedRedlines, aStart.GetContentIndex() );
1604 if( aNextRedline.nLeft == aStart.GetContentIndex() )
1605 {
1606 // select until the end of the current redline
1607 const sal_Int32 nEnd = aEnd.GetContentIndex() < aNextRedline.nRight ?
1608 aEnd.GetContentIndex() : aNextRedline.nRight;
1609 pCursor->GetPoint()->nContent.Assign( pTextNode, nEnd );
1610 CreatePortion(xAlt, pGrammarResult, false, true);
1611 aStart = *pCursor->End();
1612 // search for next redline
1613 aNextRedline = lcl_FindNextDeletedRedline(
1614 rDeletedRedlines, aStart.GetContentIndex() );
1615 }
1616 while(*pCursor->GetPoint() < aEnd)
1617 {
1618 // #125786 in table cell with fixed row height the cursor might not move forward
1619 if(!GetSh()->Right(1, SwCursorSkipMode::Cells))
1620 break;
1621
1622 bool bField = false;
1623 // read the character at the current position to check if it's a field
1624 sal_Unicode const cChar =
1625 pTextNode->GetText()[pCursor->GetMark()->GetContentIndex()];
1626 if( CH_TXTATR_BREAKWORD == cChar || CH_TXTATR_INWORD == cChar)
1627 {
1628 const SwTextAttr* pTextAttr = pTextNode->GetTextAttrForCharAt(
1629 pCursor->GetMark()->GetContentIndex() );
1630 const sal_uInt16 nWhich = pTextAttr
1631 ? pTextAttr->Which()
1633 switch (nWhich)
1634 {
1635 case RES_TXTATR_FIELD:
1637 case RES_TXTATR_FTN:
1638 case RES_TXTATR_FLYCNT:
1639 bField = true;
1640 break;
1641 }
1642 }
1643 else if (cChar == CH_TXT_ATR_FORMELEMENT)
1644 {
1645 SwPosition aPos(*pCursor->GetMark());
1646 bField = pMySh->GetDoc()->getIDocumentMarkAccess()->getDropDownFor(aPos);
1647 }
1648
1649 LanguageType eCurLanguage = lcl_GetLanguage(*GetSh());
1650 bool bRedline = aNextRedline.nLeft == pCursor->GetPoint()->GetContentIndex();
1651 // create a portion if the next character
1652 // - is a field,
1653 // - is at the beginning of a deleted redline
1654 // - has a different language
1655 if(bField || bRedline || eCurLanguage != eStartLanguage)
1656 {
1657 eStartLanguage = eCurLanguage;
1658 // go one step back - the cursor currently selects the first character
1659 // with a different language
1660 // in the case of redlining it's different
1661 if(eCurLanguage != eStartLanguage || bField)
1662 *pCursor->GetPoint() = *pCursor->GetMark();
1663 // set to the last start
1664 *pCursor->GetMark() = aStart;
1665 // create portion should only be called if a selection exists
1666 // there's no selection if there's a field at the beginning
1667 if(*pCursor->Start() != *pCursor->End())
1668 CreatePortion(xAlt, pGrammarResult, false, false);
1669 aStart = *pCursor->End();
1670 // now export the field - if there is any
1671 if(bField)
1672 {
1673 *pCursor->GetMark() = *pCursor->GetPoint();
1674 GetSh()->Right(1, SwCursorSkipMode::Cells);
1675 CreatePortion(xAlt, pGrammarResult, true, false);
1676 aStart = *pCursor->End();
1677 }
1678 }
1679 // if a redline start then create a portion for it
1680 if(bRedline)
1681 {
1682 *pCursor->GetMark() = *pCursor->GetPoint();
1683 // select until the end of the current redline
1684 const sal_Int32 nEnd = aEnd.GetContentIndex() < aNextRedline.nRight ?
1685 aEnd.GetContentIndex() : aNextRedline.nRight;
1686 pCursor->GetPoint()->nContent.Assign( pTextNode, nEnd );
1687 CreatePortion(xAlt, pGrammarResult, false, true);
1688 aStart = *pCursor->End();
1689 // search for next redline
1690 aNextRedline = lcl_FindNextDeletedRedline(
1691 rDeletedRedlines, aStart.GetContentIndex() );
1692 }
1693 *pCursor->GetMark() = *pCursor->GetPoint();
1694 }
1695 pCursor->SetMark();
1696 *pCursor->GetMark() = aStart;
1697 CreatePortion(xAlt, pGrammarResult, false, false);
1698 }
1699}
1700
1702{
1703 SwTextNode *pNode;
1704 SwWrongList *pWrong;
1705 SwNodeIndex aIdx(rErrorPosition.Start()->GetNode());
1706 SwNodeIndex aEndIdx(rErrorPosition.Start()->GetNode());
1707 sal_Int32 nStart = rErrorPosition.Start()->GetContentIndex();
1708 sal_Int32 nEnd = COMPLETE_STRING;
1709 while( aIdx <= aEndIdx )
1710 {
1711 pNode = aIdx.GetNode().GetTextNode();
1712 if( pNode ) {
1713 if( aIdx == aEndIdx )
1714 nEnd = rErrorPosition.End()->GetContentIndex();
1715 pWrong = pNode->GetGrammarCheck();
1716 if( pWrong )
1717 pWrong->RemoveEntry( nStart, nEnd );
1718 pWrong = pNode->GetWrong();
1719 if( pWrong )
1720 pWrong->RemoveEntry( nStart, nEnd );
1722 }
1723 ++aIdx;
1724 nStart = 0;
1725 }
1726}
1727
1728/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
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:58
Marks a character position inside a document model content node (SwContentNode)
SwContentIndex & Assign(const SwContentNode *, sal_Int32)
Definition: index.cxx:206
SwContentFrame * getLayoutFrame(const SwRootFrame *, const SwPosition *pPos=nullptr, std::pair< Point, bool > const *pViewPosAndCalcFrame=nullptr) const
Definition: node.cxx:1224
bool Pop(PopMode, ::std::optional< SwCallLink > &roLink)
bool LeftMargin()
Definition: crsrsh.hxx:363
bool GoEndSentence()
Definition: crstrvl1.cxx:73
void Push()
store a copy of the current cursor on the cursor stack
Definition: crsrsh.cxx:2246
void StartAction()
Definition: crsrsh.cxx:225
const SwRect & GetCharRect() const
Definition: crsrsh.hxx:525
sal_uInt16 GetCursorCnt(bool bAll=true) const
Get the number of elements in the ring of cursors.
Definition: crsrsh.cxx:2752
bool HasSelection() const
Does the current cursor create a selection?
Definition: crsrsh.cxx:2535
bool RightMargin(bool bAPI=false)
Definition: crsrsh.hxx:364
SwCursor * GetCursor(bool bMakeTableCursor=true) const
Return pointer to the current shell cursor.
Definition: crsrsh.cxx:193
void TableCursorToCursor()
enter block mode, change normal cursor into block cursor
Definition: crsrsh.cxx:895
bool ExtendSelection(bool bEnd=true, sal_Int32 nCount=1)
extend current SSelection by n characters
Definition: crsrsh.cxx:2641
SwMoveFnCollection const & MakeFindRange(SwDocPositions, SwDocPositions, SwPaM *) const
Definition: crsrsh.hxx:880
void EndAction(const bool bIdleEnd=false)
Definition: crsrsh.cxx:242
bool GoStartSentence()
Definition: crstrvl1.cxx:78
void ClearMark()
Definition: crsrsh.cxx:938
void DestroyCursor()
transform TableCursor to normal cursor, nullify Tablemode
Definition: crsrsh.cxx:150
void KillPams()
Definition: crsrsh.cxx:1021
bool IsTableMode() const
Definition: crsrsh.hxx:652
void FillFindPos(SwDocPositions ePos, SwPosition &rPos) const
Definition: swcrsr.cxx:1097
Definition: doc.hxx:192
IDocumentContentOperations const & getIDocumentContentOperations() const
Definition: doc.cxx:316
IDocumentRedlineAccess const & getIDocumentRedlineAccess() const
Definition: doc.cxx:336
IDocumentMarkAccess * getIDocumentMarkAccess()
Definition: docbm.cxx:1793
css::uno::Reference< css::linguistic2::XHyphenatedWord > Hyphenate(SwPaM *pPam, const Point &rCursorPos, sal_uInt16 *pPageCnt, sal_uInt16 *pPageSt)
Definition: docedt.cxx:795
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:1701
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:260
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:136
Base class of the Writer document model elements.
Definition: node.hxx:84
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:876
SwNodeOffset GetIndex() const
Definition: node.hxx:296
bool IsInProtectSect() const
Is node in a protected area?
Definition: node.cxx:429
SwContentNode * GetContentNode()
Definition: node.hxx:643
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:187
const SwPosition * GetMark() const
Definition: pam.hxx:263
SwNode & GetPointNode() const
Definition: pam.hxx:283
virtual void SetMark()
Unless this is called, the getter method of Mark will return Point.
Definition: pam.cxx:612
void Exchange()
Definition: pam.cxx:626
std::pair< const SwPosition *, const SwPosition * > StartEnd() const
Because sometimes the cost of the operator<= can add up.
Definition: pam.hxx:277
SwContentNode * GetPointContentNode() const
Definition: pam.hxx:287
const SwPosition * End() const
Definition: pam.hxx:271
SwPaM * GetNext()
Definition: pam.hxx:320
void DeleteMark()
Definition: pam.hxx:231
const SwPosition * GetPoint() const
Definition: pam.hxx:261
const SwPosition * Start() const
Definition: pam.hxx:266
bool HasMark() const
A PaM marks a selection if Point and Mark are distinct positions.
Definition: pam.hxx:259
void CalcStartEnd(SwNodeOffset nNdIdx, sal_Int32 &rStart, sal_Int32 &rEnd) const
Calculates the intersection with text node number nNdIdx.
Definition: docredln.cxx:1428
RedlineType GetType(sal_uInt16 nPos=0) const
Definition: docredln.cxx:1934
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:222
sal_uInt16 GetPageNum() const
Definition: rootfrm.hxx:312
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:165
static void repaintTextFrames(const SwTextNode &rNode)
Repaint all text frames of the given text node.
Definition: txtfrm.cxx:4048
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:86
virtual sal_Int32 Len() const override
Definition: ndtxt.cxx:275
void DelSoftHyph(const sal_Int32 nStart, const sal_Int32 nEnd)
Definition: thints.cxx:1877
SwWrongList * GetWrong()
Definition: txtedt.cxx:2226
bool IsSymbolAt(sal_Int32 nBegin) const
in ndcopy.cxx
Definition: itratr.cxx:856
SwGrammarMarkUp * GetGrammarCheck()
Definition: txtedt.cxx:2254
const OUString & GetText() const
Definition: ndtxt.hxx:222
LanguageType GetLang(const sal_Int32 nBegin, const sal_Int32 nLen=0, sal_uInt16 nScript=0) const
Definition: thints.cxx:3464
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:3105
void SetIdle(bool b) const
Definition: viewopt.hxx:216
bool IsIdle() const
Definition: viewopt.hxx:209
const SwViewOption * GetViewOptions() const
Definition: viewsh.hxx:436
rtl::Reference< SwDoc > mxDoc
The document; never 0.
Definition: viewsh.hxx:179
SwRootFrame * GetLayout() const
Definition: viewsh.cxx:2172
sal_uInt16 mnStartAction
!= 0 if at least one Action is active.
Definition: viewsh.hxx:181
SwDoc * GetDoc() const
Definition: viewsh.hxx:290
const SfxItemPool & GetAttrPool() const
Definition: viewsh.hxx:627
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:1282
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:1242
static SpellContentPosition lcl_FindNextDeletedRedline(const SpellContentPositions &rDeletedRedlines, sal_Int32 nSearchFrom)
Definition: edlingu.cxx:1297
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:1516
static SwSpellIter * g_pSpellIter
Definition: edlingu.cxx:194
#define CH_TXT_ATR_FORMELEMENT
Definition: hintids.hxx:180
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:174
constexpr sal_uInt16 RES_TXTATR_END(RES_TXTATR_NOEND_END)
#define CH_TXTATR_BREAKWORD
Definition: hintids.hxx:173
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:982
bool m_bRealWidth
Calculation of the width required.
Definition: crstate.hxx:149
Marks a position in the document model.
Definition: pam.hxx:37
SwNode & GetNode() const
Definition: pam.hxx:80
sal_Int32 GetContentIndex() const
Definition: pam.hxx:84
SwContentIndex nContent
Definition: pam.hxx:39
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