Impress Remote 1.0.5, tag sdremote-1.0.5
[LibreOffice.git] / sw / source / core / crsr / swcrsr.cxx
blob4e7f34216e6576f58080e1508f5fbcc292ba9559
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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 <docary.hxx>
34 #include <ndtxt.hxx>
35 #include <section.hxx>
36 #include <swtable.hxx>
37 #include <cntfrm.hxx>
38 #include <rootfrm.hxx>
39 #include <txtfrm.hxx>
40 #include <scriptinfo.hxx>
41 #include <crstate.hxx>
42 #include <docsh.hxx>
43 #include <viewsh.hxx>
44 #include <frmatr.hxx>
45 #include <breakit.hxx>
46 #include <crsskip.hxx>
47 #include <vcl/msgbox.hxx>
48 #include <mdiexp.hxx>
49 #include <statstr.hrc>
50 #include <redline.hxx>
51 #include <xmloff/odffields.hxx>
53 using namespace ::com::sun::star::i18n;
56 static const sal_uInt16 coSrchRplcThreshold = 60000;
58 struct _PercentHdl
60 SwDocShell* pDSh;
61 sal_uLong nActPos;
62 bool bBack, bNodeIdx;
64 _PercentHdl( sal_uLong nStt, sal_uLong nEnd, SwDocShell* pSh )
65 : pDSh( pSh )
67 nActPos = nStt;
68 if( 0 != ( bBack = (nStt > nEnd )) )
70 sal_uLong n = nStt; nStt = nEnd; nEnd = n;
72 ::StartProgress( STR_STATSTR_SEARCH, nStt, nEnd, 0 );
75 _PercentHdl( const SwPaM& rPam )
76 : pDSh( (SwDocShell*)rPam.GetDoc()->GetDocShell() )
78 sal_uLong nStt, nEnd;
79 if( rPam.GetPoint()->nNode == rPam.GetMark()->nNode )
81 bNodeIdx = false;
82 nStt = rPam.GetMark()->nContent.GetIndex();
83 nEnd = rPam.GetPoint()->nContent.GetIndex();
85 else
87 bNodeIdx = true;
88 nStt = rPam.GetMark()->nNode.GetIndex();
89 nEnd = rPam.GetPoint()->nNode.GetIndex();
91 nActPos = nStt;
92 if( 0 != ( bBack = (nStt > nEnd )) )
94 sal_uLong n = nStt; nStt = nEnd; nEnd = n;
96 ::StartProgress( STR_STATSTR_SEARCH, nStt, nEnd, pDSh );
99 ~_PercentHdl() { ::EndProgress( pDSh ); }
101 void NextPos( sal_uLong nPos ) const
102 { ::SetProgressState( bBack ? nActPos - nPos : nPos, pDSh ); }
104 void NextPos( SwPosition& rPos ) const
106 sal_uLong nPos;
107 if( bNodeIdx )
108 nPos = rPos.nNode.GetIndex();
109 else
110 nPos = rPos.nContent.GetIndex();
111 ::SetProgressState( bBack ? nActPos - nPos : nPos, pDSh );
115 SwCursor::SwCursor( const SwPosition &rPos, SwPaM* pRing, bool bColumnSel )
116 : SwPaM( rPos, pRing ), pSavePos( 0 ), mnRowSpanOffset( 0 ), nCursorBidiLevel( 0 ),
117 mbColumnSelection( bColumnSel )
121 // @@@ semantic: no copy ctor.
122 SwCursor::SwCursor( SwCursor& rCpy )
123 : SwPaM( rCpy ), pSavePos( 0 ), mnRowSpanOffset( rCpy.mnRowSpanOffset ),
124 nCursorBidiLevel( rCpy.nCursorBidiLevel ), mbColumnSelection( rCpy.mbColumnSelection )
128 SwCursor::~SwCursor()
130 while( pSavePos )
132 _SwCursor_SavePos* pNxt = pSavePos->pNext;
133 delete pSavePos;
134 pSavePos = pNxt;
138 SwCursor* SwCursor::Create( SwPaM* pRing ) const
140 return new SwCursor( *GetPoint(), pRing, false );
143 bool SwCursor::IsReadOnlyAvailable() const
145 return false;
148 sal_Bool SwCursor::IsSkipOverHiddenSections() const
150 return sal_True;
153 sal_Bool SwCursor::IsSkipOverProtectSections() const
155 return !IsReadOnlyAvailable();
158 // CreateNewSavePos is virtual so that derived classes of cursor can implement
159 // own SaveObjects if needed and validate them in the virtual check routines.
160 void SwCursor::SaveState()
162 _SwCursor_SavePos* pNew = CreateNewSavePos();
163 pNew->pNext = pSavePos;
164 pSavePos = pNew;
167 void SwCursor::RestoreState()
169 if( pSavePos ) // Robust
171 _SwCursor_SavePos* pDel = pSavePos;
172 pSavePos = pSavePos->pNext;
173 delete pDel;
177 _SwCursor_SavePos* SwCursor::CreateNewSavePos() const
179 return new _SwCursor_SavePos( *this );
182 /// determine if point is outside of the node-array's content area
183 sal_Bool SwCursor::IsNoCntnt() const
185 return GetPoint()->nNode.GetIndex() <
186 GetDoc()->GetNodes().GetEndOfExtras().GetIndex();
189 bool SwCursor::IsSelOvrCheck(int)
191 return false;
194 // extracted from IsSelOvr()
195 bool SwTableCursor::IsSelOvrCheck(int eFlags)
197 SwNodes& rNds = GetDoc()->GetNodes();
198 // check sections of nodes array
199 if( (nsSwCursorSelOverFlags::SELOVER_CHECKNODESSECTION & eFlags)
200 && HasMark() )
202 SwNodeIndex aOldPos( rNds, GetSavePos()->nNode );
203 if( !CheckNodesRange( aOldPos, GetPoint()->nNode, sal_True ))
205 GetPoint()->nNode = aOldPos;
206 GetPoint()->nContent.Assign( GetCntntNode(), GetSavePos()->nCntnt );
207 return true;
210 return SwCursor::IsSelOvrCheck(eFlags);
213 sal_Bool SwCursor::IsSelOvr( int eFlags )
215 SwDoc* pDoc = GetDoc();
216 SwNodes& rNds = pDoc->GetNodes();
218 sal_Bool bSkipOverHiddenSections = IsSkipOverHiddenSections();
219 sal_Bool bSkipOverProtectSections = IsSkipOverProtectSections();
221 if ( IsSelOvrCheck( eFlags ) )
223 return sal_True;
226 if( pSavePos->nNode != GetPoint()->nNode.GetIndex() &&
227 // (1997) in UI-ReadOnly everything is allowed
228 ( !pDoc->GetDocShell() || !pDoc->GetDocShell()->IsReadOnlyUI() ))
230 // check new sections
231 SwNodeIndex& rPtIdx = GetPoint()->nNode;
232 const SwSectionNode* pSectNd = rPtIdx.GetNode().FindSectionNode();
233 if( pSectNd &&
234 ((bSkipOverHiddenSections && pSectNd->GetSection().IsHiddenFlag() ) ||
235 (bSkipOverProtectSections && pSectNd->GetSection().IsProtectFlag() )))
237 if( 0 == ( nsSwCursorSelOverFlags::SELOVER_CHANGEPOS & eFlags ) )
239 // then we're already done
240 RestoreSavePos();
241 return sal_True;
244 // set cursor to new position:
245 SwNodeIndex aIdx( rPtIdx );
246 xub_StrLen nCntntPos = pSavePos->nCntnt;
247 int bGoNxt = pSavePos->nNode < rPtIdx.GetIndex();
248 SwCntntNode* pCNd = bGoNxt
249 ? rNds.GoNextSection( &rPtIdx, bSkipOverHiddenSections, bSkipOverProtectSections)
250 : rNds.GoPrevSection( &rPtIdx, bSkipOverHiddenSections, bSkipOverProtectSections);
251 if( !pCNd && ( nsSwCursorSelOverFlags::SELOVER_ENABLEREVDIREKTION & eFlags ))
253 bGoNxt = !bGoNxt;
254 pCNd = bGoNxt ? rNds.GoNextSection( &rPtIdx, bSkipOverHiddenSections, bSkipOverProtectSections)
255 : rNds.GoPrevSection( &rPtIdx, bSkipOverHiddenSections, bSkipOverProtectSections);
258 int bIsValidPos = 0 != pCNd;
259 sal_Bool bValidNodesRange = bIsValidPos &&
260 ::CheckNodesRange( rPtIdx, aIdx, sal_True );
261 if( !bValidNodesRange )
263 rPtIdx = pSavePos->nNode;
264 if( 0 == ( pCNd = rPtIdx.GetNode().GetCntntNode() ) )
266 bIsValidPos = sal_False;
267 nCntntPos = 0;
268 rPtIdx = aIdx;
269 if( 0 == ( pCNd = rPtIdx.GetNode().GetCntntNode() ) )
271 // then to the beginning of the document
272 rPtIdx = rNds.GetEndOfExtras();
273 pCNd = rNds.GoNext( &rPtIdx );
278 // register ContentIndex:
279 xub_StrLen nTmpPos = bIsValidPos ? (bGoNxt ? 0 : pCNd->Len()) : nCntntPos;
280 GetPoint()->nContent.Assign( pCNd, nTmpPos );
281 if( !bIsValidPos || !bValidNodesRange ||
282 IsInProtectTable( sal_True ) )
283 return sal_True;
286 // is there a protected section in the section?
287 if( HasMark() && bSkipOverProtectSections)
289 sal_uLong nSttIdx = GetMark()->nNode.GetIndex(),
290 nEndIdx = GetPoint()->nNode.GetIndex();
291 if( nEndIdx <= nSttIdx )
293 sal_uLong nTmp = nSttIdx;
294 nSttIdx = nEndIdx;
295 nEndIdx = nTmp;
298 const SwSectionFmts& rFmts = pDoc->GetSections();
299 for( sal_uInt16 n = 0; n < rFmts.size(); ++n )
301 const SwSectionFmt* pFmt = rFmts[n];
302 const SvxProtectItem& rProtect = pFmt->GetProtect();
303 if( rProtect.IsCntntProtected() )
305 const SwFmtCntnt& rCntnt = pFmt->GetCntnt(sal_False);
306 OSL_ENSURE( rCntnt.GetCntntIdx(), "No SectionNode?" );
307 sal_uLong nIdx = rCntnt.GetCntntIdx()->GetIndex();
308 if( nSttIdx <= nIdx && nEndIdx >= nIdx )
310 // if it is no linked section then we cannot select it
311 const SwSection& rSect = *pFmt->GetSection();
312 if( CONTENT_SECTION == rSect.GetType() )
314 RestoreSavePos();
315 return sal_True;
324 const SwNode* pNd = &GetPoint()->nNode.GetNode();
325 if( pNd->IsCntntNode() && !dynamic_cast<SwUnoCrsr*>(this) )
327 const SwCntntFrm* pFrm = ((SwCntntNode*)pNd)->getLayoutFrm( pDoc->GetCurrentLayout() );
328 if( pFrm && pFrm->IsValid() && 0 == pFrm->Frm().Height() &&
329 0 != ( nsSwCursorSelOverFlags::SELOVER_CHANGEPOS & eFlags ) )
331 // skip to the next/prev valid paragraph with a layout
332 SwNodeIndex& rPtIdx = GetPoint()->nNode;
333 int bGoNxt = pSavePos->nNode < rPtIdx.GetIndex();
334 while( 0 != ( pFrm = ( bGoNxt ? pFrm->GetNextCntntFrm()
335 : pFrm->GetPrevCntntFrm() )) &&
336 0 == pFrm->Frm().Height() )
339 // #i72394# skip to prev/next valid paragraph with a layout in case
340 // the first search did not succeed:
341 if( !pFrm )
343 bGoNxt = !bGoNxt;
344 pFrm = ((SwCntntNode*)pNd)->getLayoutFrm( pDoc->GetCurrentLayout() );
345 while ( pFrm && 0 == pFrm->Frm().Height() )
347 pFrm = bGoNxt ? pFrm->GetNextCntntFrm()
348 : pFrm->GetPrevCntntFrm();
352 SwCntntNode* pCNd;
353 if( pFrm && 0 != (pCNd = (SwCntntNode*)pFrm->GetNode()) )
355 // set this CntntNode as new position
356 rPtIdx = *pCNd;
357 pNd = pCNd;
359 // register ContentIndex:
360 xub_StrLen nTmpPos = bGoNxt ? 0 : pCNd->Len();
361 GetPoint()->nContent.Assign( pCNd, nTmpPos );
363 if( IsInProtectTable( sal_True ) )
364 pFrm = 0;
368 if( !pFrm )
370 DeleteMark();
371 RestoreSavePos();
372 return sal_True; // we need a frame
376 // is the cursor allowed to be in a protected node?
377 if( 0 == ( nsSwCursorSelOverFlags::SELOVER_CHANGEPOS & eFlags ) && !IsAtValidPos() )
379 DeleteMark();
380 RestoreSavePos();
381 return sal_True;
384 if( !HasMark() )
385 return sal_False;
387 // check for invalid sections
388 if( !::CheckNodesRange( GetMark()->nNode, GetPoint()->nNode, sal_True ))
390 DeleteMark();
391 RestoreSavePos();
392 return sal_True; // we need a frame
395 const SwTableNode* pPtNd = pNd->FindTableNode();
397 if( (pNd = &GetMark()->nNode.GetNode())->IsCntntNode() &&
398 !((SwCntntNode*)pNd)->getLayoutFrm( pDoc->GetCurrentLayout() ) && !dynamic_cast<SwUnoCrsr*>(this) )
400 DeleteMark();
401 RestoreSavePos();
402 return sal_True; // we need a frame
405 const SwTableNode* pMrkNd = pNd->FindTableNode();
407 // both in no or in same table node
408 if( ( !pMrkNd && !pPtNd ) || pPtNd == pMrkNd )
409 return sal_False;
411 // in different tables or only mark in table
412 if( ( pPtNd && pMrkNd ) || pMrkNd )
414 // not allowed, so go back to old position
415 RestoreSavePos();
416 // Crsr stays at old position
417 return sal_True;
420 // Note: this cannot happen in TableMode
421 if( pPtNd ) // if only Point in Table then go behind/in front of table
423 if( nsSwCursorSelOverFlags::SELOVER_CHANGEPOS & eFlags )
425 sal_Bool bSelTop = GetPoint()->nNode.GetIndex() <
426 (( nsSwCursorSelOverFlags::SELOVER_TOGGLE & eFlags ) ? pSavePos->nNode
427 : GetMark()->nNode.GetIndex());
429 do { // loop for table after table
430 sal_uLong nSEIdx = pPtNd->EndOfSectionIndex();
431 sal_uLong nSttEndTbl = nSEIdx + 1;
433 if( bSelTop )
434 nSttEndTbl = rNds[ nSEIdx ]->StartOfSectionIndex() - 1;
436 GetPoint()->nNode = nSttEndTbl;
437 const SwNode* pMyNd = GetNode();
439 if( pMyNd->IsSectionNode() || ( pMyNd->IsEndNode() &&
440 pMyNd->StartOfSectionNode()->IsSectionNode() ) )
442 pMyNd = bSelTop
443 ? rNds.GoPrevSection( &GetPoint()->nNode,sal_True,sal_False )
444 : rNds.GoNextSection( &GetPoint()->nNode,sal_True,sal_False );
446 /* #i12312# Handle failure of Go{Prev|Next}Section */
447 if ( 0 == pMyNd)
448 break;
450 if( 0 != ( pPtNd = pMyNd->FindTableNode() ))
451 continue;
454 // we permit these
455 if( pMyNd->IsCntntNode() &&
456 ::CheckNodesRange( GetMark()->nNode,
457 GetPoint()->nNode, sal_True ))
459 // table in table
460 const SwTableNode* pOuterTableNd = pMyNd->FindTableNode();
461 if ( pOuterTableNd )
462 pMyNd = pOuterTableNd;
463 else
465 SwCntntNode* pCNd = (SwCntntNode*)pMyNd;
466 xub_StrLen nTmpPos = bSelTop ? pCNd->Len() : 0;
467 GetPoint()->nContent.Assign( pCNd, nTmpPos );
468 return sal_False;
471 if( bSelTop
472 ? ( !pMyNd->IsEndNode() || 0 == ( pPtNd = pMyNd->FindTableNode() ))
473 : 0 == ( pPtNd = pMyNd->GetTableNode() ))
474 break;
475 } while( sal_True );
478 // stay on old position
479 RestoreSavePos();
480 return sal_True;
482 return sal_False;
485 #if defined( UNX )
486 #define IDX (*pCellStt)
487 #else
488 #define IDX aCellStt
489 #endif
492 sal_Bool SwCursor::IsInProtectTable( sal_Bool bMove, sal_Bool bChgCrsr )
494 SwCntntNode* pCNd = GetCntntNode();
495 if( !pCNd )
496 return sal_False;
498 // No table, no protected cell:
499 const SwTableNode* pTableNode = pCNd->FindTableNode();
500 if ( !pTableNode )
501 return sal_False;
503 // Current position == last save position?
504 if ( pSavePos->nNode == GetPoint()->nNode.GetIndex() )
505 return sal_False;
507 // Check for convered cell:
508 bool bInCoveredCell = false;
509 const SwStartNode* pTmpSttNode = pCNd->FindTableBoxStartNode();
510 OSL_ENSURE( pTmpSttNode, "In table, therefore I expect to get a SwTableBoxStartNode" );
511 const SwTableBox* pBox = pTmpSttNode ? pTableNode->GetTable().GetTblBox( pTmpSttNode->GetIndex() ) : 0; //Robust #151355
512 if ( pBox && pBox->getRowSpan() < 1 ) // Robust #151270
513 bInCoveredCell = true;
515 // Positions of covered cells are not acceptable:
516 if ( !bInCoveredCell )
518 // Position not protected?
519 if ( !pCNd->IsProtect() )
520 return sal_False;
522 // Cursor in protected cells allowed?
523 if ( IsReadOnlyAvailable() )
524 return sal_False;
527 // If we reach this point, we are in a protected or covered table cell!
529 if( !bMove )
531 if( bChgCrsr )
532 // restore the last save position
533 RestoreSavePos();
534 return sal_True; // Crsr stays at old position
537 // We are in a protected table cell. Traverse top to bottom?
538 if( pSavePos->nNode < GetPoint()->nNode.GetIndex() )
540 // search next valid box
541 // if there is another StartNode after the EndNode of a cell then
542 // there is another cell
543 #if defined( UNX )
544 SwNodeIndex* pCellStt = new SwNodeIndex( *GetNode()->
545 FindTableBoxStartNode()->EndOfSectionNode(), 1 );
546 #else
547 SwNodeIndex aCellStt( *GetNode()->FindTableBoxStartNode()->EndOfSectionNode(), 1 );
548 #endif
549 sal_Bool bProt = sal_True;
550 GoNextCell:
551 do {
552 if( !IDX.GetNode().IsStartNode() )
553 break;
554 ++IDX;
555 if( 0 == ( pCNd = IDX.GetNode().GetCntntNode() ))
556 pCNd = IDX.GetNodes().GoNext( &IDX );
557 if( 0 == ( bProt = pCNd->IsProtect() ))
558 break;
559 IDX.Assign( *pCNd->FindTableBoxStartNode()->EndOfSectionNode(), 1 );
560 } while( bProt );
562 SetNextCrsr:
563 if( !bProt ) // found free cell
565 GetPoint()->nNode = IDX;
566 #if defined( UNX )
567 delete pCellStt;
568 #endif
569 SwCntntNode* pTmpCNd = GetCntntNode();
570 if( pTmpCNd )
572 GetPoint()->nContent.Assign( pTmpCNd, 0 );
573 return sal_False;
575 return IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
576 nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
578 // end of table, so go to next node
579 ++IDX;
580 SwNode* pNd;
581 if( ( pNd = &IDX.GetNode())->IsEndNode() || HasMark())
583 // if only table in FlyFrame or SSelection then stay on old position
584 if( bChgCrsr )
585 RestoreSavePos();
586 #if defined( UNX )
587 delete pCellStt;
588 #endif
589 return sal_True;
591 else if( pNd->IsTableNode() && IDX++ )
592 goto GoNextCell;
594 bProt = sal_False; // index is now on a content node
595 goto SetNextCrsr;
598 // search for the previous valid box
600 // if there is another EndNode in front of the StartNode than there
601 // exists a previous cell
602 #if defined( UNX )
603 SwNodeIndex* pCellStt = new SwNodeIndex(
604 *GetNode()->FindTableBoxStartNode(), -1 );
605 #else
606 SwNodeIndex aCellStt( *GetNode()->FindTableBoxStartNode(), -1 );
607 #endif
608 SwNode* pNd;
609 sal_Bool bProt = sal_True;
610 GoPrevCell:
611 do {
612 if( !( pNd = &IDX.GetNode())->IsEndNode() )
613 break;
614 IDX.Assign( *pNd->StartOfSectionNode(), +1 );
615 if( 0 == ( pCNd = IDX.GetNode().GetCntntNode() ))
616 pCNd = pNd->GetNodes().GoNext( &IDX );
617 if( 0 == ( bProt = pCNd->IsProtect() ))
618 break;
619 IDX.Assign( *pNd->FindTableBoxStartNode(), -1 );
620 } while( bProt );
622 SetPrevCrsr:
623 if( !bProt ) // found free cell
625 GetPoint()->nNode = IDX;
626 #if defined( UNX )
627 delete pCellStt;
628 #endif
629 SwCntntNode* pTmpCNd = GetCntntNode();
630 if( pTmpCNd )
632 GetPoint()->nContent.Assign( pTmpCNd, 0 );
633 return sal_False;
635 return IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
636 nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
638 // at the beginning of a table, so go to next node
639 IDX--;
640 if( ( pNd = &IDX.GetNode())->IsStartNode() || HasMark() )
642 // if only table in FlyFrame or SSelection then stay on old position
643 if( bChgCrsr )
644 RestoreSavePos();
645 #if defined( UNX )
646 delete pCellStt;
647 #endif
648 return sal_True;
650 else if( pNd->StartOfSectionNode()->IsTableNode() && IDX-- )
651 goto GoPrevCell;
653 bProt = sal_False; // index is now on a content node
654 goto SetPrevCrsr;
658 /// Return <true> if cursor can be set to this position
659 sal_Bool SwCursor::IsAtValidPos( sal_Bool bPoint ) const
661 const SwDoc* pDoc = GetDoc();
662 const SwPosition* pPos = bPoint ? GetPoint() : GetMark();
663 const SwNode* pNd = &pPos->nNode.GetNode();
665 if( pNd->IsCntntNode() && !((SwCntntNode*)pNd)->getLayoutFrm( pDoc->GetCurrentLayout() ) &&
666 !dynamic_cast<const SwUnoCrsr*>(this) )
668 return sal_False;
671 // #i45129# - in UI-ReadOnly everything is allowed
672 if( !pDoc->GetDocShell() || !pDoc->GetDocShell()->IsReadOnlyUI() )
673 return sal_True;
675 sal_Bool bCrsrInReadOnly = IsReadOnlyAvailable();
676 if( !bCrsrInReadOnly && pNd->IsProtect() )
677 return sal_False;
679 const SwSectionNode* pSectNd = pNd->FindSectionNode();
680 if( pSectNd && (pSectNd->GetSection().IsHiddenFlag() ||
681 ( !bCrsrInReadOnly && pSectNd->GetSection().IsProtectFlag() )))
682 return sal_False;
684 return sal_True;
687 void SwCursor::SaveTblBoxCntnt( const SwPosition* ) {}
689 /// set range for search in document
690 SwMoveFnCollection* SwCursor::MakeFindRange( SwDocPositions nStart,
691 SwDocPositions nEnd, SwPaM* pRange ) const
693 pRange->SetMark();
694 FillFindPos( nStart, *pRange->GetMark() );
695 FillFindPos( nEnd, *pRange->GetPoint() );
697 // determine direction of search
698 return ( DOCPOS_START == nStart || DOCPOS_OTHERSTART == nStart ||
699 (DOCPOS_CURR == nStart &&
700 (DOCPOS_END == nEnd || DOCPOS_OTHEREND == nEnd ) ))
701 ? fnMoveForward : fnMoveBackward;
705 static sal_uLong lcl_FindSelection( SwFindParas& rParas, SwCursor* pCurCrsr,
706 SwMoveFn fnMove, SwCursor*& pFndRing,
707 SwPaM& aRegion, FindRanges eFndRngs,
708 sal_Bool bInReadOnly, sal_Bool& bCancel )
710 SwDoc* pDoc = pCurCrsr->GetDoc();
711 bool const bDoesUndo = pDoc->GetIDocumentUndoRedo().DoesUndo();
712 int nFndRet = 0;
713 sal_uLong nFound = 0;
714 int bSrchBkwrd = fnMove == fnMoveBackward, bEnde = sal_False;
715 SwPaM *pTmpCrsr = pCurCrsr, *pSaveCrsr = pCurCrsr;
717 // only create progress bar for ShellCrsr
718 bool bIsUnoCrsr = 0 != dynamic_cast<SwUnoCrsr*>(pCurCrsr);
719 _PercentHdl* pPHdl = 0;
720 sal_uInt16 nCrsrCnt = 0;
721 if( FND_IN_SEL & eFndRngs )
723 while( pCurCrsr != ( pTmpCrsr = (SwPaM*)pTmpCrsr->GetNext() ))
724 ++nCrsrCnt;
725 if( nCrsrCnt && !bIsUnoCrsr )
726 pPHdl = new _PercentHdl( 0, nCrsrCnt, pDoc->GetDocShell() );
728 else
729 pSaveCrsr = (SwPaM*)pSaveCrsr->GetPrev();
731 do {
732 aRegion.SetMark();
733 // independent from search direction: SPoint is always bigger than mark
734 // if the search area is valid
735 SwPosition *pSttPos = aRegion.GetMark(),
736 *pEndPos = aRegion.GetPoint();
737 *pSttPos = *pTmpCrsr->Start();
738 *pEndPos = *pTmpCrsr->End();
739 if( bSrchBkwrd )
740 aRegion.Exchange();
742 if( !nCrsrCnt && !pPHdl && !bIsUnoCrsr )
743 pPHdl = new _PercentHdl( aRegion );
745 // as long as found and not at same position
746 while( *pSttPos <= *pEndPos &&
747 0 != ( nFndRet = rParas.Find( pCurCrsr, fnMove,
748 &aRegion, bInReadOnly )) &&
749 ( !pFndRing ||
750 *pFndRing->GetPoint() != *pCurCrsr->GetPoint() ||
751 *pFndRing->GetMark() != *pCurCrsr->GetMark() ))
753 if( !( FIND_NO_RING & nFndRet ))
755 // #i24084# - create ring similar to the one in CreateCrsr
756 SwCursor* pNew = pCurCrsr->Create( pFndRing );
757 if( !pFndRing )
758 pFndRing = pNew;
760 pNew->SetMark();
761 *pNew->GetMark() = *pCurCrsr->GetMark();
764 ++nFound;
766 if( !( eFndRngs & FND_IN_SELALL) )
768 bEnde = sal_True;
769 break;
772 if ((coSrchRplcThreshold == nFound)
773 && pDoc->GetIDocumentUndoRedo().DoesUndo()
774 && rParas.IsReplaceMode())
776 short nRet = pCurCrsr->MaxReplaceArived();
777 if( RET_YES == nRet )
779 pDoc->GetIDocumentUndoRedo().DelAllUndoObj();
780 pDoc->GetIDocumentUndoRedo().DoUndo(false);
782 else
784 bEnde = sal_True;
785 if(RET_CANCEL == nRet)
787 bCancel = sal_True;
789 break;
793 if( bSrchBkwrd )
794 // move pEndPos in front of the found area
795 *pEndPos = *pCurCrsr->Start();
796 else
797 // move pSttPos behind the found area
798 *pSttPos = *pCurCrsr->End();
800 if( *pSttPos == *pEndPos )
801 // in area but at the end => done
802 break;
804 if( !nCrsrCnt && pPHdl )
806 pPHdl->NextPos( *aRegion.GetMark() );
810 if( bEnde || !( eFndRngs & ( FND_IN_SELALL | FND_IN_SEL )) )
811 break;
813 pTmpCrsr = ((SwPaM*)pTmpCrsr->GetNext());
814 if( nCrsrCnt && pPHdl )
816 pPHdl->NextPos( ++pPHdl->nActPos );
819 } while( pTmpCrsr != pSaveCrsr );
821 if( nFound && !pFndRing ) // if no ring should be created
822 pFndRing = pCurCrsr->Create();
824 delete pPHdl;
825 pDoc->GetIDocumentUndoRedo().DoUndo(bDoesUndo);
826 return nFound;
830 static int lcl_MakeSelFwrd( const SwNode& rSttNd, const SwNode& rEndNd,
831 SwPaM& rPam, int bFirst )
833 if( rSttNd.GetIndex() + 1 == rEndNd.GetIndex() )
834 return sal_False;
836 SwNodes& rNds = rPam.GetDoc()->GetNodes();
837 rPam.DeleteMark();
838 SwCntntNode* pCNd;
839 if( !bFirst )
841 rPam.GetPoint()->nNode = rSttNd;
842 pCNd = rNds.GoNext( &rPam.GetPoint()->nNode );
843 if( !pCNd )
844 return sal_False;
845 pCNd->MakeStartIndex( &rPam.GetPoint()->nContent );
847 else if( rSttNd.GetIndex() > rPam.GetPoint()->nNode.GetIndex() ||
848 rPam.GetPoint()->nNode.GetIndex() >= rEndNd.GetIndex() )
849 // not in this section
850 return sal_False;
852 rPam.SetMark();
853 rPam.GetPoint()->nNode = rEndNd;
854 pCNd = rNds.GoPrevious( &rPam.GetPoint()->nNode );
855 if( !pCNd )
856 return sal_False;
857 pCNd->MakeEndIndex( &rPam.GetPoint()->nContent );
859 return *rPam.GetMark() < *rPam.GetPoint();
863 static int lcl_MakeSelBkwrd( const SwNode& rSttNd, const SwNode& rEndNd,
864 SwPaM& rPam, int bFirst )
866 if( rEndNd.GetIndex() + 1 == rSttNd.GetIndex() )
867 return sal_False;
869 SwNodes& rNds = rPam.GetDoc()->GetNodes();
870 rPam.DeleteMark();
871 SwCntntNode* pCNd;
872 if( !bFirst )
874 rPam.GetPoint()->nNode = rSttNd;
875 pCNd = rNds.GoPrevious( &rPam.GetPoint()->nNode );
876 if( !pCNd )
877 return sal_False;
878 pCNd->MakeEndIndex( &rPam.GetPoint()->nContent );
880 else if( rEndNd.GetIndex() > rPam.GetPoint()->nNode.GetIndex() ||
881 rPam.GetPoint()->nNode.GetIndex() >= rSttNd.GetIndex() )
882 return sal_False; // not in this section
884 rPam.SetMark();
885 rPam.GetPoint()->nNode = rEndNd;
886 pCNd = rNds.GoNext( &rPam.GetPoint()->nNode );
887 if( !pCNd )
888 return sal_False;
889 pCNd->MakeStartIndex( &rPam.GetPoint()->nContent );
891 return *rPam.GetPoint() < *rPam.GetMark();
894 // this method "searches" for all use cases because in SwFindParas is always the
895 // correct parameters and respective search method
896 sal_uLong SwCursor::FindAll( SwFindParas& rParas,
897 SwDocPositions nStart, SwDocPositions nEnde,
898 FindRanges eFndRngs, sal_Bool& bCancel )
900 bCancel = sal_False;
901 SwCrsrSaveState aSaveState( *this );
903 // create region without adding it to the ring
904 SwPaM aRegion( *GetPoint() );
905 SwMoveFn fnMove = MakeFindRange( nStart, nEnde, &aRegion );
907 sal_uLong nFound = 0;
908 int bMvBkwrd = fnMove == fnMoveBackward;
909 sal_Bool bInReadOnly = IsReadOnlyAvailable();
911 SwCursor* pFndRing = 0;
912 SwNodes& rNds = GetDoc()->GetNodes();
914 // search in sections?
915 if( FND_IN_SEL & eFndRngs )
917 // if string was not found in region then get all sections (cursors
918 // stays unchanged)
919 if( 0 == ( nFound = lcl_FindSelection( rParas, this, fnMove,
920 pFndRing, aRegion, eFndRngs,
921 bInReadOnly, bCancel ) ))
922 return nFound;
924 // found string at least once; it's all in new Crsr ring thus delete old one
925 while( GetNext() != this )
926 delete GetNext();
928 *GetPoint() = *pFndRing->GetPoint();
929 SetMark();
930 *GetMark() = *pFndRing->GetMark();
931 pFndRing->MoveRingTo( this );
932 delete pFndRing;
934 else if( FND_IN_OTHER & eFndRngs )
936 // put cursor as copy of current into ring
937 // chaining points always to first created, so forward
938 SAL_WNODEPRECATED_DECLARATIONS_PUSH
939 std::auto_ptr< SwCursor > pSav( Create( this ) ); // save the current cursor
940 SAL_WNODEPRECATED_DECLARATIONS_POP
942 // if already outside of body text search from this position or start at
943 // 1. base section
944 if( bMvBkwrd
945 ? lcl_MakeSelBkwrd( rNds.GetEndOfExtras(),
946 *rNds.GetEndOfPostIts().StartOfSectionNode(),
947 *this, rNds.GetEndOfExtras().GetIndex() >=
948 GetPoint()->nNode.GetIndex() )
949 : lcl_MakeSelFwrd( *rNds.GetEndOfPostIts().StartOfSectionNode(),
950 rNds.GetEndOfExtras(), *this,
951 rNds.GetEndOfExtras().GetIndex() >=
952 GetPoint()->nNode.GetIndex() ))
954 nFound = lcl_FindSelection( rParas, this, fnMove, pFndRing,
955 aRegion, eFndRngs, bInReadOnly, bCancel );
958 if( !nFound )
960 // put back the old one
961 *GetPoint() = *pSav->GetPoint();
962 if( pSav->HasMark() )
964 SetMark();
965 *GetMark() = *pSav->GetMark();
967 else
968 DeleteMark();
969 return 0;
971 pSav.release();
973 if( !( FND_IN_SELALL & eFndRngs ))
975 // there should only be a single one, thus add it
976 // independent from search direction: SPoint is always bigger than
977 // mark if the search area is valid
978 *GetPoint() = *pFndRing->GetPoint();
979 SetMark();
980 *GetMark() = *pFndRing->GetMark();
982 else
984 // found string at least once; it's all in new Crsr ring thus delete old one
985 while( GetNext() != this )
986 delete GetNext();
988 *GetPoint() = *pFndRing->GetPoint();
989 SetMark();
990 *GetMark() = *pFndRing->GetMark();
991 pFndRing->MoveRingTo( this );
993 delete pFndRing;
995 else if( FND_IN_SELALL & eFndRngs )
997 SAL_WNODEPRECATED_DECLARATIONS_PUSH
998 ::std::auto_ptr< SwCursor> pSav( Create( this ) ); // save the current cursor
999 SAL_WNODEPRECATED_DECLARATIONS_POP
1001 const SwNode* pSttNd = ( FND_IN_BODYONLY & eFndRngs )
1002 ? rNds.GetEndOfContent().StartOfSectionNode()
1003 : rNds.GetEndOfPostIts().StartOfSectionNode();
1005 if( bMvBkwrd
1006 ? lcl_MakeSelBkwrd( rNds.GetEndOfContent(), *pSttNd,*this, sal_False )
1007 : lcl_MakeSelFwrd( *pSttNd, rNds.GetEndOfContent(), *this, sal_False ))
1009 nFound = lcl_FindSelection( rParas, this, fnMove, pFndRing,
1010 aRegion, eFndRngs, bInReadOnly, bCancel );
1013 if( !nFound )
1015 // put back the old one
1016 *GetPoint() = *pSav->GetPoint();
1017 if( pSav->HasMark() )
1019 SetMark();
1020 *GetMark() = *pSav->GetMark();
1022 else
1023 DeleteMark();
1024 return 0;
1026 pSav.release();
1027 while( GetNext() != this )
1028 delete GetNext();
1030 *GetPoint() = *pFndRing->GetPoint();
1031 SetMark();
1032 *GetMark() = *pFndRing->GetMark();
1033 pFndRing->MoveRingTo( this );
1034 delete pFndRing;
1036 else
1038 // if a GetMark is set then keep the GetMark of the found object
1039 // This allows spanning an area with this search.
1040 SwPosition aMarkPos( *GetMark() );
1041 int bMarkPos = HasMark() && !eFndRngs;
1043 if( 0 != (nFound = rParas.Find( this, fnMove,
1044 &aRegion, bInReadOnly ) ? 1 : 0)
1045 && bMarkPos )
1046 *GetMark() = aMarkPos;
1049 if( nFound && SwCursor::IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE ) )
1050 nFound = 0;
1051 return nFound;
1055 void SwCursor::FillFindPos( SwDocPositions ePos, SwPosition& rPos ) const
1057 bool bIsStart = true;
1058 SwCntntNode* pCNd = 0;
1059 SwNodes& rNds = GetDoc()->GetNodes();
1061 switch( ePos )
1063 case DOCPOS_START:
1064 rPos.nNode = *rNds.GetEndOfContent().StartOfSectionNode();
1065 pCNd = rNds.GoNext( &rPos.nNode );
1066 break;
1068 case DOCPOS_END:
1069 rPos.nNode = rNds.GetEndOfContent();
1070 pCNd = rNds.GoPrevious( &rPos.nNode );
1071 bIsStart = false;
1072 break;
1074 case DOCPOS_OTHERSTART:
1075 rPos.nNode = *rNds[ sal_uLong(0) ];
1076 pCNd = rNds.GoNext( &rPos.nNode );
1077 break;
1079 case DOCPOS_OTHEREND:
1080 rPos.nNode = *rNds.GetEndOfContent().StartOfSectionNode();
1081 pCNd = rNds.GoPrevious( &rPos.nNode );
1082 bIsStart = false;
1083 break;
1084 default:
1085 rPos = *GetPoint();
1088 if( pCNd )
1090 xub_StrLen nCPos = 0;
1091 if( !bIsStart )
1092 nCPos = pCNd->Len();
1093 rPos.nContent.Assign( pCNd, nCPos );
1097 short SwCursor::MaxReplaceArived()
1099 return RET_YES;
1103 sal_Bool SwCursor::IsStartWord( sal_Int16 nWordType ) const
1105 return IsStartWordWT( nWordType );
1108 sal_Bool SwCursor::IsEndWord( sal_Int16 nWordType ) const
1110 return IsEndWordWT( nWordType );
1113 sal_Bool SwCursor::IsInWord( sal_Int16 nWordType ) const
1115 return IsInWordWT( nWordType );
1118 sal_Bool SwCursor::GoStartWord()
1120 return GoStartWordWT( WordType::ANYWORD_IGNOREWHITESPACES );
1123 sal_Bool SwCursor::GoEndWord()
1125 return GoEndWordWT( WordType::ANYWORD_IGNOREWHITESPACES );
1128 sal_Bool SwCursor::GoNextWord()
1130 return GoNextWordWT( WordType::ANYWORD_IGNOREWHITESPACES );
1133 sal_Bool SwCursor::GoPrevWord()
1135 return GoPrevWordWT( WordType::ANYWORD_IGNOREWHITESPACES );
1138 sal_Bool SwCursor::SelectWord( ViewShell* pViewShell, const Point* pPt )
1140 return SelectWordWT( pViewShell, WordType::ANYWORD_IGNOREWHITESPACES, pPt );
1143 sal_Bool SwCursor::IsStartWordWT( sal_Int16 nWordType ) const
1145 sal_Bool bRet = sal_False;
1146 const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
1147 if( pTxtNd && pBreakIt->GetBreakIter().is() )
1149 xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
1150 bRet = pBreakIt->GetBreakIter()->isBeginWord(
1151 pTxtNd->GetTxt(), nPtPos,
1152 pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos )),
1153 nWordType );
1155 return bRet;
1158 sal_Bool SwCursor::IsEndWordWT( sal_Int16 nWordType ) const
1160 sal_Bool bRet = sal_False;
1161 const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
1162 if( pTxtNd && pBreakIt->GetBreakIter().is() )
1164 xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
1165 bRet = pBreakIt->GetBreakIter()->isEndWord(
1166 pTxtNd->GetTxt(), nPtPos,
1167 pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos ) ),
1168 nWordType );
1171 return bRet;
1174 sal_Bool SwCursor::IsInWordWT( sal_Int16 nWordType ) const
1176 sal_Bool bRet = sal_False;
1177 const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
1178 if( pTxtNd && pBreakIt->GetBreakIter().is() )
1180 xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
1181 Boundary aBoundary = pBreakIt->GetBreakIter()->getWordBoundary(
1182 pTxtNd->GetTxt(), nPtPos,
1183 pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos ) ),
1184 nWordType,
1185 sal_True );
1187 bRet = aBoundary.startPos != aBoundary.endPos &&
1188 aBoundary.startPos <= nPtPos &&
1189 nPtPos <= aBoundary.endPos;
1190 if(bRet)
1192 const CharClass& rCC = GetAppCharClass();
1193 bRet = rCC.isLetterNumeric( pTxtNd->GetTxt(), static_cast<xub_StrLen>(aBoundary.startPos) );
1196 return bRet;
1199 sal_Bool SwCursor::IsStartEndSentence( bool bEnd ) const
1201 sal_Bool bRet = bEnd ?
1202 GetCntntNode() && GetPoint()->nContent == GetCntntNode()->Len() :
1203 GetPoint()->nContent.GetIndex() == 0;
1205 if( !bRet )
1207 SwCursor aCrsr(*GetPoint(), 0, false);
1208 SwPosition aOrigPos = *aCrsr.GetPoint();
1209 aCrsr.GoSentence( bEnd ? SwCursor::END_SENT : SwCursor::START_SENT );
1210 bRet = aOrigPos == *aCrsr.GetPoint();
1213 return bRet;
1216 sal_Bool SwCursor::GoStartWordWT( sal_Int16 nWordType )
1218 sal_Bool bRet = sal_False;
1219 const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
1220 if( pTxtNd && pBreakIt->GetBreakIter().is() )
1222 SwCrsrSaveState aSave( *this );
1223 xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
1224 nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->getWordBoundary(
1225 pTxtNd->GetTxt(), nPtPos,
1226 pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos ) ),
1227 nWordType,
1228 sal_False ).startPos;
1230 if( nPtPos < pTxtNd->GetTxt().Len() )
1232 GetPoint()->nContent = nPtPos;
1233 if( !IsSelOvr() )
1234 bRet = sal_True;
1237 return bRet;
1240 sal_Bool SwCursor::GoEndWordWT( sal_Int16 nWordType )
1242 sal_Bool bRet = sal_False;
1243 const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
1244 if( pTxtNd && pBreakIt->GetBreakIter().is() )
1246 SwCrsrSaveState aSave( *this );
1247 xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
1248 nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->getWordBoundary(
1249 pTxtNd->GetTxt(), nPtPos,
1250 pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos ) ),
1251 nWordType,
1252 sal_True ).endPos;
1254 if( nPtPos <= pTxtNd->GetTxt().Len() &&
1255 GetPoint()->nContent.GetIndex() != nPtPos )
1257 GetPoint()->nContent = nPtPos;
1258 if( !IsSelOvr() )
1259 bRet = sal_True;
1262 return bRet;
1265 sal_Bool SwCursor::GoNextWordWT( sal_Int16 nWordType )
1267 sal_Bool bRet = sal_False;
1268 const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
1269 if( pTxtNd && pBreakIt->GetBreakIter().is() )
1271 SwCrsrSaveState aSave( *this );
1272 xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
1274 nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->nextWord(
1275 pTxtNd->GetTxt(), nPtPos,
1276 pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos, 1 ) ),
1277 nWordType ).startPos;
1279 if( nPtPos < pTxtNd->GetTxt().Len() )
1281 GetPoint()->nContent = nPtPos;
1282 if( !IsSelOvr() )
1283 bRet = sal_True;
1286 return bRet;
1289 sal_Bool SwCursor::GoPrevWordWT( sal_Int16 nWordType )
1291 sal_Bool bRet = sal_False;
1292 const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
1293 if( pTxtNd && pBreakIt->GetBreakIter().is() )
1295 SwCrsrSaveState aSave( *this );
1296 xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
1297 const xub_StrLen nPtStart = nPtPos;
1299 if( nPtPos )
1300 --nPtPos;
1301 nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->previousWord(
1302 pTxtNd->GetTxt(), nPtStart,
1303 pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos, 1 ) ),
1304 nWordType ).startPos;
1306 if( nPtPos < pTxtNd->GetTxt().Len() )
1308 GetPoint()->nContent = nPtPos;
1309 if( !IsSelOvr() )
1310 bRet = sal_True;
1313 return bRet;
1316 sal_Bool SwCursor::SelectWordWT( ViewShell* pViewShell, sal_Int16 nWordType, const Point* pPt )
1318 SwCrsrSaveState aSave( *this );
1320 sal_Bool bRet = sal_False;
1321 sal_Bool bForward = sal_True;
1322 DeleteMark();
1323 const SwRootFrm* pLayout = pViewShell->GetLayout();
1324 if( pPt && 0 != pLayout )
1326 // set the cursor to the layout position
1327 Point aPt( *pPt );
1328 pLayout->GetCrsrOfst( GetPoint(), aPt );
1329 } //swmod 071107 //swmod 071225
1331 const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
1332 if( pTxtNd && pBreakIt->GetBreakIter().is() )
1334 // Should we select the whole fieldmark?
1335 const IDocumentMarkAccess* pMarksAccess = GetDoc()->getIDocumentMarkAccess( );
1336 sw::mark::IFieldmark* pMark = GetPoint() ? pMarksAccess->getFieldmarkFor( *GetPoint( ) ) : NULL;
1337 if ( pMark && pMark->GetFieldname() != ODF_COMMENTRANGE )
1339 const SwPosition rStart = pMark->GetMarkStart();
1340 GetPoint()->nNode = rStart.nNode;
1341 GetPoint()->nContent = rStart.nContent;
1342 GetPoint()->nContent++; // Don't select the start delimiter
1344 const SwPosition rEnd = pMark->GetMarkEnd();
1346 if ( rStart != rEnd )
1348 SetMark();
1349 GetMark()->nNode = rEnd.nNode;
1350 GetMark()->nContent = rEnd.nContent;
1351 GetMark()->nContent--; //Don't select the end delimiter
1353 bRet = sal_True;
1355 else
1357 xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
1358 Boundary aBndry( pBreakIt->GetBreakIter()->getWordBoundary(
1359 pTxtNd->GetTxt(), nPtPos,
1360 pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos ) ),
1361 nWordType,
1362 bForward ));
1364 if( aBndry.startPos != aBndry.endPos )
1366 GetPoint()->nContent = (xub_StrLen)aBndry.endPos;
1367 if( !IsSelOvr() )
1369 SetMark();
1370 GetMark()->nContent = (xub_StrLen)aBndry.startPos;
1371 if( !IsSelOvr() )
1372 bRet = sal_True;
1378 if( !bRet )
1380 DeleteMark();
1381 RestoreSavePos();
1383 return bRet;
1387 static String lcl_MaskDeletedRedlines( const SwTxtNode* pTxtNd )
1389 String aRes;
1390 if (pTxtNd)
1392 //mask deleted redlines
1393 String sNodeText(pTxtNd->GetTxt());
1394 const SwDoc& rDoc = *pTxtNd->GetDoc();
1395 const bool nShowChg = IDocumentRedlineAccess::IsShowChanges( rDoc.GetRedlineMode() );
1396 if ( nShowChg )
1398 sal_uInt16 nAct = rDoc.GetRedlinePos( *pTxtNd, USHRT_MAX );
1399 for ( ; nAct < rDoc.GetRedlineTbl().size(); nAct++ )
1401 const SwRedline* pRed = rDoc.GetRedlineTbl()[ nAct ];
1402 if ( pRed->Start()->nNode > pTxtNd->GetIndex() )
1403 break;
1405 if( nsRedlineType_t::REDLINE_DELETE == pRed->GetType() )
1407 xub_StrLen nStart, nEnd;
1408 pRed->CalcStartEnd( pTxtNd->GetIndex(), nStart, nEnd );
1410 while ( nStart < nEnd && nStart < sNodeText.Len() )
1411 sNodeText.SetChar( nStart++, CH_TXTATR_INWORD );
1415 aRes = sNodeText;
1417 return aRes;
1420 sal_Bool SwCursor::GoSentence( SentenceMoveType eMoveType )
1422 sal_Bool bRet = sal_False;
1423 const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
1424 if( pTxtNd && pBreakIt->GetBreakIter().is() )
1426 String sNodeText( lcl_MaskDeletedRedlines( pTxtNd ) );
1428 SwCrsrSaveState aSave( *this );
1429 xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
1430 switch ( eMoveType )
1432 case START_SENT: /* when modifying: see also ExpandToSentenceBorders below! */
1433 nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->beginOfSentence(
1434 sNodeText,
1435 nPtPos, pBreakIt->GetLocale(
1436 pTxtNd->GetLang( nPtPos ) ));
1437 break;
1438 case END_SENT: /* when modifying: see also ExpandToSentenceBorders below! */
1439 nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->endOfSentence(
1440 sNodeText,
1441 nPtPos, pBreakIt->GetLocale(
1442 pTxtNd->GetLang( nPtPos ) ));
1443 break;
1444 case NEXT_SENT:
1446 nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->endOfSentence(
1447 sNodeText,
1448 nPtPos, pBreakIt->GetLocale(
1449 pTxtNd->GetLang( nPtPos ) ));
1450 while (nPtPos != (sal_uInt16) -1 && ++nPtPos < sNodeText.Len()
1451 && sNodeText.GetChar(nPtPos)== ' ' /*isWhiteSpace( aTxt.GetChar(nPtPos)*/ )
1453 break;
1455 case PREV_SENT:
1456 nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->beginOfSentence(
1457 sNodeText,
1458 nPtPos, pBreakIt->GetLocale(
1459 pTxtNd->GetLang( nPtPos ) ));
1460 if (nPtPos == 0)
1461 return sal_False; // the previous sentence is not in this paragraph
1462 if (nPtPos > 0)
1463 nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->beginOfSentence(
1464 sNodeText,
1465 nPtPos - 1, pBreakIt->GetLocale(
1466 pTxtNd->GetLang( nPtPos ) ));
1467 break;
1470 // it is allowed to place the PaM just behind the last
1471 // character in the text thus <= ...Len
1472 if( nPtPos <= pTxtNd->GetTxt().Len() )
1474 GetPoint()->nContent = nPtPos;
1475 if( !IsSelOvr() )
1476 bRet = sal_True;
1479 return bRet;
1483 sal_Bool SwCursor::ExpandToSentenceBorders()
1485 sal_Bool bRes = sal_False;
1486 const SwTxtNode* pStartNd = Start()->nNode.GetNode().GetTxtNode();
1487 const SwTxtNode* pEndNd = End()->nNode.GetNode().GetTxtNode();
1488 if (pStartNd && pEndNd && pBreakIt->GetBreakIter().is())
1490 if (!HasMark())
1491 SetMark();
1493 String sStartText( lcl_MaskDeletedRedlines( pStartNd ) );
1494 String sEndText( pStartNd == pEndNd? sStartText : lcl_MaskDeletedRedlines( pEndNd ) );
1496 SwCrsrSaveState aSave( *this );
1497 xub_StrLen nStartPos = Start()->nContent.GetIndex();
1498 xub_StrLen nEndPos = End()->nContent.GetIndex();
1500 nStartPos = (xub_StrLen)pBreakIt->GetBreakIter()->beginOfSentence(
1501 sStartText, nStartPos,
1502 pBreakIt->GetLocale( pStartNd->GetLang( nStartPos ) ) );
1503 nEndPos = (xub_StrLen)pBreakIt->GetBreakIter()->endOfSentence(
1504 sEndText, nEndPos,
1505 pBreakIt->GetLocale( pEndNd->GetLang( nEndPos ) ) );
1507 // it is allowed to place the PaM just behind the last
1508 // character in the text thus <= ...Len
1509 bool bChanged = false;
1510 if (nStartPos <= pStartNd->GetTxt().Len())
1512 GetMark()->nContent = nStartPos;
1513 bChanged = true;
1515 if (nEndPos <= pEndNd->GetTxt().Len())
1517 GetPoint()->nContent = nEndPos;
1518 bChanged = true;
1520 if (bChanged && !IsSelOvr())
1521 bRes = sal_True;
1523 return bRes;
1527 sal_Bool SwTableCursor::LeftRight( sal_Bool bLeft, sal_uInt16 nCnt, sal_uInt16 /*nMode*/,
1528 sal_Bool /*bVisualAllowed*/, sal_Bool /*bSkipHidden*/, sal_Bool /*bInsertCrsr*/ )
1530 return bLeft ? GoPrevCell( nCnt )
1531 : GoNextCell( nCnt );
1535 // calculate cursor bidi level: extracted from LeftRight()
1536 const SwCntntFrm*
1537 SwCursor::DoSetBidiLevelLeftRight(
1538 sal_Bool & io_rbLeft, sal_Bool bVisualAllowed, sal_Bool bInsertCrsr)
1540 // calculate cursor bidi level
1541 const SwCntntFrm* pSttFrm = NULL;
1542 SwNode& rNode = GetPoint()->nNode.GetNode();
1544 if( rNode.IsTxtNode() )
1546 const SwTxtNode& rTNd = *rNode.GetTxtNode();
1547 SwIndex& rIdx = GetPoint()->nContent;
1548 xub_StrLen nPos = rIdx.GetIndex();
1550 const SvtCTLOptions& rCTLOptions = SW_MOD()->GetCTLOptions();
1551 if ( bVisualAllowed && rCTLOptions.IsCTLFontEnabled() &&
1552 SvtCTLOptions::MOVEMENT_VISUAL ==
1553 rCTLOptions.GetCTLCursorMovement() )
1555 // for visual cursor travelling (used in bidi layout)
1556 // we first have to convert the logic to a visual position
1557 Point aPt;
1558 pSttFrm = rTNd.getLayoutFrm( GetDoc()->GetCurrentLayout(), &aPt, GetPoint() );
1559 if( pSttFrm )
1561 sal_uInt8 nCrsrLevel = GetCrsrBidiLevel();
1562 sal_Bool bForward = ! io_rbLeft;
1563 ((SwTxtFrm*)pSttFrm)->PrepareVisualMove( nPos, nCrsrLevel,
1564 bForward, bInsertCrsr );
1565 rIdx = nPos;
1566 SetCrsrBidiLevel( nCrsrLevel );
1567 io_rbLeft = ! bForward;
1570 else
1572 const SwScriptInfo* pSI = SwScriptInfo::GetScriptInfo( rTNd );
1573 if ( pSI )
1575 const xub_StrLen nMoveOverPos = io_rbLeft ?
1576 ( nPos ? nPos - 1 : 0 ) :
1577 nPos;
1578 SetCrsrBidiLevel( pSI->DirType( nMoveOverPos ) );
1582 return pSttFrm;
1585 sal_Bool SwCursor::LeftRight( sal_Bool bLeft, sal_uInt16 nCnt, sal_uInt16 nMode,
1586 sal_Bool bVisualAllowed,sal_Bool bSkipHidden, sal_Bool bInsertCrsr )
1588 // calculate cursor bidi level
1589 SwNode& rNode = GetPoint()->nNode.GetNode();
1590 const SwCntntFrm* pSttFrm = // may side-effect bLeft!
1591 DoSetBidiLevelLeftRight(bLeft, bVisualAllowed, bInsertCrsr);
1593 // can the cursor be moved n times?
1594 SwCrsrSaveState aSave( *this );
1595 SwMoveFn fnMove = bLeft ? fnMoveBackward : fnMoveForward;
1597 SwGoInDoc fnGo;
1598 if ( bSkipHidden )
1599 fnGo = CRSR_SKIP_CELLS == nMode ? fnGoCntntCellsSkipHidden : fnGoCntntSkipHidden;
1600 else
1601 fnGo = CRSR_SKIP_CELLS == nMode ? fnGoCntntCells : fnGoCntnt;
1603 while( nCnt )
1605 SwNodeIndex aOldNodeIdx( GetPoint()->nNode );
1607 bool bSuccess = Move( fnMove, fnGo );
1608 if ( !bSuccess )
1609 break;
1611 // If we were located inside a covered cell but our position has been
1612 // corrected, we check if the last move has moved the cursor to a
1613 // different table cell. In this case we set the cursor to the stored
1614 // covered position and redo the move:
1615 if ( mnRowSpanOffset )
1617 const SwNode* pOldTabBoxSttNode = aOldNodeIdx.GetNode().FindTableBoxStartNode();
1618 const SwTableNode* pOldTabSttNode = pOldTabBoxSttNode ? pOldTabBoxSttNode->FindTableNode() : 0;
1619 const SwNode* pNewTabBoxSttNode = GetPoint()->nNode.GetNode().FindTableBoxStartNode();
1620 const SwTableNode* pNewTabSttNode = pNewTabBoxSttNode ? pNewTabBoxSttNode->FindTableNode() : 0;
1622 const bool bCellChanged = pOldTabSttNode && pNewTabSttNode &&
1623 pOldTabSttNode == pNewTabSttNode &&
1624 pOldTabBoxSttNode && pNewTabBoxSttNode &&
1625 pOldTabBoxSttNode != pNewTabBoxSttNode;
1627 if ( bCellChanged )
1629 // Set cursor to start/end of covered cell:
1630 SwTableBox* pTableBox = pOldTabBoxSttNode->GetTblBox();
1631 if ( pTableBox && pTableBox->getRowSpan() > 1 )
1633 pTableBox = & pTableBox->FindEndOfRowSpan( pOldTabSttNode->GetTable(), (sal_uInt16)(pTableBox->getRowSpan() + mnRowSpanOffset ) );
1634 SwNodeIndex& rPtIdx = GetPoint()->nNode;
1635 SwNodeIndex aNewIdx( *pTableBox->GetSttNd() );
1636 rPtIdx = aNewIdx;
1638 GetDoc()->GetNodes().GoNextSection( &rPtIdx, sal_False, sal_False );
1639 SwCntntNode* pCntntNode = GetCntntNode();
1640 if ( pCntntNode )
1642 const xub_StrLen nTmpPos = bLeft ? pCntntNode->Len() : 0;
1643 GetPoint()->nContent.Assign( pCntntNode, nTmpPos );
1645 // Redo the move:
1646 bSuccess = Move( fnMove, fnGo );
1647 if ( !bSuccess )
1648 break;
1652 mnRowSpanOffset = 0;
1656 // Check if I'm inside a covered cell. Correct cursor if necessary and
1657 // store covered cell:
1658 const SwNode* pTableBoxStartNode = GetPoint()->nNode.GetNode().FindTableBoxStartNode();
1659 if ( pTableBoxStartNode )
1661 const SwTableBox* pTableBox = pTableBoxStartNode->GetTblBox();
1662 if ( pTableBox && pTableBox->getRowSpan() < 1 )
1664 // Store the row span offset:
1665 mnRowSpanOffset = pTableBox->getRowSpan();
1667 // Move cursor to non-covered cell:
1668 const SwTableNode* pTblNd = pTableBoxStartNode->FindTableNode();
1669 pTableBox = & pTableBox->FindStartOfRowSpan( pTblNd->GetTable(), USHRT_MAX );
1670 SwNodeIndex& rPtIdx = GetPoint()->nNode;
1671 SwNodeIndex aNewIdx( *pTableBox->GetSttNd() );
1672 rPtIdx = aNewIdx;
1674 GetDoc()->GetNodes().GoNextSection( &rPtIdx, sal_False, sal_False );
1675 SwCntntNode* pCntntNode = GetCntntNode();
1676 if ( pCntntNode )
1678 const xub_StrLen nTmpPos = bLeft ? pCntntNode->Len() : 0;
1679 GetPoint()->nContent.Assign( pCntntNode, nTmpPos );
1684 --nCnt;
1687 // here come some special rules for visual cursor travelling
1688 if ( pSttFrm )
1690 SwNode& rTmpNode = GetPoint()->nNode.GetNode();
1691 if ( &rTmpNode != &rNode && rTmpNode.IsTxtNode() )
1693 Point aPt;
1694 const SwCntntFrm* pEndFrm = ((SwTxtNode&)rTmpNode).getLayoutFrm( GetDoc()->GetCurrentLayout(), &aPt, GetPoint() );
1695 if ( pEndFrm )
1697 if ( ! pEndFrm->IsRightToLeft() != ! pSttFrm->IsRightToLeft() )
1699 if ( ! bLeft )
1700 pEndFrm->RightMargin( this );
1701 else
1702 pEndFrm->LeftMargin( this );
1708 return 0 == nCnt && !IsInProtectTable( sal_True ) &&
1709 !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
1710 nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
1713 // calculate cursor bidi level: extracted from UpDown()
1714 void SwCursor::DoSetBidiLevelUpDown()
1716 SwNode& rNode = GetPoint()->nNode.GetNode();
1717 if ( rNode.IsTxtNode() )
1719 const SwScriptInfo* pSI =
1720 SwScriptInfo::GetScriptInfo( (SwTxtNode&)rNode );
1721 if ( pSI )
1723 SwIndex& rIdx = GetPoint()->nContent;
1724 xub_StrLen nPos = rIdx.GetIndex();
1726 if( nPos && nPos < ((SwTxtNode&)rNode).GetTxt().Len() )
1728 const sal_uInt8 nCurrLevel = pSI->DirType( nPos );
1729 const sal_uInt8 nPrevLevel = pSI->DirType( nPos - 1 );
1731 if ( nCurrLevel % 2 != nPrevLevel % 2 )
1733 // set cursor level to the lower of the two levels
1734 SetCrsrBidiLevel( Min( nCurrLevel, nPrevLevel ) );
1736 else
1737 SetCrsrBidiLevel( nCurrLevel );
1743 sal_Bool SwCursor::UpDown( sal_Bool bUp, sal_uInt16 nCnt,
1744 Point* pPt, long nUpDownX )
1746 SwTableCursor* pTblCrsr = dynamic_cast<SwTableCursor*>(this);
1747 bool bAdjustTableCrsr = false;
1749 // If the point/mark of the table cursor in the same box then set cursor to
1750 // beginning of the box
1751 if( pTblCrsr && GetNode( sal_True )->StartOfSectionNode() ==
1752 GetNode( sal_False )->StartOfSectionNode() )
1754 if ( End() != GetPoint() )
1755 Exchange();
1756 bAdjustTableCrsr = true;
1759 sal_Bool bRet = sal_False;
1760 Point aPt;
1761 if( pPt )
1762 aPt = *pPt;
1763 SwCntntFrm* pFrm = GetCntntNode()->getLayoutFrm( GetDoc()->GetCurrentLayout(), &aPt, GetPoint() );
1765 if( pFrm )
1767 SwCrsrSaveState aSave( *this );
1769 if( !pPt )
1771 SwRect aTmpRect;
1772 pFrm->GetCharRect( aTmpRect, *GetPoint() );
1773 aPt = aTmpRect.Pos();
1775 nUpDownX = pFrm->IsVertical() ?
1776 aPt.Y() - pFrm->Frm().Top() :
1777 aPt.X() - pFrm->Frm().Left();
1780 // It is allowed to move footnotes in other footnotes but not sections
1781 const sal_Bool bChkRange = pFrm->IsInFtn() && !HasMark()
1782 ? sal_False : sal_True;
1783 const SwPosition aOldPos( *GetPoint() );
1784 sal_Bool bInReadOnly = IsReadOnlyAvailable();
1786 if ( bAdjustTableCrsr && !bUp )
1788 // Special case: We have a table cursor but the start box has more
1789 // than one paragraph. If we want to go down, we have to set the
1790 // point to the last frame in the table box. This is only necessary
1791 // if we do not already have a table selection
1792 const SwStartNode* pTblNd = GetNode( sal_True )->FindTableBoxStartNode();
1793 OSL_ENSURE( pTblNd, "pTblCrsr without SwTableNode?" );
1795 if ( pTblNd ) // safety first
1797 const SwNode* pEndNd = pTblNd->EndOfSectionNode();
1798 GetPoint()->nNode = *pEndNd;
1799 pTblCrsr->Move( fnMoveBackward, fnGoNode );
1800 pFrm = GetCntntNode()->getLayoutFrm( GetDoc()->GetCurrentLayout(), &aPt, GetPoint() );
1804 while( nCnt &&
1805 (bUp ? pFrm->UnitUp( this, nUpDownX, bInReadOnly )
1806 : pFrm->UnitDown( this, nUpDownX, bInReadOnly ) ) &&
1807 CheckNodesRange( aOldPos.nNode, GetPoint()->nNode, bChkRange ))
1809 pFrm = GetCntntNode()->getLayoutFrm( GetDoc()->GetCurrentLayout(), &aPt, GetPoint() );
1810 --nCnt;
1813 // iterate over whole number of items?
1814 if( !nCnt && !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
1815 nsSwCursorSelOverFlags::SELOVER_CHANGEPOS ) )
1817 if( !pTblCrsr )
1819 // try to position the cursor at half of the char-rect's height
1820 pFrm = GetCntntNode()->getLayoutFrm( GetDoc()->GetCurrentLayout(), &aPt, GetPoint() );
1821 SwCrsrMoveState eTmpState( MV_UPDOWN );
1822 eTmpState.bSetInReadOnly = bInReadOnly;
1823 SwRect aTmpRect;
1824 pFrm->GetCharRect( aTmpRect, *GetPoint(), &eTmpState );
1825 if ( pFrm->IsVertical() )
1827 aPt.X() = aTmpRect.Center().X();
1828 pFrm->Calc();
1829 aPt.Y() = pFrm->Frm().Top() + nUpDownX;
1831 else
1833 aPt.Y() = aTmpRect.Center().Y();
1834 pFrm->Calc();
1835 aPt.X() = pFrm->Frm().Left() + nUpDownX;
1837 pFrm->GetCrsrOfst( GetPoint(), aPt, &eTmpState );
1839 bRet = sal_True;
1841 else
1842 *GetPoint() = aOldPos;
1844 DoSetBidiLevelUpDown(); // calculate cursor bidi level
1847 return bRet;
1850 sal_Bool SwCursor::LeftRightMargin( sal_Bool bLeft, sal_Bool bAPI )
1852 Point aPt;
1853 SwCntntFrm * pFrm = GetCntntNode()->getLayoutFrm( GetDoc()->GetCurrentLayout(), &aPt, GetPoint() );
1855 // calculate cursor bidi level
1856 if ( pFrm )
1857 SetCrsrBidiLevel( pFrm->IsRightToLeft() ? 1 : 0 );
1859 return pFrm && (bLeft ? pFrm->LeftMargin( this ) :
1860 pFrm->RightMargin( this, bAPI ) );
1863 sal_Bool SwCursor::IsAtLeftRightMargin( sal_Bool bLeft, sal_Bool bAPI ) const
1865 sal_Bool bRet = sal_False;
1866 Point aPt;
1867 SwCntntFrm * pFrm = GetCntntNode()->getLayoutFrm( GetDoc()->GetCurrentLayout(), &aPt, GetPoint() );
1868 if( pFrm )
1870 SwPaM aPam( *GetPoint() );
1871 if( !bLeft && aPam.GetPoint()->nContent.GetIndex() )
1872 aPam.GetPoint()->nContent--;
1873 bRet = (bLeft ? pFrm->LeftMargin( &aPam )
1874 : pFrm->RightMargin( &aPam, bAPI ))
1875 && *aPam.GetPoint() == *GetPoint();
1877 return bRet;
1880 sal_Bool SwCursor::SttEndDoc( sal_Bool bStt )
1882 SwCrsrSaveState aSave( *this );
1883 // Never jump over section boundaries during selection!
1884 // Can the cursor still moved on?
1885 SwMoveFn fnMove = bStt ? fnMoveBackward : fnMoveForward;
1886 sal_Bool bRet = (!HasMark() || !IsNoCntnt() ) &&
1887 Move( fnMove, fnGoDoc ) &&
1888 !IsInProtectTable( sal_True ) &&
1889 !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
1890 nsSwCursorSelOverFlags::SELOVER_CHANGEPOS |
1891 nsSwCursorSelOverFlags::SELOVER_ENABLEREVDIREKTION );
1893 return bRet;
1896 sal_Bool SwCursor::GoPrevNextCell( sal_Bool bNext, sal_uInt16 nCnt )
1898 const SwTableNode* pTblNd = GetPoint()->nNode.GetNode().FindTableNode();
1899 if( !pTblNd )
1900 return sal_False;
1902 // If there is another EndNode in front of the cell's StartNode then there
1903 // exists a previous cell
1904 SwCrsrSaveState aSave( *this );
1905 SwNodeIndex& rPtIdx = GetPoint()->nNode;
1907 while( nCnt-- )
1909 const SwNode* pTableBoxStartNode = rPtIdx.GetNode().FindTableBoxStartNode();
1910 const SwTableBox* pTableBox = pTableBoxStartNode->GetTblBox();
1912 // Check if we have to move the cursor to a covered cell before
1913 // proceeding:
1914 if ( mnRowSpanOffset )
1916 if ( pTableBox && pTableBox->getRowSpan() > 1 )
1918 pTableBox = & pTableBox->FindEndOfRowSpan( pTblNd->GetTable(), (sal_uInt16)(pTableBox->getRowSpan() + mnRowSpanOffset) );
1919 SwNodeIndex aNewIdx( *pTableBox->GetSttNd() );
1920 rPtIdx = aNewIdx;
1921 pTableBoxStartNode = rPtIdx.GetNode().FindTableBoxStartNode();
1923 mnRowSpanOffset = 0;
1926 const SwNode* pTmpNode = bNext ?
1927 pTableBoxStartNode->EndOfSectionNode() :
1928 pTableBoxStartNode;
1930 SwNodeIndex aCellIdx( *pTmpNode, bNext ? 1 : -1 );
1931 if( (bNext && !aCellIdx.GetNode().IsStartNode()) ||
1932 (!bNext && !aCellIdx.GetNode().IsEndNode()) )
1933 return sal_False;
1935 rPtIdx = bNext ? aCellIdx : SwNodeIndex(*aCellIdx.GetNode().StartOfSectionNode());
1937 pTableBoxStartNode = rPtIdx.GetNode().FindTableBoxStartNode();
1938 pTableBox = pTableBoxStartNode->GetTblBox();
1939 if ( pTableBox && pTableBox->getRowSpan() < 1 )
1941 mnRowSpanOffset = pTableBox->getRowSpan();
1942 // move cursor to non-covered cell:
1943 pTableBox = & pTableBox->FindStartOfRowSpan( pTblNd->GetTable(), USHRT_MAX );
1944 SwNodeIndex aNewIdx( *pTableBox->GetSttNd() );
1945 rPtIdx = aNewIdx;
1949 ++rPtIdx;
1950 if( !rPtIdx.GetNode().IsCntntNode() )
1951 GetDoc()->GetNodes().GoNextSection( &rPtIdx, sal_True, sal_False );
1952 GetPoint()->nContent.Assign( GetCntntNode(), 0 );
1954 return !IsInProtectTable( sal_True );
1957 bool SwTableCursor::GotoTable( const String& )
1959 return false; // invalid action
1962 bool SwCursor::GotoTable( const String& rName )
1964 bool bRet = false;
1965 if ( !HasMark() )
1967 SwTable* pTmpTbl = SwTable::FindTable( GetDoc()->FindTblFmtByName( rName ) );
1968 if( pTmpTbl )
1970 // a table in a normal nodes array
1971 SwCrsrSaveState aSave( *this );
1972 GetPoint()->nNode = *pTmpTbl->GetTabSortBoxes()[ 0 ]->
1973 GetSttNd()->FindTableNode();
1974 Move( fnMoveForward, fnGoCntnt );
1975 bRet = !IsSelOvr();
1978 return bRet;
1981 sal_Bool SwCursor::GotoTblBox( const String& rName )
1983 sal_Bool bRet = sal_False;
1984 const SwTableNode* pTblNd = GetPoint()->nNode.GetNode().FindTableNode();
1985 if( pTblNd )
1987 // retrieve box by name
1988 const SwTableBox* pTblBox = pTblNd->GetTable().GetTblBox( rName );
1989 if( pTblBox && pTblBox->GetSttNd() &&
1990 ( !pTblBox->GetFrmFmt()->GetProtect().IsCntntProtected() ||
1991 IsReadOnlyAvailable() ) )
1993 SwCrsrSaveState aSave( *this );
1994 GetPoint()->nNode = *pTblBox->GetSttNd();
1995 Move( fnMoveForward, fnGoCntnt );
1996 bRet = !IsSelOvr();
1999 return bRet;
2002 sal_Bool SwCursor::MovePara(SwWhichPara fnWhichPara, SwPosPara fnPosPara )
2004 // for optimization test something before
2005 const SwNode* pNd = &GetPoint()->nNode.GetNode();
2006 bool bShortCut = false;
2007 if ( fnWhichPara == fnParaCurr )
2009 // #i41048#
2010 // If fnWhichPara == fnParaCurr then (*fnWhichPara)( *this, fnPosPara )
2011 // can already move the cursor to a different text node. In this case
2012 // we better check if IsSelOvr().
2013 const SwCntntNode* pCntntNd = pNd->GetCntntNode();
2014 if ( pCntntNd )
2016 const xub_StrLen nSttEnd = fnPosPara == fnMoveForward ? 0 : pCntntNd->Len();
2017 if ( GetPoint()->nContent.GetIndex() != nSttEnd )
2018 bShortCut = true;
2021 else
2023 if ( pNd->IsTxtNode() &&
2024 pNd->GetNodes()[ pNd->GetIndex() +
2025 (fnWhichPara == fnParaNext ? 1 : -1 ) ]->IsTxtNode() )
2026 bShortCut = true;
2029 if ( bShortCut )
2030 return (*fnWhichPara)( *this, fnPosPara );
2032 // else we must use the SaveStructure, because the next/prev is not
2033 // a same node type.
2034 SwCrsrSaveState aSave( *this );
2035 return (*fnWhichPara)( *this, fnPosPara ) &&
2036 !IsInProtectTable( sal_True ) &&
2037 !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
2038 nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
2042 sal_Bool SwCursor::MoveSection( SwWhichSection fnWhichSect,
2043 SwPosSection fnPosSect)
2045 SwCrsrSaveState aSave( *this );
2046 return (*fnWhichSect)( *this, fnPosSect ) &&
2047 !IsInProtectTable( sal_True ) &&
2048 !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
2049 nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
2052 void SwCursor::RestoreSavePos()
2054 // This method is not supposed to be used in cases when nodes may be
2055 // deleted; detect such cases, but do not crash (example: fdo#40831).
2056 sal_uLong uNodeCount = GetPoint()->nNode.GetNodes().Count();
2057 OSL_ENSURE(!pSavePos || pSavePos->nNode < uNodeCount,
2058 "SwCursor::RestoreSavePos: invalid node: "
2059 "probably something was deleted; consider using SwUnoCrsr instead");
2060 if( pSavePos && pSavePos->nNode < uNodeCount )
2062 GetPoint()->nNode = pSavePos->nNode;
2064 xub_StrLen nIdx = 0;
2065 if ( GetCntntNode() )
2067 if ( pSavePos->nCntnt <= GetCntntNode()->Len() )
2068 nIdx = pSavePos->nCntnt;
2069 else
2071 nIdx = GetCntntNode()->Len();
2072 OSL_FAIL("SwCursor::RestoreSavePos: invalid content index");
2075 GetPoint()->nContent.Assign( GetCntntNode(), nIdx );
2081 SwTableCursor::SwTableCursor( const SwPosition &rPos, SwPaM* pRing )
2082 : SwCursor( rPos, pRing, false )
2084 bParked = sal_False;
2085 bChg = sal_False;
2086 nTblPtNd = 0, nTblMkNd = 0;
2087 nTblPtCnt = 0, nTblMkCnt = 0;
2090 SwTableCursor::~SwTableCursor() {}
2093 static bool
2094 lcl_SeekEntry(const SwSelBoxes& rTmp, SwStartNode const*const pSrch,
2095 size_t & o_rFndPos)
2097 sal_uLong nIdx = pSrch->GetIndex();
2099 size_t nO = rTmp.size();
2100 if( nO > 0 )
2102 nO--;
2103 size_t nU = 0;
2104 while( nU <= nO )
2106 size_t nM = nU + ( nO - nU ) / 2;
2107 if( rTmp[ nM ]->GetSttNd() == pSrch )
2109 o_rFndPos = nM;
2110 return sal_True;
2112 else if( rTmp[ nM ]->GetSttIdx() < nIdx )
2113 nU = nM + 1;
2114 else if( nM == 0 )
2115 return sal_False;
2116 else
2117 nO = nM - 1;
2120 return sal_False;
2124 SwCursor* SwTableCursor::MakeBoxSels( SwCursor* pAktCrsr )
2126 if( bChg )
2128 if( bParked )
2130 // move back into content
2131 Exchange();
2132 Move( fnMoveForward );
2133 Exchange();
2134 Move( fnMoveForward );
2135 bParked = sal_False;
2138 bChg = sal_False;
2140 // create temporary copies so that all boxes that
2141 // have already cursors can be removed
2142 SwSelBoxes aTmp(m_SelectedBoxes);
2144 // compare old and new ones
2145 SwNodes& rNds = pAktCrsr->GetDoc()->GetNodes();
2146 const SwStartNode* pSttNd;
2147 SwPaM* pCur = pAktCrsr;
2148 do {
2149 size_t nPos;
2150 bool bDel = false;
2151 pSttNd = pCur->GetPoint()->nNode.GetNode().FindTableBoxStartNode();
2152 if( !pCur->HasMark() || !pSttNd ||
2153 pSttNd != pCur->GetMark()->nNode.GetNode().FindTableBoxStartNode() )
2154 bDel = true;
2156 else if( lcl_SeekEntry( aTmp, pSttNd, nPos ))
2158 SwNodeIndex aIdx( *pSttNd, 1 );
2159 const SwNode* pNd = &aIdx.GetNode();
2160 if( !pNd->IsCntntNode() )
2161 pNd = rNds.GoNextSection( &aIdx, sal_True, sal_False );
2163 SwPosition* pPos = pCur->GetMark();
2164 if( pNd != &pPos->nNode.GetNode() )
2165 pPos->nNode = *pNd;
2166 pPos->nContent.Assign( (SwCntntNode*)pNd, 0 );
2168 aIdx.Assign( *pSttNd->EndOfSectionNode(), - 1 );
2169 if( !( pNd = &aIdx.GetNode())->IsCntntNode() )
2170 pNd = rNds.GoPrevSection( &aIdx, sal_True, sal_False );
2172 pPos = pCur->GetPoint();
2173 if( pNd != &pPos->nNode.GetNode() )
2174 pPos->nNode = *pNd;
2175 pPos->nContent.Assign( (SwCntntNode*)pNd, ((SwCntntNode*)pNd)->Len() );
2177 aTmp.erase( aTmp.begin() + nPos );
2179 else
2180 bDel = true;
2182 pCur = (SwPaM*)pCur->GetNext();
2183 if( bDel )
2185 SwPaM* pDel = (SwPaM*)pCur->GetPrev();
2187 if( pDel == pAktCrsr )
2188 pAktCrsr->DeleteMark();
2189 else
2190 delete pDel;
2192 } while ( pAktCrsr != pCur );
2194 for (size_t nPos = 0; nPos < aTmp.size(); ++nPos)
2196 pSttNd = aTmp[ nPos ]->GetSttNd();
2198 SwNodeIndex aIdx( *pSttNd, 1 );
2199 if( &aIdx.GetNodes() != &rNds )
2200 break;
2201 const SwNode* pNd = &aIdx.GetNode();
2202 if( !pNd->IsCntntNode() )
2203 pNd = rNds.GoNextSection( &aIdx, sal_True, sal_False );
2205 SwPaM* pNew;
2206 if( pAktCrsr->GetNext() == pAktCrsr && !pAktCrsr->HasMark() )
2208 pNew = pAktCrsr;
2209 pNew->GetPoint()->nNode = *pNd;
2210 pNew->GetPoint()->nContent.Assign( (SwCntntNode*)pNd, 0 );
2212 else
2214 pNew = pAktCrsr->Create( pAktCrsr );
2215 pNew->GetPoint()->nNode = *pNd;
2216 pNew->GetPoint()->nContent.Assign( (SwCntntNode*)pNd, 0 );
2218 pNew->SetMark();
2220 SwPosition* pPos = pNew->GetPoint();
2221 pPos->nNode.Assign( *pSttNd->EndOfSectionNode(), - 1 );
2222 if( !( pNd = &pPos->nNode.GetNode())->IsCntntNode() )
2223 pNd = rNds.GoPrevSection( &pPos->nNode, sal_True, sal_False );
2225 pPos->nContent.Assign( (SwCntntNode*)pNd, ((SwCntntNode*)pNd)->Len() );
2228 return pAktCrsr;
2232 void SwTableCursor::InsertBox( const SwTableBox& rTblBox )
2234 SwTableBox* pBox = (SwTableBox*)&rTblBox;
2235 m_SelectedBoxes.insert(pBox);
2236 bChg = sal_True;
2240 void SwTableCursor::DeleteBox(size_t const nPos)
2242 m_SelectedBoxes.erase(m_SelectedBoxes.begin() + nPos);
2243 bChg = sal_True;
2246 bool SwTableCursor::NewTableSelection()
2248 bool bRet = false;
2249 const SwNode *pStart = GetCntntNode()->FindTableBoxStartNode();
2250 const SwNode *pEnd = GetCntntNode(sal_False)->FindTableBoxStartNode();
2251 if( pStart && pEnd )
2253 const SwTableNode *pTableNode = pStart->FindTableNode();
2254 if( pTableNode == pEnd->FindTableNode() &&
2255 pTableNode->GetTable().IsNewModel() )
2257 bRet = true;
2258 SwSelBoxes aNew(m_SelectedBoxes);
2259 pTableNode->GetTable().CreateSelection( pStart, pEnd, aNew,
2260 SwTable::SEARCH_NONE, false );
2261 ActualizeSelection( aNew );
2264 return bRet;
2267 void SwTableCursor::ActualizeSelection( const SwSelBoxes &rNew )
2269 size_t nOld = 0, nNew = 0;
2270 while (nOld < m_SelectedBoxes.size() && nNew < rNew.size())
2272 SwTableBox const*const pPOld = m_SelectedBoxes[ nOld ];
2273 const SwTableBox* pPNew = rNew[ nNew ];
2274 if( pPOld == pPNew )
2275 { // this box will stay
2276 ++nOld;
2277 ++nNew;
2279 else if( pPOld->GetSttIdx() < pPNew->GetSttIdx() )
2281 DeleteBox( nOld ); // this box has to go
2283 else
2285 InsertBox( *pPNew ); // this is a new one
2286 ++nOld;
2287 ++nNew;
2291 while (nOld < m_SelectedBoxes.size())
2293 DeleteBox( nOld ); // some more to delete
2296 for ( ; nNew < rNew.size(); ++nNew ) // some more to insert
2298 InsertBox( *rNew[ nNew ] );
2302 sal_Bool SwTableCursor::IsCrsrMovedUpdt()
2304 if( !IsCrsrMoved() )
2305 return sal_False;
2307 nTblMkNd = GetMark()->nNode.GetIndex();
2308 nTblPtNd = GetPoint()->nNode.GetIndex();
2309 nTblMkCnt = GetMark()->nContent.GetIndex();
2310 nTblPtCnt = GetPoint()->nContent.GetIndex();
2311 return sal_True;
2314 /// park table cursor on the boxes' start node
2315 void SwTableCursor::ParkCrsr()
2317 // de-register index from text node
2318 SwNode* pNd = &GetPoint()->nNode.GetNode();
2319 if( !pNd->IsStartNode() )
2320 pNd = pNd->StartOfSectionNode();
2321 GetPoint()->nNode = *pNd;
2322 GetPoint()->nContent.Assign( 0, 0 );
2324 pNd = &GetMark()->nNode.GetNode();
2325 if( !pNd->IsStartNode() )
2326 pNd = pNd->StartOfSectionNode();
2327 GetMark()->nNode = *pNd;
2328 GetMark()->nContent.Assign( 0, 0 );
2330 bChg = sal_True;
2331 bParked = sal_True;
2335 sal_Bool SwTableCursor::HasReadOnlyBoxSel() const
2337 sal_Bool bRet = sal_False;
2338 for (size_t n = m_SelectedBoxes.size(); n; )
2340 if (m_SelectedBoxes[--n]->GetFrmFmt()->GetProtect().IsCntntProtected())
2342 bRet = sal_True;
2343 break;
2346 return bRet;
2349 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */