Impress Remote 1.0.5, tag sdremote-1.0.5
[LibreOffice.git] / sw / source / core / crsr / crsrsh.cxx
blob379af07d0035290e3cb34df371640a9c91ee50b9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/util/SearchOptions.hpp>
21 #include <com/sun/star/text/XTextRange.hpp>
22 #include <hintids.hxx>
23 #include <svx/svdmodel.hxx>
24 #include <editeng/frmdiritem.hxx>
26 #include <SwSmartTagMgr.hxx>
27 #include <doc.hxx>
28 #include <rootfrm.hxx>
29 #include <pagefrm.hxx>
30 #include <cntfrm.hxx>
31 #include <viewimp.hxx>
32 #include <pam.hxx>
33 #include <swselectionlist.hxx>
34 #include <IBlockCursor.hxx>
35 #include "BlockCursor.hxx"
36 #include <ndtxt.hxx>
37 #include <flyfrm.hxx>
38 #include <dview.hxx>
39 #include <viewopt.hxx>
40 #include <frmtool.hxx>
41 #include <crsrsh.hxx>
42 #include <tabfrm.hxx>
43 #include <txtfrm.hxx>
44 #include <sectfrm.hxx>
45 #include <swtable.hxx>
46 #include <callnk.hxx>
47 #include <viscrs.hxx>
48 #include <section.hxx>
49 #include <docsh.hxx>
50 #include <scriptinfo.hxx>
51 #include <globdoc.hxx>
52 #include <pamtyp.hxx>
53 #include <mdiexp.hxx>
54 #include <fmteiro.hxx>
55 #include <wrong.hxx>
56 #include <unotextrange.hxx>
57 #include <vcl/svapp.hxx>
58 #include <numrule.hxx>
59 #include <IGrammarContact.hxx>
61 #include <globals.hrc>
63 #include <comcore.hrc>
65 using namespace com::sun::star;
66 using namespace util;
68 TYPEINIT2(SwCrsrShell,ViewShell,SwModify);
71 /**
72 * Delete all overlapping Cursors from a Cursor ring.
73 * @param pointer to SwCursor (ring)
75 void CheckRange( SwCursor* );
78 /**
79 * Check if pCurCrsr points into already existing ranges and delete those.
80 * @param Pointer to SwCursor object
82 void CheckRange( SwCursor* pCurCrsr )
84 const SwPosition *pStt = pCurCrsr->Start(),
85 *pEnd = pCurCrsr->GetPoint() == pStt ? pCurCrsr->GetMark() : pCurCrsr->GetPoint();
87 SwPaM *pTmpDel = 0,
88 *pTmp = (SwPaM*)pCurCrsr->GetNext();
90 // Search the complete ring
91 while( pTmp != pCurCrsr )
93 const SwPosition *pTmpStt = pTmp->Start(),
94 *pTmpEnd = pTmp->GetPoint() == pTmpStt ?
95 pTmp->GetMark() : pTmp->GetPoint();
96 if( *pStt <= *pTmpStt )
98 if( *pEnd > *pTmpStt ||
99 ( *pEnd == *pTmpStt && *pEnd == *pTmpEnd ))
100 pTmpDel = pTmp;
102 else
103 if( *pStt < *pTmpEnd )
104 pTmpDel = pTmp;
106 // If Point or Mark is within the Crsr range, we need to remove the old
107 // range. Take note that Point does not belong to the range anymore.
108 pTmp = (SwPaM*)pTmp->GetNext();
109 delete pTmpDel; // Remove old range
110 pTmpDel = 0;
114 // -----------
115 // SwCrsrShell
116 // -----------
121 SwPaM * SwCrsrShell::CreateCrsr()
123 // don't create Crsr in a table Selection (sic!)
124 OSL_ENSURE( !IsTableMode(), "in table Selection" );
126 // New cursor as copy of current one. Add to the ring.
127 // Links point to previously created one, ie forward.
128 SwShellCrsr* pNew = new SwShellCrsr( *pCurCrsr );
130 // Hide PaM logically, to avoid undoing the inverting from
131 // copied PaM (#i75172#)
132 pNew->swapContent(*pCurCrsr);
134 pCurCrsr->DeleteMark();
136 UpdateCrsr( SwCrsrShell::SCROLLWIN );
137 return pNew;
142 * Delete current Cursor, making the following one the current.
143 * Note, this function does not delete anything if there is no other cursor.
144 * @return - returns true if there was another cursor and we deleted one.
146 bool SwCrsrShell::DestroyCrsr()
148 // don't delete Crsr within table selection
149 OSL_ENSURE( !IsTableMode(), "in table Selection" );
151 // Is there a next one? Don't do anything if not.
152 if(pCurCrsr->GetNext() == pCurCrsr)
153 return false;
155 SwCallLink aLk( *this ); // watch Crsr-Moves
156 SwCursor* pNextCrsr = (SwCursor*)pCurCrsr->GetNext();
157 delete pCurCrsr;
158 pCurCrsr = dynamic_cast<SwShellCrsr*>(pNextCrsr);
159 UpdateCrsr();
160 return true;
165 * Create and return a new shell cursor.
166 * Simply returns the current shell cursor if there is no selection
167 * (HasSelection()).
169 SwPaM & SwCrsrShell::CreateNewShellCursor()
171 if (HasSelection())
173 (void) CreateCrsr(); // n.b. returns old cursor
175 return *GetCrsr();
179 * Return the current shell cursor
180 * @return - returns current `SwPaM` shell cursor
182 SwPaM & SwCrsrShell::GetCurrentShellCursor()
184 return *GetCrsr();
188 * Return pointer to the current shell cursor
189 * @return - returns pointer to current `SwPaM` shell cursor
191 SwPaM* SwCrsrShell::GetCrsr( sal_Bool bMakeTblCrsr ) const
193 if( pTblCrsr )
195 if( bMakeTblCrsr && pTblCrsr->IsCrsrMovedUpdt() )
197 //don't re-create 'parked' cursors
198 const SwCntntNode* pCNd;
199 if( pTblCrsr->GetPoint()->nNode.GetIndex() &&
200 pTblCrsr->GetMark()->nNode.GetIndex() &&
201 0 != ( pCNd = pTblCrsr->GetCntntNode() ) && pCNd->getLayoutFrm( GetLayout() ) &&
202 0 != ( pCNd = pTblCrsr->GetCntntNode(sal_False) ) && pCNd->getLayoutFrm( GetLayout() ) )
204 SwShellTableCrsr* pTC = (SwShellTableCrsr*)pTblCrsr;
205 GetLayout()->MakeTblCrsrs( *pTC );
209 if( pTblCrsr->IsChgd() )
211 const_cast<SwCrsrShell*>(this)->pCurCrsr =
212 dynamic_cast<SwShellCrsr*>(pTblCrsr->MakeBoxSels( pCurCrsr ));
215 return pCurCrsr;
219 void SwCrsrShell::StartAction()
221 if( !ActionPend() )
223 // save for update of the ribbon bar
224 const SwNode& rNd = pCurCrsr->GetPoint()->nNode.GetNode();
225 nAktNode = rNd.GetIndex();
226 nAktCntnt = pCurCrsr->GetPoint()->nContent.GetIndex();
227 nAktNdTyp = rNd.GetNodeType();
228 bAktSelection = *pCurCrsr->GetPoint() != *pCurCrsr->GetMark();
229 if( rNd.IsTxtNode() )
230 nLeftFrmPos = SwCallLink::getLayoutFrm( GetLayout(), (SwTxtNode&)rNd, nAktCntnt, sal_True );
231 else
232 nLeftFrmPos = 0;
234 ViewShell::StartAction(); // to the ViewShell
238 void SwCrsrShell::EndAction( const sal_Bool bIdleEnd )
240 sal_Bool bVis = bSVCrsrVis;
242 // Idle-formatting?
243 if( bIdleEnd && Imp()->GetRegion() )
245 pCurCrsr->Hide();
248 // Update all invalid numberings before the last action
249 if( 1 == nStartAction )
250 GetDoc()->UpdateNumRule();
252 // #i76923#: Don't show the cursor in the ViewShell::EndAction() - call.
253 // Only the UpdateCrsr shows the cursor.
254 sal_Bool bSavSVCrsrVis = bSVCrsrVis;
255 bSVCrsrVis = sal_False;
257 ViewShell::EndAction( bIdleEnd ); // have ViewShell go first
259 bSVCrsrVis = bSavSVCrsrVis;
261 if( ActionPend() )
263 if( bVis ) // display SV-Cursor again
264 pVisCrsr->Show();
266 // If there is still a ChgCall and just the "basic
267 // parenthiszing(?) (Basic-Klammerung)" exists, call it. This
268 // decouples the internal with the Basic-parenthising, the
269 // Shells are switched.
270 if( !BasicActionPend() )
272 // Within a Basic action, one needs to update the cursor,
273 // to e.g. create the table cursos. This is being done in
274 // UpdateCrsr.
275 UpdateCrsr( SwCrsrShell::CHKRANGE, bIdleEnd );
278 // watch Crsr-Moves, call Link if needed, the DTOR is key here!
279 SwCallLink aLk( *this, nAktNode, nAktCntnt, (sal_uInt8)nAktNdTyp,
280 nLeftFrmPos, bAktSelection );
283 if( bCallChgLnk && bChgCallFlag && aChgLnk.IsSet() )
285 aChgLnk.Call( this );
286 bChgCallFlag = sal_False; // reset flag
289 return;
292 sal_uInt16 nParm = SwCrsrShell::CHKRANGE;
293 if ( !bIdleEnd )
294 nParm |= SwCrsrShell::SCROLLWIN;
296 UpdateCrsr( nParm, bIdleEnd ); // Show Cursor changes
299 SwCallLink aLk( *this ); // watch Crsr-Moves
300 aLk.nNode = nAktNode; // call Link if needed
301 aLk.nNdTyp = (sal_uInt8)nAktNdTyp;
302 aLk.nCntnt = nAktCntnt;
303 aLk.nLeftFrmPos = nLeftFrmPos;
305 if( !nCrsrMove ||
306 ( 1 == nCrsrMove && bInCMvVisportChgd ) )
307 // display Cursor & Selektions again
308 ShowCrsrs( bSVCrsrVis ? sal_True : sal_False );
310 // call ChgCall if there is still one
311 if( bCallChgLnk && bChgCallFlag && aChgLnk.IsSet() )
313 aChgLnk.Call( this );
314 bChgCallFlag = sal_False; // reset flag
319 #ifdef DBG_UTIL
321 void SwCrsrShell::SttCrsrMove()
323 OSL_ENSURE( nCrsrMove < USHRT_MAX, "To many nested CrsrMoves." );
324 ++nCrsrMove;
325 StartAction();
328 void SwCrsrShell::EndCrsrMove( const sal_Bool bIdleEnd )
330 OSL_ENSURE( nCrsrMove, "EndCrsrMove() without SttCrsrMove()." );
331 EndAction( bIdleEnd );
332 if( !--nCrsrMove )
333 bInCMvVisportChgd = sal_False;
336 #endif
339 sal_Bool SwCrsrShell::LeftRight( sal_Bool bLeft, sal_uInt16 nCnt, sal_uInt16 nMode,
340 sal_Bool bVisualAllowed )
342 if( IsTableMode() )
343 return bLeft ? GoPrevCell() : GoNextCell();
345 SwCallLink aLk( *this ); // watch Crsr-Moves; call Link if needed
346 sal_Bool bRet = sal_False;
348 // #i27615# Handle cursor in front of label.
349 const SwTxtNode* pTxtNd = 0;
351 if( pBlockCrsr )
352 pBlockCrsr->clearPoints();
354 // 1. CASE: Cursor is in front of label. A move to the right
355 // will simply reset the bInFrontOfLabel flag:
356 SwShellCrsr* pShellCrsr = getShellCrsr( true );
357 if ( !bLeft && pShellCrsr->IsInFrontOfLabel() )
359 SetInFrontOfLabel( false );
360 bRet = sal_True;
362 // 2. CASE: Cursor is at beginning of numbered paragraph. A move
363 // to the left will simply set the bInFrontOfLabel flag:
364 else if ( bLeft && 0 == pShellCrsr->GetPoint()->nContent.GetIndex() &&
365 !pShellCrsr->IsInFrontOfLabel() && !pShellCrsr->HasMark() &&
366 0 != ( pTxtNd = pShellCrsr->GetNode()->GetTxtNode() ) &&
367 pTxtNd->HasVisibleNumberingOrBullet() )
369 SetInFrontOfLabel( true );
370 bRet = sal_True;
372 // 3. CASE: Regular cursor move. Reset the bInFrontOfLabel flag:
373 else
375 const sal_Bool bSkipHidden = !GetViewOptions()->IsShowHiddenChar();
376 // #i107447#
377 // To avoid loop the reset of <bInFrontOfLabel> flag is no longer
378 // reflected in the return value <bRet>.
379 const bool bResetOfInFrontOfLabel = SetInFrontOfLabel( false );
380 bRet = pShellCrsr->LeftRight( bLeft, nCnt, nMode, bVisualAllowed,
381 bSkipHidden, !IsOverwriteCrsr() );
382 if ( !bRet && bLeft && bResetOfInFrontOfLabel )
384 // undo reset of <bInFrontOfLabel> flag
385 SetInFrontOfLabel( true );
389 if( bRet )
391 UpdateCrsr();
393 return bRet;
396 void SwCrsrShell::MarkListLevel( const String& sListId,
397 const int nListLevel )
399 if ( sListId != sMarkedListId ||
400 nListLevel != nMarkedListLevel)
402 if ( sMarkedListId.Len() > 0 )
403 pDoc->MarkListLevel( sMarkedListId, nMarkedListLevel, false );
405 if ( sListId.Len() > 0 )
407 pDoc->MarkListLevel( sListId, nListLevel, true );
410 sMarkedListId = sListId;
411 nMarkedListLevel = nListLevel;
415 void SwCrsrShell::UpdateMarkedListLevel()
417 SwTxtNode * pTxtNd = _GetCrsr()->GetNode()->GetTxtNode();
419 if ( pTxtNd )
421 if ( !pTxtNd->IsNumbered() )
423 pCurCrsr->_SetInFrontOfLabel( false );
424 MarkListLevel( String(), 0 );
426 else if ( pCurCrsr->IsInFrontOfLabel() )
428 if ( pTxtNd->IsInList() )
430 OSL_ENSURE( pTxtNd->GetActualListLevel() >= 0 &&
431 pTxtNd->GetActualListLevel() < MAXLEVEL, "Which level?");
432 MarkListLevel( pTxtNd->GetListId(),
433 pTxtNd->GetActualListLevel() );
436 else
438 MarkListLevel( String(), 0 );
443 sal_Bool SwCrsrShell::UpDown( sal_Bool bUp, sal_uInt16 nCnt )
445 SET_CURR_SHELL( this );
446 SwCallLink aLk( *this ); // watch Crsr-Moves; call Link if needed
448 sal_Bool bTableMode = IsTableMode();
449 SwShellCrsr* pTmpCrsr = getShellCrsr( true );
451 sal_Bool bRet = pTmpCrsr->UpDown( bUp, nCnt );
452 // #i40019# UpDown should always reset the bInFrontOfLabel flag:
453 bRet = SetInFrontOfLabel(false) || bRet;
455 if( pBlockCrsr )
456 pBlockCrsr->clearPoints();
458 if( bRet )
460 eMvState = MV_UPDOWN; // status for Crsr travelling - GetCrsrOfst
461 if( !ActionPend() )
463 CrsrFlag eUpdtMode = SwCrsrShell::SCROLLWIN;
464 if( !bTableMode )
465 eUpdtMode = (CrsrFlag) (eUpdtMode
466 | SwCrsrShell::UPDOWN | SwCrsrShell::CHKRANGE);
467 UpdateCrsr( static_cast<sal_uInt16>(eUpdtMode) );
470 return bRet;
473 sal_Bool SwCrsrShell::LRMargin( sal_Bool bLeft, sal_Bool bAPI)
475 SwCallLink aLk( *this ); // watch Crsr-Moves; call Link if needed
476 SET_CURR_SHELL( this );
477 eMvState = MV_LEFTMARGIN; // status for Crsr travelling - GetCrsrOfst
479 const sal_Bool bTableMode = IsTableMode();
480 SwShellCrsr* pTmpCrsr = getShellCrsr( true );
482 if( pBlockCrsr )
483 pBlockCrsr->clearPoints();
485 const bool bWasAtLM =
486 ( 0 == _GetCrsr()->GetPoint()->nContent.GetIndex() );
488 sal_Bool bRet = pTmpCrsr->LeftRightMargin( bLeft, bAPI );
490 if ( bLeft && !bTableMode && bRet && bWasAtLM && !_GetCrsr()->HasMark() )
492 const SwTxtNode * pTxtNd = _GetCrsr()->GetNode()->GetTxtNode();
493 if ( pTxtNd && pTxtNd->HasVisibleNumberingOrBullet() )
494 SetInFrontOfLabel( true );
496 else if ( !bLeft )
498 bRet = SetInFrontOfLabel( false ) || bRet;
501 if( bRet )
503 UpdateCrsr();
505 return bRet;
508 sal_Bool SwCrsrShell::IsAtLRMargin( sal_Bool bLeft, sal_Bool bAPI ) const
510 const SwShellCrsr* pTmpCrsr = getShellCrsr( true );
511 return pTmpCrsr->IsAtLeftRightMargin( bLeft, bAPI );
515 sal_Bool SwCrsrShell::SttEndDoc( sal_Bool bStt )
517 SwCallLink aLk( *this ); // watch Crsr-Moves; call Link if needed
519 SwShellCrsr* pTmpCrsr = pBlockCrsr ? &pBlockCrsr->getShellCrsr() : pCurCrsr;
520 sal_Bool bRet = pTmpCrsr->SttEndDoc( bStt );
521 if( bRet )
523 if( bStt )
524 pTmpCrsr->GetPtPos().Y() = 0; // set to 0 explicitly (table header)
525 if( pBlockCrsr )
527 pBlockCrsr->clearPoints();
528 RefreshBlockCursor();
531 UpdateCrsr(SwCrsrShell::SCROLLWIN|SwCrsrShell::CHKRANGE|SwCrsrShell::READONLY);
533 return bRet;
536 void SwCrsrShell::ExtendedSelectAll()
538 SwNodes& rNodes = GetDoc()->GetNodes();
539 SwPosition* pPos = pCurCrsr->GetPoint();
540 pPos->nNode = rNodes.GetEndOfPostIts();
541 pPos->nContent.Assign( rNodes.GoNext( &pPos->nNode ), 0 );
542 pPos = pCurCrsr->GetMark();
543 pPos->nNode = rNodes.GetEndOfContent();
544 SwCntntNode* pCNd = rNodes.GoPrevious( &pPos->nNode );
545 pPos->nContent.Assign( pCNd, pCNd ? pCNd->Len() : 0 );
548 sal_Bool SwCrsrShell::MovePage( SwWhichPage fnWhichPage, SwPosPage fnPosPage )
550 sal_Bool bRet = sal_False;
552 // never jump of section borders at selection
553 if( !pCurCrsr->HasMark() || !pCurCrsr->IsNoCntnt() )
555 SwCallLink aLk( *this ); // watch Crsr-Moves; call Link if needed
556 SET_CURR_SHELL( this );
558 SwCrsrSaveState aSaveState( *pCurCrsr );
559 Point& rPt = pCurCrsr->GetPtPos();
560 SwCntntFrm * pFrm = pCurCrsr->GetCntntNode()->
561 getLayoutFrm( GetLayout(), &rPt, pCurCrsr->GetPoint(), sal_False );
562 if( pFrm && sal_True == ( bRet = GetFrmInPage( pFrm, fnWhichPage,
563 fnPosPage, pCurCrsr ) ) &&
564 !pCurCrsr->IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
565 nsSwCursorSelOverFlags::SELOVER_CHANGEPOS ))
566 UpdateCrsr();
567 else
568 bRet = sal_False;
570 return bRet;
574 sal_Bool SwCrsrShell::MovePara(SwWhichPara fnWhichPara, SwPosPara fnPosPara )
576 SwCallLink aLk( *this ); // watch Crsr-Moves; call Link if needed
577 SwCursor* pTmpCrsr = getShellCrsr( true );
578 sal_Bool bRet = pTmpCrsr->MovePara( fnWhichPara, fnPosPara );
579 if( bRet )
580 UpdateCrsr();
581 return bRet;
585 sal_Bool SwCrsrShell::MoveSection( SwWhichSection fnWhichSect,
586 SwPosSection fnPosSect)
588 SwCallLink aLk( *this ); // watch Crsr-Moves; call Link if needed
589 SwCursor* pTmpCrsr = getShellCrsr( true );
590 sal_Bool bRet = pTmpCrsr->MoveSection( fnWhichSect, fnPosSect );
591 if( bRet )
592 UpdateCrsr();
593 return bRet;
598 // position cursor
601 static SwFrm* lcl_IsInHeaderFooter( const SwNodeIndex& rIdx, Point& rPt )
603 SwFrm* pFrm = 0;
604 SwCntntNode* pCNd = rIdx.GetNode().GetCntntNode();
605 if( pCNd )
607 SwCntntFrm *pCntFrm = pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout(), &rPt, 0, sal_False );
608 pFrm = pCntFrm ? pCntFrm->GetUpper() : NULL;
609 while( pFrm && !pFrm->IsHeaderFrm() && !pFrm->IsFooterFrm() )
610 pFrm = pFrm->IsFlyFrm() ? ((SwFlyFrm*)pFrm)->AnchorFrm()
611 : pFrm->GetUpper();
613 return pFrm;
616 bool SwCrsrShell::IsInHeaderFooter( sal_Bool* pbInHeader ) const
618 Point aPt;
619 SwFrm* pFrm = ::lcl_IsInHeaderFooter( pCurCrsr->GetPoint()->nNode, aPt );
620 if( pFrm && pbInHeader )
621 *pbInHeader = pFrm->IsHeaderFrm();
622 return 0 != pFrm;
625 int SwCrsrShell::SetCrsr( const Point &rLPt, sal_Bool bOnlyText, bool bBlock )
627 SET_CURR_SHELL( this );
629 SwShellCrsr* pCrsr = getShellCrsr( bBlock );
630 SwPosition aPos( *pCrsr->GetPoint() );
631 Point aPt( rLPt );
632 Point & rAktCrsrPt = pCrsr->GetPtPos();
633 SwCrsrMoveState aTmpState( IsTableMode() ? MV_TBLSEL :
634 bOnlyText ? MV_SETONLYTEXT : MV_NONE );
635 aTmpState.bSetInReadOnly = IsReadOnlyAvailable();
637 SwTxtNode * pTxtNd = pCrsr->GetNode()->GetTxtNode();
639 if ( pTxtNd && !IsTableMode() &&
640 // #i37515# No bInFrontOfLabel during selection
641 !pCrsr->HasMark() &&
642 pTxtNd->HasVisibleNumberingOrBullet() )
644 aTmpState.bInFrontOfLabel = sal_True; // #i27615#
646 else
648 aTmpState.bInFrontOfLabel = sal_False;
651 int bRet = CRSR_POSOLD |
652 ( GetLayout()->GetCrsrOfst( &aPos, aPt, &aTmpState )
653 ? 0 : CRSR_POSCHG );
655 const bool bOldInFrontOfLabel = IsInFrontOfLabel();
656 const bool bNewInFrontOfLabel = aTmpState.bInFrontOfLabel;
658 pCrsr->SetCrsrBidiLevel( aTmpState.nCursorBidiLevel );
660 if( MV_RIGHTMARGIN == aTmpState.eState )
661 eMvState = MV_RIGHTMARGIN;
662 // is the new position in header or footer?
663 SwFrm* pFrm = lcl_IsInHeaderFooter( aPos.nNode, aPt );
664 if( IsTableMode() && !pFrm && aPos.nNode.GetNode().StartOfSectionNode() ==
665 pCrsr->GetPoint()->nNode.GetNode().StartOfSectionNode() )
666 // same table column and not in header/footer -> back
667 return bRet;
669 if( pBlockCrsr && bBlock )
671 pBlockCrsr->setEndPoint( rLPt );
672 if( !pCrsr->HasMark() )
673 pBlockCrsr->setStartPoint( rLPt );
674 else if( !pBlockCrsr->getStartPoint() )
675 pBlockCrsr->setStartPoint( pCrsr->GetMkPos() );
677 if( !pCrsr->HasMark() )
679 // is at the same position and if in header/footer -> in the same
680 if( aPos == *pCrsr->GetPoint() &&
681 bOldInFrontOfLabel == bNewInFrontOfLabel )
683 if( pFrm )
685 if( pFrm->Frm().IsInside( rAktCrsrPt ))
686 return bRet;
688 else if( aPos.nNode.GetNode().IsCntntNode() )
690 // in the same frame?
691 SwFrm* pOld = ((SwCntntNode&)aPos.nNode.GetNode()).getLayoutFrm(
692 GetLayout(), &aCharRect.Pos(), 0, sal_False );
693 SwFrm* pNew = ((SwCntntNode&)aPos.nNode.GetNode()).getLayoutFrm(
694 GetLayout(), &aPt, 0, sal_False );
695 if( pNew == pOld )
696 return bRet;
700 else
702 // SSelection over not allowed sections or if in header/footer -> different
703 if( !CheckNodesRange( aPos.nNode, pCrsr->GetMark()->nNode, sal_True )
704 || ( pFrm && !pFrm->Frm().IsInside( pCrsr->GetMkPos() ) ))
705 return bRet;
707 // is at same position but not in header/footer
708 if( aPos == *pCrsr->GetPoint() )
709 return bRet;
712 SwCallLink aLk( *this ); // watch Crsr-Moves; call Link if needed
713 SwCrsrSaveState aSaveState( *pCrsr );
715 *pCrsr->GetPoint() = aPos;
716 rAktCrsrPt = aPt;
718 // #i41424# Only update the marked number levels if necessary
719 // Force update of marked number levels if necessary.
720 if ( bNewInFrontOfLabel || bOldInFrontOfLabel )
721 pCurCrsr->_SetInFrontOfLabel( !bNewInFrontOfLabel );
722 SetInFrontOfLabel( bNewInFrontOfLabel );
724 if( !pCrsr->IsSelOvr( nsSwCursorSelOverFlags::SELOVER_CHANGEPOS ) )
726 sal_uInt16 nFlag = SwCrsrShell::SCROLLWIN | SwCrsrShell::CHKRANGE;
727 UpdateCrsr( nFlag );
728 bRet &= ~CRSR_POSOLD;
730 else if( bOnlyText && !pCurCrsr->HasMark() )
732 if( FindValidCntntNode( bOnlyText ) )
734 // position cursor in a valid content
735 if( aPos == *pCrsr->GetPoint() )
736 bRet = CRSR_POSOLD;
737 else
739 UpdateCrsr( SwCrsrShell::SCROLLWIN | SwCrsrShell::CHKRANGE );
740 bRet &= ~CRSR_POSOLD;
743 else
745 // there is no valid content -> hide cursor
746 pVisCrsr->Hide(); // always hide visible cursor
747 eMvState = MV_NONE; // status for Crsr travelling
748 bAllProtect = sal_True;
749 if( GetDoc()->GetDocShell() )
751 GetDoc()->GetDocShell()->SetReadOnlyUI( sal_True );
752 CallChgLnk(); // notify UI
757 return bRet;
761 void SwCrsrShell::TblCrsrToCursor()
763 OSL_ENSURE( pTblCrsr, "TblCrsrToCursor: Why?" );
764 delete pTblCrsr, pTblCrsr = 0;
767 void SwCrsrShell::BlockCrsrToCrsr()
769 OSL_ENSURE( pBlockCrsr, "BlockCrsrToCrsr: Why?" );
770 if( pBlockCrsr && !HasSelection() )
772 SwPaM& rPam = pBlockCrsr->getShellCrsr();
773 pCurCrsr->SetMark();
774 *pCurCrsr->GetPoint() = *rPam.GetPoint();
775 if( rPam.HasMark() )
776 *pCurCrsr->GetMark() = *rPam.GetMark();
777 else
778 pCurCrsr->DeleteMark();
780 delete pBlockCrsr, pBlockCrsr = 0;
783 void SwCrsrShell::CrsrToBlockCrsr()
785 if( !pBlockCrsr )
787 SwPosition aPos( *pCurCrsr->GetPoint() );
788 pBlockCrsr = createBlockCursor( *this, aPos );
789 SwShellCrsr &rBlock = pBlockCrsr->getShellCrsr();
790 rBlock.GetPtPos() = pCurCrsr->GetPtPos();
791 if( pCurCrsr->HasMark() )
793 rBlock.SetMark();
794 *rBlock.GetMark() = *pCurCrsr->GetMark();
795 rBlock.GetMkPos() = pCurCrsr->GetMkPos();
798 pBlockCrsr->clearPoints();
799 RefreshBlockCursor();
802 void SwCrsrShell::ClearMark()
804 // is there any GetMark?
805 if( pTblCrsr )
807 while( pCurCrsr->GetNext() != pCurCrsr )
808 delete pCurCrsr->GetNext();
809 pTblCrsr->DeleteMark();
811 if( pCurCrsr->HasMark() )
813 // move content part from mark to nodes array if not all indices
814 // were moved correctly (e.g. when deleting header/footer)
815 SwPosition& rPos = *pCurCrsr->GetMark();
816 rPos.nNode.Assign( pDoc->GetNodes(), 0 );
817 rPos.nContent.Assign( 0, 0 );
818 pCurCrsr->DeleteMark();
821 *pCurCrsr->GetPoint() = *pTblCrsr->GetPoint();
822 pCurCrsr->GetPtPos() = pTblCrsr->GetPtPos();
823 delete pTblCrsr, pTblCrsr = 0;
824 pCurCrsr->SwSelPaintRects::Show();
826 else
828 if( !pCurCrsr->HasMark() )
829 return;
830 // move content part from mark to nodes array if not all indices
831 // were moved correctly (e.g. when deleting header/footer)
832 SwPosition& rPos = *pCurCrsr->GetMark();
833 rPos.nNode.Assign( pDoc->GetNodes(), 0 );
834 rPos.nContent.Assign( 0, 0 );
835 pCurCrsr->DeleteMark();
836 if( !nCrsrMove )
837 pCurCrsr->SwSelPaintRects::Show();
842 void SwCrsrShell::NormalizePam(sal_Bool bPointFirst)
844 SwCallLink aLk( *this ); // watch Crsr-Moves; call Link if needed
845 pCurCrsr->Normalize(bPointFirst);
848 void SwCrsrShell::SwapPam()
850 SwCallLink aLk( *this ); // watch Crsr-Moves; call Link if needed
851 pCurCrsr->Exchange();
854 //TODO: provide documentation
855 /** Search in the selected area for a Selection that covers the given point.
857 If only a test run is made, then it checks if a SSelection exists but does
858 not move the current cursor. In a normal run the cursor will be moved to the
859 chosen SSelection.
861 @param rPt The point to search at.
862 @param bTstOnly Should I only do a test run? If true so do not move cursor.
863 @param bTstHit ???
865 sal_Bool SwCrsrShell::ChgCurrPam( const Point & rPt,
866 sal_Bool bTstOnly, sal_Bool bTstHit )
868 SET_CURR_SHELL( this );
870 // check if the SPoint is in a table selection
871 if( bTstOnly && pTblCrsr )
872 return pTblCrsr->IsInside( rPt );
874 SwCallLink aLk( *this ); // watch Crsr-Moves; call Link if needed
875 // search position <rPt> in document
876 SwPosition aPtPos( *pCurCrsr->GetPoint() );
877 Point aPt( rPt );
879 SwCrsrMoveState aTmpState( MV_NONE );
880 aTmpState.bSetInReadOnly = IsReadOnlyAvailable();
881 if ( !GetLayout()->GetCrsrOfst( &aPtPos, aPt, &aTmpState ) && bTstHit )
882 return sal_False;
884 // search in all selections for this position
885 SwShellCrsr* pCmp = (SwShellCrsr*)pCurCrsr; // keep the pointer on cursor
886 do {
887 if( pCmp->HasMark() &&
888 *pCmp->Start() <= aPtPos && *pCmp->End() > aPtPos )
890 if( bTstOnly || pCurCrsr == pCmp ) // is the current
891 return sal_True; // return without update
893 pCurCrsr = pCmp;
894 UpdateCrsr(); // cursor is already at the right position
895 return sal_True;
897 } while( pCurCrsr !=
898 ( pCmp = dynamic_cast<SwShellCrsr*>(pCmp->GetNext()) ) );
899 return sal_False;
903 void SwCrsrShell::KillPams()
905 // Does any exist for deletion?
906 if( !pTblCrsr && !pBlockCrsr && pCurCrsr->GetNext() == pCurCrsr )
907 return;
909 while( pCurCrsr->GetNext() != pCurCrsr )
910 delete pCurCrsr->GetNext();
911 pCurCrsr->SetColumnSelection( false );
913 if( pTblCrsr )
915 // delete the ring of cursors
916 pCurCrsr->DeleteMark();
917 *pCurCrsr->GetPoint() = *pTblCrsr->GetPoint();
918 pCurCrsr->GetPtPos() = pTblCrsr->GetPtPos();
919 delete pTblCrsr;
920 pTblCrsr = 0;
922 else if( pBlockCrsr )
924 // delete the ring of cursors
925 pCurCrsr->DeleteMark();
926 SwShellCrsr &rBlock = pBlockCrsr->getShellCrsr();
927 *pCurCrsr->GetPoint() = *rBlock.GetPoint();
928 pCurCrsr->GetPtPos() = rBlock.GetPtPos();
929 rBlock.DeleteMark();
930 pBlockCrsr->clearPoints();
932 UpdateCrsr( SwCrsrShell::SCROLLWIN );
936 int SwCrsrShell::CompareCursor( CrsrCompareType eType ) const
938 int nRet = 0;
939 const SwPosition *pFirst = 0, *pSecond = 0;
940 const SwPaM *pCur = GetCrsr(), *pStk = pCrsrStk;
941 if( CurrPtCurrMk != eType && pStk )
943 switch ( eType)
945 case StackPtStackMk:
946 pFirst = pStk->GetPoint();
947 pSecond = pStk->GetMark();
948 break;
949 case StackPtCurrPt:
950 pFirst = pStk->GetPoint();
951 pSecond = pCur->GetPoint();
952 break;
953 case StackPtCurrMk:
954 pFirst = pStk->GetPoint();
955 pSecond = pCur->GetMark();
956 break;
957 case StackMkCurrPt:
958 pFirst = pStk->GetMark();
959 pSecond = pCur->GetPoint();
960 break;
961 case StackMkCurrMk:
962 pFirst = pStk->GetMark();
963 pSecond = pStk->GetMark();
964 break;
965 case CurrPtCurrMk:
966 pFirst = pCur->GetPoint();
967 pSecond = pCur->GetMark();
968 break;
971 if( !pFirst || !pSecond )
972 nRet = INT_MAX;
973 else if( *pFirst < *pSecond )
974 nRet = -1;
975 else if( *pFirst == *pSecond )
976 nRet = 0;
977 else
978 nRet = 1;
979 return nRet;
983 bool SwCrsrShell::IsSttPara() const
984 { return pCurCrsr->GetPoint()->nContent == 0; }
987 bool SwCrsrShell::IsEndPara() const
988 { return pCurCrsr->GetPoint()->nContent == pCurCrsr->GetCntntNode()->Len(); }
991 bool SwCrsrShell::IsInFrontOfLabel() const
993 return pCurCrsr->IsInFrontOfLabel();
996 bool SwCrsrShell::SetInFrontOfLabel( bool bNew )
998 if ( bNew != IsInFrontOfLabel() )
1000 pCurCrsr->_SetInFrontOfLabel( bNew );
1001 UpdateMarkedListLevel();
1002 return true;
1004 return false;
1007 sal_Bool SwCrsrShell::GotoPage( sal_uInt16 nPage )
1009 SET_CURR_SHELL( this );
1010 SwCallLink aLk( *this ); // watch Crsr-Moves; call Link if needed
1011 SwCrsrSaveState aSaveState( *pCurCrsr );
1012 sal_Bool bRet = GetLayout()->SetCurrPage( pCurCrsr, nPage ) &&
1013 !pCurCrsr->IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
1014 nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
1015 if( bRet )
1016 UpdateCrsr(SwCrsrShell::SCROLLWIN|SwCrsrShell::CHKRANGE|SwCrsrShell::READONLY);
1017 return bRet;
1021 void SwCrsrShell::GetPageNum( sal_uInt16 &rnPhyNum, sal_uInt16 &rnVirtNum,
1022 sal_Bool bAtCrsrPos, const sal_Bool bCalcFrm )
1024 SET_CURR_SHELL( this );
1025 // page number: first visible page or the one at the cursor
1026 const SwCntntFrm* pCFrm;
1027 const SwPageFrm *pPg = 0;
1029 if( !bAtCrsrPos || 0 == (pCFrm = GetCurrFrm( bCalcFrm )) ||
1030 0 == (pPg = pCFrm->FindPageFrm()) )
1032 pPg = Imp()->GetFirstVisPage();
1033 while( pPg && pPg->IsEmptyPage() )
1034 pPg = (const SwPageFrm *)pPg->GetNext();
1036 // pPg has to exist with a default of 1 for the special case "Writerstart"
1037 rnPhyNum = pPg? pPg->GetPhyPageNum() : 1;
1038 rnVirtNum = pPg? pPg->GetVirtPageNum() : 1;
1042 sal_uInt16 SwCrsrShell::GetNextPrevPageNum( sal_Bool bNext )
1044 SET_CURR_SHELL( this );
1046 // page number: first visible page or the one at the cursor
1047 const SwPageFrm *pPg = Imp()->GetFirstVisPage();
1048 if( pPg )
1050 const SwTwips nPageTop = pPg->Frm().Top();
1052 if( bNext )
1054 // go to next view layout row:
1057 pPg = (const SwPageFrm *)pPg->GetNext();
1059 while( pPg && pPg->Frm().Top() == nPageTop );
1061 while( pPg && pPg->IsEmptyPage() )
1062 pPg = (const SwPageFrm *)pPg->GetNext();
1064 else
1066 // go to previous view layout row:
1069 pPg = (const SwPageFrm *)pPg->GetPrev();
1071 while( pPg && pPg->Frm().Top() == nPageTop );
1073 while( pPg && pPg->IsEmptyPage() )
1074 pPg = (const SwPageFrm *)pPg->GetPrev();
1077 // pPg has to exist with a default of 1 for the special case "Writerstart"
1078 return pPg ? pPg->GetPhyPageNum() : USHRT_MAX;
1082 sal_uInt16 SwCrsrShell::GetPageCnt()
1084 SET_CURR_SHELL( this );
1085 // return number of pages
1086 return GetLayout()->GetPageNum();
1089 /// go to the next SSelection
1090 sal_Bool SwCrsrShell::GoNextCrsr()
1092 // is there a ring of cursors?
1093 if( pCurCrsr->GetNext() == pCurCrsr )
1094 return sal_False;
1096 SET_CURR_SHELL( this );
1097 SwCallLink aLk( *this ); // watch Crsr-Moves; call Link if needed
1098 pCurCrsr = dynamic_cast<SwShellCrsr*>(pCurCrsr->GetNext());
1100 // #i24086#: show also all others
1101 if( !ActionPend() )
1103 UpdateCrsr();
1104 pCurCrsr->Show();
1106 return sal_True;
1109 /// go to the previous SSelection
1110 sal_Bool SwCrsrShell::GoPrevCrsr()
1112 // is there a ring of cursors?
1113 if( pCurCrsr->GetNext() == pCurCrsr )
1114 return sal_False;
1116 SET_CURR_SHELL( this );
1117 SwCallLink aLk( *this ); // watch Crsr-Moves; call Link if needed
1118 pCurCrsr = dynamic_cast<SwShellCrsr*>(pCurCrsr->GetPrev());
1120 // #i24086#: show also all others
1121 if( !ActionPend() )
1123 UpdateCrsr();
1124 pCurCrsr->Show();
1127 return sal_True;
1131 void SwCrsrShell::Paint( const Rectangle &rRect)
1133 SET_CURR_SHELL( this );
1135 // always switch off all cursors when painting
1136 SwRect aRect( rRect );
1138 bool bVis = false;
1139 // if a cursor is visible then hide the SV cursor
1140 if( pVisCrsr->IsVisible() && !aRect.IsOver( aCharRect ) )
1142 bVis = true;
1143 pVisCrsr->Hide();
1146 // re-paint area
1147 ViewShell::Paint( rRect );
1149 if( bHasFocus && !bBasicHideCrsr )
1151 SwShellCrsr* pAktCrsr = pTblCrsr ? pTblCrsr : pCurCrsr;
1153 if( !ActionPend() )
1155 // so that right/bottom borders will not be cropped
1156 pAktCrsr->Invalidate( VisArea() );
1157 pAktCrsr->Show();
1159 else
1160 pAktCrsr->Invalidate( aRect );
1163 if( bSVCrsrVis && bVis ) // also show SV cursor again
1164 pVisCrsr->Show();
1169 void SwCrsrShell::VisPortChgd( const SwRect & rRect )
1171 SET_CURR_SHELL( this );
1172 bool bVis; // switch off all cursors when scrolling
1174 // if a cursor is visible then hide the SV cursor
1175 if( ( bVis = pVisCrsr->IsVisible() ) )
1176 pVisCrsr->Hide();
1178 bVisPortChgd = sal_True;
1179 aOldRBPos.X() = VisArea().Right();
1180 aOldRBPos.Y() = VisArea().Bottom();
1182 // For not having problems with the SV cursor, Update() is called for the
1183 // Window in ViewShell::VisPo...
1184 // During painting no selections should be shown, thus the call is encapsulated. <- TODO: old artefact?
1185 ViewShell::VisPortChgd( rRect ); // move area
1187 if( bSVCrsrVis && bVis ) // show SV cursor again
1188 pVisCrsr->Show();
1190 if( nCrsrMove )
1191 bInCMvVisportChgd = sal_True;
1193 bVisPortChgd = sal_False;
1196 /** Set the cursor back into content.
1198 This should only be called if the cursor was move somewhere else (e.g. when
1199 deleting a border). The new position is calculated from its current position
1200 in the layout.
1202 void SwCrsrShell::UpdateCrsrPos()
1204 SET_CURR_SHELL( this );
1205 ++nStartAction;
1206 SwShellCrsr* pShellCrsr = getShellCrsr( true );
1207 Size aOldSz( GetDocSize() );
1208 SwCntntNode *pCNode = pShellCrsr->GetCntntNode();
1209 SwCntntFrm *pFrm = pCNode ?
1210 pCNode->getLayoutFrm( GetLayout(), &pShellCrsr->GetPtPos(), pShellCrsr->GetPoint(), sal_False ) :0;
1211 if( !pFrm || (pFrm->IsTxtFrm() && ((SwTxtFrm*)pFrm)->IsHiddenNow()) )
1213 SwCrsrMoveState aTmpState( MV_NONE );
1214 aTmpState.bSetInReadOnly = IsReadOnlyAvailable();
1215 GetLayout()->GetCrsrOfst( pShellCrsr->GetPoint(), pShellCrsr->GetPtPos(),
1216 &aTmpState );
1217 if( pShellCrsr->HasMark())
1218 pShellCrsr->DeleteMark();
1220 IGrammarContact *pGrammarContact = GetDoc() ? GetDoc()->getGrammarContact() : 0;
1221 if( pGrammarContact )
1222 pGrammarContact->updateCursorPosition( *pCurCrsr->GetPoint() );
1223 --nStartAction;
1224 if( aOldSz != GetDocSize() )
1225 SizeChgNotify();
1228 // #i65475# - if Point/Mark in hidden sections, move them out
1229 static void lcl_CheckHiddenSection( SwNodeIndex& rIdx )
1231 const SwSectionNode* pSectNd = rIdx.GetNode().FindSectionNode();
1232 if( pSectNd && pSectNd->GetSection().IsHiddenFlag() )
1234 SwNodeIndex aTmp( *pSectNd );
1235 const SwNode* pFrmNd =
1236 rIdx.GetNodes().FindPrvNxtFrmNode( aTmp, pSectNd->EndOfSectionNode() );
1237 SAL_WARN_IF( !pFrmNd, "sw", "found no Node with Frames" );
1238 rIdx = aTmp;
1242 /// Try to set the cursor to the next visible content node.
1243 static void lcl_CheckHiddenPara( SwPosition& rPos )
1245 SwNodeIndex aTmp( rPos.nNode );
1246 SwTxtNode* pTxtNd = aTmp.GetNode().GetTxtNode();
1247 while( pTxtNd && pTxtNd->HasHiddenCharAttribute( true ) )
1249 SwCntntNode* pCntnt = aTmp.GetNodes().GoNext( &aTmp );
1250 if ( pCntnt && pCntnt->IsTxtNode() )
1251 pTxtNd = (SwTxtNode*)pCntnt;
1252 else
1253 pTxtNd = 0;
1256 if ( pTxtNd )
1257 rPos = SwPosition( aTmp, SwIndex( pTxtNd, 0 ) );
1260 // #i27301# - helper class that notifies the accessibility about invalid text
1261 // selections in its destructor
1262 class SwNotifyAccAboutInvalidTextSelections
1264 private:
1265 SwCrsrShell& mrCrsrSh;
1267 public:
1268 SwNotifyAccAboutInvalidTextSelections( SwCrsrShell& _rCrsrSh )
1269 : mrCrsrSh( _rCrsrSh )
1272 ~SwNotifyAccAboutInvalidTextSelections()
1274 mrCrsrSh.InvalidateAccessibleParaTextSelection();
1277 void SwCrsrShell::UpdateCrsr( sal_uInt16 eFlags, sal_Bool bIdleEnd )
1279 SET_CURR_SHELL( this );
1281 ClearUpCrsrs();
1283 // In a BasicAction the cursor must be updated, e.g. to create the
1284 // TableCursor. EndAction now calls UpdateCrsr!
1285 if( ActionPend() && BasicActionPend() )
1287 if ( eFlags & SwCrsrShell::READONLY )
1288 bIgnoreReadonly = sal_True;
1289 return; // if not then no update
1292 // #i27301#
1293 SwNotifyAccAboutInvalidTextSelections aInvalidateTextSelections( *this );
1295 if ( bIgnoreReadonly )
1297 bIgnoreReadonly = sal_False;
1298 eFlags |= SwCrsrShell::READONLY;
1301 if( eFlags & SwCrsrShell::CHKRANGE ) // check all cursor moves for
1302 CheckRange( pCurCrsr ); // overlapping ranges
1304 if( !bIdleEnd )
1305 CheckTblBoxCntnt();
1307 // If the current cursor is in a table and point/mark in different boxes,
1308 // then the table mode is active (also if it is already active: pTblCrsr)
1309 SwPaM* pTstCrsr = getShellCrsr( true );
1310 if( pTstCrsr->HasMark() && !pBlockCrsr &&
1311 pDoc->IsIdxInTbl( pTstCrsr->GetPoint()->nNode ) &&
1312 ( pTblCrsr ||
1313 pTstCrsr->GetNode( sal_True )->StartOfSectionNode() !=
1314 pTstCrsr->GetNode( sal_False )->StartOfSectionNode() ) )
1316 SwShellCrsr* pITmpCrsr = getShellCrsr( true );
1317 Point aTmpPt( pITmpCrsr->GetPtPos() );
1318 Point aTmpMk( pITmpCrsr->GetMkPos() );
1319 SwPosition* pPos = pITmpCrsr->GetPoint();
1321 // Bug 65475 (1999) - if Point/Mark in hidden sections, move them out
1322 lcl_CheckHiddenSection( pPos->nNode );
1323 lcl_CheckHiddenSection( pITmpCrsr->GetMark()->nNode );
1325 // Move cursor out of hidden paragraphs
1326 if ( !GetViewOptions()->IsShowHiddenChar() )
1328 lcl_CheckHiddenPara( *pPos );
1329 lcl_CheckHiddenPara( *pITmpCrsr->GetMark() );
1332 SwCntntFrm *pTblFrm = pPos->nNode.GetNode().GetCntntNode()->
1333 getLayoutFrm( GetLayout(), &aTmpPt, pPos, sal_False );
1335 OSL_ENSURE( pTblFrm, "Tabelle Crsr nicht im Content ??" );
1337 // --> Make code robust. The table cursor may point
1338 // to a table in a currently inactive header.
1339 SwTabFrm *pTab = pTblFrm ? pTblFrm->FindTabFrm() : 0;
1341 if ( pTab && pTab->GetTable()->GetRowsToRepeat() > 0 )
1343 // First check if point is in repeated headline:
1344 bool bInRepeatedHeadline = pTab->IsFollow() && pTab->IsInHeadline( *pTblFrm );
1346 // Second check if mark is in repeated headline:
1347 if ( !bInRepeatedHeadline )
1349 SwCntntFrm* pMarkTblFrm = pITmpCrsr->GetCntntNode( sal_False )->
1350 getLayoutFrm( GetLayout(), &aTmpMk, pITmpCrsr->GetMark(), sal_False );
1351 OSL_ENSURE( pMarkTblFrm, "Tabelle Crsr nicht im Content ??" );
1353 if ( pMarkTblFrm )
1355 SwTabFrm* pMarkTab = pMarkTblFrm->FindTabFrm();
1356 OSL_ENSURE( pMarkTab, "Tabelle Crsr nicht im Content ??" );
1358 // Make code robust:
1359 if ( pMarkTab )
1361 bInRepeatedHeadline = pMarkTab->IsFollow() && pMarkTab->IsInHeadline( *pMarkTblFrm );
1366 // No table cursor in repeaded headlines:
1367 if ( bInRepeatedHeadline )
1369 pTblFrm = 0;
1371 SwPosSection fnPosSect = *pPos < *pITmpCrsr->GetMark()
1372 ? fnSectionStart
1373 : fnSectionEnd;
1375 // then only select inside the Box
1376 if( pTblCrsr )
1378 pCurCrsr->SetMark();
1379 *pCurCrsr->GetMark() = *pTblCrsr->GetMark();
1380 pCurCrsr->GetMkPos() = pTblCrsr->GetMkPos();
1381 pTblCrsr->DeleteMark();
1382 pTblCrsr->SwSelPaintRects::Hide();
1385 *pCurCrsr->GetPoint() = *pCurCrsr->GetMark();
1386 (*fnSectionCurr)( *pCurCrsr, fnPosSect );
1390 // we really want a table selection
1391 if( pTab && pTblFrm )
1393 if( !pTblCrsr )
1395 pTblCrsr = new SwShellTableCrsr( *this,
1396 *pCurCrsr->GetMark(), pCurCrsr->GetMkPos(),
1397 *pPos, aTmpPt );
1398 pCurCrsr->DeleteMark();
1399 pCurCrsr->SwSelPaintRects::Hide();
1401 CheckTblBoxCntnt();
1404 SwCrsrMoveState aTmpState( MV_NONE );
1405 aTmpState.bRealHeight = sal_True;
1406 if( !pTblFrm->GetCharRect( aCharRect, *pTblCrsr->GetPoint(), &aTmpState ) )
1408 Point aCentrPt( aCharRect.Center() );
1409 aTmpState.bSetInReadOnly = IsReadOnlyAvailable();
1410 pTblFrm->GetCrsrOfst( pTblCrsr->GetPoint(), aCentrPt, &aTmpState );
1411 bool const bResult =
1412 pTblFrm->GetCharRect( aCharRect, *pTblCrsr->GetPoint() );
1413 OSL_ENSURE( bResult, "GetCharRect failed." );
1414 (void) bResult; // non-debug: unused
1417 pVisCrsr->Hide(); // always hide visible Cursor
1418 // scroll Cursor to visible area
1419 if( (eFlags & SwCrsrShell::SCROLLWIN) &&
1420 (HasSelection() || eFlags & SwCrsrShell::READONLY ||
1421 !IsCrsrReadonly()) )
1423 SwFrm* pBoxFrm = pTblFrm;
1424 while( pBoxFrm && !pBoxFrm->IsCellFrm() )
1425 pBoxFrm = pBoxFrm->GetUpper();
1426 if( pBoxFrm && pBoxFrm->Frm().HasArea() )
1427 MakeVisible( pBoxFrm->Frm() );
1428 else
1429 MakeVisible( aCharRect );
1432 // let Layout create the Cursors in the Boxes
1433 if( pTblCrsr->IsCrsrMovedUpdt() )
1434 GetLayout()->MakeTblCrsrs( *pTblCrsr );
1435 if( bHasFocus && !bBasicHideCrsr )
1436 pTblCrsr->Show();
1438 // set Cursor-Points to the new Positions
1439 pTblCrsr->GetPtPos().X() = aCharRect.Left();
1440 pTblCrsr->GetPtPos().Y() = aCharRect.Top();
1442 if( bSVCrsrVis )
1444 aCrsrHeight.X() = 0;
1445 aCrsrHeight.Y() = aTmpState.aRealHeight.Y() < 0 ?
1446 -aCharRect.Width() : aCharRect.Height();
1447 pVisCrsr->Show(); // show again
1449 eMvState = MV_NONE; // state for cursor travelling - GetCrsrOfst
1450 if( pTblFrm && Imp()->IsAccessible() )
1451 Imp()->InvalidateAccessibleCursorPosition( pTblFrm );
1452 return;
1456 if( pTblCrsr )
1458 // delete Ring
1459 while( pCurCrsr->GetNext() != pCurCrsr )
1460 delete pCurCrsr->GetNext();
1461 pCurCrsr->DeleteMark();
1462 *pCurCrsr->GetPoint() = *pTblCrsr->GetPoint();
1463 pCurCrsr->GetPtPos() = pTblCrsr->GetPtPos();
1464 delete pTblCrsr, pTblCrsr = 0;
1467 pVisCrsr->Hide(); // always hide visible Cursor
1469 // are we perhaps in a protected / hidden Section ?
1471 SwShellCrsr* pShellCrsr = getShellCrsr( true );
1472 bool bChgState = true;
1473 const SwSectionNode* pSectNd = pShellCrsr->GetNode()->FindSectionNode();
1474 if( pSectNd && ( pSectNd->GetSection().IsHiddenFlag() ||
1475 ( !IsReadOnlyAvailable() &&
1476 pSectNd->GetSection().IsProtectFlag() &&
1477 ( !pDoc->GetDocShell() ||
1478 !pDoc->GetDocShell()->IsReadOnly() || bAllProtect )) ) )
1480 if( !FindValidCntntNode( !HasDrawView() ||
1481 0 == Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount()))
1483 // everything protected/hidden -> special mode
1484 if( bAllProtect && !IsReadOnlyAvailable() &&
1485 pSectNd->GetSection().IsProtectFlag() )
1486 bChgState = false;
1487 else
1489 eMvState = MV_NONE; // state for cursor travelling
1490 bAllProtect = sal_True;
1491 if( GetDoc()->GetDocShell() )
1493 GetDoc()->GetDocShell()->SetReadOnlyUI( sal_True );
1494 CallChgLnk(); // notify UI!
1496 return;
1500 if( bChgState )
1502 sal_Bool bWasAllProtect = bAllProtect;
1503 bAllProtect = sal_False;
1504 if( bWasAllProtect && GetDoc()->GetDocShell() &&
1505 GetDoc()->GetDocShell()->IsReadOnlyUI() )
1507 GetDoc()->GetDocShell()->SetReadOnlyUI( sal_False );
1508 CallChgLnk(); // notify UI!
1513 UpdateCrsrPos();
1515 // The cursor must always point into content; there's some code
1516 // that relies on this. (E.g. in SwEditShell::GetScriptType, which always
1517 // loops _behind_ the last node in the selection, which always works if you
1518 // are in content.) To achieve this, we'll force cursor(s) to point into
1519 // content, if UpdateCrsrPos() hasn't already done so.
1520 SwPaM* pCmp = pCurCrsr;
1523 // start will move forwards, end will move backwards
1524 bool bPointIsStart = ( pCmp->Start() == pCmp->GetPoint() );
1526 // move point; forward if it's the start, backwards if it's the end
1527 if( ! pCmp->GetPoint()->nNode.GetNode().IsCntntNode() )
1528 pCmp->Move( bPointIsStart ? fnMoveForward : fnMoveBackward,
1529 fnGoCntnt );
1531 // move mark (if exists); forward if it's the start, else backwards
1532 if( pCmp->HasMark() )
1534 if( ! pCmp->GetMark()->nNode.GetNode().IsCntntNode() )
1536 pCmp->Exchange();
1537 pCmp->Move( !bPointIsStart ? fnMoveForward : fnMoveBackward,
1538 fnGoCntnt );
1539 pCmp->Exchange();
1543 // iterate to next PaM in ring
1544 pCmp = static_cast<SwPaM*>( pCmp->GetNext() );
1546 while( pCmp != pCurCrsr );
1549 SwRect aOld( aCharRect );
1550 bool bFirst = true;
1551 SwCntntFrm *pFrm;
1552 int nLoopCnt = 100;
1553 SwShellCrsr* pShellCrsr = getShellCrsr( true );
1555 do {
1556 bool bAgainst;
1557 do {
1558 bAgainst = false;
1559 pFrm = pShellCrsr->GetCntntNode()->getLayoutFrm( GetLayout(),
1560 &pShellCrsr->GetPtPos(), pShellCrsr->GetPoint(), sal_False );
1561 // if the Frm doesn't exist anymore, the complete Layout has to be
1562 // created, because there used to be a Frm here!
1563 if ( !pFrm )
1567 CalcLayout();
1568 pFrm = pShellCrsr->GetCntntNode()->getLayoutFrm( GetLayout(),
1569 &pShellCrsr->GetPtPos(), pShellCrsr->GetPoint(), sal_False );
1570 } while( !pFrm );
1572 else if ( Imp()->IsIdleAction() )
1573 // Guarantee everything's properly formatted
1574 pFrm->PrepareCrsr();
1576 // In protected Fly? but ignore in case of frame selection
1577 if( !IsReadOnlyAvailable() && pFrm->IsProtected() &&
1578 ( !Imp()->GetDrawView() ||
1579 !Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount() ) &&
1580 (!pDoc->GetDocShell() ||
1581 !pDoc->GetDocShell()->IsReadOnly() || bAllProtect ) )
1583 // look for a valid position
1584 bool bChgState = true;
1585 if( !FindValidCntntNode(!HasDrawView() ||
1586 0 == Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount()))
1588 // everything is protected / hidden -> special Mode
1589 if( bAllProtect )
1590 bChgState = false;
1591 else
1593 eMvState = MV_NONE; // state for crusor travelling
1594 bAllProtect = sal_True;
1595 if( GetDoc()->GetDocShell() )
1597 GetDoc()->GetDocShell()->SetReadOnlyUI( sal_True );
1598 CallChgLnk(); // notify UI!
1600 return;
1604 if( bChgState )
1606 sal_Bool bWasAllProtect = bAllProtect;
1607 bAllProtect = sal_False;
1608 if( bWasAllProtect && GetDoc()->GetDocShell() &&
1609 GetDoc()->GetDocShell()->IsReadOnlyUI() )
1611 GetDoc()->GetDocShell()->SetReadOnlyUI( sal_False );
1612 CallChgLnk(); // notify UI!
1614 bAllProtect = sal_False;
1615 bAgainst = true; // look for the right Frm again
1618 } while( bAgainst );
1620 if( !( eFlags & SwCrsrShell::NOCALRECT ))
1622 SwCrsrMoveState aTmpState( eMvState );
1623 aTmpState.bSetInReadOnly = IsReadOnlyAvailable();
1624 aTmpState.bRealHeight = sal_True;
1625 aTmpState.bRealWidth = IsOverwriteCrsr();
1626 aTmpState.nCursorBidiLevel = pShellCrsr->GetCrsrBidiLevel();
1628 // #i27615#,#i30453#
1629 SwSpecialPos aSpecialPos;
1630 aSpecialPos.nExtendRange = SP_EXTEND_RANGE_BEFORE;
1631 if (pShellCrsr->IsInFrontOfLabel())
1633 aTmpState.pSpecialPos = &aSpecialPos;
1636 if( !pFrm->GetCharRect( aCharRect, *pShellCrsr->GetPoint(), &aTmpState ) )
1638 Point& rPt = pShellCrsr->GetPtPos();
1639 rPt = aCharRect.Center();
1640 pFrm->GetCrsrOfst( pShellCrsr->GetPoint(), rPt, &aTmpState );
1643 if( !pShellCrsr->HasMark() )
1644 aCrsrHeight = aTmpState.aRealHeight;
1645 else
1647 aCrsrHeight.X() = 0;
1648 aCrsrHeight.Y() = aTmpState.aRealHeight.Y() < 0 ?
1649 -aCharRect.Width() : aCharRect.Height();
1652 else
1654 aCrsrHeight.X() = 0;
1655 aCrsrHeight.Y() = aCharRect.Height();
1658 if( !bFirst && aOld == aCharRect )
1659 break;
1661 // if the layout says that we are after the 100th iteration still in
1662 // flow then we should always take the current position for granted.
1663 // (see bug: 29658)
1664 if( !--nLoopCnt )
1666 OSL_ENSURE( !this, "endless loop? CharRect != OldCharRect ");
1667 break;
1669 aOld = aCharRect;
1670 bFirst = false;
1672 // update cursor Points to the new Positions
1673 pShellCrsr->GetPtPos().X() = aCharRect.Left();
1674 pShellCrsr->GetPtPos().Y() = aCharRect.Top();
1676 if( !(eFlags & SwCrsrShell::UPDOWN )) // delete old Pos. of Up/Down
1678 pFrm->Calc();
1679 nUpDownX = pFrm->IsVertical() ?
1680 aCharRect.Top() - pFrm->Frm().Top() :
1681 aCharRect.Left() - pFrm->Frm().Left();
1684 // scroll Cursor to visible area
1685 if( bHasFocus && eFlags & SwCrsrShell::SCROLLWIN &&
1686 (HasSelection() || eFlags & SwCrsrShell::READONLY ||
1687 !IsCrsrReadonly() || GetViewOptions()->IsSelectionInReadonly()) )
1689 // in case of scrolling this EndAction doesn't show the SV cursor
1690 // again, thus save and reset the flag here
1691 sal_Bool bSav = bSVCrsrVis; bSVCrsrVis = sal_False;
1692 MakeSelVisible();
1693 bSVCrsrVis = bSav;
1696 } while( eFlags & SwCrsrShell::SCROLLWIN );
1698 if( pBlockCrsr )
1699 RefreshBlockCursor();
1701 if( !bIdleEnd && bHasFocus && !bBasicHideCrsr )
1703 if( pTblCrsr )
1704 pTblCrsr->SwSelPaintRects::Show();
1705 else
1707 pCurCrsr->SwSelPaintRects::Show();
1708 if( pBlockCrsr )
1710 SwShellCrsr* pNxt = dynamic_cast<SwShellCrsr*>(pCurCrsr->GetNext());
1711 while( pNxt && pNxt != pCurCrsr )
1713 pNxt->SwSelPaintRects::Show();
1714 pNxt = dynamic_cast<SwShellCrsr*>(pNxt->GetNext());
1720 eMvState = MV_NONE; // state for cursor tavelling - GetCrsrOfst
1722 if( pFrm && Imp()->IsAccessible() )
1723 Imp()->InvalidateAccessibleCursorPosition( pFrm );
1725 // switch from blinking cursor to read-only-text-selection cursor
1726 static const long nNoBlinkTime = STYLE_CURSOR_NOBLINKTIME;
1727 const long nBlinkTime = GetOut()->GetSettings().GetStyleSettings().
1728 GetCursorBlinkTime();
1730 if ( (IsCrsrReadonly() && GetViewOptions()->IsSelectionInReadonly()) ==
1731 ( nBlinkTime != nNoBlinkTime ) )
1733 // non blinking cursor in read only - text selection mode
1734 AllSettings aSettings = GetOut()->GetSettings();
1735 StyleSettings aStyleSettings = aSettings.GetStyleSettings();
1736 const long nNewBlinkTime = nBlinkTime == nNoBlinkTime ?
1737 Application::GetSettings().GetStyleSettings().GetCursorBlinkTime() :
1738 nNoBlinkTime;
1739 aStyleSettings.SetCursorBlinkTime( nNewBlinkTime );
1740 aSettings.SetStyleSettings( aStyleSettings );
1741 GetOut()->SetSettings( aSettings );
1744 if( bSVCrsrVis )
1745 pVisCrsr->Show(); // show again
1748 void SwCrsrShell::RefreshBlockCursor()
1750 OSL_ENSURE( pBlockCrsr, "Don't call me without a block cursor" );
1751 SwShellCrsr &rBlock = pBlockCrsr->getShellCrsr();
1752 Point aPt = rBlock.GetPtPos();
1753 SwCntntFrm* pFrm = rBlock.GetCntntNode()->getLayoutFrm( GetLayout(), &aPt, rBlock.GetPoint(), sal_False );
1754 Point aMk;
1755 if( pBlockCrsr->getEndPoint() && pBlockCrsr->getStartPoint() )
1757 aPt = *pBlockCrsr->getStartPoint();
1758 aMk = *pBlockCrsr->getEndPoint();
1760 else
1762 aPt = rBlock.GetPtPos();
1763 if( pFrm )
1765 if( pFrm->IsVertical() )
1766 aPt.Y() = pFrm->Frm().Top() + GetUpDownX();
1767 else
1768 aPt.X() = pFrm->Frm().Left() + GetUpDownX();
1770 aMk = rBlock.GetMkPos();
1772 SwRect aRect( aMk, aPt );
1773 aRect.Justify();
1774 SwSelectionList aSelList( pFrm );
1776 if( GetLayout()->FillSelection( aSelList, aRect ) )
1778 SwCursor* pNxt = (SwCursor*)pCurCrsr->GetNext();
1779 while( pNxt != pCurCrsr )
1781 delete pNxt;
1782 pNxt = (SwCursor*)pCurCrsr->GetNext();
1785 std::list<SwPaM*>::iterator pStart = aSelList.getStart();
1786 std::list<SwPaM*>::iterator pPam = aSelList.getEnd();
1787 OSL_ENSURE( pPam != pStart, "FillSelection should deliver at least one PaM" );
1788 pCurCrsr->SetMark();
1789 --pPam;
1790 // If there is only one text portion inside the rectangle, a simple
1791 // selection is created
1792 if( pPam == pStart )
1794 *pCurCrsr->GetPoint() = *(*pPam)->GetPoint();
1795 if( (*pPam)->HasMark() )
1796 *pCurCrsr->GetMark() = *(*pPam)->GetMark();
1797 else
1798 pCurCrsr->DeleteMark();
1799 delete *pPam;
1800 pCurCrsr->SetColumnSelection( false );
1802 else
1804 // The order of the SwSelectionList has to be preserved but
1805 // the order inside the ring created by CreateCrsr() is not like
1806 // exspected => First create the selections before the last one
1807 // downto the first selection.
1808 // At least create the cursor for the last selection
1809 --pPam;
1810 *pCurCrsr->GetPoint() = *(*pPam)->GetPoint(); // n-1 (if n == number of selections)
1811 if( (*pPam)->HasMark() )
1812 *pCurCrsr->GetMark() = *(*pPam)->GetMark();
1813 else
1814 pCurCrsr->DeleteMark();
1815 delete *pPam;
1816 pCurCrsr->SetColumnSelection( true );
1817 while( pPam != pStart )
1819 --pPam;
1821 SwShellCrsr* pNew = new SwShellCrsr( *pCurCrsr );
1822 pNew->insert( pNew->begin(), pCurCrsr->begin(), pCurCrsr->end());
1823 pCurCrsr->clear();
1824 pCurCrsr->DeleteMark();
1826 *pCurCrsr->GetPoint() = *(*pPam)->GetPoint(); // n-2, n-3, .., 2, 1
1827 if( (*pPam)->HasMark() )
1829 pCurCrsr->SetMark();
1830 *pCurCrsr->GetMark() = *(*pPam)->GetMark();
1832 else
1833 pCurCrsr->DeleteMark();
1834 pCurCrsr->SetColumnSelection( true );
1835 delete *pPam;
1838 SwShellCrsr* pNew = new SwShellCrsr( *pCurCrsr );
1839 pNew->insert( pNew->begin(), pCurCrsr->begin(), pCurCrsr->end() );
1840 pCurCrsr->clear();
1841 pCurCrsr->DeleteMark();
1843 pPam = aSelList.getEnd();
1844 --pPam;
1845 *pCurCrsr->GetPoint() = *(*pPam)->GetPoint(); // n, the last selection
1846 if( (*pPam)->HasMark() )
1848 pCurCrsr->SetMark();
1849 *pCurCrsr->GetMark() = *(*pPam)->GetMark();
1851 else
1852 pCurCrsr->DeleteMark();
1853 pCurCrsr->SetColumnSelection( true );
1854 delete *pPam;
1859 /// create a copy of the cursor and save it in the stack
1860 void SwCrsrShell::Push()
1862 pCrsrStk = new SwShellCrsr( *this, *pCurCrsr->GetPoint(),
1863 pCurCrsr->GetPtPos(), pCrsrStk );
1865 if( pCurCrsr->HasMark() )
1867 pCrsrStk->SetMark();
1868 *pCrsrStk->GetMark() = *pCurCrsr->GetMark();
1872 /** delete cursor
1874 @param bOldCrsr If <true> so delete from stack, if <false> delete current
1875 and assign the one from stack as the new current cursor.
1876 @return <true> if there was one on the stack, <false> otherwise
1878 sal_Bool SwCrsrShell::Pop( sal_Bool bOldCrsr )
1880 SwCallLink aLk( *this ); // watch Crsr-Moves; call Link if needed
1882 // are there any left?
1883 if( 0 == pCrsrStk )
1884 return sal_False;
1886 SwShellCrsr *pTmp = 0, *pOldStk = pCrsrStk;
1888 // the successor becomes the current one
1889 if( pCrsrStk->GetNext() != pCrsrStk )
1891 pTmp = dynamic_cast<SwShellCrsr*>(pCrsrStk->GetNext());
1894 if( bOldCrsr ) // delete from stack
1895 delete pCrsrStk;
1897 pCrsrStk = pTmp; // assign new one
1899 if( !bOldCrsr )
1901 SwCrsrSaveState aSaveState( *pCurCrsr );
1903 // If the visible SSelection was not changed
1904 if( pOldStk->GetPtPos() == pCurCrsr->GetPtPos() ||
1905 pOldStk->GetPtPos() == pCurCrsr->GetMkPos() )
1907 // move "Selections Rectangles"
1908 pCurCrsr->insert( pCurCrsr->begin(), pOldStk->begin(), pOldStk->end() );
1909 pOldStk->clear();
1912 if( pOldStk->HasMark() )
1914 pCurCrsr->SetMark();
1915 *pCurCrsr->GetMark() = *pOldStk->GetMark();
1916 pCurCrsr->GetMkPos() = pOldStk->GetMkPos();
1918 else
1919 // no selection so revoke old one and set to old position
1920 pCurCrsr->DeleteMark();
1921 *pCurCrsr->GetPoint() = *pOldStk->GetPoint();
1922 pCurCrsr->GetPtPos() = pOldStk->GetPtPos();
1923 delete pOldStk;
1925 if( !pCurCrsr->IsInProtectTable( sal_True ) &&
1926 !pCurCrsr->IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
1927 nsSwCursorSelOverFlags::SELOVER_CHANGEPOS ) )
1928 UpdateCrsr(); // update current cursor
1930 return sal_True;
1933 /** Combine two cursors
1935 Delete topmost from stack and use its GetMark in the current.
1937 void SwCrsrShell::Combine()
1939 // any others left?
1940 if( 0 == pCrsrStk )
1941 return;
1943 SwCallLink aLk( *this ); // watch Crsr-Moves; call Link if needed
1944 // rhbz#689053: IsSelOvr must restore the saved stack position, not the
1945 // current one, because current point + stack mark may be invalid PaM
1946 SwCrsrSaveState aSaveState(*pCrsrStk);
1947 // stack cursor & current cursor in same Section?
1948 assert(!pCrsrStk->HasMark() ||
1949 CheckNodesRange(pCrsrStk->GetMark()->nNode,
1950 pCurCrsr->GetPoint()->nNode, true));
1951 *pCrsrStk->GetPoint() = *pCurCrsr->GetPoint();
1952 pCrsrStk->GetPtPos() = pCurCrsr->GetPtPos();
1954 SwShellCrsr * pTmp = 0;
1955 if( pCrsrStk->GetNext() != pCrsrStk )
1957 pTmp = dynamic_cast<SwShellCrsr*>(pCrsrStk->GetNext());
1959 delete pCurCrsr;
1960 pCurCrsr = pCrsrStk;
1961 pCrsrStk->MoveTo(0); // remove from ring
1962 pCrsrStk = pTmp;
1963 if( !pCurCrsr->IsInProtectTable( sal_True ) &&
1964 !pCurCrsr->IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
1965 nsSwCursorSelOverFlags::SELOVER_CHANGEPOS ) )
1967 UpdateCrsr(); // update current cursor
1972 void SwCrsrShell::HideCrsrs()
1974 if( !bHasFocus || bBasicHideCrsr )
1975 return;
1977 // if cursor is visible then hide SV cursor
1978 if( pVisCrsr->IsVisible() )
1980 SET_CURR_SHELL( this );
1981 pVisCrsr->Hide();
1983 // revoke inversion of SSelection
1984 SwShellCrsr* pAktCrsr = pTblCrsr ? pTblCrsr : pCurCrsr;
1985 pAktCrsr->Hide();
1990 void SwCrsrShell::ShowCrsrs( sal_Bool bCrsrVis )
1992 if( !bHasFocus || bAllProtect || bBasicHideCrsr )
1993 return;
1995 SET_CURR_SHELL( this );
1996 SwShellCrsr* pAktCrsr = pTblCrsr ? pTblCrsr : pCurCrsr;
1997 pAktCrsr->Show();
1999 if( bSVCrsrVis && bCrsrVis ) // also show SV cursor again
2000 pVisCrsr->Show();
2005 void SwCrsrShell::ShowCrsr()
2007 if( !bBasicHideCrsr )
2009 bSVCrsrVis = sal_True;
2010 UpdateCrsr();
2015 void SwCrsrShell::HideCrsr()
2017 if( !bBasicHideCrsr )
2019 bSVCrsrVis = sal_False;
2020 // evt. die sel. Bereiche aufheben !!
2021 SET_CURR_SHELL( this );
2022 pVisCrsr->Hide();
2027 void SwCrsrShell::ShLooseFcs()
2029 if( !bBasicHideCrsr )
2030 HideCrsrs();
2031 bHasFocus = sal_False;
2035 void SwCrsrShell::ShGetFcs( sal_Bool bUpdate )
2037 bHasFocus = sal_True;
2038 if( !bBasicHideCrsr && VisArea().Width() )
2040 UpdateCrsr( static_cast<sal_uInt16>( bUpdate ?
2041 SwCrsrShell::CHKRANGE|SwCrsrShell::SCROLLWIN
2042 : SwCrsrShell::CHKRANGE ) );
2043 ShowCrsrs( bSVCrsrVis ? sal_True : sal_False );
2047 /** Get current frame in which the cursor is positioned. */
2048 SwCntntFrm *SwCrsrShell::GetCurrFrm( const sal_Bool bCalcFrm ) const
2050 SET_CURR_SHELL( (ViewShell*)this );
2051 SwCntntFrm *pRet = 0;
2052 SwCntntNode *pNd = pCurCrsr->GetCntntNode();
2053 if ( pNd )
2055 if ( bCalcFrm )
2057 const sal_uInt16* pST = &nStartAction;
2058 ++(*((sal_uInt16*)pST));
2059 const Size aOldSz( GetDocSize() );
2060 pRet = pNd->getLayoutFrm( GetLayout(), &pCurCrsr->GetPtPos(), pCurCrsr->GetPoint() );
2061 --(*((sal_uInt16*)pST));
2062 if( aOldSz != GetDocSize() )
2063 ((SwCrsrShell*)this)->SizeChgNotify();
2065 else
2066 pRet = pNd->getLayoutFrm( GetLayout(), &pCurCrsr->GetPtPos(), pCurCrsr->GetPoint(), sal_False);
2068 return pRet;
2071 //TODO: provide documentation
2072 /** forward all attribute/format changes at the current node to the Link
2074 @param pOld ???
2075 @param pNew ???
2077 void SwCrsrShell::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew )
2079 const sal_uInt16 nWhich = pOld ?
2080 pOld->Which() :
2081 pNew ?
2082 pNew->Which() :
2083 sal::static_int_cast<sal_uInt16>(RES_MSG_BEGIN);
2085 if( bCallChgLnk &&
2086 ( nWhich < RES_MSG_BEGIN || nWhich >= RES_MSG_END ||
2087 nWhich == RES_FMT_CHG || nWhich == RES_UPDATE_ATTR ||
2088 nWhich == RES_ATTRSET_CHG ))
2089 // messages are not forwarded
2090 // #i6681#: RES_UPDATE_ATTR is implicitly unset in
2091 // SwTxtNode::Insert(SwTxtHint*, sal_uInt16); we react here and thus do
2092 // not need to send the expensive RES_FMT_CHG in Insert.
2093 CallChgLnk();
2095 if( aGrfArrivedLnk.IsSet() &&
2096 ( RES_GRAPHIC_ARRIVED == nWhich || RES_GRAPHIC_SWAPIN == nWhich ))
2097 aGrfArrivedLnk.Call( this );
2100 /** Does the current cursor create a selection?
2102 This means checking if GetMark is set and if SPoint and GetMark differ.
2104 sal_Bool SwCrsrShell::HasSelection() const
2106 const SwPaM* pCrsr = getShellCrsr( true );
2107 return( IsTableMode() || ( pCrsr->HasMark() &&
2108 *pCrsr->GetPoint() != *pCrsr->GetMark())
2109 ? sal_True : sal_False );
2113 void SwCrsrShell::CallChgLnk()
2115 // Do not make any call in start/end action but just remember the change.
2116 // This will be taken care of in the end action.
2117 if( BasicActionPend() )
2118 bChgCallFlag = sal_True; // remember change
2119 else if( aChgLnk.IsSet() )
2121 if( bCallChgLnk )
2122 aChgLnk.Call( this );
2123 bChgCallFlag = sal_False; // reset flag
2127 /// get selected text of a node at current cursor
2128 String SwCrsrShell::GetSelTxt() const
2130 String aTxt;
2131 if( pCurCrsr->GetPoint()->nNode.GetIndex() ==
2132 pCurCrsr->GetMark()->nNode.GetIndex() )
2134 SwTxtNode* pTxtNd = pCurCrsr->GetNode()->GetTxtNode();
2135 if( pTxtNd )
2137 xub_StrLen nStt = pCurCrsr->Start()->nContent.GetIndex();
2138 aTxt = pTxtNd->GetExpandTxt( nStt,
2139 pCurCrsr->End()->nContent.GetIndex() - nStt );
2142 return aTxt;
2145 /// get text only from current cursor position (until end of node)
2146 String SwCrsrShell::GetText() const
2148 String aTxt;
2149 if( pCurCrsr->GetPoint()->nNode.GetIndex() ==
2150 pCurCrsr->GetMark()->nNode.GetIndex() )
2152 SwTxtNode* pTxtNd = pCurCrsr->GetNode()->GetTxtNode();
2153 if( pTxtNd )
2154 aTxt = pTxtNd->GetTxt().Copy(
2155 pCurCrsr->GetPoint()->nContent.GetIndex() );
2157 return aTxt;
2160 /** get the nth character of the current SSelection
2162 @param bEnd Start counting from the end? From start otherwise.
2163 @param nOffset position of the character
2165 sal_Unicode SwCrsrShell::GetChar( sal_Bool bEnd, long nOffset )
2167 if( IsTableMode() ) // not possible in table mode
2168 return 0;
2170 const SwPosition* pPos = !pCurCrsr->HasMark() ? pCurCrsr->GetPoint()
2171 : bEnd ? pCurCrsr->End() : pCurCrsr->Start();
2172 SwTxtNode* pTxtNd = pPos->nNode.GetNode().GetTxtNode();
2173 if( !pTxtNd )
2174 return 0;
2176 xub_StrLen nPos = pPos->nContent.GetIndex();
2177 const String& rStr = pTxtNd->GetTxt();
2178 sal_Unicode cCh = 0;
2180 if( ((nPos+nOffset) >= 0 ) && (nPos+nOffset) < rStr.Len() )
2181 cCh = rStr.GetChar( static_cast<xub_StrLen>(nPos+nOffset) );
2183 return cCh;
2186 /** extend current SSelection by n characters
2188 @param bEnd Start counting from the end? From start otherwise.
2189 @param nCount Number of characters.
2191 sal_Bool SwCrsrShell::ExtendSelection( sal_Bool bEnd, xub_StrLen nCount )
2193 if( !pCurCrsr->HasMark() || IsTableMode() )
2194 return sal_False; // no selection
2196 SwPosition* pPos = bEnd ? pCurCrsr->End() : pCurCrsr->Start();
2197 SwTxtNode* pTxtNd = pPos->nNode.GetNode().GetTxtNode();
2198 OSL_ENSURE( pTxtNd, "no text node; how should this then be extended?" );
2200 xub_StrLen nPos = pPos->nContent.GetIndex();
2201 if( bEnd )
2203 if( ( nPos + nCount ) <= pTxtNd->GetTxt().Len() )
2204 nPos = nPos + nCount;
2205 else
2206 return sal_False; // not possible
2208 else if( nPos >= nCount )
2209 nPos = nPos - nCount;
2210 else
2211 return sal_False; // not possible anymore
2213 SwCallLink aLk( *this ); // watch Crsr-Moves; call Link if needed
2215 pPos->nContent = nPos;
2216 UpdateCrsr();
2218 return sal_True;
2221 /** Move visible cursor to given position in document.
2223 @param rPt The position to move the visible cursor to.
2224 @return <sal_False> if SPoint was corrected by the layout.
2226 sal_Bool SwCrsrShell::SetVisCrsr( const Point &rPt )
2228 SET_CURR_SHELL( this );
2229 Point aPt( rPt );
2230 SwPosition aPos( *pCurCrsr->GetPoint() );
2231 SwCrsrMoveState aTmpState( MV_SETONLYTEXT );
2232 aTmpState.bSetInReadOnly = IsReadOnlyAvailable();
2233 aTmpState.bRealHeight = sal_True;
2235 sal_Bool bRet = GetLayout()->GetCrsrOfst( &aPos, aPt /*, &aTmpState*/ );
2237 SetInFrontOfLabel( false ); // #i27615#
2239 // show only in TextNodes
2240 SwTxtNode* pTxtNd = aPos.nNode.GetNode().GetTxtNode();
2241 if( !pTxtNd )
2242 return sal_False;
2244 const SwSectionNode* pSectNd = pTxtNd->FindSectionNode();
2245 if( pSectNd && (pSectNd->GetSection().IsHiddenFlag() ||
2246 ( !IsReadOnlyAvailable() &&
2247 pSectNd->GetSection().IsProtectFlag())) )
2248 return sal_False;
2250 SwCntntFrm *pFrm = pTxtNd->getLayoutFrm( GetLayout(), &aPt, &aPos );
2251 if ( Imp()->IsIdleAction() )
2252 pFrm->PrepareCrsr();
2253 SwRect aTmp( aCharRect );
2255 pFrm->GetCharRect( aCharRect, aPos, &aTmpState );
2257 // #i10137#
2258 if( aTmp == aCharRect && pVisCrsr->IsVisible() )
2259 return sal_True;
2261 pVisCrsr->Hide(); // always hide visible cursor
2262 if( IsScrollMDI( this, aCharRect ))
2264 MakeVisible( aCharRect );
2265 pCurCrsr->Show();
2269 if( aTmpState.bRealHeight )
2270 aCrsrHeight = aTmpState.aRealHeight;
2271 else
2273 aCrsrHeight.X() = 0;
2274 aCrsrHeight.Y() = aCharRect.Height();
2277 pVisCrsr->SetDragCrsr( true );
2278 pVisCrsr->Show(); // show again
2280 return bRet;
2283 sal_Bool SwCrsrShell::IsOverReadOnlyPos( const Point& rPt ) const
2285 Point aPt( rPt );
2286 SwPaM aPam( *pCurCrsr->GetPoint() );
2287 GetLayout()->GetCrsrOfst( aPam.GetPoint(), aPt );
2288 // Formular view
2289 return aPam.HasReadonlySel( GetViewOptions()->IsFormView() );
2292 sal_Bool SwCrsrShell::IsOverHeaderFooterPos( const Point& rPt ) const
2294 Point aPt( rPt );
2295 SwPaM aPam( *pCurCrsr->GetPoint() );
2296 GetLayout()->GetCrsrOfst( aPam.GetPoint(), aPt );
2298 return GetDoc()->IsInHeaderFooter( aPam.GetPoint()->nNode );
2301 /** Get the number of elements in the ring of cursors
2303 @param bAll If <false> get only spanned ones (= with selections) (Basic).
2305 sal_uInt16 SwCrsrShell::GetCrsrCnt( sal_Bool bAll ) const
2307 Ring* pTmp = GetCrsr()->GetNext();
2308 sal_uInt16 n = (bAll || ( pCurCrsr->HasMark() &&
2309 *pCurCrsr->GetPoint() != *pCurCrsr->GetMark())) ? 1 : 0;
2310 while( pTmp != pCurCrsr )
2312 if( bAll || ( ((SwPaM*)pTmp)->HasMark() &&
2313 *((SwPaM*)pTmp)->GetPoint() != *((SwPaM*)pTmp)->GetMark()))
2314 ++n;
2315 pTmp = pTmp->GetNext();
2317 return n;
2321 sal_Bool SwCrsrShell::IsStartOfDoc() const
2323 if( pCurCrsr->GetPoint()->nContent.GetIndex() )
2324 return sal_False;
2326 // after EndOfIcons comes the content selection (EndNd+StNd+CntntNd)
2327 SwNodeIndex aIdx( GetDoc()->GetNodes().GetEndOfExtras(), 2 );
2328 if( !aIdx.GetNode().IsCntntNode() )
2329 GetDoc()->GetNodes().GoNext( &aIdx );
2330 return aIdx == pCurCrsr->GetPoint()->nNode;
2334 sal_Bool SwCrsrShell::IsEndOfDoc() const
2336 SwNodeIndex aIdx( GetDoc()->GetNodes().GetEndOfContent(), -1 );
2337 SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
2338 if( !pCNd )
2339 pCNd = GetDoc()->GetNodes().GoPrevious( &aIdx );
2341 return aIdx == pCurCrsr->GetPoint()->nNode &&
2342 pCNd->Len() == pCurCrsr->GetPoint()->nContent.GetIndex();
2345 /** Invalidate cursors
2347 Delete all created cursors, set table crsr and last crsr to their TextNode
2348 (or StartNode?). They will then all re-created at the next ::GetCrsr() call.
2350 This is needed for Drag&Drop/ Clipboard-paste in tables.
2352 sal_Bool SwCrsrShell::ParkTblCrsr()
2354 if( !pTblCrsr )
2355 return sal_False;
2357 pTblCrsr->ParkCrsr();
2359 while( pCurCrsr->GetNext() != pCurCrsr )
2360 delete pCurCrsr->GetNext();
2362 // *always* move cursor's SPoint and Mark
2363 pCurCrsr->SetMark();
2364 *pCurCrsr->GetMark() = *pCurCrsr->GetPoint() = *pTblCrsr->GetPoint();
2365 pCurCrsr->DeleteMark();
2367 return sal_True;
2370 void SwCrsrShell::_ParkPams( SwPaM* pDelRg, SwShellCrsr** ppDelRing )
2372 const SwPosition *pStt = pDelRg->Start(),
2373 *pEnd = pDelRg->GetPoint() == pStt ? pDelRg->GetMark() : pDelRg->GetPoint();
2375 SwPaM *pTmpDel = 0, *pTmp = *ppDelRing;
2377 // search over the whole ring
2378 bool bGoNext;
2379 do {
2380 const SwPosition *pTmpStt = pTmp->Start(),
2381 *pTmpEnd = pTmp->GetPoint() == pTmpStt ?
2382 pTmp->GetMark() : pTmp->GetPoint();
2383 // If a SPoint or GetMark are in a cursor area than cancel the old area.
2384 // During comparison keep in mind that End() is outside the area.
2385 if( *pStt <= *pTmpStt )
2387 if( *pEnd > *pTmpStt ||
2388 ( *pEnd == *pTmpStt && *pEnd == *pTmpEnd ))
2389 pTmpDel = pTmp;
2391 else
2392 if( *pStt < *pTmpEnd )
2393 pTmpDel = pTmp;
2395 bGoNext = true;
2396 if( pTmpDel ) // is the pam in area -> delete
2398 sal_Bool bDelete = sal_True;
2399 if( *ppDelRing == pTmpDel )
2401 if( *ppDelRing == pCurCrsr )
2403 if( sal_True == ( bDelete = GoNextCrsr() ))
2405 bGoNext = false;
2406 pTmp = (SwPaM*)pTmp->GetNext();
2409 else
2410 bDelete = sal_False; // never delete the StackCrsr
2413 if( bDelete )
2414 delete pTmpDel; // invalidate old area
2415 else
2417 pTmpDel->GetPoint()->nContent.Assign( 0, 0 );
2418 pTmpDel->GetPoint()->nNode = 0;
2419 pTmpDel->SetMark();
2420 pTmpDel->DeleteMark();
2422 pTmpDel = 0;
2424 else if( !pTmp->HasMark() )
2426 // Take care that not used indices are considered.
2427 // SPoint is not in area but maybe GetMark is, thus set it.
2428 pTmp->SetMark();
2429 pTmp->DeleteMark();
2431 if( bGoNext )
2432 pTmp = (SwPaM*)pTmp->GetNext();
2433 } while( !bGoNext || *ppDelRing != pTmp );
2436 //TODO: provide documentation
2437 /** Remove selections and additional cursors of all shells.
2439 The remaining cursor of the shell is parked.
2441 @param rIdx ???
2443 void SwCrsrShell::ParkCrsr( const SwNodeIndex &rIdx )
2445 SwNode *pNode = &rIdx.GetNode();
2447 // create a new PaM
2448 SwPaM * pNew = new SwPaM( *GetCrsr()->GetPoint() );
2449 if( pNode->GetStartNode() )
2451 if( ( pNode = pNode->StartOfSectionNode())->IsTableNode() )
2453 // the given node is in a table, thus park cursor to table node
2454 // (outside of the table)
2455 pNew->GetPoint()->nNode = *pNode->StartOfSectionNode();
2457 else
2458 // Also on the start node itself. Then we need to request the start
2459 // node always via its end node! (StartOfSelection of StartNode is
2460 // the parent)
2461 pNew->GetPoint()->nNode = *pNode->EndOfSectionNode()->StartOfSectionNode();
2463 else
2464 pNew->GetPoint()->nNode = *pNode->StartOfSectionNode();
2465 pNew->SetMark();
2466 pNew->GetPoint()->nNode = *pNode->EndOfSectionNode();
2468 // take care of all shells
2469 ViewShell *pTmp = this;
2470 do {
2471 if( pTmp->IsA( TYPE( SwCrsrShell )))
2473 SwCrsrShell* pSh = (SwCrsrShell*)pTmp;
2474 if( pSh->pCrsrStk )
2475 pSh->_ParkPams( pNew, &pSh->pCrsrStk );
2477 pSh->_ParkPams( pNew, &pSh->pCurCrsr );
2478 if( pSh->pTblCrsr )
2480 // set table cursor always to 0 and the current one always to
2481 // the beginning of the table
2482 SwPaM* pTCrsr = pSh->GetTblCrs();
2483 SwNode* pTblNd = pTCrsr->GetPoint()->nNode.GetNode().FindTableNode();
2484 if ( pTblNd )
2486 pTCrsr->GetPoint()->nContent.Assign( 0, 0 );
2487 pTCrsr->GetPoint()->nNode = 0;
2488 pTCrsr->SetMark();
2489 pTCrsr->DeleteMark();
2490 pSh->pCurCrsr->GetPoint()->nNode = *pTblNd;
2494 } while ( this != (pTmp = (ViewShell*)pTmp->GetNext() ));
2495 delete pNew;
2499 /** Copy constructor
2501 Copy cursor position and add it to the ring.
2502 All views of a document are in the ring of the shell.
2504 SwCrsrShell::SwCrsrShell( SwCrsrShell& rShell, Window *pInitWin )
2505 : ViewShell( rShell, pInitWin ),
2506 SwModify( 0 ), pCrsrStk( 0 ), pBlockCrsr( 0 ), pTblCrsr( 0 ),
2507 pBoxIdx( 0 ), pBoxPtr( 0 ), nCrsrMove( 0 ), nBasicActionCnt( 0 ),
2508 eMvState( MV_NONE ),
2509 sMarkedListId(),
2510 nMarkedListLevel( 0 )
2512 SET_CURR_SHELL( this );
2513 // only keep the position of the current cursor of the copy shell
2514 pCurCrsr = new SwShellCrsr( *this, *(rShell.pCurCrsr->GetPoint()) );
2515 pCurCrsr->GetCntntNode()->Add( this );
2517 bAllProtect = bVisPortChgd = bChgCallFlag = bInCMvVisportChgd =
2518 bGCAttr = bIgnoreReadonly = bSelTblCells = bBasicHideCrsr =
2519 bOverwriteCrsr = sal_False;
2520 bCallChgLnk = bHasFocus = bSVCrsrVis = bAutoUpdateCells = sal_True;
2521 bSetCrsrInReadOnly = sal_True;
2522 pVisCrsr = new SwVisCrsr( this );
2523 mbMacroExecAllowed = rShell.IsMacroExecAllowed();
2526 /// default constructor
2527 SwCrsrShell::SwCrsrShell( SwDoc& rDoc, Window *pInitWin,
2528 const SwViewOption *pInitOpt )
2529 : ViewShell( rDoc, pInitWin, pInitOpt ),
2530 SwModify( 0 ), pCrsrStk( 0 ), pBlockCrsr( 0 ), pTblCrsr( 0 ),
2531 pBoxIdx( 0 ), pBoxPtr( 0 ), nCrsrMove( 0 ), nBasicActionCnt( 0 ),
2532 eMvState( MV_NONE ), // state for crsr-travelling - GetCrsrOfst
2533 sMarkedListId(),
2534 nMarkedListLevel( 0 )
2536 SET_CURR_SHELL( this );
2537 // create initial cursor and set it to first content position
2538 SwNodes& rNds = rDoc.GetNodes();
2540 SwNodeIndex aNodeIdx( *rNds.GetEndOfContent().StartOfSectionNode() );
2541 SwCntntNode* pCNd = rNds.GoNext( &aNodeIdx ); // gehe zum 1. ContentNode
2543 pCurCrsr = new SwShellCrsr( *this, SwPosition( aNodeIdx, SwIndex( pCNd, 0 )));
2545 // Register shell as dependent at current node. As a result all attribute
2546 // changes can be forwarded via the Link.
2547 pCNd->Add( this );
2549 bAllProtect = bVisPortChgd = bChgCallFlag = bInCMvVisportChgd =
2550 bGCAttr = bIgnoreReadonly = bSelTblCells = bBasicHideCrsr =
2551 bOverwriteCrsr = sal_False;
2552 bCallChgLnk = bHasFocus = bSVCrsrVis = bAutoUpdateCells = sal_True;
2553 bSetCrsrInReadOnly = sal_True;
2555 pVisCrsr = new SwVisCrsr( this );
2556 mbMacroExecAllowed = true;
2561 SwCrsrShell::~SwCrsrShell()
2563 // if it is not the last view then at least the field should be updated
2564 if( GetNext() != this )
2565 CheckTblBoxCntnt( pCurCrsr->GetPoint() );
2566 else
2567 ClearTblBoxCntnt();
2569 delete pVisCrsr;
2570 delete pBlockCrsr;
2571 delete pTblCrsr;
2573 // release cursors
2574 while(pCurCrsr->GetNext() != pCurCrsr)
2575 delete pCurCrsr->GetNext();
2576 delete pCurCrsr;
2578 // free stack
2579 if( pCrsrStk )
2581 while( pCrsrStk->GetNext() != pCrsrStk )
2582 delete pCrsrStk->GetNext();
2583 delete pCrsrStk;
2586 // #i54025# - do not give a HTML parser that might potentially hang as
2587 // a client at the cursor shell the chance to hang itself on a TextNode
2588 if( GetRegisteredIn() )
2589 GetRegisteredInNonConst()->Remove( this );
2592 SwShellCrsr* SwCrsrShell::getShellCrsr( bool bBlock )
2594 if( pTblCrsr )
2595 return pTblCrsr;
2596 if( pBlockCrsr && bBlock )
2597 return &pBlockCrsr->getShellCrsr();
2598 return pCurCrsr;
2601 /** Should WaitPtr be switched on for the clipboard?
2603 Wait for TableMode, multiple selections and more than x selected paragraphs.
2605 bool SwCrsrShell::ShouldWait() const
2607 if ( IsTableMode() || GetCrsrCnt() > 1 )
2608 return true;
2610 if( HasDrawView() && GetDrawView()->GetMarkedObjectList().GetMarkCount() )
2611 return true;
2613 SwPaM* pPam = GetCrsr();
2614 return pPam->Start()->nNode.GetIndex() + 10 <
2615 pPam->End()->nNode.GetIndex();
2618 size_t SwCrsrShell::UpdateTblSelBoxes()
2620 if (pTblCrsr && (pTblCrsr->IsChgd() || !pTblCrsr->GetSelectedBoxesCount()))
2622 GetLayout()->MakeTblCrsrs( *pTblCrsr );
2624 return (pTblCrsr) ? pTblCrsr->GetSelectedBoxesCount() : 0;
2627 /// show the current selected "object"
2628 void SwCrsrShell::MakeSelVisible()
2630 OSL_ENSURE( bHasFocus, "no focus but cursor should be made visible?" );
2631 if( aCrsrHeight.Y() < aCharRect.Height() && aCharRect.Height() > VisArea().Height() )
2633 SwRect aTmp( aCharRect );
2634 long nDiff = aCharRect.Height() - VisArea().Height();
2635 if( nDiff < aCrsrHeight.X() )
2636 aTmp.Top( nDiff + aCharRect.Top() );
2637 else
2639 aTmp.Top( aCrsrHeight.X() + aCharRect.Top() );
2640 aTmp.Height( aCrsrHeight.Y() );
2642 if( !aTmp.HasArea() )
2644 aTmp.SSize().Height() += 1;
2645 aTmp.SSize().Width() += 1;
2647 MakeVisible( aTmp );
2649 else
2651 if( aCharRect.HasArea() )
2652 MakeVisible( aCharRect );
2653 else
2655 SwRect aTmp( aCharRect );
2656 aTmp.SSize().Height() += 1; aTmp.SSize().Width() += 1;
2657 MakeVisible( aTmp );
2662 /// search a valid content position (not protected/hidden)
2663 sal_Bool SwCrsrShell::FindValidCntntNode( sal_Bool bOnlyText )
2665 if( pTblCrsr )
2667 OSL_ENSURE( !this, "Did not remove table selection!" );
2668 return sal_False;
2671 // #i45129# - everything is allowed in UI-readonly
2672 if( !bAllProtect && GetDoc()->GetDocShell() &&
2673 GetDoc()->GetDocShell()->IsReadOnlyUI() )
2674 return sal_True;
2676 if( pCurCrsr->HasMark() )
2677 ClearMark();
2679 // first check for frames
2680 SwNodeIndex& rNdIdx = pCurCrsr->GetPoint()->nNode;
2681 sal_uLong nNdIdx = rNdIdx.GetIndex(); // keep backup
2682 SwNodes& rNds = pDoc->GetNodes();
2683 SwCntntNode* pCNd = rNdIdx.GetNode().GetCntntNode();
2684 const SwCntntFrm * pFrm;
2686 if( pCNd && 0 != (pFrm = pCNd->getLayoutFrm( GetLayout(),0,pCurCrsr->GetPoint(),sal_False)) &&
2687 !IsReadOnlyAvailable() && pFrm->IsProtected() &&
2688 nNdIdx < rNds.GetEndOfExtras().GetIndex() )
2690 // skip protected frame
2691 SwPaM aPam( *pCurCrsr->GetPoint() );
2692 aPam.SetMark();
2693 aPam.GetMark()->nNode = rNds.GetEndOfContent();
2694 aPam.GetPoint()->nNode = *pCNd->EndOfSectionNode();
2696 sal_Bool bFirst = sal_False;
2697 if( 0 == (pCNd = ::GetNode( aPam, bFirst, fnMoveForward, sal_False )))
2699 aPam.GetMark()->nNode = *rNds.GetEndOfPostIts().StartOfSectionNode();
2700 pCNd = ::GetNode( aPam, bFirst, fnMoveBackward, sal_False );
2703 if( !pCNd ) // should *never* happen
2705 rNdIdx = nNdIdx; // back to old node
2706 return sal_False;
2708 *pCurCrsr->GetPoint() = *aPam.GetPoint();
2710 else if( bOnlyText && pCNd && pCNd->IsNoTxtNode() )
2712 // set to beginning of document
2713 rNdIdx = pDoc->GetNodes().GetEndOfExtras();
2714 pCurCrsr->GetPoint()->nContent.Assign( pDoc->GetNodes().GoNext(
2715 &rNdIdx ), 0 );
2716 nNdIdx = rNdIdx.GetIndex();
2719 sal_Bool bOk = sal_True;
2721 // #i9059# cursor may not stand in protected cells
2722 // (unless cursor in protected areas is OK.)
2723 const SwTableNode* pTableNode = rNdIdx.GetNode().FindTableNode();
2724 if( !IsReadOnlyAvailable() &&
2725 pTableNode != NULL && rNdIdx.GetNode().IsProtect() )
2727 // we're in a table, and we're in a protected area, so we're
2728 // probably in a protected cell.
2730 // move forward into non-protected area.
2731 SwPaM aPam( rNdIdx.GetNode(), 0 );
2732 while( aPam.GetNode()->IsProtect() &&
2733 aPam.Move( fnMoveForward, fnGoCntnt ) )
2734 ; // nothing to do in the loop; the aPam.Move does the moving!
2736 // didn't work? then go backwards!
2737 if( aPam.GetNode()->IsProtect() )
2739 SwPaM aTmpPaM( rNdIdx.GetNode(), 0 );
2740 aPam = aTmpPaM;
2741 while( aPam.GetNode()->IsProtect() &&
2742 aPam.Move( fnMoveBackward, fnGoCntnt ) )
2743 ; // nothing to do in the loop; the aPam.Move does the moving!
2746 // if we're successful, set the new position
2747 if( ! aPam.GetNode()->IsProtect() )
2749 *pCurCrsr->GetPoint() = *aPam.GetPoint();
2753 // in a protected frame
2754 const SwSectionNode* pSectNd = rNdIdx.GetNode().FindSectionNode();
2755 if( pSectNd && ( pSectNd->GetSection().IsHiddenFlag() ||
2756 ( !IsReadOnlyAvailable() &&
2757 pSectNd->GetSection().IsProtectFlag() )) )
2759 typedef SwCntntNode* (SwNodes:: *FNGoSection)( SwNodeIndex *, int, int ) const;
2760 FNGoSection funcGoSection = &SwNodes::GoNextSection;
2762 bOk = sal_False;
2764 for( int nLoopCnt = 0; !bOk && nLoopCnt < 2; ++nLoopCnt )
2766 bool bContinue;
2767 do {
2768 bContinue = false;
2769 while( 0 != ( pCNd = (rNds.*funcGoSection)( &rNdIdx,
2770 sal_True, !IsReadOnlyAvailable() )) )
2772 // moved inside a table -> check if it is protected
2773 if( pCNd->FindTableNode() )
2775 SwCallLink aTmp( *this );
2776 SwCrsrSaveState aSaveState( *pCurCrsr );
2777 aTmp.nNdTyp = 0; // don't do anything in DTOR
2778 if( !pCurCrsr->IsInProtectTable( sal_True, sal_True ) )
2780 const SwSectionNode* pSNd = pCNd->FindSectionNode();
2781 if( !pSNd || !pSNd->GetSection().IsHiddenFlag()
2782 || (!IsReadOnlyAvailable() &&
2783 pSNd->GetSection().IsProtectFlag() ))
2785 bOk = sal_True;
2786 break; // found non-protected cell
2788 continue; // continue search
2791 else
2793 bOk = sal_True;
2794 break; // found non-protected cell
2798 if( bOk && rNdIdx.GetIndex() < rNds.GetEndOfExtras().GetIndex() )
2800 // also check for Fly - might be protected as well
2801 if( 0 == (pFrm = pCNd->getLayoutFrm( GetLayout(),0,0,sal_False)) ||
2802 ( !IsReadOnlyAvailable() && pFrm->IsProtected() ) ||
2803 ( bOnlyText && pCNd->IsNoTxtNode() ) )
2805 // continue search
2806 bOk = sal_False;
2807 bContinue = true;
2810 } while( bContinue );
2812 if( !bOk )
2814 if( !nLoopCnt )
2815 funcGoSection = &SwNodes::GoPrevSection;
2816 rNdIdx = nNdIdx;
2820 if( bOk )
2822 pCNd = rNdIdx.GetNode().GetCntntNode();
2823 xub_StrLen nCntnt = rNdIdx.GetIndex() < nNdIdx ? pCNd->Len() : 0;
2824 pCurCrsr->GetPoint()->nContent.Assign( pCNd, nCntnt );
2826 else
2828 pCNd = rNdIdx.GetNode().GetCntntNode();
2829 // if cursor in hidden frame, always move it
2830 if( !pCNd || !pCNd->getLayoutFrm( GetLayout(),0,0,sal_False) )
2832 SwCrsrMoveState aTmpState( MV_NONE );
2833 aTmpState.bSetInReadOnly = IsReadOnlyAvailable();
2834 GetLayout()->GetCrsrOfst( pCurCrsr->GetPoint(), pCurCrsr->GetPtPos(),
2835 &aTmpState );
2838 return bOk;
2842 sal_Bool SwCrsrShell::IsCrsrReadonly() const
2844 if ( GetViewOptions()->IsReadonly() ||
2845 GetViewOptions()->IsFormView() /* Formular view */ )
2847 SwFrm *pFrm = GetCurrFrm( sal_False );
2848 const SwFlyFrm* pFly;
2849 const SwSection* pSection;
2851 if( pFrm && pFrm->IsInFly() &&
2852 (pFly = pFrm->FindFlyFrm())->GetFmt()->GetEditInReadonly().GetValue() &&
2853 pFly->Lower() &&
2854 !pFly->Lower()->IsNoTxtFrm() &&
2855 !GetDrawView()->GetMarkedObjectList().GetMarkCount() )
2857 return sal_False;
2859 // edit in readonly sections
2860 else if ( pFrm && pFrm->IsInSct() &&
2861 0 != ( pSection = pFrm->FindSctFrm()->GetSection() ) &&
2862 pSection->IsEditInReadonlyFlag() )
2864 return sal_False;
2867 return sal_True;
2869 return sal_False;
2872 /// is the cursor allowed to enter ReadOnly sections?
2873 void SwCrsrShell::SetReadOnlyAvailable( sal_Bool bFlag )
2875 // *never* switch in GlobalDoc
2876 if( (!GetDoc()->GetDocShell() ||
2877 !GetDoc()->GetDocShell()->IsA( SwGlobalDocShell::StaticType() )) &&
2878 bFlag != bSetCrsrInReadOnly )
2880 // If the flag is switched off then all selections need to be
2881 // invalidated. Otherwise we would trust that nothing protected is selected.
2882 if( !bFlag )
2884 ClearMark();
2886 bSetCrsrInReadOnly = bFlag;
2887 UpdateCrsr();
2891 sal_Bool SwCrsrShell::HasReadonlySel(bool bAnnotationMode) const
2893 sal_Bool bRet = sal_False;
2894 if( IsReadOnlyAvailable() || GetViewOptions()->IsFormView() )
2896 if( pTblCrsr )
2897 bRet = pTblCrsr->HasReadOnlyBoxSel() ||
2898 pTblCrsr->HasReadonlySel( GetViewOptions()->IsFormView() );
2899 else
2901 const SwPaM* pCrsr = pCurCrsr;
2903 do {
2904 if( pCrsr->HasReadonlySel( GetViewOptions()->IsFormView(), bAnnotationMode ) )
2905 bRet = sal_True;
2906 } while( !bRet && pCurCrsr != ( pCrsr = (SwPaM*)pCrsr->GetNext() ));
2909 return bRet;
2912 sal_Bool SwCrsrShell::IsSelFullPara() const
2914 sal_Bool bRet = sal_False;
2916 if( pCurCrsr->GetPoint()->nNode.GetIndex() ==
2917 pCurCrsr->GetMark()->nNode.GetIndex() && pCurCrsr == pCurCrsr->GetNext() )
2919 xub_StrLen nStt = pCurCrsr->GetPoint()->nContent.GetIndex(),
2920 nEnd = pCurCrsr->GetMark()->nContent.GetIndex();
2921 if( nStt > nEnd )
2923 xub_StrLen nTmp = nStt;
2924 nStt = nEnd;
2925 nEnd = nTmp;
2927 const SwCntntNode* pCNd = pCurCrsr->GetCntntNode();
2928 bRet = pCNd && !nStt && nEnd == pCNd->Len();
2930 return bRet;
2933 short SwCrsrShell::GetTextDirection( const Point* pPt ) const
2935 SwPosition aPos( *pCurCrsr->GetPoint() );
2936 Point aPt( pPt ? *pPt : pCurCrsr->GetPtPos() );
2937 if( pPt )
2939 SwCrsrMoveState aTmpState( MV_NONE );
2940 aTmpState.bSetInReadOnly = IsReadOnlyAvailable();
2942 GetLayout()->GetCrsrOfst( &aPos, aPt, &aTmpState );
2945 return pDoc->GetTextDirection( aPos, &aPt );
2948 bool SwCrsrShell::IsInVerticalText( const Point* pPt ) const
2950 const short nDir = GetTextDirection( pPt );
2951 return FRMDIR_VERT_TOP_RIGHT == nDir || FRMDIR_VERT_TOP_LEFT == nDir;
2954 sal_Bool SwCrsrShell::IsInRightToLeftText( const Point* pPt ) const
2956 const short nDir = GetTextDirection( pPt );
2957 // GetTextDirection uses FRMDIR_VERT_TOP_LEFT to indicate RTL in
2958 // vertical environment
2959 return FRMDIR_VERT_TOP_LEFT == nDir || FRMDIR_HORI_RIGHT_TOP == nDir;
2962 /// If the current cursor position is inside a hidden range, the hidden range
2963 /// is selected.
2964 bool SwCrsrShell::SelectHiddenRange()
2966 bool bRet = false;
2967 if ( !GetViewOptions()->IsShowHiddenChar() && !pCurCrsr->HasMark() )
2969 SwPosition& rPt = *(SwPosition*)pCurCrsr->GetPoint();
2970 const SwTxtNode* pNode = rPt.nNode.GetNode().GetTxtNode();
2971 if ( pNode )
2973 const xub_StrLen nPos = rPt.nContent.GetIndex();
2975 // check if nPos is in hidden range
2976 xub_StrLen nHiddenStart;
2977 xub_StrLen nHiddenEnd;
2978 SwScriptInfo::GetBoundsOfHiddenRange( *pNode, nPos, nHiddenStart, nHiddenEnd );
2979 if ( STRING_LEN != nHiddenStart )
2981 // make selection:
2982 pCurCrsr->SetMark();
2983 pCurCrsr->GetMark()->nContent = nHiddenEnd;
2984 bRet = true;
2989 return bRet;
2992 sal_uLong SwCrsrShell::Find( const SearchOptions& rSearchOpt,
2993 sal_Bool bSearchInNotes,
2994 SwDocPositions eStart, SwDocPositions eEnd,
2995 sal_Bool& bCancel,
2996 FindRanges eRng,
2997 int bReplace )
2999 if( pTblCrsr )
3000 GetCrsr();
3001 delete pTblCrsr, pTblCrsr = 0;
3002 SwCallLink aLk( *this ); // watch Crsr-Moves; call Link if needed
3003 sal_uLong nRet = pCurCrsr->Find( rSearchOpt, bSearchInNotes, eStart, eEnd,
3004 bCancel, eRng, bReplace );
3005 if( nRet || bCancel )
3006 UpdateCrsr();
3007 return nRet;
3010 sal_uLong SwCrsrShell::Find( const SwTxtFmtColl& rFmtColl,
3011 SwDocPositions eStart, SwDocPositions eEnd,
3012 sal_Bool& bCancel,
3013 FindRanges eRng,
3014 const SwTxtFmtColl* pReplFmt )
3016 if( pTblCrsr )
3017 GetCrsr();
3018 delete pTblCrsr, pTblCrsr = 0;
3019 SwCallLink aLk( *this ); // watch Crsr-Moves; call Link if needed
3020 sal_uLong nRet = pCurCrsr->Find( rFmtColl, eStart, eEnd, bCancel, eRng,
3021 pReplFmt );
3022 if( nRet )
3023 UpdateCrsr();
3024 return nRet;
3027 sal_uLong SwCrsrShell::Find( const SfxItemSet& rSet,
3028 sal_Bool bNoCollections,
3029 SwDocPositions eStart, SwDocPositions eEnd,
3030 sal_Bool& bCancel,
3031 FindRanges eRng,
3032 const SearchOptions* pSearchOpt,
3033 const SfxItemSet* rReplSet )
3035 if( pTblCrsr )
3036 GetCrsr();
3037 delete pTblCrsr, pTblCrsr = 0;
3038 SwCallLink aLk( *this ); // watch Crsr-Moves; call Link if needed
3039 sal_uLong nRet = pCurCrsr->Find( rSet, bNoCollections, eStart, eEnd,
3040 bCancel, eRng, pSearchOpt, rReplSet );
3041 if( nRet )
3042 UpdateCrsr();
3043 return nRet;
3046 void SwCrsrShell::SetSelection( const SwPaM& rCrsr )
3048 StartAction();
3049 SwPaM* pCrsr = GetCrsr();
3050 *pCrsr->GetPoint() = *rCrsr.GetPoint();
3051 if(rCrsr.HasMark())
3053 pCrsr->SetMark();
3054 *pCrsr->GetMark() = *rCrsr.GetMark();
3056 if((SwPaM*)rCrsr.GetNext() != &rCrsr)
3058 const SwPaM *_pStartCrsr = (SwPaM*)rCrsr.GetNext();
3061 SwPaM* pCurrentCrsr = CreateCrsr();
3062 *pCurrentCrsr->GetPoint() = *_pStartCrsr->GetPoint();
3063 if(_pStartCrsr->HasMark())
3065 pCurrentCrsr->SetMark();
3066 *pCurrentCrsr->GetMark() = *_pStartCrsr->GetMark();
3068 } while( (_pStartCrsr=(SwPaM *)_pStartCrsr->GetNext()) != &rCrsr );
3070 EndAction();
3073 static void lcl_RemoveMark( SwPaM* pPam )
3075 OSL_ENSURE( pPam->HasMark(), "Don't remove pPoint!" );
3076 pPam->GetMark()->nContent.Assign( 0, 0 );
3077 pPam->GetMark()->nNode = 0;
3078 pPam->DeleteMark();
3081 static const SwStartNode* lcl_NodeContext( const SwNode& rNode )
3083 const SwStartNode *pRet = rNode.StartOfSectionNode();
3084 while( pRet->IsSectionNode() || pRet->IsTableNode() ||
3085 pRet->GetStartNodeType() == SwTableBoxStartNode )
3087 pRet = pRet->StartOfSectionNode();
3089 return pRet;
3093 Checks if a position is valid. To be valid the position's node must
3094 be a content node and the content must not be unregistered.
3096 @param aPos the position to check.
3098 bool sw_PosOk(const SwPosition & aPos)
3100 return NULL != aPos.nNode.GetNode().GetCntntNode() &&
3101 aPos.nContent.GetIdxReg();
3105 Checks if a PaM is valid. For a PaM to be valid its point must be
3106 valid. Additionaly if the PaM has a mark this has to be valid, too.
3108 @param aPam the PaM to check
3110 static bool lcl_CrsrOk(SwPaM & aPam)
3112 return sw_PosOk(*aPam.GetPoint()) && (! aPam.HasMark()
3113 || sw_PosOk(*aPam.GetMark()));
3116 void SwCrsrShell::ClearUpCrsrs()
3118 // start of the ring
3119 SwPaM * pStartCrsr = GetCrsr();
3120 // start loop with second entry of the ring
3121 SwPaM * pCrsr = (SwPaM *) pStartCrsr->GetNext();
3122 SwPaM * pTmpCrsr;
3123 bool bChanged = false;
3125 // For all entries in the ring except the start entry delete the entry if
3126 // it is invalid.
3127 while (pCrsr != pStartCrsr)
3129 pTmpCrsr = (SwPaM *) pCrsr->GetNext();
3131 if ( ! lcl_CrsrOk(*pCrsr))
3133 delete pCrsr;
3135 bChanged = true;
3138 pCrsr = pTmpCrsr;
3141 if( pStartCrsr->HasMark() && !sw_PosOk( *pStartCrsr->GetMark() ) )
3143 lcl_RemoveMark( pStartCrsr );
3144 bChanged = true;
3146 if( !sw_PosOk( *pStartCrsr->GetPoint() ) )
3148 SwNodes & aNodes = GetDoc()->GetNodes();
3149 const SwNode* pStart = lcl_NodeContext( pStartCrsr->GetPoint()->nNode.GetNode() );
3150 SwNodeIndex aIdx( pStartCrsr->GetPoint()->nNode );
3151 SwNode * pNode = aNodes.GoPrevious(&aIdx);
3152 if( pNode == NULL || lcl_NodeContext( *pNode ) != pStart )
3153 aNodes.GoNext( &aIdx );
3154 if( pNode == NULL || lcl_NodeContext( *pNode ) != pStart )
3156 // If the start entry of the ring is invalid replace it with a
3157 // cursor pointing to the beginning of the first content node in the
3158 // document.
3159 aIdx = (*(aNodes.GetEndOfContent().StartOfSectionNode()));
3160 pNode = aNodes.GoNext( &aIdx );
3162 bool bFound = (pNode != NULL);
3164 OSL_ENSURE(bFound, "no content node found");
3166 if (bFound)
3168 SwPaM aTmpPam(*pNode);
3169 *pStartCrsr = aTmpPam;
3172 bChanged = true;
3175 // If at least one of the cursors in the ring have been deleted or replaced,
3176 // remove the table cursor.
3177 if (pTblCrsr != NULL && bChanged)
3178 TblCrsrToCursor();
3181 String SwCrsrShell::GetCrsrDescr() const
3183 String aResult;
3185 if (IsMultiSelection())
3186 aResult += String(SW_RES(STR_MULTISEL));
3187 else
3188 aResult = GetDoc()->GetPaMDescr(*GetCrsr());
3190 return aResult;
3193 // SMARTTAGS
3195 static void lcl_FillRecognizerData( uno::Sequence< rtl::OUString >& rSmartTagTypes,
3196 uno::Sequence< uno::Reference< container::XStringKeyMap > >& rStringKeyMaps,
3197 const SwWrongList& rSmartTagList, xub_StrLen nCurrent )
3199 // Insert smart tag information
3200 std::vector< rtl::OUString > aSmartTagTypes;
3201 std::vector< uno::Reference< container::XStringKeyMap > > aStringKeyMaps;
3203 for ( sal_uInt16 i = 0; i < rSmartTagList.Count(); ++i )
3205 const xub_StrLen nSTPos = rSmartTagList.Pos( i );
3206 const xub_StrLen nSTLen = rSmartTagList.Len( i );
3208 if ( nSTPos <= nCurrent && nCurrent < nSTPos + nSTLen )
3210 const SwWrongArea* pArea = rSmartTagList.GetElement( i );
3211 if ( pArea )
3213 aSmartTagTypes.push_back( pArea->maType );
3214 aStringKeyMaps.push_back( pArea->mxPropertyBag );
3219 if ( !aSmartTagTypes.empty() )
3221 rSmartTagTypes.realloc( aSmartTagTypes.size() );
3222 rStringKeyMaps.realloc( aSmartTagTypes.size() );
3224 std::vector< rtl::OUString >::const_iterator aTypesIter = aSmartTagTypes.begin();
3225 sal_uInt16 i = 0;
3226 for ( aTypesIter = aSmartTagTypes.begin(); aTypesIter != aSmartTagTypes.end(); ++aTypesIter )
3227 rSmartTagTypes[i++] = *aTypesIter;
3229 std::vector< uno::Reference< container::XStringKeyMap > >::const_iterator aMapsIter = aStringKeyMaps.begin();
3230 i = 0;
3231 for ( aMapsIter = aStringKeyMaps.begin(); aMapsIter != aStringKeyMaps.end(); ++aMapsIter )
3232 rStringKeyMaps[i++] = *aMapsIter;
3236 static void lcl_FillTextRange( uno::Reference<text::XTextRange>& rRange,
3237 SwTxtNode& rNode, xub_StrLen nBegin, xub_StrLen nLen )
3239 // create SwPosition for nStartIndex
3240 SwIndex aIndex( &rNode, nBegin );
3241 SwPosition aStartPos( rNode, aIndex );
3243 // create SwPosition for nEndIndex
3244 SwPosition aEndPos( aStartPos );
3245 aEndPos.nContent = nBegin + nLen;
3247 const uno::Reference<text::XTextRange> xRange =
3248 SwXTextRange::CreateXTextRange(*rNode.GetDoc(), aStartPos, &aEndPos);
3250 rRange = xRange;
3253 void SwCrsrShell::GetSmartTagTerm( uno::Sequence< rtl::OUString >& rSmartTagTypes,
3254 uno::Sequence< uno::Reference< container::XStringKeyMap > >& rStringKeyMaps,
3255 uno::Reference< text::XTextRange>& rRange ) const
3257 if ( !SwSmartTagMgr::Get().IsSmartTagsEnabled() )
3258 return;
3260 SwPaM* pCrsr = GetCrsr();
3261 SwPosition aPos( *pCrsr->GetPoint() );
3262 SwTxtNode *pNode = aPos.nNode.GetNode().GetTxtNode();
3263 if ( pNode && !pNode->IsInProtectSect() )
3265 const SwWrongList *pSmartTagList = pNode->GetSmartTags();
3266 if ( pSmartTagList )
3268 xub_StrLen nCurrent = aPos.nContent.GetIndex();
3269 xub_StrLen nBegin = nCurrent;
3270 xub_StrLen nLen = 1;
3272 if( pSmartTagList->InWrongWord( nBegin, nLen ) && !pNode->IsSymbol(nBegin) )
3274 const sal_uInt16 nIndex = pSmartTagList->GetWrongPos( nBegin );
3275 const SwWrongList* pSubList = pSmartTagList->SubList( nIndex );
3276 if ( pSubList )
3278 pSmartTagList = pSubList;
3279 nCurrent = 0;
3282 lcl_FillRecognizerData( rSmartTagTypes, rStringKeyMaps, *pSmartTagList, nCurrent );
3283 lcl_FillTextRange( rRange, *pNode, nBegin, nLen );
3289 // see also SwEditShell::GetCorrection( const Point* pPt, SwRect& rSelectRect )
3290 void SwCrsrShell::GetSmartTagTerm( const Point& rPt, SwRect& rSelectRect,
3291 uno::Sequence< rtl::OUString >& rSmartTagTypes,
3292 uno::Sequence< uno::Reference< container::XStringKeyMap > >& rStringKeyMaps,
3293 uno::Reference<text::XTextRange>& rRange )
3295 if ( !SwSmartTagMgr::Get().IsSmartTagsEnabled() )
3296 return;
3298 SwPaM* pCrsr = GetCrsr();
3299 SwPosition aPos( *pCrsr->GetPoint() );
3300 Point aPt( rPt );
3301 SwCrsrMoveState eTmpState( MV_SETONLYTEXT );
3302 SwSpecialPos aSpecialPos;
3303 eTmpState.pSpecialPos = &aSpecialPos;
3304 SwTxtNode *pNode;
3305 const SwWrongList *pSmartTagList;
3307 if( GetLayout()->GetCrsrOfst( &aPos, aPt, &eTmpState ) &&
3308 0 != (pNode = aPos.nNode.GetNode().GetTxtNode()) &&
3309 0 != (pSmartTagList = pNode->GetSmartTags()) &&
3310 !pNode->IsInProtectSect() )
3312 xub_StrLen nCurrent = aPos.nContent.GetIndex();
3313 xub_StrLen nBegin = nCurrent;
3314 xub_StrLen nLen = 1;
3316 if( pSmartTagList->InWrongWord( nBegin, nLen ) && !pNode->IsSymbol(nBegin) )
3318 const sal_uInt16 nIndex = pSmartTagList->GetWrongPos( nBegin );
3319 const SwWrongList* pSubList = pSmartTagList->SubList( nIndex );
3320 if ( pSubList )
3322 pSmartTagList = pSubList;
3323 nCurrent = eTmpState.pSpecialPos->nCharOfst;
3326 lcl_FillRecognizerData( rSmartTagTypes, rStringKeyMaps, *pSmartTagList, nCurrent );
3327 lcl_FillTextRange( rRange, *pNode, nBegin, nLen );
3329 // get smarttag word
3330 String aText( pNode->GetTxt().Copy( nBegin, nLen ) );
3332 //save the start and end positons of the line and the starting point
3333 Push();
3334 LeftMargin();
3335 xub_StrLen nLineStart = GetCrsr()->GetPoint()->nContent.GetIndex();
3336 RightMargin();
3337 xub_StrLen nLineEnd = GetCrsr()->GetPoint()->nContent.GetIndex();
3338 Pop(sal_False);
3340 // make sure the selection build later from the data below does not
3341 // include "in word" character to the left and right in order to
3342 // preserve those. Therefore count those "in words" in order to
3343 // modify the selection accordingly.
3344 const sal_Unicode* pChar = aText.GetBuffer();
3345 xub_StrLen nLeft = 0;
3346 while (pChar && *pChar++ == CH_TXTATR_INWORD)
3347 ++nLeft;
3348 pChar = aText.Len() ? aText.GetBuffer() + aText.Len() - 1 : 0;
3349 xub_StrLen nRight = 0;
3350 while (pChar && *pChar-- == CH_TXTATR_INWORD)
3351 ++nRight;
3353 aPos.nContent = nBegin + nLeft;
3354 pCrsr = GetCrsr();
3355 *pCrsr->GetPoint() = aPos;
3356 pCrsr->SetMark();
3357 ExtendSelection( sal_True, nLen - nLeft - nRight );
3358 // do not determine the rectangle in the current line
3359 xub_StrLen nWordStart = (nBegin + nLeft) < nLineStart ? nLineStart : nBegin + nLeft;
3360 // take one less than the line end - otherwise the next line would
3361 // be calculated
3362 xub_StrLen nWordEnd = (nBegin + nLen - nLeft - nRight) > nLineEnd ? nLineEnd : (nBegin + nLen - nLeft - nRight);
3363 Push();
3364 pCrsr->DeleteMark();
3365 SwIndex& rContent = GetCrsr()->GetPoint()->nContent;
3366 rContent = nWordStart;
3367 SwRect aStartRect;
3368 SwCrsrMoveState aState;
3369 aState.bRealWidth = sal_True;
3370 SwCntntNode* pCntntNode = pCrsr->GetCntntNode();
3371 SwCntntFrm *pCntntFrame = pCntntNode->getLayoutFrm( GetLayout(), &rPt, pCrsr->GetPoint(), sal_False);
3373 pCntntFrame->GetCharRect( aStartRect, *pCrsr->GetPoint(), &aState );
3374 rContent = nWordEnd - 1;
3375 SwRect aEndRect;
3376 pCntntFrame->GetCharRect( aEndRect, *pCrsr->GetPoint(),&aState );
3377 rSelectRect = aStartRect.Union( aEndRect );
3378 Pop(sal_False);
3384 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */