xref: /trunk/main/sw/source/core/crsr/swcrsr.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 
32 #include <hintids.hxx>
33 #include <editeng/protitem.hxx>
34 #include <com/sun/star/i18n/WordType.hdl>
35 #include <com/sun/star/i18n/CharType.hdl>
36 #include <unotools/charclass.hxx>
37 #include <svl/ctloptions.hxx>
38 #include <swmodule.hxx>
39 #include <fmtcntnt.hxx>
40 #include <swtblfmt.hxx>
41 #include <swcrsr.hxx>
42 #include <unocrsr.hxx>
43 #include <doc.hxx>
44 #include <IDocumentUndoRedo.hxx>
45 #include <docary.hxx>
46 #include <ndtxt.hxx>
47 #include <section.hxx>
48 #include <swtable.hxx>
49 #include <cntfrm.hxx>
50 #include <rootfrm.hxx>
51 #include <txtfrm.hxx>
52 #include <scriptinfo.hxx>
53 #include <crstate.hxx>
54 #include <docsh.hxx>
55 #include <viewsh.hxx>
56 #include <frmatr.hxx>
57 #include <breakit.hxx>
58 #include <crsskip.hxx>
59 #include <vcl/msgbox.hxx>
60 #include <mdiexp.hxx>           // ...Percent()
61 #include <statstr.hrc>          // ResId fuer Statusleiste
62 #include <redline.hxx>      // SwRedline
63 
64 
65 using namespace ::com::sun::star::i18n;
66 
67 
68 static const sal_uInt16 coSrchRplcThreshold = 60000;
69 
70 struct _PercentHdl
71 {
72     SwDocShell* pDSh;
73     sal_uLong nActPos;
74     sal_Bool bBack, bNodeIdx;
75 
76     _PercentHdl( sal_uLong nStt, sal_uLong nEnd, SwDocShell* pSh )
77         : pDSh( pSh )
78     {
79         nActPos = nStt;
80         if( 0 != ( bBack = (nStt > nEnd )) )
81         {
82             sal_uLong n = nStt; nStt = nEnd; nEnd = n;
83         }
84         ::StartProgress( STR_STATSTR_SEARCH, nStt, nEnd, 0 );
85     }
86 
87     _PercentHdl( const SwPaM& rPam )
88         : pDSh( (SwDocShell*)rPam.GetDoc()->GetDocShell() )
89     {
90         sal_uLong nStt, nEnd;
91         if( rPam.GetPoint()->nNode == rPam.GetMark()->nNode )
92         {
93             bNodeIdx = sal_False;
94             nStt = rPam.GetMark()->nContent.GetIndex();
95             nEnd = rPam.GetPoint()->nContent.GetIndex();
96         }
97         else
98         {
99             bNodeIdx = sal_True;
100             nStt = rPam.GetMark()->nNode.GetIndex();
101             nEnd = rPam.GetPoint()->nNode.GetIndex();
102         }
103         nActPos = nStt;
104         if( 0 != ( bBack = (nStt > nEnd )) )
105         {
106             sal_uLong n = nStt; nStt = nEnd; nEnd = n;
107         }
108         ::StartProgress( STR_STATSTR_SEARCH, nStt, nEnd, pDSh );
109     }
110 
111     ~_PercentHdl()                      { ::EndProgress( pDSh ); }
112 
113     void NextPos( sal_uLong nPos ) const
114         { ::SetProgressState( bBack ? nActPos - nPos : nPos, pDSh ); }
115 
116     void NextPos( SwPosition& rPos ) const
117         {
118             sal_uLong nPos;
119             if( bNodeIdx )
120                 nPos = rPos.nNode.GetIndex();
121             else
122                 nPos = rPos.nContent.GetIndex();
123             ::SetProgressState( bBack ? nActPos - nPos : nPos, pDSh );
124         }
125 };
126 
127 SwCursor::SwCursor( const SwPosition &rPos, SwPaM* pRing, bool bColumnSel )
128     : SwPaM( rPos, pRing ), pSavePos( 0 ), mnRowSpanOffset( 0 ), nCursorBidiLevel( 0 ),
129     mbColumnSelection( bColumnSel )
130 {
131 }
132 
133 // @@@ semantic: no copy ctor.
134 SwCursor::SwCursor( SwCursor& rCpy )
135     : SwPaM( rCpy ), pSavePos( 0 ), mnRowSpanOffset( rCpy.mnRowSpanOffset ),
136     nCursorBidiLevel( rCpy.nCursorBidiLevel ), mbColumnSelection( rCpy.mbColumnSelection )
137 {
138 }
139 
140 SwCursor::~SwCursor()
141 {
142     while( pSavePos )
143     {
144         _SwCursor_SavePos* pNxt = pSavePos->pNext;
145         delete pSavePos;
146         pSavePos = pNxt;
147     }
148 }
149 
150 SwCursor* SwCursor::Create( SwPaM* pRing ) const
151 {
152     return new SwCursor( *GetPoint(), pRing, false );
153 }
154 
155 bool SwCursor::IsReadOnlyAvailable() const
156 {
157     return false;
158 }
159 
160 sal_Bool SwCursor::IsSkipOverHiddenSections() const
161 {
162     return sal_True;
163 }
164 
165 sal_Bool SwCursor::IsSkipOverProtectSections() const
166 {
167     return !IsReadOnlyAvailable();
168 }
169 
170 
171 // Sicher die aktuelle Position, damit ggfs. auf diese zurueck
172 // gefallen werden kann. Die SavePos Objekte werden als Stack verwaltet,
173 // damit das auch alles bei verschachtelten Aufrufen funktioniert.
174 // Das CreateNewSavePos ist virtual, damit abgeleitete Klassen vom Cursor
175 // gegebenenfalls eigene SaveObjecte anlegen und in den virtuellen
176 // Check-Routinen verwenden koennen.
177 
178 void SwCursor::SaveState()
179 {
180     _SwCursor_SavePos* pNew = CreateNewSavePos();
181     pNew->pNext = pSavePos;
182     pSavePos = pNew;
183 }
184 
185 void SwCursor::RestoreState()
186 {
187     if( pSavePos ) // Robust
188     {
189         _SwCursor_SavePos* pDel = pSavePos;
190         pSavePos = pSavePos->pNext;
191         delete pDel;
192     }
193 }
194 
195 _SwCursor_SavePos* SwCursor::CreateNewSavePos() const
196 {
197     return new _SwCursor_SavePos( *this );
198 }
199 
200 // stelle fest, ob sich der Point ausserhalb des Content-Bereichs
201 // vom Nodes-Array befindet
202 sal_Bool SwCursor::IsNoCntnt() const
203 {
204     return GetPoint()->nNode.GetIndex() <
205             GetDoc()->GetNodes().GetEndOfExtras().GetIndex();
206 }
207 
208 bool SwCursor::IsSelOvrCheck(int)
209 {
210     return false;
211 }
212 
213 // extracted from IsSelOvr()
214 bool SwTableCursor::IsSelOvrCheck(int eFlags)
215 {
216     SwNodes& rNds = GetDoc()->GetNodes();
217     // check sections of nodes array
218     if( (nsSwCursorSelOverFlags::SELOVER_CHECKNODESSECTION & eFlags)
219         && HasMark() )
220     {
221         SwNodeIndex aOldPos( rNds, GetSavePos()->nNode );
222         if( !CheckNodesRange( aOldPos, GetPoint()->nNode, sal_True ))
223         {
224             GetPoint()->nNode = aOldPos;
225             GetPoint()->nContent.Assign( GetCntntNode(), GetSavePos()->nCntnt );
226             return true;
227         }
228     }
229     return SwCursor::IsSelOvrCheck(eFlags);
230 }
231 
232 sal_Bool SwCursor::IsSelOvr( int eFlags )
233 {
234     SwDoc* pDoc = GetDoc();
235     SwNodes& rNds = pDoc->GetNodes();
236 
237     sal_Bool bSkipOverHiddenSections = IsSkipOverHiddenSections();
238     sal_Bool bSkipOverProtectSections = IsSkipOverProtectSections();
239 
240     if ( IsSelOvrCheck( eFlags ) )
241     {
242         return sal_True;
243     }
244 
245 // neu: Bereiche ueberpruefen
246 // Anfang
247     if( pSavePos->nNode != GetPoint()->nNode.GetIndex() &&
248         //JP 28.10.97: Bug 45129 - im UI-ReadOnly ist alles erlaubt
249         ( !pDoc->GetDocShell() || !pDoc->GetDocShell()->IsReadOnlyUI() ))
250     {
251         // teste doch mal die neuen Sections:
252         SwNodeIndex& rPtIdx = GetPoint()->nNode;
253         const SwSectionNode* pSectNd = rPtIdx.GetNode().FindSectionNode();
254         if( pSectNd &&
255             ((bSkipOverHiddenSections && pSectNd->GetSection().IsHiddenFlag() ) ||
256              (bSkipOverProtectSections && pSectNd->GetSection().IsProtectFlag() )))
257         {
258             if( 0 == ( nsSwCursorSelOverFlags::SELOVER_CHANGEPOS & eFlags ) )
259             {
260                 // dann wars das schon
261                 RestoreSavePos();
262                 return sal_True;
263             }
264 
265             // dann setze den Cursor auf die neue Position:
266             SwNodeIndex aIdx( rPtIdx );
267             xub_StrLen nCntntPos = pSavePos->nCntnt;
268             int bGoNxt = pSavePos->nNode < rPtIdx.GetIndex();
269             SwCntntNode* pCNd = bGoNxt
270                     ? rNds.GoNextSection( &rPtIdx, bSkipOverHiddenSections, bSkipOverProtectSections)
271                     : rNds.GoPrevSection( &rPtIdx, bSkipOverHiddenSections, bSkipOverProtectSections);
272             if( !pCNd && ( nsSwCursorSelOverFlags::SELOVER_ENABLEREVDIREKTION & eFlags ))
273             {
274                 bGoNxt = !bGoNxt;
275                 pCNd = bGoNxt ? rNds.GoNextSection( &rPtIdx, bSkipOverHiddenSections, bSkipOverProtectSections)
276                               : rNds.GoPrevSection( &rPtIdx, bSkipOverHiddenSections, bSkipOverProtectSections);
277             }
278 
279             int bIsValidPos = 0 != pCNd;
280             sal_Bool bValidNodesRange = bIsValidPos &&
281                                     ::CheckNodesRange( rPtIdx, aIdx, sal_True );
282             if( !bValidNodesRange )
283             {
284                 rPtIdx = pSavePos->nNode;
285                 if( 0 == ( pCNd = rPtIdx.GetNode().GetCntntNode() ) )
286                 {
287                     bIsValidPos = sal_False;
288                     nCntntPos = 0;
289                     rPtIdx = aIdx;
290                     if( 0 == ( pCNd = rPtIdx.GetNode().GetCntntNode() ) )
291                     {
292                         // dann auf den Anfang vom Doc
293                         rPtIdx = rNds.GetEndOfExtras();
294                         pCNd = rNds.GoNext( &rPtIdx );
295                     }
296                 }
297             }
298 
299             // ContentIndex noch anmelden:
300             xub_StrLen nTmpPos = bIsValidPos ? (bGoNxt ? 0 : pCNd->Len()) : nCntntPos;
301             GetPoint()->nContent.Assign( pCNd, nTmpPos );
302             if( !bIsValidPos || !bValidNodesRange ||
303                 // sollten wir in einer Tabelle gelandet sein?
304                 IsInProtectTable( sal_True ) )
305                 return sal_True;
306         }
307 
308         // oder sollte eine geschuetzte Section innerhalb der Selektion liegen?
309         if( HasMark() && bSkipOverProtectSections)
310         {
311             sal_uLong nSttIdx = GetMark()->nNode.GetIndex(),
312                   nEndIdx = GetPoint()->nNode.GetIndex();
313             if( nEndIdx <= nSttIdx )
314             {
315                 sal_uLong nTmp = nSttIdx;
316                 nSttIdx = nEndIdx;
317                 nEndIdx = nTmp;
318             }
319 
320             const SwSectionFmts& rFmts = pDoc->GetSections();
321             for( sal_uInt16 n = 0; n < rFmts.Count(); ++n )
322             {
323                 const SwSectionFmt* pFmt = rFmts[n];
324                 const SvxProtectItem& rProtect = pFmt->GetProtect();
325                 if( rProtect.IsCntntProtected() )
326                 {
327                     const SwFmtCntnt& rCntnt = pFmt->GetCntnt(sal_False);
328                     ASSERT( rCntnt.GetCntntIdx(), "wo ist der SectionNode?" );
329                     sal_uLong nIdx = rCntnt.GetCntntIdx()->GetIndex();
330                     if( nSttIdx <= nIdx && nEndIdx >= nIdx )
331                     {
332                         // ist es keine gelinkte Section, dann kann sie auch
333                         // nicht mitselektiert werden
334                         const SwSection& rSect = *pFmt->GetSection();
335                         if( CONTENT_SECTION == rSect.GetType() )
336                         {
337                             RestoreSavePos();
338                             return sal_True;
339                         }
340                     }
341                 }
342             }
343         }
344 
345     }
346 // Ende
347 // neu: Bereiche ueberpruefen
348 
349     const SwNode* pNd = &GetPoint()->nNode.GetNode();
350     if( pNd->IsCntntNode() && !dynamic_cast<SwUnoCrsr*>(this) )
351     {
352         const SwCntntFrm* pFrm = ((SwCntntNode*)pNd)->getLayoutFrm( pDoc->GetCurrentLayout() );
353         if( pFrm && pFrm->IsValid() && 0 == pFrm->Frm().Height() &&
354             0 != ( nsSwCursorSelOverFlags::SELOVER_CHANGEPOS & eFlags ) )
355         {
356             // skip to the next / prev valid paragraph with a layout
357             SwNodeIndex& rPtIdx = GetPoint()->nNode;
358             int bGoNxt = pSavePos->nNode < rPtIdx.GetIndex();
359             while( 0 != ( pFrm = ( bGoNxt ? pFrm->GetNextCntntFrm()
360                                           : pFrm->GetPrevCntntFrm() )) &&
361                     0 == pFrm->Frm().Height() )
362                 ;
363 
364             // --> LIJIAN/FME 2007-11-27 #i72394# skip to prev /next valid paragraph
365             // with a layout in case the first search did not succeed:
366             if( !pFrm )
367             {
368                 bGoNxt = !bGoNxt;
369                 pFrm = ((SwCntntNode*)pNd)->getLayoutFrm( pDoc->GetCurrentLayout() );
370                 while ( pFrm && 0 == pFrm->Frm().Height() )
371                 {
372                     pFrm = bGoNxt ? pFrm->GetNextCntntFrm()
373                         :   pFrm->GetPrevCntntFrm();
374                 }
375             }
376             // <--
377 
378             SwCntntNode* pCNd;
379             if( pFrm && 0 != (pCNd = (SwCntntNode*)pFrm->GetNode()) )
380             {
381                 // set this cntntNode as new position
382                 rPtIdx = *pCNd;
383                 pNd = pCNd;
384 
385                 // ContentIndex noch anmelden:
386                 xub_StrLen nTmpPos = bGoNxt ? 0 : pCNd->Len();
387                 GetPoint()->nContent.Assign( pCNd, nTmpPos );
388 
389                     // sollten wir in einer Tabelle gelandet sein?
390                 if( IsInProtectTable( sal_True ) )
391                     pFrm = 0;
392             }
393         }
394 
395         if( !pFrm )
396         {
397             DeleteMark();
398             RestoreSavePos();
399             return sal_True;        // ohne Frames geht gar nichts!
400         }
401     }
402 
403     // darf der Cursor in geschuetzen "Nodes" stehen?
404     if( 0 == ( nsSwCursorSelOverFlags::SELOVER_CHANGEPOS & eFlags ) && !IsAtValidPos() )
405     {
406         DeleteMark();
407         RestoreSavePos();
408         return sal_True;
409     }
410 
411     if( !HasMark() )
412         return sal_False;
413 
414     //JP 19.08.98: teste mal auf ungueltige Selektion - sprich ueber
415     //              GrundSections:
416     if( !::CheckNodesRange( GetMark()->nNode, GetPoint()->nNode, sal_True ))
417     {
418         DeleteMark();
419         RestoreSavePos();
420         return sal_True;        // ohne Frames geht gar nichts!
421     }
422 
423     const SwTableNode* pPtNd = pNd->FindTableNode();
424 
425     if( (pNd = &GetMark()->nNode.GetNode())->IsCntntNode() &&
426         !((SwCntntNode*)pNd)->getLayoutFrm( pDoc->GetCurrentLayout() ) && !dynamic_cast<SwUnoCrsr*>(this) )
427     {
428         DeleteMark();
429         RestoreSavePos();
430         return sal_True;        // ohne Frames geht gar nichts!
431     }
432 
433     const SwTableNode* pMrkNd = pNd->FindTableNode();
434 
435     // beide in keinem oder beide im gleichen TableNode
436     if( ( !pMrkNd && !pPtNd ) || pPtNd == pMrkNd )
437         return sal_False;
438 
439     // in unterschiedlichen Tabellen oder nur Mark in der Tabelle
440     if( ( pPtNd && pMrkNd ) || pMrkNd )
441     {                       // dann lasse das nicht zu, alte Pos zurueck
442         RestoreSavePos();
443         // Crsr bleibt an der alten Position
444         return sal_True;
445     }
446 
447     // ACHTUNG: dieses kann nicht im TableMode geschehen !!
448     if( pPtNd )     // nur Point in Tabelle, dann gehe hinter/vor diese
449     {
450         if( nsSwCursorSelOverFlags::SELOVER_CHANGEPOS & eFlags )
451         {
452             sal_Bool bSelTop = GetPoint()->nNode.GetIndex() <
453                     (( nsSwCursorSelOverFlags::SELOVER_TOGGLE & eFlags ) ? pSavePos->nNode
454                                                  : GetMark()->nNode.GetIndex());
455 
456             do {
457                 // in Schleife fuer Tabelle hinter Tabelle
458                 sal_uLong nSEIdx = pPtNd->EndOfSectionIndex();
459                 sal_uLong nSttEndTbl = nSEIdx + 1; // dflt. Sel. nach unten
460 
461                 if( bSelTop )                               // Sel. nach oben
462                     nSttEndTbl = rNds[ nSEIdx ]->StartOfSectionIndex() - 1;
463 
464                 GetPoint()->nNode = nSttEndTbl;
465                 const SwNode* pMyNd = GetNode();
466 
467                 if( pMyNd->IsSectionNode() || ( pMyNd->IsEndNode() &&
468                     pMyNd->StartOfSectionNode()->IsSectionNode() ) )
469                 {
470                     // die lassen wir zu:
471                     pMyNd = bSelTop
472                         ? rNds.GoPrevSection( &GetPoint()->nNode,sal_True,sal_False )
473                         : rNds.GoNextSection( &GetPoint()->nNode,sal_True,sal_False );
474 
475                     /* #i12312# Handle failure of Go{Prev|Next}Section */
476                     if ( 0 == pMyNd)
477                         break;
478 
479                     if( 0 != ( pPtNd = pMyNd->FindTableNode() ))
480                         continue;
481                 }
482 
483                 if( pMyNd->IsCntntNode() &&      // ist es ein ContentNode ??
484                     ::CheckNodesRange( GetMark()->nNode,
485                                        GetPoint()->nNode, sal_True ))
486                 {
487                     // TABLE IN TABLE
488                     const SwTableNode* pOuterTableNd = pMyNd->FindTableNode();
489                     if ( pOuterTableNd )
490                         pMyNd = pOuterTableNd;
491                     else
492                     {
493                         SwCntntNode* pCNd = (SwCntntNode*)pMyNd;
494                         xub_StrLen nTmpPos = bSelTop ? pCNd->Len() : 0;
495                         GetPoint()->nContent.Assign( pCNd, nTmpPos );
496                         return sal_False;
497                     }
498                 }
499                 if( bSelTop
500                     ? ( !pMyNd->IsEndNode() || 0 == ( pPtNd = pMyNd->FindTableNode() ))
501                     : 0 == ( pPtNd = pMyNd->GetTableNode() ))
502                     break;
503             } while( sal_True );
504         }
505 
506         // dann verbleibe auf der alten Position
507         RestoreSavePos();
508         return sal_True;        // Crsr bleibt an der alten Position
509     }
510     return sal_False;       // was bleibt noch ??
511 }
512 
513 #if defined( UNX )
514 #define IDX     (*pCellStt)
515 #else
516 #define IDX     aCellStt
517 #endif
518 
519 
520 sal_Bool SwCursor::IsInProtectTable( sal_Bool bMove, sal_Bool bChgCrsr )
521 {
522     SwCntntNode* pCNd = GetCntntNode();
523     if( !pCNd )
524         return sal_False;
525 
526     // No table, no protected cell:
527     const SwTableNode* pTableNode = pCNd->FindTableNode();
528     if ( !pTableNode )
529         return sal_False;
530 
531     // Current position == last save position?
532     if ( pSavePos->nNode == GetPoint()->nNode.GetIndex() )
533         return sal_False;
534 
535     // Check for convered cell:
536     bool bInCoveredCell = false;
537     const SwStartNode* pTmpSttNode = pCNd->FindTableBoxStartNode();
538     ASSERT( pTmpSttNode, "In table, therefore I expect to get a SwTableBoxStartNode" )
539     const SwTableBox* pBox = pTmpSttNode ? pTableNode->GetTable().GetTblBox( pTmpSttNode->GetIndex() ) : 0; //Robust #151355
540     if ( pBox && pBox->getRowSpan() < 1 ) // Robust #151270
541         bInCoveredCell = true;
542 
543     // Positions of covered cells are not acceptable:
544     if ( !bInCoveredCell )
545     {
546         // Position not protected?
547         if ( !pCNd->IsProtect() )
548             return sal_False;
549 
550         // Cursor in protected cells allowed?
551         if ( IsReadOnlyAvailable() )
552             return sal_False;
553     }
554 
555     // If we reach this point, we are in a protected or covered table cell!
556 
557     if( !bMove )
558     {
559         if( bChgCrsr )
560             // restore the last save position
561             RestoreSavePos();
562         return sal_True;        // Crsr bleibt an der alten Position
563     }
564 
565     // wir stehen in einer geschuetzten TabellenZelle
566     // von Oben nach Unten Traveln ?
567     if( pSavePos->nNode < GetPoint()->nNode.GetIndex() )
568     {
569         // suche die naechste "gueltige" Box
570 
571         // folgt nach dem EndNode der Zelle ein weiterer StartNode, dann
572         // gibt es auch eine naechste Zelle
573 #if defined( UNX )
574         SwNodeIndex* pCellStt = new SwNodeIndex( *GetNode()->
575                         FindTableBoxStartNode()->EndOfSectionNode(), 1 );
576 #else
577         SwNodeIndex aCellStt( *GetNode()->FindTableBoxStartNode()->EndOfSectionNode(), 1 );
578 #endif
579         sal_Bool bProt = sal_True;
580 GoNextCell:
581         do {
582             if( !IDX.GetNode().IsStartNode() )
583                 break;
584             IDX++;
585             if( 0 == ( pCNd = IDX.GetNode().GetCntntNode() ))
586                 pCNd = IDX.GetNodes().GoNext( &IDX );
587             if( 0 == ( bProt = pCNd->IsProtect() ))
588                 break;
589             IDX.Assign( *pCNd->FindTableBoxStartNode()->EndOfSectionNode(), 1 );
590         } while( bProt );
591 
592 SetNextCrsr:
593         if( !bProt )        // eine freie Zelle gefunden
594         {
595             GetPoint()->nNode = IDX;
596 #if defined( UNX )
597             delete pCellStt;
598 #endif
599             SwCntntNode* pTmpCNd = GetCntntNode();
600             if( pTmpCNd )
601             {
602                 GetPoint()->nContent.Assign( pTmpCNd, 0 );
603                 return sal_False;
604             }
605             return IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
606                              nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
607         }
608         // am Ende der Tabelle, also setze hinter diese
609         IDX++;     // auf den naechsten Node
610         SwNode* pNd;
611         if( ( pNd = &IDX.GetNode())->IsEndNode() || HasMark())
612         {
613             // Tabelle allein in einem FlyFrame oder SSelection,
614             // dann verbleibe auf der alten Position
615             if( bChgCrsr )
616                 RestoreSavePos();
617 #if defined( UNX )
618             delete pCellStt;
619 #endif
620             return sal_True;        // Crsr bleibt an der alten Position
621         }
622         else if( pNd->IsTableNode() && IDX++ )
623             goto GoNextCell;
624 
625         bProt = sal_False;      // Index steht jetzt auf einem ContentNode
626         goto SetNextCrsr;
627     }
628 
629     // suche die vorherige "gueltige" Box
630     {
631         // liegt vor dem StartNode der Zelle ein weiterer EndNode, dann
632         // gibt es auch eine vorherige Zelle
633 #if defined( UNX )
634         SwNodeIndex* pCellStt = new SwNodeIndex(
635                     *GetNode()->FindTableBoxStartNode(), -1 );
636 #else
637         SwNodeIndex aCellStt( *GetNode()->FindTableBoxStartNode(), -1 );
638 #endif
639         SwNode* pNd;
640         sal_Bool bProt = sal_True;
641 GoPrevCell:
642         do {
643             if( !( pNd = &IDX.GetNode())->IsEndNode() )
644                 break;
645             IDX.Assign( *pNd->StartOfSectionNode(), +1 );
646             if( 0 == ( pCNd = IDX.GetNode().GetCntntNode() ))
647                 pCNd = pNd->GetNodes().GoNext( &IDX );
648             if( 0 == ( bProt = pCNd->IsProtect() ))
649                 break;
650             IDX.Assign( *pNd->FindTableBoxStartNode(), -1 );
651         } while( bProt );
652 
653 SetPrevCrsr:
654         if( !bProt )        // eine freie Zelle gefunden
655         {
656             GetPoint()->nNode = IDX;
657 #if defined( UNX )
658             delete pCellStt;
659 #endif
660             SwCntntNode* pTmpCNd = GetCntntNode();
661             if( pTmpCNd )
662             {
663                 GetPoint()->nContent.Assign( pTmpCNd, 0 );
664                 return sal_False;
665             }
666             return IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
667                              nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
668         }
669         // am Start der Tabelle, also setze vor diese
670         IDX--;     // auf den naechsten Node
671         if( ( pNd = &IDX.GetNode())->IsStartNode() || HasMark() )
672         {
673             // Tabelle allein in einem FlyFrame oder Selektion,
674             // dann verbleibe auf der alten Position
675             if( bChgCrsr )
676                 RestoreSavePos();
677 #if defined( UNX )
678             delete pCellStt;
679 #endif
680             return sal_True;        // Crsr bleibt an der alten Position
681         }
682         else if( pNd->StartOfSectionNode()->IsTableNode() && IDX-- )
683             goto GoPrevCell;
684 
685         bProt = sal_False;      // Index steht jetzt auf einem ContentNode
686         goto SetPrevCrsr;
687     }
688 }
689 
690 // sal_True: an die Position kann der Cursor gesetzt werden
691 sal_Bool SwCursor::IsAtValidPos( sal_Bool bPoint ) const
692 {
693     const SwDoc* pDoc = GetDoc();
694     const SwPosition* pPos = bPoint ? GetPoint() : GetMark();
695     const SwNode* pNd = &pPos->nNode.GetNode();
696 
697     if( pNd->IsCntntNode() && !((SwCntntNode*)pNd)->getLayoutFrm( pDoc->GetCurrentLayout() ) &&
698         !dynamic_cast<const SwUnoCrsr*>(this) )
699     {
700         return sal_False;
701     }
702 
703         //JP 28.10.97: Bug 45129 - im UI-ReadOnly ist alles erlaubt
704     if( !pDoc->GetDocShell() || !pDoc->GetDocShell()->IsReadOnlyUI() )
705         return sal_True;
706 
707     sal_Bool bCrsrInReadOnly = IsReadOnlyAvailable();
708     if( !bCrsrInReadOnly && pNd->IsProtect() )
709         return sal_False;
710 
711     const SwSectionNode* pSectNd = pNd->FindSectionNode();
712     if( pSectNd && (pSectNd->GetSection().IsHiddenFlag() ||
713                     ( !bCrsrInReadOnly && pSectNd->GetSection().IsProtectFlag() )))
714         return sal_False;
715 
716     return sal_True;
717 }
718 
719 void SwCursor::SaveTblBoxCntnt( const SwPosition* ) {}
720 
721 // setze den SRange fuer das Suchen im Dokument
722 SwMoveFnCollection* SwCursor::MakeFindRange( SwDocPositions nStart,
723                                 SwDocPositions nEnd, SwPaM* pRange ) const
724 {
725     pRange->SetMark();
726     FillFindPos( nStart, *pRange->GetMark() );
727     FillFindPos( nEnd, *pRange->GetPoint() );
728 
729     // bestimme die Richtung, in der zu suchen ist
730     // ( GetPoint > GetMark -> vorwaerts, sonst rueckwaerts )
731     return ( DOCPOS_START == nStart || DOCPOS_OTHERSTART == nStart ||
732               (DOCPOS_CURR == nStart &&
733                 (DOCPOS_END == nEnd || DOCPOS_OTHEREND == nEnd ) ))
734                 ? fnMoveForward : fnMoveBackward;
735 }
736 
737 
738 sal_uLong lcl_FindSelection( SwFindParas& rParas, SwCursor* pCurCrsr,
739                         SwMoveFn fnMove, SwCursor*& pFndRing,
740                         SwPaM& aRegion, FindRanges eFndRngs,
741                         sal_Bool bInReadOnly, sal_Bool& bCancel )
742 {
743     SwDoc* pDoc = pCurCrsr->GetDoc();
744     bool const bDoesUndo = pDoc->GetIDocumentUndoRedo().DoesUndo();
745     int nFndRet = 0;
746     sal_uLong nFound = 0;
747     int bSrchBkwrd = fnMove == fnMoveBackward, bEnde = sal_False;
748     SwPaM *pTmpCrsr = pCurCrsr, *pSaveCrsr = pCurCrsr;
749 
750     // only create progress-bar for ShellCrsr
751     bool bIsUnoCrsr = 0 != dynamic_cast<SwUnoCrsr*>(pCurCrsr);
752     _PercentHdl* pPHdl = 0;
753     sal_uInt16 nCrsrCnt = 0;
754     if( FND_IN_SEL & eFndRngs )
755     {
756         while( pCurCrsr != ( pTmpCrsr = (SwPaM*)pTmpCrsr->GetNext() ))
757             ++nCrsrCnt;
758         if( nCrsrCnt && !bIsUnoCrsr )
759             pPHdl = new _PercentHdl( 0, nCrsrCnt, pDoc->GetDocShell() );
760     }
761     else
762         pSaveCrsr = (SwPaM*)pSaveCrsr->GetPrev();
763 
764     do {
765         aRegion.SetMark();
766         // egal in welche Richtung, SPoint ist immer groesser als Mark,
767         // wenn der Suchbereich gueltig ist !!
768         SwPosition *pSttPos = aRegion.GetMark(),
769                         *pEndPos = aRegion.GetPoint();
770         *pSttPos = *pTmpCrsr->Start();
771         *pEndPos = *pTmpCrsr->End();
772         if( bSrchBkwrd )
773             aRegion.Exchange();
774 
775         if( !nCrsrCnt && !pPHdl && !bIsUnoCrsr )
776             pPHdl = new _PercentHdl( aRegion );
777 
778         // solange gefunden und nicht auf gleicher Position haengen bleibt
779         while(  *pSttPos <= *pEndPos &&
780                 0 != ( nFndRet = rParas.Find( pCurCrsr, fnMove,
781                                             &aRegion, bInReadOnly )) &&
782                 ( !pFndRing ||
783                     *pFndRing->GetPoint() != *pCurCrsr->GetPoint() ||
784                     *pFndRing->GetMark() != *pCurCrsr->GetMark() ))
785         {
786             if( !( FIND_NO_RING & nFndRet ))
787             {
788                 // Bug 24084: Ring richtig herum aufbauen -> gleiche Mimik
789                 //            wie beim CreateCrsr !!!!
790 
791                 SwCursor* pNew = pCurCrsr->Create( pFndRing );
792                 if( !pFndRing )
793                     pFndRing = pNew;
794 
795                 pNew->SetMark();
796                 *pNew->GetMark() = *pCurCrsr->GetMark();
797             }
798 
799             ++nFound;
800 
801             if( !( eFndRngs & FND_IN_SELALL) )
802             {
803                 bEnde = sal_True;
804                 break;
805             }
806 
807             if ((coSrchRplcThreshold == nFound)
808                 && pDoc->GetIDocumentUndoRedo().DoesUndo()
809                 && rParas.IsReplaceMode())
810             {
811                 short nRet = pCurCrsr->MaxReplaceArived();
812                 if( RET_YES == nRet )
813                 {
814                     pDoc->GetIDocumentUndoRedo().DelAllUndoObj();
815                     pDoc->GetIDocumentUndoRedo().DoUndo(false);
816                 }
817                 else
818                 {
819                     bEnde = sal_True;
820                     if(RET_CANCEL == nRet)
821                     {
822                         bCancel = sal_True;
823                         //unwind() ??
824                     }
825                     break;
826                 }
827             }
828 
829             if( bSrchBkwrd )
830                 // bewege pEndPos vor den gefundenen Bereich
831                 *pEndPos = *pCurCrsr->Start();
832             else
833                 // bewege pSttPos hinter den gefundenen Bereich
834                 *pSttPos = *pCurCrsr->End();
835 
836             if( *pSttPos == *pEndPos )      // im Bereich, aber am Ende
837                 break;                      // fertig
838 
839             if( !nCrsrCnt && pPHdl )
840             {
841                 pPHdl->NextPos( *aRegion.GetMark() );
842             }
843         }
844 
845         if( bEnde || !( eFndRngs & ( FND_IN_SELALL | FND_IN_SEL )) )
846             break;
847 
848         pTmpCrsr = ((SwPaM*)pTmpCrsr->GetNext());
849         if( nCrsrCnt && pPHdl )
850         {
851             pPHdl->NextPos( ++pPHdl->nActPos );
852         }
853 
854     } while( pTmpCrsr != pSaveCrsr );
855 
856     if( nFound && !pFndRing )       // falls kein Ring aufgebaut werden soll
857         pFndRing = pCurCrsr->Create();
858 
859     delete pPHdl;
860     pDoc->GetIDocumentUndoRedo().DoUndo(bDoesUndo);
861     return nFound;
862 }
863 
864 
865 int lcl_MakeSelFwrd( const SwNode& rSttNd, const SwNode& rEndNd,
866                         SwPaM& rPam, int bFirst )
867 {
868     if( rSttNd.GetIndex() + 1 == rEndNd.GetIndex() )
869         return sal_False;
870 
871     SwNodes& rNds = rPam.GetDoc()->GetNodes();
872     rPam.DeleteMark();
873     SwCntntNode* pCNd;
874     if( !bFirst )
875     {
876         rPam.GetPoint()->nNode = rSttNd;
877         pCNd = rNds.GoNext( &rPam.GetPoint()->nNode );
878         if( !pCNd )
879             return sal_False;
880         pCNd->MakeStartIndex( &rPam.GetPoint()->nContent );
881     }
882     else if( rSttNd.GetIndex() > rPam.GetPoint()->nNode.GetIndex() ||
883              rPam.GetPoint()->nNode.GetIndex() >= rEndNd.GetIndex() )
884         return sal_False;       // steht nicht in dieser Section
885 
886     rPam.SetMark();
887     rPam.GetPoint()->nNode = rEndNd;
888     pCNd = rNds.GoPrevious( &rPam.GetPoint()->nNode );
889     if( !pCNd )
890         return sal_False;
891     pCNd->MakeEndIndex( &rPam.GetPoint()->nContent );
892 
893     return *rPam.GetMark() < *rPam.GetPoint();
894 }
895 
896 
897 int lcl_MakeSelBkwrd( const SwNode& rSttNd, const SwNode& rEndNd,
898                         SwPaM& rPam, int bFirst )
899 {
900     if( rEndNd.GetIndex() + 1 == rSttNd.GetIndex() )
901         return sal_False;
902 
903     SwNodes& rNds = rPam.GetDoc()->GetNodes();
904     rPam.DeleteMark();
905     SwCntntNode* pCNd;
906     if( !bFirst )
907     {
908         rPam.GetPoint()->nNode = rSttNd;
909         pCNd = rNds.GoPrevious( &rPam.GetPoint()->nNode );
910         if( !pCNd )
911             return sal_False;
912         pCNd->MakeEndIndex( &rPam.GetPoint()->nContent );
913     }
914     else if( rEndNd.GetIndex() > rPam.GetPoint()->nNode.GetIndex() ||
915              rPam.GetPoint()->nNode.GetIndex() >= rSttNd.GetIndex() )
916         return sal_False;       // steht nicht in dieser Section
917 
918     rPam.SetMark();
919     rPam.GetPoint()->nNode = rEndNd;
920     pCNd = rNds.GoNext( &rPam.GetPoint()->nNode );
921     if( !pCNd )
922         return sal_False;
923     pCNd->MakeStartIndex( &rPam.GetPoint()->nContent );
924 
925     return *rPam.GetPoint() < *rPam.GetMark();
926 }
927 
928 
929 // diese Methode "sucht" fuer alle Anwendungsfaelle, denn in SwFindParas
930 // steht immer die richtigen Parameter und die entsprechende Find-Methode
931 
932 sal_uLong SwCursor::FindAll( SwFindParas& rParas,
933                             SwDocPositions nStart, SwDocPositions nEnde,
934                             FindRanges eFndRngs, sal_Bool& bCancel )
935 {
936     bCancel = sal_False;
937     SwCrsrSaveState aSaveState( *this );
938 
939     // Region erzeugen, ohne das diese in den Ring aufgenommen wird !
940     SwPaM aRegion( *GetPoint() );
941     SwMoveFn fnMove = MakeFindRange( nStart, nEnde, &aRegion );
942 
943     sal_uLong nFound = 0;
944     int bMvBkwrd = fnMove == fnMoveBackward;
945     sal_Bool bInReadOnly = IsReadOnlyAvailable();
946 
947     SwCursor* pFndRing = 0;
948     SwNodes& rNds = GetDoc()->GetNodes();
949 
950     // suche in Bereichen ?
951     if( FND_IN_SEL & eFndRngs )
952     {
953         // String nicht im Bereich gefunden, dann erhalte alle Bereiche,
954         // der Cursor beleibt unveraendert
955         if( 0 == ( nFound = lcl_FindSelection( rParas, this, fnMove,
956                                                 pFndRing, aRegion, eFndRngs,
957                                                 bInReadOnly, bCancel ) ))
958             return nFound;
959 
960         // der String wurde ein- bis mehrmals gefunden. Das steht alles
961         // im neuen Crsr-Ring. Darum hebe erstmal den alten Ring auf
962         while( GetNext() != this )
963             delete GetNext();
964 
965         *GetPoint() = *pFndRing->GetPoint();
966         SetMark();
967         *GetMark() = *pFndRing->GetMark();
968         pFndRing->MoveRingTo( this );
969         delete pFndRing;
970     }
971     else if( FND_IN_OTHER & eFndRngs )
972     {
973         // Cursor als Kopie vom akt. und in den Ring aufnehmen
974         // Verkettung zeigt immer auf den zuerst erzeugten, also vorwaerts
975         std::auto_ptr< SwCursor > pSav( Create( this ) );   // save the current cursor
976 
977         // wenn schon ausserhalb vom Bodytext, suche von der Position,
978         // ansonsten beginne mit der 1. GrundSection
979         if( bMvBkwrd
980             ? lcl_MakeSelBkwrd( rNds.GetEndOfExtras(),
981                     *rNds.GetEndOfPostIts().StartOfSectionNode(),
982                      *this, rNds.GetEndOfExtras().GetIndex() >=
983                     GetPoint()->nNode.GetIndex() )
984             : lcl_MakeSelFwrd( *rNds.GetEndOfPostIts().StartOfSectionNode(),
985                     rNds.GetEndOfExtras(), *this,
986                     rNds.GetEndOfExtras().GetIndex() >=
987                     GetPoint()->nNode.GetIndex() ))
988         {
989             nFound = lcl_FindSelection( rParas, this, fnMove, pFndRing,
990                                         aRegion, eFndRngs, bInReadOnly, bCancel );
991         }
992 
993         if( !nFound )
994         {
995             // den alten wieder zurueck
996             *GetPoint() = *pSav->GetPoint();
997             if( pSav->HasMark() )
998             {
999                 SetMark();
1000                 *GetMark() = *pSav->GetMark();
1001             }
1002             else
1003                 DeleteMark();
1004             return 0;
1005         }
1006         pSav.release();
1007 
1008         if( !( FND_IN_SELALL & eFndRngs ))
1009         {
1010             // es sollte nur einer gesucht werden, also fuege in dazu
1011             // egal in welche Richtung, SPoint ist immer groesser als Mark,
1012             // wenn der Suchbereich gueltig ist !!
1013             *GetPoint() = *pFndRing->GetPoint();
1014             SetMark();
1015             *GetMark() = *pFndRing->GetMark();
1016         }
1017         else
1018         {
1019             // es  wurde ein- bis mehrmals gefunden. Das steht alles
1020             // im neuen Crsr-Ring. Darum hebe erstmal den alten Ring auf
1021             while( GetNext() != this )
1022                 delete GetNext();
1023 
1024             *GetPoint() = *pFndRing->GetPoint();
1025             SetMark();
1026             *GetMark() = *pFndRing->GetMark();
1027             pFndRing->MoveRingTo( this );
1028         }
1029         delete pFndRing;
1030     }
1031     else if( FND_IN_SELALL & eFndRngs )
1032     {
1033         ::std::auto_ptr< SwCursor> pSav( Create( this ) );  // save the current cursor
1034 
1035         const SwNode* pSttNd = ( FND_IN_BODYONLY & eFndRngs )
1036                             ? rNds.GetEndOfContent().StartOfSectionNode()
1037                             : rNds.GetEndOfPostIts().StartOfSectionNode();
1038 
1039         if( bMvBkwrd
1040             ? lcl_MakeSelBkwrd( rNds.GetEndOfContent(), *pSttNd,*this, sal_False )
1041             : lcl_MakeSelFwrd( *pSttNd, rNds.GetEndOfContent(), *this, sal_False ))
1042         {
1043             nFound = lcl_FindSelection( rParas, this, fnMove, pFndRing,
1044                                         aRegion, eFndRngs, bInReadOnly, bCancel );
1045         }
1046 
1047         if( !nFound )
1048         {
1049             // den alten wieder zurueck
1050             *GetPoint() = *pSav->GetPoint();
1051             if( pSav->HasMark() )
1052             {
1053                 SetMark();
1054                 *GetMark() = *pSav->GetMark();
1055             }
1056             else
1057                 DeleteMark();
1058             return 0;
1059         }
1060         pSav.release();
1061         while( GetNext() != this )
1062             delete GetNext();
1063 
1064         *GetPoint() = *pFndRing->GetPoint();
1065         SetMark();
1066         *GetMark() = *pFndRing->GetMark();
1067         pFndRing->MoveRingTo( this );
1068         delete pFndRing;
1069     }
1070     else
1071     {
1072         // ist ein GetMark gesetzt, dann wird bei gefundenem Object
1073         // der GetMark beibehalten !! Dadurch kann ein Bereich mit der Suche
1074         // aufgespannt werden.
1075         SwPosition aMarkPos( *GetMark() );
1076         int bMarkPos = HasMark() && !eFndRngs;
1077 
1078         if( 0 != (nFound = rParas.Find( this, fnMove,
1079                                         &aRegion, bInReadOnly ) ? 1 : 0)
1080             && bMarkPos )
1081             *GetMark() = aMarkPos;
1082     }
1083 
1084     if( nFound && SwCursor::IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE ) )
1085         nFound = 0;
1086     return nFound;
1087 }
1088 
1089 
1090 void SwCursor::FillFindPos( SwDocPositions ePos, SwPosition& rPos ) const
1091 {
1092     sal_Bool bIsStart = sal_True;
1093     SwCntntNode* pCNd = 0;
1094     SwNodes& rNds = GetDoc()->GetNodes();
1095 
1096     switch( ePos )
1097     {
1098     case DOCPOS_START:
1099         rPos.nNode = *rNds.GetEndOfContent().StartOfSectionNode();
1100         pCNd = rNds.GoNext( &rPos.nNode );
1101         break;
1102 
1103     case DOCPOS_END:
1104         rPos.nNode = rNds.GetEndOfContent();
1105         pCNd = rNds.GoPrevious( &rPos.nNode );
1106         bIsStart = sal_False;
1107         break;
1108 
1109     case DOCPOS_OTHERSTART:
1110         rPos.nNode = *rNds[ sal_uLong(0) ];
1111         pCNd = rNds.GoNext( &rPos.nNode );
1112         break;
1113 
1114     case DOCPOS_OTHEREND:
1115         rPos.nNode = *rNds.GetEndOfContent().StartOfSectionNode();
1116         pCNd = rNds.GoPrevious( &rPos.nNode );
1117         bIsStart = sal_False;
1118         break;
1119 
1120 //  case DOCPOS_CURR:
1121     default:
1122         rPos = *GetPoint();
1123     }
1124 
1125     if( pCNd )
1126     {
1127         xub_StrLen nCPos = 0;
1128         if( !bIsStart )
1129             nCPos = pCNd->Len();
1130         rPos.nContent.Assign( pCNd, nCPos );
1131     }
1132 }
1133 
1134 short SwCursor::MaxReplaceArived()
1135 {
1136     return RET_YES;
1137 }
1138 
1139 
1140 sal_Bool SwCursor::IsStartWord( sal_Int16 nWordType ) const
1141 {
1142     return IsStartWordWT( nWordType );
1143 }
1144 
1145 sal_Bool SwCursor::IsEndWord( sal_Int16 nWordType ) const
1146 {
1147     return IsEndWordWT( nWordType );
1148 }
1149 
1150 sal_Bool SwCursor::IsInWord( sal_Int16 nWordType ) const
1151 {
1152     return IsInWordWT( nWordType );
1153 }
1154 
1155 sal_Bool SwCursor::GoStartWord()
1156 {
1157     return GoStartWordWT( WordType::ANYWORD_IGNOREWHITESPACES );
1158 }
1159 
1160 sal_Bool SwCursor::GoEndWord()
1161 {
1162     return GoEndWordWT( WordType::ANYWORD_IGNOREWHITESPACES );
1163 }
1164 
1165 sal_Bool SwCursor::GoNextWord()
1166 {
1167     return GoNextWordWT( WordType::ANYWORD_IGNOREWHITESPACES );
1168 }
1169 
1170 sal_Bool SwCursor::GoPrevWord()
1171 {
1172     return GoPrevWordWT( WordType::ANYWORD_IGNOREWHITESPACES );
1173 }
1174 
1175 sal_Bool SwCursor::SelectWord( ViewShell* pViewShell, const Point* pPt )
1176 {
1177     return SelectWordWT( pViewShell, WordType::ANYWORD_IGNOREWHITESPACES, pPt );
1178 }
1179 
1180 sal_Bool SwCursor::IsStartWordWT( sal_Int16 nWordType ) const
1181 {
1182     sal_Bool bRet = sal_False;
1183     const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
1184     if( pTxtNd && pBreakIt->GetBreakIter().is() )
1185     {
1186         xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
1187         bRet = pBreakIt->GetBreakIter()->isBeginWord(
1188                             pTxtNd->GetTxt(), nPtPos,
1189                             pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos )),
1190                             nWordType );
1191     }
1192     return bRet;
1193 }
1194 
1195 sal_Bool SwCursor::IsEndWordWT( sal_Int16 nWordType ) const
1196 {
1197     sal_Bool bRet = sal_False;
1198     const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
1199     if( pTxtNd && pBreakIt->GetBreakIter().is() )
1200     {
1201         xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
1202         bRet = pBreakIt->GetBreakIter()->isEndWord(
1203                             pTxtNd->GetTxt(), nPtPos,
1204                             pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos ) ),
1205                             nWordType );
1206 
1207     }
1208     return bRet;
1209 }
1210 
1211 sal_Bool SwCursor::IsInWordWT( sal_Int16 nWordType ) const
1212 {
1213     sal_Bool bRet = sal_False;
1214     const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
1215     if( pTxtNd && pBreakIt->GetBreakIter().is() )
1216     {
1217         xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
1218         Boundary aBoundary = pBreakIt->GetBreakIter()->getWordBoundary(
1219                             pTxtNd->GetTxt(), nPtPos,
1220                             pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos ) ),
1221                             nWordType,
1222                             sal_True );
1223 
1224         bRet = aBoundary.startPos != aBoundary.endPos &&
1225                 aBoundary.startPos <= nPtPos &&
1226                     nPtPos <= aBoundary.endPos;
1227         if(bRet)
1228         {
1229             const CharClass& rCC = GetAppCharClass();
1230             bRet = rCC.isLetterNumeric( pTxtNd->GetTxt(), static_cast<xub_StrLen>(aBoundary.startPos) );
1231         }
1232     }
1233     return bRet;
1234 }
1235 
1236 sal_Bool SwCursor::IsStartEndSentence( bool bEnd ) const
1237 {
1238     sal_Bool bRet = bEnd ?
1239                     GetCntntNode() && GetPoint()->nContent == GetCntntNode()->Len() :
1240                     GetPoint()->nContent.GetIndex() == 0;
1241 
1242     if( !bRet )
1243     {
1244         SwCursor aCrsr(*GetPoint(), 0, false);
1245         SwPosition aOrigPos = *aCrsr.GetPoint();
1246         aCrsr.GoSentence( bEnd ? SwCursor::END_SENT : SwCursor::START_SENT );
1247         bRet = aOrigPos == *aCrsr.GetPoint();
1248     }
1249 
1250     return bRet;
1251 }
1252 
1253 sal_Bool SwCursor::GoStartWordWT( sal_Int16 nWordType )
1254 {
1255     sal_Bool bRet = sal_False;
1256     const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
1257     if( pTxtNd && pBreakIt->GetBreakIter().is() )
1258     {
1259         SwCrsrSaveState aSave( *this );
1260         xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
1261         nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->getWordBoundary(
1262                             pTxtNd->GetTxt(), nPtPos,
1263                             pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos ) ),
1264                             nWordType,
1265                             sal_False ).startPos;
1266 
1267         if( nPtPos < pTxtNd->GetTxt().Len() )
1268         {
1269             GetPoint()->nContent = nPtPos;
1270             if( !IsSelOvr() )
1271                 bRet = sal_True;
1272         }
1273     }
1274     return bRet;
1275 }
1276 
1277 sal_Bool SwCursor::GoEndWordWT( sal_Int16 nWordType )
1278 {
1279     sal_Bool bRet = sal_False;
1280     const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
1281     if( pTxtNd && pBreakIt->GetBreakIter().is() )
1282     {
1283         SwCrsrSaveState aSave( *this );
1284         xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
1285         nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->getWordBoundary(
1286                             pTxtNd->GetTxt(), nPtPos,
1287                             pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos ) ),
1288                             nWordType,
1289                             sal_True ).endPos;
1290 
1291         if( nPtPos <= pTxtNd->GetTxt().Len() &&
1292             GetPoint()->nContent.GetIndex() != nPtPos )
1293         {
1294             GetPoint()->nContent = nPtPos;
1295             if( !IsSelOvr() )
1296                 bRet = sal_True;
1297         }
1298     }
1299     return bRet;
1300 }
1301 
1302 sal_Bool SwCursor::GoNextWordWT( sal_Int16 nWordType )
1303 {
1304     sal_Bool bRet = sal_False;
1305     const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
1306     if( pTxtNd && pBreakIt->GetBreakIter().is() )
1307     {
1308         SwCrsrSaveState aSave( *this );
1309         xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
1310 
1311         nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->nextWord(
1312                                 pTxtNd->GetTxt(), nPtPos,
1313             pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos, 1 ) ),
1314                     nWordType ).startPos;
1315 
1316         if( nPtPos < pTxtNd->GetTxt().Len() )
1317         {
1318             GetPoint()->nContent = nPtPos;
1319             if( !IsSelOvr() )
1320                 bRet = sal_True;
1321         }
1322     }
1323     return bRet;
1324 }
1325 
1326 sal_Bool SwCursor::GoPrevWordWT( sal_Int16 nWordType )
1327 {
1328     sal_Bool bRet = sal_False;
1329     const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
1330     if( pTxtNd && pBreakIt->GetBreakIter().is() )
1331     {
1332         SwCrsrSaveState aSave( *this );
1333         xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
1334         const xub_StrLen nPtStart = nPtPos;
1335 
1336         if( nPtPos )
1337             --nPtPos;
1338         nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->previousWord(
1339                                 pTxtNd->GetTxt(), nPtStart,
1340             pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos, 1 ) ),
1341                     nWordType ).startPos;
1342 
1343         if( nPtPos < pTxtNd->GetTxt().Len() )
1344         {
1345             GetPoint()->nContent = nPtPos;
1346             if( !IsSelOvr() )
1347                 bRet = sal_True;
1348         }
1349     }
1350     return bRet;
1351 }
1352 
1353 sal_Bool SwCursor::SelectWordWT( ViewShell* pViewShell, sal_Int16 nWordType, const Point* pPt )
1354 {
1355     SwCrsrSaveState aSave( *this );
1356 
1357     sal_Bool bRet = sal_False;
1358     sal_Bool bForward = sal_True;
1359     DeleteMark();
1360     const SwRootFrm* pLayout = pViewShell->GetLayout();
1361     if( pPt && 0 != pLayout )
1362     {
1363         // set the cursor to the layout position
1364         Point aPt( *pPt );
1365         pLayout->GetCrsrOfst( GetPoint(), aPt );
1366     }   //swmod 071107//swmod 071225
1367 
1368     const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
1369     if( pTxtNd && pBreakIt->GetBreakIter().is() )
1370     {
1371         xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
1372         Boundary aBndry( pBreakIt->GetBreakIter()->getWordBoundary(
1373                             pTxtNd->GetTxt(), nPtPos,
1374                             pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos ) ),
1375                             nWordType,
1376                             bForward ));
1377 
1378         if( aBndry.startPos != aBndry.endPos )
1379         {
1380             GetPoint()->nContent = (xub_StrLen)aBndry.endPos;
1381             if( !IsSelOvr() )
1382             {
1383                 SetMark();
1384                 GetMark()->nContent = (xub_StrLen)aBndry.startPos;
1385                 if( !IsSelOvr() )
1386                     bRet = sal_True;
1387             }
1388         }
1389     }
1390 
1391     if( !bRet )
1392     {
1393         DeleteMark();
1394         RestoreSavePos();
1395     }
1396     return bRet;
1397 }
1398 
1399 //-----------------------------------------------------------------------------
1400 
1401 static String lcl_MaskDeletedRedlines( const SwTxtNode* pTxtNd )
1402 {
1403     String aRes;
1404     if (pTxtNd)
1405     {
1406         //mask deleted redlines
1407         String sNodeText(pTxtNd->GetTxt());
1408         const SwDoc& rDoc = *pTxtNd->GetDoc();
1409         const bool nShowChg = IDocumentRedlineAccess::IsShowChanges( rDoc.GetRedlineMode() );
1410         if ( nShowChg )
1411         {
1412             sal_uInt16 nAct = rDoc.GetRedlinePos( *pTxtNd, USHRT_MAX );
1413             for ( ; nAct < rDoc.GetRedlineTbl().Count(); nAct++ )
1414             {
1415                 const SwRedline* pRed = rDoc.GetRedlineTbl()[ nAct ];
1416                 if ( pRed->Start()->nNode > pTxtNd->GetIndex() )
1417                     break;
1418 
1419                 if( nsRedlineType_t::REDLINE_DELETE == pRed->GetType() )
1420                 {
1421                     xub_StrLen nStart, nEnd;
1422                     pRed->CalcStartEnd( pTxtNd->GetIndex(), nStart, nEnd );
1423 
1424                     while ( nStart < nEnd && nStart < sNodeText.Len() )
1425                         sNodeText.SetChar( nStart++, CH_TXTATR_INWORD );
1426                 }
1427             }
1428         }
1429         aRes = sNodeText;
1430     }
1431     return aRes;
1432 }
1433 
1434 sal_Bool SwCursor::GoSentence( SentenceMoveType eMoveType )
1435 {
1436     sal_Bool bRet = sal_False;
1437     const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
1438     if( pTxtNd && pBreakIt->GetBreakIter().is() )
1439     {
1440         String sNodeText( lcl_MaskDeletedRedlines( pTxtNd ) );
1441 
1442         SwCrsrSaveState aSave( *this );
1443         xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
1444         switch ( eMoveType )
1445         {
1446         case START_SENT: /* when modifying: see also ExpandToSentenceBorders below! */
1447             nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->beginOfSentence(
1448                                     sNodeText,
1449                                     nPtPos, pBreakIt->GetLocale(
1450                                             pTxtNd->GetLang( nPtPos ) ));
1451             break;
1452         case END_SENT: /* when modifying: see also ExpandToSentenceBorders below! */
1453             nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->endOfSentence(
1454                                     sNodeText,
1455                                     nPtPos, pBreakIt->GetLocale(
1456                                                 pTxtNd->GetLang( nPtPos ) ));
1457             break;
1458         case NEXT_SENT:
1459             {
1460                 nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->endOfSentence(
1461                                         sNodeText,
1462                                         nPtPos, pBreakIt->GetLocale(
1463                                                     pTxtNd->GetLang( nPtPos ) ));
1464                 while (nPtPos != (sal_uInt16) -1 && ++nPtPos < sNodeText.Len()
1465                        && sNodeText.GetChar(nPtPos)== ' ' /*isWhiteSpace( aTxt.GetChar(nPtPos)*/ )
1466                     ;
1467                 break;
1468             }
1469         case PREV_SENT:
1470             nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->beginOfSentence(
1471                                     sNodeText,
1472                                     nPtPos, pBreakIt->GetLocale(
1473                                                 pTxtNd->GetLang( nPtPos ) ));
1474             if (nPtPos == 0)
1475                 return sal_False;   // the previous sentence is not in this paragraph
1476             if (nPtPos > 0)
1477                 nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->beginOfSentence(
1478                                     sNodeText,
1479                                     nPtPos - 1, pBreakIt->GetLocale(
1480                                                 pTxtNd->GetLang( nPtPos ) ));
1481             break;
1482         }
1483 
1484         // it is allowed to place the PaM just behind the last
1485         // character in the text thus <= ...Len
1486         if( nPtPos <= pTxtNd->GetTxt().Len() )
1487         {
1488             GetPoint()->nContent = nPtPos;
1489             if( !IsSelOvr() )
1490                 bRet = sal_True;
1491         }
1492     }
1493     return bRet;
1494 }
1495 
1496 
1497 sal_Bool SwCursor::ExpandToSentenceBorders()
1498 {
1499     sal_Bool bRes = sal_False;
1500     const SwTxtNode* pStartNd = Start()->nNode.GetNode().GetTxtNode();
1501     const SwTxtNode* pEndNd   = End()->nNode.GetNode().GetTxtNode();
1502     if (pStartNd && pEndNd && pBreakIt->GetBreakIter().is())
1503     {
1504         if (!HasMark())
1505             SetMark();
1506 
1507         String sStartText( lcl_MaskDeletedRedlines( pStartNd ) );
1508         String sEndText( pStartNd == pEndNd? sStartText : lcl_MaskDeletedRedlines( pEndNd ) );
1509 
1510         SwCrsrSaveState aSave( *this );
1511         xub_StrLen nStartPos = Start()->nContent.GetIndex();
1512         xub_StrLen nEndPos   = End()->nContent.GetIndex();
1513 
1514         nStartPos = (xub_StrLen)pBreakIt->GetBreakIter()->beginOfSentence(
1515                                 sStartText, nStartPos,
1516                                 pBreakIt->GetLocale( pStartNd->GetLang( nStartPos ) ) );
1517         nEndPos   = (xub_StrLen)pBreakIt->GetBreakIter()->endOfSentence(
1518                                 sEndText, nEndPos,
1519                                 pBreakIt->GetLocale( pEndNd->GetLang( nEndPos ) ) );
1520 
1521         // it is allowed to place the PaM just behind the last
1522         // character in the text thus <= ...Len
1523         bool bChanged = false;
1524         if (nStartPos <= pStartNd->GetTxt().Len())
1525         {
1526             GetMark()->nContent = nStartPos;
1527             bChanged = true;
1528         }
1529         if (nEndPos <= pEndNd->GetTxt().Len())
1530         {
1531             GetPoint()->nContent = nEndPos;
1532             bChanged = true;
1533         }
1534         if (bChanged && !IsSelOvr())
1535             bRes = sal_True;
1536     }
1537     return bRes;
1538 }
1539 
1540 
1541 sal_Bool SwTableCursor::LeftRight( sal_Bool bLeft, sal_uInt16 nCnt, sal_uInt16 /*nMode*/,
1542     sal_Bool /*bVisualAllowed*/, sal_Bool /*bSkipHidden*/, sal_Bool /*bInsertCrsr*/ )
1543 {
1544     return bLeft ? GoPrevCell( nCnt )
1545                  : GoNextCell( nCnt );
1546 }
1547 
1548 
1549 // calculate cursor bidi level: extracted from LeftRight()
1550 const SwCntntFrm*
1551 SwCursor::DoSetBidiLevelLeftRight(
1552     sal_Bool & io_rbLeft, sal_Bool bVisualAllowed, sal_Bool bInsertCrsr)
1553 {
1554     // calculate cursor bidi level
1555     const SwCntntFrm* pSttFrm = NULL;
1556     SwNode& rNode = GetPoint()->nNode.GetNode();
1557 
1558     if( rNode.IsTxtNode() )
1559     {
1560         const SwTxtNode& rTNd = *rNode.GetTxtNode();
1561         SwIndex& rIdx = GetPoint()->nContent;
1562         xub_StrLen nPos = rIdx.GetIndex();
1563 
1564         const SvtCTLOptions& rCTLOptions = SW_MOD()->GetCTLOptions();
1565         if ( bVisualAllowed && rCTLOptions.IsCTLFontEnabled() &&
1566              SvtCTLOptions::MOVEMENT_VISUAL ==
1567              rCTLOptions.GetCTLCursorMovement() )
1568         {
1569             // for visual cursor travelling (used in bidi layout)
1570             // we first have to convert the logic to a visual position
1571             Point aPt;
1572             pSttFrm = rTNd.getLayoutFrm( GetDoc()->GetCurrentLayout(), &aPt, GetPoint() );
1573             if( pSttFrm )
1574             {
1575                 sal_uInt8 nCrsrLevel = GetCrsrBidiLevel();
1576                 sal_Bool bForward = ! io_rbLeft;
1577                 ((SwTxtFrm*)pSttFrm)->PrepareVisualMove( nPos, nCrsrLevel,
1578                                                          bForward, bInsertCrsr );
1579                 rIdx = nPos;
1580                 SetCrsrBidiLevel( nCrsrLevel );
1581                 io_rbLeft = ! bForward;
1582             }
1583         }
1584         else
1585         {
1586             const SwScriptInfo* pSI = SwScriptInfo::GetScriptInfo( rTNd );
1587             if ( pSI )
1588             {
1589                 const xub_StrLen nMoveOverPos = io_rbLeft ?
1590                                                ( nPos ? nPos - 1 : 0 ) :
1591                                                 nPos;
1592                 SetCrsrBidiLevel( pSI->DirType( nMoveOverPos ) );
1593             }
1594         }
1595     }
1596     return pSttFrm;
1597 }
1598 
1599 sal_Bool SwCursor::LeftRight( sal_Bool bLeft, sal_uInt16 nCnt, sal_uInt16 nMode,
1600                           sal_Bool bVisualAllowed,sal_Bool bSkipHidden, sal_Bool bInsertCrsr )
1601 {
1602     // calculate cursor bidi level
1603     SwNode& rNode = GetPoint()->nNode.GetNode();
1604     const SwCntntFrm* pSttFrm = // may side-effect bLeft!
1605         DoSetBidiLevelLeftRight(bLeft, bVisualAllowed, bInsertCrsr);
1606 
1607     // kann der Cursor n-mal weiterverschoben werden ?
1608     SwCrsrSaveState aSave( *this );
1609     SwMoveFn fnMove = bLeft ? fnMoveBackward : fnMoveForward;
1610 
1611     SwGoInDoc fnGo;
1612     if ( bSkipHidden )
1613         fnGo = CRSR_SKIP_CELLS == nMode ? fnGoCntntCellsSkipHidden : fnGoCntntSkipHidden;
1614     else
1615         fnGo = CRSR_SKIP_CELLS == nMode ? fnGoCntntCells : fnGoCntnt;
1616 
1617     // ASSERT( not in covered cell )
1618 
1619     while( nCnt )
1620     {
1621         SwNodeIndex aOldNodeIdx( GetPoint()->nNode );
1622 
1623         bool bSuccess = Move( fnMove, fnGo );
1624         if ( !bSuccess )
1625             break;
1626 
1627         // If we were located inside a covered cell but our position has been
1628         // corrected, we check if the last move has moved the cursor to a different
1629         // table cell. In this case we set the cursor to the stored covered position
1630         // and redo the move:
1631         if ( mnRowSpanOffset )
1632         {
1633             const SwNode* pOldTabBoxSttNode = aOldNodeIdx.GetNode().FindTableBoxStartNode();
1634             const SwTableNode* pOldTabSttNode = pOldTabBoxSttNode ? pOldTabBoxSttNode->FindTableNode() : 0;
1635             const SwNode* pNewTabBoxSttNode = GetPoint()->nNode.GetNode().FindTableBoxStartNode();
1636             const SwTableNode* pNewTabSttNode = pNewTabBoxSttNode ? pNewTabBoxSttNode->FindTableNode() : 0;
1637 
1638             const bool bCellChanged = pOldTabSttNode && pNewTabSttNode &&
1639                                       pOldTabSttNode == pNewTabSttNode &&
1640                                       pOldTabBoxSttNode && pNewTabBoxSttNode &&
1641                                       pOldTabBoxSttNode != pNewTabBoxSttNode;
1642 
1643             if ( bCellChanged )
1644             {
1645                 // Set cursor to start/end of covered cell:
1646                 SwTableBox* pTableBox = pOldTabBoxSttNode->GetTblBox();
1647                 const long nRowSpan = pTableBox->getRowSpan();
1648                 if ( nRowSpan > 1 )
1649                 {
1650                     pTableBox = & pTableBox->FindEndOfRowSpan( pOldTabSttNode->GetTable(), (sal_uInt16)(pTableBox->getRowSpan() + mnRowSpanOffset ) );
1651                     SwNodeIndex& rPtIdx = GetPoint()->nNode;
1652                     SwNodeIndex aNewIdx( *pTableBox->GetSttNd() );
1653                     rPtIdx = aNewIdx;
1654 
1655                     GetDoc()->GetNodes().GoNextSection( &rPtIdx, sal_False, sal_False );
1656                     SwCntntNode* pCntntNode = GetCntntNode();
1657                     if ( pCntntNode )
1658                     {
1659                         const xub_StrLen nTmpPos = bLeft ? pCntntNode->Len() : 0;
1660                         GetPoint()->nContent.Assign( pCntntNode, nTmpPos );
1661 
1662                         // Redo the move:
1663                         bSuccess = Move( fnMove, fnGo );
1664                         if ( !bSuccess )
1665                             break;
1666                     }
1667                 }
1668 
1669                 mnRowSpanOffset = 0;
1670             }
1671         }
1672 
1673         // Check if I'm inside a covered cell. Correct cursor if necessary and
1674         // store covered cell:
1675         const SwNode* pTableBoxStartNode = GetPoint()->nNode.GetNode().FindTableBoxStartNode();
1676         if ( pTableBoxStartNode )
1677         {
1678             const SwTableBox* pTableBox = pTableBoxStartNode->GetTblBox();
1679             if ( pTableBox->getRowSpan() < 1 )
1680             {
1681                 // Store the row span offset:
1682                 mnRowSpanOffset = pTableBox->getRowSpan();
1683 
1684                 // Move cursor to non-covered cell:
1685                 const SwTableNode* pTblNd = pTableBoxStartNode->FindTableNode();
1686                 pTableBox = & pTableBox->FindStartOfRowSpan( pTblNd->GetTable(), USHRT_MAX );
1687                 SwNodeIndex& rPtIdx = GetPoint()->nNode;
1688                 SwNodeIndex aNewIdx( *pTableBox->GetSttNd() );
1689                 rPtIdx = aNewIdx;
1690 
1691                 GetDoc()->GetNodes().GoNextSection( &rPtIdx, sal_False, sal_False );
1692                 SwCntntNode* pCntntNode = GetCntntNode();
1693                 if ( pCntntNode )
1694                 {
1695                     const xub_StrLen nTmpPos = bLeft ? pCntntNode->Len() : 0;
1696                     GetPoint()->nContent.Assign( pCntntNode, nTmpPos );
1697                 }
1698             }
1699         }
1700 
1701         --nCnt;
1702     }
1703 
1704     // here come some special rules for visual cursor travelling
1705     if ( pSttFrm )
1706     {
1707         SwNode& rTmpNode = GetPoint()->nNode.GetNode();
1708         if ( &rTmpNode != &rNode && rTmpNode.IsTxtNode() )
1709         {
1710             Point aPt;
1711             const SwCntntFrm* pEndFrm = ((SwTxtNode&)rTmpNode).getLayoutFrm( GetDoc()->GetCurrentLayout(), &aPt, GetPoint() );
1712             if ( pEndFrm )
1713             {
1714                 if ( ! pEndFrm->IsRightToLeft() != ! pSttFrm->IsRightToLeft() )
1715                 {
1716                     if ( ! bLeft )
1717                         pEndFrm->RightMargin( this );
1718                     else
1719                         pEndFrm->LeftMargin( this );
1720                 }
1721             }
1722         }
1723     }
1724 
1725     return 0 == nCnt && !IsInProtectTable( sal_True ) &&
1726             !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
1727                        nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
1728 }
1729 
1730 // calculate cursor bidi level: extracted from UpDown()
1731 void SwCursor::DoSetBidiLevelUpDown()
1732 {
1733     SwNode& rNode = GetPoint()->nNode.GetNode();
1734     if ( rNode.IsTxtNode() )
1735     {
1736         const SwScriptInfo* pSI =
1737             SwScriptInfo::GetScriptInfo( (SwTxtNode&)rNode );
1738         if ( pSI )
1739         {
1740             SwIndex& rIdx = GetPoint()->nContent;
1741             xub_StrLen nPos = rIdx.GetIndex();
1742 
1743             if( nPos && nPos < ((SwTxtNode&)rNode).GetTxt().Len() )
1744             {
1745                 const sal_uInt8 nCurrLevel = pSI->DirType( nPos );
1746                 const sal_uInt8 nPrevLevel = pSI->DirType( nPos - 1 );
1747 
1748                 if ( nCurrLevel % 2 != nPrevLevel % 2 )
1749                 {
1750                     // set cursor level to the lower of the two levels
1751                     SetCrsrBidiLevel( Min( nCurrLevel, nPrevLevel ) );
1752                 }
1753                 else
1754                     SetCrsrBidiLevel( nCurrLevel );
1755             }
1756         }
1757     }
1758 }
1759 
1760 sal_Bool SwCursor::UpDown( sal_Bool bUp, sal_uInt16 nCnt,
1761                             Point* pPt, long nUpDownX )
1762 {
1763     SwTableCursor* pTblCrsr = dynamic_cast<SwTableCursor*>(this);
1764     sal_Bool bAdjustTableCrsr = sal_False;
1765 
1766     // vom Tabellen Crsr Point/Mark in der gleichen Box ??
1767     // dann stelle den Point an den Anfang der Box
1768     if( pTblCrsr && GetNode( sal_True )->StartOfSectionNode() ==
1769                     GetNode( sal_False )->StartOfSectionNode() )
1770     {
1771         if ( End() != GetPoint() )
1772             Exchange();
1773         bAdjustTableCrsr = sal_True;
1774     }
1775 
1776     sal_Bool bRet = sal_False;
1777     Point aPt;
1778     if( pPt )
1779         aPt = *pPt;
1780     SwCntntFrm* pFrm = GetCntntNode()->getLayoutFrm( GetDoc()->GetCurrentLayout(), &aPt, GetPoint() );
1781 
1782     if( pFrm )
1783     {
1784         SwCrsrSaveState aSave( *this );
1785 
1786         if( !pPt )
1787         {
1788             SwRect aTmpRect;
1789             pFrm->GetCharRect( aTmpRect, *GetPoint() );
1790             aPt = aTmpRect.Pos();
1791 
1792             nUpDownX = pFrm->IsVertical() ?
1793                 aPt.Y() - pFrm->Frm().Top() :
1794                 aPt.X() - pFrm->Frm().Left();
1795         }
1796 
1797         // Bei Fussnoten ist auch die Bewegung in eine andere Fussnote erlaubt.
1798         // aber keine Selection!!
1799         const sal_Bool bChkRange = pFrm->IsInFtn() && !HasMark()
1800                                     ? sal_False : sal_True;
1801         const SwPosition aOldPos( *GetPoint() );
1802         sal_Bool bInReadOnly = IsReadOnlyAvailable();
1803 
1804         if ( bAdjustTableCrsr && !bUp )
1805         {
1806             // Special case: We have a table cursor but the start box
1807             // has more than one paragraph. If we want to go down, we have to
1808             // set the point to the last frame in the table box. This is
1809             // only necessary if we do not already have a table selection
1810             const SwStartNode* pTblNd = GetNode( sal_True )->FindTableBoxStartNode();
1811             ASSERT( pTblNd, "pTblCrsr without SwTableNode?" )
1812 
1813             if ( pTblNd ) // safety first
1814             {
1815                 const SwNode* pEndNd = pTblNd->EndOfSectionNode();
1816                 GetPoint()->nNode = *pEndNd;
1817                 pTblCrsr->Move( fnMoveBackward, fnGoNode );
1818                 pFrm = GetCntntNode()->getLayoutFrm( GetDoc()->GetCurrentLayout(), &aPt, GetPoint() );
1819             }
1820         }
1821 
1822         while( nCnt &&
1823                (bUp ? pFrm->UnitUp( this, nUpDownX, bInReadOnly )
1824                     : pFrm->UnitDown( this, nUpDownX, bInReadOnly ) ) &&
1825                 CheckNodesRange( aOldPos.nNode, GetPoint()->nNode, bChkRange ))
1826         {
1827             pFrm = GetCntntNode()->getLayoutFrm( GetDoc()->GetCurrentLayout(), &aPt, GetPoint() );
1828             --nCnt;
1829         }
1830 
1831         if( !nCnt && !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
1832                                 nsSwCursorSelOverFlags::SELOVER_CHANGEPOS ) )  // die gesamte Anzahl durchlaufen ?
1833         {
1834             if( !pTblCrsr )
1835             {
1836                 // dann versuche den Cursor auf die Position zu setzen,
1837                 // auf halber Heohe vom Char-Rectangle
1838                 pFrm = GetCntntNode()->getLayoutFrm( GetDoc()->GetCurrentLayout(), &aPt, GetPoint() );
1839                 SwCrsrMoveState eTmpState( MV_UPDOWN );
1840                 eTmpState.bSetInReadOnly = bInReadOnly;
1841                 SwRect aTmpRect;
1842                 pFrm->GetCharRect( aTmpRect, *GetPoint(), &eTmpState );
1843                 if ( pFrm->IsVertical() )
1844                 {
1845                     aPt.X() = aTmpRect.Center().X();
1846                     pFrm->Calc();
1847                     aPt.Y() = pFrm->Frm().Top() + nUpDownX;
1848                 }
1849                 else
1850                 {
1851                     aPt.Y() = aTmpRect.Center().Y();
1852                     pFrm->Calc();
1853                     aPt.X() = pFrm->Frm().Left() + nUpDownX;
1854                 }
1855                 pFrm->GetCrsrOfst( GetPoint(), aPt, &eTmpState );
1856             }
1857             bRet = sal_True;
1858         }
1859         else
1860             *GetPoint() = aOldPos;
1861 
1862         DoSetBidiLevelUpDown(); // calculate cursor bidi level
1863     }
1864 
1865     return bRet;
1866 }
1867 
1868 sal_Bool SwCursor::LeftRightMargin( sal_Bool bLeft, sal_Bool bAPI )
1869 {
1870     Point aPt;
1871     SwCntntFrm * pFrm = GetCntntNode()->getLayoutFrm( GetDoc()->GetCurrentLayout(), &aPt, GetPoint() );
1872 
1873     // calculate cursor bidi level
1874     if ( pFrm )
1875         SetCrsrBidiLevel( pFrm->IsRightToLeft() ? 1 : 0 );
1876 
1877     return pFrm && (bLeft ? pFrm->LeftMargin( this ) :
1878                             pFrm->RightMargin( this, bAPI ) );
1879 }
1880 
1881 sal_Bool SwCursor::IsAtLeftRightMargin( sal_Bool bLeft, sal_Bool bAPI ) const
1882 {
1883     sal_Bool bRet = sal_False;
1884     Point aPt;
1885     SwCntntFrm * pFrm = GetCntntNode()->getLayoutFrm( GetDoc()->GetCurrentLayout(), &aPt, GetPoint() );
1886     if( pFrm )
1887     {
1888         SwPaM aPam( *GetPoint() );
1889         if( !bLeft && aPam.GetPoint()->nContent.GetIndex() )
1890             aPam.GetPoint()->nContent--;
1891         bRet = (bLeft ? pFrm->LeftMargin( &aPam )
1892                       : pFrm->RightMargin( &aPam, bAPI ))
1893                 && *aPam.GetPoint() == *GetPoint();
1894     }
1895     return bRet;
1896 }
1897 
1898 sal_Bool SwCursor::SttEndDoc( sal_Bool bStt )
1899 {
1900     SwCrsrSaveState aSave( *this );
1901 
1902     // Springe beim Selektieren nie ueber Section-Grenzen !!
1903     // kann der Cursor weiterverschoben werden ?
1904     SwMoveFn fnMove = bStt ? fnMoveBackward : fnMoveForward;
1905     sal_Bool bRet = (!HasMark() || !IsNoCntnt() ) &&
1906                     Move( fnMove, fnGoDoc ) &&
1907                     !IsInProtectTable( sal_True ) &&
1908                     !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
1909                                nsSwCursorSelOverFlags::SELOVER_CHANGEPOS |
1910                                nsSwCursorSelOverFlags::SELOVER_ENABLEREVDIREKTION );
1911 
1912     return bRet;
1913 }
1914 
1915 sal_Bool SwCursor::GoPrevNextCell( sal_Bool bNext, sal_uInt16 nCnt )
1916 {
1917     const SwTableNode* pTblNd = GetPoint()->nNode.GetNode().FindTableNode();
1918     if( !pTblNd )
1919         return sal_False;
1920 
1921     // liegt vor dem StartNode der Cell ein weiterer EndNode, dann
1922     // gibt es auch eine vorherige Celle
1923     SwCrsrSaveState aSave( *this );
1924     SwNodeIndex& rPtIdx = GetPoint()->nNode;
1925 
1926     while( nCnt-- )
1927     {
1928         const SwNode* pTableBoxStartNode = rPtIdx.GetNode().FindTableBoxStartNode();
1929         const SwTableBox* pTableBox = pTableBoxStartNode->GetTblBox();
1930 
1931         // Check if we have to move the cursor to a covered cell before
1932         // proceeding:
1933         if ( mnRowSpanOffset )
1934         {
1935             if ( pTableBox->getRowSpan() > 1 )
1936             {
1937                 pTableBox = & pTableBox->FindEndOfRowSpan( pTblNd->GetTable(), (sal_uInt16)(pTableBox->getRowSpan() + mnRowSpanOffset) );
1938                 SwNodeIndex aNewIdx( *pTableBox->GetSttNd() );
1939                 rPtIdx = aNewIdx;
1940                 pTableBoxStartNode = rPtIdx.GetNode().FindTableBoxStartNode();
1941             }
1942             mnRowSpanOffset = 0;
1943         }
1944 
1945         const SwNode* pTmpNode = bNext ?
1946                                  pTableBoxStartNode->EndOfSectionNode() :
1947                                  pTableBoxStartNode;
1948 
1949         SwNodeIndex aCellIdx( *pTmpNode, bNext ? 1 : -1 );
1950         if(  (bNext && !aCellIdx.GetNode().IsStartNode()) ||
1951             (!bNext && !aCellIdx.GetNode().IsEndNode()) )
1952             return sal_False;
1953 
1954         rPtIdx = bNext ? aCellIdx : SwNodeIndex(*aCellIdx.GetNode().StartOfSectionNode());
1955 
1956         pTableBoxStartNode = rPtIdx.GetNode().FindTableBoxStartNode();
1957         pTableBox = pTableBoxStartNode->GetTblBox();
1958         if ( pTableBox->getRowSpan() < 1 )
1959         {
1960             mnRowSpanOffset = pTableBox->getRowSpan();
1961             // move cursor to non-covered cell:
1962             pTableBox = & pTableBox->FindStartOfRowSpan( pTblNd->GetTable(), USHRT_MAX );
1963             SwNodeIndex aNewIdx( *pTableBox->GetSttNd() );
1964             rPtIdx = aNewIdx;
1965         }
1966     }
1967 
1968     rPtIdx++;
1969     if( !rPtIdx.GetNode().IsCntntNode() )
1970         GetDoc()->GetNodes().GoNextSection( &rPtIdx, sal_True, sal_False );
1971     GetPoint()->nContent.Assign( GetCntntNode(), 0 );
1972 
1973     return !IsInProtectTable( sal_True );
1974 }
1975 
1976 sal_Bool SwTableCursor::GotoTable( const String& /*rName*/ )
1977 {
1978     return sal_False; // invalid action
1979 }
1980 
1981 sal_Bool SwCursor::GotoTable( const String& rName )
1982 {
1983     sal_Bool bRet = sal_False;
1984     if ( !HasMark() )
1985     {
1986         SwTable* pTmpTbl = SwTable::FindTable( GetDoc()->FindTblFmtByName( rName ) );
1987         if( pTmpTbl )
1988         {
1989             // eine Tabelle im normalen NodesArr
1990             SwCrsrSaveState aSave( *this );
1991             GetPoint()->nNode = *pTmpTbl->GetTabSortBoxes()[ 0 ]->
1992                                 GetSttNd()->FindTableNode();
1993             Move( fnMoveForward, fnGoCntnt );
1994             bRet = !IsSelOvr();
1995         }
1996     }
1997     return bRet;
1998 }
1999 
2000 sal_Bool SwCursor::GotoTblBox( const String& rName )
2001 {
2002     sal_Bool bRet = sal_False;
2003     const SwTableNode* pTblNd = GetPoint()->nNode.GetNode().FindTableNode();
2004     if( pTblNd )
2005     {
2006         // erfrage die Box, mit dem Nanen
2007         const SwTableBox* pTblBox = pTblNd->GetTable().GetTblBox( rName );
2008         if( pTblBox && pTblBox->GetSttNd() &&
2009             ( !pTblBox->GetFrmFmt()->GetProtect().IsCntntProtected() ||
2010               IsReadOnlyAvailable() ) )
2011         {
2012             SwCrsrSaveState aSave( *this );
2013             GetPoint()->nNode = *pTblBox->GetSttNd();
2014             Move( fnMoveForward, fnGoCntnt );
2015             bRet = !IsSelOvr();
2016         }
2017     }
2018     return bRet;
2019 }
2020 
2021 sal_Bool SwCursor::MovePara(SwWhichPara fnWhichPara, SwPosPara fnPosPara )
2022 {
2023     //JP 28.8.2001: for optimization test something before
2024     const SwNode* pNd = &GetPoint()->nNode.GetNode();
2025     bool bShortCut = false;
2026     if ( fnWhichPara == fnParaCurr )
2027     {
2028         // --> FME 2005-02-21 #i41048#
2029         // If fnWhichPara == fnParaCurr, (*fnWhichPara)( *this, fnPosPara )
2030         // can already move the cursor to a different text node. In this case
2031         // we better check if IsSelOvr().
2032         const SwCntntNode* pCntntNd = pNd->GetCntntNode();
2033         if ( pCntntNd )
2034         {
2035             const xub_StrLen nSttEnd = fnPosPara == fnMoveForward ? 0 : pCntntNd->Len();
2036             if ( GetPoint()->nContent.GetIndex() != nSttEnd )
2037                 bShortCut = true;
2038         }
2039         // <--
2040     }
2041     else
2042     {
2043         if ( pNd->IsTxtNode() &&
2044              pNd->GetNodes()[ pNd->GetIndex() +
2045                     (fnWhichPara == fnParaNext ? 1 : -1 ) ]->IsTxtNode() )
2046             bShortCut = true;
2047     }
2048 
2049     if ( bShortCut )
2050         return (*fnWhichPara)( *this, fnPosPara );
2051 
2052     // else we must use the SaveStructure, because the next/prev is not
2053     // a same node type.
2054     SwCrsrSaveState aSave( *this );
2055     return (*fnWhichPara)( *this, fnPosPara ) &&
2056             !IsInProtectTable( sal_True ) &&
2057             !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
2058                        nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
2059 }
2060 
2061 
2062 sal_Bool SwCursor::MoveSection( SwWhichSection fnWhichSect,
2063                                 SwPosSection fnPosSect)
2064 {
2065     SwCrsrSaveState aSave( *this );
2066     return (*fnWhichSect)( *this, fnPosSect ) &&
2067             !IsInProtectTable( sal_True ) &&
2068             !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
2069                        nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
2070 }
2071 
2072 /*
2073     sal_Bool MoveTable( SwWhichTable, SwPosTable );
2074     sal_Bool MoveColumn( SwWhichColumn, SwPosColumn );
2075     sal_Bool MoveRegion( SwWhichRegion, SwPosRegion );
2076 */
2077 
2078 void SwCursor::RestoreSavePos()     // Point auf die SavePos setzen
2079 {
2080     if( pSavePos )
2081     {
2082         GetPoint()->nNode = pSavePos->nNode;
2083         GetPoint()->nContent.Assign( GetCntntNode(), pSavePos->nCntnt );
2084     }
2085 }
2086 
2087 
2088 /*  */
2089 
2090 SwTableCursor::SwTableCursor( const SwPosition &rPos, SwPaM* pRing )
2091     : SwCursor( rPos, pRing, false )
2092 {
2093     bParked = sal_False;
2094     bChg = sal_False;
2095     nTblPtNd = 0, nTblMkNd = 0;
2096     nTblPtCnt = 0, nTblMkCnt = 0;
2097 }
2098 
2099 SwTableCursor::~SwTableCursor() {}
2100 
2101 
2102 sal_Bool lcl_SeekEntry( const SwSelBoxes& rTmp, const SwStartNode* pSrch, sal_uInt16& rFndPos )
2103 {
2104     sal_uLong nIdx = pSrch->GetIndex();
2105 
2106     sal_uInt16 nO = rTmp.Count(), nM, nU = 0;
2107     if( nO > 0 )
2108     {
2109         nO--;
2110         while( nU <= nO )
2111         {
2112             nM = nU + ( nO - nU ) / 2;
2113             if( rTmp[ nM ]->GetSttNd() == pSrch )
2114             {
2115                 rFndPos = nM;
2116                 return sal_True;
2117             }
2118             else if( rTmp[ nM ]->GetSttIdx() < nIdx )
2119                 nU = nM + 1;
2120             else if( nM == 0 )
2121                 return sal_False;
2122             else
2123                 nO = nM - 1;
2124         }
2125     }
2126     return sal_False;
2127 }
2128 
2129 
2130 SwCursor* SwTableCursor::MakeBoxSels( SwCursor* pAktCrsr )
2131 {
2132     if( bChg )      // ???
2133     {
2134         if( bParked )
2135         {
2136             // wieder in den Inhalt schieben
2137             Exchange();
2138             Move( fnMoveForward );
2139             Exchange();
2140             Move( fnMoveForward );
2141             bParked = sal_False;
2142         }
2143 
2144         bChg = sal_False;
2145 
2146         // temp Kopie anlegen, damit alle Boxen, fuer die schon Cursor
2147         // existieren, entfernt werden koennen.
2148         SwSelBoxes aTmp;
2149         aTmp.Insert( &aSelBoxes );
2150 
2151         //Jetzt die Alten und die neuen abgleichen.
2152         SwNodes& rNds = pAktCrsr->GetDoc()->GetNodes();
2153         sal_uInt16 nPos;
2154         const SwStartNode* pSttNd;
2155         SwPaM* pCur = pAktCrsr;
2156         do {
2157             sal_Bool bDel = sal_False;
2158             pSttNd = pCur->GetPoint()->nNode.GetNode().FindTableBoxStartNode();
2159             if( !pCur->HasMark() || !pSttNd ||
2160                 pSttNd != pCur->GetMark()->nNode.GetNode().FindTableBoxStartNode() )
2161                 bDel = sal_True;
2162 
2163             else if( lcl_SeekEntry( aTmp, pSttNd, nPos ))
2164             {
2165                 SwNodeIndex aIdx( *pSttNd, 1 );
2166                 const SwNode* pNd = &aIdx.GetNode();
2167                 if( !pNd->IsCntntNode() )
2168                     pNd = rNds.GoNextSection( &aIdx, sal_True, sal_False );
2169 
2170                 SwPosition* pPos = pCur->GetMark();
2171                 if( pNd != &pPos->nNode.GetNode() )
2172                     pPos->nNode = *pNd;
2173                 pPos->nContent.Assign( (SwCntntNode*)pNd, 0 );
2174 
2175                 aIdx.Assign( *pSttNd->EndOfSectionNode(), - 1 );
2176                 if( !( pNd = &aIdx.GetNode())->IsCntntNode() )
2177                     pNd = rNds.GoPrevSection( &aIdx, sal_True, sal_False );
2178 
2179                 pPos = pCur->GetPoint();
2180                 if( pNd != &pPos->nNode.GetNode() )
2181                     pPos->nNode = *pNd;
2182                 pPos->nContent.Assign( (SwCntntNode*)pNd, ((SwCntntNode*)pNd)->Len() );
2183 
2184                 aTmp.Remove( nPos );
2185             }
2186             else
2187                 bDel = sal_True;
2188 
2189             pCur = (SwPaM*)pCur->GetNext();
2190             if( bDel )
2191             {
2192                 SwPaM* pDel = (SwPaM*)pCur->GetPrev();
2193 /*
2194 JP 20.07.98: der alte Code geht mit dem UNO-TableCrsr nicht
2195                 if( pDel == pAktCrsr )
2196                 {
2197                     if( pAktCrsr->GetNext() == pAktCrsr )
2198                     {
2199                         pAktCrsr->DeleteMark();
2200                         break;      // es gibt nichts mehr zu loeschen!
2201                     }
2202                     pAktCrsr = (SwCursor*)pDel->GetPrev();
2203                 }
2204                 delete pDel;
2205 */
2206 
2207                 if( pDel == pAktCrsr )
2208                     pAktCrsr->DeleteMark();
2209                 else
2210                     delete pDel;
2211             }
2212         } while ( pAktCrsr != pCur );
2213 
2214         for( nPos = 0; nPos < aTmp.Count(); ++nPos )
2215         {
2216             pSttNd = aTmp[ nPos ]->GetSttNd();
2217 
2218             SwNodeIndex aIdx( *pSttNd, 1 );
2219             if( &aIdx.GetNodes() != &rNds )
2220                 break;
2221             const SwNode* pNd = &aIdx.GetNode();
2222             if( !pNd->IsCntntNode() )
2223                 pNd = rNds.GoNextSection( &aIdx, sal_True, sal_False );
2224 
2225             SwPaM* pNew;
2226             if( pAktCrsr->GetNext() == pAktCrsr && !pAktCrsr->HasMark() )
2227             {
2228                 pNew = pAktCrsr;
2229                 pNew->GetPoint()->nNode = *pNd;
2230                 pNew->GetPoint()->nContent.Assign( (SwCntntNode*)pNd, 0 );
2231             }
2232             else
2233             {
2234                 pNew = pAktCrsr->Create( pAktCrsr );
2235                 pNew->GetPoint()->nNode = *pNd;
2236                 pNew->GetPoint()->nContent.Assign( (SwCntntNode*)pNd, 0 );
2237             }
2238             pNew->SetMark();
2239 
2240             SwPosition* pPos = pNew->GetPoint();
2241             pPos->nNode.Assign( *pSttNd->EndOfSectionNode(), - 1 );
2242             if( !( pNd = &pPos->nNode.GetNode())->IsCntntNode() )
2243                 pNd = rNds.GoPrevSection( &pPos->nNode, sal_True, sal_False );
2244 
2245             pPos->nContent.Assign( (SwCntntNode*)pNd, ((SwCntntNode*)pNd)->Len() );
2246         }
2247     }
2248     return pAktCrsr;
2249 }
2250 
2251 
2252 void SwTableCursor::InsertBox( const SwTableBox& rTblBox )
2253 {
2254     SwTableBox* pBox = (SwTableBox*)&rTblBox;
2255     aSelBoxes.Insert( pBox );
2256     bChg = sal_True;
2257 }
2258 
2259 bool SwTableCursor::NewTableSelection()
2260 {
2261     bool bRet = false;
2262     const SwNode *pStart = GetCntntNode()->FindTableBoxStartNode();
2263     const SwNode *pEnd = GetCntntNode(sal_False)->FindTableBoxStartNode();
2264     if( pStart && pEnd )
2265     {
2266         const SwTableNode *pTableNode = pStart->FindTableNode();
2267         if( pTableNode == pEnd->FindTableNode() &&
2268             pTableNode->GetTable().IsNewModel() )
2269         {
2270             bRet = true;
2271             SwSelBoxes aNew;
2272             aNew.Insert( &aSelBoxes );
2273             pTableNode->GetTable().CreateSelection( pStart, pEnd, aNew,
2274                 SwTable::SEARCH_NONE, false );
2275             ActualizeSelection( aNew );
2276         }
2277     }
2278     return bRet;
2279 }
2280 
2281 void SwTableCursor::ActualizeSelection( const SwSelBoxes &rNew )
2282 {
2283     sal_uInt16 nOld = 0, nNew = 0;
2284     while ( nOld < aSelBoxes.Count() && nNew < rNew.Count() )
2285     {
2286         const SwTableBox* pPOld = *( aSelBoxes.GetData() + nOld );
2287         const SwTableBox* pPNew = *( rNew.GetData() + nNew );
2288         if( pPOld == pPNew )
2289         {   // this box will stay
2290             ++nOld;
2291             ++nNew;
2292         }
2293         else if( pPOld->GetSttIdx() < pPNew->GetSttIdx() )
2294             DeleteBox( nOld ); // this box has to go
2295         else
2296         {
2297             InsertBox( *pPNew ); // this is a new one
2298             ++nOld;
2299             ++nNew;
2300         }
2301     }
2302 
2303     while( nOld < aSelBoxes.Count() )
2304         DeleteBox( nOld ); // some more to delete
2305 
2306     for( ; nNew < rNew.Count(); ++nNew ) // some more to insert
2307         InsertBox( **( rNew.GetData() + nNew ) );
2308 }
2309 
2310 sal_Bool SwTableCursor::IsCrsrMovedUpdt()
2311 {
2312     if( !IsCrsrMoved() )
2313         return sal_False;
2314 
2315     nTblMkNd = GetMark()->nNode.GetIndex();
2316     nTblPtNd = GetPoint()->nNode.GetIndex();
2317     nTblMkCnt = GetMark()->nContent.GetIndex();
2318     nTblPtCnt = GetPoint()->nContent.GetIndex();
2319     return sal_True;
2320 }
2321 
2322 
2323 // Parke den Tabellen-Cursor auf dem StartNode der Boxen.
2324 void SwTableCursor::ParkCrsr()
2325 {
2326     // Index aus dem TextNode abmelden
2327     SwNode* pNd = &GetPoint()->nNode.GetNode();
2328     if( !pNd->IsStartNode() )
2329         pNd = pNd->StartOfSectionNode();
2330     GetPoint()->nNode = *pNd;
2331     GetPoint()->nContent.Assign( 0, 0 );
2332 
2333     pNd = &GetMark()->nNode.GetNode();
2334     if( !pNd->IsStartNode() )
2335         pNd = pNd->StartOfSectionNode();
2336     GetMark()->nNode = *pNd;
2337     GetMark()->nContent.Assign( 0, 0 );
2338 
2339     bChg = sal_True;
2340     bParked = sal_True;
2341 }
2342 
2343 
2344 sal_Bool SwTableCursor::HasReadOnlyBoxSel() const
2345 {
2346     sal_Bool bRet = sal_False;
2347     for( sal_uInt16 n = aSelBoxes.Count(); n;  )
2348         if( aSelBoxes[ --n ]->GetFrmFmt()->GetProtect().IsCntntProtected() )
2349         {
2350             bRet = sal_True;
2351             break;
2352         }
2353     return bRet;
2354 }
2355 
2356 
2357