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