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 )
98 {
99 pFootnoteBoss = pFrame->FindFootnoteBossFrame();
100 if (!pFootnoteBoss)
101 break;
102 pFrame = pFootnoteBoss->FindFootnoteCont();
103 if( pFrame )
104 {
105 if( bSkip )
106 bSkip = false;
107 else
108 {
109 const SwContentFrame* pCnt = static_cast<const SwLayoutFrame*>
110 (pFrame)->ContainsContent();
111 if( pCnt )
112 {
113 SwTextFrame const*const pTF(
114 static_cast<const SwTextFrame*>(pCnt));
115 *GetCursor_()->GetPoint() =
116 pTF->MapViewToModelPos(pTF->GetOffset());
117 UpdateCursor( SwCursorShell::SCROLLWIN |
118 SwCursorShell::CHKRANGE | SwCursorShell::READONLY );
119 bRet = true;
120 break;
121 }
122 }
123 }
124 if( pFootnoteBoss->GetNext() && !pFootnoteBoss->IsPageFrame() )
125 pFrame = pFootnoteBoss->GetNext();
126 else
127 pFrame = pFootnoteBoss->GetUpper();
128 }
129 }
130 }
131 return bRet;
132 }
133
GotoFootnoteAnchor()134 bool SwCursor::GotoFootnoteAnchor()
135 {
136 // jump from footnote to anchor
137 const SwNode* pSttNd = GetNode().FindFootnoteStartNode();
138 if( pSttNd )
139 {
140 // search in all footnotes in document for this StartIndex
141 const SwFootnoteIdxs& rFootnoteArr = pSttNd->GetDoc().GetFootnoteIdxs();
142 for( size_t n = 0; n < rFootnoteArr.size(); ++n )
143 {
144 const SwTextFootnote* pTextFootnote = rFootnoteArr[ n ];
145 if( nullptr != pTextFootnote->GetStartNode() &&
146 pSttNd == &pTextFootnote->GetStartNode()->GetNode() )
147 {
148 SwCursorSaveState aSaveState( *this );
149
150 SwTextNode& rTNd = const_cast<SwTextNode&>(pTextFootnote->GetTextNode());
151 GetPoint()->nNode = rTNd;
152 GetPoint()->nContent.Assign( &rTNd, pTextFootnote->GetStart() );
153
154 return !IsSelOvr( SwCursorSelOverFlags::CheckNodeSection |
155 SwCursorSelOverFlags::Toggle );
156 }
157 }
158 }
159 return false;
160 }
161
GotoFootnoteAnchor()162 bool SwCursorShell::GotoFootnoteAnchor()
163 {
164 // jump from footnote to anchor
165 SwCallLink aLk( *this ); // watch Cursor-Moves
166 bool bRet = m_pCurrentCursor->GotoFootnoteAnchor();
167 if( bRet )
168 {
169 // special treatment for table header row
170 m_pCurrentCursor->GetPtPos() = Point();
171 UpdateCursor( SwCursorShell::SCROLLWIN | SwCursorShell::CHKRANGE |
172 SwCursorShell::READONLY );
173 }
174 return bRet;
175 }
176
CmpLE(const SwTextFootnote & rFootnote,sal_uLong nNd,sal_Int32 nCnt)177 static bool CmpLE( 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
CmpL(const SwTextFootnote & rFootnote,sal_uLong nNd,sal_Int32 nCnt)183 static bool CmpL( const SwTextFootnote& rFootnote, sal_uLong nNd, sal_Int32 nCnt )
184 {
185 const sal_uLong nTNd = rFootnote.GetTextNode().GetIndex();
186 return nTNd < nNd || ( nTNd == nNd && rFootnote.GetStart() < nCnt );
187 }
188
GotoNextFootnoteAnchor()189 bool SwCursor::GotoNextFootnoteAnchor()
190 {
191 const SwFootnoteIdxs& rFootnoteArr = GetDoc().GetFootnoteIdxs();
192 const SwTextFootnote* pTextFootnote = nullptr;
193 size_t nPos = 0;
194
195 if( rFootnoteArr.empty() )
196 {
197 SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::NavElementNotFound );
198 return false;
199 }
200
201 if( rFootnoteArr.SeekEntry( GetPoint()->nNode, &nPos ))
202 {
203 // there is a footnote with this index, so search also for the next one
204 if( nPos < rFootnoteArr.size() )
205 {
206 sal_uLong nNdPos = GetPoint()->nNode.GetIndex();
207 const sal_Int32 nCntPos = GetPoint()->nContent.GetIndex();
208
209 pTextFootnote = rFootnoteArr[ nPos ];
210 // search forwards
211 if( CmpLE( *pTextFootnote, nNdPos, nCntPos ) )
212 {
213 pTextFootnote = nullptr;
214 for( ++nPos; nPos < rFootnoteArr.size(); ++nPos )
215 {
216 pTextFootnote = rFootnoteArr[ nPos ];
217 if( !CmpLE( *pTextFootnote, nNdPos, nCntPos ) )
218 break; // found
219 pTextFootnote = nullptr;
220 }
221 }
222 else if( nPos )
223 {
224 // search backwards
225 pTextFootnote = nullptr;
226 while( nPos )
227 {
228 pTextFootnote = rFootnoteArr[ --nPos ];
229 if( CmpLE( *pTextFootnote, nNdPos, nCntPos ) )
230 {
231 pTextFootnote = rFootnoteArr[ ++nPos ];
232 break; // found
233 }
234 }
235 }
236 }
237 }
238 else if( nPos < rFootnoteArr.size() )
239 pTextFootnote = rFootnoteArr[ nPos ];
240
241 if (pTextFootnote == nullptr)
242 {
243 pTextFootnote = rFootnoteArr[ 0 ];
244 SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::EndWrapped );
245 }
246 else
247 SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::Empty );
248
249 bool bRet = nullptr != pTextFootnote;
250 if( bRet )
251 {
252 SwCursorSaveState aSaveState( *this );
253
254 SwTextNode& rTNd = const_cast<SwTextNode&>(pTextFootnote->GetTextNode());
255 GetPoint()->nNode = rTNd;
256 GetPoint()->nContent.Assign( &rTNd, pTextFootnote->GetStart() );
257 bRet = !IsSelOvr();
258 }
259 return bRet;
260 }
261
GotoPrevFootnoteAnchor()262 bool SwCursor::GotoPrevFootnoteAnchor()
263 {
264 const SwFootnoteIdxs& rFootnoteArr = GetDoc().GetFootnoteIdxs();
265 const SwTextFootnote* pTextFootnote = nullptr;
266 size_t nPos = 0;
267
268 if( rFootnoteArr.empty() )
269 {
270 SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::NavElementNotFound );
271 return false;
272 }
273
274 if( rFootnoteArr.SeekEntry( GetPoint()->nNode, &nPos ) )
275 {
276 // there is a footnote with this index, so search also for the next one
277 sal_uLong nNdPos = GetPoint()->nNode.GetIndex();
278 const sal_Int32 nCntPos = GetPoint()->nContent.GetIndex();
279
280 pTextFootnote = rFootnoteArr[ nPos ];
281 // search forwards
282 if( CmpL( *pTextFootnote, nNdPos, nCntPos ))
283 {
284 for( ++nPos; nPos < rFootnoteArr.size(); ++nPos )
285 {
286 pTextFootnote = rFootnoteArr[ nPos ];
287 if( !CmpL( *pTextFootnote, nNdPos, nCntPos ) )
288 {
289 pTextFootnote = rFootnoteArr[ nPos-1 ];
290 break;
291 }
292 }
293 }
294 else if( nPos )
295 {
296 // search backwards
297 pTextFootnote = nullptr;
298 while( nPos )
299 {
300 pTextFootnote = rFootnoteArr[ --nPos ];
301 if( CmpL( *pTextFootnote, nNdPos, nCntPos ))
302 break; // found
303 pTextFootnote = nullptr;
304 }
305 }
306 else
307 pTextFootnote = nullptr;
308 }
309 else if( nPos )
310 pTextFootnote = rFootnoteArr[ nPos-1 ];
311
312 if( pTextFootnote == nullptr )
313 {
314 pTextFootnote = rFootnoteArr[ rFootnoteArr.size() - 1 ];
315 SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::StartWrapped );
316 }
317 else
318 SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::Empty );
319
320 bool bRet = nullptr != pTextFootnote;
321 if( bRet )
322 {
323 SwCursorSaveState aSaveState( *this );
324
325 SwTextNode& rTNd = const_cast<SwTextNode&>(pTextFootnote->GetTextNode());
326 GetPoint()->nNode = rTNd;
327 GetPoint()->nContent.Assign( &rTNd, pTextFootnote->GetStart() );
328 bRet = !IsSelOvr();
329 }
330 return bRet;
331 }
332
GotoNextFootnoteAnchor()333 bool SwCursorShell::GotoNextFootnoteAnchor()
334 {
335 return CallCursorFN( &SwCursor::GotoNextFootnoteAnchor );
336 }
337
GotoPrevFootnoteAnchor()338 bool SwCursorShell::GotoPrevFootnoteAnchor()
339 {
340 return CallCursorFN( &SwCursor::GotoPrevFootnoteAnchor );
341 }
342
343 /// jump from border to anchor
GotoFlyAnchor()344 void SwCursorShell::GotoFlyAnchor()
345 {
346 CurrShell aCurr( this );
347 const SwFrame* pFrame = GetCurrFrame();
348 do {
349 pFrame = pFrame->GetUpper();
350 } while( pFrame && !pFrame->IsFlyFrame() );
351
352 if( !pFrame ) // no FlyFrame
353 return;
354
355 SwCallLink aLk( *this ); // watch Cursor-Moves
356 SwCursorSaveState aSaveState( *m_pCurrentCursor );
357
358 // jump in BodyFrame closest to FlyFrame
359 SwRect aTmpRect( m_aCharRect );
360 if( !pFrame->getFrameArea().IsInside( aTmpRect ))
361 aTmpRect = pFrame->getFrameArea();
362 Point aPt( aTmpRect.Left(), aTmpRect.Top() +
363 ( aTmpRect.Bottom() - aTmpRect.Top() ) / 2 );
364 aPt.setX(aPt.getX() > (pFrame->getFrameArea().Left() + (pFrame->getFrameArea().SSize().Width() / 2 ))
365 ? pFrame->getFrameArea().Right()
366 : pFrame->getFrameArea().Left());
367
368 const SwPageFrame* pPageFrame = pFrame->FindPageFrame();
369 const SwContentFrame* pFndFrame = pPageFrame->GetContentPos( aPt, false, true );
370 pFndFrame->GetModelPositionForViewPoint( m_pCurrentCursor->GetPoint(), aPt );
371
372 bool bRet = !m_pCurrentCursor->IsInProtectTable() && !m_pCurrentCursor->IsSelOvr();
373 if( bRet )
374 UpdateCursor( SwCursorShell::SCROLLWIN | SwCursorShell::CHKRANGE |
375 SwCursorShell::READONLY );
376 }
377
378 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
379