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>
30 #include <comphelper/lok.hxx>
34 - Reset of the cursor stack
36 - if applicable: GCAttr
45 const tools::Long nReadOnlyScrollOfst
= 10;
54 ShellMoveCursor( SwWrtShell
* pWrtSh
, bool bSel
)
56 bAct
= !pWrtSh
->ActionPend() && (pWrtSh
->GetFrameType(nullptr,false) & FrameTypeFlags::FLY_ANY
);
58 pSh
->MoveCursor( bSel
);
59 pWrtSh
->GetView().GetViewFrame().GetBindings().Invalidate(SID_HYPERLINK_GETLINK
);
61 ~ShellMoveCursor() COVERITY_NOEXCEPT_FALSE
65 // The action is used for scrolling in "single paragraph"
66 // frames with fixed height.
67 pSh
->StartAllAction();
75 void SwWrtShell::MoveCursor( bool bWithSelect
)
88 (this->*m_fnKillSel
)( nullptr, false );
92 bool SwWrtShell::SimpleMove( FNSimpleMove FnSimpleMove
, bool bSelect
)
99 bRet
= (this->*FnSimpleMove
)();
104 bRet
= (this->*FnSimpleMove
)();
111 bool SwWrtShell::Left( SwCursorSkipMode nMode
, bool bSelect
,
112 sal_uInt16 nCount
, bool bBasicCall
, bool bVisual
)
114 if ( !bSelect
&& !bBasicCall
&& IsCursorReadonly() && !GetViewOptions()->IsSelectionInReadonly())
116 Point
aTmp( VisArea().Pos() );
117 aTmp
.AdjustX( -(VisArea().Width() * nReadOnlyScrollOfst
/ 100) );
118 m_rView
.SetVisArea( aTmp
);
123 ShellMoveCursor
aTmp( this, bSelect
);
124 return SwCursorShell::Left( nCount
, nMode
, bVisual
);
128 bool SwWrtShell::Right( SwCursorSkipMode nMode
, bool bSelect
,
129 sal_uInt16 nCount
, bool bBasicCall
, bool bVisual
)
131 if ( !bSelect
&& !bBasicCall
&& IsCursorReadonly() && !GetViewOptions()->IsSelectionInReadonly() )
133 Point
aTmp( VisArea().Pos() );
134 aTmp
.AdjustX(VisArea().Width() * nReadOnlyScrollOfst
/ 100 );
135 aTmp
.setX( m_rView
.SetHScrollMax( aTmp
.X() ) );
136 m_rView
.SetVisArea( aTmp
);
141 ShellMoveCursor
aTmp( this, bSelect
);
142 return SwCursorShell::Right( nCount
, nMode
, bVisual
);
146 bool SwWrtShell::Up( bool bSelect
, sal_uInt16 nCount
, bool bBasicCall
)
148 if ( !bSelect
&& !bBasicCall
&& IsCursorReadonly() && !GetViewOptions()->IsSelectionInReadonly())
150 Point
aTmp( VisArea().Pos() );
151 aTmp
.AdjustY( -(VisArea().Height() * nReadOnlyScrollOfst
/ 100) );
152 m_rView
.SetVisArea( aTmp
);
156 ShellMoveCursor
aTmp( this, bSelect
);
157 return SwCursorShell::Up(nCount
);
160 bool SwWrtShell::Down( bool bSelect
, sal_uInt16 nCount
, bool bBasicCall
)
162 if ( !bSelect
&& !bBasicCall
&& IsCursorReadonly() && !GetViewOptions()->IsSelectionInReadonly())
164 Point
aTmp( VisArea().Pos() );
165 aTmp
.AdjustY(VisArea().Height() * nReadOnlyScrollOfst
/ 100 );
166 aTmp
.setY( m_rView
.SetVScrollMax( aTmp
.Y() ) );
167 m_rView
.SetVisArea( aTmp
);
171 ShellMoveCursor
aTmp( this, bSelect
);
172 return SwCursorShell::Down(nCount
);
175 bool SwWrtShell::LeftMargin( bool bSelect
, bool bBasicCall
)
177 if ( !bSelect
&& !bBasicCall
&& IsCursorReadonly() )
179 Point
aTmp( VisArea().Pos() );
180 aTmp
.setX( DOCUMENTBORDER
);
181 m_rView
.SetVisArea( aTmp
);
186 ShellMoveCursor
aTmp( this, bSelect
);
187 return SwCursorShell::LeftMargin();
191 bool SwWrtShell::RightMargin( bool bSelect
, bool bBasicCall
)
193 if ( !bSelect
&& !bBasicCall
&& IsCursorReadonly() )
195 Point
aTmp( VisArea().Pos() );
196 aTmp
.setX( GetDocSize().Width() - VisArea().Width() + DOCUMENTBORDER
);
197 if( DOCUMENTBORDER
> aTmp
.X() )
198 aTmp
.setX( DOCUMENTBORDER
);
199 m_rView
.SetVisArea( aTmp
);
204 ShellMoveCursor
aTmp( this, bSelect
);
205 return SwCursorShell::RightMargin(bBasicCall
);
209 bool SwWrtShell::GoStart( bool bKeepArea
, bool *pMoveTable
,
210 bool bSelect
, bool bDontMoveRegion
)
212 if ( IsCursorInTable() )
214 const bool bBoxSelection
= HasBoxSelection();
223 if ( !bBoxSelection
&& (MoveSection( GoCurrSection
, fnSectionStart
)
230 SwTableNode
const*const pTable(getShellCursor(false)->GetPoint()->GetNode().FindTableNode());
232 if( MoveTable( GotoCurrTable
, fnTableStart
) || bDontMoveRegion
)
238 else if (SwCursor
const*const pCursor
= getShellCursor(false);
239 pTable
->GetNodes()[pTable
->GetIndex()+1]->EndOfSectionIndex()
240 < pCursor
->GetPoint()->GetNode().GetIndex()
241 && pMoveTable
!= nullptr // only set by SelAll()
242 // problem: cursor isn't inside 1st cell, and didn't move there
243 // workaround: try to move cursor outside of table for SelAll()
246 assert(!*pMoveTable
);
249 else if( bBoxSelection
&& pMoveTable
)
251 // JP 09.01.96: We have a box selection (or an empty cell)
252 // and we want select (pMoveTable will be
253 // set in SelAll). Then the table must not
254 // be left, otherwise there is no selection
255 // of the entire table possible!
268 const FrameTypeFlags nFrameType
= GetFrameType(nullptr,false);
269 if ( FrameTypeFlags::FLY_ANY
& nFrameType
)
271 if( MoveSection( GoCurrSection
, fnSectionStart
) )
273 else if ( FrameTypeFlags::FLY_FREE
& nFrameType
|| bDontMoveRegion
)
276 if(( FrameTypeFlags::HEADER
| FrameTypeFlags::FOOTER
| FrameTypeFlags::FOOTNOTE
) & nFrameType
)
278 if ( MoveSection( GoCurrSection
, fnSectionStart
) )
280 else if ( bKeepArea
)
284 // first try to move to the start of the current SwSection
285 return SwCursorShell::MoveRegion( GotoCurrRegionAndSkip
, fnRegionStart
) ||
286 (pMoveTable
!= nullptr
287 // move to start of text - if in different table, move out
289 // TODO who needs SttEndDoc for other case?
290 : SwCursorShell::SttEndDoc(true));
293 bool SwWrtShell::GoEnd(bool bKeepArea
, const bool *pMoveTable
)
295 if (pMoveTable
&& *pMoveTable
) // only in SelAll()
297 SwTableNode
const*const pTable(getShellCursor(false)->GetPoint()->GetNode().FindTableNode());
299 if (MoveTable(GotoCurrTable
, fnTableEnd
))
303 else if (SwCursor
const*const pCursor
= getShellCursor(false);
304 pCursor
->GetPoint()->GetNode().GetIndex()
305 < pTable
->GetNodes()[pTable
->EndOfSectionIndex()-1]->StartOfSectionIndex()
306 // problem: cursor isn't inside 1st cell, and didn't move there
307 // workaround: try to move cursor outside of table for SelAll()
318 if ( IsCursorInTable() )
320 if ( MoveSection( GoCurrSection
, fnSectionEnd
) ||
321 MoveTable( GotoCurrTable
, fnTableEnd
) )
326 const FrameTypeFlags nFrameType
= GetFrameType(nullptr,false);
327 if ( FrameTypeFlags::FLY_ANY
& nFrameType
)
329 if ( MoveSection( GoCurrSection
, fnSectionEnd
) )
331 else if ( FrameTypeFlags::FLY_FREE
& nFrameType
)
334 if(( FrameTypeFlags::HEADER
| FrameTypeFlags::FOOTER
| FrameTypeFlags::FOOTNOTE
) & nFrameType
)
336 if ( MoveSection( GoCurrSection
, fnSectionEnd
) )
338 else if ( bKeepArea
)
343 return SwCursorShell::MoveRegion( GotoCurrRegionAndSkip
, fnRegionEnd
) ||
344 SwCursorShell::SttEndDoc(false);
347 bool SwWrtShell::StartOfSection(bool const bSelect
)
349 ShellMoveCursor
aTmp( this, bSelect
);
350 return GoStart(false, nullptr, bSelect
);
353 bool SwWrtShell::EndOfSection(bool const bSelect
)
355 ShellMoveCursor
aTmp( this, bSelect
);
359 bool SwWrtShell::SttNxtPg( bool bSelect
)
361 ShellMoveCursor
aTmp( this, bSelect
);
362 return MovePage( GetNextFrame
, GetFirstSub
);
365 void SwWrtShell::SttPrvPg( bool bSelect
)
367 ShellMoveCursor
aTmp( this, bSelect
);
368 MovePage( GetPrevFrame
, GetFirstSub
);
371 void SwWrtShell::EndNxtPg( bool bSelect
)
373 ShellMoveCursor
aTmp( this, bSelect
);
374 MovePage( GetNextFrame
, GetLastSub
);
377 bool SwWrtShell::EndPrvPg( bool bSelect
)
379 ShellMoveCursor
aTmp( this, bSelect
);
380 return MovePage( GetPrevFrame
, GetLastSub
);
383 bool SwWrtShell::SttPg( bool bSelect
)
385 ShellMoveCursor
aTmp( this, bSelect
);
386 return MovePage( GetThisFrame
, GetFirstSub
);
389 bool SwWrtShell::EndPg( bool bSelect
)
391 ShellMoveCursor
aTmp( this, bSelect
);
392 return MovePage( GetThisFrame
, GetLastSub
);
395 bool SwWrtShell::SttPara( bool bSelect
)
397 ShellMoveCursor
aTmp( this, bSelect
);
398 return MovePara( GoCurrPara
, fnParaStart
);
401 void SwWrtShell::EndPara( bool bSelect
)
403 ShellMoveCursor
aTmp( this, bSelect
);
404 MovePara(GoCurrPara
,fnParaEnd
);
407 // Column-by-jumping.
408 // SSelection with or without
409 // returns success or failure
411 void SwWrtShell::StartOfColumn()
413 ShellMoveCursor
aTmp( this, false/*bSelect*/);
414 MoveColumn(GetCurrColumn
, GetColumnStt
);
417 void SwWrtShell::EndOfColumn()
419 ShellMoveCursor
aTmp( this, false/*bSelect*/);
420 MoveColumn(GetCurrColumn
, GetColumnEnd
);
423 void SwWrtShell::StartOfNextColumn()
425 ShellMoveCursor
aTmp( this, false/*bSelect*/);
426 MoveColumn( GetNextColumn
, GetColumnStt
);
429 void SwWrtShell::EndOfNextColumn()
431 ShellMoveCursor
aTmp( this, false/*bSelect*/);
432 MoveColumn(GetNextColumn
, GetColumnEnd
);
435 void SwWrtShell::StartOfPrevColumn()
437 ShellMoveCursor
aTmp( this, false/*bSelect*/);
438 MoveColumn(GetPrevColumn
, GetColumnStt
);
441 void SwWrtShell::EndOfPrevColumn()
443 ShellMoveCursor
aTmp( this, false/*bSelect*/);
444 MoveColumn(GetPrevColumn
, GetColumnEnd
);
447 bool SwWrtShell::PushCursor(SwTwips lOffset
, bool bSelect
)
450 SwRect
aOldRect( GetCharRect() ), aTmpArea( VisArea() );
452 // m_bDestOnStack indicates if I could not set the coursor at the current
453 // position, because in this region is no content.
454 if( !m_bDestOnStack
)
456 Point
aPt( aOldRect
.Center() );
458 if (SfxViewShell
* pKitView
= comphelper::LibreOfficeKit::isActive() ? GetSfxViewShell() : nullptr)
460 SwRect
aLOKVis(pKitView
->getLOKVisibleArea());
461 if (!aLOKVis
.Overlaps(aOldRect
))
462 aPt
.setY( aLOKVis
.Top() + aLOKVis
.Height() / 2 );
464 else if( !IsCursorVisible() )
465 // set CursorPos to top-/bottom left pos. So the pagescroll is not
466 // be dependent on the current cursor, but on the visarea.
467 aPt
.setY( aTmpArea
.Top() + aTmpArea
.Height() / 2 );
469 aPt
.AdjustY(lOffset
);
470 m_aDest
= GetContentPos(aPt
,lOffset
> 0);
471 m_aDest
.setX( aPt
.X() );
472 m_bDestOnStack
= true;
475 // If we had a frame selection, it must be removed after the m_fnSetCursor
476 // and we have to remember the position on the stack to return to it later.
477 bool bIsFrameSel
= false;
479 //Target position is now within the viewable region -->
480 //Place the cursor at the target position; remember that no target
481 //position is longer on the stack.
482 //The new visible region is to be determined beforehand.
483 aTmpArea
.Pos().AdjustY(lOffset
);
484 if( aTmpArea
.Contains(m_aDest
) )
491 bIsFrameSel
= IsFrameSelected();
492 bool bIsObjSel
= 0 != IsObjSelected();
495 if( bIsFrameSel
|| bIsObjSel
)
501 GetView().SetDrawFuncPtr( nullptr );
502 GetView().LeaveDrawCreate();
508 (this->*m_fnSetCursor
)( &m_aDest
, true );
510 bDiff
= aOldRect
!= GetCharRect();
514 // In frames take only the upper corner
515 // so that it can be re-selected.
516 aOldRect
.SSize( 5, 5 );
519 // reset Dest. SPoint Flags
520 m_bDestOnStack
= false;
523 // Position into the stack; bDiff indicates if there is a
524 // difference between the old and the new cursor position.
525 m_pCursorStack
.reset( new CursorStack( bDiff
, bIsFrameSel
, aOldRect
.Center(),
526 lOffset
, std::move(m_pCursorStack
) ) );
527 return !m_bDestOnStack
&& bDiff
;
530 bool SwWrtShell::PopCursor(bool bUpdate
, bool bSelect
)
532 if( nullptr == m_pCursorStack
)
535 const bool bValidPos
= m_pCursorStack
->bValidCurPos
;
536 if( bUpdate
&& bValidPos
)
538 // If a predecessor is on the stack,
539 // use the flag for a valid position.
540 SwRect
aTmpArea(VisArea());
541 aTmpArea
.Pos().AdjustY( -(m_pCursorStack
->lOffset
) );
542 if( aTmpArea
.Contains( m_pCursorStack
->aDocPos
) )
549 (this->*m_fnSetCursor
)(&m_pCursorStack
->aDocPos
, !m_pCursorStack
->bIsFrameSel
);
550 if( m_pCursorStack
->bIsFrameSel
&& IsObjSelectable(m_pCursorStack
->aDocPos
))
553 SelectObj( m_pCursorStack
->aDocPos
);
554 EnterSelFrameMode( &m_pCursorStack
->aDocPos
);
557 // If a discrepancy between the visible range and the
558 // remembered cursor position occurs, all of the remembered
559 // positions are thrown away.
566 m_pCursorStack
= std::move(m_pCursorStack
->pNext
);
567 if( nullptr == m_pCursorStack
)
570 m_bDestOnStack
= false;
575 // Reset of all pushed cursor positions; these will
576 // not be displayed ( --> No Start-/EndAction!!)
578 void SwWrtShell::ResetCursorStack_()
580 while(m_pCursorStack
)
581 m_pCursorStack
= std::move(m_pCursorStack
->pNext
);
583 m_bDestOnStack
= false;
586 if no stack exists --> cancel selection
587 if stack && change of direction
588 --> pop cursor and return
594 bool SwWrtShell::PageCursor(SwTwips lOffset
, bool bSelect
)
596 // Do nothing if an offset of 0 was indicated
597 if(!lOffset
) return false;
598 // Was once used to force a reformat of the layout.
599 // This has not work that way, because the cursor was not set
600 // because this does not happen within a
601 // Start-/EndActionParentheses.
602 // Because only SwViewShell::EndAction() is called at the end,
603 // no updating of the display of the cursor position takes place.
604 // The CursorShell-Actionparentheses cannot be used, because it
605 // always leads to displaying the cursor, thus also,
606 // if after the scroll scrolled in a region without a valid position.
607 // SwViewShell::StartAction();
608 PageMove eDir
= lOffset
> 0? MV_PAGE_DOWN
: MV_PAGE_UP
;
609 // Change of direction and stack present
610 if( eDir
!= m_ePageMove
&& m_ePageMove
!= MV_NO
&& PopCursor( true, bSelect
))
613 const bool bRet
= PushCursor(lOffset
, bSelect
);
618 bool SwWrtShell::GotoPage(sal_uInt16 nPage
, bool bRecord
)
620 addCurrentPosition();
621 ShellMoveCursor
aTmp( this, false);
622 if( SwCursorShell::GotoPage(nPage
) && bRecord
)
634 bool SwWrtShell::GotoMark( const ::sw::mark::MarkBase
* const pMark
, bool bSelect
)
636 ShellMoveCursor
aTmp( this, bSelect
);
637 SwPosition aPos
= *GetCursor()->GetPoint();
638 bool bRet
= SwCursorShell::GotoMark( pMark
, true/*bStart*/ );
640 m_aNavigationMgr
.addEntry(aPos
);
644 bool SwWrtShell::GotoFly( const OUString
& rName
, FlyCntType eType
, bool bSelFrame
)
646 SwPosition aPos
= *GetCursor()->GetPoint();
647 bool bRet
= SwFEShell::GotoFly(rName
, eType
, bSelFrame
);
649 m_aNavigationMgr
.addEntry(aPos
);
653 bool SwWrtShell::GotoINetAttr( const SwTextINetFormat
& rAttr
)
655 SwPosition aPos
= *GetCursor()->GetPoint();
656 bool bRet
= SwCursorShell::GotoINetAttr(rAttr
);
658 m_aNavigationMgr
.addEntry(aPos
);
662 void SwWrtShell::GotoOutline( SwOutlineNodes::size_type nIdx
)
664 addCurrentPosition();
665 SwCursorShell::GotoOutline (nIdx
);
668 bool SwWrtShell::GotoOutline( const OUString
& rName
)
670 SwPosition aPos
= *GetCursor()->GetPoint();
671 bool bRet
= SwCursorShell::GotoOutline (rName
);
673 m_aNavigationMgr
.addEntry(aPos
);
677 bool SwWrtShell::GotoDrawingObject(std::u16string_view rName
)
679 SwPosition aPos
= *GetCursor()->GetPoint();
680 SdrPage
* pPage
= getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
681 for (const rtl::Reference
<SdrObject
>& pObj
: *pPage
)
683 if (pObj
->GetName() == rName
)
685 bool bRet
= SelectObj(Point(), 0, pObj
.get());
688 m_aNavigationMgr
.addEntry(aPos
);
697 bool SwWrtShell::GotoRegion( std::u16string_view rName
)
699 SwPosition aPos
= *GetCursor()->GetPoint();
700 bool bRet
= SwCursorShell::GotoRegion (rName
);
702 m_aNavigationMgr
.addEntry(aPos
);
706 bool SwWrtShell::GotoRefMark( const OUString
& rRefMark
, sal_uInt16 nSubType
,
707 sal_uInt16 nSeqNo
, sal_uInt16 nFlags
)
709 SwPosition aPos
= *GetCursor()->GetPoint();
710 bool bRet
= SwCursorShell::GotoRefMark(rRefMark
, nSubType
, nSeqNo
, nFlags
);
712 m_aNavigationMgr
.addEntry(aPos
);
716 bool SwWrtShell::GotoNextTOXBase( const OUString
* pName
)
718 SwPosition aPos
= *GetCursor()->GetPoint();
719 bool bRet
= SwCursorShell::GotoNextTOXBase(pName
);
721 m_aNavigationMgr
.addEntry(aPos
);
725 bool SwWrtShell::GotoTable( const OUString
& rName
)
727 SwPosition aPos
= *GetCursor()->GetPoint();
728 bool bRet
= SwCursorShell::GotoTable(rName
);
730 m_aNavigationMgr
.addEntry(aPos
);
734 void SwWrtShell::GotoFormatField( const SwFormatField
& rField
) {
735 SwPosition aPos
= *GetCursor()->GetPoint();
736 bool bRet
= SwCursorShell::GotoFormatField(rField
);
738 m_aNavigationMgr
.addEntry(aPos
);
741 void SwWrtShell::GotoFootnoteAnchor(const SwTextFootnote
& rTextFootnote
)
743 SwPosition aPos
= *GetCursor()->GetPoint();
744 bool bRet
= SwCursorShell::GotoFootnoteAnchor(rTextFootnote
);
746 m_aNavigationMgr
.addEntry(aPos
);
749 const SwRangeRedline
* SwWrtShell::GotoRedline( SwRedlineTable::size_type nArrPos
, bool bSelect
) {
750 SwPosition aPos
= *GetCursor()->GetPoint();
751 const SwRangeRedline
*pRedline
= SwCursorShell::GotoRedline(nArrPos
, bSelect
);
753 m_aNavigationMgr
.addEntry(aPos
);
757 bool SwWrtShell::SelectTextAttr( sal_uInt16 nWhich
, const SwTextAttr
* pAttr
)
761 SwMvContext
aMvContext(this);
763 bRet
= SwCursorShell::SelectTextAttr( nWhich
, false, pAttr
);
769 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */