xref: /core/sw/source/core/crsr/crstrvl.cxx (revision 0d276227903b18a067010f917e999053fbeded11)
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 <memory>
21 #include <utility>
22 #include <hintids.hxx>
23 #include <comphelper/string.hxx>
24 #include <svl/itemiter.hxx>
25 #include <editeng/lrspitem.hxx>
26 #include <editeng/adjustitem.hxx>
27 #include <editeng/formatbreakitem.hxx>
28 #include <svx/svdobj.hxx>
29 #include <osl/diagnose.h>
30 #include <crsrsh.hxx>
31 #include <doc.hxx>
32 #include <IDocumentUndoRedo.hxx>
33 #include <IDocumentRedlineAccess.hxx>
34 #include <IDocumentFieldsAccess.hxx>
35 #include <IDocumentLayoutAccess.hxx>
36 #include <pagefrm.hxx>
37 #include <cntfrm.hxx>
38 #include <rootfrm.hxx>
39 #include <pam.hxx>
40 #include <ndtxt.hxx>
41 #include <fldbas.hxx>
42 #include <swtable.hxx>
43 #include <docary.hxx>
44 #include <txtfld.hxx>
45 #include <fmtfld.hxx>
46 #include <txtftn.hxx>
47 #include <txtinet.hxx>
48 #include <fmtinfmt.hxx>
49 #include <txttxmrk.hxx>
50 #include <frmfmt.hxx>
51 #include <flyfrm.hxx>
52 #include <viscrs.hxx>
53 #include "callnk.hxx"
54 #include <doctxm.hxx>
55 #include <docfld.hxx>
56 #include <expfld.hxx>
57 #include <reffld.hxx>
58 #include <flddat.hxx>
59 #include <cellatr.hxx>
60 #include <swundo.hxx>
61 #include <redline.hxx>
62 #include <fmtcntnt.hxx>
63 #include <fmthdft.hxx>
64 #include <pagedesc.hxx>
65 #include <fesh.hxx>
66 #include <charfmt.hxx>
67 #include <fmturl.hxx>
68 #include <txtfrm.hxx>
69 #include <wrong.hxx>
70 #include <calbck.hxx>
71 #include <unotools/intlwrapper.hxx>
72 #include <docufld.hxx>
73 #include <svx/srchdlg.hxx>
74 #include <frameformats.hxx>
75 #include <docsh.hxx>
76 #include <wrtsh.hxx>
77 #include <textcontentcontrol.hxx>
78 
79 using namespace ::com::sun::star;
80 
MoveCursorToNum()81 void SwCursorShell::MoveCursorToNum()
82 {
83     SwCallLink aLk( *this ); // watch Cursor-Moves
84     SwCursorSaveState aSaveState( *m_pCurrentCursor );
85     if( ActionPend() )
86         return;
87     CurrShell aCurr( this );
88     // try to set cursor onto this position, at half of the char-
89     // SRectangle's height
90     Point aPt( m_pCurrentCursor->GetPtPos() );
91     std::pair<Point, bool> const tmp(aPt, true);
92     SwContentFrame * pFrame = m_pCurrentCursor->GetPointContentNode()->getLayoutFrame(
93                 GetLayout(), m_pCurrentCursor->GetPoint(), &tmp);
94     pFrame->GetCharRect( m_aCharRect, *m_pCurrentCursor->GetPoint() );
95     pFrame->Calc(GetOut());
96     if( pFrame->IsVertical() )
97     {
98         aPt.setX(m_aCharRect.Center().getX());
99         aPt.setY(pFrame->getFrameArea().Top() + GetUpDownX());
100     }
101     else
102     {
103         aPt.setY(m_aCharRect.Center().getY());
104         aPt.setX(pFrame->getFrameArea().Left() + GetUpDownX());
105     }
106     pFrame->GetModelPositionForViewPoint( m_pCurrentCursor->GetPoint(), aPt );
107     if ( !m_pCurrentCursor->IsSelOvr( SwCursorSelOverFlags::Toggle |
108                                 SwCursorSelOverFlags::ChangePos ))
109     {
110         UpdateCursor(SwCursorShell::UPDOWN |
111                 SwCursorShell::SCROLLWIN | SwCursorShell::CHKRANGE |
112                 SwCursorShell::READONLY );
113     }
114 }
115 
116 /// go to next/previous point on the same level
GotoNextNum()117 void SwCursorShell::GotoNextNum()
118 {
119     if (!SwDoc::GotoNextNum(*m_pCurrentCursor->GetPoint(), GetLayout()))
120         return;
121     MoveCursorToNum();
122 }
123 
GotoPrevNum()124 void SwCursorShell::GotoPrevNum()
125 {
126     if (!SwDoc::GotoPrevNum(*m_pCurrentCursor->GetPoint(), GetLayout()))
127         return;
128     MoveCursorToNum();
129 }
130 
131 /// jump from content to header
GotoHeaderText()132 bool SwCursorShell::GotoHeaderText()
133 {
134     const SwFrame* pFrame = GetCurrFrame()->FindPageFrame();
135     while( pFrame && !pFrame->IsHeaderFrame() )
136         pFrame = pFrame->GetLower();
137     // found header, search 1. content frame
138     while( pFrame && !pFrame->IsContentFrame() )
139         pFrame = pFrame->GetLower();
140 
141     if( !pFrame )
142         return false;
143 
144     CurrShell aCurr( this );
145     // get header frame
146     SwCallLink aLk( *this ); // watch Cursor-Moves
147     SwCursor *pTmpCursor = getShellCursor( true );
148     SwCursorSaveState aSaveState( *pTmpCursor );
149     pFrame->Calc(GetOut());
150     Point aPt( pFrame->getFrameArea().Pos() + pFrame->getFramePrintArea().Pos() );
151     pFrame->GetModelPositionForViewPoint( pTmpCursor->GetPoint(), aPt );
152     if( !pTmpCursor->IsSelOvr() )
153         UpdateCursor();
154     else
155         pFrame = nullptr;
156     return nullptr != pFrame;
157 }
158 
159 /// jump from content to footer
GotoFooterText()160 bool SwCursorShell::GotoFooterText()
161 {
162     const SwPageFrame* pFrame = GetCurrFrame()->FindPageFrame();
163     if( !pFrame )
164         return false;
165 
166     const SwFrame* pLower = pFrame->GetLastLower();
167 
168     while( pLower && !pLower->IsFooterFrame() )
169         pLower = pLower->GetLower();
170     // found footer, search 1. content frame
171     while( pLower && !pLower->IsContentFrame() )
172         pLower = pLower->GetLower();
173 
174     if( !pLower )
175         return false;
176 
177     SwCursor *pTmpCursor = getShellCursor( true );
178     CurrShell aCurr( this );
179     // get position in footer
180     SwCallLink aLk( *this ); // watch Cursor-Moves
181     SwCursorSaveState aSaveState( *pTmpCursor );
182     pLower->Calc(GetOut());
183     Point aPt( pLower->getFrameArea().Pos() + pLower->getFramePrintArea().Pos() );
184     pLower->GetModelPositionForViewPoint( pTmpCursor->GetPoint(), aPt );
185     if( !pTmpCursor->IsSelOvr() )
186         UpdateCursor();
187     else
188         pFrame = nullptr;
189     return nullptr != pFrame;
190 }
191 
SetCursorInHdFt(size_t nDescNo,bool bInHeader,bool bEven,bool bFirst)192 bool SwCursorShell::SetCursorInHdFt(size_t nDescNo, bool bInHeader, bool bEven, bool bFirst)
193 {
194     SwDoc *pMyDoc = GetDoc();
195     const SwPageDesc* pDesc = nullptr;
196 
197     CurrShell aCurr( this );
198 
199     if( SIZE_MAX == nDescNo )
200     {
201         // take the current one
202         const SwContentFrame *pCurrFrame = GetCurrFrame();
203         const SwPageFrame* pPage = (pCurrFrame == nullptr) ? nullptr : pCurrFrame->FindPageFrame();
204         if( pPage && pMyDoc->ContainsPageDesc(
205                 pPage->GetPageDesc(), &nDescNo) )
206             pDesc = pPage->GetPageDesc();
207     }
208     else
209         if (nDescNo < pMyDoc->GetPageDescCnt())
210             pDesc = &pMyDoc->GetPageDesc( nDescNo );
211 
212     if( !pDesc )
213         return false;
214 
215     // check if the attribute exists
216     const SwFormatContent* pCnt = nullptr;
217     if( bInHeader )
218     {
219         const SwFormatHeader& rHd
220             = bEven ? bFirst ? pDesc->GetFirstLeft().GetHeader() : pDesc->GetLeft().GetHeader()
221                     : bFirst ? pDesc->GetFirstMaster().GetHeader() : pDesc->GetMaster().GetHeader();
222         if( rHd.GetHeaderFormat() )
223             pCnt = &rHd.GetHeaderFormat()->GetContent();
224     }
225     else
226     {
227         const SwFormatFooter& rFt
228             = bEven ? bFirst ? pDesc->GetFirstLeft().GetFooter() : pDesc->GetLeft().GetFooter()
229                     : bFirst ? pDesc->GetFirstMaster().GetFooter() : pDesc->GetMaster().GetFooter();
230         if( rFt.GetFooterFormat() )
231             pCnt = &rFt.GetFooterFormat()->GetContent();
232     }
233 
234     if( !pCnt || !pCnt->GetContentIdx() )
235         return false;
236 
237     SwNodeIndex aIdx( *pCnt->GetContentIdx(), 1 );
238     SwContentNode* pCNd = aIdx.GetNode().GetContentNode();
239     if( !pCNd )
240         pCNd = SwNodes::GoNext(&aIdx);
241 
242     Point aPt( m_pCurrentCursor->GetPtPos() );
243 
244     std::pair<Point, bool> const tmp(aPt, false);
245     if (!pCNd || nullptr == pCNd->getLayoutFrame(GetLayout(), nullptr, &tmp))
246         return false;
247 
248     // then we can set the cursor in here
249     SwCallLink aLk( *this ); // watch Cursor-Moves
250     SwCursorSaveState aSaveState( *m_pCurrentCursor );
251 
252     ClearMark();
253 
254     SwPosition& rPos = *m_pCurrentCursor->GetPoint();
255     rPos.Assign( *pCNd );
256 
257     if (m_pCurrentCursor->IsSelOvr())
258         return false;
259 
260     UpdateCursor( SwCursorShell::SCROLLWIN | SwCursorShell::CHKRANGE |
261                 SwCursorShell::READONLY );
262     return true;
263 }
264 
265 /// jump to the next index
GotoNextTOXBase(const UIName * pName)266 bool SwCursorShell::GotoNextTOXBase( const UIName* pName )
267 {
268     const SwSectionFormats& rFormats = GetDoc()->GetSections();
269     SwContentNode* pFnd = nullptr;
270     for( SwSectionFormats::size_type n = rFormats.size(); n; )
271     {
272         const SwSection* pSect = rFormats[ --n ]->GetSection();
273         if (SectionType::ToxContent == pSect->GetType())
274         {
275             SwSectionNode const*const pSectNd(
276                     pSect->GetFormat()->GetSectionNode());
277             if (   pSectNd
278                 && m_pCurrentCursor->GetPoint()->GetNode() < *pSectNd
279                 && (!pFnd  || pFnd->GetIndex() > pSectNd->GetIndex())
280                 && (!pName || *pName ==
281                     static_cast<SwTOXBaseSection const*>(pSect)->GetTOXName()))
282             {
283                 SwNodeIndex aIdx(*pSectNd, 1);
284                 SwContentNode* pCNd = aIdx.GetNode().GetContentNode();
285                 if (!pCNd)
286                     pCNd = SwNodes::GoNext(&aIdx);
287                 if (pCNd &&
288                     pCNd->EndOfSectionIndex() <= pSectNd->EndOfSectionIndex())
289                 {
290                     SwContentFrame const*const pCFrame(
291                             pCNd->getLayoutFrame(GetLayout()));
292                     if (pCFrame &&
293                         (IsReadOnlyAvailable() || !pCFrame->IsProtected()))
294                     {
295                         pFnd = pCNd;
296                     }
297                 }
298             }
299         }
300     }
301     if( !pFnd )
302         return false;
303     SwCallLink aLk( *this ); // watch Cursor-Moves
304     SwCursorSaveState aSaveState( *m_pCurrentCursor );
305     m_pCurrentCursor->GetPoint()->Assign( *pFnd );
306     bool bRet = !m_pCurrentCursor->IsSelOvr();
307     if( bRet )
308         UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
309     return bRet;
310 }
311 
312 /// jump to previous index
GotoPrevTOXBase(const UIName * pName)313 bool SwCursorShell::GotoPrevTOXBase( const UIName* pName )
314 {
315     const SwSectionFormats& rFormats = GetDoc()->GetSections();
316     SwContentNode* pFnd = nullptr;
317     for( SwSectionFormats::size_type n = rFormats.size(); n; )
318     {
319         const SwSection* pSect = rFormats[ --n ]->GetSection();
320         if (SectionType::ToxContent == pSect->GetType())
321         {
322             SwSectionNode const*const pSectNd(
323                     pSect->GetFormat()->GetSectionNode());
324             if (   pSectNd
325                 && m_pCurrentCursor->GetPoint()->GetNode() > *pSectNd->EndOfSectionNode()
326                 && (!pFnd  || *pFnd < *pSectNd)
327                 && (!pName || *pName ==
328                     static_cast<SwTOXBaseSection const*>(pSect)->GetTOXName()))
329             {
330                 SwNodeIndex aIdx(*pSectNd, 1);
331                 SwContentNode* pCNd = aIdx.GetNode().GetContentNode();
332                 if (!pCNd)
333                     pCNd = SwNodes::GoNext(&aIdx);
334                 if (pCNd &&
335                     pCNd->EndOfSectionIndex() <= pSectNd->EndOfSectionIndex())
336                 {
337                     SwContentFrame const*const pCFrame(
338                             pCNd->getLayoutFrame(GetLayout()));
339                     if (pCFrame &&
340                         (IsReadOnlyAvailable() || !pCFrame->IsProtected()))
341                     {
342                         pFnd = pCNd;
343                     }
344                 }
345             }
346         }
347     }
348 
349     if( !pFnd )
350         return false;
351 
352     SwCallLink aLk( *this ); // watch Cursor-Moves
353     SwCursorSaveState aSaveState( *m_pCurrentCursor );
354     m_pCurrentCursor->GetPoint()->Assign(*pFnd);
355     bool bRet = !m_pCurrentCursor->IsSelOvr();
356     if( bRet )
357         UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
358     return bRet;
359 }
360 
361 /// jump to index of TOXMark
GotoTOXMarkBase()362 void SwCursorShell::GotoTOXMarkBase()
363 {
364     SwTOXMarks aMarks;
365     sal_uInt16 nCnt = SwDoc::GetCurTOXMark(*m_pCurrentCursor->GetPoint(), aMarks);
366     if(!nCnt)
367         return;
368     // Take the 1. and get the index type. Ask it for the actual index.
369     const SwTOXType* pType = aMarks[0]->GetTOXType();
370     auto pContentFrame = pType->FindContentFrame(*GetLayout());
371     if(!pContentFrame)
372         return;
373     SwCallLink aLk(*this); // watch Cursor-Moves
374     SwCursorSaveState aSaveState(*m_pCurrentCursor);
375     assert(pContentFrame->IsTextFrame());
376     *m_pCurrentCursor->GetPoint() = static_cast<SwTextFrame const*>(pContentFrame)->MapViewToModelPos(TextFrameIndex(0));
377     if(!m_pCurrentCursor->IsInProtectTable() && !m_pCurrentCursor->IsSelOvr())
378         UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
379 }
380 
381 /// Jump to next/previous table formula
382 /// Optionally it is possible to also jump to broken formulas
GotoNxtPrvTableFormula(bool bNext,bool bOnlyErrors)383 bool SwCursorShell::GotoNxtPrvTableFormula( bool bNext, bool bOnlyErrors )
384 {
385     SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::Empty );
386 
387     if( IsTableMode() )
388         return false;
389 
390     bool bFnd = false;
391     SwPosition aOldPos = *m_pCurrentCursor->GetPoint();
392     SwPosition& rPos = *m_pCurrentCursor->GetPoint();
393 
394     Point aPt;
395     SwPosition aFndPos( GetDoc()->GetNodes().GetEndOfContent() );
396     if( !bNext )
397         aFndPos.Assign(SwNodeOffset(0));
398     SetGetExpField aFndGEF( aFndPos ), aCurGEF( rPos );
399 
400     {
401         const SwNode* pSttNd = rPos.GetNode().FindTableBoxStartNode();
402         if( pSttNd )
403         {
404             const SwTableBox* pTBox = pSttNd->FindTableNode()->GetTable().
405                                         GetTableBox( pSttNd->GetIndex() );
406             if( pTBox )
407                 aCurGEF = SetGetExpField( *pTBox );
408         }
409     }
410 
411     if( rPos.GetNode() < GetDoc()->GetNodes().GetEndOfExtras() )
412     {
413         // also at collection use only the first frame
414         std::pair<Point, bool> const tmp(aPt, false);
415         aCurGEF.SetBodyPos( *rPos.GetNode().GetContentNode()->getLayoutFrame( GetLayout(),
416                                 &rPos, &tmp) );
417     }
418 
419     std::vector<SwTableBoxFormula*> aTableBoxFormulas;
420     SwTable::GatherFormulas(*GetDoc(), aTableBoxFormulas);
421     const sal_uInt32 nMaxItems(aTableBoxFormulas.size());
422     if( nMaxItems > 0 )
423     {
424         sal_uInt8 nMaxDo = 2;
425         do {
426             for (SwTableBoxFormula* pItem : aTableBoxFormulas)
427             {
428                 const SwTableBox* pTBox;
429                 auto & rFormulaItem = *pItem;
430                 pTBox = rFormulaItem.GetTableBox();
431                 if( pTBox &&
432                     pTBox->GetSttNd() &&
433                     pTBox->GetSttNd()->GetNodes().IsDocNodes() &&
434                     ( !bOnlyErrors ||
435                       !rFormulaItem.HasValidBoxes() ) )
436                 {
437                     SwNodeIndex aIdx( *pTBox->GetSttNd() );
438                     const SwContentNode* pCNd = SwNodes::GoNext(&aIdx);
439                     std::pair<Point, bool> const tmp(aPt, false);
440                     if (pCNd)
441                     {
442                         const SwContentFrame* pCFrame = pCNd->getLayoutFrame(GetLayout(), nullptr, &tmp);
443                         if (pCFrame && (IsReadOnlyAvailable() || !pCFrame->IsProtected() ))
444                         {
445                             SetGetExpField aCmp( *pTBox );
446                             aCmp.SetBodyPos( *pCFrame );
447 
448                             if( bNext ? ( aCurGEF < aCmp && aCmp < aFndGEF )
449                                     : ( aCmp < aCurGEF && aFndGEF < aCmp ))
450                             {
451                                 aFndGEF = aCmp;
452                                 bFnd = true;
453                             }
454                         }
455                     }
456                 }
457             }
458             if( !bFnd )
459             {
460                 if( bNext )
461                 {
462                     rPos.Assign(SwNodeOffset(0), 0);
463                     aCurGEF = SetGetExpField( rPos );
464                     SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::EndWrapped );
465                 }
466                 else
467                 {
468                     aCurGEF = SetGetExpField( SwPosition( GetDoc()->GetNodes().GetEndOfContent() ) );
469                     SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::StartWrapped );
470                 }
471             }
472         } while( !bFnd && --nMaxDo );
473     }
474 
475     if( !bFnd )
476     {
477         rPos = std::move(aOldPos);
478         SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::NavElementNotFound );
479         return false;
480     }
481 
482     CurrShell aCurr( this );
483     SwCallLink aLk( *this ); // watch Cursor-Moves
484     SwCursorSaveState aSaveState( *m_pCurrentCursor );
485 
486     aFndGEF.GetPosOfContent( rPos );
487     m_pCurrentCursor->DeleteMark();
488 
489     bFnd = !m_pCurrentCursor->IsSelOvr();
490     if( bFnd )
491         UpdateCursor( SwCursorShell::SCROLLWIN | SwCursorShell::CHKRANGE |
492                     SwCursorShell::READONLY );
493 
494     return bFnd;
495 }
496 
497 /// jump to next/previous index marker
GotoNxtPrvTOXMark(bool bNext)498 bool SwCursorShell::GotoNxtPrvTOXMark( bool bNext )
499 {
500     SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::Empty );
501 
502     if( IsTableMode() )
503         return false;
504 
505     bool bFnd = false;
506     SwPosition& rPos = *m_pCurrentCursor->GetPoint();
507 
508     Point aPt;
509     SwPosition aFndPos( GetDoc()->GetNodes().GetEndOfContent() );
510     if( !bNext )
511         aFndPos.Assign(SwNodeOffset(0));
512     SetGetExpField aFndGEF( aFndPos ), aCurGEF( rPos );
513 
514     if( rPos.GetNodeIndex() < GetDoc()->GetNodes().GetEndOfExtras().GetIndex() )
515     {
516         // also at collection use only the first frame
517         std::pair<Point, bool> const tmp(aPt, false);
518         aCurGEF.SetBodyPos( *rPos.GetNode().
519                     GetContentNode()->getLayoutFrame(GetLayout(), &rPos, &tmp));
520     }
521 
522     std::vector<const SwTOXMark*> aSurrogates;
523     GetDoc()->ForEachTOXMark(
524         [&aSurrogates] (const SwTOXMark& rItem) -> bool
525         {
526             aSurrogates.push_back(&rItem);
527             return true;
528         });
529     const sal_uInt32 nMaxItems(aSurrogates.size());
530     if( nMaxItems == 0 )
531     {
532         SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::NavElementNotFound );
533         return false;
534     }
535 
536     const SwTextNode* pTextNd;
537     const SwTextTOXMark* pTextTOX;
538     do {
539         for (const SwTOXMark* pItem : aSurrogates)
540         {
541             auto & rToxMarkItem = *pItem;
542             pTextTOX = rToxMarkItem.GetTextTOXMark();
543             if( !pTextTOX )
544                 continue;
545             pTextNd = &pTextTOX->GetTextNode();
546             if( !pTextNd->GetNodes().IsDocNodes() )
547                 continue;
548             std::pair<Point, bool> const tmp(aPt, false);
549             const SwContentFrame* pCFrame = pTextNd->getLayoutFrame(GetLayout(), nullptr, &tmp);
550             if( pCFrame && ( IsReadOnlyAvailable() || !pCFrame->IsProtected() ))
551             {
552                 SetGetExpField aCmp( *pTextNd, *pTextTOX );
553                 aCmp.SetBodyPos( *pCFrame );
554 
555                 if( bNext ? ( aCurGEF < aCmp && aCmp < aFndGEF )
556                           : ( aCmp < aCurGEF && aFndGEF < aCmp ))
557                 {
558                     aFndGEF = aCmp;
559                     bFnd = true;
560                 }
561             }
562         }
563         if( !bFnd )
564         {
565             if ( bNext )
566             {
567                 rPos.Assign(SwNodeOffset(0), 0);
568                 aCurGEF = SetGetExpField( rPos );
569                 SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::EndWrapped );
570             }
571             else
572             {
573                 aCurGEF = SetGetExpField( SwPosition( GetDoc()->GetNodes().GetEndOfContent() ) );
574                 SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::StartWrapped );
575             }
576         }
577     } while ( !bFnd );
578 
579     CurrShell aCurr( this );
580     SwCallLink aLk( *this ); // watch Cursor-Moves
581     SwCursorSaveState aSaveState( *m_pCurrentCursor );
582 
583     aFndGEF.GetPosOfContent( rPos );
584 
585     bFnd = !m_pCurrentCursor->IsSelOvr();
586     if( bFnd )
587         UpdateCursor( SwCursorShell::SCROLLWIN | SwCursorShell::CHKRANGE |
588                     SwCursorShell::READONLY );
589     return bFnd;
590 }
591 
592 /// traveling between marks
GotoTOXMark(const SwTOXMark & rStart,SwTOXSearch eDir)593 const SwTOXMark& SwCursorShell::GotoTOXMark( const SwTOXMark& rStart,
594                                             SwTOXSearch eDir )
595 {
596     CurrShell aCurr( this );
597     SwCallLink aLk( *this ); // watch Cursor-Moves
598     SwCursorSaveState aSaveState( *m_pCurrentCursor );
599 
600     const SwTOXMark& rNewMark = GetDoc()->GotoTOXMark( rStart, eDir,
601                                                     IsReadOnlyAvailable() );
602     // set position
603     SwPosition& rPos = *GetCursor()->GetPoint();
604     rPos.Assign(rNewMark.GetTextTOXMark()->GetTextNode(),
605                  rNewMark.GetTextTOXMark()->GetStart() );
606     GetCursor()->DeleteMark(); // tdf#158783 prevent UpdateCursor resetting point
607 
608     if( !m_pCurrentCursor->IsSelOvr() )
609         UpdateCursor( SwCursorShell::SCROLLWIN | SwCursorShell::CHKRANGE |
610                     SwCursorShell::READONLY );
611 
612     return rNewMark;
613 }
614 
615 /// jump to next/previous field type
lcl_MakeFieldLst(SetGetExpFields & rLst,const SwFieldType & rFieldType,const bool bInReadOnly,const bool bChkInpFlag=false)616 static void lcl_MakeFieldLst(
617     SetGetExpFields& rLst,
618     const SwFieldType& rFieldType,
619     const bool bInReadOnly,
620     const bool bChkInpFlag = false )
621 {
622     // always search the 1. frame
623     Point aPt;
624     std::vector<SwFormatField*> vFields;
625     rFieldType.GatherFields(vFields, false);
626     for(SwFormatField* pFormatField: vFields)
627     {
628         SwTextField* pTextField = pFormatField->GetTextField();
629         if ( pTextField != nullptr
630              && ( !bChkInpFlag
631                   || static_cast<const SwSetExpField*>(pTextField->GetFormatField().GetField())->GetInputFlag() ) )
632         {
633             const SwTextNode& rTextNode = pTextField->GetTextNode();
634             std::pair<Point, bool> const tmp(aPt, false);
635             const SwContentFrame* pCFrame =
636                 rTextNode.getLayoutFrame(
637                     rTextNode.GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(),
638                     nullptr, &tmp);
639             if ( pCFrame != nullptr
640                  && ( bInReadOnly || !pCFrame->IsProtected() ) )
641             {
642                 std::unique_ptr<SetGetExpField> pNew(new SetGetExpField( rTextNode, pTextField ));
643                 pNew->SetBodyPos( *pCFrame );
644                 rLst.insert( std::move(pNew) );
645             }
646         }
647     }
648 }
649 
650 static SetGetExpFields::const_iterator
lcl_FindField(bool & o_rFound,SetGetExpFields const & rSrtLst,SwRootFrame const * const pLayout,SwTextNode * const pTextNode,SwTextField const * const pTextField,SwPosition const & rPos,sal_Int32 const nContentOffset)651 lcl_FindField(bool & o_rFound, SetGetExpFields const& rSrtLst,
652         SwRootFrame const *const pLayout, SwTextNode *const pTextNode,
653         SwTextField const *const pTextField, SwPosition const& rPos,
654         sal_Int32 const nContentOffset)
655 {
656     std::optional<SetGetExpField> oSrch;
657     if (-1 == nContentOffset)
658     {
659         oSrch.emplace(rPos.GetNode(), pTextField, rPos.GetContentIndex());
660     }
661     else
662     {
663         oSrch.emplace(rPos.GetNode(), pTextField, nContentOffset);
664     }
665 
666     if (rPos.GetNodeIndex() < pTextNode->GetNodes().GetEndOfExtras().GetIndex())
667     {
668         // also at collection use only the first frame
669         Point aPt;
670         std::pair<Point, bool> const tmp(aPt, false);
671         oSrch->SetBodyPos(*pTextNode->getLayoutFrame(pLayout, &rPos, &tmp));
672     }
673 
674     SetGetExpFields::const_iterator it = rSrtLst.lower_bound(&*oSrch);
675 
676     o_rFound = (it != rSrtLst.end()) && (**it == *oSrch);
677     return it;
678 }
679 
MoveFieldType(const SwFieldType * pFieldType,const bool bNext,const SwFieldIds nResType,const bool bAddSetExpressionFieldsToInputFields)680 bool SwCursorShell::MoveFieldType(
681     const SwFieldType* pFieldType,
682     const bool bNext,
683     const SwFieldIds nResType,
684     const bool bAddSetExpressionFieldsToInputFields )
685 {
686     // sorted list of all fields
687     SetGetExpFields aSrtLst;
688 
689     if ( pFieldType )
690     {
691         if( SwFieldIds::Input != pFieldType->Which() && !pFieldType->HasWriterListeners() )
692         {
693             return false;
694         }
695 
696         // found Modify object, add all fields to array
697         ::lcl_MakeFieldLst( aSrtLst, *pFieldType, IsReadOnlyAvailable() );
698 
699         if( SwFieldIds::Input == pFieldType->Which() && bAddSetExpressionFieldsToInputFields )
700         {
701             // there are hidden input fields in the set exp. fields
702             const SwFieldTypes& rFieldTypes = *mxDoc->getIDocumentFieldsAccess().GetFieldTypes();
703             const size_t nSize = rFieldTypes.size();
704             for( size_t i=0; i < nSize; ++i )
705             {
706                 pFieldType = rFieldTypes[ i ].get();
707                 if ( SwFieldIds::SetExp == pFieldType->Which() )
708                 {
709                     ::lcl_MakeFieldLst( aSrtLst, *pFieldType, IsReadOnlyAvailable(), true );
710                 }
711             }
712         }
713     }
714     else
715     {
716         const SwFieldTypes& rFieldTypes = *mxDoc->getIDocumentFieldsAccess().GetFieldTypes();
717         const size_t nSize = rFieldTypes.size();
718         const bool bAllFieldTypes = nResType == SwFieldIds::Unknown;
719         for( size_t i=0; i < nSize; ++i )
720         {
721             pFieldType = rFieldTypes[ i ].get();
722             if (bAllFieldTypes || nResType == pFieldType->Which())
723             {
724                 ::lcl_MakeFieldLst( aSrtLst, *pFieldType, IsReadOnlyAvailable() );
725             }
726         }
727     }
728 
729     // found no fields?
730     if( aSrtLst.empty() )
731         return false;
732 
733     SetGetExpFields::const_iterator it;
734     SwCursor* pCursor = getShellCursor( true );
735     {
736         // (1998): Always use field for search so that the right one is found as
737         // well some are in frames that are anchored to a paragraph that has a
738         // field
739         const SwPosition& rPos = *pCursor->GetPoint();
740 
741         SwTextNode* pTNd = rPos.GetNode().GetTextNode();
742         assert(pTNd && "No ContentNode");
743 
744         SwTextField * pTextField = pTNd->GetFieldTextAttrAt(rPos.GetContentIndex(), ::sw::GetTextAttrMode::Default);
745         const bool bDelField = ( pTextField == nullptr );
746         sal_Int32 nContentOffset = -1;
747 
748         if( bDelField )
749         {
750             // create dummy for the search
751             // NOTE: with SfxPoolItemHolder in SwTextAttr the
752             // SwFormatField will just be managed by it, when
753             // wanted and handing over bPassingOwnership==true
754             pTextField = new SwTextField (
755                 SfxPoolItemHolder(
756                     mxDoc->GetAttrPool(),
757                     new SwFormatField(
758                         SwDateTimeField(
759                             static_cast<SwDateTimeFieldType*>(mxDoc->getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::DateTime )))),
760                     true), // bPassingOwnership
761                 rPos.GetContentIndex(),
762                 mxDoc->IsClipBoard() );
763             pTextField->ChgTextNode( pTNd );
764         }
765         else
766         {
767             // the cursor might be anywhere inside the input field,
768             // but we will be searching for the field start
769             if (pTextField->Which() == RES_TXTATR_INPUTFIELD
770                     && rPos.GetContentIndex() != pTextField->GetStart())
771                 nContentOffset = pTextField->GetStart();
772         }
773         bool isSrch;
774         it = lcl_FindField(isSrch, aSrtLst,
775                 GetLayout(), pTNd, pTextField, rPos, nContentOffset);
776 
777         if( bDelField )
778         {
779             // with using SfxPoolItemHolder in SwTextAttr there is no need anymore
780             // to cleanup the contained SwFormatField self
781             delete pTextField;
782         }
783 
784         if( it != aSrtLst.end() && isSrch ) // found
785         {
786             if( bNext )
787             {
788                 if( ++it == aSrtLst.end() )
789                     return false; // already at the end
790             }
791             else
792             {
793                 if( it == aSrtLst.begin() )
794                     return false; // no more steps backward possible
795                 --it;
796             }
797         }
798         else // not found
799         {
800             if( bNext )
801             {
802                 if( it == aSrtLst.end() )
803                     return false;
804             }
805             else
806             {
807                 if( it == aSrtLst.begin() )
808                     return false; // no more steps backward possible
809                 --it;
810             }
811         }
812     }
813     const SetGetExpField& rFnd = **it;
814 
815     CurrShell aCurr( this );
816     SwCallLink aLk( *this ); // watch Cursor-Moves
817     SwCursorSaveState aSaveState( *pCursor );
818 
819     rFnd.GetPosOfContent( *pCursor->GetPoint() );
820     bool bRet = !m_pCurrentCursor->IsSelOvr( SwCursorSelOverFlags::CheckNodeSection |
821                                      SwCursorSelOverFlags::Toggle );
822     if( bRet )
823         UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
824     return bRet;
825 }
826 
GotoFootnoteAnchor(const SwTextFootnote & rTextFootnote)827 bool SwCursorShell::GotoFootnoteAnchor(const SwTextFootnote& rTextFootnote)
828 {
829     if (SwWrtShell* pWrtSh = dynamic_cast<SwWrtShell*>(this))
830         pWrtSh->addCurrentPosition();
831 
832     bool bRet = false;
833     SwCursor* pCursor = getShellCursor(true);
834 
835     CurrShell aCurr(this);
836     SwCallLink aLk(*this); // watch Cursor-Moves
837     SwCursorSaveState aSaveState(*pCursor);
838 
839     pCursor->GetPoint()->Assign(rTextFootnote.GetTextNode(),
840                                 rTextFootnote.GetStart());
841     bRet = !pCursor->IsSelOvr();
842     if (bRet)
843         UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
844     return bRet;
845 }
846 
GotoFormatContentControl(const SwFormatContentControl & rContentControl)847 bool SwCursorShell::GotoFormatContentControl(const SwFormatContentControl& rContentControl)
848 {
849     const std::shared_ptr<SwContentControl>& pContentControl = rContentControl.GetContentControl();
850     const SwTextContentControl* pTextContentControl = pContentControl->GetTextAttr();
851     if (!pTextContentControl)
852         return false;
853 
854     CurrShell aCurr(this);
855     SwCallLink aLink(*this);
856 
857     SwCursor* pCursor = getShellCursor(true);
858     SwCursorSaveState aSaveState(*pCursor);
859 
860     SwTextNode* pTextNode = pContentControl->GetTextNode();
861     // Don't select the text attribute itself at the start.
862     sal_Int32 nStart = pTextContentControl->GetStart() + 1;
863     pCursor->GetPoint()->Assign(*pTextNode, nStart);
864 
865     bool bRet = true;
866     // select contents for certain controls or conditions
867     if (pContentControl->GetShowingPlaceHolder() || pContentControl->GetCheckbox()
868         || pContentControl->GetSelectedListItem() || pContentControl->GetSelectedDate())
869     {
870         pCursor->SetMark();
871         // Don't select the CH_TXTATR_BREAKWORD itself at the end.
872         sal_Int32 nEnd = *pTextContentControl->End() - 1;
873         pCursor->GetMark()->Assign(*pTextNode, nEnd);
874         bRet = !pCursor->IsSelOvr();
875     }
876     else
877         ClearMark();
878 
879     if (bRet)
880     {
881         UpdateCursor(SwCursorShell::SCROLLWIN | SwCursorShell::CHKRANGE
882                      | SwCursorShell::READONLY);
883     }
884 
885     return bRet;
886 }
887 
888 /**
889  * Go to the next (or previous) form control, based first on tabIndex and then paragraph position,
890  * where a tabIndex of 1 is first, 0 is last, and -1 is excluded.
891  */
GotoFormControl(bool bNext)892 void SwCursorShell::GotoFormControl(bool bNext)
893 {
894     // (note: this only applies to modern content controls and legacy fieldmarks,
895     //  since activeX richText controls aren't exposed to SW keystrokes)
896 
897     struct FormControlSort
898     {
899         bool operator()(std::pair<const SwPosition&, sal_uInt32> rLHS,
900                         std::pair<const SwPosition&, sal_uInt32> rRHS) const
901         {
902             assert(rLHS.second && rRHS.second && "tabIndex zero must be changed to SAL_MAX_UINT32");
903             //first compare tabIndexes where 1 has the priority.
904             if (rLHS.second < rRHS.second)
905                 return true;
906             if (rLHS.second > rRHS.second)
907                 return false;
908 
909             // when tabIndexes are equal (and they usually are) then sort by paragraph position
910             return rLHS.first < rRHS.first;
911         }
912     };
913     std::map<std::pair<SwPosition, sal_uInt32>,
914              std::pair<SwTextContentControl*, sw::mark::Fieldmark*>, FormControlSort>  aFormMap;
915 
916     // add all of the eligible modern Content Controls into a sorted map
917     SwContentControlManager& rManager = GetDoc()->GetContentControlManager();
918     for (size_t  i = 0; i < rManager.GetCount(); ++i)
919     {
920         SwTextContentControl* pTCC = rManager.UnsortedGet(i);
921         if (!pTCC || !pTCC->GetTextNode())
922             continue;
923         auto pCC = pTCC->GetContentControl().GetContentControl();
924 
925         // -1 indicates the control should not participate in keyboard tab navigation
926         if (pCC && pCC->GetTabIndex() == SAL_MAX_UINT32)
927             continue;
928 
929         const SwPosition nPos(*pTCC->GetTextNode(), pTCC->GetStart());
930 
931         // since 0 is the lowest priority (1 is the highest), and -1 has already been excluded,
932         // use SAL_MAX_UINT32 as zero's tabIndex so that automatic sorting is correct.
933         sal_uInt32 nTabIndex = pCC && pCC->GetTabIndex() ? pCC->GetTabIndex() : SAL_MAX_UINT32;
934 
935         const std::pair<SwTextContentControl*, sw::mark::Fieldmark*> pFormControl(pTCC, nullptr);
936         aFormMap[std::make_pair(nPos, nTabIndex)] = pFormControl;
937     }
938 
939     if (aFormMap.begin() == aFormMap.end())
940     {
941         // only legacy fields exist. Avoid reprocessing everything and use legacy code path.
942         GotoFieldmark(bNext ? GetFieldmarkAfter() : GetFieldmarkBefore());
943         return;
944     }
945 
946     // add all of the legacy form field controls into the sorted map
947     IDocumentMarkAccess* pMarkAccess = GetDoc()->getIDocumentMarkAccess();
948     for (auto it = pMarkAccess->getFieldmarksBegin(); it != pMarkAccess->getFieldmarksEnd(); ++it)
949     {
950         sw::mark::Fieldmark* pFieldMark = *it;
951         assert(pFieldMark);
952         // legacy form fields do not have (functional) tabIndexes - use lowest priority for them
953         aFormMap[std::make_pair((*it)->GetMarkStart(), SAL_MAX_UINT32)] =
954             std::pair<SwTextContentControl*, sw::mark::Fieldmark*>(nullptr, pFieldMark);
955     }
956 
957     if (aFormMap.begin() == aFormMap.end())
958         return;
959 
960     // Identify the current location in the document, and the current tab index priority
961 
962     // A content control could contain a Fieldmark, so check for legacy fieldmarks first
963     sw::mark::Fieldmark* pFieldMark = GetCurrentFieldmark();
964     SwTextContentControl* pTCC = !pFieldMark ? CursorInsideContentControl() : nullptr;
965 
966     auto pCC = pTCC ? pTCC->GetContentControl().GetContentControl() : nullptr;
967     const sal_uInt32 nCurTabIndex = pCC && pCC->GetTabIndex() ? pCC->GetTabIndex() : SAL_MAX_UINT32;
968 
969     SwPosition nCurPos(*GetCursor()->GetPoint());
970     if (pFieldMark)
971         nCurPos = pFieldMark->GetMarkStart();
972     else if (pTCC && pTCC->GetTextNode())
973         nCurPos = SwPosition(*pTCC->GetTextNode(), pTCC->GetStart());
974 
975     // Find the previous (or next) tab control and navigate to it
976     const std::pair<SwPosition, sal_uInt32> nOldPos(nCurPos, nCurTabIndex);
977 
978     // lower_bound acts like find, and returns a pointer to nFindPos if it exists,
979     // otherwise it will point to the previous entry.
980     auto aNewPos = aFormMap.lower_bound(nOldPos);
981     if (bNext && aNewPos != aFormMap.end())
982         ++aNewPos;
983     else if (!bNext && aNewPos != aFormMap.end() && aNewPos->first == nOldPos)
984     {
985         // Found the current position - need to return previous
986         if (aNewPos == aFormMap.begin())
987             aNewPos = aFormMap.end(); // prepare to loop around
988         else
989             --aNewPos;
990     }
991 
992     if (aNewPos == aFormMap.end())
993     {
994         // Loop around to the other side
995         if (bNext)
996             aNewPos = aFormMap.begin();
997         else
998             --aNewPos;
999     }
1000 
1001     // the entry contains a pointer to either a Content Control (first) or Fieldmark (second)
1002     if (aNewPos->second.first)
1003     {
1004         auto& rFCC = static_cast<SwFormatContentControl&>(aNewPos->second.first->GetAttr());
1005         GotoFormatContentControl(rFCC);
1006     }
1007     else
1008     {
1009         assert(aNewPos->second.second);
1010         GotoFieldmark(aNewPos->second.second);
1011     }
1012 }
1013 
GotoFormatField(const SwFormatField & rField)1014 bool SwCursorShell::GotoFormatField( const SwFormatField& rField )
1015 {
1016     SwTextField const*const pTextField(rField.GetTextField());
1017     if (!pTextField
1018         || (GetLayout()->IsHideRedlines()
1019              && sw::IsFieldDeletedInModel(
1020                  GetDoc()->getIDocumentRedlineAccess(), *pTextField)))
1021         return false;
1022 
1023     CurrShell aCurr( this );
1024     SwCallLink aLk( *this ); // watch Cursor-Moves
1025 
1026     SwCursor* pCursor = getShellCursor( true );
1027     SwCursorSaveState aSaveState( *pCursor );
1028 
1029     SwTextNode* pTNd = pTextField->GetpTextNode();
1030     pCursor->GetPoint()->Assign(*pTNd, pTextField->GetStart() );
1031 
1032     bool bRet = !pCursor->IsSelOvr();
1033     if( bRet )
1034         UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
1035     if (&pCursor->GetPoint()->GetNode() != pTNd)
1036     {
1037         // tdf#161346 failed to move to field
1038         return false;
1039     }
1040     return bRet;
1041 }
1042 
GetTextFieldAtPos(const SwPosition * pPos,::sw::GetTextAttrMode const eMode)1043 SwTextField * SwCursorShell::GetTextFieldAtPos(
1044     const SwPosition* pPos,
1045     ::sw::GetTextAttrMode const eMode)
1046 {
1047     SwTextField* pTextField = nullptr;
1048 
1049     SwTextNode * const pNode = pPos->GetNode().GetTextNode();
1050     if ( pNode != nullptr )
1051     {
1052         pTextField = pNode->GetFieldTextAttrAt(pPos->GetContentIndex(), eMode);
1053     }
1054 
1055     return pTextField;
1056 }
1057 
GetTextFieldAtCursor(const SwPaM * pCursor,::sw::GetTextAttrMode const eMode)1058 SwTextField* SwCursorShell::GetTextFieldAtCursor(
1059     const SwPaM* pCursor,
1060     ::sw::GetTextAttrMode const eMode)
1061 {
1062     SwTextField* pTextField = GetTextFieldAtPos(pCursor->Start(), eMode);
1063     if ( !pTextField
1064         || pCursor->Start()->GetNode() != pCursor->End()->GetNode() )
1065         return nullptr;
1066 
1067     SwTextField* pFieldAtCursor = nullptr;
1068     const sal_Int32 nTextFieldLength =
1069         pTextField->End() != nullptr
1070         ? *(pTextField->End()) - pTextField->GetStart()
1071         : 1;
1072     if ( ( pCursor->End()->GetContentIndex() - pCursor->Start()->GetContentIndex() ) <= nTextFieldLength )
1073     {
1074         pFieldAtCursor = pTextField;
1075     }
1076 
1077     return pFieldAtCursor;
1078 }
1079 
GetFieldAtCursor(const SwPaM * const pCursor,const bool bIncludeInputFieldAtStart)1080 SwField* SwCursorShell::GetFieldAtCursor(
1081     const SwPaM *const pCursor,
1082     const bool bIncludeInputFieldAtStart)
1083 {
1084     SwTextField *const pField(GetTextFieldAtCursor(pCursor,
1085         bIncludeInputFieldAtStart ? ::sw::GetTextAttrMode::Default : ::sw::GetTextAttrMode::Expand));
1086     return pField
1087         ? const_cast<SwField*>(pField->GetFormatField().GetField())
1088         : nullptr;
1089 }
1090 
GetCurField(const bool bIncludeInputFieldAtStart) const1091 SwField* SwCursorShell::GetCurField( const bool bIncludeInputFieldAtStart ) const
1092 {
1093     SwPaM* pCursor = GetCursor();
1094     if ( pCursor->IsMultiSelection() )
1095     {
1096         // multi selection not handled.
1097         return nullptr;
1098     }
1099 
1100     SwField* pCurField = GetFieldAtCursor( pCursor, bIncludeInputFieldAtStart );
1101     if ( pCurField != nullptr
1102          && SwFieldIds::Table == pCurField->GetTyp()->Which() )
1103     {
1104         // table formula? convert internal name into external
1105         const SwTableNode* pTableNd = IsCursorInTable();
1106         static_cast<SwTableField*>(pCurField)->PtrToBoxNm( pTableNd ? &pTableNd->GetTable() : nullptr );
1107     }
1108 
1109     return pCurField;
1110 }
1111 
CursorInsideInputField() const1112 bool SwCursorShell::CursorInsideInputField() const
1113 {
1114     for(SwPaM& rCursor : GetCursor()->GetRingContainer())
1115     {
1116         if (dynamic_cast<const SwTextInputField*>(GetTextFieldAtCursor(&rCursor, ::sw::GetTextAttrMode::Parent)))
1117             return true;
1118     }
1119     return false;
1120 }
1121 
CursorInsideContentControl() const1122 SwTextContentControl* SwCursorShell::CursorInsideContentControl() const
1123 {
1124     for (SwPaM& rCursor : GetCursor()->GetRingContainer())
1125     {
1126         const SwPosition* pStart = rCursor.Start();
1127         SwTextNode* pTextNode = pStart->GetNode().GetTextNode();
1128         if (!pTextNode)
1129         {
1130             continue;
1131         }
1132 
1133         sal_Int32 nIndex = pStart->GetContentIndex();
1134         if (SwTextAttr* pAttr = pTextNode->GetTextAttrAt(nIndex, RES_TXTATR_CONTENTCONTROL, ::sw::GetTextAttrMode::Parent))
1135         {
1136             return static_txtattr_cast<SwTextContentControl*>(pAttr);
1137         }
1138     }
1139 
1140     return nullptr;
1141 }
1142 
PosInsideInputField(const SwPosition & rPos)1143 bool SwCursorShell::PosInsideInputField( const SwPosition& rPos )
1144 {
1145     return dynamic_cast<const SwTextInputField*>(GetTextFieldAtPos(&rPos, ::sw::GetTextAttrMode::Parent)) != nullptr;
1146 }
1147 
DocPtInsideInputField(const Point & rDocPt) const1148 bool SwCursorShell::DocPtInsideInputField( const Point& rDocPt ) const
1149 {
1150     SwPosition aPos( *(GetCursor()->Start()) );
1151     Point aDocPt( rDocPt );
1152     if ( GetLayout()->GetModelPositionForViewPoint( &aPos, aDocPt ) )
1153     {
1154         return PosInsideInputField( aPos );
1155     }
1156     return false;
1157 }
1158 
StartOfInputFieldAtPos(const SwPosition & rPos)1159 sal_Int32 SwCursorShell::StartOfInputFieldAtPos( const SwPosition& rPos )
1160 {
1161     const SwTextInputField* pTextInputField = dynamic_cast<const SwTextInputField*>(GetTextFieldAtPos(&rPos, ::sw::GetTextAttrMode::Default));
1162     assert(pTextInputField != nullptr
1163         && "<SwEditShell::StartOfInputFieldAtPos(..)> - no Input Field at given position");
1164     return pTextInputField->GetStart();
1165 }
1166 
EndOfInputFieldAtPos(const SwPosition & rPos)1167 sal_Int32 SwCursorShell::EndOfInputFieldAtPos( const SwPosition& rPos )
1168 {
1169     const SwTextInputField* pTextInputField = dynamic_cast<const SwTextInputField*>(GetTextFieldAtPos(&rPos, ::sw::GetTextAttrMode::Default));
1170     assert(pTextInputField != nullptr
1171         && "<SwEditShell::EndOfInputFieldAtPos(..)> - no Input Field at given position");
1172     return *(pTextInputField->End());
1173 }
1174 
GotoOutline(SwOutlineNodes::size_type nIdx)1175 void SwCursorShell::GotoOutline( SwOutlineNodes::size_type nIdx )
1176 {
1177     SwCursor* pCursor = getShellCursor( true );
1178 
1179     CurrShell aCurr( this );
1180     SwCallLink aLk( *this ); // watch Cursor-Moves
1181     SwCursorSaveState aSaveState( *pCursor );
1182 
1183     const SwNodes& rNds = GetDoc()->GetNodes();
1184     SwTextNode* pTextNd = rNds.GetOutLineNds()[ nIdx ]->GetTextNode();
1185     pCursor->GetPoint()->Assign(*pTextNd);
1186 
1187     if( !pCursor->IsSelOvr() )
1188         UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
1189 }
1190 
GotoOutline(const OUString & rName)1191 bool SwCursorShell::GotoOutline( const OUString& rName )
1192 {
1193     SwCursor* pCursor = getShellCursor( true );
1194 
1195     CurrShell aCurr( this );
1196     SwCallLink aLk( *this ); // watch Cursor-Moves
1197     SwCursorSaveState aSaveState( *pCursor );
1198 
1199     bool bRet = false;
1200     if (mxDoc->GotoOutline(*pCursor->GetPoint(), rName, GetLayout())
1201         && !pCursor->IsSelOvr())
1202     {
1203         UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
1204         bRet = true;
1205     }
1206     return bRet;
1207 }
1208 
1209 /// jump to next node with outline num.
GotoNextOutline()1210 bool SwCursorShell::GotoNextOutline()
1211 {
1212     const SwNodes& rNds = GetDoc()->GetNodes();
1213 
1214     if ( rNds.GetOutLineNds().empty() )
1215     {
1216         SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::NavElementNotFound );
1217         return false;
1218     }
1219 
1220     SwCursor* pCursor = getShellCursor( true );
1221     SwNode* pNd = &(pCursor->GetPointNode());
1222     SwOutlineNodes::size_type nPos;
1223     bool bUseFirst = !rNds.GetOutLineNds().Seek_Entry( pNd, &nPos );
1224     SwOutlineNodes::size_type const nStartPos(nPos);
1225 
1226     do
1227     {
1228         if (!bUseFirst)
1229         {
1230             ++nPos;
1231         }
1232         if (rNds.GetOutLineNds().size() <= nPos)
1233         {
1234             nPos = 0;
1235         }
1236 
1237         if (bUseFirst)
1238         {
1239             bUseFirst = false;
1240         }
1241         else
1242         {
1243             if (nPos == nStartPos)
1244             {
1245                 SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::NavElementNotFound );
1246                 return false;
1247             }
1248         }
1249 
1250         pNd = rNds.GetOutLineNds()[ nPos ];
1251     }
1252     while (!sw::IsParaPropsNode(*GetLayout(), *pNd->GetTextNode()));
1253 
1254     if (nPos < nStartPos)
1255     {
1256         SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::EndWrapped );
1257     }
1258     else
1259     {
1260         SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::Empty );
1261     }
1262 
1263     CurrShell aCurr( this );
1264     SwCallLink aLk( *this ); // watch Cursor-Moves
1265     SwCursorSaveState aSaveState( *pCursor );
1266     pCursor->GetPoint()->Assign(*pNd);
1267 
1268     bool bRet = !pCursor->IsSelOvr();
1269     if( bRet )
1270         UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
1271     return bRet;
1272 }
1273 
1274 /// jump to previous node with outline num.
GotoPrevOutline()1275 bool SwCursorShell::GotoPrevOutline()
1276 {
1277     const SwNodes& rNds = GetDoc()->GetNodes();
1278 
1279     if ( rNds.GetOutLineNds().empty() )
1280     {
1281         SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::NavElementNotFound );
1282         return false;
1283     }
1284 
1285     SwCursor* pCursor = getShellCursor( true );
1286     SwNode* pNd = &(pCursor->GetPointNode());
1287     SwOutlineNodes::size_type nPos;
1288     (void)rNds.GetOutLineNds().Seek_Entry(pNd, &nPos);
1289     SwOutlineNodes::size_type const nStartPos(nPos);
1290 
1291     do
1292     {
1293         if (nPos == 0)
1294         {
1295             nPos = rNds.GetOutLineNds().size() - 1;
1296         }
1297         else
1298         {
1299             --nPos; // before
1300         }
1301         if (nPos == nStartPos)
1302         {
1303             pNd = nullptr;
1304             break;
1305         }
1306 
1307         pNd = rNds.GetOutLineNds()[ nPos ];
1308     }
1309     while (!sw::IsParaPropsNode(*GetLayout(), *pNd->GetTextNode()));
1310 
1311     if (!pNd)
1312     {
1313         SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::NavElementNotFound );
1314         return false;
1315     }
1316 
1317     if (nStartPos < nPos)
1318     {
1319         SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::StartWrapped );
1320     }
1321     else
1322     {
1323         SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::Empty );
1324     }
1325     CurrShell aCurr( this );
1326     SwCallLink aLk( *this ); // watch Cursor-Moves
1327     SwCursorSaveState aSaveState( *pCursor );
1328     pCursor->GetPoint()->Assign(*pNd);
1329 
1330     bool bRet = !pCursor->IsSelOvr();
1331     if( bRet )
1332         UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
1333     return bRet;
1334 }
1335 
1336 /// search "outline position" before previous outline node at given level
GetOutlinePos(sal_uInt8 nLevel,SwPaM * pPaM)1337 SwOutlineNodes::size_type SwCursorShell::GetOutlinePos(sal_uInt8 nLevel, SwPaM* pPaM)
1338 {
1339     SwPaM* pCursor = pPaM ? pPaM : getShellCursor(true);
1340     const SwNodes& rNds = GetDoc()->GetNodes();
1341 
1342     SwNode* pNd = &(pCursor->GetPointNode());
1343     SwOutlineNodes::size_type nPos;
1344     if( rNds.GetOutLineNds().Seek_Entry( pNd, &nPos ))
1345         nPos++; // is at correct position; take next for while
1346 
1347     while( nPos-- ) // check the one in front of the current
1348     {
1349         pNd = rNds.GetOutLineNds()[ nPos ];
1350 
1351         if (sw::IsParaPropsNode(*GetLayout(), *pNd->GetTextNode())
1352             && pNd->GetTextNode()->GetAttrOutlineLevel()-1 <= nLevel)
1353         {
1354             if (pNd->GetIndex() < rNds.GetEndOfExtras().GetIndex()
1355                     && pCursor->GetPointNode().GetIndex() > rNds.GetEndOfExtras().GetIndex())
1356             {
1357                 // node found in extras but cursor position is not in extras
1358                 return SwOutlineNodes::npos;
1359             }
1360             return nPos;
1361         }
1362     }
1363     return SwOutlineNodes::npos; // no more left
1364 }
1365 
MakeOutlineSel(SwOutlineNodes::size_type nSttPos,SwOutlineNodes::size_type nEndPos,bool bWithChildren,bool bKillPams,const SwOutlineNodesInline * pOutlNdsInline)1366 void SwCursorShell::MakeOutlineSel(SwOutlineNodes::size_type nSttPos, SwOutlineNodes::size_type nEndPos,
1367                                   bool bWithChildren , bool bKillPams, const SwOutlineNodesInline* pOutlNdsInline)
1368 {
1369     const SwNodes& rNds = GetDoc()->GetNodes();
1370     const SwOutlineNodes& rOutlNds = rNds.GetOutLineNds();
1371     if( rOutlNds.empty() )
1372         return;
1373 
1374     CurrShell aCurr( this );
1375     SwCallLink aLk( *this ); // watch Cursor-Moves
1376 
1377     if( nSttPos > nEndPos ) // parameters switched?
1378     {
1379         OSL_ENSURE( false, "Start > End for array access" );
1380         std::swap(nSttPos, nEndPos);
1381     }
1382 
1383     SwNode* pSttNd = rOutlNds[ nSttPos ];
1384     SwNode* pEndNd = rOutlNds[ nEndPos ];
1385 
1386     if (pOutlNdsInline)
1387     {
1388         pSttNd = const_cast<SwNode*>(SwOutlineNodes::GetRootNode(pSttNd));
1389 
1390         SwOutlineNodesInline::size_type nEndPosInline;
1391         pOutlNdsInline->Seek_Entry( pEndNd, &nEndPosInline );
1392         assert(nEndPosInline != SwOutlineNodesInline::npos && "always sets some number <= pOutlNdsInline->size()");
1393 
1394         // headings in flys
1395         if (bWithChildren)
1396         {
1397             const int nLevel = pEndNd->GetTextNode()->GetAttrOutlineLevel() - 1;
1398             for( ++nEndPosInline; nEndPosInline < pOutlNdsInline->size(); ++nEndPosInline )
1399             {
1400                 pEndNd = (*pOutlNdsInline)[ nEndPosInline ];
1401                 const int nNxtLevel = pEndNd->GetTextNode()->GetAttrOutlineLevel()-1;
1402                 if( nNxtLevel <= nLevel )
1403                     break; // EndPos is now on the next one
1404             }
1405             // set anchor node of the fly node
1406             if ( nEndPosInline < pOutlNdsInline->size() )
1407                 pEndNd = const_cast<SwNode*>(SwOutlineNodes::GetRootNode(pEndNd));
1408         }
1409         else if (++nEndPosInline < pOutlNdsInline->size())
1410             pEndNd = const_cast<SwNode*>(SwOutlineNodes::GetRootNode((*pOutlNdsInline)[nEndPosInline]));
1411 
1412         if (nEndPosInline == pOutlNdsInline->size()) // no end found
1413             pEndNd = &rNds.GetEndOfContent();
1414     }
1415     else
1416     {
1417         if (bWithChildren)
1418         {
1419             const int nLevel = pEndNd->GetTextNode()->GetAttrOutlineLevel()-1;
1420             for( ++nEndPos; nEndPos < rOutlNds.size(); ++nEndPos )
1421             {
1422                 pEndNd = rOutlNds[ nEndPos ];
1423                 const int nNxtLevel = pEndNd->GetTextNode()->GetAttrOutlineLevel()-1;
1424                 if( nNxtLevel <= nLevel )
1425                     break; // EndPos is now on the next one
1426             }
1427         }
1428         // if without children then set onto next one
1429         else if (++nEndPos < rOutlNds.size())
1430             pEndNd = rOutlNds[ nEndPos ];
1431 
1432         if (nEndPos == rOutlNds.size()) // no end found
1433             pEndNd = &rNds.GetEndOfContent();
1434     }
1435 
1436     if( bKillPams )
1437         KillPams();
1438 
1439     SwCursorSaveState aSaveState( *m_pCurrentCursor );
1440 
1441     // set end to the end of the previous content node
1442     m_pCurrentCursor->GetPoint()->Assign(*pSttNd);
1443     m_pCurrentCursor->SetMark();
1444     m_pCurrentCursor->GetPoint()->Assign(*pEndNd);
1445     m_pCurrentCursor->Move( fnMoveBackward, GoInNode ); // end of predecessor
1446 
1447     // and everything is already selected
1448     bool bRet = !m_pCurrentCursor->IsSelOvr();
1449     if( bRet )
1450         UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
1451 }
1452 
1453 /// jump to reference marker
GotoRefMark(const SwMarkName & rRefMark,ReferencesSubtype nSubType,sal_uInt16 nSeqNo,sal_uInt16 nFlags)1454 bool SwCursorShell::GotoRefMark( const SwMarkName& rRefMark, ReferencesSubtype nSubType,
1455                                     sal_uInt16 nSeqNo, sal_uInt16 nFlags )
1456 {
1457     CurrShell aCurr( this );
1458     SwCallLink aLk( *this ); // watch Cursor-Moves
1459     SwCursorSaveState aSaveState( *m_pCurrentCursor );
1460 
1461     sal_Int32 nPos = -1;
1462 
1463     SwPaM* pCursor = GetCursor();
1464     SwPosition* pPos = pCursor->GetPoint();
1465     SwTextNode* pRefTextNd = pPos->GetNode().GetTextNode();
1466     SwContentFrame* pRefFrame = GetCurrFrame();
1467 
1468     SwTextNode* pTextNd = SwGetRefFieldType::FindAnchor(GetDoc(), rRefMark,
1469                                 nSubType, nSeqNo, nFlags, &nPos, nullptr, GetLayout(), pRefTextNd, pRefFrame);
1470     if( !pTextNd || !pTextNd->GetNodes().IsDocNodes() )
1471         return false;
1472 
1473     m_pCurrentCursor->GetPoint()->Assign(*pTextNd, nPos );
1474 
1475     if( m_pCurrentCursor->IsSelOvr() )
1476         return false;
1477 
1478     UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
1479     return true;
1480 }
1481 
IsPageAtPos(const Point & rPt) const1482 bool SwCursorShell::IsPageAtPos( const Point &rPt ) const
1483 {
1484     if( GetLayout() )
1485         return nullptr != GetLayout()->GetPageAtPos( rPt );
1486     return false;
1487 }
1488 
GetContentAtPos(const Point & rPt,SwContentAtPos & rContentAtPos,bool bSetCursor,SwRect * pFieldRect)1489 bool SwCursorShell::GetContentAtPos( const Point& rPt,
1490                                    SwContentAtPos& rContentAtPos,
1491                                    bool bSetCursor,
1492                                    SwRect* pFieldRect )
1493 {
1494     CurrShell aCurr( this );
1495     bool bRet = false;
1496 
1497     if( IsTableMode() )
1498     {
1499         rContentAtPos.eContentAtPos = IsAttrAtPos::NONE;
1500         rContentAtPos.aFnd.pField = nullptr;
1501         return false;
1502     }
1503 
1504     Point aPt( rPt );
1505     SwPosition aPos( *m_pCurrentCursor->GetPoint() );
1506 
1507     SwTextNode* pTextNd;
1508     SwCursorMoveState aTmpState;
1509     aTmpState.m_bFieldInfo = true;
1510     aTmpState.m_bExactOnly = !( IsAttrAtPos::Outline & rContentAtPos.eContentAtPos );
1511     aTmpState.m_bContentCheck = bool(IsAttrAtPos::ContentCheck & rContentAtPos.eContentAtPos);
1512     aTmpState.m_bSetInReadOnly = IsReadOnlyAvailable();
1513     aTmpState.m_bPosMatchesBounds = true; // treat last half of character same as first half
1514 
1515     SwSpecialPos aSpecialPos;
1516     aTmpState.m_pSpecialPos = ( IsAttrAtPos::SmartTag & rContentAtPos.eContentAtPos ) ?
1517                             &aSpecialPos : nullptr;
1518 
1519     const bool bCursorFoundExact = GetLayout()->GetModelPositionForViewPoint( &aPos, aPt, &aTmpState );
1520     pTextNd = aPos.GetNode().GetTextNode();
1521 
1522     const SwNodes& rNds = GetDoc()->GetNodes();
1523     if( pTextNd
1524         && IsAttrAtPos::Outline & rContentAtPos.eContentAtPos
1525         && !rNds.GetOutLineNds().empty() )
1526     {
1527         // only for nodes in outline nodes
1528         SwOutlineNodes::size_type nPos = 0;
1529         bool bFoundOutline = rNds.GetOutLineNds().Seek_Entry(pTextNd, &nPos);
1530         if (!bFoundOutline && nPos && (IsAttrAtPos::AllowContaining & rContentAtPos.eContentAtPos))
1531         {
1532             // nPos points to the first found outline node not before pTextNd, or to end();
1533             // when bFoundOutline is false, and nPos is not 0, it means that there were
1534             // outline nodes before pTextNd, and nPos-1 points to the last of those.
1535             pTextNd = rNds.GetOutLineNds()[nPos - 1]->GetTextNode();
1536             bFoundOutline = true;
1537         }
1538         if (bFoundOutline)
1539         {
1540             rContentAtPos.eContentAtPos = IsAttrAtPos::Outline;
1541             rContentAtPos.sStr = sw::GetExpandTextMerged(GetLayout(), *pTextNd, true, false, ExpandMode::ExpandFootnote);
1542             rContentAtPos.aFnd.pNode = pTextNd;
1543             bRet = true;
1544         }
1545     }
1546     else if ( IsAttrAtPos::ContentCheck & rContentAtPos.eContentAtPos
1547               && bCursorFoundExact )
1548     {
1549         bRet = true;
1550     }
1551     else if( pTextNd
1552              && IsAttrAtPos::NumLabel & rContentAtPos.eContentAtPos)
1553     {
1554         bRet = aTmpState.m_bInNumPortion;
1555         rContentAtPos.aFnd.pNode = sw::GetParaPropsNode(*GetLayout(), aPos.GetNode());
1556 
1557         Size aSizeLogic(aTmpState.m_nInNumPortionOffset, 0);
1558         Size aSizePixel = GetWin()->LogicToPixel(aSizeLogic);
1559         rContentAtPos.nDist = aSizePixel.Width();
1560     }
1561     else if( bCursorFoundExact && pTextNd )
1562     {
1563         SwContentFrame *pFrame(nullptr);
1564         if( !aTmpState.m_bPosCorr )
1565         {
1566             SwTextAttr* pTextAttr;
1567             if ( IsAttrAtPos::SmartTag & rContentAtPos.eContentAtPos
1568                  && !aTmpState.m_bFootnoteNoInfo )
1569             {
1570                 const SwWrongList* pSmartTagList = pTextNd->GetSmartTags();
1571                 sal_Int32 nCurrent = aPos.GetContentIndex();
1572                 const sal_Int32 nBegin = nCurrent;
1573                 sal_Int32 nLen = 1;
1574 
1575                 if (pSmartTagList && pSmartTagList->InWrongWord(nCurrent, nLen) && !pTextNd->IsSymbolAt(nBegin))
1576                 {
1577                     const sal_uInt16 nIndex = pSmartTagList->GetWrongPos( nBegin );
1578                     const SwWrongList* pSubList = pSmartTagList->SubList( nIndex );
1579                     if ( pSubList )
1580                     {
1581                         nCurrent = aTmpState.m_pSpecialPos->nCharOfst;
1582 
1583                         if ( pSubList->InWrongWord( nCurrent, nLen ) )
1584                             bRet = true;
1585                     }
1586                     else
1587                         bRet = true;
1588 
1589                     if( bRet && bSetCursor )
1590                     {
1591                         SwCursorSaveState aSaveState( *m_pCurrentCursor );
1592                         SwCallLink aLk( *this ); // watch Cursor-Moves
1593                         m_pCurrentCursor->DeleteMark();
1594                         *m_pCurrentCursor->GetPoint() = aPos;
1595                         if( m_pCurrentCursor->IsSelOvr( SwCursorSelOverFlags::CheckNodeSection | SwCursorSelOverFlags::Toggle) )
1596                             bRet = false;
1597                         else
1598                             UpdateCursor();
1599                     }
1600                     if( bRet )
1601                     {
1602                         rContentAtPos.eContentAtPos = IsAttrAtPos::SmartTag;
1603 
1604                         std::pair<Point, bool> tmp(aPt, true);
1605                         if (pFieldRect)
1606                         {
1607                             pFrame = pTextNd->getLayoutFrame(GetLayout(), nullptr, &tmp);
1608                             if (pFrame)
1609                                 pFrame->GetCharRect( *pFieldRect, aPos, &aTmpState );
1610                         }
1611                     }
1612                 }
1613             }
1614 
1615             if ( !bRet
1616                  && ( IsAttrAtPos::Field | IsAttrAtPos::ClickField ) & rContentAtPos.eContentAtPos
1617                  && !aTmpState.m_bFootnoteNoInfo )
1618             {
1619                 pTextAttr = pTextNd->GetFieldTextAttrAt( aPos.GetContentIndex() );
1620                 const SwField* pField = pTextAttr != nullptr
1621                                       ? pTextAttr->GetFormatField().GetField()
1622                                       : nullptr;
1623                 if ( IsAttrAtPos::ClickField & rContentAtPos.eContentAtPos
1624                      && pField && !pField->HasClickHdl() )
1625                 {
1626                     pField = nullptr;
1627                 }
1628 
1629                 if ( pField )
1630                 {
1631                     if (pFieldRect)
1632                     {
1633                         std::pair<Point, bool> tmp(aPt, true);
1634                         pFrame = pTextNd->getLayoutFrame(GetLayout(), nullptr, &tmp);
1635                         if (pFrame)
1636                         {
1637                             //tdf#116397 now that we looking for the bounds of the field drop the SmartTag
1638                             //index within field setting so we don't the bounds of the char within the field
1639                             SwSpecialPos* pSpecialPos = aTmpState.m_pSpecialPos;
1640                             aTmpState.m_pSpecialPos = nullptr;
1641                             pFrame->GetCharRect( *pFieldRect, aPos, &aTmpState );
1642                             aTmpState.m_pSpecialPos = pSpecialPos;
1643                         }
1644                     }
1645 
1646                     if( bSetCursor )
1647                     {
1648                         SwCallLink aLk( *this ); // watch Cursor-Moves
1649                         SwCursorSaveState aSaveState( *m_pCurrentCursor );
1650                         m_pCurrentCursor->DeleteMark();
1651                         *m_pCurrentCursor->GetPoint() = aPos;
1652                         if( m_pCurrentCursor->IsSelOvr() )
1653                         {
1654                             // allow click fields in protected sections
1655                             // only placeholder is not possible
1656                             if( IsAttrAtPos::Field & rContentAtPos.eContentAtPos
1657                                 || SwFieldIds::JumpEdit == pField->Which() )
1658                                 pField = nullptr;
1659                         }
1660                         else
1661                             UpdateCursor();
1662                     }
1663                     else if( SwFieldIds::Table == pField->Which() &&
1664                         static_cast<const SwTableField*>(pField)->IsIntrnlName() )
1665                     {
1666                         // create from internal (for CORE) the external
1667                         // (for UI) formula
1668                         const SwTableNode* pTableNd = pTextNd->FindTableNode();
1669                         if( pTableNd )        // is in a table
1670                             const_cast<SwTableField*>(static_cast<const SwTableField*>(pField))->PtrToBoxNm( &pTableNd->GetTable() );
1671                     }
1672                 }
1673 
1674                 if( pField )
1675                 {
1676                     rContentAtPos.aFnd.pField = pField;
1677                     rContentAtPos.pFndTextAttr = pTextAttr;
1678                     rContentAtPos.eContentAtPos = IsAttrAtPos::Field;
1679                     bRet = true;
1680                 }
1681             }
1682 
1683             if( !bRet && IsAttrAtPos::FormControl & rContentAtPos.eContentAtPos )
1684             {
1685                 IDocumentMarkAccess* pMarksAccess = GetDoc()->getIDocumentMarkAccess( );
1686                 sw::mark::Fieldmark* pFieldBookmark = pMarksAccess->getInnerFieldmarkFor(aPos);
1687                 if (bCursorFoundExact && pFieldBookmark)
1688                 {
1689                     rContentAtPos.eContentAtPos = IsAttrAtPos::FormControl;
1690                     rContentAtPos.aFnd.pFieldmark = pFieldBookmark;
1691                     bRet=true;
1692                 }
1693             }
1694 
1695             if (!bRet && rContentAtPos.eContentAtPos & IsAttrAtPos::ContentControl)
1696             {
1697                 SwTextAttr* pAttr = pTextNd->GetTextAttrAt(
1698                     aPos.GetContentIndex(), RES_TXTATR_CONTENTCONTROL, ::sw::GetTextAttrMode::Parent);
1699                 if (pAttr)
1700                 {
1701                     rContentAtPos.eContentAtPos = IsAttrAtPos::ContentControl;
1702                     rContentAtPos.pFndTextAttr = pAttr;
1703                     bRet = true;
1704                 }
1705             }
1706 
1707             if( !bRet && IsAttrAtPos::Footnote & rContentAtPos.eContentAtPos )
1708             {
1709                 if( aTmpState.m_bFootnoteNoInfo )
1710                 {
1711                     // over the footnote's char
1712                     bRet = true;
1713                     if( bSetCursor )
1714                     {
1715                         *m_pCurrentCursor->GetPoint() = aPos;
1716                         if( !GotoFootnoteAnchor() )
1717                             bRet = false;
1718                     }
1719                     if( bRet )
1720                         rContentAtPos.eContentAtPos = IsAttrAtPos::Footnote;
1721                 }
1722                 else if ( nullptr != ( pTextAttr = pTextNd->GetTextAttrForCharAt(
1723                     aPos.GetContentIndex(), RES_TXTATR_FTN )) )
1724                 {
1725                     bRet = true;
1726                     if( bSetCursor )
1727                     {
1728                         if (SwWrtShell* pWrtSh = dynamic_cast<SwWrtShell*>(this))
1729                             pWrtSh->addCurrentPosition();
1730 
1731                         SwCallLink aLk( *this ); // watch Cursor-Moves
1732                         SwCursorSaveState aSaveState( *m_pCurrentCursor );
1733                         m_pCurrentCursor->GetPoint()->Assign( *static_cast<SwTextFootnote*>(pTextAttr)->GetStartNode() );
1734                         SwContentNode* pCNd = SwNodes::GoNextSection(
1735                             m_pCurrentCursor->GetPoint(),
1736                             true, !IsReadOnlyAvailable() );
1737 
1738                         if( pCNd )
1739                         {
1740                             if( m_pCurrentCursor->IsSelOvr( SwCursorSelOverFlags::CheckNodeSection |
1741                                 SwCursorSelOverFlags::Toggle ))
1742                                 bRet = false;
1743                             else
1744                                 UpdateCursor();
1745                         }
1746                         else
1747                             bRet = false;
1748                     }
1749 
1750                     if( bRet )
1751                     {
1752                         rContentAtPos.eContentAtPos = IsAttrAtPos::Footnote;
1753                         rContentAtPos.pFndTextAttr = pTextAttr;
1754                         rContentAtPos.aFnd.pAttr = &pTextAttr->GetAttr();
1755 
1756                         if (pFieldRect)
1757                         {
1758                             std::pair<Point, bool> tmp(aPt, true);
1759                             pFrame = pTextNd->getLayoutFrame(GetLayout(), nullptr, &tmp);
1760                             if (pFrame)
1761                                 pFrame->GetCharRect( *pFieldRect, aPos, &aTmpState );
1762                         }
1763                     }
1764                 }
1765             }
1766 
1767             if( !bRet
1768                 && ( IsAttrAtPos::ToxMark | IsAttrAtPos::RefMark ) & rContentAtPos.eContentAtPos
1769                 && !aTmpState.m_bFootnoteNoInfo )
1770             {
1771                 pTextAttr = nullptr;
1772                 if( IsAttrAtPos::ToxMark & rContentAtPos.eContentAtPos )
1773                 {
1774                     std::vector<SwTextAttr *> const marks(
1775                         pTextNd->GetTextAttrsAt(
1776                            aPos.GetContentIndex(), RES_TXTATR_TOXMARK));
1777                     if (!marks.empty())
1778                     {   // hmm... can only return 1 here
1779                         pTextAttr = *marks.begin();
1780                     }
1781                 }
1782 
1783                 if( !pTextAttr &&
1784                     IsAttrAtPos::RefMark & rContentAtPos.eContentAtPos )
1785                 {
1786                     std::vector<SwTextAttr *> const marks(
1787                         pTextNd->GetTextAttrsAt(
1788                            aPos.GetContentIndex(), RES_TXTATR_REFMARK));
1789                     if (!marks.empty())
1790                     {   // hmm... can only return 1 here
1791                         pTextAttr = *marks.begin();
1792                     }
1793                 }
1794 
1795                 if( pTextAttr )
1796                 {
1797                     bRet = true;
1798                     if( bSetCursor )
1799                     {
1800                         SwCallLink aLk( *this ); // watch Cursor-Moves
1801                         SwCursorSaveState aSaveState( *m_pCurrentCursor );
1802                         m_pCurrentCursor->DeleteMark();
1803                         *m_pCurrentCursor->GetPoint() = aPos;
1804                         if( m_pCurrentCursor->IsSelOvr( SwCursorSelOverFlags::CheckNodeSection | SwCursorSelOverFlags::Toggle ) )
1805                             bRet = false;
1806                         else
1807                             UpdateCursor();
1808                     }
1809 
1810                     if( bRet )
1811                     {
1812                         OUStringBuffer aStringBuffer;
1813                         if (RES_TXTATR_TOXMARK == pTextAttr->Which())
1814                         {
1815                             // tdf#143157 - include first and secondary keys in index fields
1816                             const auto& aSwTOXMark = pTextAttr->GetTOXMark();
1817                             const auto aSecondaryKey = aSwTOXMark.GetSecondaryKey();
1818 
1819                             aStringBuffer.append(aSwTOXMark.GetPrimaryKey());
1820                             if (!aSecondaryKey.isEmpty())
1821                             {
1822                                 if (!aStringBuffer.isEmpty())
1823                                     aStringBuffer.append(" > ");
1824                                 aStringBuffer.append(aSecondaryKey);
1825                             }
1826 
1827                             const auto aAlternativeText = aSwTOXMark.GetAlternativeText();
1828                             if (!aStringBuffer.isEmpty() && !aAlternativeText.isEmpty())
1829                                 aStringBuffer.append(" > ");
1830                             aStringBuffer.append(aAlternativeText);
1831                         }
1832 
1833                         // tdf#143157 - include expanded text in index fields
1834                         const sal_Int32* pEnd = pTextAttr->GetEnd();
1835                         if (pEnd)
1836                         {
1837                             const auto aExpandText = pTextNd->GetExpandText(
1838                                 GetLayout(), pTextAttr->GetStart(), *pEnd - pTextAttr->GetStart());
1839                             if (!aStringBuffer.isEmpty() && !aExpandText.isEmpty())
1840                                 aStringBuffer.append(" > ");
1841                             aStringBuffer.append(aExpandText);
1842                         }
1843                         rContentAtPos.sStr = aStringBuffer.makeStringAndClear();
1844 
1845                         rContentAtPos.eContentAtPos =
1846                             RES_TXTATR_TOXMARK == pTextAttr->Which()
1847                             ? IsAttrAtPos::ToxMark
1848                             : IsAttrAtPos::RefMark;
1849                         rContentAtPos.pFndTextAttr = pTextAttr;
1850                         rContentAtPos.aFnd.pAttr = &pTextAttr->GetAttr();
1851 
1852                         std::pair<Point, bool> tmp(aPt, true);
1853                         if (pFieldRect)
1854                         {
1855                             pFrame = pTextNd->getLayoutFrame(GetLayout(), nullptr, &tmp);
1856                             if (pFrame)
1857                                 pFrame->GetCharRect( *pFieldRect, aPos, &aTmpState );
1858                         }
1859                     }
1860                 }
1861             }
1862 
1863             if ( !bRet
1864                  && IsAttrAtPos::InetAttr & rContentAtPos.eContentAtPos
1865                  && !aTmpState.m_bFootnoteNoInfo )
1866             {
1867                 sal_Int32 index = aPos.GetContentIndex();
1868                 pTextAttr = pTextNd->GetTextAttrAt(index, RES_TXTATR_INETFMT);
1869 
1870                 // "detect" only INetAttrs with URLs
1871                 if( pTextAttr && !pTextAttr->GetINetFormat().GetValue().isEmpty() )
1872                 {
1873                     bRet = true;
1874                     if( bSetCursor )
1875                     {
1876                         SwCursorSaveState aSaveState( *m_pCurrentCursor );
1877                         SwCallLink aLk( *this ); // watch Cursor-Moves
1878                         m_pCurrentCursor->DeleteMark();
1879                         *m_pCurrentCursor->GetPoint() = aPos;
1880                         if( m_pCurrentCursor->IsSelOvr( SwCursorSelOverFlags::CheckNodeSection |
1881                             SwCursorSelOverFlags::Toggle) )
1882                             bRet = false;
1883                         else
1884                             UpdateCursor();
1885                     }
1886                     if( bRet )
1887                     {
1888                         const sal_Int32 nSt = pTextAttr->GetStart();
1889                         const sal_Int32 nEnd = *pTextAttr->End();
1890 
1891                         rContentAtPos.sStr = pTextNd->GetExpandText(GetLayout(), nSt, nEnd-nSt);
1892 
1893                         rContentAtPos.aFnd.pAttr = &pTextAttr->GetAttr();
1894                         rContentAtPos.eContentAtPos = IsAttrAtPos::InetAttr;
1895                         rContentAtPos.pFndTextAttr = pTextAttr;
1896 
1897                         if (pFieldRect)
1898                         {
1899                             std::pair<Point, bool> tmp(aPt, true);
1900                             pFrame = pTextNd->getLayoutFrame(GetLayout(), nullptr, &tmp);
1901                             if (pFrame)
1902                             {
1903                                 //get bounding box of range
1904                                 SwRect aStart;
1905                                 SwPosition aStartPos(*pTextNd, nSt);
1906                                 pFrame->GetCharRect(aStart, aStartPos, &aTmpState);
1907                                 SwRect aEnd;
1908                                 SwPosition aEndPos(*pTextNd, nEnd);
1909                                 pFrame->GetCharRect(aEnd, aEndPos, &aTmpState);
1910                                 if (aStart.Top() != aEnd.Top() || aStart.Bottom() != aEnd.Bottom())
1911                                 {
1912                                     aStart.Left(pFrame->getFrameArea().Left());
1913                                     aEnd.Right(pFrame->getFrameArea().Right());
1914                                 }
1915                                 *pFieldRect = aStart.Union(aEnd);
1916                             }
1917                         }
1918                     }
1919                 }
1920             }
1921 
1922             if( !bRet && IsAttrAtPos::Redline & rContentAtPos.eContentAtPos )
1923             {
1924                 SwRedlineTable::size_type index;
1925                 IDocumentRedlineAccess const& rIDRA{GetDoc()->getIDocumentRedlineAccess()};
1926                 const SwRangeRedline* pRedl{rIDRA.GetRedline(aPos, &index)};
1927 
1928                 if( pRedl )
1929                 {
1930                     // treat insert/delete as more important than formatting
1931                     for (; index < rIDRA.GetRedlineTable().size(); ++index)
1932                     {
1933                         SwRangeRedline const*const pTmp{rIDRA.GetRedlineTable()[index]};
1934                         if (aPos < *pTmp->Start())
1935                         {
1936                             break;
1937                         }
1938                         switch (pRedl->GetType())
1939                         {
1940                             case RedlineType::Format:
1941                             case RedlineType::FmtColl:
1942                             case RedlineType::ParagraphFormat:
1943                                 switch (pTmp->GetType())
1944                                 {
1945                                     case RedlineType::Insert:
1946                                     case RedlineType::Delete:
1947                                         pRedl = pTmp;
1948                                         break;
1949                                     default:
1950                                         break;
1951                                 }
1952                             break;
1953                             default:
1954                                 break;
1955                         }
1956                     };
1957 
1958                     rContentAtPos.aFnd.pRedl = pRedl;
1959                     rContentAtPos.eContentAtPos = IsAttrAtPos::Redline;
1960                     rContentAtPos.pFndTextAttr = nullptr;
1961                     bRet = true;
1962 
1963                     if (pFieldRect)
1964                     {
1965                         std::pair<Point, bool> tmp(aPt, true);
1966                         pFrame = pTextNd->getLayoutFrame(GetLayout(), nullptr, &tmp);
1967                         if( pFrame )
1968                         {
1969                             // not sure if this should be limited to one
1970                             // paragraph, or mark the entire redline; let's
1971                             // leave it limited to one for now...
1972                             sal_Int32 nStart;
1973                             sal_Int32 nEnd;
1974                             pRedl->CalcStartEnd(pTextNd->GetIndex(), nStart, nEnd);
1975                             if (nStart == COMPLETE_STRING)
1976                             {
1977                                 // consistency: found pRedl, so there must be
1978                                 // something in pTextNd
1979                                 assert(nEnd != COMPLETE_STRING);
1980                                 nStart = 0;
1981                             }
1982                             if (nEnd == COMPLETE_STRING)
1983                             {
1984                                 nEnd = pTextNd->Len();
1985                             }
1986                             //get bounding box of range
1987                             SwRect aStart;
1988                             pFrame->GetCharRect(aStart, SwPosition(*pTextNd, nStart), &aTmpState);
1989                             SwRect aEnd;
1990                             pFrame->GetCharRect(aEnd, SwPosition(*pTextNd, nEnd), &aTmpState);
1991                             if (aStart.Top() != aEnd.Top() || aStart.Bottom() != aEnd.Bottom())
1992                             {
1993                                 aStart.Left(pFrame->getFrameArea().Left());
1994                                 aEnd.Right(pFrame->getFrameArea().Right());
1995                             }
1996                             *pFieldRect = aStart.Union(aEnd);
1997                         }
1998                     }
1999                 }
2000             }
2001         }
2002 
2003         if( !bRet && ( ( IsAttrAtPos::TableRedline & rContentAtPos.eContentAtPos ) ||
2004                      ( IsAttrAtPos::TableColRedline & rContentAtPos.eContentAtPos ) ) )
2005         {
2006             const SwTableNode* pTableNd;
2007             const SwTableBox* pBox;
2008             const SwTableLine* pTableLine;
2009             const SwStartNode* pSttNd = pTextNd->FindTableBoxStartNode();
2010             if( pSttNd && nullptr != ( pTableNd = pTextNd->FindTableNode()) &&
2011                 nullptr != ( pBox = pTableNd->GetTable().GetTableBox(
2012                 pSttNd->GetIndex() )) &&
2013                 nullptr != ( pTableLine = pBox->GetUpper() ) &&
2014                 ( RedlineType::None != pBox->GetRedlineType() ||
2015                 RedlineType::None != pTableLine->GetRedlineType() ) )
2016             {
2017                 const SwRedlineTable& aRedlineTable = GetDoc()->getIDocumentRedlineAccess().GetRedlineTable();
2018                 if ( RedlineType::None != pTableLine->GetRedlineType() )
2019                 {
2020                     SwRedlineTable::size_type nPos = 0;
2021                     nPos = pTableLine->UpdateTextChangesOnly(nPos);
2022                     if ( nPos != SwRedlineTable::npos )
2023                     {
2024                         rContentAtPos.aFnd.pRedl = aRedlineTable[nPos];
2025                         rContentAtPos.eContentAtPos = IsAttrAtPos::TableRedline;
2026                         bRet = true;
2027                     }
2028                 }
2029                 else
2030                 {
2031                     SwRedlineTable::size_type n = 0;
2032                     SwNodeIndex aIdx( *pSttNd, 1 );
2033                     const SwPosition aBoxStart(aIdx);
2034                     const SwRangeRedline* pFnd = aRedlineTable.FindAtPosition( aBoxStart, n, /*next=*/true );
2035                     if( pFnd && RedlineType::Delete == pFnd->GetType() )
2036                     {
2037                         rContentAtPos.aFnd.pRedl = aRedlineTable[n];
2038                         rContentAtPos.eContentAtPos = IsAttrAtPos::TableColRedline;
2039                         bRet = true;
2040                     }
2041                 }
2042             }
2043         }
2044 
2045         if( !bRet
2046              && ( IsAttrAtPos::TableBoxFml & rContentAtPos.eContentAtPos
2047 #ifdef DBG_UTIL
2048                   || IsAttrAtPos::TableBoxValue & rContentAtPos.eContentAtPos
2049 #endif
2050             ) )
2051         {
2052             const SwTableNode* pTableNd;
2053             const SwTableBox* pBox;
2054             const SwStartNode* pSttNd = pTextNd->FindTableBoxStartNode();
2055             const SwTableBoxFormula* pItem;
2056 #ifdef DBG_UTIL
2057             const SwTableBoxValue* pItem2 = nullptr;
2058 #endif
2059             if( pSttNd && nullptr != ( pTableNd = pTextNd->FindTableNode()) &&
2060                 nullptr != ( pBox = pTableNd->GetTable().GetTableBox(
2061                 pSttNd->GetIndex() )) &&
2062 #ifdef DBG_UTIL
2063                 ( (pItem = pBox->GetFrameFormat()->GetItemIfSet( RES_BOXATR_FORMULA, false )) ||
2064                   (pItem2 = pBox->GetFrameFormat()->GetItemIfSet( RES_BOXATR_VALUE, false )) )
2065 #else
2066                 (pItem = pBox->GetFrameFormat()->GetItemIfSet( RES_BOXATR_FORMULA, false ))
2067 #endif
2068                 )
2069             {
2070                 std::pair<Point, bool> tmp(aPt, true);
2071                 SwFrame* pF = pTextNd->getLayoutFrame(GetLayout(), nullptr, &tmp);
2072                 if( pF )
2073                 {
2074                     // then the CellFrame
2075                     pFrame = static_cast<SwContentFrame*>(pF);
2076                     while( pF && !pF->IsCellFrame() )
2077                         pF = pF->GetUpper();
2078                 }
2079 
2080                 if( aTmpState.m_bPosCorr )
2081                 {
2082                     if( pF && !pF->getFrameArea().Contains( aPt ))
2083                         pF = nullptr;
2084                 }
2085                 else if( !pF )
2086                     pF = pFrame;
2087 
2088                 if( pF ) // only then it is valid
2089                 {
2090                     // create from internal (for CORE) the external
2091                     // (for UI) formula
2092                     rContentAtPos.eContentAtPos = IsAttrAtPos::TableBoxFml;
2093 #ifdef DBG_UTIL
2094                     if( pItem2 )
2095                         rContentAtPos.eContentAtPos = IsAttrAtPos::TableBoxValue;
2096                     else
2097 #endif
2098                         const_cast<SwTableBoxFormula&>(*pItem).PtrToBoxNm( &pTableNd->GetTable() );
2099 
2100                     bRet = true;
2101                     if( bSetCursor )
2102                     {
2103                         SwCallLink aLk( *this ); // watch Cursor-Moves
2104                         SwCursorSaveState aSaveState( *m_pCurrentCursor );
2105                         *m_pCurrentCursor->GetPoint() = std::move(aPos);
2106                         if( m_pCurrentCursor->IsSelOvr( SwCursorSelOverFlags::CheckNodeSection |
2107                             SwCursorSelOverFlags::Toggle) )
2108                             bRet = false;
2109                         else
2110                             UpdateCursor();
2111                     }
2112 
2113                     if( bRet )
2114                     {
2115                         if( pFieldRect )
2116                         {
2117                             *pFieldRect = pF->getFramePrintArea();
2118                             *pFieldRect += pF->getFrameArea().Pos();
2119                         }
2120                         rContentAtPos.pFndTextAttr = nullptr;
2121                         rContentAtPos.aFnd.pAttr = pItem;
2122                     }
2123                 }
2124             }
2125         }
2126 
2127 #ifdef DBG_UTIL
2128         if( !bRet && IsAttrAtPos::CurrAttrs & rContentAtPos.eContentAtPos )
2129         {
2130             const sal_Int32 n = aPos.GetContentIndex();
2131             SfxItemSetFixed<POOLATTR_BEGIN, POOLATTR_END - 1>  aSet( GetDoc()->GetAttrPool() );
2132             if( pTextNd->GetpSwpHints() )
2133             {
2134                 for( size_t i = 0; i < pTextNd->GetSwpHints().Count(); ++i )
2135                 {
2136                     const SwTextAttr* pHt = pTextNd->GetSwpHints().Get(i);
2137                     const sal_Int32 nAttrStart = pHt->GetStart();
2138                     if( nAttrStart > n ) // over the section
2139                         break;
2140 
2141                     if( nullptr != pHt->End() && (
2142                         ( nAttrStart < n &&
2143                         ( pHt->DontExpand() ? n < *pHt->End()
2144                         : n <= *pHt->End() )) ||
2145                         ( n == nAttrStart &&
2146                         ( nAttrStart == *pHt->End() || !n ))) )
2147                     {
2148                         aSet.Put( pHt->GetAttr() );
2149                     }
2150                 }
2151                 if( pTextNd->HasSwAttrSet() &&
2152                     pTextNd->GetpSwAttrSet()->Count() )
2153                 {
2154                     SfxItemSet aFormatSet( pTextNd->GetSwAttrSet() );
2155                     // remove all from format set that are also in TextSet
2156                     aFormatSet.Differentiate( aSet );
2157                     // now merge all together
2158                     aSet.Put( aFormatSet );
2159                 }
2160             }
2161             else
2162                 pTextNd->SwContentNode::GetAttr( aSet );
2163 
2164             rContentAtPos.sStr = "Pos: (";
2165             rContentAtPos.sStr += OUString::number( sal_Int32(aPos.GetNodeIndex()));
2166             rContentAtPos.sStr += ":";
2167             rContentAtPos.sStr += OUString::number( aPos.GetContentIndex());
2168             rContentAtPos.sStr += ")";
2169             rContentAtPos.sStr += "\nParagraph Style: ";
2170             rContentAtPos.sStr += pTextNd->GetFormatColl()->GetName().toString();
2171             if( pTextNd->GetCondFormatColl() )
2172             {
2173                 rContentAtPos.sStr += "\nConditional Style: " + pTextNd->GetCondFormatColl()->GetName().toString();
2174             }
2175 
2176             if( aSet.Count() )
2177             {
2178                 OUStringBuffer sAttrs;
2179                 SfxItemIter aIter( aSet );
2180                 const SfxPoolItem* pItem = aIter.GetCurItem();
2181                 const IntlWrapper aInt(SvtSysLocale().GetUILanguageTag());
2182                 do
2183                 {
2184                     if( !IsInvalidItem( pItem ))
2185                     {
2186                         OUString aStr;
2187                         GetDoc()->GetAttrPool().GetPresentation(*pItem,
2188                             MapUnit::MapCM, aStr, aInt);
2189                         if (!sAttrs.isEmpty())
2190                             sAttrs.append(", ");
2191                         sAttrs.append(aStr);
2192                     }
2193                     pItem = aIter.NextItem();
2194                 } while (pItem);
2195                 if (!sAttrs.isEmpty())
2196                 {
2197                     if( !rContentAtPos.sStr.isEmpty() )
2198                         rContentAtPos.sStr += "\n";
2199                     rContentAtPos.sStr += "Attr: " + sAttrs;
2200                 }
2201             }
2202             bRet = true;
2203             rContentAtPos.eContentAtPos = IsAttrAtPos::CurrAttrs;
2204         }
2205 #endif
2206     }
2207 
2208     if( !bRet )
2209     {
2210         rContentAtPos.eContentAtPos = IsAttrAtPos::NONE;
2211         rContentAtPos.aFnd.pField = nullptr;
2212     }
2213     return bRet;
2214 }
2215 
2216 // #i90516#
GetPostItFieldAtCursor() const2217 const SwPostItField* SwCursorShell::GetPostItFieldAtCursor() const
2218 {
2219     if ( IsTableMode() )
2220         return nullptr;
2221 
2222     const SwPosition* pCursorPos = GetCursor_()->GetPoint();
2223     const SwTextNode* pTextNd = pCursorPos->GetNode().GetTextNode();
2224     if ( !pTextNd )
2225         return nullptr;
2226 
2227     const SwPostItField* pPostItField = nullptr;
2228     SwTextAttr* pTextAttr = pTextNd->GetFieldTextAttrAt( pCursorPos->GetContentIndex() );
2229     const SwField* pField = pTextAttr != nullptr ? pTextAttr->GetFormatField().GetField() : nullptr;
2230     if ( pField && pField->Which()== SwFieldIds::Postit )
2231     {
2232         pPostItField = static_cast<const SwPostItField*>(pField);
2233     }
2234 
2235     return pPostItField;
2236 }
2237 
2238 /// is the node in a protected section?
IsInProtectSect() const2239 bool SwContentAtPos::IsInProtectSect() const
2240 {
2241     const SwTextNode* pNd = nullptr;
2242     if( pFndTextAttr )
2243     {
2244         switch( eContentAtPos )
2245         {
2246         case IsAttrAtPos::Field:
2247         case IsAttrAtPos::ClickField:
2248             pNd = static_txtattr_cast<SwTextField const*>(pFndTextAttr)->GetpTextNode();
2249             break;
2250 
2251         case IsAttrAtPos::Footnote:
2252             pNd = &static_cast<const SwTextFootnote*>(pFndTextAttr)->GetTextNode();
2253             break;
2254 
2255         case IsAttrAtPos::InetAttr:
2256             pNd = static_txtattr_cast<SwTextINetFormat const*>(pFndTextAttr)->GetpTextNode();
2257             break;
2258 
2259         default:
2260             break;
2261         }
2262     }
2263 
2264     if( !pNd )
2265         return false;
2266     if( pNd->IsInProtectSect() )
2267         return true;
2268 
2269     const SwContentFrame* pFrame = pNd->getLayoutFrame(pNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, nullptr);
2270     return pFrame && pFrame->IsProtected() ;
2271 }
2272 
IsInRTLText() const2273 bool SwContentAtPos::IsInRTLText()const
2274 {
2275     const SwTextNode* pNd = nullptr;
2276     if (!pFndTextAttr || (eContentAtPos != IsAttrAtPos::Footnote))
2277         return false;
2278 
2279     const SwTextFootnote* pTextFootnote = static_cast<const SwTextFootnote*>(pFndTextAttr);
2280     if(!pTextFootnote->GetStartNode())
2281         return false;
2282 
2283     SwStartNode* pSttNd = pTextFootnote->GetStartNode()->GetNode().GetStartNode();
2284     SwPaM aTemp( *pSttNd );
2285     aTemp.Move(fnMoveForward, GoInNode);
2286     SwContentNode* pContentNode = aTemp.GetPointContentNode();
2287     if(pContentNode && pContentNode->IsTextNode())
2288         pNd = pContentNode->GetTextNode();
2289     if(!pNd)
2290         return false;
2291 
2292     bool bRet = false;
2293     SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pNd);
2294     SwTextFrame* pTmpFrame = aIter.First();
2295     while( pTmpFrame )
2296     {
2297         if ( !pTmpFrame->IsFollow())
2298         {
2299             bRet = pTmpFrame->IsRightToLeft();
2300             break;
2301         }
2302         pTmpFrame = aIter.Next();
2303     }
2304     return bRet;
2305 }
2306 
SelectTextModel(const sal_Int32 nStart,const sal_Int32 nEnd)2307 bool SwCursorShell::SelectTextModel( const sal_Int32 nStart,
2308                                  const sal_Int32 nEnd )
2309 {
2310     CurrShell aCurr( this );
2311     bool bRet = false;
2312 
2313     SwCallLink aLk( *this );
2314     SwCursorSaveState aSaveState( *m_pCurrentCursor );
2315 
2316     SwPosition& rPos = *m_pCurrentCursor->GetPoint();
2317     assert(nEnd <= rPos.GetNode().GetTextNode()->Len());
2318     m_pCurrentCursor->DeleteMark();
2319     rPos.SetContent(nStart);
2320     m_pCurrentCursor->SetMark();
2321     rPos.SetContent(nEnd);
2322 
2323     if( !m_pCurrentCursor->IsSelOvr() )
2324     {
2325         UpdateCursor();
2326         bRet = true;
2327     }
2328 
2329     return bRet;
2330 }
2331 
GetCursorPointAsViewIndex() const2332 TextFrameIndex SwCursorShell::GetCursorPointAsViewIndex() const
2333 {
2334     SwPosition const*const pPos(GetCursor()->GetPoint());
2335     SwTextNode const*const pTextNode(pPos->GetNode().GetTextNode());
2336     assert(pTextNode);
2337     SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(pTextNode->getLayoutFrame(GetLayout())));
2338     assert(pFrame);
2339     return pFrame->MapModelToViewPos(*pPos);
2340 }
2341 
SelectTextView(TextFrameIndex const nStart,TextFrameIndex const nEnd)2342 bool SwCursorShell::SelectTextView(TextFrameIndex const nStart,
2343                                  TextFrameIndex const nEnd)
2344 {
2345     CurrShell aCurr( this );
2346     bool bRet = false;
2347 
2348     SwCallLink aLk( *this );
2349     SwCursorSaveState aSaveState( *m_pCurrentCursor );
2350 
2351     SwPosition& rPos = *m_pCurrentCursor->GetPoint();
2352     m_pCurrentCursor->DeleteMark();
2353     // indexes must correspond to cursor point!
2354     SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(m_pCurrentCursor->GetPoint()->GetNode().GetTextNode()->getLayoutFrame(GetLayout())));
2355     assert(pFrame);
2356     rPos = pFrame->MapViewToModelPos(nStart);
2357     m_pCurrentCursor->SetMark();
2358     rPos = pFrame->MapViewToModelPos(nEnd);
2359 
2360     if (!m_pCurrentCursor->IsSelOvr())
2361     {
2362         UpdateCursor();
2363         bRet = true;
2364     }
2365 
2366     return bRet;
2367 }
2368 
SelectTextAttr(sal_uInt16 nWhich,bool bExpand,const SwTextAttr * pTextAttr)2369 bool SwCursorShell::SelectTextAttr( sal_uInt16 nWhich,
2370                                      bool bExpand,
2371                                      const SwTextAttr* pTextAttr )
2372 {
2373     CurrShell aCurr( this );
2374 
2375     if( IsTableMode() )
2376         return false;
2377 
2378     if( !pTextAttr )
2379     {
2380         SwPosition& rPos = *m_pCurrentCursor->GetPoint();
2381         SwTextNode* pTextNd = rPos.GetNode().GetTextNode();
2382         pTextAttr = pTextNd
2383             ? pTextNd->GetTextAttrAt(rPos.GetContentIndex(),
2384                     nWhich,
2385                     bExpand ? ::sw::GetTextAttrMode::Expand : ::sw::GetTextAttrMode::Default)
2386             : nullptr;
2387     }
2388     if( !pTextAttr )
2389         return false;
2390 
2391     const sal_Int32* pEnd = pTextAttr->End();
2392     sal_Int32 const nEnd(pEnd ? *pEnd : pTextAttr->GetStart() + 1);
2393     assert(nEnd <= m_pCurrentCursor->GetPoint()->GetNode().GetTextNode()->Len());
2394     bool bRet = SelectTextModel(pTextAttr->GetStart(), nEnd);
2395     return bRet;
2396 }
2397 
GotoINetAttr(const SwTextINetFormat & rAttr)2398 bool SwCursorShell::GotoINetAttr( const SwTextINetFormat& rAttr )
2399 {
2400     if( !rAttr.GetpTextNode() )
2401         return false;
2402     SwCursor* pCursor = getShellCursor( true );
2403 
2404     CurrShell aCurr( this );
2405     SwCallLink aLk( *this ); // watch Cursor-Moves
2406     SwCursorSaveState aSaveState( *pCursor );
2407 
2408     pCursor->GetPoint()->Assign(*rAttr.GetpTextNode(), rAttr.GetStart() );
2409     bool bRet = !pCursor->IsSelOvr();
2410     if( bRet )
2411         UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
2412     return bRet;
2413 }
2414 
FindINetAttr(std::u16string_view rName) const2415 const SwFormatINetFormat* SwCursorShell::FindINetAttr( std::u16string_view rName ) const
2416 {
2417     return mxDoc->FindINetAttr( rName );
2418 }
2419 
GetShadowCursorPos(const Point & rPt,SwFillMode eFillMode,SwRect & rRect,sal_Int16 & rOrient)2420 bool SwCursorShell::GetShadowCursorPos( const Point& rPt, SwFillMode eFillMode,
2421                                 SwRect& rRect, sal_Int16& rOrient )
2422 {
2423 
2424     CurrShell aCurr( this );
2425 
2426     if (IsTableMode() || HasSelection()
2427         || !GetDoc()->GetIDocumentUndoRedo().DoesUndo())
2428         return false;
2429 
2430     Point aPt( rPt );
2431     SwPosition aPos( *m_pCurrentCursor->GetPoint() );
2432 
2433     SwFillCursorPos aFPos( eFillMode );
2434     SwCursorMoveState aTmpState( &aFPos );
2435 
2436     bool bRet = false;
2437     if( GetLayout()->GetModelPositionForViewPoint( &aPos, aPt, &aTmpState ) &&
2438         !aPos.GetNode().IsProtect())
2439     {
2440         // start position in protected section?
2441         rRect = aFPos.aCursor;
2442         rOrient = aFPos.eOrient;
2443         bRet = true;
2444     }
2445     return bRet;
2446 }
2447 
SetShadowCursorPos(const Point & rPt,SwFillMode eFillMode)2448 bool SwCursorShell::SetShadowCursorPos( const Point& rPt, SwFillMode eFillMode )
2449 {
2450     CurrShell aCurr( this );
2451 
2452     if (IsTableMode() || HasSelection()
2453         || !GetDoc()->GetIDocumentUndoRedo().DoesUndo())
2454         return false;
2455 
2456     Point aPt( rPt );
2457     SwPosition aPos( *m_pCurrentCursor->GetPoint() );
2458 
2459     SwFillCursorPos aFPos( eFillMode );
2460     SwCursorMoveState aTmpState( &aFPos );
2461 
2462     if( !GetLayout()->GetModelPositionForViewPoint( &aPos, aPt, &aTmpState ) )
2463         return false;
2464 
2465     SwCallLink aLk( *this ); // watch Cursor-Moves
2466     StartAction();
2467 
2468     SwContentNode* pCNd = aPos.GetNode().GetContentNode();
2469     SwUndoId nUndoId = SwUndoId::INS_FROM_SHADOWCRSR;
2470     // If only the paragraph attributes "Adjust" or "LRSpace" are set,
2471     // then the following should not delete those again.
2472     if( 0 == aFPos.nParaCnt + aFPos.nColumnCnt &&
2473         ( SwFillMode::Indent == aFPos.eMode ||
2474           ( text::HoriOrientation::NONE != aFPos.eOrient &&
2475             0 == aFPos.nTabCnt + aFPos.nSpaceCnt )) &&
2476         pCNd && pCNd->Len() )
2477         nUndoId = SwUndoId::EMPTY;
2478 
2479     GetDoc()->GetIDocumentUndoRedo().StartUndo( nUndoId, nullptr );
2480 
2481     SwTextFormatColl* pNextFormat = nullptr;
2482     SwTextNode* pTNd = pCNd ? pCNd->GetTextNode() : nullptr;
2483     if( pTNd )
2484         pNextFormat = &pTNd->GetTextColl()->GetNextTextFormatColl();
2485 
2486     const SwSectionNode* pSectNd = pCNd ? pCNd->FindSectionNode() : nullptr;
2487     if( pSectNd && aFPos.nParaCnt )
2488     {
2489         SwNodeIndex aEnd( aPos.GetNode(), 1 );
2490         while( aEnd.GetNode().IsEndNode() &&
2491                 &aEnd.GetNode() !=
2492                 pSectNd->EndOfSectionNode() )
2493             ++aEnd;
2494 
2495         if( aEnd.GetNode().IsEndNode() &&
2496             pCNd->Len() == aPos.GetContentIndex() )
2497             aPos.Assign( *pSectNd->EndOfSectionNode() );
2498     }
2499 
2500     for( sal_uInt16 n = 0; n < aFPos.nParaCnt + aFPos.nColumnCnt; ++n )
2501     {
2502         GetDoc()->getIDocumentContentOperations().AppendTextNode( aPos );
2503         if( !n && pNextFormat )
2504         {
2505             *m_pCurrentCursor->GetPoint() = aPos;
2506             GetDoc()->SetTextFormatColl( *m_pCurrentCursor, pNextFormat, false );
2507         }
2508         if( n < aFPos.nColumnCnt )
2509         {
2510             *m_pCurrentCursor->GetPoint() = aPos;
2511             GetDoc()->getIDocumentContentOperations().InsertPoolItem( *m_pCurrentCursor,
2512                     SvxFormatBreakItem( SvxBreak::ColumnBefore, RES_BREAK ) );
2513         }
2514     }
2515 
2516     *m_pCurrentCursor->GetPoint() = aPos;
2517     switch( aFPos.eMode )
2518     {
2519     case SwFillMode::Indent:
2520         if( nullptr != (pCNd = aPos.GetNode().GetContentNode() ))
2521         {
2522             assert(pCNd->IsTextNode()); // ???
2523             SfxItemSetFixed<
2524                     RES_PARATR_ADJUST, RES_PARATR_ADJUST,
2525                     RES_MARGIN_FIRSTLINE, RES_MARGIN_TEXTLEFT> aSet(GetDoc()->GetAttrPool());
2526             SvxFirstLineIndentItem firstLine(pCNd->GetAttr(RES_MARGIN_FIRSTLINE));
2527             SvxTextLeftMarginItem leftMargin(pCNd->GetAttr(RES_MARGIN_TEXTLEFT));
2528             firstLine.SetTextFirstLineOffset(SvxIndentValue::zero());
2529             leftMargin.SetTextLeft(SvxIndentValue::twips(aFPos.nTabCnt));
2530             aSet.Put(firstLine);
2531             aSet.Put(leftMargin);
2532 
2533             const SvxAdjustItem& rAdj = pCNd->GetAttr(RES_PARATR_ADJUST);
2534             if( SvxAdjust::Left != rAdj.GetAdjust() )
2535                 aSet.Put( SvxAdjustItem( SvxAdjust::Left, RES_PARATR_ADJUST ) );
2536 
2537             GetDoc()->getIDocumentContentOperations().InsertItemSet( *m_pCurrentCursor, aSet );
2538         }
2539         else {
2540             OSL_ENSURE( false, "No ContentNode" );
2541         }
2542         break;
2543 
2544     case SwFillMode::Tab:
2545     case SwFillMode::TabSpace:
2546     case SwFillMode::Space:
2547         {
2548             OUStringBuffer sInsert;
2549             if (aFPos.eMode == SwFillMode::Space)
2550             {
2551                 comphelper::string::padToLength(sInsert, sInsert.getLength() + aFPos.nSpaceOnlyCnt, ' ');
2552             }
2553             else
2554             {
2555                 if (aFPos.nTabCnt)
2556                     comphelper::string::padToLength(sInsert, aFPos.nTabCnt, '\t');
2557                 if (aFPos.nSpaceCnt)
2558                     comphelper::string::padToLength(sInsert, sInsert.getLength() + aFPos.nSpaceCnt, ' ');
2559             }
2560             if (!sInsert.isEmpty())
2561                 GetDoc()->getIDocumentContentOperations().InsertString( *m_pCurrentCursor, sInsert.makeStringAndClear());
2562         }
2563         [[fallthrough]]; // still need to set orientation
2564     case SwFillMode::Margin:
2565         if( text::HoriOrientation::NONE != aFPos.eOrient )
2566         {
2567             SvxAdjustItem aAdj( SvxAdjust::Left, RES_PARATR_ADJUST );
2568             switch( aFPos.eOrient )
2569             {
2570             case text::HoriOrientation::CENTER:
2571                 aAdj.SetAdjust( SvxAdjust::Center );
2572                 break;
2573             case text::HoriOrientation::RIGHT:
2574                 aAdj.SetAdjust( SvxAdjust::Right );
2575                 break;
2576             default:
2577                 break;
2578             }
2579             GetDoc()->getIDocumentContentOperations().InsertPoolItem( *m_pCurrentCursor, aAdj );
2580         }
2581         break;
2582     }
2583 
2584     GetDoc()->GetIDocumentUndoRedo().EndUndo( nUndoId, nullptr );
2585     EndAction();
2586 
2587     return true;
2588 }
2589 
SelNextRedline()2590 const SwRangeRedline* SwCursorShell::SelNextRedline()
2591 {
2592     if( IsTableMode() )
2593         return nullptr;
2594 
2595     CurrShell aCurr( this );
2596     SwCallLink aLk( *this ); // watch Cursor-Moves
2597     SwCursorSaveState aSaveState( *m_pCurrentCursor );
2598 
2599     // ensure point is at the end so alternating SelNext/SelPrev works
2600     NormalizePam(false);
2601     const SwRangeRedline* pFnd = GetDoc()->getIDocumentRedlineAccess().SelNextRedline( *m_pCurrentCursor );
2602 
2603     // at the end of the document, go to the start of the document, and try again
2604     if ( !pFnd )
2605     {
2606         GetDoc()->GetDocShell()->GetWrtShell()->StartOfSection();
2607         pFnd = GetDoc()->getIDocumentRedlineAccess().SelNextRedline( *m_pCurrentCursor );
2608     }
2609 
2610     if( pFnd && !m_pCurrentCursor->IsInProtectTable() && !m_pCurrentCursor->IsSelOvr() )
2611         UpdateCursor( SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
2612     else
2613         pFnd = nullptr;
2614     return pFnd;
2615 }
2616 
SelPrevRedline()2617 const SwRangeRedline* SwCursorShell::SelPrevRedline()
2618 {
2619     if( IsTableMode() )
2620         return nullptr;
2621 
2622     CurrShell aCurr( this );
2623     SwCallLink aLk( *this ); // watch Cursor-Moves
2624     SwCursorSaveState aSaveState( *m_pCurrentCursor );
2625 
2626     // ensure point is at the start so alternating SelNext/SelPrev works
2627     NormalizePam(true);
2628     const SwRangeRedline* pFnd = GetDoc()->getIDocumentRedlineAccess().SelPrevRedline( *m_pCurrentCursor );
2629 
2630     // at the start of the document, go to the end of the document, and try again
2631     if ( !pFnd )
2632     {
2633         GetDoc()->GetDocShell()->GetWrtShell()->EndOfSection();
2634         pFnd = GetDoc()->getIDocumentRedlineAccess().SelPrevRedline( *m_pCurrentCursor );
2635     }
2636 
2637     if( pFnd && !m_pCurrentCursor->IsInProtectTable() && !m_pCurrentCursor->IsSelOvr() )
2638         UpdateCursor( SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
2639     else
2640         pFnd = nullptr;
2641     return pFnd;
2642 }
2643 
GotoRedline_(SwRedlineTable::size_type nArrPos,bool bSelect)2644 const SwRangeRedline* SwCursorShell::GotoRedline_( SwRedlineTable::size_type nArrPos, bool bSelect )
2645 {
2646     const SwRangeRedline* pFnd = nullptr;
2647     SwCallLink aLk( *this ); // watch Cursor-Moves
2648     SwCursorSaveState aSaveState( *m_pCurrentCursor );
2649 
2650     pFnd = GetDoc()->getIDocumentRedlineAccess().GetRedlineTable()[ nArrPos ];
2651     if( !pFnd )
2652         return nullptr;
2653 
2654     *m_pCurrentCursor->GetPoint() = *pFnd->Start();
2655 
2656     SwPosition* pPtPos = m_pCurrentCursor->GetPoint();
2657     if( !pPtPos->GetNode().IsContentNode() )
2658     {
2659         SwContentNode* pCNd = SwNodes::GoNextSection(pPtPos,
2660                                 true, IsReadOnlyAvailable() );
2661         if( pCNd )
2662         {
2663             if( pPtPos->GetNode() <= pFnd->End()->GetNode() )
2664                 pPtPos->SetContent( 0 );
2665             else
2666                 pFnd = nullptr;
2667         }
2668     }
2669 
2670     if( pFnd && bSelect )
2671     {
2672         m_pCurrentCursor->SetMark();
2673         if( RedlineType::FmtColl == pFnd->GetType() )
2674         {
2675             SwContentNode* pCNd = pPtPos->GetNode().GetContentNode();
2676             m_pCurrentCursor->GetPoint()->SetContent( pCNd->Len() );
2677             m_pCurrentCursor->GetMark()->Assign( *pCNd, 0 );
2678         }
2679         else
2680             *m_pCurrentCursor->GetPoint() = *pFnd->End();
2681 
2682         pPtPos = m_pCurrentCursor->GetPoint();
2683         if( !pPtPos->GetNode().IsContentNode() )
2684         {
2685             SwContentNode* pCNd = SwNodes::GoPrevSection( pPtPos,
2686                                         true, IsReadOnlyAvailable() );
2687             if( pCNd )
2688             {
2689                 if( pPtPos->GetNode() >= m_pCurrentCursor->GetMark()->GetNode() )
2690                     pPtPos->SetContent( pCNd->Len() );
2691                 else
2692                     pFnd = nullptr;
2693             }
2694         }
2695     }
2696 
2697     if( !pFnd )
2698     {
2699         m_pCurrentCursor->DeleteMark();
2700         m_pCurrentCursor->RestoreSavePos();
2701     }
2702     else if( bSelect && *m_pCurrentCursor->GetMark() == *m_pCurrentCursor->GetPoint() )
2703         m_pCurrentCursor->DeleteMark();
2704 
2705     if( pFnd && !m_pCurrentCursor->IsInProtectTable() && !m_pCurrentCursor->IsSelOvr() )
2706         UpdateCursor( SwCursorShell::SCROLLWIN | SwCursorShell::CHKRANGE
2707                     | SwCursorShell::READONLY );
2708     else
2709     {
2710         pFnd = nullptr;
2711         if( bSelect )
2712             m_pCurrentCursor->DeleteMark();
2713     }
2714     return pFnd;
2715 }
2716 
GotoRedline(SwRedlineTable::size_type nArrPos,bool bSelect)2717 const SwRangeRedline* SwCursorShell::GotoRedline( SwRedlineTable::size_type nArrPos, bool bSelect )
2718 {
2719     const SwRangeRedline* pFnd = nullptr;
2720     if( IsTableMode() )
2721         return nullptr;
2722 
2723     CurrShell aCurr( this );
2724 
2725     const SwRedlineTable& rTable = GetDoc()->getIDocumentRedlineAccess().GetRedlineTable();
2726     const SwRangeRedline* pTmp = rTable[ nArrPos ];
2727     sal_uInt16 nSeqNo = pTmp->GetSeqNo();
2728     if( !nSeqNo || !bSelect )
2729     {
2730         pFnd = GotoRedline_( nArrPos, bSelect );
2731         return pFnd;
2732     }
2733 
2734     bool bCheck = false;
2735     int nLoopCnt = 2;
2736     SwRedlineTable::size_type nArrSavPos = nArrPos;
2737 
2738     do {
2739         pTmp = GotoRedline_( nArrPos, true );
2740 
2741         if( !pFnd )
2742             pFnd = pTmp;
2743 
2744         if( pTmp && bCheck )
2745         {
2746             // Check for overlaps. These can happen when FormatColl-
2747             // Redlines were stretched over a whole paragraph
2748             SwPaM* pCur = m_pCurrentCursor;
2749             SwPaM* pNextPam = pCur->GetNext();
2750             auto [pCStt, pCEnd] = pCur->StartEnd(); // SwPosition*
2751             while( pCur != pNextPam )
2752             {
2753                 auto [pNStt, pNEnd] = pNextPam->StartEnd(); // SwPosition*
2754 
2755                 bool bDel = true;
2756                 switch( ::ComparePosition( *pCStt, *pCEnd,
2757                                            *pNStt, *pNEnd ))
2758                 {
2759                 case SwComparePosition::Inside:         // Pos1 is completely in Pos2
2760                     if( !pCur->HasMark() )
2761                     {
2762                         pCur->SetMark();
2763                         *pCur->GetMark() = *pNStt;
2764                     }
2765                     else
2766                         *pCStt = *pNStt;
2767                     *pCEnd = *pNEnd;
2768                     break;
2769 
2770                 case SwComparePosition::Outside:        // Pos2 is completely in Pos1
2771                 case SwComparePosition::Equal:          // Pos1 has same size as Pos2
2772                     break;
2773 
2774                 case SwComparePosition::OverlapBefore: // Pos1 overlaps Pos2 at beginning
2775                     if( !pCur->HasMark() )
2776                         pCur->SetMark();
2777                     *pCEnd = *pNEnd;
2778                     break;
2779                 case SwComparePosition::OverlapBehind: // Pos1 overlaps Pos2 at end
2780                     if( !pCur->HasMark() )
2781                     {
2782                         pCur->SetMark();
2783                         *pCur->GetMark() = *pNStt;
2784                     }
2785                     else
2786                         *pCStt = *pNStt;
2787                     break;
2788 
2789                 default:
2790                     bDel = false;
2791                 }
2792 
2793                 if( bDel )
2794                 {
2795                     // not needed anymore
2796                     SwPaM* pPrevPam = pNextPam->GetPrev();
2797                     delete pNextPam;
2798                     pNextPam = pPrevPam;
2799                 }
2800                 pNextPam = pNextPam->GetNext();
2801             }
2802         }
2803 
2804         SwRedlineTable::size_type nFndPos = 2 == nLoopCnt
2805                             ? rTable.FindNextOfSeqNo( nArrPos )
2806                             : rTable.FindPrevOfSeqNo( nArrPos );
2807         if( SwRedlineTable::npos != nFndPos ||
2808             ( 0 != ( --nLoopCnt ) && SwRedlineTable::npos != (
2809                     nFndPos = rTable.FindPrevOfSeqNo( nArrSavPos ))) )
2810         {
2811             if( pTmp )
2812             {
2813                 // create new cursor
2814                 CreateCursor();
2815                 bCheck = true;
2816             }
2817             nArrPos = nFndPos;
2818         }
2819         else
2820             nLoopCnt = 0;
2821 
2822     } while( nLoopCnt );
2823     return pFnd;
2824 }
2825 
SelectNxtPrvHyperlink(bool bNext)2826 bool SwCursorShell::SelectNxtPrvHyperlink( bool bNext )
2827 {
2828     SwNodes& rNds = GetDoc()->GetNodes();
2829     const SwNode* pBodyEndNd = &rNds.GetEndOfContent();
2830     const SwNode* pBodySttNd = pBodyEndNd->StartOfSectionNode();
2831     SwNodeOffset nBodySttNdIdx = pBodySttNd->GetIndex();
2832     Point aPt;
2833 
2834     SetGetExpField aCmpPos( SwPosition( bNext ? *pBodyEndNd : *pBodySttNd ) );
2835     SetGetExpField aCurPos( bNext ? *m_pCurrentCursor->End() : *m_pCurrentCursor->Start() );
2836     if( aCurPos.GetNode() < nBodySttNdIdx )
2837     {
2838         const SwContentNode* pCNd = aCurPos.GetNodeFromContent()->GetContentNode();
2839         std::pair<Point, bool> tmp(aPt, true);
2840         if (pCNd)
2841         {
2842             SwContentFrame* pFrame = pCNd->getLayoutFrame(GetLayout(), nullptr, &tmp);
2843             if( pFrame )
2844                 aCurPos.SetBodyPos( *pFrame );
2845         }
2846     }
2847 
2848     // check first all the hyperlink fields
2849     {
2850         const SwTextNode* pTextNd;
2851         const SwCharFormats* pFormats = GetDoc()->GetCharFormats();
2852         for( SwCharFormats::size_type n = pFormats->size(); 1 < n; )
2853         {
2854             SwIterator<SwTextINetFormat,SwCharFormat> aIter(*(*pFormats)[--n]);
2855 
2856             for( SwTextINetFormat* pFnd = aIter.First(); pFnd; pFnd = aIter.Next() )
2857             {
2858                 pTextNd = pFnd->GetpTextNode();
2859                 if( pTextNd && pTextNd->GetNodes().IsDocNodes() )
2860                 {
2861                     SwTextINetFormat& rAttr = *pFnd;
2862                     SetGetExpField aPos( *pTextNd, rAttr );
2863                     if (pTextNd->GetIndex() < nBodySttNdIdx)
2864                     {
2865                         std::pair<Point, bool> tmp(aPt, true);
2866                         SwContentFrame* pFrame = pTextNd->getLayoutFrame(GetLayout(), nullptr, &tmp);
2867                         if (pFrame)
2868                         {
2869                             aPos.SetBodyPos( *pFrame );
2870                         }
2871                     }
2872 
2873                     if( bNext
2874                         ? ( aPos < aCmpPos && aCurPos < aPos )
2875                         : ( aCmpPos < aPos && aPos < aCurPos ))
2876                     {
2877                         OUString sText(pTextNd->GetExpandText(GetLayout(),
2878                                         rAttr.GetStart(),
2879                                         *rAttr.GetEnd() - rAttr.GetStart() ) );
2880 
2881                         sText = sText.replaceAll("\x0a", "");
2882                         sText = comphelper::string::strip(sText, ' ');
2883 
2884                         if( !sText.isEmpty() )
2885                             aCmpPos = aPos;
2886                     }
2887                 }
2888             }
2889         }
2890     }
2891 
2892     // then check all the Flys with a URL or image map
2893     {
2894         for(sw::SpzFrameFormat* pSpz: *GetDoc()->GetSpzFrameFormats())
2895         {
2896             if (pSpz->Which() != RES_FLYFRMFMT)
2897                 continue;
2898             auto pFormat = static_cast<SwFlyFrameFormat*>(pSpz);
2899             const SwFormatURL& rURLItem = pFormat->GetURL();
2900             if( rURLItem.GetMap() || !rURLItem.GetURL().isEmpty() )
2901             {
2902                 SwFlyFrame* pFly = pFormat->GetFrame( &aPt );
2903                 SwPosition aTmpPos( *pBodySttNd );
2904                 if( pFly &&
2905                     GetBodyTextNode( *GetDoc(), aTmpPos, *pFly->GetLower() ) )
2906                 {
2907                     SetGetExpField aPos( *pFormat, &aTmpPos );
2908 
2909                     if( bNext
2910                             ? ( aPos < aCmpPos && aCurPos < aPos )
2911                             : ( aCmpPos < aPos && aPos < aCurPos ))
2912                         aCmpPos = aPos;
2913                 }
2914             }
2915         }
2916     }
2917 
2918     // found any URL ?
2919     const SwTextINetFormat* pFndAttr = aCmpPos.GetINetFormat();
2920     const SwFlyFrameFormat* pFndFormat = aCmpPos.GetFlyFormat();
2921     if( !pFndAttr && !pFndFormat )
2922         return false;
2923 
2924     CurrShell aCurr( this );
2925     SwCallLink aLk( *this );
2926 
2927     bool bRet = false;
2928     // found a text attribute ?
2929     if( pFndAttr )
2930     {
2931         SwCursorSaveState aSaveState( *m_pCurrentCursor );
2932 
2933         aCmpPos.GetPosOfContent( *m_pCurrentCursor->GetPoint() );
2934         m_pCurrentCursor->DeleteMark();
2935         m_pCurrentCursor->SetMark();
2936         m_pCurrentCursor->GetPoint()->SetContent( *pFndAttr->End() );
2937 
2938         if( !m_pCurrentCursor->IsInProtectTable() && !m_pCurrentCursor->IsSelOvr() )
2939         {
2940             UpdateCursor( SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|
2941                                 SwCursorShell::READONLY );
2942             bRet = true;
2943         }
2944     }
2945     // found a draw object ?
2946     else if( RES_DRAWFRMFMT == pFndFormat->Which() )
2947     {
2948         const SdrObject* pSObj = pFndFormat->FindSdrObject();
2949         if (pSObj)
2950         {
2951             static_cast<SwFEShell*>(this)->SelectObj( pSObj->GetCurrentBoundRect().Center() );
2952             MakeSelVisible();
2953             bRet = true;
2954         }
2955     }
2956     else // then is it a fly
2957     {
2958         SwFlyFrame* pFly = pFndFormat->GetFrame(&aPt);
2959         if( pFly )
2960         {
2961             static_cast<SwFEShell*>(this)->SelectFlyFrame( *pFly );
2962             MakeSelVisible();
2963             bRet = true;
2964         }
2965     }
2966     return bRet;
2967 }
2968 
2969 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2970