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