Update ooo320-m1
[ooovba.git] / sw / source / core / crsr / swcrsr.cxx
blob749046780bb8ccadf5e78852dc077996189a005e
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: swcrsr.cxx,v $
10 * $Revision: 1.59 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
35 #include <hintids.hxx>
36 #include <svx/protitem.hxx>
38 #include <com/sun/star/i18n/WordType.hdl>
39 #include <com/sun/star/i18n/CharType.hdl>
41 #include <unotools/charclass.hxx>
42 #include <svtools/ctloptions.hxx>
43 #include <swmodule.hxx>
44 #include <fmtcntnt.hxx>
45 #include <swtblfmt.hxx>
46 #include <swcrsr.hxx>
47 #include <unocrsr.hxx>
48 #include <doc.hxx>
49 #include <docary.hxx>
50 #include <ndtxt.hxx>
51 #include <section.hxx>
52 #include <swtable.hxx>
53 #include <cntfrm.hxx>
54 #include <rootfrm.hxx>
55 #include <txtfrm.hxx>
56 #include <scriptinfo.hxx>
57 #include <crstate.hxx>
58 #include <docsh.hxx>
59 #include <frmatr.hxx>
60 #include <breakit.hxx>
61 #include <crsskip.hxx>
62 #include <vcl/msgbox.hxx>
63 #include <mdiexp.hxx> // ...Percent()
64 #ifndef _STATSTR_HRC
65 #include <statstr.hrc> // ResId fuer Statusleiste
66 #endif
67 #include <redline.hxx> // SwRedline
70 using namespace ::com::sun::star::i18n;
73 static const USHORT coSrchRplcThreshold = 60000;
75 struct _PercentHdl
77 SwDocShell* pDSh;
78 ULONG nActPos;
79 BOOL bBack, bNodeIdx;
81 _PercentHdl( ULONG nStt, ULONG nEnd, SwDocShell* pSh )
82 : pDSh( pSh )
84 nActPos = nStt;
85 if( 0 != ( bBack = (nStt > nEnd )) )
87 ULONG n = nStt; nStt = nEnd; nEnd = n;
89 ::StartProgress( STR_STATSTR_SEARCH, nStt, nEnd, 0 );
92 _PercentHdl( const SwPaM& rPam )
93 : pDSh( (SwDocShell*)rPam.GetDoc()->GetDocShell() )
95 ULONG nStt, nEnd;
96 if( rPam.GetPoint()->nNode == rPam.GetMark()->nNode )
98 bNodeIdx = FALSE;
99 nStt = rPam.GetMark()->nContent.GetIndex();
100 nEnd = rPam.GetPoint()->nContent.GetIndex();
102 else
104 bNodeIdx = TRUE;
105 nStt = rPam.GetMark()->nNode.GetIndex();
106 nEnd = rPam.GetPoint()->nNode.GetIndex();
108 nActPos = nStt;
109 if( 0 != ( bBack = (nStt > nEnd )) )
111 ULONG n = nStt; nStt = nEnd; nEnd = n;
113 ::StartProgress( STR_STATSTR_SEARCH, nStt, nEnd, pDSh );
116 ~_PercentHdl() { ::EndProgress( pDSh ); }
118 void NextPos( ULONG nPos ) const
119 { ::SetProgressState( bBack ? nActPos - nPos : nPos, pDSh ); }
121 void NextPos( SwPosition& rPos ) const
123 ULONG nPos;
124 if( bNodeIdx )
125 nPos = rPos.nNode.GetIndex();
126 else
127 nPos = rPos.nContent.GetIndex();
128 ::SetProgressState( bBack ? nActPos - nPos : nPos, pDSh );
132 SwCursor::SwCursor( const SwPosition &rPos, SwPaM* pRing, bool bColumnSel )
133 : SwPaM( rPos, pRing ), pSavePos( 0 ), mnRowSpanOffset( 0 ), nCursorBidiLevel( 0 ),
134 mbColumnSelection( bColumnSel )
138 // @@@ semantic: no copy ctor.
139 SwCursor::SwCursor( SwCursor& rCpy )
140 : SwPaM( rCpy ), pSavePos( 0 ), mnRowSpanOffset( rCpy.mnRowSpanOffset ),
141 nCursorBidiLevel( rCpy.nCursorBidiLevel ), mbColumnSelection( rCpy.mbColumnSelection )
145 SwCursor::~SwCursor()
147 while( pSavePos )
149 _SwCursor_SavePos* pNxt = pSavePos->pNext;
150 delete pSavePos;
151 pSavePos = pNxt;
155 SwCursor* SwCursor::Create( SwPaM* pRing ) const
157 return new SwCursor( *GetPoint(), pRing, false );
160 bool SwCursor::IsReadOnlyAvailable() const
162 return false;
165 BOOL SwCursor::IsSkipOverHiddenSections() const
167 return TRUE;
170 BOOL SwCursor::IsSkipOverProtectSections() const
172 return !IsReadOnlyAvailable();
176 // Sicher die aktuelle Position, damit ggfs. auf diese zurueck
177 // gefallen werden kann. Die SavePos Objekte werden als Stack verwaltet,
178 // damit das auch alles bei verschachtelten Aufrufen funktioniert.
179 // Das CreateNewSavePos ist virtual, damit abgeleitete Klassen vom Cursor
180 // gegebenenfalls eigene SaveObjecte anlegen und in den virtuellen
181 // Check-Routinen verwenden koennen.
183 void SwCursor::SaveState()
185 _SwCursor_SavePos* pNew = CreateNewSavePos();
186 pNew->pNext = pSavePos;
187 pSavePos = pNew;
190 void SwCursor::RestoreState()
192 if( pSavePos ) // Robust
194 _SwCursor_SavePos* pDel = pSavePos;
195 pSavePos = pSavePos->pNext;
196 delete pDel;
200 _SwCursor_SavePos* SwCursor::CreateNewSavePos() const
202 return new _SwCursor_SavePos( *this );
205 // stelle fest, ob sich der Point ausserhalb des Content-Bereichs
206 // vom Nodes-Array befindet
207 BOOL SwCursor::IsNoCntnt() const
209 return GetPoint()->nNode.GetIndex() <
210 GetDoc()->GetNodes().GetEndOfExtras().GetIndex();
213 bool SwCursor::IsSelOvrCheck(int)
215 return false;
218 // extracted from IsSelOvr()
219 bool SwTableCursor::IsSelOvrCheck(int eFlags)
221 SwNodes& rNds = GetDoc()->GetNodes();
222 // check sections of nodes array
223 if( (nsSwCursorSelOverFlags::SELOVER_CHECKNODESSECTION & eFlags)
224 && HasMark() )
226 SwNodeIndex aOldPos( rNds, GetSavePos()->nNode );
227 if( !CheckNodesRange( aOldPos, GetPoint()->nNode, TRUE ))
229 GetPoint()->nNode = aOldPos;
230 GetPoint()->nContent.Assign( GetCntntNode(), GetSavePos()->nCntnt );
231 return true;
234 return SwCursor::IsSelOvrCheck(eFlags);
237 BOOL SwCursor::IsSelOvr( int eFlags )
239 SwDoc* pDoc = GetDoc();
240 SwNodes& rNds = pDoc->GetNodes();
242 BOOL bSkipOverHiddenSections = IsSkipOverHiddenSections();
243 BOOL bSkipOverProtectSections = IsSkipOverProtectSections();
245 if ( IsSelOvrCheck( eFlags ) )
247 return TRUE;
250 // neu: Bereiche ueberpruefen
251 // Anfang
252 if( pSavePos->nNode != GetPoint()->nNode.GetIndex() &&
253 //JP 28.10.97: Bug 45129 - im UI-ReadOnly ist alles erlaubt
254 ( !pDoc->GetDocShell() || !pDoc->GetDocShell()->IsReadOnlyUI() ))
256 // teste doch mal die neuen Sections:
257 SwNodeIndex& rPtIdx = GetPoint()->nNode;
258 const SwSectionNode* pSectNd = rPtIdx.GetNode().FindSectionNode();
259 if( pSectNd &&
260 ((bSkipOverHiddenSections && pSectNd->GetSection().IsHiddenFlag() ) ||
261 (bSkipOverProtectSections && pSectNd->GetSection().IsProtectFlag() )))
263 if( 0 == ( nsSwCursorSelOverFlags::SELOVER_CHANGEPOS & eFlags ) )
265 // dann wars das schon
266 RestoreSavePos();
267 return TRUE;
270 // dann setze den Cursor auf die neue Position:
271 SwNodeIndex aIdx( rPtIdx );
272 xub_StrLen nCntntPos = pSavePos->nCntnt;
273 int bGoNxt = pSavePos->nNode < rPtIdx.GetIndex();
274 SwCntntNode* pCNd = bGoNxt
275 ? rNds.GoNextSection( &rPtIdx, bSkipOverHiddenSections, bSkipOverProtectSections)
276 : rNds.GoPrevSection( &rPtIdx, bSkipOverHiddenSections, bSkipOverProtectSections);
277 if( !pCNd && ( nsSwCursorSelOverFlags::SELOVER_ENABLEREVDIREKTION & eFlags ))
279 bGoNxt = !bGoNxt;
280 pCNd = bGoNxt ? rNds.GoNextSection( &rPtIdx, bSkipOverHiddenSections, bSkipOverProtectSections)
281 : rNds.GoPrevSection( &rPtIdx, bSkipOverHiddenSections, bSkipOverProtectSections);
284 int bIsValidPos = 0 != pCNd;
285 BOOL bValidNodesRange = bIsValidPos &&
286 ::CheckNodesRange( rPtIdx, aIdx, TRUE );
287 if( !bValidNodesRange )
289 rPtIdx = pSavePos->nNode;
290 if( 0 == ( pCNd = rPtIdx.GetNode().GetCntntNode() ) )
292 bIsValidPos = FALSE;
293 nCntntPos = 0;
294 rPtIdx = aIdx;
295 if( 0 == ( pCNd = rPtIdx.GetNode().GetCntntNode() ) )
297 // dann auf den Anfang vom Doc
298 rPtIdx = rNds.GetEndOfExtras();
299 pCNd = rNds.GoNext( &rPtIdx );
304 // ContentIndex noch anmelden:
305 xub_StrLen nTmpPos = bIsValidPos ? (bGoNxt ? 0 : pCNd->Len()) : nCntntPos;
306 GetPoint()->nContent.Assign( pCNd, nTmpPos );
307 if( !bIsValidPos || !bValidNodesRange ||
308 // sollten wir in einer Tabelle gelandet sein?
309 IsInProtectTable( TRUE ) )
310 return TRUE;
313 // oder sollte eine geschuetzte Section innerhalb der Selektion liegen?
314 if( HasMark() && bSkipOverProtectSections)
316 ULONG nSttIdx = GetMark()->nNode.GetIndex(),
317 nEndIdx = GetPoint()->nNode.GetIndex();
318 if( nEndIdx <= nSttIdx )
320 ULONG nTmp = nSttIdx;
321 nSttIdx = nEndIdx;
322 nEndIdx = nTmp;
325 const SwSectionFmts& rFmts = pDoc->GetSections();
326 for( USHORT n = 0; n < rFmts.Count(); ++n )
328 const SwSectionFmt* pFmt = rFmts[n];
329 const SvxProtectItem& rProtect = pFmt->GetProtect();
330 if( rProtect.IsCntntProtected() )
332 const SwFmtCntnt& rCntnt = pFmt->GetCntnt(FALSE);
333 ASSERT( rCntnt.GetCntntIdx(), "wo ist der SectionNode?" );
334 ULONG nIdx = rCntnt.GetCntntIdx()->GetIndex();
335 if( nSttIdx <= nIdx && nEndIdx >= nIdx )
337 // ist es keine gelinkte Section, dann kann sie auch
338 // nicht mitselektiert werden
339 const SwSection& rSect = *pFmt->GetSection();
340 if( CONTENT_SECTION == rSect.GetType() )
342 RestoreSavePos();
343 return TRUE;
351 // Ende
352 // neu: Bereiche ueberpruefen
354 const SwNode* pNd = &GetPoint()->nNode.GetNode();
355 if( pNd->IsCntntNode() && !dynamic_cast<SwUnoCrsr*>(this) )
357 const SwCntntFrm* pFrm = ((SwCntntNode*)pNd)->GetFrm();
358 if( pFrm && pFrm->IsValid() && 0 == pFrm->Frm().Height() &&
359 0 != ( nsSwCursorSelOverFlags::SELOVER_CHANGEPOS & eFlags ) )
361 // skip to the next / prev valid paragraph with a layout
362 SwNodeIndex& rPtIdx = GetPoint()->nNode;
363 int bGoNxt = pSavePos->nNode < rPtIdx.GetIndex();
364 while( 0 != ( pFrm = ( bGoNxt ? pFrm->GetNextCntntFrm()
365 : pFrm->GetPrevCntntFrm() )) &&
366 0 == pFrm->Frm().Height() )
369 // --> LIJIAN/FME 2007-11-27 #i72394# skip to prev /next valid paragraph
370 // with a layout in case the first search did not succeed:
371 if( !pFrm )
373 bGoNxt = !bGoNxt;
374 pFrm = ((SwCntntNode*)pNd)->GetFrm();
375 while ( pFrm && 0 == pFrm->Frm().Height() )
377 pFrm = bGoNxt ? pFrm->GetNextCntntFrm()
378 : pFrm->GetPrevCntntFrm();
381 // <--
383 SwCntntNode* pCNd;
384 if( pFrm && 0 != (pCNd = (SwCntntNode*)pFrm->GetNode()) )
386 // set this cntntNode as new position
387 rPtIdx = *pCNd;
388 pNd = pCNd;
390 // ContentIndex noch anmelden:
391 xub_StrLen nTmpPos = bGoNxt ? 0 : pCNd->Len();
392 GetPoint()->nContent.Assign( pCNd, nTmpPos );
394 // sollten wir in einer Tabelle gelandet sein?
395 if( IsInProtectTable( TRUE ) )
396 pFrm = 0;
400 if( !pFrm )
402 DeleteMark();
403 RestoreSavePos();
404 return TRUE; // ohne Frames geht gar nichts!
408 // darf der Cursor in geschuetzen "Nodes" stehen?
409 if( 0 == ( nsSwCursorSelOverFlags::SELOVER_CHANGEPOS & eFlags ) && !IsAtValidPos() )
411 DeleteMark();
412 RestoreSavePos();
413 return TRUE;
416 if( !HasMark() )
417 return FALSE;
419 //JP 19.08.98: teste mal auf ungueltige Selektion - sprich ueber
420 // GrundSections:
421 if( !::CheckNodesRange( GetMark()->nNode, GetPoint()->nNode, TRUE ))
423 DeleteMark();
424 RestoreSavePos();
425 return TRUE; // ohne Frames geht gar nichts!
428 const SwTableNode* pPtNd = pNd->FindTableNode();
430 if( (pNd = &GetMark()->nNode.GetNode())->IsCntntNode() &&
431 !((SwCntntNode*)pNd)->GetFrm() && !dynamic_cast<SwUnoCrsr*>(this) )
433 DeleteMark();
434 RestoreSavePos();
435 return TRUE; // ohne Frames geht gar nichts!
438 const SwTableNode* pMrkNd = pNd->FindTableNode();
440 // beide in keinem oder beide im gleichen TableNode
441 if( ( !pMrkNd && !pPtNd ) || pPtNd == pMrkNd )
442 return FALSE;
444 // in unterschiedlichen Tabellen oder nur Mark in der Tabelle
445 if( ( pPtNd && pMrkNd ) || pMrkNd )
446 { // dann lasse das nicht zu, alte Pos zurueck
447 RestoreSavePos();
448 // Crsr bleibt an der alten Position
449 return TRUE;
452 // ACHTUNG: dieses kann nicht im TableMode geschehen !!
453 if( pPtNd ) // nur Point in Tabelle, dann gehe hinter/vor diese
455 if( nsSwCursorSelOverFlags::SELOVER_CHANGEPOS & eFlags )
457 BOOL bSelTop = GetPoint()->nNode.GetIndex() <
458 (( nsSwCursorSelOverFlags::SELOVER_TOGGLE & eFlags ) ? pSavePos->nNode
459 : GetMark()->nNode.GetIndex());
461 do {
462 // in Schleife fuer Tabelle hinter Tabelle
463 ULONG nSEIdx = pPtNd->EndOfSectionIndex();
464 ULONG nSttEndTbl = nSEIdx + 1; // dflt. Sel. nach unten
466 if( bSelTop ) // Sel. nach oben
467 nSttEndTbl = rNds[ nSEIdx ]->StartOfSectionIndex() - 1;
469 GetPoint()->nNode = nSttEndTbl;
470 const SwNode* pMyNd = GetNode();
472 if( pMyNd->IsSectionNode() || ( pMyNd->IsEndNode() &&
473 pMyNd->StartOfSectionNode()->IsSectionNode() ) )
475 // die lassen wir zu:
476 pMyNd = bSelTop
477 ? rNds.GoPrevSection( &GetPoint()->nNode,TRUE,FALSE )
478 : rNds.GoNextSection( &GetPoint()->nNode,TRUE,FALSE );
480 /* #i12312# Handle failure of Go{Prev|Next}Section */
481 if ( 0 == pMyNd)
482 break;
484 if( 0 != ( pPtNd = pMyNd->FindTableNode() ))
485 continue;
488 if( pMyNd->IsCntntNode() && // ist es ein ContentNode ??
489 ::CheckNodesRange( GetMark()->nNode,
490 GetPoint()->nNode, TRUE ))
492 // TABLE IN TABLE
493 const SwTableNode* pOuterTableNd = pMyNd->FindTableNode();
494 if ( pOuterTableNd )
495 pMyNd = pOuterTableNd;
496 else
498 SwCntntNode* pCNd = (SwCntntNode*)pMyNd;
499 xub_StrLen nTmpPos = bSelTop ? pCNd->Len() : 0;
500 GetPoint()->nContent.Assign( pCNd, nTmpPos );
501 return FALSE;
504 if( bSelTop
505 ? ( !pMyNd->IsEndNode() || 0 == ( pPtNd = pMyNd->FindTableNode() ))
506 : 0 == ( pPtNd = pMyNd->GetTableNode() ))
507 break;
508 } while( TRUE );
511 // dann verbleibe auf der alten Position
512 RestoreSavePos();
513 return TRUE; // Crsr bleibt an der alten Position
515 return FALSE; // was bleibt noch ??
518 #if defined( UNX )
519 #define IDX (*pCellStt)
520 #else
521 #define IDX aCellStt
522 #endif
525 BOOL SwCursor::IsInProtectTable( BOOL bMove, BOOL bChgCrsr )
527 SwCntntNode* pCNd = GetCntntNode();
528 if( !pCNd )
529 return FALSE;
531 // No table, no protected cell:
532 const SwTableNode* pTableNode = pCNd->FindTableNode();
533 if ( !pTableNode )
534 return FALSE;
536 // Current position == last save position?
537 if ( pSavePos->nNode == GetPoint()->nNode.GetIndex() )
538 return FALSE;
540 // Check for convered cell:
541 bool bInCoveredCell = false;
542 const SwStartNode* pTmpSttNode = pCNd->FindTableBoxStartNode();
543 ASSERT( pTmpSttNode, "In table, therefore I expect to get a SwTableBoxStartNode" )
544 const SwTableBox* pBox = pTmpSttNode ? pTableNode->GetTable().GetTblBox( pTmpSttNode->GetIndex() ) : 0; //Robust #151355
545 if ( pBox && pBox->getRowSpan() < 1 ) // Robust #151270
546 bInCoveredCell = true;
548 // Positions of covered cells are not acceptable:
549 if ( !bInCoveredCell )
551 // Position not protected?
552 if ( !pCNd->IsProtect() )
553 return FALSE;
555 // Cursor in protected cells allowed?
556 if ( IsReadOnlyAvailable() )
557 return FALSE;
560 // If we reach this point, we are in a protected or covered table cell!
562 if( !bMove )
564 if( bChgCrsr )
565 // restore the last save position
566 RestoreSavePos();
567 return TRUE; // Crsr bleibt an der alten Position
570 // wir stehen in einer geschuetzten TabellenZelle
571 // von Oben nach Unten Traveln ?
572 if( pSavePos->nNode < GetPoint()->nNode.GetIndex() )
574 // suche die naechste "gueltige" Box
576 // folgt nach dem EndNode der Zelle ein weiterer StartNode, dann
577 // gibt es auch eine naechste Zelle
578 #if defined( UNX )
579 SwNodeIndex* pCellStt = new SwNodeIndex( *GetNode()->
580 FindTableBoxStartNode()->EndOfSectionNode(), 1 );
581 #else
582 SwNodeIndex aCellStt( *GetNode()->FindTableBoxStartNode()->EndOfSectionNode(), 1 );
583 #endif
584 BOOL bProt = TRUE;
585 GoNextCell:
586 do {
587 if( !IDX.GetNode().IsStartNode() )
588 break;
589 IDX++;
590 if( 0 == ( pCNd = IDX.GetNode().GetCntntNode() ))
591 pCNd = IDX.GetNodes().GoNext( &IDX );
592 if( 0 == ( bProt = pCNd->IsProtect() ))
593 break;
594 IDX.Assign( *pCNd->FindTableBoxStartNode()->EndOfSectionNode(), 1 );
595 } while( bProt );
597 SetNextCrsr:
598 if( !bProt ) // eine freie Zelle gefunden
600 GetPoint()->nNode = IDX;
601 #if defined( UNX )
602 delete pCellStt;
603 #endif
604 SwCntntNode* pTmpCNd = GetCntntNode();
605 if( pTmpCNd )
607 GetPoint()->nContent.Assign( pTmpCNd, 0 );
608 return FALSE;
610 return IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
611 nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
613 // am Ende der Tabelle, also setze hinter diese
614 IDX++; // auf den naechsten Node
615 SwNode* pNd;
616 if( ( pNd = &IDX.GetNode())->IsEndNode() || HasMark())
618 // Tabelle allein in einem FlyFrame oder SSelection,
619 // dann verbleibe auf der alten Position
620 if( bChgCrsr )
621 RestoreSavePos();
622 #if defined( UNX )
623 delete pCellStt;
624 #endif
625 return TRUE; // Crsr bleibt an der alten Position
627 else if( pNd->IsTableNode() && IDX++ )
628 goto GoNextCell;
630 bProt = FALSE; // Index steht jetzt auf einem ContentNode
631 goto SetNextCrsr;
634 // suche die vorherige "gueltige" Box
636 // liegt vor dem StartNode der Zelle ein weiterer EndNode, dann
637 // gibt es auch eine vorherige Zelle
638 #if defined( UNX )
639 SwNodeIndex* pCellStt = new SwNodeIndex(
640 *GetNode()->FindTableBoxStartNode(), -1 );
641 #else
642 SwNodeIndex aCellStt( *GetNode()->FindTableBoxStartNode(), -1 );
643 #endif
644 SwNode* pNd;
645 BOOL bProt = TRUE;
646 GoPrevCell:
647 do {
648 if( !( pNd = &IDX.GetNode())->IsEndNode() )
649 break;
650 IDX.Assign( *pNd->StartOfSectionNode(), +1 );
651 if( 0 == ( pCNd = IDX.GetNode().GetCntntNode() ))
652 pCNd = pNd->GetNodes().GoNext( &IDX );
653 if( 0 == ( bProt = pCNd->IsProtect() ))
654 break;
655 IDX.Assign( *pNd->FindTableBoxStartNode(), -1 );
656 } while( bProt );
658 SetPrevCrsr:
659 if( !bProt ) // eine freie Zelle gefunden
661 GetPoint()->nNode = IDX;
662 #if defined( UNX )
663 delete pCellStt;
664 #endif
665 SwCntntNode* pTmpCNd = GetCntntNode();
666 if( pTmpCNd )
668 GetPoint()->nContent.Assign( pTmpCNd, 0 );
669 return FALSE;
671 return IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
672 nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
674 // am Start der Tabelle, also setze vor diese
675 IDX--; // auf den naechsten Node
676 if( ( pNd = &IDX.GetNode())->IsStartNode() || HasMark() )
678 // Tabelle allein in einem FlyFrame oder Selektion,
679 // dann verbleibe auf der alten Position
680 if( bChgCrsr )
681 RestoreSavePos();
682 #if defined( UNX )
683 delete pCellStt;
684 #endif
685 return TRUE; // Crsr bleibt an der alten Position
687 else if( pNd->StartOfSectionNode()->IsTableNode() && IDX-- )
688 goto GoPrevCell;
690 bProt = FALSE; // Index steht jetzt auf einem ContentNode
691 goto SetPrevCrsr;
695 // TRUE: an die Position kann der Cursor gesetzt werden
696 BOOL SwCursor::IsAtValidPos( BOOL bPoint ) const
698 const SwDoc* pDoc = GetDoc();
699 const SwPosition* pPos = bPoint ? GetPoint() : GetMark();
700 const SwNode* pNd = &pPos->nNode.GetNode();
702 if( pNd->IsCntntNode() && !((SwCntntNode*)pNd)->GetFrm() &&
703 !dynamic_cast<const SwUnoCrsr*>(this) )
705 return FALSE;
708 //JP 28.10.97: Bug 45129 - im UI-ReadOnly ist alles erlaubt
709 if( !pDoc->GetDocShell() || !pDoc->GetDocShell()->IsReadOnlyUI() )
710 return TRUE;
712 BOOL bCrsrInReadOnly = IsReadOnlyAvailable();
713 if( !bCrsrInReadOnly && pNd->IsProtect() )
714 return FALSE;
716 const SwSectionNode* pSectNd = pNd->FindSectionNode();
717 if( pSectNd && (pSectNd->GetSection().IsHiddenFlag() ||
718 ( !bCrsrInReadOnly && pSectNd->GetSection().IsProtectFlag() )))
719 return FALSE;
721 return TRUE;
724 void SwCursor::SaveTblBoxCntnt( const SwPosition* ) {}
726 // setze den SRange fuer das Suchen im Dokument
727 SwMoveFnCollection* SwCursor::MakeFindRange( SwDocPositions nStart,
728 SwDocPositions nEnd, SwPaM* pRange ) const
730 pRange->SetMark();
731 FillFindPos( nStart, *pRange->GetMark() );
732 FillFindPos( nEnd, *pRange->GetPoint() );
734 // bestimme die Richtung, in der zu suchen ist
735 // ( GetPoint > GetMark -> vorwaerts, sonst rueckwaerts )
736 return ( DOCPOS_START == nStart || DOCPOS_OTHERSTART == nStart ||
737 (DOCPOS_CURR == nStart &&
738 (DOCPOS_END == nEnd || DOCPOS_OTHEREND == nEnd ) ))
739 ? fnMoveForward : fnMoveBackward;
743 ULONG lcl_FindSelection( SwFindParas& rParas, SwCursor* pCurCrsr,
744 SwMoveFn fnMove, SwCursor*& pFndRing,
745 SwPaM& aRegion, FindRanges eFndRngs,
746 BOOL bInReadOnly, BOOL& bCancel )
748 SwDoc* pDoc = pCurCrsr->GetDoc();
749 BOOL bDoesUndo = pDoc->DoesUndo();
750 int nFndRet = 0;
751 ULONG nFound = 0;
752 int bSrchBkwrd = fnMove == fnMoveBackward, bEnde = FALSE;
753 SwPaM *pTmpCrsr = pCurCrsr, *pSaveCrsr = pCurCrsr;
755 // only create progress-bar for ShellCrsr
756 bool bIsUnoCrsr = 0 != dynamic_cast<SwUnoCrsr*>(pCurCrsr);
757 _PercentHdl* pPHdl = 0;
758 USHORT nCrsrCnt = 0;
759 if( FND_IN_SEL & eFndRngs )
761 while( pCurCrsr != ( pTmpCrsr = (SwPaM*)pTmpCrsr->GetNext() ))
762 ++nCrsrCnt;
763 if( nCrsrCnt && !bIsUnoCrsr )
764 pPHdl = new _PercentHdl( 0, nCrsrCnt, pDoc->GetDocShell() );
766 else
767 pSaveCrsr = (SwPaM*)pSaveCrsr->GetPrev();
769 do {
770 aRegion.SetMark();
771 // egal in welche Richtung, SPoint ist immer groesser als Mark,
772 // wenn der Suchbereich gueltig ist !!
773 SwPosition *pSttPos = aRegion.GetMark(),
774 *pEndPos = aRegion.GetPoint();
775 *pSttPos = *pTmpCrsr->Start();
776 *pEndPos = *pTmpCrsr->End();
777 if( bSrchBkwrd )
778 aRegion.Exchange();
780 if( !nCrsrCnt && !pPHdl && !bIsUnoCrsr )
781 pPHdl = new _PercentHdl( aRegion );
783 // solange gefunden und nicht auf gleicher Position haengen bleibt
784 while( *pSttPos <= *pEndPos &&
785 0 != ( nFndRet = rParas.Find( pCurCrsr, fnMove,
786 &aRegion, bInReadOnly )) &&
787 ( !pFndRing ||
788 *pFndRing->GetPoint() != *pCurCrsr->GetPoint() ||
789 *pFndRing->GetMark() != *pCurCrsr->GetMark() ))
791 if( !( FIND_NO_RING & nFndRet ))
793 // Bug 24084: Ring richtig herum aufbauen -> gleiche Mimik
794 // wie beim CreateCrsr !!!!
796 SwCursor* pNew = pCurCrsr->Create( pFndRing );
797 if( !pFndRing )
798 pFndRing = pNew;
800 pNew->SetMark();
801 *pNew->GetMark() = *pCurCrsr->GetMark();
804 ++nFound;
806 if( !( eFndRngs & FND_IN_SELALL) )
808 bEnde = TRUE;
809 break;
812 if( coSrchRplcThreshold == nFound && pDoc->DoesUndo()
813 && rParas.IsReplaceMode())
815 short nRet = pCurCrsr->MaxReplaceArived();
816 if( RET_YES == nRet )
818 pDoc->DelAllUndoObj();
819 pDoc->DoUndo( FALSE );
821 else
823 bEnde = TRUE;
824 if(RET_CANCEL == nRet)
826 bCancel = TRUE;
827 //unwind() ??
829 break;
833 if( bSrchBkwrd )
834 // bewege pEndPos vor den gefundenen Bereich
835 *pEndPos = *pCurCrsr->Start();
836 else
837 // bewege pSttPos hinter den gefundenen Bereich
838 *pSttPos = *pCurCrsr->End();
840 if( *pSttPos == *pEndPos ) // im Bereich, aber am Ende
841 break; // fertig
843 if( !nCrsrCnt && pPHdl )
845 pPHdl->NextPos( *aRegion.GetMark() );
849 if( bEnde || !( eFndRngs & ( FND_IN_SELALL | FND_IN_SEL )) )
850 break;
852 pTmpCrsr = ((SwPaM*)pTmpCrsr->GetNext());
853 if( nCrsrCnt && pPHdl )
855 pPHdl->NextPos( ++pPHdl->nActPos );
858 } while( pTmpCrsr != pSaveCrsr );
860 if( nFound && !pFndRing ) // falls kein Ring aufgebaut werden soll
861 pFndRing = pCurCrsr->Create();
863 delete pPHdl;
864 pDoc->DoUndo( bDoesUndo );
865 return nFound;
869 int lcl_MakeSelFwrd( const SwNode& rSttNd, const SwNode& rEndNd,
870 SwPaM& rPam, int bFirst )
872 if( rSttNd.GetIndex() + 1 == rEndNd.GetIndex() )
873 return FALSE;
875 SwNodes& rNds = rPam.GetDoc()->GetNodes();
876 rPam.DeleteMark();
877 SwCntntNode* pCNd;
878 if( !bFirst )
880 rPam.GetPoint()->nNode = rSttNd;
881 pCNd = rNds.GoNext( &rPam.GetPoint()->nNode );
882 if( !pCNd )
883 return FALSE;
884 pCNd->MakeStartIndex( &rPam.GetPoint()->nContent );
886 else if( rSttNd.GetIndex() > rPam.GetPoint()->nNode.GetIndex() ||
887 rPam.GetPoint()->nNode.GetIndex() >= rEndNd.GetIndex() )
888 return FALSE; // steht nicht in dieser Section
890 rPam.SetMark();
891 rPam.GetPoint()->nNode = rEndNd;
892 pCNd = rNds.GoPrevious( &rPam.GetPoint()->nNode );
893 if( !pCNd )
894 return FALSE;
895 pCNd->MakeEndIndex( &rPam.GetPoint()->nContent );
897 return *rPam.GetMark() < *rPam.GetPoint();
901 int lcl_MakeSelBkwrd( const SwNode& rSttNd, const SwNode& rEndNd,
902 SwPaM& rPam, int bFirst )
904 if( rEndNd.GetIndex() + 1 == rSttNd.GetIndex() )
905 return FALSE;
907 SwNodes& rNds = rPam.GetDoc()->GetNodes();
908 rPam.DeleteMark();
909 SwCntntNode* pCNd;
910 if( !bFirst )
912 rPam.GetPoint()->nNode = rSttNd;
913 pCNd = rNds.GoPrevious( &rPam.GetPoint()->nNode );
914 if( !pCNd )
915 return FALSE;
916 pCNd->MakeEndIndex( &rPam.GetPoint()->nContent );
918 else if( rEndNd.GetIndex() > rPam.GetPoint()->nNode.GetIndex() ||
919 rPam.GetPoint()->nNode.GetIndex() >= rSttNd.GetIndex() )
920 return FALSE; // steht nicht in dieser Section
922 rPam.SetMark();
923 rPam.GetPoint()->nNode = rEndNd;
924 pCNd = rNds.GoNext( &rPam.GetPoint()->nNode );
925 if( !pCNd )
926 return FALSE;
927 pCNd->MakeStartIndex( &rPam.GetPoint()->nContent );
929 return *rPam.GetPoint() < *rPam.GetMark();
933 // diese Methode "sucht" fuer alle Anwendungsfaelle, denn in SwFindParas
934 // steht immer die richtigen Parameter und die entsprechende Find-Methode
936 ULONG SwCursor::FindAll( SwFindParas& rParas,
937 SwDocPositions nStart, SwDocPositions nEnde,
938 FindRanges eFndRngs, BOOL& bCancel )
940 bCancel = FALSE;
941 SwCrsrSaveState aSaveState( *this );
943 // Region erzeugen, ohne das diese in den Ring aufgenommen wird !
944 SwPaM aRegion( *GetPoint() );
945 SwMoveFn fnMove = MakeFindRange( nStart, nEnde, &aRegion );
947 ULONG nFound = 0;
948 int bMvBkwrd = fnMove == fnMoveBackward;
949 BOOL bInReadOnly = IsReadOnlyAvailable();
951 SwCursor* pFndRing = 0;
952 SwNodes& rNds = GetDoc()->GetNodes();
954 // suche in Bereichen ?
955 if( FND_IN_SEL & eFndRngs )
957 // String nicht im Bereich gefunden, dann erhalte alle Bereiche,
958 // der Cursor beleibt unveraendert
959 if( 0 == ( nFound = lcl_FindSelection( rParas, this, fnMove,
960 pFndRing, aRegion, eFndRngs,
961 bInReadOnly, bCancel ) ))
962 return nFound;
964 // der String wurde ein- bis mehrmals gefunden. Das steht alles
965 // im neuen Crsr-Ring. Darum hebe erstmal den alten Ring auf
966 while( GetNext() != this )
967 delete GetNext();
969 *GetPoint() = *pFndRing->GetPoint();
970 SetMark();
971 *GetMark() = *pFndRing->GetMark();
972 pFndRing->MoveRingTo( this );
973 delete pFndRing;
975 else if( FND_IN_OTHER & eFndRngs )
977 // Cursor als Kopie vom akt. und in den Ring aufnehmen
978 // Verkettung zeigt immer auf den zuerst erzeugten, also vorwaerts
979 SwCursor* pSav = Create( this ); // sicher den aktuellen Crsr
981 // wenn schon ausserhalb vom Bodytext, suche von der Position,
982 // ansonsten beginne mit der 1. GrundSection
983 if( bMvBkwrd
984 ? lcl_MakeSelBkwrd( rNds.GetEndOfExtras(),
985 *rNds.GetEndOfPostIts().StartOfSectionNode(),
986 *this, rNds.GetEndOfExtras().GetIndex() >=
987 GetPoint()->nNode.GetIndex() )
988 : lcl_MakeSelFwrd( *rNds.GetEndOfPostIts().StartOfSectionNode(),
989 rNds.GetEndOfExtras(), *this,
990 rNds.GetEndOfExtras().GetIndex() >=
991 GetPoint()->nNode.GetIndex() ))
993 nFound = lcl_FindSelection( rParas, this, fnMove, pFndRing,
994 aRegion, eFndRngs, bInReadOnly, bCancel );
997 if( !nFound )
999 // den alten wieder zurueck
1000 *GetPoint() = *pSav->GetPoint();
1001 if( pSav->HasMark() )
1003 SetMark();
1004 *GetMark() = *pSav->GetMark();
1006 else
1007 DeleteMark();
1008 return 0;
1011 delete pSav;
1012 if( !( FND_IN_SELALL & eFndRngs ))
1014 // es sollte nur einer gesucht werden, also fuege in dazu
1015 // egal in welche Richtung, SPoint ist immer groesser als Mark,
1016 // wenn der Suchbereich gueltig ist !!
1017 *GetPoint() = *pFndRing->GetPoint();
1018 SetMark();
1019 *GetMark() = *pFndRing->GetMark();
1021 else
1023 // es wurde ein- bis mehrmals gefunden. Das steht alles
1024 // im neuen Crsr-Ring. Darum hebe erstmal den alten Ring auf
1025 while( GetNext() != this )
1026 delete GetNext();
1028 *GetPoint() = *pFndRing->GetPoint();
1029 SetMark();
1030 *GetMark() = *pFndRing->GetMark();
1031 pFndRing->MoveRingTo( this );
1033 delete pFndRing;
1035 else if( FND_IN_SELALL & eFndRngs )
1037 SwCursor* pSav = Create( this ); // sicher den aktuellen Crsr
1039 const SwNode* pSttNd = ( FND_IN_BODYONLY & eFndRngs )
1040 ? rNds.GetEndOfContent().StartOfSectionNode()
1041 : rNds.GetEndOfPostIts().StartOfSectionNode();
1043 if( bMvBkwrd
1044 ? lcl_MakeSelBkwrd( rNds.GetEndOfContent(), *pSttNd,*this, FALSE )
1045 : lcl_MakeSelFwrd( *pSttNd, rNds.GetEndOfContent(), *this, FALSE ))
1047 nFound = lcl_FindSelection( rParas, this, fnMove, pFndRing,
1048 aRegion, eFndRngs, bInReadOnly, bCancel );
1051 if( !nFound )
1053 // den alten wieder zurueck
1054 *GetPoint() = *pSav->GetPoint();
1055 if( pSav->HasMark() )
1057 SetMark();
1058 *GetMark() = *pSav->GetMark();
1060 else
1061 DeleteMark();
1062 return 0;
1064 // es wurde ein- bis mehrmals gefunden. Das steht alles
1065 // im neuen Crsr-Ring. Darum hebe erstmal den alten Ring auf
1066 delete pSav;
1068 while( GetNext() != this )
1069 delete GetNext();
1071 *GetPoint() = *pFndRing->GetPoint();
1072 SetMark();
1073 *GetMark() = *pFndRing->GetMark();
1074 pFndRing->MoveRingTo( this );
1075 delete pFndRing;
1077 else
1079 // ist ein GetMark gesetzt, dann wird bei gefundenem Object
1080 // der GetMark beibehalten !! Dadurch kann ein Bereich mit der Suche
1081 // aufgespannt werden.
1082 SwPosition aMarkPos( *GetMark() );
1083 int bMarkPos = HasMark() && !eFndRngs;
1085 if( 0 != (nFound = rParas.Find( this, fnMove,
1086 &aRegion, bInReadOnly ) ? 1 : 0)
1087 && bMarkPos )
1088 *GetMark() = aMarkPos;
1091 if( nFound && SwCursor::IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE ) )
1092 nFound = 0;
1093 return nFound;
1097 void SwCursor::FillFindPos( SwDocPositions ePos, SwPosition& rPos ) const
1099 BOOL bIsStart = TRUE;
1100 SwCntntNode* pCNd = 0;
1101 SwNodes& rNds = GetDoc()->GetNodes();
1103 switch( ePos )
1105 case DOCPOS_START:
1106 rPos.nNode = *rNds.GetEndOfContent().StartOfSectionNode();
1107 pCNd = rNds.GoNext( &rPos.nNode );
1108 break;
1110 case DOCPOS_END:
1111 rPos.nNode = rNds.GetEndOfContent();
1112 pCNd = rNds.GoPrevious( &rPos.nNode );
1113 bIsStart = FALSE;
1114 break;
1116 case DOCPOS_OTHERSTART:
1117 rPos.nNode = *rNds[ ULONG(0) ];
1118 pCNd = rNds.GoNext( &rPos.nNode );
1119 break;
1121 case DOCPOS_OTHEREND:
1122 rPos.nNode = *rNds.GetEndOfContent().StartOfSectionNode();
1123 pCNd = rNds.GoPrevious( &rPos.nNode );
1124 bIsStart = FALSE;
1125 break;
1127 // case DOCPOS_CURR:
1128 default:
1129 rPos = *GetPoint();
1132 if( pCNd )
1134 xub_StrLen nCPos = 0;
1135 if( !bIsStart )
1136 nCPos = pCNd->Len();
1137 rPos.nContent.Assign( pCNd, nCPos );
1141 short SwCursor::MaxReplaceArived()
1143 return RET_YES;
1147 BOOL SwCursor::IsStartWord() const
1149 return IsStartWordWT( WordType::ANYWORD_IGNOREWHITESPACES );
1152 BOOL SwCursor::IsEndWord() const
1154 return IsEndWordWT( WordType::ANYWORD_IGNOREWHITESPACES );
1157 BOOL SwCursor::IsInWord() const
1159 return IsInWordWT( WordType::ANYWORD_IGNOREWHITESPACES );
1162 BOOL SwCursor::GoStartWord()
1164 return GoStartWordWT( WordType::ANYWORD_IGNOREWHITESPACES );
1167 BOOL SwCursor::GoEndWord()
1169 return GoEndWordWT( WordType::ANYWORD_IGNOREWHITESPACES );
1172 BOOL SwCursor::GoNextWord()
1174 return GoNextWordWT( WordType::ANYWORD_IGNOREWHITESPACES );
1177 BOOL SwCursor::GoPrevWord()
1179 return GoPrevWordWT( WordType::ANYWORD_IGNOREWHITESPACES );
1182 BOOL SwCursor::SelectWord( const Point* pPt )
1184 return SelectWordWT( WordType::ANYWORD_IGNOREWHITESPACES, pPt );
1187 BOOL SwCursor::IsStartWordWT( sal_Int16 nWordType ) const
1189 BOOL bRet = FALSE;
1190 const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
1191 if( pTxtNd && pBreakIt->GetBreakIter().is() )
1193 xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
1194 bRet = pBreakIt->GetBreakIter()->isBeginWord(
1195 pTxtNd->GetTxt(), nPtPos,
1196 pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos )),
1197 nWordType );
1199 return bRet;
1202 BOOL SwCursor::IsEndWordWT( sal_Int16 nWordType ) const
1204 BOOL bRet = FALSE;
1205 const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
1206 if( pTxtNd && pBreakIt->GetBreakIter().is() )
1208 xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
1209 bRet = pBreakIt->GetBreakIter()->isEndWord(
1210 pTxtNd->GetTxt(), nPtPos,
1211 pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos ) ),
1212 nWordType );
1215 return bRet;
1218 BOOL SwCursor::IsInWordWT( sal_Int16 nWordType ) const
1220 BOOL bRet = FALSE;
1221 const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
1222 if( pTxtNd && pBreakIt->GetBreakIter().is() )
1224 xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
1225 Boundary aBoundary = pBreakIt->GetBreakIter()->getWordBoundary(
1226 pTxtNd->GetTxt(), nPtPos,
1227 pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos ) ),
1228 nWordType,
1229 TRUE );
1231 bRet = aBoundary.startPos != aBoundary.endPos &&
1232 aBoundary.startPos <= nPtPos &&
1233 nPtPos <= aBoundary.endPos;
1234 if(bRet)
1236 const CharClass& rCC = GetAppCharClass();
1237 bRet = rCC.isLetterNumeric( pTxtNd->GetTxt(), static_cast<xub_StrLen>(aBoundary.startPos) );
1240 return bRet;
1243 BOOL SwCursor::IsStartEndSentence( bool bEnd ) const
1245 BOOL bRet = bEnd ?
1246 GetCntntNode() && GetPoint()->nContent == GetCntntNode()->Len() :
1247 GetPoint()->nContent.GetIndex() == 0;
1249 if( !bRet )
1251 SwCursor aCrsr(*GetPoint(), 0, false);
1252 SwPosition aOrigPos = *aCrsr.GetPoint();
1253 aCrsr.GoSentence( bEnd ? SwCursor::END_SENT : SwCursor::START_SENT );
1254 bRet = aOrigPos == *aCrsr.GetPoint();
1257 return bRet;
1260 BOOL SwCursor::GoStartWordWT( sal_Int16 nWordType )
1262 BOOL bRet = FALSE;
1263 const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
1264 if( pTxtNd && pBreakIt->GetBreakIter().is() )
1266 SwCrsrSaveState aSave( *this );
1267 xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
1268 nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->getWordBoundary(
1269 pTxtNd->GetTxt(), nPtPos,
1270 pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos ) ),
1271 nWordType,
1272 FALSE ).startPos;
1274 if( nPtPos < pTxtNd->GetTxt().Len() )
1276 GetPoint()->nContent = nPtPos;
1277 if( !IsSelOvr() )
1278 bRet = TRUE;
1281 return bRet;
1284 BOOL SwCursor::GoEndWordWT( sal_Int16 nWordType )
1286 BOOL bRet = FALSE;
1287 const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
1288 if( pTxtNd && pBreakIt->GetBreakIter().is() )
1290 SwCrsrSaveState aSave( *this );
1291 xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
1292 nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->getWordBoundary(
1293 pTxtNd->GetTxt(), nPtPos,
1294 pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos ) ),
1295 nWordType,
1296 TRUE ).endPos;
1298 if( nPtPos <= pTxtNd->GetTxt().Len() &&
1299 GetPoint()->nContent.GetIndex() != nPtPos )
1301 GetPoint()->nContent = nPtPos;
1302 if( !IsSelOvr() )
1303 bRet = TRUE;
1306 return bRet;
1309 BOOL SwCursor::GoNextWordWT( sal_Int16 nWordType )
1311 BOOL bRet = FALSE;
1312 const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
1313 if( pTxtNd && pBreakIt->GetBreakIter().is() )
1315 SwCrsrSaveState aSave( *this );
1316 xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
1318 nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->nextWord(
1319 pTxtNd->GetTxt(), nPtPos,
1320 pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos, 1 ) ),
1321 nWordType ).startPos;
1323 if( nPtPos < pTxtNd->GetTxt().Len() )
1325 GetPoint()->nContent = nPtPos;
1326 if( !IsSelOvr() )
1327 bRet = TRUE;
1330 return bRet;
1333 BOOL SwCursor::GoPrevWordWT( sal_Int16 nWordType )
1335 BOOL bRet = FALSE;
1336 const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
1337 if( pTxtNd && pBreakIt->GetBreakIter().is() )
1339 SwCrsrSaveState aSave( *this );
1340 xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
1341 const xub_StrLen nPtStart = nPtPos;
1343 if( nPtPos )
1344 --nPtPos;
1345 nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->previousWord(
1346 pTxtNd->GetTxt(), nPtStart,
1347 pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos, 1 ) ),
1348 nWordType ).startPos;
1350 if( nPtPos < pTxtNd->GetTxt().Len() )
1352 GetPoint()->nContent = nPtPos;
1353 if( !IsSelOvr() )
1354 bRet = TRUE;
1357 return bRet;
1360 BOOL SwCursor::SelectWordWT( sal_Int16 nWordType, const Point* pPt )
1362 SwCrsrSaveState aSave( *this );
1364 BOOL bRet = FALSE;
1365 BOOL bForward = TRUE;
1366 DeleteMark();
1367 SwRootFrm* pLayout;
1368 if( pPt && 0 != (pLayout = GetDoc()->GetRootFrm()) )
1370 // set the cursor to the layout position
1371 Point aPt( *pPt );
1372 pLayout->GetCrsrOfst( GetPoint(), aPt );
1375 const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
1376 if( pTxtNd && pBreakIt->GetBreakIter().is() )
1378 xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
1379 Boundary aBndry( pBreakIt->GetBreakIter()->getWordBoundary(
1380 pTxtNd->GetTxt(), nPtPos,
1381 pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos ) ),
1382 nWordType,
1383 bForward ));
1385 if( aBndry.startPos != aBndry.endPos )
1387 GetPoint()->nContent = (xub_StrLen)aBndry.endPos;
1388 if( !IsSelOvr() )
1390 SetMark();
1391 GetMark()->nContent = (xub_StrLen)aBndry.startPos;
1392 if( !IsSelOvr() )
1393 bRet = TRUE;
1398 if( !bRet )
1400 DeleteMark();
1401 RestoreSavePos();
1403 return bRet;
1406 //-----------------------------------------------------------------------------
1407 BOOL SwCursor::GoSentence( SentenceMoveType eMoveType )
1409 BOOL bRet = FALSE;
1410 const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
1411 if( pTxtNd && pBreakIt->GetBreakIter().is() )
1413 //mask deleted redlines
1414 String sNodeText(pTxtNd->GetTxt());
1415 const SwDoc& rDoc = *pTxtNd->GetDoc();
1416 const bool nShowChg = IDocumentRedlineAccess::IsShowChanges( rDoc.GetRedlineMode() );
1417 if ( nShowChg )
1419 USHORT nAct = rDoc.GetRedlinePos( *pTxtNd, USHRT_MAX );
1420 for ( ; nAct < rDoc.GetRedlineTbl().Count(); nAct++ )
1422 const SwRedline* pRed = rDoc.GetRedlineTbl()[ nAct ];
1423 if ( pRed->Start()->nNode > pTxtNd->GetIndex() )
1424 break;
1426 if( nsRedlineType_t::REDLINE_DELETE == pRed->GetType() )
1428 xub_StrLen nStart, nEnd;
1429 pRed->CalcStartEnd( pTxtNd->GetIndex(), nStart, nEnd );
1431 while ( nStart < nEnd && nStart < sNodeText.Len() )
1432 sNodeText.SetChar( nStart++, CH_TXTATR_INWORD );
1436 SwCrsrSaveState aSave( *this );
1437 xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
1438 switch ( eMoveType )
1440 case END_SENT:
1441 nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->endOfSentence(
1442 sNodeText,
1443 nPtPos, pBreakIt->GetLocale(
1444 pTxtNd->GetLang( nPtPos ) ));
1445 break;
1446 case NEXT_SENT:
1448 nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->endOfSentence(
1449 sNodeText,
1450 nPtPos, pBreakIt->GetLocale(
1451 pTxtNd->GetLang( nPtPos ) ));
1452 while (nPtPos != (USHORT) -1 && ++nPtPos < sNodeText.Len()
1453 && sNodeText.GetChar(nPtPos)== ' ' /*isWhiteSpace( aTxt.GetChar(nPtPos)*/ )
1455 break;
1457 case START_SENT:
1458 nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->beginOfSentence(
1459 sNodeText,
1460 nPtPos, pBreakIt->GetLocale(
1461 pTxtNd->GetLang( nPtPos ) ));
1462 break;
1463 case PREV_SENT:
1464 nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->beginOfSentence(
1465 sNodeText,
1466 nPtPos, pBreakIt->GetLocale(
1467 pTxtNd->GetLang( nPtPos ) ));
1468 if (nPtPos == 0)
1469 return FALSE; // the previous sentence is not in this paragraph
1470 if (nPtPos > 0)
1471 nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->beginOfSentence(
1472 sNodeText,
1473 nPtPos - 1, pBreakIt->GetLocale(
1474 pTxtNd->GetLang( nPtPos ) ));
1475 break;
1478 // it is allowed to place the PaM just behind the last
1479 // character in the text thus <= ...Len
1480 if( nPtPos <= pTxtNd->GetTxt().Len() )
1482 GetPoint()->nContent = nPtPos;
1483 if( !IsSelOvr() )
1484 bRet = TRUE;
1487 return bRet;
1490 BOOL SwTableCursor::LeftRight( BOOL bLeft, USHORT nCnt, USHORT /*nMode*/,
1491 BOOL /*bVisualAllowed*/, BOOL /*bSkipHidden*/, BOOL /*bInsertCrsr*/ )
1493 return bLeft ? GoPrevCell( nCnt )
1494 : GoNextCell( nCnt );
1498 // calculate cursor bidi level: extracted from LeftRight()
1499 const SwCntntFrm*
1500 SwCursor::DoSetBidiLevelLeftRight(
1501 BOOL & io_rbLeft, BOOL bVisualAllowed, BOOL bInsertCrsr)
1503 // calculate cursor bidi level
1504 const SwCntntFrm* pSttFrm = NULL;
1505 SwNode& rNode = GetPoint()->nNode.GetNode();
1507 if( rNode.IsTxtNode() )
1509 const SwTxtNode& rTNd = *rNode.GetTxtNode();
1510 SwIndex& rIdx = GetPoint()->nContent;
1511 xub_StrLen nPos = rIdx.GetIndex();
1513 const SvtCTLOptions& rCTLOptions = SW_MOD()->GetCTLOptions();
1514 if ( bVisualAllowed && rCTLOptions.IsCTLFontEnabled() &&
1515 SvtCTLOptions::MOVEMENT_VISUAL ==
1516 rCTLOptions.GetCTLCursorMovement() )
1518 // for visual cursor travelling (used in bidi layout)
1519 // we first have to convert the logic to a visual position
1520 Point aPt;
1521 pSttFrm = rTNd.GetFrm( &aPt, GetPoint() );
1522 if( pSttFrm )
1524 BYTE nCrsrLevel = GetCrsrBidiLevel();
1525 sal_Bool bForward = ! io_rbLeft;
1526 ((SwTxtFrm*)pSttFrm)->PrepareVisualMove( nPos, nCrsrLevel,
1527 bForward, bInsertCrsr );
1528 rIdx = nPos;
1529 SetCrsrBidiLevel( nCrsrLevel );
1530 io_rbLeft = ! bForward;
1533 else
1535 const SwScriptInfo* pSI = SwScriptInfo::GetScriptInfo( rTNd );
1536 if ( pSI )
1538 const xub_StrLen nMoveOverPos = io_rbLeft ?
1539 ( nPos ? nPos - 1 : 0 ) :
1540 nPos;
1541 SetCrsrBidiLevel( pSI->DirType( nMoveOverPos ) );
1545 return pSttFrm;
1548 BOOL SwCursor::LeftRight( BOOL bLeft, USHORT nCnt, USHORT nMode,
1549 BOOL bVisualAllowed,BOOL bSkipHidden, BOOL bInsertCrsr )
1551 // calculate cursor bidi level
1552 SwNode& rNode = GetPoint()->nNode.GetNode();
1553 const SwCntntFrm* pSttFrm = // may side-effect bLeft!
1554 DoSetBidiLevelLeftRight(bLeft, bVisualAllowed, bInsertCrsr);
1556 // kann der Cursor n-mal weiterverschoben werden ?
1557 SwCrsrSaveState aSave( *this );
1558 SwMoveFn fnMove = bLeft ? fnMoveBackward : fnMoveForward;
1560 SwGoInDoc fnGo;
1561 if ( bSkipHidden )
1562 fnGo = CRSR_SKIP_CELLS == nMode ? fnGoCntntCellsSkipHidden : fnGoCntntSkipHidden;
1563 else
1564 fnGo = CRSR_SKIP_CELLS == nMode ? fnGoCntntCells : fnGoCntnt;
1566 // ASSERT( not in covered cell )
1568 while( nCnt )
1570 SwNodeIndex aOldNodeIdx( GetPoint()->nNode );
1572 bool bSuccess = Move( fnMove, fnGo );
1573 if ( !bSuccess )
1574 break;
1576 // If we were located inside a covered cell but our position has been
1577 // corrected, we check if the last move has moved the cursor to a different
1578 // table cell. In this case we set the cursor to the stored covered position
1579 // and redo the move:
1580 if ( mnRowSpanOffset )
1582 const SwNode* pOldTabBoxSttNode = aOldNodeIdx.GetNode().FindTableBoxStartNode();
1583 const SwTableNode* pOldTabSttNode = pOldTabBoxSttNode ? pOldTabBoxSttNode->FindTableNode() : 0;
1584 const SwNode* pNewTabBoxSttNode = GetPoint()->nNode.GetNode().FindTableBoxStartNode();
1585 const SwTableNode* pNewTabSttNode = pNewTabBoxSttNode ? pNewTabBoxSttNode->FindTableNode() : 0;
1587 const bool bCellChanged = pOldTabSttNode && pNewTabSttNode &&
1588 pOldTabSttNode == pNewTabSttNode &&
1589 pOldTabBoxSttNode && pNewTabBoxSttNode &&
1590 pOldTabBoxSttNode != pNewTabBoxSttNode;
1592 if ( bCellChanged )
1594 // Set cursor to start/end of covered cell:
1595 SwTableBox* pTableBox = pOldTabBoxSttNode->GetTblBox();
1596 const long nRowSpan = pTableBox->getRowSpan();
1597 if ( nRowSpan > 1 )
1599 pTableBox = & pTableBox->FindEndOfRowSpan( pOldTabSttNode->GetTable(), (USHORT)(pTableBox->getRowSpan() + mnRowSpanOffset ) );
1600 SwNodeIndex& rPtIdx = GetPoint()->nNode;
1601 SwNodeIndex aNewIdx( *pTableBox->GetSttNd() );
1602 rPtIdx = aNewIdx;
1604 GetDoc()->GetNodes().GoNextSection( &rPtIdx, FALSE, FALSE );
1605 SwCntntNode* pCntntNode = GetCntntNode();
1606 if ( pCntntNode )
1608 const xub_StrLen nTmpPos = bLeft ? pCntntNode->Len() : 0;
1609 GetPoint()->nContent.Assign( pCntntNode, nTmpPos );
1611 // Redo the move:
1612 bSuccess = Move( fnMove, fnGo );
1613 if ( !bSuccess )
1614 break;
1618 mnRowSpanOffset = 0;
1622 // Check if I'm inside a covered cell. Correct cursor if necessary and
1623 // store covered cell:
1624 const SwNode* pTableBoxStartNode = GetPoint()->nNode.GetNode().FindTableBoxStartNode();
1625 if ( pTableBoxStartNode )
1627 const SwTableBox* pTableBox = pTableBoxStartNode->GetTblBox();
1628 if ( pTableBox->getRowSpan() < 1 )
1630 // Store the row span offset:
1631 mnRowSpanOffset = pTableBox->getRowSpan();
1633 // Move cursor to non-covered cell:
1634 const SwTableNode* pTblNd = pTableBoxStartNode->FindTableNode();
1635 pTableBox = & pTableBox->FindStartOfRowSpan( pTblNd->GetTable(), USHRT_MAX );
1636 SwNodeIndex& rPtIdx = GetPoint()->nNode;
1637 SwNodeIndex aNewIdx( *pTableBox->GetSttNd() );
1638 rPtIdx = aNewIdx;
1640 GetDoc()->GetNodes().GoNextSection( &rPtIdx, FALSE, FALSE );
1641 SwCntntNode* pCntntNode = GetCntntNode();
1642 if ( pCntntNode )
1644 const xub_StrLen nTmpPos = bLeft ? pCntntNode->Len() : 0;
1645 GetPoint()->nContent.Assign( pCntntNode, nTmpPos );
1650 --nCnt;
1653 // here come some special rules for visual cursor travelling
1654 if ( pSttFrm )
1656 SwNode& rTmpNode = GetPoint()->nNode.GetNode();
1657 if ( &rTmpNode != &rNode && rTmpNode.IsTxtNode() )
1659 Point aPt;
1660 const SwCntntFrm* pEndFrm = ((SwTxtNode&)rTmpNode).GetFrm( &aPt, GetPoint() );
1661 if ( pEndFrm )
1663 if ( ! pEndFrm->IsRightToLeft() != ! pSttFrm->IsRightToLeft() )
1665 if ( ! bLeft )
1666 pEndFrm->RightMargin( this );
1667 else
1668 pEndFrm->LeftMargin( this );
1674 return 0 == nCnt && !IsInProtectTable( TRUE ) &&
1675 !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
1676 nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
1679 // calculate cursor bidi level: extracted from UpDown()
1680 void SwCursor::DoSetBidiLevelUpDown()
1682 SwNode& rNode = GetPoint()->nNode.GetNode();
1683 if ( rNode.IsTxtNode() )
1685 const SwScriptInfo* pSI =
1686 SwScriptInfo::GetScriptInfo( (SwTxtNode&)rNode );
1687 if ( pSI )
1689 SwIndex& rIdx = GetPoint()->nContent;
1690 xub_StrLen nPos = rIdx.GetIndex();
1692 if( nPos && nPos < ((SwTxtNode&)rNode).GetTxt().Len() )
1694 const BYTE nCurrLevel = pSI->DirType( nPos );
1695 const BYTE nPrevLevel = pSI->DirType( nPos - 1 );
1697 if ( nCurrLevel % 2 != nPrevLevel % 2 )
1699 // set cursor level to the lower of the two levels
1700 SetCrsrBidiLevel( Min( nCurrLevel, nPrevLevel ) );
1702 else
1703 SetCrsrBidiLevel( nCurrLevel );
1709 BOOL SwCursor::UpDown( BOOL bUp, USHORT nCnt,
1710 Point* pPt, long nUpDownX )
1712 SwTableCursor* pTblCrsr = dynamic_cast<SwTableCursor*>(this);
1713 sal_Bool bAdjustTableCrsr = sal_False;
1715 // vom Tabellen Crsr Point/Mark in der gleichen Box ??
1716 // dann stelle den Point an den Anfang der Box
1717 if( pTblCrsr && GetNode( TRUE )->StartOfSectionNode() ==
1718 GetNode( FALSE )->StartOfSectionNode() )
1720 if ( End() != GetPoint() )
1721 Exchange();
1722 bAdjustTableCrsr = sal_True;
1725 BOOL bRet = FALSE;
1726 Point aPt;
1727 if( pPt )
1728 aPt = *pPt;
1729 SwCntntFrm* pFrm = GetCntntNode()->GetFrm( &aPt, GetPoint() );
1731 if( pFrm )
1733 SwCrsrSaveState aSave( *this );
1735 if( !pPt )
1737 SwRect aTmpRect;
1738 pFrm->GetCharRect( aTmpRect, *GetPoint() );
1739 aPt = aTmpRect.Pos();
1741 nUpDownX = pFrm->IsVertical() ?
1742 aPt.Y() - pFrm->Frm().Top() :
1743 aPt.X() - pFrm->Frm().Left();
1746 // Bei Fussnoten ist auch die Bewegung in eine andere Fussnote erlaubt.
1747 // aber keine Selection!!
1748 const BOOL bChkRange = pFrm->IsInFtn() && !HasMark()
1749 ? FALSE : TRUE;
1750 const SwPosition aOldPos( *GetPoint() );
1751 BOOL bInReadOnly = IsReadOnlyAvailable();
1753 if ( bAdjustTableCrsr && !bUp )
1755 // Special case: We have a table cursor but the start box
1756 // has more than one paragraph. If we want to go down, we have to
1757 // set the point to the last frame in the table box. This is
1758 // only necessary if we do not already have a table selection
1759 const SwStartNode* pTblNd = GetNode( TRUE )->FindTableBoxStartNode();
1760 ASSERT( pTblNd, "pTblCrsr without SwTableNode?" )
1762 if ( pTblNd ) // safety first
1764 const SwNode* pEndNd = pTblNd->EndOfSectionNode();
1765 GetPoint()->nNode = *pEndNd;
1766 pTblCrsr->Move( fnMoveBackward, fnGoNode );
1767 pFrm = GetCntntNode()->GetFrm( &aPt, GetPoint() );
1771 while( nCnt &&
1772 (bUp ? pFrm->UnitUp( this, nUpDownX, bInReadOnly )
1773 : pFrm->UnitDown( this, nUpDownX, bInReadOnly ) ) &&
1774 CheckNodesRange( aOldPos.nNode, GetPoint()->nNode, bChkRange ))
1776 pFrm = GetCntntNode()->GetFrm( &aPt, GetPoint() );
1777 --nCnt;
1780 if( !nCnt && !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
1781 nsSwCursorSelOverFlags::SELOVER_CHANGEPOS ) ) // die gesamte Anzahl durchlaufen ?
1783 if( !pTblCrsr )
1785 // dann versuche den Cursor auf die Position zu setzen,
1786 // auf halber Heohe vom Char-Rectangle
1787 pFrm = GetCntntNode()->GetFrm( &aPt, GetPoint() );
1788 SwCrsrMoveState eTmpState( MV_UPDOWN );
1789 eTmpState.bSetInReadOnly = bInReadOnly;
1790 SwRect aTmpRect;
1791 pFrm->GetCharRect( aTmpRect, *GetPoint(), &eTmpState );
1792 if ( pFrm->IsVertical() )
1794 aPt.X() = aTmpRect.Center().X();
1795 pFrm->Calc();
1796 aPt.Y() = pFrm->Frm().Top() + nUpDownX;
1798 else
1800 aPt.Y() = aTmpRect.Center().Y();
1801 pFrm->Calc();
1802 aPt.X() = pFrm->Frm().Left() + nUpDownX;
1804 pFrm->GetCrsrOfst( GetPoint(), aPt, &eTmpState );
1806 bRet = TRUE;
1808 else
1809 *GetPoint() = aOldPos;
1811 DoSetBidiLevelUpDown(); // calculate cursor bidi level
1814 return bRet;
1817 BOOL SwCursor::LeftRightMargin( BOOL bLeft, BOOL bAPI )
1819 Point aPt;
1820 SwCntntFrm * pFrm = GetCntntNode()->GetFrm( &aPt, GetPoint() );
1822 // calculate cursor bidi level
1823 if ( pFrm )
1824 SetCrsrBidiLevel( pFrm->IsRightToLeft() ? 1 : 0 );
1826 return pFrm && (bLeft ? pFrm->LeftMargin( this ) :
1827 pFrm->RightMargin( this, bAPI ) );
1830 BOOL SwCursor::IsAtLeftRightMargin( BOOL bLeft, BOOL bAPI ) const
1832 BOOL bRet = FALSE;
1833 Point aPt;
1834 SwCntntFrm * pFrm = GetCntntNode()->GetFrm( &aPt, GetPoint() );
1835 if( pFrm )
1837 SwPaM aPam( *GetPoint() );
1838 if( !bLeft && aPam.GetPoint()->nContent.GetIndex() )
1839 aPam.GetPoint()->nContent--;
1840 bRet = (bLeft ? pFrm->LeftMargin( &aPam )
1841 : pFrm->RightMargin( &aPam, bAPI ))
1842 && *aPam.GetPoint() == *GetPoint();
1844 return bRet;
1847 BOOL SwCursor::SttEndDoc( BOOL bStt )
1849 SwCrsrSaveState aSave( *this );
1851 // Springe beim Selektieren nie ueber Section-Grenzen !!
1852 // kann der Cursor weiterverschoben werden ?
1853 SwMoveFn fnMove = bStt ? fnMoveBackward : fnMoveForward;
1854 BOOL bRet = (!HasMark() || !IsNoCntnt() ) &&
1855 Move( fnMove, fnGoDoc ) &&
1856 !IsInProtectTable( TRUE ) &&
1857 !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
1858 nsSwCursorSelOverFlags::SELOVER_CHANGEPOS |
1859 nsSwCursorSelOverFlags::SELOVER_ENABLEREVDIREKTION );
1861 return bRet;
1864 BOOL SwCursor::GoPrevNextCell( BOOL bNext, USHORT nCnt )
1866 const SwTableNode* pTblNd = GetPoint()->nNode.GetNode().FindTableNode();
1867 if( !pTblNd )
1868 return FALSE;
1870 // liegt vor dem StartNode der Cell ein weiterer EndNode, dann
1871 // gibt es auch eine vorherige Celle
1872 SwCrsrSaveState aSave( *this );
1873 SwNodeIndex& rPtIdx = GetPoint()->nNode;
1875 while( nCnt-- )
1877 const SwNode* pTableBoxStartNode = rPtIdx.GetNode().FindTableBoxStartNode();
1878 const SwTableBox* pTableBox = pTableBoxStartNode->GetTblBox();
1880 // Check if we have to move the cursor to a covered cell before
1881 // proceeding:
1882 if ( mnRowSpanOffset )
1884 if ( pTableBox->getRowSpan() > 1 )
1886 pTableBox = & pTableBox->FindEndOfRowSpan( pTblNd->GetTable(), (USHORT)(pTableBox->getRowSpan() + mnRowSpanOffset) );
1887 SwNodeIndex aNewIdx( *pTableBox->GetSttNd() );
1888 rPtIdx = aNewIdx;
1889 pTableBoxStartNode = rPtIdx.GetNode().FindTableBoxStartNode();
1891 mnRowSpanOffset = 0;
1894 const SwNode* pTmpNode = bNext ?
1895 pTableBoxStartNode->EndOfSectionNode() :
1896 pTableBoxStartNode;
1898 SwNodeIndex aCellIdx( *pTmpNode, bNext ? 1 : -1 );
1899 if( (bNext && !aCellIdx.GetNode().IsStartNode()) ||
1900 (!bNext && !aCellIdx.GetNode().IsEndNode()) )
1901 return FALSE;
1903 rPtIdx = bNext ? aCellIdx : SwNodeIndex(*aCellIdx.GetNode().StartOfSectionNode());
1905 pTableBoxStartNode = rPtIdx.GetNode().FindTableBoxStartNode();
1906 pTableBox = pTableBoxStartNode->GetTblBox();
1907 if ( pTableBox->getRowSpan() < 1 )
1909 mnRowSpanOffset = pTableBox->getRowSpan();
1910 // move cursor to non-covered cell:
1911 pTableBox = & pTableBox->FindStartOfRowSpan( pTblNd->GetTable(), USHRT_MAX );
1912 SwNodeIndex aNewIdx( *pTableBox->GetSttNd() );
1913 rPtIdx = aNewIdx;
1917 rPtIdx++;
1918 if( !rPtIdx.GetNode().IsCntntNode() )
1919 GetDoc()->GetNodes().GoNextSection( &rPtIdx, TRUE, FALSE );
1920 GetPoint()->nContent.Assign( GetCntntNode(), 0 );
1922 return !IsInProtectTable( TRUE );
1925 BOOL SwTableCursor::GotoTable( const String& /*rName*/ )
1927 return FALSE; // invalid action
1930 BOOL SwCursor::GotoTable( const String& rName )
1932 BOOL bRet = FALSE;
1933 if ( !HasMark() )
1935 SwTable* pTmpTbl = SwTable::FindTable( GetDoc()->FindTblFmtByName( rName ) );
1936 if( pTmpTbl )
1938 // eine Tabelle im normalen NodesArr
1939 SwCrsrSaveState aSave( *this );
1940 GetPoint()->nNode = *pTmpTbl->GetTabSortBoxes()[ 0 ]->
1941 GetSttNd()->FindTableNode();
1942 Move( fnMoveForward, fnGoCntnt );
1943 bRet = !IsSelOvr();
1946 return bRet;
1949 BOOL SwCursor::GotoTblBox( const String& rName )
1951 BOOL bRet = FALSE;
1952 const SwTableNode* pTblNd = GetPoint()->nNode.GetNode().FindTableNode();
1953 if( pTblNd )
1955 // erfrage die Box, mit dem Nanen
1956 const SwTableBox* pTblBox = pTblNd->GetTable().GetTblBox( rName );
1957 if( pTblBox && pTblBox->GetSttNd() &&
1958 ( !pTblBox->GetFrmFmt()->GetProtect().IsCntntProtected() ||
1959 IsReadOnlyAvailable() ) )
1961 SwCrsrSaveState aSave( *this );
1962 GetPoint()->nNode = *pTblBox->GetSttNd();
1963 Move( fnMoveForward, fnGoCntnt );
1964 bRet = !IsSelOvr();
1967 return bRet;
1970 BOOL SwCursor::MovePara(SwWhichPara fnWhichPara, SwPosPara fnPosPara )
1972 //JP 28.8.2001: for optimization test something before
1973 const SwNode* pNd = &GetPoint()->nNode.GetNode();
1974 bool bShortCut = false;
1975 if ( fnWhichPara == fnParaCurr )
1977 // --> FME 2005-02-21 #i41048#
1978 // If fnWhichPara == fnParaCurr, (*fnWhichPara)( *this, fnPosPara )
1979 // can already move the cursor to a different text node. In this case
1980 // we better check if IsSelOvr().
1981 const SwCntntNode* pCntntNd = pNd->GetCntntNode();
1982 if ( pCntntNd )
1984 const xub_StrLen nSttEnd = fnPosPara == fnMoveForward ? 0 : pCntntNd->Len();
1985 if ( GetPoint()->nContent.GetIndex() != nSttEnd )
1986 bShortCut = true;
1988 // <--
1990 else
1992 if ( pNd->IsTxtNode() &&
1993 pNd->GetNodes()[ pNd->GetIndex() +
1994 (fnWhichPara == fnParaNext ? 1 : -1 ) ]->IsTxtNode() )
1995 bShortCut = true;
1998 if ( bShortCut )
1999 return (*fnWhichPara)( *this, fnPosPara );
2001 // else we must use the SaveStructure, because the next/prev is not
2002 // a same node type.
2003 SwCrsrSaveState aSave( *this );
2004 return (*fnWhichPara)( *this, fnPosPara ) &&
2005 !IsInProtectTable( TRUE ) &&
2006 !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
2007 nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
2011 BOOL SwCursor::MoveSection( SwWhichSection fnWhichSect,
2012 SwPosSection fnPosSect)
2014 SwCrsrSaveState aSave( *this );
2015 return (*fnWhichSect)( *this, fnPosSect ) &&
2016 !IsInProtectTable( TRUE ) &&
2017 !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
2018 nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
2022 BOOL MoveTable( SwWhichTable, SwPosTable );
2023 BOOL MoveColumn( SwWhichColumn, SwPosColumn );
2024 BOOL MoveRegion( SwWhichRegion, SwPosRegion );
2027 void SwCursor::RestoreSavePos() // Point auf die SavePos setzen
2029 if( pSavePos )
2031 GetPoint()->nNode = pSavePos->nNode;
2032 GetPoint()->nContent.Assign( GetCntntNode(), pSavePos->nCntnt );
2037 /* \f */
2039 SwTableCursor::SwTableCursor( const SwPosition &rPos, SwPaM* pRing )
2040 : SwCursor( rPos, pRing, false )
2042 bParked = FALSE;
2043 bChg = FALSE;
2044 nTblPtNd = 0, nTblMkNd = 0;
2045 nTblPtCnt = 0, nTblMkCnt = 0;
2048 SwTableCursor::~SwTableCursor() {}
2051 BOOL lcl_SeekEntry( const SwSelBoxes& rTmp, const SwStartNode* pSrch, USHORT& rFndPos )
2053 ULONG nIdx = pSrch->GetIndex();
2055 USHORT nO = rTmp.Count(), nM, nU = 0;
2056 if( nO > 0 )
2058 nO--;
2059 while( nU <= nO )
2061 nM = nU + ( nO - nU ) / 2;
2062 if( rTmp[ nM ]->GetSttNd() == pSrch )
2064 rFndPos = nM;
2065 return TRUE;
2067 else if( rTmp[ nM ]->GetSttIdx() < nIdx )
2068 nU = nM + 1;
2069 else if( nM == 0 )
2070 return FALSE;
2071 else
2072 nO = nM - 1;
2075 return FALSE;
2079 SwCursor* SwTableCursor::MakeBoxSels( SwCursor* pAktCrsr )
2081 if( bChg ) // ???
2083 if( bParked )
2085 // wieder in den Inhalt schieben
2086 Exchange();
2087 Move( fnMoveForward );
2088 Exchange();
2089 Move( fnMoveForward );
2090 bParked = FALSE;
2093 bChg = FALSE;
2095 // temp Kopie anlegen, damit alle Boxen, fuer die schon Cursor
2096 // existieren, entfernt werden koennen.
2097 SwSelBoxes aTmp;
2098 aTmp.Insert( &aSelBoxes );
2100 //Jetzt die Alten und die neuen abgleichen.
2101 SwNodes& rNds = pAktCrsr->GetDoc()->GetNodes();
2102 USHORT nPos;
2103 const SwStartNode* pSttNd;
2104 SwPaM* pCur = pAktCrsr;
2105 do {
2106 BOOL bDel = FALSE;
2107 pSttNd = pCur->GetPoint()->nNode.GetNode().FindTableBoxStartNode();
2108 if( !pCur->HasMark() || !pSttNd ||
2109 pSttNd != pCur->GetMark()->nNode.GetNode().FindTableBoxStartNode() )
2110 bDel = TRUE;
2112 else if( lcl_SeekEntry( aTmp, pSttNd, nPos ))
2114 SwNodeIndex aIdx( *pSttNd, 1 );
2115 const SwNode* pNd = &aIdx.GetNode();
2116 if( !pNd->IsCntntNode() )
2117 pNd = rNds.GoNextSection( &aIdx, TRUE, FALSE );
2119 SwPosition* pPos = pCur->GetMark();
2120 if( pNd != &pPos->nNode.GetNode() )
2121 pPos->nNode = *pNd;
2122 pPos->nContent.Assign( (SwCntntNode*)pNd, 0 );
2124 aIdx.Assign( *pSttNd->EndOfSectionNode(), - 1 );
2125 if( !( pNd = &aIdx.GetNode())->IsCntntNode() )
2126 pNd = rNds.GoPrevSection( &aIdx, TRUE, FALSE );
2128 pPos = pCur->GetPoint();
2129 if( pNd != &pPos->nNode.GetNode() )
2130 pPos->nNode = *pNd;
2131 pPos->nContent.Assign( (SwCntntNode*)pNd, ((SwCntntNode*)pNd)->Len() );
2133 aTmp.Remove( nPos );
2135 else
2136 bDel = TRUE;
2138 pCur = (SwPaM*)pCur->GetNext();
2139 if( bDel )
2141 SwPaM* pDel = (SwPaM*)pCur->GetPrev();
2143 JP 20.07.98: der alte Code geht mit dem UNO-TableCrsr nicht
2144 if( pDel == pAktCrsr )
2146 if( pAktCrsr->GetNext() == pAktCrsr )
2148 pAktCrsr->DeleteMark();
2149 break; // es gibt nichts mehr zu loeschen!
2151 pAktCrsr = (SwCursor*)pDel->GetPrev();
2153 delete pDel;
2156 if( pDel == pAktCrsr )
2157 pAktCrsr->DeleteMark();
2158 else
2159 delete pDel;
2161 } while ( pAktCrsr != pCur );
2163 for( nPos = 0; nPos < aTmp.Count(); ++nPos )
2165 pSttNd = aTmp[ nPos ]->GetSttNd();
2167 SwNodeIndex aIdx( *pSttNd, 1 );
2168 if( &aIdx.GetNodes() != &rNds )
2169 break;
2170 const SwNode* pNd = &aIdx.GetNode();
2171 if( !pNd->IsCntntNode() )
2172 pNd = rNds.GoNextSection( &aIdx, TRUE, FALSE );
2174 SwPaM* pNew;
2175 if( pAktCrsr->GetNext() == pAktCrsr && !pAktCrsr->HasMark() )
2177 pNew = pAktCrsr;
2178 pNew->GetPoint()->nNode = *pNd;
2179 pNew->GetPoint()->nContent.Assign( (SwCntntNode*)pNd, 0 );
2181 else
2183 pNew = pAktCrsr->Create( pAktCrsr );
2184 pNew->GetPoint()->nNode = *pNd;
2185 pNew->GetPoint()->nContent.Assign( (SwCntntNode*)pNd, 0 );
2187 pNew->SetMark();
2189 SwPosition* pPos = pNew->GetPoint();
2190 pPos->nNode.Assign( *pSttNd->EndOfSectionNode(), - 1 );
2191 if( !( pNd = &pPos->nNode.GetNode())->IsCntntNode() )
2192 pNd = rNds.GoPrevSection( &pPos->nNode, TRUE, FALSE );
2194 pPos->nContent.Assign( (SwCntntNode*)pNd, ((SwCntntNode*)pNd)->Len() );
2197 return pAktCrsr;
2201 void SwTableCursor::InsertBox( const SwTableBox& rTblBox )
2203 SwTableBox* pBox = (SwTableBox*)&rTblBox;
2204 aSelBoxes.Insert( pBox );
2205 bChg = TRUE;
2208 bool SwTableCursor::NewTableSelection()
2210 bool bRet = false;
2211 const SwNode *pStart = GetCntntNode()->FindTableBoxStartNode();
2212 const SwNode *pEnd = GetCntntNode(FALSE)->FindTableBoxStartNode();
2213 if( pStart && pEnd )
2215 const SwTableNode *pTableNode = pStart->FindTableNode();
2216 if( pTableNode == pEnd->FindTableNode() &&
2217 pTableNode->GetTable().IsNewModel() )
2219 bRet = true;
2220 SwSelBoxes aNew;
2221 aNew.Insert( &aSelBoxes );
2222 pTableNode->GetTable().CreateSelection( pStart, pEnd, aNew,
2223 SwTable::SEARCH_NONE, false );
2224 ActualizeSelection( aNew );
2227 return bRet;
2230 void SwTableCursor::ActualizeSelection( const SwSelBoxes &rNew )
2232 USHORT nOld = 0, nNew = 0;
2233 while ( nOld < aSelBoxes.Count() && nNew < rNew.Count() )
2235 const SwTableBox* pPOld = *( aSelBoxes.GetData() + nOld );
2236 const SwTableBox* pPNew = *( rNew.GetData() + nNew );
2237 if( pPOld == pPNew )
2238 { // this box will stay
2239 ++nOld;
2240 ++nNew;
2242 else if( pPOld->GetSttIdx() < pPNew->GetSttIdx() )
2243 DeleteBox( nOld ); // this box has to go
2244 else
2246 InsertBox( *pPNew ); // this is a new one
2247 ++nOld;
2248 ++nNew;
2252 while( nOld < aSelBoxes.Count() )
2253 DeleteBox( nOld ); // some more to delete
2255 for( ; nNew < rNew.Count(); ++nNew ) // some more to insert
2256 InsertBox( **( rNew.GetData() + nNew ) );
2259 BOOL SwTableCursor::IsCrsrMovedUpdt()
2261 if( !IsCrsrMoved() )
2262 return FALSE;
2264 nTblMkNd = GetMark()->nNode.GetIndex();
2265 nTblPtNd = GetPoint()->nNode.GetIndex();
2266 nTblMkCnt = GetMark()->nContent.GetIndex();
2267 nTblPtCnt = GetPoint()->nContent.GetIndex();
2268 return TRUE;
2272 // Parke den Tabellen-Cursor auf dem StartNode der Boxen.
2273 void SwTableCursor::ParkCrsr()
2275 // Index aus dem TextNode abmelden
2276 SwNode* pNd = &GetPoint()->nNode.GetNode();
2277 if( !pNd->IsStartNode() )
2278 pNd = pNd->StartOfSectionNode();
2279 GetPoint()->nNode = *pNd;
2280 GetPoint()->nContent.Assign( 0, 0 );
2282 pNd = &GetMark()->nNode.GetNode();
2283 if( !pNd->IsStartNode() )
2284 pNd = pNd->StartOfSectionNode();
2285 GetMark()->nNode = *pNd;
2286 GetMark()->nContent.Assign( 0, 0 );
2288 bChg = TRUE;
2289 bParked = TRUE;
2293 BOOL SwTableCursor::HasReadOnlyBoxSel() const
2295 BOOL bRet = FALSE;
2296 for( USHORT n = aSelBoxes.Count(); n; )
2297 if( aSelBoxes[ --n ]->GetFrmFmt()->GetProtect().IsCntntProtected() )
2299 bRet = TRUE;
2300 break;
2302 return bRet;