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