1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sfx2/bindings.hxx>
21 #include <sfx2/viewfrm.hxx>
24 #include <viewopt.hxx>
25 #include <drawbase.hxx>
26 #include <IDocumentDrawModelAccess.hxx>
27 #include <drawdoc.hxx>
28 #include <svx/svdpage.hxx>
29 #include <svx/svdview.hxx>
33 - Reset of the cursor stack
35 - if applicable: GCAttr
44 const tools::Long nReadOnlyScrollOfst
= 10;
53 ShellMoveCursor( SwWrtShell
* pWrtSh
, bool bSel
)
55 bAct
= !pWrtSh
->ActionPend() && (pWrtSh
->GetFrameType(nullptr,false) & FrameTypeFlags::FLY_ANY
);
57 pSh
->MoveCursor( bSel
);
58 pWrtSh
->GetView().GetViewFrame().GetBindings().Invalidate(SID_HYPERLINK_GETLINK
);
60 ~ShellMoveCursor() COVERITY_NOEXCEPT_FALSE
64 // The action is used for scrolling in "single paragraph"
65 // frames with fixed height.
66 pSh
->StartAllAction();
74 void SwWrtShell::MoveCursor( bool bWithSelect
)
87 (this->*m_fnKillSel
)( nullptr, false );
91 bool SwWrtShell::SimpleMove( FNSimpleMove FnSimpleMove
, bool bSelect
)
98 bRet
= (this->*FnSimpleMove
)();
103 bRet
= (this->*FnSimpleMove
)();
110 bool SwWrtShell::Left( SwCursorSkipMode nMode
, bool bSelect
,
111 sal_uInt16 nCount
, bool bBasicCall
, bool bVisual
)
113 if ( !bSelect
&& !bBasicCall
&& IsCursorReadonly() && !GetViewOptions()->IsSelectionInReadonly())
115 Point
aTmp( VisArea().Pos() );
116 aTmp
.AdjustX( -(VisArea().Width() * nReadOnlyScrollOfst
/ 100) );
117 m_rView
.SetVisArea( aTmp
);
122 ShellMoveCursor
aTmp( this, bSelect
);
123 return SwCursorShell::Left( nCount
, nMode
, bVisual
);
127 bool SwWrtShell::Right( SwCursorSkipMode nMode
, bool bSelect
,
128 sal_uInt16 nCount
, bool bBasicCall
, bool bVisual
)
130 if ( !bSelect
&& !bBasicCall
&& IsCursorReadonly() && !GetViewOptions()->IsSelectionInReadonly() )
132 Point
aTmp( VisArea().Pos() );
133 aTmp
.AdjustX(VisArea().Width() * nReadOnlyScrollOfst
/ 100 );
134 aTmp
.setX( m_rView
.SetHScrollMax( aTmp
.X() ) );
135 m_rView
.SetVisArea( aTmp
);
140 ShellMoveCursor
aTmp( this, bSelect
);
141 return SwCursorShell::Right( nCount
, nMode
, bVisual
);
145 bool SwWrtShell::Up( bool bSelect
, sal_uInt16 nCount
, bool bBasicCall
)
147 if ( !bSelect
&& !bBasicCall
&& IsCursorReadonly() && !GetViewOptions()->IsSelectionInReadonly())
149 Point
aTmp( VisArea().Pos() );
150 aTmp
.AdjustY( -(VisArea().Height() * nReadOnlyScrollOfst
/ 100) );
151 m_rView
.SetVisArea( aTmp
);
155 ShellMoveCursor
aTmp( this, bSelect
);
156 return SwCursorShell::Up(nCount
);
159 bool SwWrtShell::Down( bool bSelect
, sal_uInt16 nCount
, bool bBasicCall
)
161 if ( !bSelect
&& !bBasicCall
&& IsCursorReadonly() && !GetViewOptions()->IsSelectionInReadonly())
163 Point
aTmp( VisArea().Pos() );
164 aTmp
.AdjustY(VisArea().Height() * nReadOnlyScrollOfst
/ 100 );
165 aTmp
.setY( m_rView
.SetVScrollMax( aTmp
.Y() ) );
166 m_rView
.SetVisArea( aTmp
);
170 ShellMoveCursor
aTmp( this, bSelect
);
171 return SwCursorShell::Down(nCount
);
174 bool SwWrtShell::LeftMargin( bool bSelect
, bool bBasicCall
)
176 if ( !bSelect
&& !bBasicCall
&& IsCursorReadonly() )
178 Point
aTmp( VisArea().Pos() );
179 aTmp
.setX( DOCUMENTBORDER
);
180 m_rView
.SetVisArea( aTmp
);
185 ShellMoveCursor
aTmp( this, bSelect
);
186 return SwCursorShell::LeftMargin();
190 bool SwWrtShell::RightMargin( bool bSelect
, bool bBasicCall
)
192 if ( !bSelect
&& !bBasicCall
&& IsCursorReadonly() )
194 Point
aTmp( VisArea().Pos() );
195 aTmp
.setX( GetDocSize().Width() - VisArea().Width() + DOCUMENTBORDER
);
196 if( DOCUMENTBORDER
> aTmp
.X() )
197 aTmp
.setX( DOCUMENTBORDER
);
198 m_rView
.SetVisArea( aTmp
);
203 ShellMoveCursor
aTmp( this, bSelect
);
204 return SwCursorShell::RightMargin(bBasicCall
);
208 bool SwWrtShell::GoStart( bool bKeepArea
, bool *pMoveTable
,
209 bool bSelect
, bool bDontMoveRegion
)
211 if ( IsCursorInTable() )
213 const bool bBoxSelection
= HasBoxSelection();
222 if ( !bBoxSelection
&& (MoveSection( GoCurrSection
, fnSectionStart
)
229 SwTableNode
const*const pTable(getShellCursor(false)->GetPoint()->GetNode().FindTableNode());
231 if( MoveTable( GotoCurrTable
, fnTableStart
) || bDontMoveRegion
)
237 else if (SwCursor
const*const pCursor
= getShellCursor(false);
238 pTable
->GetNodes()[pTable
->GetIndex()+1]->EndOfSectionIndex()
239 < pCursor
->GetPoint()->GetNode().GetIndex()
240 && pMoveTable
!= nullptr // only set by SelAll()
241 // problem: cursor isn't inside 1st cell, and didn't move there
242 // workaround: try to move cursor outside of table for SelAll()
245 assert(!*pMoveTable
);
248 else if( bBoxSelection
&& pMoveTable
)
250 // JP 09.01.96: We have a box selection (or an empty cell)
251 // and we want select (pMoveTable will be
252 // set in SelAll). Then the table must not
253 // be left, otherwise there is no selection
254 // of the entire table possible!
267 const FrameTypeFlags nFrameType
= GetFrameType(nullptr,false);
268 if ( FrameTypeFlags::FLY_ANY
& nFrameType
)
270 if( MoveSection( GoCurrSection
, fnSectionStart
) )
272 else if ( FrameTypeFlags::FLY_FREE
& nFrameType
|| bDontMoveRegion
)
275 if(( FrameTypeFlags::HEADER
| FrameTypeFlags::FOOTER
| FrameTypeFlags::FOOTNOTE
) & nFrameType
)
277 if ( MoveSection( GoCurrSection
, fnSectionStart
) )
279 else if ( bKeepArea
)
283 // first try to move to the start of the current SwSection
284 return SwCursorShell::MoveRegion( GotoCurrRegionAndSkip
, fnRegionStart
) ||
285 (pMoveTable
!= nullptr
286 // move to start of text - if in different table, move out
288 // TODO who needs SttEndDoc for other case?
289 : SwCursorShell::SttEndDoc(true));
292 bool SwWrtShell::GoEnd(bool bKeepArea
, const bool *pMoveTable
)
294 if (pMoveTable
&& *pMoveTable
) // only in SelAll()
296 SwTableNode
const*const pTable(getShellCursor(false)->GetPoint()->GetNode().FindTableNode());
298 if (MoveTable(GotoCurrTable
, fnTableEnd
))
302 else if (SwCursor
const*const pCursor
= getShellCursor(false);
303 pCursor
->GetPoint()->GetNode().GetIndex()
304 < pTable
->GetNodes()[pTable
->EndOfSectionIndex()-1]->StartOfSectionIndex()
305 // problem: cursor isn't inside 1st cell, and didn't move there
306 // workaround: try to move cursor outside of table for SelAll()
317 if ( IsCursorInTable() )
319 if ( MoveSection( GoCurrSection
, fnSectionEnd
) ||
320 MoveTable( GotoCurrTable
, fnTableEnd
) )
325 const FrameTypeFlags nFrameType
= GetFrameType(nullptr,false);
326 if ( FrameTypeFlags::FLY_ANY
& nFrameType
)
328 if ( MoveSection( GoCurrSection
, fnSectionEnd
) )
330 else if ( FrameTypeFlags::FLY_FREE
& nFrameType
)
333 if(( FrameTypeFlags::HEADER
| FrameTypeFlags::FOOTER
| FrameTypeFlags::FOOTNOTE
) & nFrameType
)
335 if ( MoveSection( GoCurrSection
, fnSectionEnd
) )
337 else if ( bKeepArea
)
342 return SwCursorShell::MoveRegion( GotoCurrRegionAndSkip
, fnRegionEnd
) ||
343 SwCursorShell::SttEndDoc(false);
346 bool SwWrtShell::StartOfSection(bool const bSelect
)
348 ShellMoveCursor
aTmp( this, bSelect
);
349 return GoStart(false, nullptr, bSelect
);
352 bool SwWrtShell::EndOfSection(bool const bSelect
)
354 ShellMoveCursor
aTmp( this, bSelect
);
358 bool SwWrtShell::SttNxtPg( bool bSelect
)
360 ShellMoveCursor
aTmp( this, bSelect
);
361 return MovePage( GetNextFrame
, GetFirstSub
);
364 void SwWrtShell::SttPrvPg( bool bSelect
)
366 ShellMoveCursor
aTmp( this, bSelect
);
367 MovePage( GetPrevFrame
, GetFirstSub
);
370 void SwWrtShell::EndNxtPg( bool bSelect
)
372 ShellMoveCursor
aTmp( this, bSelect
);
373 MovePage( GetNextFrame
, GetLastSub
);
376 bool SwWrtShell::EndPrvPg( bool bSelect
)
378 ShellMoveCursor
aTmp( this, bSelect
);
379 return MovePage( GetPrevFrame
, GetLastSub
);
382 bool SwWrtShell::SttPg( bool bSelect
)
384 ShellMoveCursor
aTmp( this, bSelect
);
385 return MovePage( GetThisFrame
, GetFirstSub
);
388 bool SwWrtShell::EndPg( bool bSelect
)
390 ShellMoveCursor
aTmp( this, bSelect
);
391 return MovePage( GetThisFrame
, GetLastSub
);
394 bool SwWrtShell::SttPara( bool bSelect
)
396 ShellMoveCursor
aTmp( this, bSelect
);
397 return MovePara( GoCurrPara
, fnParaStart
);
400 void SwWrtShell::EndPara( bool bSelect
)
402 ShellMoveCursor
aTmp( this, bSelect
);
403 MovePara(GoCurrPara
,fnParaEnd
);
406 // Column-by-jumping.
407 // SSelection with or without
408 // returns success or failure
410 void SwWrtShell::StartOfColumn()
412 ShellMoveCursor
aTmp( this, false/*bSelect*/);
413 MoveColumn(GetCurrColumn
, GetColumnStt
);
416 void SwWrtShell::EndOfColumn()
418 ShellMoveCursor
aTmp( this, false/*bSelect*/);
419 MoveColumn(GetCurrColumn
, GetColumnEnd
);
422 void SwWrtShell::StartOfNextColumn()
424 ShellMoveCursor
aTmp( this, false/*bSelect*/);
425 MoveColumn( GetNextColumn
, GetColumnStt
);
428 void SwWrtShell::EndOfNextColumn()
430 ShellMoveCursor
aTmp( this, false/*bSelect*/);
431 MoveColumn(GetNextColumn
, GetColumnEnd
);
434 void SwWrtShell::StartOfPrevColumn()
436 ShellMoveCursor
aTmp( this, false/*bSelect*/);
437 MoveColumn(GetPrevColumn
, GetColumnStt
);
440 void SwWrtShell::EndOfPrevColumn()
442 ShellMoveCursor
aTmp( this, false/*bSelect*/);
443 MoveColumn(GetPrevColumn
, GetColumnEnd
);
446 bool SwWrtShell::PushCursor(SwTwips lOffset
, bool bSelect
)
449 SwRect
aOldRect( GetCharRect() ), aTmpArea( VisArea() );
451 // m_bDestOnStack indicates if I could not set the coursor at the current
452 // position, because in this region is no content.
453 if( !m_bDestOnStack
)
455 Point
aPt( aOldRect
.Center() );
457 if( !IsCursorVisible() )
458 // set CursorPos to top-/bottom left pos. So the pagescroll is not
459 // be dependent on the current cursor, but on the visarea.
460 aPt
.setY( aTmpArea
.Top() + aTmpArea
.Height() / 2 );
462 aPt
.AdjustY(lOffset
);
463 m_aDest
= GetContentPos(aPt
,lOffset
> 0);
464 m_aDest
.setX( aPt
.X() );
465 m_bDestOnStack
= true;
468 // If we had a frame selection, it must be removed after the m_fnSetCursor
469 // and we have to remember the position on the stack to return to it later.
470 bool bIsFrameSel
= false;
472 //Target position is now within the viewable region -->
473 //Place the cursor at the target position; remember that no target
474 //position is longer on the stack.
475 //The new visible region is to be determined beforehand.
476 aTmpArea
.Pos().AdjustY(lOffset
);
477 if( aTmpArea
.Contains(m_aDest
) )
484 bIsFrameSel
= IsFrameSelected();
485 bool bIsObjSel
= 0 != IsObjSelected();
488 if( bIsFrameSel
|| bIsObjSel
)
494 GetView().SetDrawFuncPtr( nullptr );
495 GetView().LeaveDrawCreate();
501 (this->*m_fnSetCursor
)( &m_aDest
, true );
503 bDiff
= aOldRect
!= GetCharRect();
507 // In frames take only the upper corner
508 // so that it can be re-selected.
509 aOldRect
.SSize( 5, 5 );
512 // reset Dest. SPoint Flags
513 m_bDestOnStack
= false;
516 // Position into the stack; bDiff indicates if there is a
517 // difference between the old and the new cursor position.
518 m_pCursorStack
.reset( new CursorStack( bDiff
, bIsFrameSel
, aOldRect
.Center(),
519 lOffset
, std::move(m_pCursorStack
) ) );
520 return !m_bDestOnStack
&& bDiff
;
523 bool SwWrtShell::PopCursor(bool bUpdate
, bool bSelect
)
525 if( nullptr == m_pCursorStack
)
528 const bool bValidPos
= m_pCursorStack
->bValidCurPos
;
529 if( bUpdate
&& bValidPos
)
531 // If a predecessor is on the stack,
532 // use the flag for a valid position.
533 SwRect
aTmpArea(VisArea());
534 aTmpArea
.Pos().AdjustY( -(m_pCursorStack
->lOffset
) );
535 if( aTmpArea
.Contains( m_pCursorStack
->aDocPos
) )
542 (this->*m_fnSetCursor
)(&m_pCursorStack
->aDocPos
, !m_pCursorStack
->bIsFrameSel
);
543 if( m_pCursorStack
->bIsFrameSel
&& IsObjSelectable(m_pCursorStack
->aDocPos
))
546 SelectObj( m_pCursorStack
->aDocPos
);
547 EnterSelFrameMode( &m_pCursorStack
->aDocPos
);
550 // If a discrepancy between the visible range and the
551 // remembered cursor position occurs, all of the remembered
552 // positions are thrown away.
559 m_pCursorStack
= std::move(m_pCursorStack
->pNext
);
560 if( nullptr == m_pCursorStack
)
563 m_bDestOnStack
= false;
568 // Reset of all pushed cursor positions; these will
569 // not be displayed ( --> No Start-/EndAction!!)
571 void SwWrtShell::ResetCursorStack_()
573 while(m_pCursorStack
)
574 m_pCursorStack
= std::move(m_pCursorStack
->pNext
);
576 m_bDestOnStack
= false;
579 if no stack exists --> cancel selection
580 if stack && change of direction
581 --> pop cursor and return
587 bool SwWrtShell::PageCursor(SwTwips lOffset
, bool bSelect
)
589 // Do nothing if an offset of 0 was indicated
590 if(!lOffset
) return false;
591 // Was once used to force a reformat of the layout.
592 // This has not work that way, because the cursor was not set
593 // because this does not happen within a
594 // Start-/EndActionParentheses.
595 // Because only SwViewShell::EndAction() is called at the end,
596 // no updating of the display of the cursor position takes place.
597 // The CursorShell-Actionparentheses cannot be used, because it
598 // always leads to displaying the cursor, thus also,
599 // if after the scroll scrolled in a region without a valid position.
600 // SwViewShell::StartAction();
601 PageMove eDir
= lOffset
> 0? MV_PAGE_DOWN
: MV_PAGE_UP
;
602 // Change of direction and stack present
603 if( eDir
!= m_ePageMove
&& m_ePageMove
!= MV_NO
&& PopCursor( true, bSelect
))
606 const bool bRet
= PushCursor(lOffset
, bSelect
);
611 bool SwWrtShell::GotoPage(sal_uInt16 nPage
, bool bRecord
)
613 addCurrentPosition();
614 ShellMoveCursor
aTmp( this, false);
615 if( SwCursorShell::GotoPage(nPage
) && bRecord
)
627 bool SwWrtShell::GotoMark( const ::sw::mark::IMark
* const pMark
, bool bSelect
)
629 ShellMoveCursor
aTmp( this, bSelect
);
630 SwPosition aPos
= *GetCursor()->GetPoint();
631 bool bRet
= SwCursorShell::GotoMark( pMark
, true/*bStart*/ );
633 m_aNavigationMgr
.addEntry(aPos
);
637 bool SwWrtShell::GotoFly( const OUString
& rName
, FlyCntType eType
, bool bSelFrame
)
639 SwPosition aPos
= *GetCursor()->GetPoint();
640 bool bRet
= SwFEShell::GotoFly(rName
, eType
, bSelFrame
);
642 m_aNavigationMgr
.addEntry(aPos
);
646 bool SwWrtShell::GotoINetAttr( const SwTextINetFormat
& rAttr
)
648 SwPosition aPos
= *GetCursor()->GetPoint();
649 bool bRet
= SwCursorShell::GotoINetAttr(rAttr
);
651 m_aNavigationMgr
.addEntry(aPos
);
655 void SwWrtShell::GotoOutline( SwOutlineNodes::size_type nIdx
)
657 addCurrentPosition();
658 SwCursorShell::GotoOutline (nIdx
);
661 bool SwWrtShell::GotoOutline( const OUString
& rName
)
663 SwPosition aPos
= *GetCursor()->GetPoint();
664 bool bRet
= SwCursorShell::GotoOutline (rName
);
666 m_aNavigationMgr
.addEntry(aPos
);
670 bool SwWrtShell::GotoDrawingObject(std::u16string_view rName
)
672 SwPosition aPos
= *GetCursor()->GetPoint();
674 SdrView
* pDrawView
= GetDrawView();
677 pDrawView
->SdrEndTextEdit();
678 pDrawView
->UnmarkAll();
679 SdrPage
* pPage
= getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
680 const size_t nCount
= pPage
->GetObjCount();
681 for (size_t i
= 0; i
< nCount
; ++i
)
683 SdrObject
* pObj
= pPage
->GetObj(i
);
684 if (pObj
->GetName() == rName
)
686 SdrPageView
* pPageView
= pDrawView
->GetSdrPageView();
689 pDrawView
->MarkObj(pObj
, pPageView
);
690 m_aNavigationMgr
.addEntry(aPos
);
703 bool SwWrtShell::GotoRegion( std::u16string_view rName
)
705 SwPosition aPos
= *GetCursor()->GetPoint();
706 bool bRet
= SwCursorShell::GotoRegion (rName
);
708 m_aNavigationMgr
.addEntry(aPos
);
712 bool SwWrtShell::GotoRefMark( const OUString
& rRefMark
, sal_uInt16 nSubType
,
715 SwPosition aPos
= *GetCursor()->GetPoint();
716 bool bRet
= SwCursorShell::GotoRefMark(rRefMark
, nSubType
, nSeqNo
);
718 m_aNavigationMgr
.addEntry(aPos
);
722 bool SwWrtShell::GotoNextTOXBase( const OUString
* pName
)
724 SwPosition aPos
= *GetCursor()->GetPoint();
725 bool bRet
= SwCursorShell::GotoNextTOXBase(pName
);
727 m_aNavigationMgr
.addEntry(aPos
);
731 bool SwWrtShell::GotoTable( const OUString
& rName
)
733 SwPosition aPos
= *GetCursor()->GetPoint();
734 bool bRet
= SwCursorShell::GotoTable(rName
);
736 m_aNavigationMgr
.addEntry(aPos
);
740 void SwWrtShell::GotoFormatField( const SwFormatField
& rField
) {
741 SwPosition aPos
= *GetCursor()->GetPoint();
742 bool bRet
= SwCursorShell::GotoFormatField(rField
);
744 m_aNavigationMgr
.addEntry(aPos
);
747 void SwWrtShell::GotoFootnoteAnchor(const SwTextFootnote
& rTextFootnote
)
749 SwPosition aPos
= *GetCursor()->GetPoint();
750 bool bRet
= SwCursorShell::GotoFootnoteAnchor(rTextFootnote
);
752 m_aNavigationMgr
.addEntry(aPos
);
755 const SwRangeRedline
* SwWrtShell::GotoRedline( SwRedlineTable::size_type nArrPos
, bool bSelect
) {
756 SwPosition aPos
= *GetCursor()->GetPoint();
757 const SwRangeRedline
*pRedline
= SwCursorShell::GotoRedline(nArrPos
, bSelect
);
759 m_aNavigationMgr
.addEntry(aPos
);
763 bool SwWrtShell::SelectTextAttr( sal_uInt16 nWhich
, const SwTextAttr
* pAttr
)
767 SwMvContext
aMvContext(this);
769 bRet
= SwCursorShell::SelectTextAttr( nWhich
, false, pAttr
);
775 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */