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 .
22 #include <rootfrm.hxx>
26 #include <IDocumentMarkAccess.hxx>
27 #include <IDocumentSettingAccess.hxx>
31 struct CursorStateHelper
33 explicit CursorStateHelper(SwCursorShell
const & rShell
)
34 : m_pCursor(rShell
.GetCursor())
35 , m_aSaveState(*m_pCursor
)
38 void SetCursorToMark(::sw::mark::IMark
const * const pMark
)
40 *(m_pCursor
->GetPoint()) = pMark
->GetMarkStart();
41 if(pMark
->IsExpanded())
44 *(m_pCursor
->GetMark()) = pMark
->GetMarkEnd();
48 /// returns true if the Cursor had been rolled back
49 bool RollbackIfIllegal()
51 if(m_pCursor
->IsSelOvr(SwCursorSelOverFlags::CheckNodeSection
52 | SwCursorSelOverFlags::Toggle
))
54 m_pCursor
->DeleteMark();
55 m_pCursor
->RestoreSavePos();
62 SwCursorSaveState m_aSaveState
;
65 bool lcl_ReverseMarkOrderingByEnd(const ::sw::mark::IMark
* pFirst
,
66 const ::sw::mark::IMark
* pSecond
)
68 return pFirst
->GetMarkEnd() > pSecond
->GetMarkEnd();
71 bool lcl_IsInvisibleBookmark(const ::sw::mark::IMark
* pMark
)
73 return IDocumentMarkAccess::GetType(*pMark
) != IDocumentMarkAccess::MarkType::BOOKMARK
;
77 // at CurrentCursor.SPoint
78 ::sw::mark::IMark
* SwCursorShell::SetBookmark(
79 const vcl::KeyCode
& rCode
,
80 const OUString
& rName
,
81 IDocumentMarkAccess::MarkType eMark
)
84 ::sw::mark::IMark
* pMark
= getIDocumentMarkAccess()->makeMark(
87 eMark
, sw::mark::InsertMode::New
);
88 ::sw::mark::IBookmark
* pBookmark
= dynamic_cast< ::sw::mark::IBookmark
* >(pMark
);
91 pBookmark
->SetKeyCode(rCode
);
92 pBookmark
->SetShortName(OUString());
97 // set CurrentCursor.SPoint
99 // at CurrentCursor.SPoint
100 ::sw::mark::IMark
* SwCursorShell::SetBookmark2(
101 const vcl::KeyCode
& rCode
,
102 const OUString
& rName
,
104 const OUString
& rCondition
)
107 ::sw::mark::IMark
* pMark
= getIDocumentMarkAccess()->makeMark(
110 IDocumentMarkAccess::MarkType::BOOKMARK
, sw::mark::InsertMode::New
);
111 ::sw::mark::IBookmark
* pBookmark
= dynamic_cast< ::sw::mark::IBookmark
* >(pMark
);
114 pBookmark
->SetKeyCode(rCode
);
115 pBookmark
->SetShortName(OUString());
116 pBookmark
->Hide(bHide
);
117 pBookmark
->SetHideCondition(rCondition
);
125 bool IsMarkHidden(SwRootFrame
const& rLayout
, ::sw::mark::IMark
const& rMark
)
127 if (!rLayout
.HasMergedParas())
131 SwNode
const& rNode(rMark
.GetMarkPos().GetNode());
132 SwTextNode
const*const pTextNode(rNode
.GetTextNode());
133 if (pTextNode
== nullptr)
134 { // UNO_BOOKMARK may point to table node
135 return rNode
.GetRedlineMergeFlag() == SwNode::Merge::Hidden
;
137 SwTextFrame
const*const pFrame(static_cast<SwTextFrame
const*>(
138 pTextNode
->getLayoutFrame(&rLayout
)));
143 if (rMark
.IsExpanded())
145 SwTextFrame
const*const pOtherFrame(static_cast<SwTextFrame
const*>(
146 rMark
.GetOtherMarkPos().GetNode().GetTextNode()->getLayoutFrame(&rLayout
)));
147 return pFrame
== pOtherFrame
148 && pFrame
->MapModelToViewPos(rMark
.GetMarkPos())
149 == pFrame
->MapModelToViewPos(rMark
.GetOtherMarkPos());
153 if (rMark
.GetMarkPos().GetContentIndex() == pTextNode
->Len())
154 { // at end of node: never deleted (except if node deleted)
155 return pTextNode
->GetRedlineMergeFlag() == SwNode::Merge::Hidden
;
158 { // check character following mark pos
159 return pFrame
->MapModelToViewPos(rMark
.GetMarkPos())
160 == pFrame
->MapModelToView(pTextNode
, rMark
.GetMarkPos().GetContentIndex() + 1);
167 // set CurrentCursor.SPoint
168 bool SwCursorShell::GotoMark(const ::sw::mark::IMark
* const pMark
, bool bAtStart
)
170 if (sw::IsMarkHidden(*GetLayout(), *pMark
))
174 // watch Cursor-Moves
175 CursorStateHelper
aCursorSt(*this);
177 *aCursorSt
.m_pCursor
->GetPoint() = pMark
->GetMarkStart();
179 *aCursorSt
.m_pCursor
->GetPoint() = pMark
->GetMarkEnd();
181 if(aCursorSt
.RollbackIfIllegal()) return false;
183 UpdateCursor(SwCursorShell::SCROLLWIN
|SwCursorShell::CHKRANGE
|SwCursorShell::READONLY
);
187 bool SwCursorShell::GotoMark(const ::sw::mark::IMark
* const pMark
)
189 if (sw::IsMarkHidden(*GetLayout(), *pMark
))
193 // watch Cursor-Moves
194 CursorStateHelper
aCursorSt(*this);
195 aCursorSt
.SetCursorToMark(pMark
);
197 if(aCursorSt
.RollbackIfIllegal()) return false;
199 UpdateCursor(SwCursorShell::SCROLLWIN
|SwCursorShell::CHKRANGE
|SwCursorShell::READONLY
);
203 bool SwCursorShell::GoNextBookmark()
205 IDocumentMarkAccess
* pMarkAccess
= getIDocumentMarkAccess();
206 std::vector
<::sw::mark::IMark
*> vCandidates
;
208 pMarkAccess
->findFirstBookmarkStartsAfter(*GetCursor()->GetPoint()),
209 pMarkAccess
->getBookmarksEnd(),
210 back_inserter(vCandidates
),
211 &lcl_IsInvisibleBookmark
);
213 // watch Cursor-Moves
214 CursorStateHelper
aCursorSt(*this);
215 auto ppMark
= vCandidates
.begin();
216 for(; ppMark
!=vCandidates
.end(); ++ppMark
)
218 if (sw::IsMarkHidden(*GetLayout(), **ppMark
))
222 aCursorSt
.SetCursorToMark(*ppMark
);
223 if(!aCursorSt
.RollbackIfIllegal())
224 break; // found legal move
226 if(ppMark
==vCandidates
.end())
232 UpdateCursor(SwCursorShell::SCROLLWIN
|SwCursorShell::CHKRANGE
|SwCursorShell::READONLY
);
236 bool SwCursorShell::GoPrevBookmark()
238 IDocumentMarkAccess
* pMarkAccess
= getIDocumentMarkAccess();
239 // candidates from which to choose the mark before
240 // no need to consider marks starting after rPos
241 std::vector
<::sw::mark::IMark
*> vCandidates
;
243 pMarkAccess
->getBookmarksBegin(),
244 pMarkAccess
->findFirstBookmarkStartsAfter(*GetCursor()->GetPoint()),
245 back_inserter(vCandidates
),
246 &lcl_IsInvisibleBookmark
);
250 &lcl_ReverseMarkOrderingByEnd
);
252 // watch Cursor-Moves
253 CursorStateHelper
aCursorSt(*this);
254 auto ppMark
= vCandidates
.begin();
255 for(; ppMark
!=vCandidates
.end(); ++ppMark
)
257 // ignoring those not ending before the Cursor
258 // (we were only able to eliminate those starting
259 // behind the Cursor by the upper_bound(..)
261 if(!((**ppMark
).GetMarkEnd() < *GetCursor()->GetPoint()))
263 if (sw::IsMarkHidden(*GetLayout(), **ppMark
))
267 aCursorSt
.SetCursorToMark(*ppMark
);
268 if(!aCursorSt
.RollbackIfIllegal())
269 break; // found legal move
271 if(ppMark
==vCandidates
.end())
277 UpdateCursor(SwCursorShell::SCROLLWIN
|SwCursorShell::CHKRANGE
|SwCursorShell::READONLY
);
281 bool SwCursorShell::IsFormProtected()
283 return getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_FORM
);
286 ::sw::mark::IFieldmark
* SwCursorShell::GetCurrentFieldmark()
289 SwPosition
pos(*GetCursor()->Start());
290 return getIDocumentMarkAccess()->getInnerFieldmarkFor(pos
);
293 sw::mark::IFieldmark
* SwCursorShell::GetFieldmarkAfter(bool bLoop
)
295 SwPosition
pos(*GetCursor()->GetPoint());
296 return getIDocumentMarkAccess()->getFieldmarkAfter(pos
, bLoop
);
299 sw::mark::IFieldmark
* SwCursorShell::GetFieldmarkBefore(bool bLoop
)
301 SwPosition
pos(*GetCursor()->GetPoint());
302 return getIDocumentMarkAccess()->getFieldmarkBefore(pos
, bLoop
);
305 bool SwCursorShell::GotoFieldmark(::sw::mark::IFieldmark
const * const pMark
)
307 if(pMark
==nullptr) return false;
309 // watch Cursor-Moves
310 CursorStateHelper
aCursorSt(*this);
311 aCursorSt
.SetCursorToMark(pMark
);
312 aCursorSt
.m_pCursor
->GetPoint()->AdjustContent(+1);
313 aCursorSt
.m_pCursor
->GetMark()->AdjustContent(-1);
315 if(aCursorSt
.RollbackIfIllegal()) return false;
317 UpdateCursor(SwCursorShell::SCROLLWIN
|SwCursorShell::CHKRANGE
|SwCursorShell::READONLY
);
321 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */