Line data Source code
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 <hintids.hxx>
21 : #include <editeng/protitem.hxx>
22 : #include <com/sun/star/i18n/WordType.hpp>
23 : #include <com/sun/star/i18n/CharType.hpp>
24 : #include <unotools/charclass.hxx>
25 : #include <svl/ctloptions.hxx>
26 : #include <swmodule.hxx>
27 : #include <fmtcntnt.hxx>
28 : #include <swtblfmt.hxx>
29 : #include <swcrsr.hxx>
30 : #include <unocrsr.hxx>
31 : #include <doc.hxx>
32 : #include <IDocumentUndoRedo.hxx>
33 : #include <IDocumentRedlineAccess.hxx>
34 : #include <IDocumentLayoutAccess.hxx>
35 : #include <docary.hxx>
36 : #include <ndtxt.hxx>
37 : #include <section.hxx>
38 : #include <swtable.hxx>
39 : #include <cntfrm.hxx>
40 : #include <rootfrm.hxx>
41 : #include <txtfrm.hxx>
42 : #include <scriptinfo.hxx>
43 : #include <crstate.hxx>
44 : #include <docsh.hxx>
45 : #include <viewsh.hxx>
46 : #include <frmatr.hxx>
47 : #include <breakit.hxx>
48 : #include <crsskip.hxx>
49 : #include <vcl/msgbox.hxx>
50 : #include <mdiexp.hxx>
51 : #include <statstr.hrc>
52 : #include <redline.hxx>
53 : #include <txatbase.hxx>
54 :
55 : using namespace ::com::sun::star::i18n;
56 :
57 : static const sal_uInt16 coSrchRplcThreshold = 60000;
58 :
59 : struct _PercentHdl
60 : {
61 : SwDocShell* pDSh;
62 : sal_uLong nActPos;
63 : bool bBack, bNodeIdx;
64 :
65 0 : _PercentHdl( sal_uLong nStt, sal_uLong nEnd, SwDocShell* pSh )
66 0 : : pDSh(pSh), bBack(false), bNodeIdx(false)
67 : {
68 0 : nActPos = nStt;
69 0 : if( ( bBack = (nStt > nEnd )) )
70 : {
71 0 : sal_uLong n = nStt; nStt = nEnd; nEnd = n;
72 : }
73 0 : ::StartProgress( STR_STATSTR_SEARCH, nStt, nEnd, 0 );
74 0 : }
75 :
76 3 : explicit _PercentHdl( const SwPaM& rPam )
77 3 : : pDSh( rPam.GetDoc()->GetDocShell() )
78 : {
79 : sal_uLong nStt, nEnd;
80 3 : if( rPam.GetPoint()->nNode == rPam.GetMark()->nNode )
81 : {
82 3 : bNodeIdx = false;
83 3 : nStt = rPam.GetMark()->nContent.GetIndex();
84 3 : nEnd = rPam.GetPoint()->nContent.GetIndex();
85 : }
86 : else
87 : {
88 0 : bNodeIdx = true;
89 0 : nStt = rPam.GetMark()->nNode.GetIndex();
90 0 : nEnd = rPam.GetPoint()->nNode.GetIndex();
91 : }
92 3 : nActPos = nStt;
93 3 : if( ( bBack = (nStt > nEnd )) )
94 : {
95 0 : sal_uLong n = nStt; nStt = nEnd; nEnd = n;
96 : }
97 3 : ::StartProgress( STR_STATSTR_SEARCH, nStt, nEnd, pDSh );
98 3 : }
99 :
100 3 : ~_PercentHdl() { ::EndProgress( pDSh ); }
101 :
102 0 : void NextPos( sal_uLong nPos ) const
103 0 : { ::SetProgressState( bBack ? nActPos - nPos : nPos, pDSh ); }
104 :
105 0 : void NextPos( SwPosition& rPos ) const
106 : {
107 : sal_uLong nPos;
108 0 : if( bNodeIdx )
109 0 : nPos = rPos.nNode.GetIndex();
110 : else
111 0 : nPos = rPos.nContent.GetIndex();
112 0 : ::SetProgressState( bBack ? nActPos - nPos : nPos, pDSh );
113 0 : }
114 : };
115 :
116 256320 : SwCursor::SwCursor( const SwPosition &rPos, SwPaM* pRing, bool bColumnSel )
117 : : SwPaM( rPos, pRing )
118 : , m_pSavePos(nullptr)
119 : , m_nRowSpanOffset(0)
120 : , m_nCursorBidiLevel(0)
121 256320 : , m_bColumnSelection(bColumnSel)
122 : {
123 256320 : }
124 :
125 : // @@@ semantic: no copy ctor.
126 0 : SwCursor::SwCursor(SwCursor const& rCpy, SwPaM *const pRing)
127 : : SwPaM( rCpy, pRing )
128 : , m_pSavePos(nullptr)
129 : , m_nRowSpanOffset(rCpy.m_nRowSpanOffset)
130 : , m_nCursorBidiLevel(rCpy.m_nCursorBidiLevel)
131 0 : , m_bColumnSelection(rCpy.m_bColumnSelection)
132 : {
133 0 : }
134 :
135 513325 : SwCursor::~SwCursor()
136 : {
137 512632 : while( m_pSavePos )
138 : {
139 0 : _SwCursor_SavePos* pNxt = m_pSavePos->pNext;
140 0 : delete m_pSavePos;
141 0 : m_pSavePos = pNxt;
142 : }
143 257009 : }
144 :
145 693 : SwCursor* SwCursor::Create( SwPaM* pRing ) const
146 : {
147 693 : return new SwCursor( *GetPoint(), pRing, false );
148 : }
149 :
150 4 : bool SwCursor::IsReadOnlyAvailable() const
151 : {
152 4 : return false;
153 : }
154 :
155 421 : bool SwCursor::IsSkipOverHiddenSections() const
156 : {
157 421 : return true;
158 : }
159 :
160 421 : bool SwCursor::IsSkipOverProtectSections() const
161 : {
162 421 : return !IsReadOnlyAvailable();
163 : }
164 :
165 : // CreateNewSavePos is virtual so that derived classes of cursor can implement
166 : // own SaveObjects if needed and validate them in the virtual check routines.
167 95050 : void SwCursor::SaveState()
168 : {
169 95050 : _SwCursor_SavePos* pNew = CreateNewSavePos();
170 95050 : pNew->pNext = m_pSavePos;
171 95050 : m_pSavePos = pNew;
172 95050 : }
173 :
174 95050 : void SwCursor::RestoreState()
175 : {
176 95050 : if (m_pSavePos) // Robust
177 : {
178 95050 : _SwCursor_SavePos* pDel = m_pSavePos;
179 95050 : m_pSavePos = m_pSavePos->pNext;
180 95050 : delete pDel;
181 : }
182 95050 : }
183 :
184 95050 : _SwCursor_SavePos* SwCursor::CreateNewSavePos() const
185 : {
186 95050 : return new _SwCursor_SavePos( *this );
187 : }
188 :
189 : /// determine if point is outside of the node-array's content area
190 10 : bool SwCursor::IsNoContent() const
191 : {
192 10 : return GetPoint()->nNode.GetIndex() <
193 10 : GetDoc()->GetNodes().GetEndOfExtras().GetIndex();
194 : }
195 :
196 66324 : bool SwCursor::IsSelOvrCheck(int)
197 : {
198 66324 : return false;
199 : }
200 :
201 : // extracted from IsSelOvr()
202 28 : bool SwTableCursor::IsSelOvrCheck(int eFlags)
203 : {
204 28 : SwNodes& rNds = GetDoc()->GetNodes();
205 : // check sections of nodes array
206 56 : if( (nsSwCursorSelOverFlags::SELOVER_CHECKNODESSECTION & eFlags)
207 28 : && HasMark() )
208 : {
209 13 : SwNodeIndex aOldPos( rNds, GetSavePos()->nNode );
210 13 : if( !CheckNodesRange( aOldPos, GetPoint()->nNode, true ))
211 : {
212 0 : GetPoint()->nNode = aOldPos;
213 0 : GetPoint()->nContent.Assign( GetContentNode(), GetSavePos()->nContent );
214 0 : return true;
215 13 : }
216 : }
217 28 : return SwCursor::IsSelOvrCheck(eFlags);
218 : }
219 :
220 : namespace
221 : {
222 96632 : const SwTextAttr* InputFieldAtPos(SwPosition *pPos)
223 : {
224 96632 : SwTextNode* pTextNd = pPos->nNode.GetNode().GetTextNode();
225 96632 : if (!pTextNd)
226 0 : return NULL;
227 96632 : return pTextNd->GetTextAttrAt(pPos->nContent.GetIndex(), RES_TXTATR_INPUTFIELD, SwTextNode::PARENT);
228 : }
229 : }
230 :
231 66324 : bool SwCursor::IsSelOvr( int eFlags )
232 : {
233 66324 : SwDoc* pDoc = GetDoc();
234 66324 : SwNodes& rNds = pDoc->GetNodes();
235 :
236 66324 : bool bSkipOverHiddenSections = IsSkipOverHiddenSections();
237 66324 : bool bSkipOverProtectSections = IsSkipOverProtectSections();
238 :
239 66324 : if ( IsSelOvrCheck( eFlags ) )
240 : {
241 0 : return true;
242 : }
243 :
244 158604 : if (m_pSavePos->nNode != GetPoint()->nNode.GetIndex() &&
245 : // (1997) in UI-ReadOnly everything is allowed
246 92280 : ( !pDoc->GetDocShell() || !pDoc->GetDocShell()->IsReadOnlyUI() ))
247 : {
248 : // check new sections
249 46140 : SwNodeIndex& rPtIdx = GetPoint()->nNode;
250 46140 : const SwSectionNode* pSectNd = rPtIdx.GetNode().FindSectionNode();
251 46140 : if( pSectNd &&
252 5 : ((bSkipOverHiddenSections && pSectNd->GetSection().IsHiddenFlag() ) ||
253 0 : (bSkipOverProtectSections && pSectNd->GetSection().IsProtectFlag() )))
254 : {
255 0 : if( 0 == ( nsSwCursorSelOverFlags::SELOVER_CHANGEPOS & eFlags ) )
256 : {
257 : // then we're already done
258 0 : RestoreSavePos();
259 0 : return true;
260 : }
261 :
262 : // set cursor to new position:
263 0 : SwNodeIndex aIdx( rPtIdx );
264 0 : sal_Int32 nContentPos = m_pSavePos->nContent;
265 0 : bool bGoNxt = m_pSavePos->nNode < rPtIdx.GetIndex();
266 : SwContentNode* pCNd = bGoNxt
267 0 : ? rNds.GoNextSection( &rPtIdx, bSkipOverHiddenSections, bSkipOverProtectSections)
268 0 : : SwNodes::GoPrevSection( &rPtIdx, bSkipOverHiddenSections, bSkipOverProtectSections);
269 0 : if( !pCNd && ( nsSwCursorSelOverFlags::SELOVER_ENABLEREVDIREKTION & eFlags ))
270 : {
271 0 : bGoNxt = !bGoNxt;
272 0 : pCNd = bGoNxt ? rNds.GoNextSection( &rPtIdx, bSkipOverHiddenSections, bSkipOverProtectSections)
273 0 : : SwNodes::GoPrevSection( &rPtIdx, bSkipOverHiddenSections, bSkipOverProtectSections);
274 : }
275 :
276 0 : bool bIsValidPos = 0 != pCNd;
277 0 : const bool bValidNodesRange = bIsValidPos &&
278 0 : ::CheckNodesRange( rPtIdx, aIdx, true );
279 0 : if( !bValidNodesRange )
280 : {
281 0 : rPtIdx = m_pSavePos->nNode;
282 0 : if( 0 == ( pCNd = rPtIdx.GetNode().GetContentNode() ) )
283 : {
284 0 : bIsValidPos = false;
285 0 : nContentPos = 0;
286 0 : rPtIdx = aIdx;
287 0 : if( 0 == ( pCNd = rPtIdx.GetNode().GetContentNode() ) )
288 : {
289 : // then to the beginning of the document
290 0 : rPtIdx = rNds.GetEndOfExtras();
291 0 : pCNd = rNds.GoNext( &rPtIdx );
292 : }
293 : }
294 : }
295 :
296 : // register ContentIndex:
297 0 : const sal_Int32 nTmpPos = bIsValidPos ? (bGoNxt ? 0 : pCNd->Len()) : nContentPos;
298 0 : GetPoint()->nContent.Assign( pCNd, nTmpPos );
299 0 : if( !bIsValidPos || !bValidNodesRange ||
300 0 : IsInProtectTable( true ) )
301 0 : return true;
302 : }
303 :
304 : // is there a protected section in the section?
305 46140 : if( HasMark() && bSkipOverProtectSections)
306 : {
307 0 : sal_uLong nSttIdx = GetMark()->nNode.GetIndex(),
308 0 : nEndIdx = GetPoint()->nNode.GetIndex();
309 0 : if( nEndIdx <= nSttIdx )
310 : {
311 0 : sal_uLong nTmp = nSttIdx;
312 0 : nSttIdx = nEndIdx;
313 0 : nEndIdx = nTmp;
314 : }
315 :
316 0 : const SwSectionFormats& rFormats = pDoc->GetSections();
317 0 : for( SwSectionFormats::size_type n = 0; n < rFormats.size(); ++n )
318 : {
319 0 : const SwSectionFormat* pFormat = rFormats[n];
320 0 : const SvxProtectItem& rProtect = pFormat->GetProtect();
321 0 : if( rProtect.IsContentProtected() )
322 : {
323 0 : const SwFormatContent& rContent = pFormat->GetContent(false);
324 : OSL_ENSURE( rContent.GetContentIdx(), "No SectionNode?" );
325 0 : sal_uLong nIdx = rContent.GetContentIdx()->GetIndex();
326 0 : if( nSttIdx <= nIdx && nEndIdx >= nIdx )
327 : {
328 : // if it is no linked section then we cannot select it
329 0 : const SwSection& rSect = *pFormat->GetSection();
330 0 : if( CONTENT_SECTION == rSect.GetType() )
331 : {
332 0 : RestoreSavePos();
333 0 : return true;
334 : }
335 : }
336 : }
337 : }
338 : }
339 : }
340 :
341 66324 : const SwNode* pNd = &GetPoint()->nNode.GetNode();
342 66324 : if( pNd->IsContentNode() && !dynamic_cast<SwUnoCrsr*>(this) )
343 : {
344 421 : const SwContentFrm* pFrm = static_cast<const SwContentNode*>(pNd)->getLayoutFrm( pDoc->getIDocumentLayoutAccess().GetCurrentLayout() );
345 842 : if ( (nsSwCursorSelOverFlags::SELOVER_CHANGEPOS & eFlags) //allowed to change position if it's a bad one
346 375 : && pFrm && pFrm->IsValid() && !pFrm->Frm().Height() //a bad zero height position
347 421 : && !InputFieldAtPos(GetPoint()) ) //unless it's a (vertical) input field
348 : {
349 : // skip to the next/prev valid paragraph with a layout
350 0 : SwNodeIndex& rPtIdx = GetPoint()->nNode;
351 0 : bool bGoNxt = m_pSavePos->nNode < rPtIdx.GetIndex();
352 0 : while( 0 != ( pFrm = ( bGoNxt ? pFrm->GetNextContentFrm() : pFrm->GetPrevContentFrm() ))
353 0 : && 0 == pFrm->Frm().Height() )
354 : ;
355 :
356 : // #i72394# skip to prev/next valid paragraph with a layout in case
357 : // the first search did not succeed:
358 0 : if( !pFrm )
359 : {
360 0 : bGoNxt = !bGoNxt;
361 0 : pFrm = static_cast<const SwContentNode*>(pNd)->getLayoutFrm( pDoc->getIDocumentLayoutAccess().GetCurrentLayout() );
362 0 : while ( pFrm && 0 == pFrm->Frm().Height() )
363 : {
364 : pFrm = bGoNxt ? pFrm->GetNextContentFrm()
365 0 : : pFrm->GetPrevContentFrm();
366 : }
367 : }
368 :
369 0 : SwContentNode* pCNd = (pFrm != NULL) ? const_cast<SwContentNode*>(pFrm->GetNode()) : NULL;
370 0 : if ( pCNd != NULL )
371 : {
372 : // set this ContentNode as new position
373 0 : rPtIdx = *pCNd;
374 :
375 : // assign corresponding ContentIndex
376 0 : const sal_Int32 nTmpPos = bGoNxt ? 0 : pCNd->Len();
377 0 : GetPoint()->nContent.Assign( pCNd, nTmpPos );
378 :
379 0 : if (rPtIdx.GetIndex() == m_pSavePos->nNode
380 0 : && nTmpPos == m_pSavePos->nContent)
381 : {
382 : // new position equals saved one
383 : // --> trigger restore of saved pos by setting <pFrm> to NULL - see below
384 0 : pFrm = NULL;
385 : }
386 :
387 0 : if ( IsInProtectTable( true ) )
388 : {
389 : // new position in protected table
390 : // --> trigger restore of saved pos by setting <pFrm> to NULL - see below
391 0 : pFrm = NULL;
392 : }
393 : }
394 : }
395 :
396 421 : if( !pFrm )
397 : {
398 0 : DeleteMark();
399 0 : RestoreSavePos();
400 0 : return true; // we need a frame
401 : }
402 : }
403 :
404 : // is the cursor allowed to be in a protected node?
405 66324 : if( 0 == ( nsSwCursorSelOverFlags::SELOVER_CHANGEPOS & eFlags ) && !IsAtValidPos() )
406 : {
407 0 : DeleteMark();
408 0 : RestoreSavePos();
409 0 : return true;
410 : }
411 :
412 66324 : if( !HasMark() )
413 18008 : return false;
414 :
415 : // check for invalid sections
416 48316 : if( !::CheckNodesRange( GetMark()->nNode, GetPoint()->nNode, true ))
417 : {
418 0 : DeleteMark();
419 0 : RestoreSavePos();
420 0 : return true; // we need a frame
421 : }
422 :
423 144948 : if( (pNd = &GetMark()->nNode.GetNode())->IsContentNode()
424 48316 : && !static_cast<const SwContentNode*>(pNd)->getLayoutFrm( pDoc->getIDocumentLayoutAccess().GetCurrentLayout() )
425 140135 : && !dynamic_cast<SwUnoCrsr*>(this) )
426 : {
427 0 : DeleteMark();
428 0 : RestoreSavePos();
429 0 : return true; // we need a frame
430 : }
431 :
432 : // ensure that selection is only inside an InputField or contains the InputField completely
433 : {
434 48316 : const SwTextAttr* pInputFieldTextAttrAtPoint = InputFieldAtPos(GetPoint());
435 48316 : const SwTextAttr* pInputFieldTextAttrAtMark = InputFieldAtPos(GetMark());
436 :
437 48316 : if ( pInputFieldTextAttrAtPoint != pInputFieldTextAttrAtMark )
438 : {
439 : const sal_uLong nRefNodeIdx =
440 0 : ( nsSwCursorSelOverFlags::SELOVER_TOGGLE & eFlags )
441 : ? m_pSavePos->nNode
442 0 : : GetMark()->nNode.GetIndex();
443 : const sal_Int32 nRefContentIdx =
444 0 : ( nsSwCursorSelOverFlags::SELOVER_TOGGLE & eFlags )
445 : ? m_pSavePos->nContent
446 0 : : GetMark()->nContent.GetIndex();
447 : const bool bIsForwardSelection =
448 0 : nRefNodeIdx < GetPoint()->nNode.GetIndex()
449 0 : || ( nRefNodeIdx == GetPoint()->nNode.GetIndex()
450 0 : && nRefContentIdx < GetPoint()->nContent.GetIndex() );
451 :
452 0 : if ( pInputFieldTextAttrAtPoint != NULL )
453 : {
454 : const sal_Int32 nNewPointPos =
455 0 : bIsForwardSelection ? *(pInputFieldTextAttrAtPoint->End()) : pInputFieldTextAttrAtPoint->GetStart();
456 0 : SwTextNode* pTextNdAtPoint = GetPoint()->nNode.GetNode().GetTextNode();
457 0 : GetPoint()->nContent.Assign( pTextNdAtPoint, nNewPointPos );
458 : }
459 :
460 0 : if ( pInputFieldTextAttrAtMark != NULL )
461 : {
462 : const sal_Int32 nNewMarkPos =
463 0 : bIsForwardSelection ? pInputFieldTextAttrAtMark->GetStart() : *(pInputFieldTextAttrAtMark->End());
464 0 : SwTextNode* pTextNdAtMark = GetMark()->nNode.GetNode().GetTextNode();
465 0 : GetMark()->nContent.Assign( pTextNdAtMark, nNewMarkPos );
466 : }
467 : }
468 : }
469 :
470 48316 : const SwTableNode* pPtNd = GetPoint()->nNode.GetNode().FindTableNode();
471 48316 : const SwTableNode* pMrkNd = GetMark()->nNode.GetNode().FindTableNode();
472 : // both in no or in same table node
473 48316 : if( ( !pMrkNd && !pPtNd ) || pPtNd == pMrkNd )
474 48315 : return false;
475 :
476 : // in different tables or only mark in table
477 1 : if( pMrkNd )
478 : {
479 : // not allowed, so go back to old position
480 1 : RestoreSavePos();
481 : // Crsr stays at old position
482 1 : return true;
483 : }
484 :
485 : // Note: this cannot happen in TableMode
486 : // Only Point in Table then go behind/in front of table
487 0 : if (nsSwCursorSelOverFlags::SELOVER_CHANGEPOS & eFlags)
488 : {
489 0 : bool bSelTop = GetPoint()->nNode.GetIndex() <
490 0 : ((nsSwCursorSelOverFlags::SELOVER_TOGGLE & eFlags)
491 0 : ? m_pSavePos->nNode : GetMark()->nNode.GetIndex());
492 :
493 : do { // loop for table after table
494 0 : sal_uLong nSEIdx = pPtNd->EndOfSectionIndex();
495 0 : sal_uLong nSttEndTable = nSEIdx + 1;
496 :
497 0 : if( bSelTop )
498 0 : nSttEndTable = rNds[ nSEIdx ]->StartOfSectionIndex() - 1;
499 :
500 0 : GetPoint()->nNode = nSttEndTable;
501 0 : const SwNode* pMyNd = &(GetNode());
502 :
503 0 : if( pMyNd->IsSectionNode() || ( pMyNd->IsEndNode() &&
504 0 : pMyNd->StartOfSectionNode()->IsSectionNode() ) )
505 : {
506 0 : pMyNd = bSelTop
507 0 : ? SwNodes::GoPrevSection( &GetPoint()->nNode,true,false )
508 0 : : rNds.GoNextSection( &GetPoint()->nNode,true,false );
509 :
510 : /* #i12312# Handle failure of Go{Prev|Next}Section */
511 0 : if ( 0 == pMyNd)
512 0 : break;
513 :
514 0 : if( 0 != ( pPtNd = pMyNd->FindTableNode() ))
515 0 : continue;
516 : }
517 :
518 : // we permit these
519 0 : if( pMyNd->IsContentNode() &&
520 0 : ::CheckNodesRange( GetMark()->nNode,
521 0 : GetPoint()->nNode, true ))
522 : {
523 : // table in table
524 0 : const SwTableNode* pOuterTableNd = pMyNd->FindTableNode();
525 0 : if ( pOuterTableNd )
526 0 : pMyNd = pOuterTableNd;
527 : else
528 : {
529 0 : SwContentNode* pCNd = const_cast<SwContentNode*>(static_cast<const SwContentNode*>(pMyNd));
530 0 : GetPoint()->nContent.Assign( pCNd, bSelTop ? pCNd->Len() : 0 );
531 0 : return false;
532 : }
533 : }
534 0 : if( bSelTop
535 0 : ? ( !pMyNd->IsEndNode() || 0 == ( pPtNd = pMyNd->FindTableNode() ))
536 : : 0 == ( pPtNd = pMyNd->GetTableNode() ))
537 0 : break;
538 0 : } while( true );
539 : }
540 :
541 : // stay on old position
542 0 : RestoreSavePos();
543 0 : return true;
544 : }
545 :
546 67094 : bool SwCursor::IsInProtectTable( bool bMove, bool bChgCrsr )
547 : {
548 67094 : SwContentNode* pCNd = GetContentNode();
549 67094 : if( !pCNd )
550 0 : return false;
551 :
552 : // No table, no protected cell:
553 67094 : const SwTableNode* pTableNode = pCNd->FindTableNode();
554 67094 : if ( !pTableNode )
555 51733 : return false;
556 :
557 : // Current position == last save position?
558 15361 : if (m_pSavePos->nNode == GetPoint()->nNode.GetIndex())
559 11745 : return false;
560 :
561 : // Check for convered cell:
562 3616 : bool bInCoveredCell = false;
563 3616 : const SwStartNode* pTmpSttNode = pCNd->FindTableBoxStartNode();
564 : OSL_ENSURE( pTmpSttNode, "In table, therefore I expect to get a SwTableBoxStartNode" );
565 3616 : const SwTableBox* pBox = pTmpSttNode ? pTableNode->GetTable().GetTableBox( pTmpSttNode->GetIndex() ) : 0; //Robust #151355
566 3616 : if ( pBox && pBox->getRowSpan() < 1 ) // Robust #151270
567 9 : bInCoveredCell = true;
568 :
569 : // Positions of covered cells are not acceptable:
570 3616 : if ( !bInCoveredCell )
571 : {
572 : // Position not protected?
573 3607 : if ( !pCNd->IsProtect() )
574 3607 : return false;
575 :
576 : // Cursor in protected cells allowed?
577 0 : if ( IsReadOnlyAvailable() )
578 0 : return false;
579 : }
580 :
581 : // If we reach this point, we are in a protected or covered table cell!
582 :
583 9 : if( !bMove )
584 : {
585 0 : if( bChgCrsr )
586 : // restore the last save position
587 0 : RestoreSavePos();
588 :
589 0 : return true; // Crsr stays at old position
590 : }
591 :
592 : // We are in a protected table cell. Traverse top to bottom?
593 9 : if (m_pSavePos->nNode < GetPoint()->nNode.GetIndex())
594 : {
595 : // search next valid box
596 : // if there is another StartNode after the EndNode of a cell then
597 : // there is another cell
598 9 : SwNodeIndex aCellStt( *GetNode().FindTableBoxStartNode()->EndOfSectionNode(), 1 );
599 9 : bool bProt = true;
600 : GoNextCell:
601 0 : do {
602 9 : if( !aCellStt.GetNode().IsStartNode() )
603 3 : break;
604 6 : ++aCellStt;
605 6 : if( 0 == ( pCNd = aCellStt.GetNode().GetContentNode() ))
606 0 : pCNd = aCellStt.GetNodes().GoNext( &aCellStt );
607 6 : if( !( bProt = pCNd->IsProtect() ))
608 6 : break;
609 0 : aCellStt.Assign( *pCNd->FindTableBoxStartNode()->EndOfSectionNode(), 1 );
610 : } while( bProt );
611 :
612 : SetNextCrsr:
613 12 : if( !bProt ) // found free cell
614 : {
615 9 : GetPoint()->nNode = aCellStt;
616 9 : SwContentNode* pTmpCNd = GetContentNode();
617 9 : if( pTmpCNd )
618 : {
619 9 : GetPoint()->nContent.Assign( pTmpCNd, 0 );
620 9 : return false;
621 : }
622 : return IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
623 0 : nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
624 : }
625 : // end of table, so go to next node
626 3 : ++aCellStt;
627 : SwNode* pNd;
628 3 : if( ( pNd = &aCellStt.GetNode())->IsEndNode() || HasMark())
629 : {
630 : // if only table in FlyFrame or SSelection then stay on old position
631 0 : if( bChgCrsr )
632 0 : RestoreSavePos();
633 0 : return true;
634 : }
635 3 : else if( pNd->IsTableNode() && aCellStt++ )
636 0 : goto GoNextCell;
637 :
638 3 : bProt = false; // index is now on a content node
639 3 : goto SetNextCrsr;
640 : }
641 :
642 : // search for the previous valid box
643 : {
644 : // if there is another EndNode in front of the StartNode than there
645 : // exists a previous cell
646 0 : SwNodeIndex aCellStt( *GetNode().FindTableBoxStartNode(), -1 );
647 : SwNode* pNd;
648 0 : bool bProt = true;
649 : GoPrevCell:
650 0 : do {
651 0 : if( !( pNd = &aCellStt.GetNode())->IsEndNode() )
652 0 : break;
653 0 : aCellStt.Assign( *pNd->StartOfSectionNode(), +1 );
654 0 : if( 0 == ( pCNd = aCellStt.GetNode().GetContentNode() ))
655 0 : pCNd = pNd->GetNodes().GoNext( &aCellStt );
656 0 : if( !( bProt = pCNd->IsProtect() ))
657 0 : break;
658 0 : aCellStt.Assign( *pNd->FindTableBoxStartNode(), -1 );
659 : } while( bProt );
660 :
661 : SetPrevCrsr:
662 0 : if( !bProt ) // found free cell
663 : {
664 0 : GetPoint()->nNode = aCellStt;
665 0 : SwContentNode* pTmpCNd = GetContentNode();
666 0 : if( pTmpCNd )
667 : {
668 0 : GetPoint()->nContent.Assign( pTmpCNd, 0 );
669 0 : return false;
670 : }
671 : return IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
672 0 : nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
673 : }
674 : // at the beginning of a table, so go to next node
675 0 : --aCellStt;
676 0 : if( ( pNd = &aCellStt.GetNode())->IsStartNode() || HasMark() )
677 : {
678 : // if only table in FlyFrame or SSelection then stay on old position
679 0 : if( bChgCrsr )
680 0 : RestoreSavePos();
681 0 : return true;
682 : }
683 0 : else if( pNd->StartOfSectionNode()->IsTableNode() && aCellStt-- )
684 0 : goto GoPrevCell;
685 :
686 0 : bProt = false; // index is now on a content node
687 0 : goto SetPrevCrsr;
688 : }
689 : }
690 :
691 : /// Return <true> if cursor can be set to this position
692 55 : bool SwCursor::IsAtValidPos( bool bPoint ) const
693 : {
694 55 : const SwDoc* pDoc = GetDoc();
695 55 : const SwPosition* pPos = bPoint ? GetPoint() : GetMark();
696 55 : const SwNode* pNd = &pPos->nNode.GetNode();
697 :
698 55 : if( pNd->IsContentNode() && !static_cast<const SwContentNode*>(pNd)->getLayoutFrm( pDoc->getIDocumentLayoutAccess().GetCurrentLayout() ) &&
699 0 : !dynamic_cast<const SwUnoCrsr*>(this) )
700 : {
701 0 : return false;
702 : }
703 :
704 : // #i45129# - in UI-ReadOnly everything is allowed
705 55 : if( !pDoc->GetDocShell() || !pDoc->GetDocShell()->IsReadOnlyUI() )
706 55 : return true;
707 :
708 0 : const bool bCrsrInReadOnly = IsReadOnlyAvailable();
709 0 : if( !bCrsrInReadOnly && pNd->IsProtect() )
710 0 : return false;
711 :
712 0 : const SwSectionNode* pSectNd = pNd->FindSectionNode();
713 0 : if( pSectNd && (pSectNd->GetSection().IsHiddenFlag() ||
714 0 : ( !bCrsrInReadOnly && pSectNd->GetSection().IsProtectFlag() )))
715 0 : return false;
716 :
717 0 : return true;
718 : }
719 :
720 0 : void SwCursor::SaveTableBoxContent( const SwPosition* ) {}
721 :
722 : /// set range for search in document
723 110 : SwMoveFnCollection* SwCursor::MakeFindRange( SwDocPositions nStart,
724 : SwDocPositions nEnd, SwPaM* pRange ) const
725 : {
726 110 : pRange->SetMark();
727 110 : FillFindPos( nStart, *pRange->GetMark() );
728 110 : FillFindPos( nEnd, *pRange->GetPoint() );
729 :
730 : // determine direction of search
731 58 : return ( DOCPOS_START == nStart || DOCPOS_OTHERSTART == nStart ||
732 14 : (DOCPOS_CURR == nStart &&
733 3 : (DOCPOS_END == nEnd || DOCPOS_OTHEREND == nEnd ) ))
734 217 : ? fnMoveForward : fnMoveBackward;
735 : }
736 :
737 4 : static sal_uLong lcl_FindSelection( SwFindParas& rParas, SwCursor* pCurCrsr,
738 : SwMoveFn fnMove, SwCursor*& pFndRing,
739 : SwPaM& aRegion, FindRanges eFndRngs,
740 : bool bInReadOnly, bool& bCancel )
741 : {
742 4 : SwDoc* pDoc = pCurCrsr->GetDoc();
743 4 : bool const bDoesUndo = pDoc->GetIDocumentUndoRedo().DoesUndo();
744 4 : int nFndRet = 0;
745 4 : sal_uLong nFound = 0;
746 4 : const bool bSrchBkwrd = fnMove == fnMoveBackward;
747 4 : SwPaM *pTmpCrsr = pCurCrsr, *pSaveCrsr = pCurCrsr;
748 :
749 : // only create progress bar for ShellCrsr
750 4 : bool bIsUnoCrsr = 0 != dynamic_cast<SwUnoCrsr*>(pCurCrsr);
751 4 : _PercentHdl* pPHdl = 0;
752 4 : sal_uInt16 nCrsrCnt = 0;
753 4 : if( FND_IN_SEL & eFndRngs )
754 : {
755 2 : while( pCurCrsr != ( pTmpCrsr = pTmpCrsr->GetNext() ))
756 0 : ++nCrsrCnt;
757 1 : if( nCrsrCnt && !bIsUnoCrsr )
758 0 : pPHdl = new _PercentHdl( 0, nCrsrCnt, pDoc->GetDocShell() );
759 : }
760 : else
761 3 : pSaveCrsr = static_cast<SwPaM*>(pSaveCrsr->GetPrev());
762 :
763 4 : bool bEnd = false;
764 0 : do {
765 4 : aRegion.SetMark();
766 : // independent from search direction: SPoint is always bigger than mark
767 : // if the search area is valid
768 4 : SwPosition *pSttPos = aRegion.GetMark(),
769 4 : *pEndPos = aRegion.GetPoint();
770 4 : *pSttPos = *pTmpCrsr->Start();
771 4 : *pEndPos = *pTmpCrsr->End();
772 4 : if( bSrchBkwrd )
773 0 : aRegion.Exchange();
774 :
775 4 : if( !nCrsrCnt && !pPHdl && !bIsUnoCrsr )
776 3 : pPHdl = new _PercentHdl( aRegion );
777 :
778 : // as long as found and not at same position
779 16 : while( *pSttPos <= *pEndPos &&
780 : 0 != ( nFndRet = rParas.Find( pCurCrsr, fnMove,
781 12 : &aRegion, bInReadOnly )) &&
782 4 : ( !pFndRing ||
783 0 : *pFndRing->GetPoint() != *pCurCrsr->GetPoint() ||
784 0 : *pFndRing->GetMark() != *pCurCrsr->GetMark() ))
785 : {
786 4 : if( !( FIND_NO_RING & nFndRet ))
787 : {
788 : // #i24084# - create ring similar to the one in CreateCrsr
789 4 : SwCursor* pNew = pCurCrsr->Create( pFndRing );
790 4 : if( !pFndRing )
791 4 : pFndRing = pNew;
792 :
793 4 : pNew->SetMark();
794 4 : *pNew->GetMark() = *pCurCrsr->GetMark();
795 : }
796 :
797 4 : ++nFound;
798 :
799 4 : if( !( eFndRngs & FND_IN_SELALL) )
800 : {
801 4 : bEnd = true;
802 4 : break;
803 : }
804 :
805 0 : if ((coSrchRplcThreshold == nFound)
806 0 : && pDoc->GetIDocumentUndoRedo().DoesUndo()
807 0 : && rParas.IsReplaceMode())
808 : {
809 0 : short nRet = pCurCrsr->MaxReplaceArived();
810 0 : if( RET_YES == nRet )
811 : {
812 0 : pDoc->GetIDocumentUndoRedo().DelAllUndoObj();
813 0 : pDoc->GetIDocumentUndoRedo().DoUndo(false);
814 : }
815 : else
816 : {
817 0 : bEnd = true;
818 0 : if(RET_CANCEL == nRet)
819 : {
820 0 : bCancel = true;
821 : }
822 0 : break;
823 : }
824 : }
825 :
826 0 : if( bSrchBkwrd )
827 : // move pEndPos in front of the found area
828 0 : *pEndPos = *pCurCrsr->Start();
829 : else
830 : // move pSttPos behind the found area
831 0 : *pSttPos = *pCurCrsr->End();
832 :
833 0 : if( *pSttPos == *pEndPos )
834 : // in area but at the end => done
835 0 : break;
836 :
837 0 : if( !nCrsrCnt && pPHdl )
838 : {
839 0 : pPHdl->NextPos( *aRegion.GetMark() );
840 : }
841 : }
842 :
843 4 : if( bEnd || !( eFndRngs & ( FND_IN_SELALL | FND_IN_SEL )) )
844 : break;
845 :
846 0 : pTmpCrsr = pTmpCrsr->GetNext();
847 0 : if( nCrsrCnt && pPHdl )
848 : {
849 0 : pPHdl->NextPos( ++pPHdl->nActPos );
850 : }
851 :
852 : } while( pTmpCrsr != pSaveCrsr );
853 :
854 4 : if( nFound && !pFndRing ) // if no ring should be created
855 0 : pFndRing = pCurCrsr->Create();
856 :
857 4 : delete pPHdl;
858 4 : pDoc->GetIDocumentUndoRedo().DoUndo(bDoesUndo);
859 4 : return nFound;
860 : }
861 :
862 4 : static bool lcl_MakeSelFwrd( const SwNode& rSttNd, const SwNode& rEndNd,
863 : SwPaM& rPam, bool bFirst )
864 : {
865 4 : if( rSttNd.GetIndex() + 1 == rEndNd.GetIndex() )
866 0 : return false;
867 :
868 4 : SwNodes& rNds = rPam.GetDoc()->GetNodes();
869 4 : rPam.DeleteMark();
870 : SwContentNode* pCNd;
871 4 : if( !bFirst )
872 : {
873 3 : rPam.GetPoint()->nNode = rSttNd;
874 3 : pCNd = rNds.GoNext( &rPam.GetPoint()->nNode );
875 3 : if( !pCNd )
876 0 : return false;
877 3 : pCNd->MakeStartIndex( &rPam.GetPoint()->nContent );
878 : }
879 2 : else if( rSttNd.GetIndex() > rPam.GetPoint()->nNode.GetIndex() ||
880 1 : rPam.GetPoint()->nNode.GetIndex() >= rEndNd.GetIndex() )
881 : // not in this section
882 0 : return false;
883 :
884 4 : rPam.SetMark();
885 4 : rPam.GetPoint()->nNode = rEndNd;
886 4 : pCNd = SwNodes::GoPrevious( &rPam.GetPoint()->nNode );
887 4 : if( !pCNd )
888 0 : return false;
889 4 : pCNd->MakeEndIndex( &rPam.GetPoint()->nContent );
890 :
891 4 : return *rPam.GetMark() < *rPam.GetPoint();
892 : }
893 :
894 0 : static bool lcl_MakeSelBkwrd( const SwNode& rSttNd, const SwNode& rEndNd,
895 : SwPaM& rPam, bool bFirst )
896 : {
897 0 : if( rEndNd.GetIndex() + 1 == rSttNd.GetIndex() )
898 0 : return false;
899 :
900 0 : SwNodes& rNds = rPam.GetDoc()->GetNodes();
901 0 : rPam.DeleteMark();
902 : SwContentNode* pCNd;
903 0 : if( !bFirst )
904 : {
905 0 : rPam.GetPoint()->nNode = rSttNd;
906 0 : pCNd = SwNodes::GoPrevious( &rPam.GetPoint()->nNode );
907 0 : if( !pCNd )
908 0 : return false;
909 0 : pCNd->MakeEndIndex( &rPam.GetPoint()->nContent );
910 : }
911 0 : else if( rEndNd.GetIndex() > rPam.GetPoint()->nNode.GetIndex() ||
912 0 : rPam.GetPoint()->nNode.GetIndex() >= rSttNd.GetIndex() )
913 0 : return false; // not in this section
914 :
915 0 : rPam.SetMark();
916 0 : rPam.GetPoint()->nNode = rEndNd;
917 0 : pCNd = rNds.GoNext( &rPam.GetPoint()->nNode );
918 0 : if( !pCNd )
919 0 : return false;
920 0 : pCNd->MakeStartIndex( &rPam.GetPoint()->nContent );
921 :
922 0 : return *rPam.GetPoint() < *rPam.GetMark();
923 : }
924 :
925 : // this method "searches" for all use cases because in SwFindParas is always the
926 : // correct parameters and respective search method
927 18 : sal_uLong SwCursor::FindAll( SwFindParas& rParas,
928 : SwDocPositions nStart, SwDocPositions nEnde,
929 : FindRanges eFndRngs, bool& bCancel )
930 : {
931 18 : bCancel = false;
932 18 : SwCrsrSaveState aSaveState( *this );
933 :
934 : // create region without adding it to the ring
935 36 : SwPaM aRegion( *GetPoint() );
936 18 : SwMoveFn fnMove = MakeFindRange( nStart, nEnde, &aRegion );
937 :
938 18 : sal_uLong nFound = 0;
939 18 : const bool bMvBkwrd = fnMove == fnMoveBackward;
940 18 : bool bInReadOnly = IsReadOnlyAvailable();
941 :
942 18 : SwCursor* pFndRing = 0;
943 18 : SwNodes& rNds = GetDoc()->GetNodes();
944 :
945 : // search in sections?
946 18 : if( FND_IN_SEL & eFndRngs )
947 : {
948 : // if string was not found in region then get all sections (cursors
949 : // stays unchanged)
950 1 : if( 0 == ( nFound = lcl_FindSelection( rParas, this, fnMove,
951 : pFndRing, aRegion, eFndRngs,
952 1 : bInReadOnly, bCancel ) ))
953 0 : return nFound;
954 :
955 : // found string at least once; it's all in new Crsr ring thus delete old one
956 2 : while( GetNext() != this )
957 0 : delete GetNext();
958 :
959 1 : *GetPoint() = *pFndRing->GetPoint();
960 1 : SetMark();
961 1 : *GetMark() = *pFndRing->GetMark();
962 1 : pFndRing->GetRingContainer().merge( GetRingContainer() );
963 1 : delete pFndRing;
964 : }
965 17 : else if( FND_IN_OTHER & eFndRngs )
966 : {
967 : // put cursor as copy of current into ring
968 : // chaining points always to first created, so forward
969 4 : std::unique_ptr< SwCursor > pSav( Create( this ) ); // save the current cursor
970 :
971 : // if already outside of body text search from this position or start at
972 : // 1. base section
973 8 : if( bMvBkwrd
974 0 : ? lcl_MakeSelBkwrd( rNds.GetEndOfExtras(),
975 0 : *rNds.GetEndOfPostIts().StartOfSectionNode(),
976 0 : *this, rNds.GetEndOfExtras().GetIndex() >=
977 0 : GetPoint()->nNode.GetIndex() )
978 4 : : lcl_MakeSelFwrd( *rNds.GetEndOfPostIts().StartOfSectionNode(),
979 4 : rNds.GetEndOfExtras(), *this,
980 4 : rNds.GetEndOfExtras().GetIndex() >=
981 8 : GetPoint()->nNode.GetIndex() ))
982 : {
983 : nFound = lcl_FindSelection( rParas, this, fnMove, pFndRing,
984 3 : aRegion, eFndRngs, bInReadOnly, bCancel );
985 : }
986 :
987 4 : if( !nFound )
988 : {
989 : // put back the old one
990 1 : *GetPoint() = *pSav->GetPoint();
991 1 : if( pSav->HasMark() )
992 : {
993 0 : SetMark();
994 0 : *GetMark() = *pSav->GetMark();
995 : }
996 : else
997 1 : DeleteMark();
998 1 : return 0;
999 : }
1000 3 : pSav.release();
1001 :
1002 3 : if( !( FND_IN_SELALL & eFndRngs ))
1003 : {
1004 : // there should only be a single one, thus add it
1005 : // independent from search direction: SPoint is always bigger than
1006 : // mark if the search area is valid
1007 3 : *GetPoint() = *pFndRing->GetPoint();
1008 3 : SetMark();
1009 3 : *GetMark() = *pFndRing->GetMark();
1010 : }
1011 : else
1012 : {
1013 : // found string at least once; it's all in new Crsr ring thus delete old one
1014 0 : while( GetNext() != this )
1015 0 : delete GetNext();
1016 :
1017 0 : *GetPoint() = *pFndRing->GetPoint();
1018 0 : SetMark();
1019 0 : *GetMark() = *pFndRing->GetMark();
1020 0 : pFndRing->GetRingContainer().merge( GetRingContainer() );
1021 : }
1022 3 : delete pFndRing;
1023 : }
1024 13 : else if( FND_IN_SELALL & eFndRngs )
1025 : {
1026 0 : ::std::unique_ptr< SwCursor> pSav( Create( this ) ); // save the current cursor
1027 :
1028 0 : const SwNode* pSttNd = ( FND_IN_BODYONLY & eFndRngs )
1029 0 : ? rNds.GetEndOfContent().StartOfSectionNode()
1030 0 : : rNds.GetEndOfPostIts().StartOfSectionNode();
1031 :
1032 0 : if( bMvBkwrd
1033 0 : ? lcl_MakeSelBkwrd( rNds.GetEndOfContent(), *pSttNd, *this, false )
1034 0 : : lcl_MakeSelFwrd( *pSttNd, rNds.GetEndOfContent(), *this, false ))
1035 : {
1036 : nFound = lcl_FindSelection( rParas, this, fnMove, pFndRing,
1037 0 : aRegion, eFndRngs, bInReadOnly, bCancel );
1038 : }
1039 :
1040 0 : if( !nFound )
1041 : {
1042 : // put back the old one
1043 0 : *GetPoint() = *pSav->GetPoint();
1044 0 : if( pSav->HasMark() )
1045 : {
1046 0 : SetMark();
1047 0 : *GetMark() = *pSav->GetMark();
1048 : }
1049 : else
1050 0 : DeleteMark();
1051 0 : return 0;
1052 : }
1053 0 : pSav.release();
1054 0 : while( GetNext() != this )
1055 0 : delete GetNext();
1056 :
1057 0 : *GetPoint() = *pFndRing->GetPoint();
1058 0 : SetMark();
1059 0 : *GetMark() = *pFndRing->GetMark();
1060 0 : pFndRing->GetRingContainer().merge( GetRingContainer() );
1061 0 : delete pFndRing;
1062 : }
1063 : else
1064 : {
1065 : // if a GetMark is set then keep the GetMark of the found object
1066 : // This allows spanning an area with this search.
1067 13 : SwPosition aMarkPos( *GetMark() );
1068 13 : const bool bMarkPos = HasMark() && !eFndRngs;
1069 :
1070 26 : if( 0 != (nFound = rParas.Find( this, fnMove,
1071 13 : &aRegion, bInReadOnly ) ? 1 : 0)
1072 13 : && bMarkPos )
1073 0 : *GetMark() = aMarkPos;
1074 : }
1075 :
1076 17 : if( nFound && SwCursor::IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE ) )
1077 0 : nFound = 0;
1078 35 : return nFound;
1079 : }
1080 :
1081 224 : void SwCursor::FillFindPos( SwDocPositions ePos, SwPosition& rPos ) const
1082 : {
1083 224 : bool bIsStart = true;
1084 224 : SwContentNode* pCNd = 0;
1085 224 : SwNodes& rNds = GetDoc()->GetNodes();
1086 :
1087 224 : switch( ePos )
1088 : {
1089 : case DOCPOS_START:
1090 59 : rPos.nNode = *rNds.GetEndOfContent().StartOfSectionNode();
1091 59 : pCNd = rNds.GoNext( &rPos.nNode );
1092 59 : break;
1093 : case DOCPOS_END:
1094 63 : rPos.nNode = rNds.GetEndOfContent();
1095 63 : pCNd = SwNodes::GoPrevious( &rPos.nNode );
1096 63 : bIsStart = false;
1097 63 : break;
1098 : case DOCPOS_OTHERSTART:
1099 44 : rPos.nNode = *rNds[ sal_uLong(0) ];
1100 44 : pCNd = rNds.GoNext( &rPos.nNode );
1101 44 : break;
1102 : case DOCPOS_OTHEREND:
1103 44 : rPos.nNode = *rNds.GetEndOfContent().StartOfSectionNode();
1104 44 : pCNd = SwNodes::GoPrevious( &rPos.nNode );
1105 44 : bIsStart = false;
1106 44 : break;
1107 : default:
1108 14 : rPos = *GetPoint();
1109 : }
1110 :
1111 224 : if( pCNd )
1112 : {
1113 166 : rPos.nContent.Assign( pCNd, bIsStart ? 0 : pCNd->Len() );
1114 : }
1115 224 : }
1116 :
1117 0 : short SwCursor::MaxReplaceArived()
1118 : {
1119 0 : return RET_YES;
1120 : }
1121 :
1122 2 : bool SwCursor::IsStartWord( sal_Int16 nWordType ) const
1123 : {
1124 2 : return IsStartWordWT( nWordType );
1125 : }
1126 :
1127 0 : bool SwCursor::IsEndWord( sal_Int16 nWordType ) const
1128 : {
1129 0 : return IsEndWordWT( nWordType );
1130 : }
1131 :
1132 0 : bool SwCursor::IsInWord( sal_Int16 nWordType ) const
1133 : {
1134 0 : return IsInWordWT( nWordType );
1135 : }
1136 :
1137 0 : bool SwCursor::GoStartWord()
1138 : {
1139 0 : return GoStartWordWT( WordType::ANYWORD_IGNOREWHITESPACES );
1140 : }
1141 :
1142 0 : bool SwCursor::GoEndWord()
1143 : {
1144 0 : return GoEndWordWT( WordType::ANYWORD_IGNOREWHITESPACES );
1145 : }
1146 :
1147 0 : bool SwCursor::GoNextWord()
1148 : {
1149 0 : return GoNextWordWT( WordType::ANYWORD_IGNOREWHITESPACES );
1150 : }
1151 :
1152 0 : bool SwCursor::GoPrevWord()
1153 : {
1154 0 : return GoPrevWordWT( WordType::ANYWORD_IGNOREWHITESPACES );
1155 : }
1156 :
1157 2 : bool SwCursor::SelectWord( SwViewShell* pViewShell, const Point* pPt )
1158 : {
1159 2 : return SelectWordWT( pViewShell, WordType::ANYWORD_IGNOREWHITESPACES, pPt );
1160 : }
1161 :
1162 6 : bool SwCursor::IsStartWordWT( sal_Int16 nWordType ) const
1163 : {
1164 6 : bool bRet = false;
1165 6 : const SwTextNode* pTextNd = GetNode().GetTextNode();
1166 6 : if( pTextNd && g_pBreakIt->GetBreakIter().is() )
1167 : {
1168 6 : const sal_Int32 nPtPos = GetPoint()->nContent.GetIndex();
1169 12 : bRet = g_pBreakIt->GetBreakIter()->isBeginWord(
1170 6 : pTextNd->GetText(), nPtPos,
1171 6 : g_pBreakIt->GetLocale( pTextNd->GetLang( nPtPos )),
1172 12 : nWordType );
1173 : }
1174 6 : return bRet;
1175 : }
1176 :
1177 8 : bool SwCursor::IsEndWordWT( sal_Int16 nWordType ) const
1178 : {
1179 8 : bool bRet = false;
1180 8 : const SwTextNode* pTextNd = GetNode().GetTextNode();
1181 8 : if( pTextNd && g_pBreakIt->GetBreakIter().is() )
1182 : {
1183 8 : const sal_Int32 nPtPos = GetPoint()->nContent.GetIndex();
1184 16 : bRet = g_pBreakIt->GetBreakIter()->isEndWord(
1185 8 : pTextNd->GetText(), nPtPos,
1186 8 : g_pBreakIt->GetLocale( pTextNd->GetLang( nPtPos ) ),
1187 16 : nWordType );
1188 :
1189 : }
1190 8 : return bRet;
1191 : }
1192 :
1193 0 : bool SwCursor::IsInWordWT( sal_Int16 nWordType ) const
1194 : {
1195 0 : bool bRet = false;
1196 0 : const SwTextNode* pTextNd = GetNode().GetTextNode();
1197 0 : if( pTextNd && g_pBreakIt->GetBreakIter().is() )
1198 : {
1199 0 : const sal_Int32 nPtPos = GetPoint()->nContent.GetIndex();
1200 0 : Boundary aBoundary = g_pBreakIt->GetBreakIter()->getWordBoundary(
1201 0 : pTextNd->GetText(), nPtPos,
1202 0 : g_pBreakIt->GetLocale( pTextNd->GetLang( nPtPos ) ),
1203 : nWordType,
1204 0 : true );
1205 :
1206 0 : bRet = aBoundary.startPos != aBoundary.endPos &&
1207 0 : aBoundary.startPos <= nPtPos &&
1208 0 : nPtPos <= aBoundary.endPos;
1209 0 : if(bRet)
1210 : {
1211 0 : const CharClass& rCC = GetAppCharClass();
1212 0 : bRet = rCC.isLetterNumeric( pTextNd->GetText(), aBoundary.startPos );
1213 : }
1214 : }
1215 0 : return bRet;
1216 : }
1217 :
1218 0 : bool SwCursor::IsStartEndSentence( bool bEnd ) const
1219 : {
1220 : bool bRet = bEnd ?
1221 0 : GetContentNode() && GetPoint()->nContent == GetContentNode()->Len() :
1222 0 : GetPoint()->nContent.GetIndex() == 0;
1223 :
1224 0 : if( !bRet )
1225 : {
1226 0 : SwCursor aCrsr(*GetPoint(), 0, false);
1227 0 : SwPosition aOrigPos = *aCrsr.GetPoint();
1228 0 : aCrsr.GoSentence( bEnd ? SwCursor::END_SENT : SwCursor::START_SENT );
1229 0 : bRet = aOrigPos == *aCrsr.GetPoint();
1230 : }
1231 0 : return bRet;
1232 : }
1233 :
1234 2 : bool SwCursor::GoStartWordWT( sal_Int16 nWordType )
1235 : {
1236 2 : bool bRet = false;
1237 2 : const SwTextNode* pTextNd = GetNode().GetTextNode();
1238 2 : if( pTextNd && g_pBreakIt->GetBreakIter().is() )
1239 : {
1240 2 : SwCrsrSaveState aSave( *this );
1241 2 : sal_Int32 nPtPos = GetPoint()->nContent.GetIndex();
1242 4 : nPtPos = g_pBreakIt->GetBreakIter()->getWordBoundary(
1243 2 : pTextNd->GetText(), nPtPos,
1244 2 : g_pBreakIt->GetLocale( pTextNd->GetLang( nPtPos ) ),
1245 : nWordType,
1246 4 : false ).startPos;
1247 :
1248 2 : if (nPtPos < pTextNd->GetText().getLength() && nPtPos >= 0)
1249 : {
1250 2 : GetPoint()->nContent = nPtPos;
1251 2 : if( !IsSelOvr() )
1252 2 : bRet = true;
1253 2 : }
1254 : }
1255 2 : return bRet;
1256 : }
1257 :
1258 4 : bool SwCursor::GoEndWordWT( sal_Int16 nWordType )
1259 : {
1260 4 : bool bRet = false;
1261 4 : const SwTextNode* pTextNd = GetNode().GetTextNode();
1262 4 : if( pTextNd && g_pBreakIt->GetBreakIter().is() )
1263 : {
1264 4 : SwCrsrSaveState aSave( *this );
1265 4 : sal_Int32 nPtPos = GetPoint()->nContent.GetIndex();
1266 8 : nPtPos = g_pBreakIt->GetBreakIter()->getWordBoundary(
1267 4 : pTextNd->GetText(), nPtPos,
1268 4 : g_pBreakIt->GetLocale( pTextNd->GetLang( nPtPos ) ),
1269 : nWordType,
1270 8 : true ).endPos;
1271 :
1272 8 : if (nPtPos <= pTextNd->GetText().getLength() && nPtPos >= 0 &&
1273 4 : GetPoint()->nContent.GetIndex() != nPtPos )
1274 : {
1275 4 : GetPoint()->nContent = nPtPos;
1276 4 : if( !IsSelOvr() )
1277 4 : bRet = true;
1278 4 : }
1279 : }
1280 4 : return bRet;
1281 : }
1282 :
1283 2 : bool SwCursor::GoNextWordWT( sal_Int16 nWordType )
1284 : {
1285 2 : bool bRet = false;
1286 2 : const SwTextNode* pTextNd = GetNode().GetTextNode();
1287 2 : if( pTextNd && g_pBreakIt->GetBreakIter().is() )
1288 : {
1289 2 : SwCrsrSaveState aSave( *this );
1290 2 : sal_Int32 nPtPos = GetPoint()->nContent.GetIndex();
1291 :
1292 4 : nPtPos = g_pBreakIt->GetBreakIter()->nextWord(
1293 2 : pTextNd->GetText(), nPtPos,
1294 2 : g_pBreakIt->GetLocale( pTextNd->GetLang( nPtPos, 1 ) ),
1295 4 : nWordType ).startPos;
1296 :
1297 2 : if (nPtPos < pTextNd->GetText().getLength() && nPtPos >= 0)
1298 : {
1299 2 : GetPoint()->nContent = nPtPos;
1300 2 : if( !IsSelOvr() )
1301 2 : bRet = true;
1302 2 : }
1303 : }
1304 2 : return bRet;
1305 : }
1306 :
1307 3 : bool SwCursor::GoPrevWordWT( sal_Int16 nWordType )
1308 : {
1309 3 : bool bRet = false;
1310 3 : const SwTextNode* pTextNd = GetNode().GetTextNode();
1311 3 : if( pTextNd && g_pBreakIt->GetBreakIter().is() )
1312 : {
1313 3 : SwCrsrSaveState aSave( *this );
1314 3 : sal_Int32 nPtPos = GetPoint()->nContent.GetIndex();
1315 3 : const sal_Int32 nPtStart = nPtPos;
1316 :
1317 3 : if( nPtPos )
1318 3 : --nPtPos;
1319 6 : nPtPos = g_pBreakIt->GetBreakIter()->previousWord(
1320 3 : pTextNd->GetText(), nPtStart,
1321 3 : g_pBreakIt->GetLocale( pTextNd->GetLang( nPtPos, 1 ) ),
1322 6 : nWordType ).startPos;
1323 :
1324 3 : if (nPtPos < pTextNd->GetText().getLength() && nPtPos >= 0)
1325 : {
1326 3 : GetPoint()->nContent = nPtPos;
1327 3 : if( !IsSelOvr() )
1328 3 : bRet = true;
1329 3 : }
1330 : }
1331 3 : return bRet;
1332 : }
1333 :
1334 2 : bool SwCursor::SelectWordWT( SwViewShell* pViewShell, sal_Int16 nWordType, const Point* pPt )
1335 : {
1336 2 : SwCrsrSaveState aSave( *this );
1337 :
1338 2 : bool bRet = false;
1339 2 : bool bForward = true;
1340 2 : DeleteMark();
1341 2 : const SwRootFrm* pLayout = pViewShell->GetLayout();
1342 2 : if( pPt && 0 != pLayout )
1343 : {
1344 : // set the cursor to the layout position
1345 0 : Point aPt( *pPt );
1346 0 : pLayout->GetCrsrOfst( GetPoint(), aPt );
1347 : }
1348 :
1349 2 : const SwTextNode* pTextNd = GetNode().GetTextNode();
1350 2 : if( pTextNd && g_pBreakIt->GetBreakIter().is() )
1351 : {
1352 : // Should we select the whole fieldmark?
1353 2 : const IDocumentMarkAccess* pMarksAccess = GetDoc()->getIDocumentMarkAccess( );
1354 2 : sw::mark::IMark* pMark = GetPoint() ? pMarksAccess->getFieldmarkFor( *GetPoint( ) ) : NULL;
1355 2 : if ( pMark )
1356 : {
1357 0 : const SwPosition rStart = pMark->GetMarkStart();
1358 0 : GetPoint()->nNode = rStart.nNode;
1359 0 : GetPoint()->nContent = rStart.nContent;
1360 0 : ++GetPoint()->nContent; // Don't select the start delimiter
1361 :
1362 0 : const SwPosition rEnd = pMark->GetMarkEnd();
1363 :
1364 0 : if ( rStart != rEnd )
1365 : {
1366 0 : SetMark();
1367 0 : GetMark()->nNode = rEnd.nNode;
1368 0 : GetMark()->nContent = rEnd.nContent;
1369 0 : --GetMark()->nContent; //Don't select the end delimiter
1370 : }
1371 0 : bRet = true;
1372 : }
1373 : else
1374 : {
1375 2 : sal_Int32 nPtPos = GetPoint()->nContent.GetIndex();
1376 4 : Boundary aBndry( g_pBreakIt->GetBreakIter()->getWordBoundary(
1377 2 : pTextNd->GetText(), nPtPos,
1378 2 : g_pBreakIt->GetLocale( pTextNd->GetLang( nPtPos ) ),
1379 : nWordType,
1380 4 : bForward ));
1381 :
1382 2 : if (pViewShell->isTiledRendering() && aBndry.startPos == aBndry.endPos && nPtPos > 0)
1383 : {
1384 : // nPtPos is the end of the paragraph, select the last word then.
1385 0 : --nPtPos;
1386 0 : aBndry = Boundary( g_pBreakIt->GetBreakIter()->getWordBoundary(
1387 0 : pTextNd->GetText(), nPtPos,
1388 0 : g_pBreakIt->GetLocale( pTextNd->GetLang( nPtPos ) ),
1389 : nWordType,
1390 0 : bForward ));
1391 : }
1392 :
1393 2 : if( aBndry.startPos != aBndry.endPos )
1394 : {
1395 2 : GetPoint()->nContent = aBndry.endPos;
1396 2 : if( !IsSelOvr() )
1397 : {
1398 2 : SetMark();
1399 2 : GetMark()->nContent = aBndry.startPos;
1400 2 : if (sw::mark::IMark* pAnnotationMark = pMarksAccess->getAnnotationMarkFor(*GetPoint()))
1401 : {
1402 : // An annotation mark covers the selected word. Check
1403 : // if it covers only the word: in that case we select
1404 : // the comment anchor as well.
1405 2 : bool bStartMatch = GetMark()->nNode == pAnnotationMark->GetMarkStart().nNode &&
1406 2 : GetMark()->nContent == pAnnotationMark->GetMarkStart().nContent;
1407 2 : bool bEndMatch = GetPoint()->nNode == pAnnotationMark->GetMarkEnd().nNode &&
1408 2 : GetPoint()->nContent.GetIndex() + 1 == pAnnotationMark->GetMarkEnd().nContent.GetIndex();
1409 1 : if (bStartMatch && bEndMatch)
1410 1 : ++GetPoint()->nContent;
1411 : }
1412 2 : if( !IsSelOvr() )
1413 2 : bRet = true;
1414 : }
1415 : }
1416 : }
1417 : }
1418 :
1419 2 : if( !bRet )
1420 : {
1421 0 : DeleteMark();
1422 0 : RestoreSavePos();
1423 : }
1424 2 : return bRet;
1425 : }
1426 :
1427 9 : static OUString lcl_MaskDeletedRedlines( const SwTextNode* pTextNd )
1428 : {
1429 9 : OUString aRes;
1430 9 : if (pTextNd)
1431 : {
1432 : //mask deleted redlines
1433 9 : OUString sNodeText(pTextNd->GetText());
1434 9 : const SwDoc& rDoc = *pTextNd->GetDoc();
1435 9 : const bool nShowChg = IDocumentRedlineAccess::IsShowChanges( rDoc.getIDocumentRedlineAccess().GetRedlineMode() );
1436 9 : if ( nShowChg )
1437 : {
1438 9 : sal_uInt16 nAct = rDoc.getIDocumentRedlineAccess().GetRedlinePos( *pTextNd, USHRT_MAX );
1439 9 : for ( ; nAct < rDoc.getIDocumentRedlineAccess().GetRedlineTable().size(); nAct++ )
1440 : {
1441 0 : const SwRangeRedline* pRed = rDoc.getIDocumentRedlineAccess().GetRedlineTable()[ nAct ];
1442 0 : if ( pRed->Start()->nNode > pTextNd->GetIndex() )
1443 0 : break;
1444 :
1445 0 : if( nsRedlineType_t::REDLINE_DELETE == pRed->GetType() )
1446 : {
1447 : sal_Int32 nStart, nEnd;
1448 0 : pRed->CalcStartEnd( pTextNd->GetIndex(), nStart, nEnd );
1449 :
1450 0 : while ( nStart < nEnd && nStart < sNodeText.getLength() )
1451 0 : sNodeText = sNodeText.replaceAt( nStart++, 1, OUString(CH_TXTATR_INWORD) );
1452 : }
1453 : }
1454 : }
1455 9 : aRes = sNodeText;
1456 : }
1457 9 : return aRes;
1458 : }
1459 :
1460 9 : bool SwCursor::GoSentence( SentenceMoveType eMoveType )
1461 : {
1462 9 : bool bRet = false;
1463 9 : const SwTextNode* pTextNd = GetNode().GetTextNode();
1464 9 : if( pTextNd && g_pBreakIt->GetBreakIter().is() )
1465 : {
1466 9 : OUString sNodeText( lcl_MaskDeletedRedlines( pTextNd ) );
1467 :
1468 18 : SwCrsrSaveState aSave( *this );
1469 9 : sal_Int32 nPtPos = GetPoint()->nContent.GetIndex();
1470 9 : switch ( eMoveType )
1471 : {
1472 : case START_SENT: /* when modifying: see also ExpandToSentenceBorders below! */
1473 4 : nPtPos = g_pBreakIt->GetBreakIter()->beginOfSentence(
1474 : sNodeText,
1475 : nPtPos, g_pBreakIt->GetLocale(
1476 2 : pTextNd->GetLang( nPtPos ) ));
1477 2 : break;
1478 : case END_SENT: /* when modifying: see also ExpandToSentenceBorders below! */
1479 6 : nPtPos = g_pBreakIt->GetBreakIter()->endOfSentence(
1480 : sNodeText,
1481 : nPtPos, g_pBreakIt->GetLocale(
1482 3 : pTextNd->GetLang( nPtPos ) ));
1483 3 : break;
1484 : case NEXT_SENT:
1485 : {
1486 4 : nPtPos = g_pBreakIt->GetBreakIter()->endOfSentence(
1487 : sNodeText,
1488 : nPtPos, g_pBreakIt->GetLocale(
1489 2 : pTextNd->GetLang( nPtPos ) ));
1490 6 : while (nPtPos>=0 && ++nPtPos < sNodeText.getLength()
1491 4 : && sNodeText[nPtPos] == ' ' /*isWhiteSpace( aText.GetChar(nPtPos)*/ )
1492 : ;
1493 2 : break;
1494 : }
1495 : case PREV_SENT:
1496 4 : nPtPos = g_pBreakIt->GetBreakIter()->beginOfSentence(
1497 : sNodeText,
1498 : nPtPos, g_pBreakIt->GetLocale(
1499 2 : pTextNd->GetLang( nPtPos ) ));
1500 2 : if (nPtPos == 0)
1501 0 : return false; // the previous sentence is not in this paragraph
1502 2 : if (nPtPos > 0)
1503 4 : nPtPos = g_pBreakIt->GetBreakIter()->beginOfSentence(
1504 : sNodeText,
1505 : nPtPos - 1, g_pBreakIt->GetLocale(
1506 2 : pTextNd->GetLang( nPtPos ) ));
1507 2 : break;
1508 : }
1509 :
1510 : // it is allowed to place the PaM just behind the last
1511 : // character in the text thus <= ...Len
1512 9 : if (nPtPos <= pTextNd->GetText().getLength() && nPtPos >= 0)
1513 : {
1514 9 : GetPoint()->nContent = nPtPos;
1515 9 : if( !IsSelOvr() )
1516 9 : bRet = true;
1517 9 : }
1518 : }
1519 9 : return bRet;
1520 : }
1521 :
1522 0 : bool SwCursor::ExpandToSentenceBorders()
1523 : {
1524 0 : bool bRes = false;
1525 0 : const SwTextNode* pStartNd = Start()->nNode.GetNode().GetTextNode();
1526 0 : const SwTextNode* pEndNd = End()->nNode.GetNode().GetTextNode();
1527 0 : if (pStartNd && pEndNd && g_pBreakIt->GetBreakIter().is())
1528 : {
1529 0 : if (!HasMark())
1530 0 : SetMark();
1531 :
1532 0 : OUString sStartText( lcl_MaskDeletedRedlines( pStartNd ) );
1533 0 : OUString sEndText( pStartNd == pEndNd? sStartText : lcl_MaskDeletedRedlines( pEndNd ) );
1534 :
1535 0 : SwCrsrSaveState aSave( *this );
1536 0 : sal_Int32 nStartPos = Start()->nContent.GetIndex();
1537 0 : sal_Int32 nEndPos = End()->nContent.GetIndex();
1538 :
1539 0 : nStartPos = g_pBreakIt->GetBreakIter()->beginOfSentence(
1540 : sStartText, nStartPos,
1541 0 : g_pBreakIt->GetLocale( pStartNd->GetLang( nStartPos ) ) );
1542 0 : nEndPos = g_pBreakIt->GetBreakIter()->endOfSentence(
1543 : sEndText, nEndPos,
1544 0 : g_pBreakIt->GetLocale( pEndNd->GetLang( nEndPos ) ) );
1545 :
1546 : // it is allowed to place the PaM just behind the last
1547 : // character in the text thus <= ...Len
1548 0 : bool bChanged = false;
1549 0 : if (nStartPos <= pStartNd->GetText().getLength() && nStartPos >= 0)
1550 : {
1551 0 : GetMark()->nContent = nStartPos;
1552 0 : bChanged = true;
1553 : }
1554 0 : if (nEndPos <= pEndNd->GetText().getLength() && nEndPos >= 0)
1555 : {
1556 0 : GetPoint()->nContent = nEndPos;
1557 0 : bChanged = true;
1558 : }
1559 0 : if (bChanged && !IsSelOvr())
1560 0 : bRes = true;
1561 : }
1562 0 : return bRes;
1563 : }
1564 :
1565 4 : bool SwTableCursor::LeftRight( bool bLeft, sal_uInt16 nCnt, sal_uInt16 /*nMode*/,
1566 : bool /*bVisualAllowed*/, bool /*bSkipHidden*/, bool /*bInsertCrsr*/ )
1567 : {
1568 2 : return bLeft ? GoPrevCell( nCnt )
1569 6 : : GoNextCell( nCnt );
1570 : }
1571 :
1572 : // calculate cursor bidi level: extracted from LeftRight()
1573 : const SwContentFrm*
1574 43 : SwCursor::DoSetBidiLevelLeftRight(
1575 : bool & io_rbLeft, bool bVisualAllowed, bool bInsertCrsr)
1576 : {
1577 : // calculate cursor bidi level
1578 43 : const SwContentFrm* pSttFrm = NULL;
1579 43 : SwNode& rNode = GetPoint()->nNode.GetNode();
1580 :
1581 43 : if( rNode.IsTextNode() )
1582 : {
1583 43 : const SwTextNode& rTNd = *rNode.GetTextNode();
1584 43 : SwIndex& rIdx = GetPoint()->nContent;
1585 43 : sal_Int32 nPos = rIdx.GetIndex();
1586 :
1587 43 : const SvtCTLOptions& rCTLOptions = SW_MOD()->GetCTLOptions();
1588 43 : if ( bVisualAllowed && rCTLOptions.IsCTLFontEnabled() &&
1589 : SvtCTLOptions::MOVEMENT_VISUAL ==
1590 0 : rCTLOptions.GetCTLCursorMovement() )
1591 : {
1592 : // for visual cursor travelling (used in bidi layout)
1593 : // we first have to convert the logic to a visual position
1594 0 : Point aPt;
1595 0 : pSttFrm = rTNd.getLayoutFrm( GetDoc()->getIDocumentLayoutAccess().GetCurrentLayout(), &aPt, GetPoint() );
1596 0 : if( pSttFrm )
1597 : {
1598 0 : sal_uInt8 nCrsrLevel = GetCrsrBidiLevel();
1599 0 : bool bForward = ! io_rbLeft;
1600 : const_cast<SwTextFrm*>(static_cast<const SwTextFrm*>(pSttFrm))->PrepareVisualMove( nPos, nCrsrLevel,
1601 0 : bForward, bInsertCrsr );
1602 0 : rIdx = nPos;
1603 0 : SetCrsrBidiLevel( nCrsrLevel );
1604 0 : io_rbLeft = ! bForward;
1605 : }
1606 : }
1607 : else
1608 : {
1609 43 : const SwScriptInfo* pSI = SwScriptInfo::GetScriptInfo( rTNd );
1610 43 : if ( pSI )
1611 : {
1612 : const sal_Int32 nMoveOverPos = io_rbLeft ?
1613 9 : ( nPos ? nPos - 1 : 0 ) :
1614 40 : nPos;
1615 31 : SetCrsrBidiLevel( pSI->DirType( nMoveOverPos ) );
1616 : }
1617 : }
1618 : }
1619 43 : return pSttFrm;
1620 : }
1621 :
1622 42903 : bool SwCursor::LeftRight( bool bLeft, sal_uInt16 nCnt, sal_uInt16 nMode,
1623 : bool bVisualAllowed,bool bSkipHidden, bool bInsertCrsr )
1624 : {
1625 : // calculate cursor bidi level
1626 42903 : SwNode& rNode = GetPoint()->nNode.GetNode();
1627 : const SwContentFrm* pSttFrm = // may side-effect bLeft!
1628 42903 : DoSetBidiLevelLeftRight(bLeft, bVisualAllowed, bInsertCrsr);
1629 :
1630 : // can the cursor be moved n times?
1631 42903 : SwCrsrSaveState aSave( *this );
1632 42903 : SwMoveFn fnMove = bLeft ? fnMoveBackward : fnMoveForward;
1633 :
1634 : SwGoInDoc fnGo;
1635 42903 : if ( bSkipHidden )
1636 32 : fnGo = CRSR_SKIP_CELLS == nMode ? fnGoContentCellsSkipHidden : fnGoContentSkipHidden;
1637 : else
1638 42871 : fnGo = CRSR_SKIP_CELLS == nMode ? fnGoContentCells : fnGoContent;
1639 :
1640 202407 : while( nCnt )
1641 : {
1642 117875 : SwNodeIndex aOldNodeIdx( GetPoint()->nNode );
1643 :
1644 117875 : if ( !Move( fnMove, fnGo ) )
1645 1274 : break;
1646 :
1647 : // If we were located inside a covered cell but our position has been
1648 : // corrected, we check if the last move has moved the cursor to a
1649 : // different table cell. In this case we set the cursor to the stored
1650 : // covered position and redo the move:
1651 116601 : if (m_nRowSpanOffset)
1652 : {
1653 0 : const SwNode* pOldTabBoxSttNode = aOldNodeIdx.GetNode().FindTableBoxStartNode();
1654 0 : const SwTableNode* pOldTabSttNode = pOldTabBoxSttNode ? pOldTabBoxSttNode->FindTableNode() : 0;
1655 0 : const SwNode* pNewTabBoxSttNode = GetPoint()->nNode.GetNode().FindTableBoxStartNode();
1656 0 : const SwTableNode* pNewTabSttNode = pNewTabBoxSttNode ? pNewTabBoxSttNode->FindTableNode() : 0;
1657 :
1658 0 : const bool bCellChanged = pOldTabSttNode && pNewTabSttNode &&
1659 0 : pOldTabSttNode == pNewTabSttNode &&
1660 0 : pOldTabBoxSttNode && pNewTabBoxSttNode &&
1661 0 : pOldTabBoxSttNode != pNewTabBoxSttNode;
1662 :
1663 0 : if ( bCellChanged )
1664 : {
1665 : // Set cursor to start/end of covered cell:
1666 0 : SwTableBox* pTableBox = pOldTabBoxSttNode->GetTableBox();
1667 0 : if ( pTableBox && pTableBox->getRowSpan() > 1 )
1668 : {
1669 : pTableBox = & pTableBox->FindEndOfRowSpan(
1670 0 : pOldTabSttNode->GetTable(),
1671 0 : static_cast<sal_uInt16>(pTableBox->getRowSpan() + m_nRowSpanOffset));
1672 0 : SwNodeIndex& rPtIdx = GetPoint()->nNode;
1673 0 : SwNodeIndex aNewIdx( *pTableBox->GetSttNd() );
1674 0 : rPtIdx = aNewIdx;
1675 :
1676 0 : GetDoc()->GetNodes().GoNextSection( &rPtIdx, false, false );
1677 0 : SwContentNode* pContentNode = GetContentNode();
1678 0 : if ( pContentNode )
1679 : {
1680 0 : GetPoint()->nContent.Assign( pContentNode, bLeft ? pContentNode->Len() : 0 );
1681 :
1682 : // Redo the move:
1683 0 : if ( !Move( fnMove, fnGo ) )
1684 0 : break;
1685 0 : }
1686 : }
1687 0 : m_nRowSpanOffset = 0;
1688 : }
1689 : }
1690 :
1691 : // Check if I'm inside a covered cell. Correct cursor if necessary and
1692 : // store covered cell:
1693 116601 : const SwNode* pTableBoxStartNode = GetPoint()->nNode.GetNode().FindTableBoxStartNode();
1694 116601 : if ( pTableBoxStartNode )
1695 : {
1696 299 : const SwTableBox* pTableBox = pTableBoxStartNode->GetTableBox();
1697 299 : if ( pTableBox && pTableBox->getRowSpan() < 1 )
1698 : {
1699 : // Store the row span offset:
1700 1 : m_nRowSpanOffset = pTableBox->getRowSpan();
1701 :
1702 : // Move cursor to non-covered cell:
1703 1 : const SwTableNode* pTableNd = pTableBoxStartNode->FindTableNode();
1704 1 : pTableBox = & pTableBox->FindStartOfRowSpan( pTableNd->GetTable(), USHRT_MAX );
1705 1 : SwNodeIndex& rPtIdx = GetPoint()->nNode;
1706 1 : SwNodeIndex aNewIdx( *pTableBox->GetSttNd() );
1707 1 : rPtIdx = aNewIdx;
1708 :
1709 1 : GetDoc()->GetNodes().GoNextSection( &rPtIdx, false, false );
1710 1 : SwContentNode* pContentNode = GetContentNode();
1711 1 : if ( pContentNode )
1712 : {
1713 1 : GetPoint()->nContent.Assign( pContentNode, bLeft ? pContentNode->Len() : 0 );
1714 1 : }
1715 : }
1716 : }
1717 116601 : --nCnt;
1718 116601 : }
1719 :
1720 : // here come some special rules for visual cursor travelling
1721 42903 : if ( pSttFrm )
1722 : {
1723 0 : SwNode& rTmpNode = GetPoint()->nNode.GetNode();
1724 0 : if ( &rTmpNode != &rNode && rTmpNode.IsTextNode() )
1725 : {
1726 0 : Point aPt;
1727 0 : const SwContentFrm* pEndFrm = rTmpNode.GetTextNode()->getLayoutFrm( GetDoc()->getIDocumentLayoutAccess().GetCurrentLayout(), &aPt, GetPoint() );
1728 0 : if ( pEndFrm )
1729 : {
1730 0 : if ( ! pEndFrm->IsRightToLeft() != ! pSttFrm->IsRightToLeft() )
1731 : {
1732 0 : if ( ! bLeft )
1733 0 : pEndFrm->RightMargin( this );
1734 : else
1735 0 : pEndFrm->LeftMargin( this );
1736 : }
1737 : }
1738 : }
1739 : }
1740 :
1741 84532 : return 0 == nCnt && !IsInProtectTable( true ) &&
1742 : !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
1743 84532 : nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
1744 : }
1745 :
1746 : // calculate cursor bidi level: extracted from UpDown()
1747 6 : void SwCursor::DoSetBidiLevelUpDown()
1748 : {
1749 6 : SwNode& rNode = GetPoint()->nNode.GetNode();
1750 6 : if ( rNode.IsTextNode() )
1751 : {
1752 : const SwScriptInfo* pSI =
1753 6 : SwScriptInfo::GetScriptInfo( *rNode.GetTextNode() );
1754 6 : if ( pSI )
1755 : {
1756 5 : SwIndex& rIdx = GetPoint()->nContent;
1757 5 : const sal_Int32 nPos = rIdx.GetIndex();
1758 :
1759 5 : if (nPos && nPos < rNode.GetTextNode()->GetText().getLength())
1760 : {
1761 0 : const sal_uInt8 nCurrLevel = pSI->DirType( nPos );
1762 0 : const sal_uInt8 nPrevLevel = pSI->DirType( nPos - 1 );
1763 :
1764 0 : if ( nCurrLevel % 2 != nPrevLevel % 2 )
1765 : {
1766 : // set cursor level to the lower of the two levels
1767 0 : SetCrsrBidiLevel( std::min( nCurrLevel, nPrevLevel ) );
1768 : }
1769 : else
1770 0 : SetCrsrBidiLevel( nCurrLevel );
1771 : }
1772 : }
1773 : }
1774 6 : }
1775 :
1776 9 : bool SwCursor::UpDown( bool bUp, sal_uInt16 nCnt,
1777 : Point* pPt, long nUpDownX )
1778 : {
1779 9 : SwTableCursor* pTableCrsr = dynamic_cast<SwTableCursor*>(this);
1780 9 : bool bAdjustTableCrsr = false;
1781 :
1782 : // If the point/mark of the table cursor in the same box then set cursor to
1783 : // beginning of the box
1784 12 : if( pTableCrsr && GetNode( true ).StartOfSectionNode() ==
1785 3 : GetNode( false ).StartOfSectionNode() )
1786 : {
1787 3 : if ( End() != GetPoint() )
1788 0 : Exchange();
1789 3 : bAdjustTableCrsr = true;
1790 : }
1791 :
1792 9 : bool bRet = false;
1793 9 : Point aPt;
1794 9 : if( pPt )
1795 6 : aPt = *pPt;
1796 9 : SwContentFrm* pFrm = GetContentNode()->getLayoutFrm( GetDoc()->getIDocumentLayoutAccess().GetCurrentLayout(), &aPt, GetPoint() );
1797 :
1798 9 : if( pFrm )
1799 : {
1800 9 : SwCrsrSaveState aSave( *this );
1801 :
1802 9 : if( !pPt )
1803 : {
1804 3 : SwRect aTmpRect;
1805 3 : pFrm->GetCharRect( aTmpRect, *GetPoint() );
1806 3 : aPt = aTmpRect.Pos();
1807 :
1808 3 : nUpDownX = pFrm->IsVertical() ?
1809 0 : aPt.getY() - pFrm->Frm().Top() :
1810 3 : aPt.getX() - pFrm->Frm().Left();
1811 : }
1812 :
1813 : // It is allowed to move footnotes in other footnotes but not sections
1814 9 : const bool bChkRange = !pFrm->IsInFootnote() || HasMark();
1815 18 : const SwPosition aOldPos( *GetPoint() );
1816 9 : const bool bInReadOnly = IsReadOnlyAvailable();
1817 :
1818 9 : if ( bAdjustTableCrsr && !bUp )
1819 : {
1820 : // Special case: We have a table cursor but the start box has more
1821 : // than one paragraph. If we want to go down, we have to set the
1822 : // point to the last frame in the table box. This is only necessary
1823 : // if we do not already have a table selection
1824 1 : const SwStartNode* pTableNd = GetNode( true ).FindTableBoxStartNode();
1825 : OSL_ENSURE( pTableNd, "pTableCrsr without SwTableNode?" );
1826 :
1827 1 : if ( pTableNd ) // safety first
1828 : {
1829 1 : const SwNode* pEndNd = pTableNd->EndOfSectionNode();
1830 1 : GetPoint()->nNode = *pEndNd;
1831 1 : pTableCrsr->Move( fnMoveBackward, fnGoNode );
1832 1 : pFrm = GetContentNode()->getLayoutFrm( GetDoc()->getIDocumentLayoutAccess().GetCurrentLayout(), &aPt, GetPoint() );
1833 : }
1834 : }
1835 :
1836 36 : while( nCnt &&
1837 4 : (bUp ? pFrm->UnitUp( this, nUpDownX, bInReadOnly )
1838 32 : : pFrm->UnitDown( this, nUpDownX, bInReadOnly ) ) &&
1839 9 : CheckNodesRange( aOldPos.nNode, GetPoint()->nNode, bChkRange ))
1840 : {
1841 9 : pFrm = GetContentNode()->getLayoutFrm( GetDoc()->getIDocumentLayoutAccess().GetCurrentLayout(), &aPt, GetPoint() );
1842 9 : --nCnt;
1843 : }
1844 :
1845 : // iterate over whole number of items?
1846 18 : if( !nCnt && !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
1847 9 : nsSwCursorSelOverFlags::SELOVER_CHANGEPOS ) )
1848 : {
1849 9 : if( !pTableCrsr )
1850 : {
1851 : // try to position the cursor at half of the char-rect's height
1852 6 : pFrm = GetContentNode()->getLayoutFrm( GetDoc()->getIDocumentLayoutAccess().GetCurrentLayout(), &aPt, GetPoint() );
1853 6 : SwCrsrMoveState eTmpState( MV_UPDOWN );
1854 6 : eTmpState.bSetInReadOnly = bInReadOnly;
1855 6 : SwRect aTmpRect;
1856 6 : pFrm->GetCharRect( aTmpRect, *GetPoint(), &eTmpState );
1857 6 : if ( pFrm->IsVertical() )
1858 : {
1859 0 : aPt.setX(aTmpRect.Center().getX());
1860 0 : pFrm->Calc();
1861 0 : aPt.setY(pFrm->Frm().Top() + nUpDownX);
1862 : }
1863 : else
1864 : {
1865 6 : aPt.setY(aTmpRect.Center().getY());
1866 6 : pFrm->Calc();
1867 6 : aPt.setX(pFrm->Frm().Left() + nUpDownX);
1868 : }
1869 6 : pFrm->GetCrsrOfst( GetPoint(), aPt, &eTmpState );
1870 : }
1871 9 : bRet = !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE | nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
1872 : }
1873 : else
1874 0 : *GetPoint() = aOldPos;
1875 :
1876 18 : DoSetBidiLevelUpDown(); // calculate cursor bidi level
1877 : }
1878 9 : return bRet;
1879 : }
1880 :
1881 1 : bool SwCursor::LeftRightMargin( bool bLeft, bool bAPI )
1882 : {
1883 1 : Point aPt;
1884 1 : SwContentFrm * pFrm = GetContentNode()->getLayoutFrm( GetDoc()->getIDocumentLayoutAccess().GetCurrentLayout(), &aPt, GetPoint() );
1885 :
1886 : // calculate cursor bidi level
1887 1 : if ( pFrm )
1888 1 : SetCrsrBidiLevel( pFrm->IsRightToLeft() ? 1 : 0 );
1889 :
1890 1 : SwCrsrSaveState aSave( *this );
1891 : return pFrm
1892 1 : && (bLeft ? pFrm->LeftMargin( this ) : pFrm->RightMargin( this, bAPI ) )
1893 2 : && !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE | nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
1894 : }
1895 :
1896 0 : bool SwCursor::IsAtLeftRightMargin( bool bLeft, bool bAPI ) const
1897 : {
1898 0 : bool bRet = false;
1899 0 : Point aPt;
1900 0 : SwContentFrm * pFrm = GetContentNode()->getLayoutFrm( GetDoc()->getIDocumentLayoutAccess().GetCurrentLayout(), &aPt, GetPoint() );
1901 0 : if( pFrm )
1902 : {
1903 0 : SwPaM aPam( *GetPoint() );
1904 0 : if( !bLeft && aPam.GetPoint()->nContent.GetIndex() )
1905 0 : --aPam.GetPoint()->nContent;
1906 0 : bRet = (bLeft ? pFrm->LeftMargin( &aPam )
1907 0 : : pFrm->RightMargin( &aPam, bAPI ))
1908 0 : && *aPam.GetPoint() == *GetPoint();
1909 : }
1910 0 : return bRet;
1911 : }
1912 :
1913 132 : bool SwCursor::SttEndDoc( bool bStt )
1914 : {
1915 132 : SwCrsrSaveState aSave( *this );
1916 : // Never jump over section boundaries during selection!
1917 : // Can the cursor still moved on?
1918 132 : SwMoveFn fnMove = bStt ? fnMoveBackward : fnMoveForward;
1919 274 : bool bRet = (!HasMark() || !IsNoContent() ) &&
1920 264 : Move( fnMove, fnGoDoc ) &&
1921 396 : !IsInProtectTable( true ) &&
1922 : !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
1923 : nsSwCursorSelOverFlags::SELOVER_CHANGEPOS |
1924 264 : nsSwCursorSelOverFlags::SELOVER_ENABLEREVDIREKTION );
1925 132 : return bRet;
1926 : }
1927 :
1928 4 : bool SwCursor::GoPrevNextCell( bool bNext, sal_uInt16 nCnt )
1929 : {
1930 4 : const SwTableNode* pTableNd = GetPoint()->nNode.GetNode().FindTableNode();
1931 4 : if( !pTableNd )
1932 0 : return false;
1933 :
1934 : // If there is another EndNode in front of the cell's StartNode then there
1935 : // exists a previous cell
1936 4 : SwCrsrSaveState aSave( *this );
1937 4 : SwNodeIndex& rPtIdx = GetPoint()->nNode;
1938 :
1939 12 : while( nCnt-- )
1940 : {
1941 4 : const SwNode* pTableBoxStartNode = rPtIdx.GetNode().FindTableBoxStartNode();
1942 4 : const SwTableBox* pTableBox = pTableBoxStartNode->GetTableBox();
1943 :
1944 : // Check if we have to move the cursor to a covered cell before
1945 : // proceeding:
1946 4 : if (m_nRowSpanOffset)
1947 : {
1948 0 : if ( pTableBox && pTableBox->getRowSpan() > 1 )
1949 : {
1950 0 : pTableBox = & pTableBox->FindEndOfRowSpan( pTableNd->GetTable(),
1951 0 : static_cast<sal_uInt16>(pTableBox->getRowSpan() + m_nRowSpanOffset));
1952 0 : SwNodeIndex aNewIdx( *pTableBox->GetSttNd() );
1953 0 : rPtIdx = aNewIdx;
1954 0 : pTableBoxStartNode = rPtIdx.GetNode().FindTableBoxStartNode();
1955 : }
1956 0 : m_nRowSpanOffset = 0;
1957 : }
1958 :
1959 : const SwNode* pTmpNode = bNext ?
1960 : pTableBoxStartNode->EndOfSectionNode() :
1961 4 : pTableBoxStartNode;
1962 :
1963 4 : SwNodeIndex aCellIdx( *pTmpNode, bNext ? 1 : -1 );
1964 8 : if( (bNext && !aCellIdx.GetNode().IsStartNode()) ||
1965 6 : (!bNext && !aCellIdx.GetNode().IsEndNode()) )
1966 0 : return false;
1967 :
1968 4 : rPtIdx = bNext ? aCellIdx : SwNodeIndex(*aCellIdx.GetNode().StartOfSectionNode());
1969 :
1970 4 : pTableBoxStartNode = rPtIdx.GetNode().FindTableBoxStartNode();
1971 4 : pTableBox = pTableBoxStartNode->GetTableBox();
1972 4 : if ( pTableBox && pTableBox->getRowSpan() < 1 )
1973 : {
1974 0 : m_nRowSpanOffset = pTableBox->getRowSpan();
1975 : // move cursor to non-covered cell:
1976 0 : pTableBox = & pTableBox->FindStartOfRowSpan( pTableNd->GetTable(), USHRT_MAX );
1977 0 : SwNodeIndex aNewIdx( *pTableBox->GetSttNd() );
1978 0 : rPtIdx = aNewIdx;
1979 : }
1980 4 : }
1981 :
1982 4 : ++rPtIdx;
1983 4 : if( !rPtIdx.GetNode().IsContentNode() )
1984 0 : GetDoc()->GetNodes().GoNextSection( &rPtIdx, true, false );
1985 4 : GetPoint()->nContent.Assign( GetContentNode(), 0 );
1986 :
1987 4 : return !IsInProtectTable( true );
1988 : }
1989 :
1990 0 : bool SwTableCursor::GotoTable( const OUString& )
1991 : {
1992 0 : return false; // invalid action
1993 : }
1994 :
1995 8 : bool SwCursor::GotoTable( const OUString& rName )
1996 : {
1997 8 : bool bRet = false;
1998 8 : if ( !HasMark() )
1999 : {
2000 8 : SwTable* pTmpTable = SwTable::FindTable( GetDoc()->FindTableFormatByName( rName ) );
2001 8 : if( pTmpTable )
2002 : {
2003 : // a table in a normal nodes array
2004 8 : SwCrsrSaveState aSave( *this );
2005 16 : GetPoint()->nNode = *pTmpTable->GetTabSortBoxes()[ 0 ]->
2006 16 : GetSttNd()->FindTableNode();
2007 8 : Move( fnMoveForward, fnGoContent );
2008 8 : bRet = !IsSelOvr();
2009 : }
2010 : }
2011 8 : return bRet;
2012 : }
2013 :
2014 3 : bool SwCursor::GotoTableBox( const OUString& rName )
2015 : {
2016 3 : bool bRet = false;
2017 3 : const SwTableNode* pTableNd = GetPoint()->nNode.GetNode().FindTableNode();
2018 3 : if( pTableNd )
2019 : {
2020 : // retrieve box by name
2021 3 : const SwTableBox* pTableBox = pTableNd->GetTable().GetTableBox( rName );
2022 9 : if( pTableBox && pTableBox->GetSttNd() &&
2023 3 : ( !pTableBox->GetFrameFormat()->GetProtect().IsContentProtected() ||
2024 0 : IsReadOnlyAvailable() ) )
2025 : {
2026 3 : SwCrsrSaveState aSave( *this );
2027 3 : GetPoint()->nNode = *pTableBox->GetSttNd();
2028 3 : Move( fnMoveForward, fnGoContent );
2029 3 : bRet = !IsSelOvr();
2030 : }
2031 : }
2032 3 : return bRet;
2033 : }
2034 :
2035 39506 : bool SwCursor::MovePara(SwWhichPara fnWhichPara, SwPosPara fnPosPara )
2036 : {
2037 : // for optimization test something before
2038 39506 : const SwNode* pNd = &GetPoint()->nNode.GetNode();
2039 39506 : bool bShortCut = false;
2040 39506 : if ( fnWhichPara == fnParaCurr )
2041 : {
2042 : // #i41048#
2043 : // If fnWhichPara == fnParaCurr then (*fnWhichPara)( *this, fnPosPara )
2044 : // can already move the cursor to a different text node. In this case
2045 : // we better check if IsSelOvr().
2046 25074 : const SwContentNode* pContentNd = pNd->GetContentNode();
2047 25074 : if ( pContentNd )
2048 : {
2049 25074 : const sal_Int32 nSttEnd = fnPosPara == fnMoveForward ? 0 : pContentNd->Len();
2050 25074 : if ( GetPoint()->nContent.GetIndex() != nSttEnd )
2051 25074 : bShortCut = true;
2052 : }
2053 : }
2054 : else
2055 : {
2056 28864 : if ( pNd->IsTextNode() &&
2057 28864 : pNd->GetNodes()[ pNd->GetIndex() +
2058 28864 : (fnWhichPara == fnParaNext ? 1 : -1 ) ]->IsTextNode() )
2059 4620 : bShortCut = true;
2060 : }
2061 :
2062 39506 : if ( bShortCut )
2063 29694 : return (*fnWhichPara)( *this, fnPosPara );
2064 :
2065 : // else we must use the SaveStructure, because the next/prev is not
2066 : // a same node type.
2067 9812 : SwCrsrSaveState aSave( *this );
2068 15363 : return (*fnWhichPara)( *this, fnPosPara ) &&
2069 15363 : !IsInProtectTable( true ) &&
2070 : !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
2071 15363 : nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
2072 : }
2073 :
2074 41915 : bool SwCursor::MoveSection( SwWhichSection fnWhichSect,
2075 : SwPosSection fnPosSect)
2076 : {
2077 41915 : SwCrsrSaveState aSave( *this );
2078 61608 : return (*fnWhichSect)( *this, fnPosSect ) &&
2079 61608 : !IsInProtectTable( true ) &&
2080 : !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
2081 61608 : nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
2082 : }
2083 :
2084 1 : void SwCursor::RestoreSavePos()
2085 : {
2086 : // This method is not supposed to be used in cases when nodes may be
2087 : // deleted; detect such cases, but do not crash (example: fdo#40831).
2088 1 : sal_uLong uNodeCount = GetPoint()->nNode.GetNodes().Count();
2089 : OSL_ENSURE(!m_pSavePos || m_pSavePos->nNode < uNodeCount,
2090 : "SwCursor::RestoreSavePos: invalid node: "
2091 : "probably something was deleted; consider using SwUnoCrsr instead");
2092 1 : if (m_pSavePos && m_pSavePos->nNode < uNodeCount)
2093 : {
2094 1 : GetPoint()->nNode = m_pSavePos->nNode;
2095 :
2096 1 : sal_Int32 nIdx = 0;
2097 1 : if ( GetContentNode() )
2098 : {
2099 1 : if (m_pSavePos->nContent <= GetContentNode()->Len())
2100 1 : nIdx = m_pSavePos->nContent;
2101 : else
2102 : {
2103 0 : nIdx = GetContentNode()->Len();
2104 : OSL_FAIL("SwCursor::RestoreSavePos: invalid content index");
2105 : }
2106 : }
2107 1 : GetPoint()->nContent.Assign( GetContentNode(), nIdx );
2108 : }
2109 1 : }
2110 :
2111 115 : SwTableCursor::SwTableCursor( const SwPosition &rPos, SwPaM* pRing )
2112 115 : : SwCursor( rPos, pRing, false )
2113 : {
2114 115 : m_bParked = false;
2115 115 : m_bChanged = false;
2116 115 : m_nTablePtNd = 0, m_nTableMkNd = 0;
2117 115 : m_nTablePtCnt = 0, m_nTableMkCnt = 0;
2118 115 : }
2119 :
2120 115 : SwTableCursor::~SwTableCursor() {}
2121 :
2122 : static bool
2123 17 : lcl_SeekEntry(const SwSelBoxes& rTmp, SwStartNode const*const pSrch,
2124 : size_t & o_rFndPos)
2125 : {
2126 17 : sal_uLong nIdx = pSrch->GetIndex();
2127 :
2128 17 : size_t nO = rTmp.size();
2129 17 : if( nO > 0 )
2130 : {
2131 11 : nO--;
2132 11 : size_t nU = 0;
2133 26 : while( nU <= nO )
2134 : {
2135 14 : size_t nM = nU + ( nO - nU ) / 2;
2136 14 : if( rTmp[ nM ]->GetSttNd() == pSrch )
2137 : {
2138 5 : o_rFndPos = nM;
2139 5 : return true;
2140 : }
2141 9 : else if( rTmp[ nM ]->GetSttIdx() < nIdx )
2142 4 : nU = nM + 1;
2143 5 : else if( nM == 0 )
2144 5 : return false;
2145 : else
2146 0 : nO = nM - 1;
2147 : }
2148 : }
2149 7 : return false;
2150 : }
2151 :
2152 122 : SwCursor* SwTableCursor::MakeBoxSels( SwCursor* pAktCrsr )
2153 : {
2154 122 : if (m_bChanged)
2155 : {
2156 122 : if (m_bParked)
2157 : {
2158 : // move back into content
2159 0 : Exchange();
2160 0 : Move( fnMoveForward );
2161 0 : Exchange();
2162 0 : Move( fnMoveForward );
2163 0 : m_bParked = false;
2164 : }
2165 :
2166 122 : m_bChanged = false;
2167 :
2168 : // create temporary copies so that all boxes that
2169 : // have already cursors can be removed
2170 122 : SwSelBoxes aTmp(m_SelectedBoxes);
2171 :
2172 : // compare old and new ones
2173 122 : SwNodes& rNds = pAktCrsr->GetDoc()->GetNodes();
2174 : const SwStartNode* pSttNd;
2175 122 : SwPaM* pCur = pAktCrsr;
2176 133 : do {
2177 : size_t nPos;
2178 133 : bool bDel = false;
2179 133 : pSttNd = pCur->GetPoint()->nNode.GetNode().FindTableBoxStartNode();
2180 150 : if( !pCur->HasMark() || !pSttNd ||
2181 17 : pSttNd != pCur->GetMark()->nNode.GetNode().FindTableBoxStartNode() )
2182 116 : bDel = true;
2183 :
2184 17 : else if( lcl_SeekEntry( aTmp, pSttNd, nPos ))
2185 : {
2186 5 : SwNodeIndex aIdx( *pSttNd, 1 );
2187 5 : const SwNode* pNd = &aIdx.GetNode();
2188 5 : if( !pNd->IsContentNode() )
2189 0 : pNd = rNds.GoNextSection( &aIdx, true, false );
2190 :
2191 5 : SwPosition* pPos = pCur->GetMark();
2192 5 : if( pNd != &pPos->nNode.GetNode() )
2193 0 : pPos->nNode = *pNd;
2194 5 : pPos->nContent.Assign( const_cast<SwContentNode*>(static_cast<const SwContentNode*>(pNd)), 0 );
2195 :
2196 5 : aIdx.Assign( *pSttNd->EndOfSectionNode(), - 1 );
2197 5 : if( !( pNd = &aIdx.GetNode())->IsContentNode() )
2198 0 : pNd = SwNodes::GoPrevSection( &aIdx, true, false );
2199 :
2200 5 : pPos = pCur->GetPoint();
2201 5 : if (pNd && pNd != &pPos->nNode.GetNode())
2202 0 : pPos->nNode = *pNd;
2203 5 : pPos->nContent.Assign(const_cast<SwContentNode*>(static_cast<const SwContentNode*>(pNd)), pNd ? static_cast<const SwContentNode*>(pNd)->Len() : 0);
2204 :
2205 5 : aTmp.erase( aTmp.begin() + nPos );
2206 : }
2207 : else
2208 12 : bDel = true;
2209 :
2210 133 : pCur = pCur->GetNext();
2211 133 : if( bDel )
2212 : {
2213 128 : SwPaM* pDel = pCur->GetPrev();
2214 :
2215 128 : if( pDel == pAktCrsr )
2216 118 : pAktCrsr->DeleteMark();
2217 : else
2218 10 : delete pDel;
2219 : }
2220 : } while ( pAktCrsr != pCur );
2221 :
2222 957 : for (size_t nPos = 0; nPos < aTmp.size(); ++nPos)
2223 : {
2224 835 : pSttNd = aTmp[ nPos ]->GetSttNd();
2225 :
2226 835 : SwNodeIndex aIdx( *pSttNd, 1 );
2227 835 : if( &aIdx.GetNodes() != &rNds )
2228 0 : break;
2229 835 : SwNode* pNd = &aIdx.GetNode();
2230 835 : if( !pNd->IsContentNode() )
2231 0 : pNd = rNds.GoNextSection( &aIdx, true, false );
2232 :
2233 1051 : SwPaM *const pNew = (!pAktCrsr->IsMultiSelection() && !pAktCrsr->HasMark())
2234 : ? pAktCrsr
2235 1553 : : pAktCrsr->Create( pAktCrsr );
2236 835 : pNew->GetPoint()->nNode = *pNd;
2237 835 : pNew->GetPoint()->nContent.Assign( static_cast<SwContentNode*>(pNd), 0 );
2238 835 : pNew->SetMark();
2239 :
2240 835 : SwPosition* pPos = pNew->GetPoint();
2241 835 : pPos->nNode.Assign( *pSttNd->EndOfSectionNode(), - 1 );
2242 835 : if( !( pNd = &pPos->nNode.GetNode())->IsContentNode() )
2243 0 : pNd = SwNodes::GoPrevSection( &pPos->nNode, true, false );
2244 :
2245 835 : pPos->nContent.Assign(static_cast<SwContentNode*>(pNd), pNd ? static_cast<SwContentNode*>(pNd)->Len() : 0);
2246 957 : }
2247 : }
2248 122 : return pAktCrsr;
2249 : }
2250 :
2251 836 : void SwTableCursor::InsertBox( const SwTableBox& rTableBox )
2252 : {
2253 836 : SwTableBox* pBox = const_cast<SwTableBox*>(&rTableBox);
2254 836 : m_SelectedBoxes.insert(pBox);
2255 836 : m_bChanged = true;
2256 836 : }
2257 :
2258 16 : void SwTableCursor::DeleteBox(size_t const nPos)
2259 : {
2260 16 : m_SelectedBoxes.erase(m_SelectedBoxes.begin() + nPos);
2261 16 : m_bChanged = true;
2262 16 : }
2263 :
2264 493 : bool SwTableCursor::NewTableSelection()
2265 : {
2266 493 : bool bRet = false;
2267 493 : const SwNode *pStart = GetContentNode()->FindTableBoxStartNode();
2268 493 : const SwNode *pEnd = GetContentNode(false)->FindTableBoxStartNode();
2269 493 : if( pStart && pEnd )
2270 : {
2271 493 : const SwTableNode *pTableNode = pStart->FindTableNode();
2272 986 : if( pTableNode == pEnd->FindTableNode() &&
2273 493 : pTableNode->GetTable().IsNewModel() )
2274 : {
2275 493 : bRet = true;
2276 493 : SwSelBoxes aNew(m_SelectedBoxes);
2277 493 : pTableNode->GetTable().CreateSelection( pStart, pEnd, aNew,
2278 493 : SwTable::SEARCH_NONE, false );
2279 493 : ActualizeSelection( aNew );
2280 : }
2281 : }
2282 493 : return bRet;
2283 : }
2284 :
2285 493 : void SwTableCursor::ActualizeSelection( const SwSelBoxes &rNew )
2286 : {
2287 493 : size_t nOld = 0, nNew = 0;
2288 2769 : while (nOld < m_SelectedBoxes.size() && nNew < rNew.size())
2289 : {
2290 1783 : SwTableBox const*const pPOld = m_SelectedBoxes[ nOld ];
2291 1783 : const SwTableBox* pPNew = rNew[ nNew ];
2292 1783 : if( pPOld == pPNew )
2293 : { // this box will stay
2294 1773 : ++nOld;
2295 1773 : ++nNew;
2296 : }
2297 10 : else if( pPOld->GetSttIdx() < pPNew->GetSttIdx() )
2298 : {
2299 5 : DeleteBox( nOld ); // this box has to go
2300 : }
2301 : else
2302 : {
2303 5 : InsertBox( *pPNew ); // this is a new one
2304 5 : ++nOld;
2305 5 : ++nNew;
2306 : }
2307 : }
2308 :
2309 993 : while (nOld < m_SelectedBoxes.size())
2310 : {
2311 7 : DeleteBox( nOld ); // some more to delete
2312 : }
2313 :
2314 1324 : for ( ; nNew < rNew.size(); ++nNew ) // some more to insert
2315 : {
2316 831 : InsertBox( *rNew[ nNew ] );
2317 : }
2318 493 : }
2319 :
2320 279 : bool SwTableCursor::IsCrsrMovedUpdate()
2321 : {
2322 279 : if( !IsCrsrMoved() )
2323 260 : return false;
2324 :
2325 19 : m_nTableMkNd = GetMark()->nNode.GetIndex();
2326 19 : m_nTablePtNd = GetPoint()->nNode.GetIndex();
2327 19 : m_nTableMkCnt = GetMark()->nContent.GetIndex();
2328 19 : m_nTablePtCnt = GetPoint()->nContent.GetIndex();
2329 19 : return true;
2330 : }
2331 :
2332 : /// park table cursor on the boxes' start node
2333 0 : void SwTableCursor::ParkCrsr()
2334 : {
2335 : // de-register index from text node
2336 0 : SwNode* pNd = &GetPoint()->nNode.GetNode();
2337 0 : if( !pNd->IsStartNode() )
2338 0 : pNd = pNd->StartOfSectionNode();
2339 0 : GetPoint()->nNode = *pNd;
2340 0 : GetPoint()->nContent.Assign( 0, 0 );
2341 :
2342 0 : pNd = &GetMark()->nNode.GetNode();
2343 0 : if( !pNd->IsStartNode() )
2344 0 : pNd = pNd->StartOfSectionNode();
2345 0 : GetMark()->nNode = *pNd;
2346 0 : GetMark()->nContent.Assign( 0, 0 );
2347 :
2348 0 : m_bChanged = true;
2349 0 : m_bParked = true;
2350 0 : }
2351 :
2352 25 : bool SwTableCursor::HasReadOnlyBoxSel() const
2353 : {
2354 25 : bool bRet = false;
2355 129 : for (size_t n = m_SelectedBoxes.size(); n; )
2356 : {
2357 79 : if (m_SelectedBoxes[--n]->GetFrameFormat()->GetProtect().IsContentProtected())
2358 : {
2359 0 : bRet = true;
2360 0 : break;
2361 : }
2362 : }
2363 25 : return bRet;
2364 177 : }
2365 :
2366 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|