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 <crsrsh.hxx>
21 #include <doc.hxx>
22 #include <pagefrm.hxx>
23 #include <cntfrm.hxx>
24 #include <ftnfrm.hxx>
25 #include <swcrsr.hxx>
26 #include <ndtxt.hxx>
27 #include <txtfrm.hxx>
28 #include <txtftn.hxx>
29 #include <ftnidx.hxx>
30 #include <viscrs.hxx>
31 #include "callnk.hxx"
32 #include <svx/srchdlg.hxx>
33
CallCursorShellFN(FNCursorShell fnCursor)34 bool SwCursorShell::CallCursorShellFN( FNCursorShell fnCursor )
35 {
36 SwCallLink aLk( *this ); // watch Cursor-Moves
37 bool bRet = (this->*fnCursor)();
38 if( bRet )
39 UpdateCursor( SwCursorShell::SCROLLWIN | SwCursorShell::CHKRANGE |
40 SwCursorShell::READONLY );
41 return bRet;
42 }
43
CallCursorFN(FNCursor fnCursor)44 bool SwCursorShell::CallCursorFN( FNCursor fnCursor )
45 {
46 SwCallLink aLk( *this ); // watch Cursor-Moves
47 SwCursor* pCursor = getShellCursor( true );
48 bool bRet = (pCursor->*fnCursor)();
49 if( bRet )
50 UpdateCursor( SwCursorShell::SCROLLWIN | SwCursorShell::CHKRANGE |
51 SwCursorShell::READONLY );
52 return bRet;
53 }
54
GotoFootnoteText()55 bool SwCursor::GotoFootnoteText()
56 {
57 // jump from content to footnote
58 bool bRet = false;
59 SwTextNode* pTextNd = GetPoint()->nNode.GetNode().GetTextNode();
60
61 SwTextAttr *const pFootnote( pTextNd
62 ? pTextNd->GetTextAttrForCharAt(
63 GetPoint()->nContent.GetIndex(), RES_TXTATR_FTN)
64 : nullptr);
65 if (pFootnote)
66 {
67 SwCursorSaveState aSaveState( *this );
68 GetPoint()->nNode = *static_cast<SwTextFootnote*>(pFootnote)->GetStartNode();
69
70 SwContentNode* pCNd = GetDoc()->GetNodes().GoNextSection(
71 &GetPoint()->nNode,
72 true, !IsReadOnlyAvailable() );
73 if( pCNd )
74 {
75 GetPoint()->nContent.Assign( pCNd, 0 );
76 bRet = !IsSelOvr( SwCursorSelOverFlags::CheckNodeSection |
77 SwCursorSelOverFlags::Toggle );
78 }
79 }
80 return bRet;
81 }
82
GotoFootnoteText()83 bool SwCursorShell::GotoFootnoteText()
84 {
85 bool bRet = CallCursorFN( &SwCursor::GotoFootnoteText );
86 if( !bRet )
87 {
88 SwTextNode* pTextNd = GetCursor_() ?
89 GetCursor_()->GetPoint()->nNode.GetNode().GetTextNode() : nullptr;
90 if( pTextNd )
91 {
92 std::pair<Point, bool> const tmp(GetCursor_()->GetSttPos(), true);
93 const SwFrame *pFrame = pTextNd->getLayoutFrame( GetLayout(),
94 GetCursor_()->Start(), &tmp);
95 const SwFootnoteBossFrame* pFootnoteBoss;
96 bool bSkip = pFrame && pFrame->IsInFootnote();
97 while( pFrame && nullptr != ( pFootnoteBoss = pFrame->FindFootnoteBossFrame() ) )
98 {
99 if( nullptr != ( pFrame = pFootnoteBoss->FindFootnoteCont() ) )
100 {
101 if( bSkip )
102 bSkip = false;
103 else
104 {
105 const SwContentFrame* pCnt = static_cast<const SwLayoutFrame*>
106 (pFrame)->ContainsContent();
107 if( pCnt )
108 {
109 SwTextFrame const*const pTF(
110 static_cast<const SwTextFrame*>(pCnt));
111 *GetCursor_()->GetPoint() =
112 pTF->MapViewToModelPos(pTF->GetOfst());
113 UpdateCursor( SwCursorShell::SCROLLWIN |
114 SwCursorShell::CHKRANGE | SwCursorShell::READONLY );
115 bRet = true;
116 break;
117 }
118 }
119 }
120 if( pFootnoteBoss->GetNext() && !pFootnoteBoss->IsPageFrame() )
121 pFrame = pFootnoteBoss->GetNext();
122 else
123 pFrame = pFootnoteBoss->GetUpper();
124 }
125 }
126 }
127 return bRet;
128 }
129
GotoFootnoteAnchor()130 bool SwCursor::GotoFootnoteAnchor()
131 {
132 // jump from footnote to anchor
133 const SwNode* pSttNd = GetNode().FindFootnoteStartNode();
134 if( pSttNd )
135 {
136 // search in all footnotes in document for this StartIndex
137 const SwTextFootnote* pTextFootnote;
138 const SwFootnoteIdxs& rFootnoteArr = pSttNd->GetDoc()->GetFootnoteIdxs();
139 for( size_t n = 0; n < rFootnoteArr.size(); ++n )
140 if( nullptr != ( pTextFootnote = rFootnoteArr[ n ])->GetStartNode() &&
141 pSttNd == &pTextFootnote->GetStartNode()->GetNode() )
142 {
143 SwCursorSaveState aSaveState( *this );
144
145 SwTextNode& rTNd = const_cast<SwTextNode&>(pTextFootnote->GetTextNode());
146 GetPoint()->nNode = rTNd;
147 GetPoint()->nContent.Assign( &rTNd, pTextFootnote->GetStart() );
148
149 return !IsSelOvr( SwCursorSelOverFlags::CheckNodeSection |
150 SwCursorSelOverFlags::Toggle );
151 }
152 }
153 return false;
154 }
155
GotoFootnoteAnchor()156 bool SwCursorShell::GotoFootnoteAnchor()
157 {
158 // jump from footnote to anchor
159 SwCallLink aLk( *this ); // watch Cursor-Moves
160 bool bRet = m_pCurrentCursor->GotoFootnoteAnchor();
161 if( bRet )
162 {
163 // special treatment for table header row
164 m_pCurrentCursor->GetPtPos() = Point();
165 UpdateCursor( SwCursorShell::SCROLLWIN | SwCursorShell::CHKRANGE |
166 SwCursorShell::READONLY );
167 }
168 return bRet;
169 }
170
CmpLE(const SwTextFootnote & rFootnote,sal_uLong nNd,sal_Int32 nCnt)171 static bool CmpLE( const SwTextFootnote& rFootnote, sal_uLong nNd, sal_Int32 nCnt )
172 {
173 const sal_uLong nTNd = rFootnote.GetTextNode().GetIndex();
174 return nTNd < nNd || ( nTNd == nNd && rFootnote.GetStart() <= nCnt );
175 }
176
CmpL(const SwTextFootnote & rFootnote,sal_uLong nNd,sal_Int32 nCnt)177 static bool CmpL( const SwTextFootnote& rFootnote, sal_uLong nNd, sal_Int32 nCnt )
178 {
179 const sal_uLong nTNd = rFootnote.GetTextNode().GetIndex();
180 return nTNd < nNd || ( nTNd == nNd && rFootnote.GetStart() < nCnt );
181 }
182
GotoNextFootnoteAnchor()183 bool SwCursor::GotoNextFootnoteAnchor()
184 {
185 const SwFootnoteIdxs& rFootnoteArr = GetDoc()->GetFootnoteIdxs();
186 const SwTextFootnote* pTextFootnote = nullptr;
187 size_t nPos = 0;
188
189 if( rFootnoteArr.empty() )
190 {
191 SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::NavElementNotFound );
192 return false;
193 }
194
195 if( rFootnoteArr.SeekEntry( GetPoint()->nNode, &nPos ))
196 {
197 // there is a footnote with this index, so search also for the next one
198 if( nPos < rFootnoteArr.size() )
199 {
200 sal_uLong nNdPos = GetPoint()->nNode.GetIndex();
201 const sal_Int32 nCntPos = GetPoint()->nContent.GetIndex();
202
203 pTextFootnote = rFootnoteArr[ nPos ];
204 // search forwards
205 if( CmpLE( *pTextFootnote, nNdPos, nCntPos ) )
206 {
207 pTextFootnote = nullptr;
208 for( ++nPos; nPos < rFootnoteArr.size(); ++nPos )
209 {
210 pTextFootnote = rFootnoteArr[ nPos ];
211 if( !CmpLE( *pTextFootnote, nNdPos, nCntPos ) )
212 break; // found
213 pTextFootnote = nullptr;
214 }
215 }
216 else if( nPos )
217 {
218 // search backwards
219 pTextFootnote = nullptr;
220 while( nPos )
221 {
222 pTextFootnote = rFootnoteArr[ --nPos ];
223 if( CmpLE( *pTextFootnote, nNdPos, nCntPos ) )
224 {
225 pTextFootnote = rFootnoteArr[ ++nPos ];
226 break; // found
227 }
228 }
229 }
230 }
231 }
232 else if( nPos < rFootnoteArr.size() )
233 pTextFootnote = rFootnoteArr[ nPos ];
234
235 if (pTextFootnote == nullptr)
236 {
237 pTextFootnote = rFootnoteArr[ 0 ];
238 SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::EndWrapped );
239 }
240 else
241 SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::Empty );
242
243 bool bRet = nullptr != pTextFootnote;
244 if( bRet )
245 {
246 SwCursorSaveState aSaveState( *this );
247
248 SwTextNode& rTNd = const_cast<SwTextNode&>(pTextFootnote->GetTextNode());
249 GetPoint()->nNode = rTNd;
250 GetPoint()->nContent.Assign( &rTNd, pTextFootnote->GetStart() );
251 bRet = !IsSelOvr();
252 }
253 return bRet;
254 }
255
GotoPrevFootnoteAnchor()256 bool SwCursor::GotoPrevFootnoteAnchor()
257 {
258 const SwFootnoteIdxs& rFootnoteArr = GetDoc()->GetFootnoteIdxs();
259 const SwTextFootnote* pTextFootnote = nullptr;
260 size_t nPos = 0;
261
262 if( rFootnoteArr.empty() )
263 {
264 SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::NavElementNotFound );
265 return false;
266 }
267
268 if( rFootnoteArr.SeekEntry( GetPoint()->nNode, &nPos ) )
269 {
270 // there is a footnote with this index, so search also for the next one
271 sal_uLong nNdPos = GetPoint()->nNode.GetIndex();
272 const sal_Int32 nCntPos = GetPoint()->nContent.GetIndex();
273
274 pTextFootnote = rFootnoteArr[ nPos ];
275 // search forwards
276 if( CmpL( *pTextFootnote, nNdPos, nCntPos ))
277 {
278 for( ++nPos; nPos < rFootnoteArr.size(); ++nPos )
279 {
280 pTextFootnote = rFootnoteArr[ nPos ];
281 if( !CmpL( *pTextFootnote, nNdPos, nCntPos ) )
282 {
283 pTextFootnote = rFootnoteArr[ nPos-1 ];
284 break;
285 }
286 }
287 }
288 else if( nPos )
289 {
290 // search backwards
291 pTextFootnote = nullptr;
292 while( nPos )
293 {
294 pTextFootnote = rFootnoteArr[ --nPos ];
295 if( CmpL( *pTextFootnote, nNdPos, nCntPos ))
296 break; // found
297 pTextFootnote = nullptr;
298 }
299 }
300 else
301 pTextFootnote = nullptr;
302 }
303 else if( nPos )
304 pTextFootnote = rFootnoteArr[ nPos-1 ];
305
306 if( pTextFootnote == nullptr )
307 {
308 pTextFootnote = rFootnoteArr[ rFootnoteArr.size() - 1 ];
309 SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::StartWrapped );
310 }
311 else
312 SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::Empty );
313
314 bool bRet = nullptr != pTextFootnote;
315 if( bRet )
316 {
317 SwCursorSaveState aSaveState( *this );
318
319 SwTextNode& rTNd = const_cast<SwTextNode&>(pTextFootnote->GetTextNode());
320 GetPoint()->nNode = rTNd;
321 GetPoint()->nContent.Assign( &rTNd, pTextFootnote->GetStart() );
322 bRet = !IsSelOvr();
323 }
324 return bRet;
325 }
326
GotoNextFootnoteAnchor()327 bool SwCursorShell::GotoNextFootnoteAnchor()
328 {
329 return CallCursorFN( &SwCursor::GotoNextFootnoteAnchor );
330 }
331
GotoPrevFootnoteAnchor()332 bool SwCursorShell::GotoPrevFootnoteAnchor()
333 {
334 return CallCursorFN( &SwCursor::GotoPrevFootnoteAnchor );
335 }
336
337 /// jump from border to anchor
GotoFlyAnchor()338 void SwCursorShell::GotoFlyAnchor()
339 {
340 SET_CURR_SHELL( this );
341 const SwFrame* pFrame = GetCurrFrame();
342 do {
343 pFrame = pFrame->GetUpper();
344 } while( pFrame && !pFrame->IsFlyFrame() );
345
346 if( !pFrame ) // no FlyFrame
347 return;
348
349 SwCallLink aLk( *this ); // watch Cursor-Moves
350 SwCursorSaveState aSaveState( *m_pCurrentCursor );
351
352 // jump in BodyFrame closest to FlyFrame
353 SwRect aTmpRect( m_aCharRect );
354 if( !pFrame->getFrameArea().IsInside( aTmpRect ))
355 aTmpRect = pFrame->getFrameArea();
356 Point aPt( aTmpRect.Left(), aTmpRect.Top() +
357 ( aTmpRect.Bottom() - aTmpRect.Top() ) / 2 );
358 aPt.setX(aPt.getX() > (pFrame->getFrameArea().Left() + (pFrame->getFrameArea().SSize().Width() / 2 ))
359 ? pFrame->getFrameArea().Right()
360 : pFrame->getFrameArea().Left());
361
362 const SwPageFrame* pPageFrame = pFrame->FindPageFrame();
363 const SwContentFrame* pFndFrame = pPageFrame->GetContentPos( aPt, false, true );
364 pFndFrame->GetCursorOfst( m_pCurrentCursor->GetPoint(), aPt );
365
366 bool bRet = !m_pCurrentCursor->IsInProtectTable() && !m_pCurrentCursor->IsSelOvr();
367 if( bRet )
368 UpdateCursor( SwCursorShell::SCROLLWIN | SwCursorShell::CHKRANGE |
369 SwCursorShell::READONLY );
370 }
371
372 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
373