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