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