blob: a60a887ece01dd5d970813a9ab4ffa8476e550ea [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"
#include <com/sun/star/util/SearchOptions.hpp>
#include <com/sun/star/text/XTextRange.hpp>
#include <hintids.hxx>
#include <svx/svdmodel.hxx>
#include <editeng/frmdiritem.hxx>
#include <SwSmartTagMgr.hxx>
#include <doc.hxx>
#include <rootfrm.hxx>
#include <pagefrm.hxx>
#include <cntfrm.hxx>
#include <viewimp.hxx>
#include <pam.hxx>
#include <swselectionlist.hxx>
#include <IBlockCursor.hxx>
#include "BlockCursor.hxx"
#include <ndtxt.hxx>
#include <flyfrm.hxx>
#include <dview.hxx>
#include <viewopt.hxx>
#include <frmtool.hxx>
#include <crsrsh.hxx>
#include <tabfrm.hxx>
#include <txtfrm.hxx>
#include <sectfrm.hxx>
#include <swtable.hxx>
#include <callnk.hxx>
#include <viscrs.hxx>
#include <section.hxx>
#include <docsh.hxx>
#include <scriptinfo.hxx>
#include <globdoc.hxx>
#include <pamtyp.hxx>
#include <mdiexp.hxx> // ...Percent()
#include <fmteiro.hxx>
#include <wrong.hxx> // SMARTTAGS
#include <unotextrange.hxx> // SMARTTAGS
#include <vcl/svapp.hxx>
#include <numrule.hxx>
#include <IGrammarContact.hxx>
#include <globals.hrc>
#include <comcore.hrc>
using namespace com::sun::star;
using namespace util;
TYPEINIT2(SwCrsrShell,ViewShell,SwModify);
// Funktion loescht, alle ueberlappenden Cursor aus einem Cursor-Ring
void CheckRange( SwCursor* );
//-----------------------------------------------------------------------
/*
* Ueberpruefe ob der pCurCrsr in einen schon bestehenden Bereich zeigt.
* Wenn ja, dann hebe den alten Bereich auf.
*/
void CheckRange( SwCursor* pCurCrsr )
{
const SwPosition *pStt = pCurCrsr->Start(),
*pEnd = pCurCrsr->GetPoint() == pStt ? pCurCrsr->GetMark() : pCurCrsr->GetPoint();
SwPaM *pTmpDel = 0,
*pTmp = (SwPaM*)pCurCrsr->GetNext();
// durchsuche den gesamten Ring
while( pTmp != pCurCrsr )
{
const SwPosition *pTmpStt = pTmp->Start(),
*pTmpEnd = pTmp->GetPoint() == pTmpStt ?
pTmp->GetMark() : pTmp->GetPoint();
if( *pStt <= *pTmpStt )
{
if( *pEnd > *pTmpStt ||
( *pEnd == *pTmpStt && *pEnd == *pTmpEnd ))
pTmpDel = pTmp;
}
else
if( *pStt < *pTmpEnd )
pTmpDel = pTmp;
/*
* liegt ein SPoint oder GetMark innerhalb vom Crsr-Bereich
* muss der alte Bereich aufgehoben werden.
* Beim Vergleich ist darauf zu achten, das SPoint nicht mehr zum
* Bereich gehoert !
*/
pTmp = (SwPaM*)pTmp->GetNext();
if( pTmpDel )
{
delete pTmpDel; // hebe alten Bereich auf
pTmpDel = 0;
}
}
}
// -------------- Methoden von der SwCrsrShell -------------
SwPaM * SwCrsrShell::CreateCrsr()
{
// Innerhalb der Tabellen-SSelection keinen neuen Crsr anlegen
ASSERT( !IsTableMode(), "in Tabellen SSelection" );
// neuen Cursor als Kopie vom akt. und in den Ring aufnehmen
// Verkettung zeigt immer auf den zuerst erzeugten, also vorwaerts
SwShellCrsr* pNew = new SwShellCrsr( *pCurCrsr );
// hier den akt. Pam nur logisch Hiden, weil sonst die Invertierung
// vom kopierten Pam aufgehoben wird !!
// #i75172# to be able to make a complete content swap, i moved this to a method
// pNew->Insert( pCurCrsr, 0 );
// pCurCrsr->Remove( 0, pCurCrsr->Count() );
pNew->swapContent(*pCurCrsr);
pCurCrsr->DeleteMark();
UpdateCrsr( SwCrsrShell::SCROLLWIN );
// return pCurCrsr;
return pNew;
}
// loesche den aktuellen Cursor und der folgende wird zum Aktuellen
sal_Bool SwCrsrShell::DestroyCrsr()
{
// Innerhalb der Tabellen-SSelection keinen neuen Crsr loeschen
ASSERT( !IsTableMode(), "in Tabellen SSelection" );
// ist ueberhaupt ein naechtser vorhanden ?
if(pCurCrsr->GetNext() == pCurCrsr)
return sal_False;
SwCallLink aLk( *this ); // Crsr-Moves ueberwachen,
SwCursor* pNextCrsr = (SwCursor*)pCurCrsr->GetNext();
delete pCurCrsr;
pCurCrsr = dynamic_cast<SwShellCrsr*>(pNextCrsr);
UpdateCrsr();
return sal_True;
}
SwPaM & SwCrsrShell::CreateNewShellCursor()
{
if (HasSelection())
{
(void) CreateCrsr(); // n.b. returns old cursor
}
return *GetCrsr();
}
SwPaM & SwCrsrShell::GetCurrentShellCursor()
{
return *GetCrsr();
}
// gebe den aktuellen zurueck
SwPaM* SwCrsrShell::GetCrsr( sal_Bool bMakeTblCrsr ) const
{
if( pTblCrsr )
{
if( bMakeTblCrsr && pTblCrsr->IsCrsrMovedUpdt() )
{
// geparkte Cursor werden nicht wieder erzeugt
const SwCntntNode* pCNd;
if( pTblCrsr->GetPoint()->nNode.GetIndex() &&
pTblCrsr->GetMark()->nNode.GetIndex() &&
0 != ( pCNd = pTblCrsr->GetCntntNode() ) && pCNd->getLayoutFrm( GetLayout() ) &&
0 != ( pCNd = pTblCrsr->GetCntntNode(sal_False) ) && pCNd->getLayoutFrm( GetLayout() ) )
{
SwShellTableCrsr* pTC = (SwShellTableCrsr*)pTblCrsr;
GetLayout()->MakeTblCrsrs( *pTC );
}
}
if( pTblCrsr->IsChgd() )
{
const_cast<SwCrsrShell*>(this)->pCurCrsr =
dynamic_cast<SwShellCrsr*>(pTblCrsr->MakeBoxSels( pCurCrsr ));
}
}
return pCurCrsr;
}
void SwCrsrShell::StartAction()
{
if( !ActionPend() )
{
// fuer das Update des Ribbon-Bars merken
const SwNode& rNd = pCurCrsr->GetPoint()->nNode.GetNode();
nAktNode = rNd.GetIndex();
nAktCntnt = pCurCrsr->GetPoint()->nContent.GetIndex();
nAktNdTyp = rNd.GetNodeType();
bAktSelection = *pCurCrsr->GetPoint() != *pCurCrsr->GetMark();
if( ND_TEXTNODE & nAktNdTyp )
nLeftFrmPos = SwCallLink::getLayoutFrm( GetLayout(), (SwTxtNode&)rNd, nAktCntnt, sal_True );
else
nLeftFrmPos = 0;
}
ViewShell::StartAction(); // zur ViewShell
}
void SwCrsrShell::EndAction( const sal_Bool bIdleEnd )
{
/*
//OS: Wird z.B. eine Basic-Action im Hintergrund ausgefuehrt, geht es so nicht
if( !bHasFocus )
{
// hat die Shell nicht den Focus, dann nur das EndAction an
// die ViewShell weitergeben.
ViewShell::EndAction( bIdleEnd );
return;
}
*/
sal_Bool bVis = bSVCrsrVis;
// Idle-Formatierung ?
if( bIdleEnd && Imp()->GetRegion() )
{
pCurCrsr->Hide();
#ifdef SHOW_IDLE_REGION
if( GetWin() )
{
GetWin()->Push();
GetWin()->ChangePen( Pen( Color( COL_YELLOW )));
for( sal_uInt16 n = 0; n < aPntReg.Count(); ++n )
{
SwRect aIRect( aPntReg[n] );
GetWin()->DrawRect( aIRect.SVRect() );
}
GetWin()->Pop();
}
#endif
}
// vor der letzten Action alle invaliden Numerierungen updaten
if( 1 == nStartAction )
GetDoc()->UpdateNumRule();
// Task: 76923: dont show the cursor in the ViewShell::EndAction() - call.
// Only the UpdateCrsr shows the cursor.
sal_Bool bSavSVCrsrVis = bSVCrsrVis;
bSVCrsrVis = sal_False;
ViewShell::EndAction( bIdleEnd ); //der ViewShell den Vortritt lassen
bSVCrsrVis = bSavSVCrsrVis;
if( ActionPend() )
{
if( bVis ) // auch SV-Cursor wieder anzeigen
pVisCrsr->Show();
// falls noch ein ChgCall vorhanden ist und nur noch die Basic
// Klammerung vorhanden ist, dann rufe ihn. Dadurch wird die interne
// mit der Basic-Klammerung entkoppelt; die Shells werden umgeschaltet
if( !BasicActionPend() )
{
//JP 12.01.98: Bug #46496# - es muss innerhalb einer BasicAction
// der Cursor geupdatet werden; um z.B. den
// TabellenCursor zu erzeugen. Im UpdateCrsr wird
// das jetzt beruecksichtigt!
UpdateCrsr( SwCrsrShell::CHKRANGE, bIdleEnd );
{
// Crsr-Moves ueberwachen, evt. Link callen
// der DTOR ist das interressante!!
SwCallLink aLk( *this, nAktNode, nAktCntnt, (sal_uInt8)nAktNdTyp,
nLeftFrmPos, bAktSelection );
}
if( bCallChgLnk && bChgCallFlag && aChgLnk.IsSet() )
{
aChgLnk.Call( this );
bChgCallFlag = sal_False; // Flag zuruecksetzen
}
}
return;
}
sal_uInt16 nParm = SwCrsrShell::CHKRANGE;
if ( !bIdleEnd )
nParm |= SwCrsrShell::SCROLLWIN;
// if( !IsViewLocked() )
UpdateCrsr( nParm, bIdleEnd ); // Cursor-Aenderungen anzeigen
{
SwCallLink aLk( *this ); // Crsr-Moves ueberwachen,
aLk.nNode = nAktNode; // evt. Link callen
aLk.nNdTyp = (sal_uInt8)nAktNdTyp;
aLk.nCntnt = nAktCntnt;
aLk.nLeftFrmPos = nLeftFrmPos;
if( !nCrsrMove ||
( 1 == nCrsrMove && bInCMvVisportChgd ) )
ShowCrsrs( bSVCrsrVis ? sal_True : sal_False ); // Cursor & Selektionen wieder anzeigen
}
// falls noch ein ChgCall vorhanden ist, dann rufe ihn
if( bCallChgLnk && bChgCallFlag && aChgLnk.IsSet() )
{
aChgLnk.Call( this );
bChgCallFlag = sal_False; // Flag zuruecksetzen
}
}
#if defined(DBG_UTIL)
void SwCrsrShell::SttCrsrMove()
{
ASSERT( nCrsrMove < USHRT_MAX, "To many nested CrsrMoves." );
++nCrsrMove;
StartAction();
}
void SwCrsrShell::EndCrsrMove( const sal_Bool bIdleEnd )
{
ASSERT( nCrsrMove, "EndCrsrMove() ohne SttCrsrMove()." );
EndAction( bIdleEnd );
if( !--nCrsrMove )
bInCMvVisportChgd = sal_False;
}
#endif
sal_Bool SwCrsrShell::LeftRight( sal_Bool bLeft, sal_uInt16 nCnt, sal_uInt16 nMode,
sal_Bool bVisualAllowed )
{
if( IsTableMode() )
return bLeft ? GoPrevCell() : GoNextCell();
SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen
sal_Bool bRet = sal_False;
// #i27615# Handle cursor in front of label.
const SwTxtNode* pTxtNd = 0;
if( pBlockCrsr )
pBlockCrsr->clearPoints();
//
// 1. CASE: Cursor is in front of label. A move to the right
// will simply reset the bInFrontOfLabel flag:
//
SwShellCrsr* pShellCrsr = getShellCrsr( true );
if ( !bLeft && pShellCrsr->IsInFrontOfLabel() )
{
SetInFrontOfLabel( sal_False );
bRet = sal_True;
}
//
// 2. CASE: Cursor is at beginning of numbered paragraph. A move
// to the left will simply set the bInFrontOfLabel flag:
//
else if ( bLeft && 0 == pShellCrsr->GetPoint()->nContent.GetIndex() &&
!pShellCrsr->IsInFrontOfLabel() && !pShellCrsr->HasMark() &&
0 != ( pTxtNd = pShellCrsr->GetNode()->GetTxtNode() ) &&
pTxtNd->HasVisibleNumberingOrBullet() )
{
SetInFrontOfLabel( sal_True );
bRet = sal_True;
}
//
// 3. CASE: Regular cursor move. Reset the bInFrontOfLabel flag:
//
else
{
const sal_Bool bSkipHidden = !GetViewOptions()->IsShowHiddenChar();
// --> OD 2009-12-30 #i107447#
// To avoid loop the reset of <bInFrontOfLabel> flag is no longer
// reflected in the return value <bRet>.
const bool bResetOfInFrontOfLabel = SetInFrontOfLabel( sal_False );
bRet = pShellCrsr->LeftRight( bLeft, nCnt, nMode, bVisualAllowed,
bSkipHidden, !IsOverwriteCrsr() );
if ( !bRet && bLeft && bResetOfInFrontOfLabel )
{
// undo reset of <bInFrontOfLabel> flag
SetInFrontOfLabel( sal_True );
}
// <--
}
if( bRet )
{
UpdateCrsr();
}
return bRet;
}
void SwCrsrShell::FirePageChangeEvent(sal_uInt16 nOldPage, sal_uInt16 nNewPage)
{
#ifdef ACCESSIBLE_LAYOUT
if( Imp()->IsAccessible() )
Imp()->FirePageChangeEvent( nOldPage, nNewPage );
#endif
}
void SwCrsrShell::FireColumnChangeEvent(sal_uInt16 nOldColumn, sal_uInt16 nNewColumn)
{
#ifdef ACCESSIBLE_LAYOUT
if( Imp()->IsAccessible() )
Imp()->FireColumnChangeEvent( nOldColumn, nNewColumn);
#endif
}
void SwCrsrShell::FireSectionChangeEvent(sal_uInt16 nOldSection, sal_uInt16 nNewSection)
{
#ifdef ACCESSIBLE_LAYOUT
if( Imp()->IsAccessible() )
Imp()->FireSectionChangeEvent( nOldSection, nNewSection );
#endif
}
bool SwCrsrShell::bColumnChange()
{
SwFrm* pCurrFrm = GetCurrFrm(sal_False);
if (pCurrFrm == NULL)
{
return sal_False;
}
SwFrm* pCurrCol=((SwFrm*)pCurrFrm)->FindColFrm();
while(pCurrCol== NULL && pCurrFrm!=NULL )
{
SwLayoutFrm* pParent = pCurrFrm->GetUpper();
if(pParent!=NULL)
{
pCurrCol=((SwFrm*)pParent)->FindColFrm();
pCurrFrm = (SwFrm*)pParent;
}
else
{
break;
}
}
if(oldColFrm == pCurrCol)
return sal_False;
else
{
oldColFrm = pCurrCol;
return sal_True;
}
}
// --> OD 2008-04-02 #refactorlists#
void SwCrsrShell::MarkListLevel( const String& sListId,
const int nListLevel )
{
if ( sListId != sMarkedListId ||
nListLevel != nMarkedListLevel)
{
if ( sMarkedListId.Len() > 0 )
pDoc->MarkListLevel( sMarkedListId, nMarkedListLevel, sal_False );
if ( sListId.Len() > 0 )
{
pDoc->MarkListLevel( sListId, nListLevel, sal_True );
}
sMarkedListId = sListId;
nMarkedListLevel = nListLevel;
}
}
void SwCrsrShell::UpdateMarkedListLevel()
{
SwTxtNode * pTxtNd = _GetCrsr()->GetNode()->GetTxtNode();
if ( pTxtNd )
{
if ( !pTxtNd->IsNumbered() )
{
pCurCrsr->_SetInFrontOfLabel( sal_False );
MarkListLevel( String(), 0 );
}
else if ( pCurCrsr->IsInFrontOfLabel() )
{
if ( pTxtNd->IsInList() )
{
ASSERT( pTxtNd->GetActualListLevel() >= 0 &&
pTxtNd->GetActualListLevel() < MAXLEVEL, "Which level?")
MarkListLevel( pTxtNd->GetListId(),
pTxtNd->GetActualListLevel() );
}
}
else
{
MarkListLevel( String(), 0 );
}
}
}
// <--
sal_Bool SwCrsrShell::UpDown( sal_Bool bUp, sal_uInt16 nCnt )
{
SET_CURR_SHELL( this );
SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen
sal_Bool bTableMode = IsTableMode();
SwShellCrsr* pTmpCrsr = getShellCrsr( true );
sal_Bool bRet = pTmpCrsr->UpDown( bUp, nCnt );
// --> FME 2005-01-10 #i40019# UpDown should always reset the
// bInFrontOfLabel flag:
bRet = SetInFrontOfLabel(sal_False) || bRet;
// <--
if( pBlockCrsr )
pBlockCrsr->clearPoints();
if( bRet )
{
eMvState = MV_UPDOWN; // Status fuers Crsr-Travelling - GetCrsrOfst
if( !ActionPend() )
{
CrsrFlag eUpdtMode = SwCrsrShell::SCROLLWIN;
if( !bTableMode )
eUpdtMode = (CrsrFlag) (eUpdtMode
| SwCrsrShell::UPDOWN | SwCrsrShell::CHKRANGE);
UpdateCrsr( static_cast<sal_uInt16>(eUpdtMode) );
}
}
return bRet;
}
sal_Bool SwCrsrShell::LRMargin( sal_Bool bLeft, sal_Bool bAPI)
{
SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen
SET_CURR_SHELL( this );
eMvState = MV_LEFTMARGIN; // Status fuers Crsr-Travelling - GetCrsrOfst
const sal_Bool bTableMode = IsTableMode();
SwShellCrsr* pTmpCrsr = getShellCrsr( true );
if( pBlockCrsr )
pBlockCrsr->clearPoints();
const sal_Bool bWasAtLM =
( 0 == _GetCrsr()->GetPoint()->nContent.GetIndex() );
sal_Bool bRet = pTmpCrsr->LeftRightMargin( bLeft, bAPI );
if ( bLeft && !bTableMode && bRet && bWasAtLM && !_GetCrsr()->HasMark() )
{
const SwTxtNode * pTxtNd = _GetCrsr()->GetNode()->GetTxtNode();
if ( pTxtNd && pTxtNd->HasVisibleNumberingOrBullet() )
SetInFrontOfLabel( sal_True );
}
else if ( !bLeft )
{
bRet = SetInFrontOfLabel( sal_False ) || bRet;
}
if( bRet )
{
UpdateCrsr();
}
return bRet;
}
sal_Bool SwCrsrShell::IsAtLRMargin( sal_Bool bLeft, sal_Bool bAPI ) const
{
const SwShellCrsr* pTmpCrsr = getShellCrsr( true );
return pTmpCrsr->IsAtLeftRightMargin( bLeft, bAPI );
}
sal_Bool SwCrsrShell::SttEndDoc( sal_Bool bStt )
{
SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen
SwShellCrsr* pTmpCrsr = pBlockCrsr ? &pBlockCrsr->getShellCrsr() : pCurCrsr;
sal_Bool bRet = pTmpCrsr->SttEndDoc( bStt );
if( bRet )
{
if( bStt )
pTmpCrsr->GetPtPos().Y() = 0; // expl. 0 setzen (TabellenHeader)
if( pBlockCrsr )
{
pBlockCrsr->clearPoints();
RefreshBlockCursor();
}
UpdateCrsr(SwCrsrShell::SCROLLWIN|SwCrsrShell::CHKRANGE|SwCrsrShell::READONLY);
}
return bRet;
}
void SwCrsrShell::ExtendedSelectAll()
{
SwNodes& rNodes = GetDoc()->GetNodes();
SwPosition* pPos = pCurCrsr->GetPoint();
pPos->nNode = rNodes.GetEndOfPostIts();
pPos->nContent.Assign( rNodes.GoNext( &pPos->nNode ), 0 );
pPos = pCurCrsr->GetMark();
pPos->nNode = rNodes.GetEndOfContent();
SwCntntNode* pCNd = rNodes.GoPrevious( &pPos->nNode );
pPos->nContent.Assign( pCNd, pCNd ? pCNd->Len() : 0 );
}
sal_Bool SwCrsrShell::MovePage( SwWhichPage fnWhichPage, SwPosPage fnPosPage )
{
sal_Bool bRet = sal_False;
// Springe beim Selektieren nie ueber Section-Grenzen !!
if( !pCurCrsr->HasMark() || !pCurCrsr->IsNoCntnt() )
{
SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen
SET_CURR_SHELL( this );
SwCrsrSaveState aSaveState( *pCurCrsr );
Point& rPt = pCurCrsr->GetPtPos();
SwCntntFrm * pFrm = pCurCrsr->GetCntntNode()->
getLayoutFrm( GetLayout(), &rPt, pCurCrsr->GetPoint(), sal_False );
if( pFrm && sal_True == ( bRet = GetFrmInPage( pFrm, fnWhichPage,
fnPosPage, pCurCrsr ) ) &&
!pCurCrsr->IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
nsSwCursorSelOverFlags::SELOVER_CHANGEPOS ))
UpdateCrsr();
else
bRet = sal_False;
}
return bRet;
}
sal_Bool SwCrsrShell::MovePara(SwWhichPara fnWhichPara, SwPosPara fnPosPara )
{
SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen
SwCursor* pTmpCrsr = getShellCrsr( true );
sal_Bool bRet = pTmpCrsr->MovePara( fnWhichPara, fnPosPara );
if( bRet )
UpdateCrsr();
return bRet;
}
sal_Bool SwCrsrShell::MoveSection( SwWhichSection fnWhichSect,
SwPosSection fnPosSect)
{
SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen
SwCursor* pTmpCrsr = getShellCrsr( true );
sal_Bool bRet = pTmpCrsr->MoveSection( fnWhichSect, fnPosSect );
if( bRet )
UpdateCrsr();
return bRet;
}
// Positionieren des Cursors
SwFrm* lcl_IsInHeaderFooter( const SwNodeIndex& rIdx, Point& rPt )
{
SwFrm* pFrm = 0;
SwCntntNode* pCNd = rIdx.GetNode().GetCntntNode();
if( pCNd )
{
pFrm = pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout(), &rPt, 0, sal_False )->GetUpper();
while( pFrm && !pFrm->IsHeaderFrm() && !pFrm->IsFooterFrm() )
pFrm = pFrm->IsFlyFrm() ? ((SwFlyFrm*)pFrm)->AnchorFrm()
: pFrm->GetUpper();
}
return pFrm;
}
sal_Bool SwCrsrShell::IsInHeaderFooter( sal_Bool* pbInHeader ) const
{
Point aPt;
SwFrm* pFrm = ::lcl_IsInHeaderFooter( pCurCrsr->GetPoint()->nNode, aPt );
if( pFrm && pbInHeader )
*pbInHeader = pFrm->IsHeaderFrm();
return 0 != pFrm;
}
int SwCrsrShell::SetCrsr( const Point &rLPt, sal_Bool bOnlyText, bool bBlock )
{
SET_CURR_SHELL( this );
SwShellCrsr* pCrsr = getShellCrsr( bBlock );
SwPosition aPos( *pCrsr->GetPoint() );
Point aPt( rLPt );
Point & rAktCrsrPt = pCrsr->GetPtPos();
SwCrsrMoveState aTmpState( IsTableMode() ? MV_TBLSEL :
bOnlyText ? MV_SETONLYTEXT : MV_NONE );
aTmpState.bSetInReadOnly = IsReadOnlyAvailable();
SwTxtNode * pTxtNd = pCrsr->GetNode()->GetTxtNode();
if ( pTxtNd && !IsTableMode() &&
// --> FME 2004-11-25 #i37515# No bInFrontOfLabel during selection
!pCrsr->HasMark() &&
// <--
pTxtNd->HasVisibleNumberingOrBullet() )
{
aTmpState.bInFrontOfLabel = sal_True; // #i27615#
}
else
{
aTmpState.bInFrontOfLabel = sal_False;
}
int bRet = CRSR_POSOLD |
( GetLayout()->GetCrsrOfst( &aPos, aPt, &aTmpState )
? 0 : CRSR_POSCHG );
const bool bOldInFrontOfLabel = IsInFrontOfLabel();
const bool bNewInFrontOfLabel = aTmpState.bInFrontOfLabel;
pCrsr->SetCrsrBidiLevel( aTmpState.nCursorBidiLevel );
if( MV_RIGHTMARGIN == aTmpState.eState )
eMvState = MV_RIGHTMARGIN;
// steht neu Pos im Header/Footer ?
SwFrm* pFrm = lcl_IsInHeaderFooter( aPos.nNode, aPt );
if( IsTableMode() && !pFrm && aPos.nNode.GetNode().StartOfSectionNode() ==
pCrsr->GetPoint()->nNode.GetNode().StartOfSectionNode() )
// gleiche Tabellenzelle und nicht im Header/Footer
// -> zurueck
return bRet;
if( pBlockCrsr && bBlock )
{
pBlockCrsr->setEndPoint( rLPt );
if( !pCrsr->HasMark() )
pBlockCrsr->setStartPoint( rLPt );
else if( !pBlockCrsr->getStartPoint() )
pBlockCrsr->setStartPoint( pCrsr->GetMkPos() );
}
if( !pCrsr->HasMark() )
{
// steht an der gleichen Position und wenn im Header/Footer,
// dann im gleichen
if( aPos == *pCrsr->GetPoint() &&
bOldInFrontOfLabel == bNewInFrontOfLabel )
{
if( pFrm )
{
if( pFrm->Frm().IsInside( rAktCrsrPt ))
return bRet;
}
else if( aPos.nNode.GetNode().IsCntntNode() )
{
// im gleichen Frame gelandet?
SwFrm* pOld = ((SwCntntNode&)aPos.nNode.GetNode()).getLayoutFrm(
GetLayout(), &aCharRect.Pos(), 0, sal_False );
SwFrm* pNew = ((SwCntntNode&)aPos.nNode.GetNode()).getLayoutFrm(
GetLayout(), &aPt, 0, sal_False );
if( pNew == pOld )
return bRet;
}
}
}
else
{
// SSelection ueber nicht erlaubte Sections oder wenn im Header/Footer
// dann in verschiedene
if( !CheckNodesRange( aPos.nNode, pCrsr->GetMark()->nNode, sal_True )
|| ( pFrm && !pFrm->Frm().IsInside( pCrsr->GetMkPos() ) ))
return bRet;
// steht an der gleichen Position und nicht im Header/Footer
if( aPos == *pCrsr->GetPoint() )
return bRet;
}
SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen
SwCrsrSaveState aSaveState( *pCrsr );
*pCrsr->GetPoint() = aPos;
rAktCrsrPt = aPt;
// --> FME 2005-01-31 #i41424# Only update the marked number levels if necessary
// Force update of marked number levels if necessary.
if ( bNewInFrontOfLabel || bOldInFrontOfLabel )
pCurCrsr->_SetInFrontOfLabel( !bNewInFrontOfLabel );
SetInFrontOfLabel( bNewInFrontOfLabel );
// <--
if( !pCrsr->IsSelOvr( nsSwCursorSelOverFlags::SELOVER_CHANGEPOS ) )
{
sal_uInt16 nFlag = SwCrsrShell::SCROLLWIN | SwCrsrShell::CHKRANGE;
UpdateCrsr( nFlag );
bRet &= ~CRSR_POSOLD;
}
else if( bOnlyText && !pCurCrsr->HasMark() )
{
if( FindValidCntntNode( bOnlyText ) )
{
// Cursor in einen gueltigen Content stellen
if( aPos == *pCrsr->GetPoint() )
bRet = CRSR_POSOLD;
else
{
UpdateCrsr( SwCrsrShell::SCROLLWIN | SwCrsrShell::CHKRANGE );
bRet &= ~CRSR_POSOLD;
}
}
else
{
// es gibt keinen gueltigen Inhalt -> Cursor verstecken
pVisCrsr->Hide(); // sichtbaren Cursor immer verstecken
eMvState = MV_NONE; // Status fuers Crsr-Travelling
bAllProtect = sal_True;
if( GetDoc()->GetDocShell() )
{
GetDoc()->GetDocShell()->SetReadOnlyUI( sal_True );
CallChgLnk(); // UI bescheid sagen!
}
}
}
return bRet;
}
void SwCrsrShell::TblCrsrToCursor()
{
ASSERT( pTblCrsr, "TblCrsrToCursor: Why?" );
delete pTblCrsr, pTblCrsr = 0;
}
void SwCrsrShell::BlockCrsrToCrsr()
{
ASSERT( pBlockCrsr, "BlockCrsrToCrsr: Why?" );
if( pBlockCrsr && !HasSelection() )
{
SwPaM& rPam = pBlockCrsr->getShellCrsr();
pCurCrsr->SetMark();
*pCurCrsr->GetPoint() = *rPam.GetPoint();
if( rPam.HasMark() )
*pCurCrsr->GetMark() = *rPam.GetMark();
else
pCurCrsr->DeleteMark();
}
delete pBlockCrsr, pBlockCrsr = 0;
}
void SwCrsrShell::CrsrToBlockCrsr()
{
if( !pBlockCrsr )
{
SwPosition aPos( *pCurCrsr->GetPoint() );
pBlockCrsr = createBlockCursor( *this, aPos );
SwShellCrsr &rBlock = pBlockCrsr->getShellCrsr();
rBlock.GetPtPos() = pCurCrsr->GetPtPos();
if( pCurCrsr->HasMark() )
{
rBlock.SetMark();
*rBlock.GetMark() = *pCurCrsr->GetMark();
rBlock.GetMkPos() = pCurCrsr->GetMkPos();
}
}
pBlockCrsr->clearPoints();
RefreshBlockCursor();
}
void SwCrsrShell::ClearMark()
{
// ist ueberhaupt ein GetMark gesetzt ?
if( pTblCrsr )
{
while( pCurCrsr->GetNext() != pCurCrsr )
delete pCurCrsr->GetNext();
pTblCrsr->DeleteMark();
if( pCurCrsr->HasMark() )
{
// falls doch nicht alle Indizies richtig verschoben werden
// (z.B.: Kopf-/Fusszeile loeschen) den Content-Anteil vom
// Mark aufs Nodes-Array setzen
SwPosition& rPos = *pCurCrsr->GetMark();
rPos.nNode.Assign( pDoc->GetNodes(), 0 );
rPos.nContent.Assign( 0, 0 );
pCurCrsr->DeleteMark();
}
*pCurCrsr->GetPoint() = *pTblCrsr->GetPoint();
pCurCrsr->GetPtPos() = pTblCrsr->GetPtPos();
delete pTblCrsr, pTblCrsr = 0;
pCurCrsr->SwSelPaintRects::Show();
}
else
{
if( !pCurCrsr->HasMark() )
return;
// falls doch nicht alle Indizies richtig verschoben werden
// (z.B.: Kopf-/Fusszeile loeschen) den Content-Anteil vom
// Mark aufs Nodes-Array setzen
SwPosition& rPos = *pCurCrsr->GetMark();
rPos.nNode.Assign( pDoc->GetNodes(), 0 );
rPos.nContent.Assign( 0, 0 );
pCurCrsr->DeleteMark();
if( !nCrsrMove )
pCurCrsr->SwSelPaintRects::Show();
}
}
void SwCrsrShell::NormalizePam(sal_Bool bPointFirst)
{
SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen
pCurCrsr->Normalize(bPointFirst);
}
void SwCrsrShell::SwapPam()
{
SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen
pCurCrsr->Exchange();
}
// suche innerhalb der Selektierten-Bereiche nach einer Selektion, die
// den angebenen SPoint umschliesst
// Ist das Flag bTstOnly gesetzt, dann wird nur getestet, ob dort eine
// SSelection besteht; des akt. Cursr wird nicht umgesetzt!
// Ansonsten wird er auf die gewaehlte SSelection gesetzt.
sal_Bool SwCrsrShell::ChgCurrPam(
const Point & rPt,
sal_Bool bTstOnly,
sal_Bool bTstHit )
{
SET_CURR_SHELL( this );
// Pruefe ob der SPoint in einer Tabellen-Selektion liegt
if( bTstOnly && pTblCrsr )
return pTblCrsr->IsInside( rPt );
SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen
// Suche die Position rPt im Dokument
SwPosition aPtPos( *pCurCrsr->GetPoint() );
Point aPt( rPt );
SwCrsrMoveState aTmpState( MV_NONE );
aTmpState.bSetInReadOnly = IsReadOnlyAvailable();
if ( !GetLayout()->GetCrsrOfst( &aPtPos, aPt, &aTmpState ) && bTstHit )
return sal_False;
// suche in allen Selektionen nach dieser Position
SwShellCrsr* pCmp = (SwShellCrsr*)pCurCrsr; // sicher den Pointer auf Cursor
do {
if( pCmp->HasMark() &&
*pCmp->Start() <= aPtPos && *pCmp->End() > aPtPos )
{
if( bTstOnly || pCurCrsr == pCmp ) // ist der aktuelle.
return sal_True; // return ohne Update
pCurCrsr = pCmp;
UpdateCrsr(); // Cursor steht schon richtig
return sal_True;
}
} while( pCurCrsr !=
( pCmp = dynamic_cast<SwShellCrsr*>(pCmp->GetNext()) ) );
return sal_False;
}
void SwCrsrShell::KillPams()
{
// keiner zum loeschen vorhanden?
if( !pTblCrsr && !pBlockCrsr && pCurCrsr->GetNext() == pCurCrsr )
return;
while( pCurCrsr->GetNext() != pCurCrsr )
delete pCurCrsr->GetNext();
pCurCrsr->SetColumnSelection( false );
if( pTblCrsr )
{
// Cursor Ring loeschen
pCurCrsr->DeleteMark();
*pCurCrsr->GetPoint() = *pTblCrsr->GetPoint();
pCurCrsr->GetPtPos() = pTblCrsr->GetPtPos();
delete pTblCrsr;
pTblCrsr = 0;
}
else if( pBlockCrsr )
{
// delete the ring of cursors
pCurCrsr->DeleteMark();
SwShellCrsr &rBlock = pBlockCrsr->getShellCrsr();
*pCurCrsr->GetPoint() = *rBlock.GetPoint();
pCurCrsr->GetPtPos() = rBlock.GetPtPos();
rBlock.DeleteMark();
pBlockCrsr->clearPoints();
}
UpdateCrsr( SwCrsrShell::SCROLLWIN );
}
int SwCrsrShell::CompareCursor( CrsrCompareType eType ) const
{
int nRet = 0;
const SwPosition *pFirst = 0, *pSecond = 0;
const SwPaM *pCur = GetCrsr(), *pStk = pCrsrStk;
if( CurrPtCurrMk != eType && pStk )
{
switch ( eType)
{
case StackPtStackMk:
pFirst = pStk->GetPoint();
pSecond = pStk->GetMark();
break;
case StackPtCurrPt:
pFirst = pStk->GetPoint();
pSecond = pCur->GetPoint();
break;
case StackPtCurrMk:
pFirst = pStk->GetPoint();
pSecond = pCur->GetMark();
break;
case StackMkCurrPt:
pFirst = pStk->GetMark();
pSecond = pCur->GetPoint();
break;
case StackMkCurrMk:
pFirst = pStk->GetMark();
pSecond = pStk->GetMark();
break;
case CurrPtCurrMk:
pFirst = pCur->GetPoint();
pSecond = pCur->GetMark();
break;
}
}
if( !pFirst || !pSecond )
nRet = INT_MAX;
else if( *pFirst < *pSecond )
nRet = -1;
else if( *pFirst == *pSecond )
nRet = 0;
else
nRet = 1;
return nRet;
}
sal_Bool SwCrsrShell::IsSttPara() const
{ return( pCurCrsr->GetPoint()->nContent == 0 ? sal_True : sal_False ); }
sal_Bool SwCrsrShell::IsEndPara() const
{ return( pCurCrsr->GetPoint()->nContent == pCurCrsr->GetCntntNode()->Len() ? sal_True : sal_False ); }
sal_Bool SwCrsrShell::IsInFrontOfLabel() const
{
return pCurCrsr->IsInFrontOfLabel();
}
bool SwCrsrShell::SetInFrontOfLabel( sal_Bool bNew )
{
if ( bNew != IsInFrontOfLabel() )
{
pCurCrsr->_SetInFrontOfLabel( bNew );
UpdateMarkedListLevel();
return true;
}
return false;
}
sal_Bool SwCrsrShell::GotoPage( sal_uInt16 nPage )
{
SET_CURR_SHELL( this );
SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen
SwCrsrSaveState aSaveState( *pCurCrsr );
sal_Bool bRet = GetLayout()->SetCurrPage( pCurCrsr, nPage ) &&
!pCurCrsr->IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
if( bRet )
UpdateCrsr(SwCrsrShell::SCROLLWIN|SwCrsrShell::CHKRANGE|SwCrsrShell::READONLY);
return bRet;
}
void SwCrsrShell::GetPageNum( sal_uInt16 &rnPhyNum, sal_uInt16 &rnVirtNum,
sal_Bool bAtCrsrPos, const sal_Bool bCalcFrm )
{
SET_CURR_SHELL( this );
// Seitennummer: die erste sichtbare Seite oder die am Cursor
const SwCntntFrm* pCFrm;
const SwPageFrm *pPg = 0;
if( !bAtCrsrPos || 0 == (pCFrm = GetCurrFrm( bCalcFrm )) ||
0 == (pPg = pCFrm->FindPageFrm()) )
{
pPg = Imp()->GetFirstVisPage();
while( pPg && pPg->IsEmptyPage() )
pPg = (const SwPageFrm *)pPg->GetNext();
}
// Abfrage auf pPg muss fuer den Sonderfall Writerstart mit
// standard.vor sein.
rnPhyNum = pPg? pPg->GetPhyPageNum() : 1;
rnVirtNum = pPg? pPg->GetVirtPageNum() : 1;
}
sal_uInt16 SwCrsrShell::GetNextPrevPageNum( sal_Bool bNext )
{
SET_CURR_SHELL( this );
// Seitennummer: die erste sichtbare Seite oder die am Cursor
const SwPageFrm *pPg = Imp()->GetFirstVisPage();
if( pPg )
{
const SwTwips nPageTop = pPg->Frm().Top();
if( bNext )
{
// go to next view layout row:
do
{
pPg = (const SwPageFrm *)pPg->GetNext();
}
while( pPg && pPg->Frm().Top() == nPageTop );
while( pPg && pPg->IsEmptyPage() )
pPg = (const SwPageFrm *)pPg->GetNext();
}
else
{
// go to previous view layout row:
do
{
pPg = (const SwPageFrm *)pPg->GetPrev();
}
while( pPg && pPg->Frm().Top() == nPageTop );
while( pPg && pPg->IsEmptyPage() )
pPg = (const SwPageFrm *)pPg->GetPrev();
}
}
// Abfrage auf pPg muss fuer den Sonderfall Writerstart mit
// standard.vor sein.
return pPg ? pPg->GetPhyPageNum() : USHRT_MAX;
}
sal_uInt16 SwCrsrShell::GetPageCnt()
{
SET_CURR_SHELL( this );
// gebe die Anzahl der Seiten zurueck
return GetLayout()->GetPageNum();
}
// Gehe zur naechsten SSelection
sal_Bool SwCrsrShell::GoNextCrsr()
{
// besteht ueberhaupt ein Ring ?
if( pCurCrsr->GetNext() == pCurCrsr )
return sal_False;
SET_CURR_SHELL( this );
SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen
pCurCrsr = dynamic_cast<SwShellCrsr*>(pCurCrsr->GetNext());
// Bug 24086: auch alle anderen anzeigen
if( !ActionPend() )
{
UpdateCrsr();
pCurCrsr->Show();
}
return sal_True;
}
// gehe zur vorherigen SSelection
sal_Bool SwCrsrShell::GoPrevCrsr()
{
// besteht ueberhaupt ein Ring ?
if( pCurCrsr->GetNext() == pCurCrsr )
return sal_False;
SET_CURR_SHELL( this );
SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen
pCurCrsr = dynamic_cast<SwShellCrsr*>(pCurCrsr->GetPrev());
// Bug 24086: auch alle anderen anzeigen
if( !ActionPend() )
{
UpdateCrsr();
pCurCrsr->Show();
}
return sal_True;
}
void SwCrsrShell::Paint( const Rectangle &rRect)
{
SET_CURR_SHELL( this );
// beim Painten immer alle Cursor ausschalten
SwRect aRect( rRect );
sal_Bool bVis = sal_False;
// ist Cursor sichtbar, dann verstecke den SV-Cursor
if( pVisCrsr->IsVisible() && !aRect.IsOver( aCharRect ) ) //JP 18.06.97: ???
{
bVis = sal_True;
pVisCrsr->Hide();
}
// Bereich neu painten
ViewShell::Paint( rRect );
if( bHasFocus && !bBasicHideCrsr )
{
SwShellCrsr* pAktCrsr = pTblCrsr ? pTblCrsr : pCurCrsr;
// pAktCrsr->Invalidate( aRect );
if( !ActionPend() )
{
// damit nicht rechts/unten die Raender abgeschnitten werden
pAktCrsr->Invalidate( VisArea() );
pAktCrsr->Show();
}
else
pAktCrsr->Invalidate( aRect );
}
if( bSVCrsrVis && bVis ) // auch SV-Cursor wieder anzeigen
pVisCrsr->Show();
}
void SwCrsrShell::VisPortChgd( const SwRect & rRect )
{
SET_CURR_SHELL( this );
sal_Bool bVis; // beim Scrollen immer alle Cursor ausschalten
// ist Cursor sichtbar, dann verstecke den SV-Cursor
if( sal_True == ( bVis = pVisCrsr->IsVisible() ))
pVisCrsr->Hide();
bVisPortChgd = sal_True;
aOldRBPos.X() = VisArea().Right();
aOldRBPos.Y() = VisArea().Bottom();
//Damit es es keine Probleme mit dem SV-Cursor gibt, wird in
//ViewShell::VisPo.. ein Update() auf das Window gerufen.
//Waehrend des Paintens duerfen aber nun wieder keine Selectionen
//angezeigt werden, deshalb wird der Aufruf hier geklammert.
ViewShell::VisPortChgd( rRect ); // Bereich verschieben
/*
SwRect aRect( rRect );
if( VisArea().IsOver( aRect ) )
pCurCrsr->Invalidate( aRect );
*/
if( bSVCrsrVis && bVis ) // auch SV-Cursor wieder anzeigen
pVisCrsr->Show();
if( nCrsrMove )
bInCMvVisportChgd = sal_True;
bVisPortChgd = sal_False;
}
// aktualisiere den Crsrs, d.H. setze ihn wieder in den Content.
// Das sollte nur aufgerufen werden, wenn der Cursor z.B. beim
// Loeschen von Rahmen irgendwohin gesetzt wurde. Die Position
// ergibt sich aus seiner aktuellen Position im Layout !!
void SwCrsrShell::UpdateCrsrPos()
{
SET_CURR_SHELL( this );
++nStartAction;
SwShellCrsr* pShellCrsr = getShellCrsr( true );
Size aOldSz( GetDocSize() );
SwCntntNode *pCNode = pShellCrsr->GetCntntNode();
SwCntntFrm *pFrm = pCNode ?
pCNode->getLayoutFrm( GetLayout(), &pShellCrsr->GetPtPos(), pShellCrsr->GetPoint(), sal_False ) :0;
if( !pFrm || (pFrm->IsTxtFrm() && ((SwTxtFrm*)pFrm)->IsHiddenNow()) )
{
SwCrsrMoveState aTmpState( MV_NONE );
aTmpState.bSetInReadOnly = IsReadOnlyAvailable();
GetLayout()->GetCrsrOfst( pShellCrsr->GetPoint(), pShellCrsr->GetPtPos(),
&aTmpState );
if( pShellCrsr->HasMark())
pShellCrsr->DeleteMark();
}
IGrammarContact *pGrammarContact = GetDoc() ? GetDoc()->getGrammarContact() : 0;
if( pGrammarContact )
pGrammarContact->updateCursorPosition( *pCurCrsr->GetPoint() );
--nStartAction;
if( aOldSz != GetDocSize() )
SizeChgNotify();
}
// JP 30.04.99: Bug 65475 - falls Point/Mark in versteckten Bereichen
// stehen, so mussen diese daraus verschoben werden
static void lcl_CheckHiddenSection( SwNodeIndex& rIdx )
{
const SwSectionNode* pSectNd = rIdx.GetNode().FindSectionNode();
if( pSectNd && pSectNd->GetSection().IsHiddenFlag() )
{
SwNodeIndex aTmp( *pSectNd );
#if OSL_DEBUG_LEVEL > 1
const SwNode* pFrmNd =
#endif
rIdx.GetNodes().FindPrvNxtFrmNode( aTmp, pSectNd->EndOfSectionNode() );
#if OSL_DEBUG_LEVEL > 1
(void) pFrmNd;
ASSERT( pFrmNd, "keinen Node mit Frames gefunden" );
#endif
rIdx = aTmp;
}
}
// Try to set the cursor to the next visible content node.
static void lcl_CheckHiddenPara( SwPosition& rPos )
{
SwNodeIndex aTmp( rPos.nNode );
SwTxtNode* pTxtNd = aTmp.GetNode().GetTxtNode();
while( pTxtNd && pTxtNd->HasHiddenCharAttribute( true ) )
{
SwCntntNode* pCntnt = aTmp.GetNodes().GoNext( &aTmp );
if ( pCntnt && pCntnt->IsTxtNode() )
pTxtNd = (SwTxtNode*)pCntnt;
else
pTxtNd = 0;
}
if ( pTxtNd )
rPos = SwPosition( aTmp, SwIndex( pTxtNd, 0 ) );
}
// --> OD 2005-12-14 #i27301# - helper class, which notifies the accessibility
// about invalid text selections in its destructor
class SwNotifyAccAboutInvalidTextSelections
{
private:
SwCrsrShell& mrCrsrSh;
public:
SwNotifyAccAboutInvalidTextSelections( SwCrsrShell& _rCrsrSh )
: mrCrsrSh( _rCrsrSh )
{}
~SwNotifyAccAboutInvalidTextSelections()
{
mrCrsrSh.InvalidateAccessibleParaTextSelection();
}
};
// <--
void SwCrsrShell::UpdateCrsr( sal_uInt16 eFlags, sal_Bool bIdleEnd )
{
SET_CURR_SHELL( this );
ClearUpCrsrs();
// erfrage den Count fuer die Start-/End-Actions und ob die Shell
// ueberhaupt den Focus hat
// if( ActionPend() /*|| !bHasFocus*/ )
//JP 12.01.98: Bug #46496# - es muss innerhalb einer BasicAction der
// Cursor geupdatet werden; um z.B. den TabellenCursor zu
// erzeugen. Im EndAction wird jetzt das UpdateCrsr gerufen!
if( ActionPend() && BasicActionPend() )
{
if ( eFlags & SwCrsrShell::READONLY )
bIgnoreReadonly = sal_True;
return; // wenn nicht, dann kein Update !!
}
SwNotifyAccAboutInvalidTextSelections aInvalidateTextSelections( *this );
if ( bIgnoreReadonly )
{
bIgnoreReadonly = sal_False;
eFlags |= SwCrsrShell::READONLY;
}
if( eFlags & SwCrsrShell::CHKRANGE ) // alle Cursor-Bewegungen auf
CheckRange( pCurCrsr ); // ueberlappende Bereiche testen
if( !bIdleEnd )
CheckTblBoxCntnt();
// steht der akt. Crsr in einer Tabelle und in unterschiedlichen Boxen
// (oder ist noch TabellenMode), dann gilt der Tabellen Mode
SwPaM* pTstCrsr = getShellCrsr( true );
if( pTstCrsr->HasMark() && !pBlockCrsr &&
pDoc->IsIdxInTbl( pTstCrsr->GetPoint()->nNode ) &&
( pTblCrsr ||
pTstCrsr->GetNode( sal_True )->StartOfSectionNode() !=
pTstCrsr->GetNode( sal_False )->StartOfSectionNode() ) )
{
SwShellCrsr* pITmpCrsr = getShellCrsr( true );
Point aTmpPt( pITmpCrsr->GetPtPos() );
Point aTmpMk( pITmpCrsr->GetMkPos() );
SwPosition* pPos = pITmpCrsr->GetPoint();
// JP 30.04.99: Bug 65475 - falls Point/Mark in versteckten Bereichen
// stehen, so mussen diese daraus verschoben werden
lcl_CheckHiddenSection( pPos->nNode );
lcl_CheckHiddenSection( pITmpCrsr->GetMark()->nNode );
// Move cursor out of hidden paragraphs
if ( !GetViewOptions()->IsShowHiddenChar() )
{
lcl_CheckHiddenPara( *pPos );
lcl_CheckHiddenPara( *pITmpCrsr->GetMark() );
}
SwCntntFrm *pTblFrm = pPos->nNode.GetNode().GetCntntNode()->
getLayoutFrm( GetLayout(), &aTmpPt, pPos, sal_False );
ASSERT( pTblFrm, "Tabelle Crsr nicht im Content ??" );
// --> FME 2005-12-02 #126107# Make code robust. The table
// cursor may point to a table in a currently inactive header.
SwTabFrm *pTab = pTblFrm ? pTblFrm->FindTabFrm() : 0;
// <--
if ( pTab && pTab->GetTable()->GetRowsToRepeat() > 0 )
{
// First check if point is in repeated headline:
bool bInRepeatedHeadline = pTab->IsFollow() && pTab->IsInHeadline( *pTblFrm );
// Second check if mark is in repeated headline:
if ( !bInRepeatedHeadline )
{
SwCntntFrm* pMarkTblFrm = pITmpCrsr->GetCntntNode( sal_False )->
getLayoutFrm( GetLayout(), &aTmpMk, pITmpCrsr->GetMark(), sal_False );
ASSERT( pMarkTblFrm, "Tabelle Crsr nicht im Content ??" );
if ( pMarkTblFrm )
{
SwTabFrm* pMarkTab = pMarkTblFrm->FindTabFrm();
ASSERT( pMarkTab, "Tabelle Crsr nicht im Content ??" );
// --> FME 2005-11-28 #120360# Make code robust:
if ( pMarkTab )
{
bInRepeatedHeadline = pMarkTab->IsFollow() && pMarkTab->IsInHeadline( *pMarkTblFrm );
}
// <--
}
}
// No table cursor in repeaded headlines:
if ( bInRepeatedHeadline )
{
pTblFrm = 0;
SwPosSection fnPosSect = *pPos < *pITmpCrsr->GetMark()
? fnSectionStart
: fnSectionEnd;
// dann nur innerhalb der Box selektieren
if( pTblCrsr )
{
pCurCrsr->SetMark();
*pCurCrsr->GetMark() = *pTblCrsr->GetMark();
pCurCrsr->GetMkPos() = pTblCrsr->GetMkPos();
pTblCrsr->DeleteMark();
pTblCrsr->SwSelPaintRects::Hide();
}
*pCurCrsr->GetPoint() = *pCurCrsr->GetMark();
(*fnSectionCurr)( *pCurCrsr, fnPosSect );
}
}
// wir wollen wirklich eine Tabellen-Selektion
if( pTab && pTblFrm )
{
if( !pTblCrsr )
{
pTblCrsr = new SwShellTableCrsr( *this,
*pCurCrsr->GetMark(), pCurCrsr->GetMkPos(),
*pPos, aTmpPt );
pCurCrsr->DeleteMark();
pCurCrsr->SwSelPaintRects::Hide();
CheckTblBoxCntnt();
}
SwCrsrMoveState aTmpState( MV_NONE );
aTmpState.bRealHeight = sal_True;
if( !pTblFrm->GetCharRect( aCharRect, *pTblCrsr->GetPoint(), &aTmpState ) )
{
Point aCentrPt( aCharRect.Center() );
aTmpState.bSetInReadOnly = IsReadOnlyAvailable();
pTblFrm->GetCrsrOfst( pTblCrsr->GetPoint(), aCentrPt, &aTmpState );
#ifndef DBG_UTIL
pTblFrm->GetCharRect( aCharRect, *pTblCrsr->GetPoint() );
#else
if ( !pTblFrm->GetCharRect( aCharRect, *pTblCrsr->GetPoint() ) )
ASSERT( !this, "GetCharRect failed." );
#endif
}
// ALIGNRECT( aCharRect );
pVisCrsr->Hide(); // sichtbaren Cursor immer verstecken
// Curosr in den sichtbaren Bereich scrollen
if( (eFlags & SwCrsrShell::SCROLLWIN) &&
(HasSelection() || eFlags & SwCrsrShell::READONLY ||
!IsCrsrReadonly()) )
{
SwFrm* pBoxFrm = pTblFrm;
while( pBoxFrm && !pBoxFrm->IsCellFrm() )
pBoxFrm = pBoxFrm->GetUpper();
if( pBoxFrm && pBoxFrm->Frm().HasArea() )
MakeVisible( pBoxFrm->Frm() );
else
MakeVisible( aCharRect );
}
// lasse vom Layout die Crsr in den Boxen erzeugen
if( pTblCrsr->IsCrsrMovedUpdt() )
GetLayout()->MakeTblCrsrs( *pTblCrsr );
if( bHasFocus && !bBasicHideCrsr )
pTblCrsr->Show();
// Cursor-Points auf die neuen Positionen setzen
pTblCrsr->GetPtPos().X() = aCharRect.Left();
pTblCrsr->GetPtPos().Y() = aCharRect.Top();
if( bSVCrsrVis )
{
aCrsrHeight.X() = 0;
aCrsrHeight.Y() = aTmpState.aRealHeight.Y() < 0 ?
-aCharRect.Width() : aCharRect.Height();
pVisCrsr->Show(); // wieder anzeigen
}
eMvState = MV_NONE; // Status fuers Crsr-Travelling - GetCrsrOfst
if( pTblFrm && Imp()->IsAccessible() )
Imp()->InvalidateAccessibleCursorPosition( pTblFrm );
return;
}
}
if( pTblCrsr )
{
// Cursor Ring loeschen
while( pCurCrsr->GetNext() != pCurCrsr )
delete pCurCrsr->GetNext();
pCurCrsr->DeleteMark();
*pCurCrsr->GetPoint() = *pTblCrsr->GetPoint();
pCurCrsr->GetPtPos() = pTblCrsr->GetPtPos();
delete pTblCrsr, pTblCrsr = 0;
}
pVisCrsr->Hide(); // sichtbaren Cursor immer verstecken
// sind wir vielleicht in einer geschuetzten/versteckten Section ?
{
SwShellCrsr* pShellCrsr = getShellCrsr( true );
sal_Bool bChgState = sal_True;
const SwSectionNode* pSectNd = pShellCrsr->GetNode()->FindSectionNode();
if( pSectNd && ( pSectNd->GetSection().IsHiddenFlag() ||
( !IsReadOnlyAvailable() &&
pSectNd->GetSection().IsProtectFlag() &&
( !pDoc->GetDocShell() ||
!pDoc->GetDocShell()->IsReadOnly() || bAllProtect )) ) )
{
if( !FindValidCntntNode( !HasDrawView() ||
0 == Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount()))
{
// alles ist geschuetzt / versteckt -> besonderer Mode
if( bAllProtect && !IsReadOnlyAvailable() &&
pSectNd->GetSection().IsProtectFlag() )
bChgState = sal_False;
else
{
eMvState = MV_NONE; // Status fuers Crsr-Travelling
bAllProtect = sal_True;
if( GetDoc()->GetDocShell() )
{
GetDoc()->GetDocShell()->SetReadOnlyUI( sal_True );
CallChgLnk(); // UI bescheid sagen!
}
return;
}
}
}
if( bChgState )
{
sal_Bool bWasAllProtect = bAllProtect;
bAllProtect = sal_False;
if( bWasAllProtect && GetDoc()->GetDocShell() &&
GetDoc()->GetDocShell()->IsReadOnlyUI() )
{
GetDoc()->GetDocShell()->SetReadOnlyUI( sal_False );
CallChgLnk(); // UI bescheid sagen!
}
}
}
UpdateCrsrPos();
// #100722# The cursor must always point into content; there's some code
// that relies on this. (E.g. in SwEditShell::GetScriptType, which always
// loops _behind_ the last node in the selection, which always works if you
// are in content.) To achieve this, we'll force cursor(s) to point into
// content, if UpdateCrsrPos() hasn't already done so.
SwPaM* pCmp = pCurCrsr;
do
{
// start will move forwards, end will move backwards
bool bPointIsStart = ( pCmp->Start() == pCmp->GetPoint() );
// move point; forward if it's the start, backwards if it's the end
if( ! pCmp->GetPoint()->nNode.GetNode().IsCntntNode() )
pCmp->Move( bPointIsStart ? fnMoveForward : fnMoveBackward,
fnGoCntnt );
// move mark (if exists); forward if it's the start, else backwards
if( pCmp->HasMark() )
{
if( ! pCmp->GetMark()->nNode.GetNode().IsCntntNode() )
{
pCmp->Exchange();
pCmp->Move( !bPointIsStart ? fnMoveForward : fnMoveBackward,
fnGoCntnt );
pCmp->Exchange();
}
}
// iterate to next PaM in ring
pCmp = static_cast<SwPaM*>( pCmp->GetNext() );
}
while( pCmp != pCurCrsr );
SwRect aOld( aCharRect );
sal_Bool bFirst = sal_True;
SwCntntFrm *pFrm;
int nLoopCnt = 100;
SwShellCrsr* pShellCrsr = getShellCrsr( true );
do {
sal_Bool bAgainst;
do {
bAgainst = sal_False;
pFrm = pShellCrsr->GetCntntNode()->getLayoutFrm( GetLayout(),
&pShellCrsr->GetPtPos(), pShellCrsr->GetPoint(), sal_False );
// ist der Frm nicht mehr vorhanden, dann muss das gesamte Layout
// erzeugt werden, weil ja mal hier einer vorhanden war !!
if ( !pFrm )
{
do
{
CalcLayout();
pFrm = pShellCrsr->GetCntntNode()->getLayoutFrm( GetLayout(),
&pShellCrsr->GetPtPos(), pShellCrsr->GetPoint(), sal_False );
} while( !pFrm );
}
else if ( Imp()->IsIdleAction() )
//Wir stellen sicher, dass anstaendig Formatiert wurde #42224#
pFrm->PrepareCrsr();
// im geschuetzten Fly? aber bei Rahmenselektion ignorieren
if( !IsReadOnlyAvailable() && pFrm->IsProtected() &&
( !Imp()->GetDrawView() ||
!Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount() ) &&
(!pDoc->GetDocShell() ||
!pDoc->GetDocShell()->IsReadOnly() || bAllProtect ) )
{
// dann suche eine gueltige Position
sal_Bool bChgState = sal_True;
if( !FindValidCntntNode(!HasDrawView() ||
0 == Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount()))
{
// alles ist geschuetzt / versteckt -> besonderer Mode
if( bAllProtect )
bChgState = sal_False;
else
{
eMvState = MV_NONE; // Status fuers Crsr-Travelling
bAllProtect = sal_True;
if( GetDoc()->GetDocShell() )
{
GetDoc()->GetDocShell()->SetReadOnlyUI( sal_True );
CallChgLnk(); // UI bescheid sagen!
}
return;
}
}
if( bChgState )
{
sal_Bool bWasAllProtect = bAllProtect;
bAllProtect = sal_False;
if( bWasAllProtect && GetDoc()->GetDocShell() &&
GetDoc()->GetDocShell()->IsReadOnlyUI() )
{
GetDoc()->GetDocShell()->SetReadOnlyUI( sal_False );
CallChgLnk(); // UI bescheid sagen!
}
bAllProtect = sal_False;
bAgainst = sal_True; // nochmal den richigen Frm suchen
}
}
} while( bAgainst );
if( !( eFlags & SwCrsrShell::NOCALRECT ))
{
SwCrsrMoveState aTmpState( eMvState );
aTmpState.bSetInReadOnly = IsReadOnlyAvailable();
aTmpState.bRealHeight = sal_True;
aTmpState.bRealWidth = IsOverwriteCrsr();
aTmpState.nCursorBidiLevel = pShellCrsr->GetCrsrBidiLevel();
// #i27615#,#i30453#
SwSpecialPos aSpecialPos;
aSpecialPos.nExtendRange = SP_EXTEND_RANGE_BEFORE;
if (pShellCrsr->IsInFrontOfLabel())
{
aTmpState.pSpecialPos = &aSpecialPos;
}
if( !pFrm->GetCharRect( aCharRect, *pShellCrsr->GetPoint(), &aTmpState ) )
{
Point& rPt = pShellCrsr->GetPtPos();
rPt = aCharRect.Center();
pFrm->GetCrsrOfst( pShellCrsr->GetPoint(), rPt, &aTmpState );
}
// ALIGNRECT( aCharRect );
if( !pShellCrsr->HasMark() )
aCrsrHeight = aTmpState.aRealHeight;
else
{
aCrsrHeight.X() = 0;
aCrsrHeight.Y() = aTmpState.aRealHeight.Y() < 0 ?
-aCharRect.Width() : aCharRect.Height();
}
}
else
{
aCrsrHeight.X() = 0;
aCrsrHeight.Y() = aCharRect.Height();
}
if( !bFirst && aOld == aCharRect )
break;
// falls das Layout meint, nach dem 100 durchlauf ist man immer noch
// im Fluss, sollte man die akt. Pos. als gegeben hinnehmen!
// siehe Bug: 29658
if( !--nLoopCnt )
{
ASSERT( !this, "Endlosschleife? CharRect != OldCharRect ");
break;
}
aOld = aCharRect;
bFirst = sal_False;
// Cursor-Points auf die neuen Positionen setzen
pShellCrsr->GetPtPos().X() = aCharRect.Left();
pShellCrsr->GetPtPos().Y() = aCharRect.Top();
if( !(eFlags & SwCrsrShell::UPDOWN )) // alte Pos. von Up/Down loeschen
{
pFrm->Calc();
nUpDownX = pFrm->IsVertical() ?
aCharRect.Top() - pFrm->Frm().Top() :
aCharRect.Left() - pFrm->Frm().Left();
}
// Curosr in den sichtbaren Bereich scrollen
if( bHasFocus && eFlags & SwCrsrShell::SCROLLWIN &&
(HasSelection() || eFlags & SwCrsrShell::READONLY ||
!IsCrsrReadonly() || GetViewOptions()->IsSelectionInReadonly()) )
{
//JP 30.04.99: damit das EndAction, beim evtuellen Scrollen, den
// SV-Crsr nicht wieder sichtbar macht, wird hier das Flag
// gesichert und zurueckgesetzt.
sal_Bool bSav = bSVCrsrVis; bSVCrsrVis = sal_False;
MakeSelVisible();
bSVCrsrVis = bSav;
}
} while( eFlags & SwCrsrShell::SCROLLWIN );
if( pBlockCrsr )
RefreshBlockCursor();
if( !bIdleEnd && bHasFocus && !bBasicHideCrsr )
{
if( pTblCrsr )
pTblCrsr->SwSelPaintRects::Show();
else
{
pCurCrsr->SwSelPaintRects::Show();
if( pBlockCrsr )
{
SwShellCrsr* pNxt = dynamic_cast<SwShellCrsr*>(pCurCrsr->GetNext());
while( pNxt && pNxt != pCurCrsr )
{
pNxt->SwSelPaintRects::Show();
pNxt = dynamic_cast<SwShellCrsr*>(pNxt->GetNext());
}
}
}
}
eMvState = MV_NONE; // Status fuers Crsr-Travelling - GetCrsrOfst
if( pFrm && Imp()->IsAccessible() )
Imp()->InvalidateAccessibleCursorPosition( pFrm );
// switch from blinking cursor to read-only-text-selection cursor
static const long nNoBlinkTime = STYLE_CURSOR_NOBLINKTIME;
const long nBlinkTime = GetOut()->GetSettings().GetStyleSettings().
GetCursorBlinkTime();
if ( (IsCrsrReadonly() && GetViewOptions()->IsSelectionInReadonly()) ==
( nBlinkTime != nNoBlinkTime ) )
{
// non blinking cursor in read only - text selection mode
AllSettings aSettings = GetOut()->GetSettings();
StyleSettings aStyleSettings = aSettings.GetStyleSettings();
const long nNewBlinkTime = nBlinkTime == nNoBlinkTime ?
Application::GetSettings().GetStyleSettings().GetCursorBlinkTime() :
nNoBlinkTime;
aStyleSettings.SetCursorBlinkTime( nNewBlinkTime );
aSettings.SetStyleSettings( aStyleSettings );
GetOut()->SetSettings( aSettings );
}
if( bSVCrsrVis )
pVisCrsr->Show(); // wieder anzeigen
}
void SwCrsrShell::RefreshBlockCursor()
{
ASSERT( pBlockCrsr, "Don't call me without a block cursor" );
SwShellCrsr &rBlock = pBlockCrsr->getShellCrsr();
Point aPt = rBlock.GetPtPos();
SwCntntFrm* pFrm = rBlock.GetCntntNode()->getLayoutFrm( GetLayout(), &aPt, rBlock.GetPoint(), sal_False );
Point aMk;
if( pBlockCrsr->getEndPoint() && pBlockCrsr->getStartPoint() )
{
aPt = *pBlockCrsr->getStartPoint();
aMk = *pBlockCrsr->getEndPoint();
}
else
{
aPt = rBlock.GetPtPos();
if( pFrm )
{
if( pFrm->IsVertical() )
aPt.Y() = pFrm->Frm().Top() + GetUpDownX();
else
aPt.X() = pFrm->Frm().Left() + GetUpDownX();
}
aMk = rBlock.GetMkPos();
}
SwRect aRect( aMk, aPt );
aRect.Justify();
SwSelectionList aSelList( pFrm );
if( GetLayout()->FillSelection( aSelList, aRect ) )
{
SwCursor* pNxt = (SwCursor*)pCurCrsr->GetNext();
while( pNxt != pCurCrsr )
{
delete pNxt;
pNxt = (SwCursor*)pCurCrsr->GetNext();
}
std::list<SwPaM*>::iterator pStart = aSelList.getStart();
std::list<SwPaM*>::iterator pPam = aSelList.getEnd();
ASSERT( pPam != pStart, "FillSelection should deliver at least one PaM" )
pCurCrsr->SetMark();
--pPam;
// If there is only one text portion inside the rectangle, a simple
// selection is created
if( pPam == pStart )
{
*pCurCrsr->GetPoint() = *(*pPam)->GetPoint();
if( (*pPam)->HasMark() )
*pCurCrsr->GetMark() = *(*pPam)->GetMark();
else
pCurCrsr->DeleteMark();
delete *pPam;
pCurCrsr->SetColumnSelection( false );
}
else
{
// The order of the SwSelectionList has to be preserved but
// the order inside the ring created by CreateCrsr() is not like
// exspected => First create the selections before the last one
// downto the first selection.
// At least create the cursor for the last selection
--pPam;
*pCurCrsr->GetPoint() = *(*pPam)->GetPoint(); // n-1 (if n == number of selections)
if( (*pPam)->HasMark() )
*pCurCrsr->GetMark() = *(*pPam)->GetMark();
else
pCurCrsr->DeleteMark();
delete *pPam;
pCurCrsr->SetColumnSelection( true );
while( pPam != pStart )
{
--pPam;
SwShellCrsr* pNew = new SwShellCrsr( *pCurCrsr );
pNew->Insert( pCurCrsr, 0 );
pCurCrsr->Remove( 0, pCurCrsr->Count() );
pCurCrsr->DeleteMark();
*pCurCrsr->GetPoint() = *(*pPam)->GetPoint(); // n-2, n-3, .., 2, 1
if( (*pPam)->HasMark() )
{
pCurCrsr->SetMark();
*pCurCrsr->GetMark() = *(*pPam)->GetMark();
}
else
pCurCrsr->DeleteMark();
pCurCrsr->SetColumnSelection( true );
delete *pPam;
}
{
SwShellCrsr* pNew = new SwShellCrsr( *pCurCrsr );
pNew->Insert( pCurCrsr, 0 );
pCurCrsr->Remove( 0, pCurCrsr->Count() );
pCurCrsr->DeleteMark();
}
pPam = aSelList.getEnd();
--pPam;
*pCurCrsr->GetPoint() = *(*pPam)->GetPoint(); // n, the last selection
if( (*pPam)->HasMark() )
{
pCurCrsr->SetMark();
*pCurCrsr->GetMark() = *(*pPam)->GetMark();
}
else
pCurCrsr->DeleteMark();
pCurCrsr->SetColumnSelection( true );
delete *pPam;
}
}
}
// erzeuge eine Kopie vom Cursor und speicher diese im Stack
void SwCrsrShell::Push()
{
pCrsrStk = new SwShellCrsr( *this, *pCurCrsr->GetPoint(),
pCurCrsr->GetPtPos(), pCrsrStk );
if( pCurCrsr->HasMark() )
{
pCrsrStk->SetMark();
*pCrsrStk->GetMark() = *pCurCrsr->GetMark();
}
}
/*
* Loescht einen Cursor (gesteuert durch bOldCrsr)
* - vom Stack oder ( bOldCrsr = sal_True )
* - den aktuellen und der auf dem Stack stehende wird zum aktuellen
*
* Return: es war auf dem Stack noch einer vorhanden
*/
sal_Bool SwCrsrShell::Pop( sal_Bool bOldCrsr )
{
SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen
// noch weitere vorhanden ?
if( 0 == pCrsrStk )
return sal_False;
SwShellCrsr *pTmp = 0, *pOldStk = pCrsrStk;
// der Nachfolger wird der Aktuelle
if( pCrsrStk->GetNext() != pCrsrStk )
{
pTmp = dynamic_cast<SwShellCrsr*>(pCrsrStk->GetNext());
}
if( bOldCrsr ) // loesche vom Stack
delete pCrsrStk; //
pCrsrStk = pTmp; // neu zuweisen
if( !bOldCrsr )
{
SwCrsrSaveState aSaveState( *pCurCrsr );
// wurde die sichtbare SSelection nicht veraendert
if( pOldStk->GetPtPos() == pCurCrsr->GetPtPos() ||
pOldStk->GetPtPos() == pCurCrsr->GetMkPos() )
{
// "Selektions-Rechtecke" verschieben
pCurCrsr->Insert( pOldStk, 0 );
pOldStk->Remove( 0, pOldStk->Count() );
}
if( pOldStk->HasMark() )
{
pCurCrsr->SetMark();
*pCurCrsr->GetMark() = *pOldStk->GetMark();
pCurCrsr->GetMkPos() = pOldStk->GetMkPos();
}
else
// keine Selection also alte aufheben und auf die alte Pos setzen
pCurCrsr->DeleteMark();
*pCurCrsr->GetPoint() = *pOldStk->GetPoint();
pCurCrsr->GetPtPos() = pOldStk->GetPtPos();
delete pOldStk;
if( !pCurCrsr->IsInProtectTable( sal_True ) &&
!pCurCrsr->IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
nsSwCursorSelOverFlags::SELOVER_CHANGEPOS ) )
UpdateCrsr(); // akt. Cursor Updaten
}
return sal_True;
}
/*
* Verbinde zwei Cursor miteinander.
* Loesche vom Stack den obersten und setzen dessen GetMark im Aktuellen.
*/
void SwCrsrShell::Combine()
{
// noch weitere vorhanden ?
if( 0 == pCrsrStk )
return;
SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen
SwCrsrSaveState aSaveState( *pCurCrsr );
if( pCrsrStk->HasMark() ) // nur wenn GetMark gesetzt wurde
{
#ifndef DBG_UTIL
CheckNodesRange( pCrsrStk->GetMark()->nNode, pCurCrsr->GetPoint()->nNode, sal_True );
#else
if( !CheckNodesRange( pCrsrStk->GetMark()->nNode, pCurCrsr->GetPoint()->nNode, sal_True ))
ASSERT( !this, "StackCrsr & akt. Crsr nicht in gleicher Section." );
#endif
// kopiere das GetMark
if( !pCurCrsr->HasMark() )
pCurCrsr->SetMark();
*pCurCrsr->GetMark() = *pCrsrStk->GetMark();
pCurCrsr->GetMkPos() = pCrsrStk->GetMkPos();
}
SwShellCrsr * pTmp = 0;
if( pCrsrStk->GetNext() != pCrsrStk )
{
pTmp = dynamic_cast<SwShellCrsr*>(pCrsrStk->GetNext());
}
delete pCrsrStk;
pCrsrStk = pTmp;
if( !pCurCrsr->IsInProtectTable( sal_True ) &&
!pCurCrsr->IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
nsSwCursorSelOverFlags::SELOVER_CHANGEPOS ) )
UpdateCrsr(); // akt. Cursor Updaten
}
void SwCrsrShell::HideCrsrs()
{
if( !bHasFocus || bBasicHideCrsr )
return;
// ist Cursor sichtbar, dann verstecke den SV-Cursor
if( pVisCrsr->IsVisible() )
{
SET_CURR_SHELL( this );
pVisCrsr->Hide();
}
// hebe die Invertierung der SSelection auf
SwShellCrsr* pAktCrsr = pTblCrsr ? pTblCrsr : pCurCrsr;
pAktCrsr->Hide();
}
void SwCrsrShell::ShowCrsrs( sal_Bool bCrsrVis )
{
if( !bHasFocus || bAllProtect || bBasicHideCrsr )
return;
SET_CURR_SHELL( this );
SwShellCrsr* pAktCrsr = pTblCrsr ? pTblCrsr : pCurCrsr;
pAktCrsr->Show();
if( bSVCrsrVis && bCrsrVis ) // auch SV-Cursor wieder anzeigen
pVisCrsr->Show();
}
// Methoden zum Anzeigen bzw. Verstecken des sichtbaren Text-Cursors
void SwCrsrShell::ShowCrsr()
{
if( !bBasicHideCrsr )
{
bSVCrsrVis = sal_True;
pCurCrsr->SetShowTxtInputFldOverlay( true );
UpdateCrsr();
}
}
void SwCrsrShell::HideCrsr()
{
if( !bBasicHideCrsr )
{
bSVCrsrVis = sal_False;
// evt. die sel. Bereiche aufheben !!
SET_CURR_SHELL( this );
pCurCrsr->SetShowTxtInputFldOverlay( false );
pVisCrsr->Hide();
}
}
void SwCrsrShell::ShLooseFcs()
{
if( !bBasicHideCrsr )
HideCrsrs();
bHasFocus = sal_False;
}
void SwCrsrShell::ShGetFcs( sal_Bool bUpdate )
{
bHasFocus = sal_True;
if( !bBasicHideCrsr && VisArea().Width() )
{
UpdateCrsr( static_cast<sal_uInt16>( bUpdate ?
SwCrsrShell::CHKRANGE|SwCrsrShell::SCROLLWIN
: SwCrsrShell::CHKRANGE ) );
ShowCrsrs( bSVCrsrVis ? sal_True : sal_False );
}
}
// gebe den aktuellen Frame, in dem der Cursor steht, zurueck
SwCntntFrm *SwCrsrShell::GetCurrFrm( const sal_Bool bCalcFrm ) const
{
SET_CURR_SHELL( (ViewShell*)this );
SwCntntFrm *pRet = 0;
SwCntntNode *pNd = pCurCrsr->GetCntntNode();
if ( pNd )
{
if ( bCalcFrm )
{
const sal_uInt16* pST = &nStartAction;
++(*((sal_uInt16*)pST));
const Size aOldSz( GetDocSize() );
pRet = pNd->getLayoutFrm( GetLayout(), &pCurCrsr->GetPtPos(), pCurCrsr->GetPoint() );
--(*((sal_uInt16*)pST));
if( aOldSz != GetDocSize() )
((SwCrsrShell*)this)->SizeChgNotify();
}
else
pRet = pNd->getLayoutFrm( GetLayout(), &pCurCrsr->GetPtPos(), pCurCrsr->GetPoint(), sal_False);
}
return pRet;
}
// alle Attribut/Format-Aenderungen am akt. Node werden an den
// Link weitergeleitet.
void SwCrsrShell::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew )
{
const sal_uInt16 nWhich = pOld ?
pOld->Which() :
pNew ?
pNew->Which() :
sal::static_int_cast<sal_uInt16>(RES_MSG_BEGIN);
if( bCallChgLnk &&
( nWhich < RES_MSG_BEGIN || nWhich >= RES_MSG_END ||
nWhich == RES_FMT_CHG || nWhich == RES_UPDATE_ATTR ||
nWhich == RES_ATTRSET_CHG ))
// die Messages werden nicht weitergemeldet
//MA 07. Apr. 94 fix(6681): RES_UPDATE_ATTR wird implizit vom
//SwTxtNode::Insert(SwTxtHint*, sal_uInt16) abgesetzt; hier wird reagiert und
//vom Insert brauch nicht mehr die Keule RES_FMT_CHG versandt werden.
CallChgLnk();
if( aGrfArrivedLnk.IsSet() &&
( RES_GRAPHIC_ARRIVED == nWhich || RES_GRAPHIC_SWAPIN == nWhich ))
aGrfArrivedLnk.Call( this );
}
// Abfrage, ob der aktuelle Cursor eine Selektion aufspannt,
// also, ob GetMark gesetzt und SPoint und GetMark unterschiedlich sind.
sal_Bool SwCrsrShell::HasSelection() const
{
const SwPaM* pCrsr = getShellCrsr( true );
return( IsTableMode() || ( pCrsr->HasMark() &&
*pCrsr->GetPoint() != *pCrsr->GetMark())
? sal_True : sal_False );
}
void SwCrsrShell::CallChgLnk()
{
// innerhalb von Start-/End-Action kein Call, sondern nur merken,
// das sich etwas geaendert hat. Wird bei EndAction beachtet.
if( BasicActionPend() )
bChgCallFlag = sal_True; // das Change merken
else if( aChgLnk.IsSet() )
{
if( bCallChgLnk )
aChgLnk.Call( this );
bChgCallFlag = sal_False; // Flag zuruecksetzen
}
}
// returne den am akt.Cursor selektierten Text eines Nodes.
String SwCrsrShell::GetSelTxt() const
{
String aTxt;
if( pCurCrsr->GetPoint()->nNode.GetIndex() ==
pCurCrsr->GetMark()->nNode.GetIndex() )
{
SwTxtNode* pTxtNd = pCurCrsr->GetNode()->GetTxtNode();
if( pTxtNd )
{
xub_StrLen nStt = pCurCrsr->Start()->nContent.GetIndex();
aTxt = pTxtNd->GetExpandTxt( nStt,
pCurCrsr->End()->nContent.GetIndex() - nStt );
}
}
return aTxt;
}
// gebe nur den Text ab der akt. Cursor Position zurueck (bis zum NodeEnde)
String SwCrsrShell::GetText() const
{
String aTxt;
if( pCurCrsr->GetPoint()->nNode.GetIndex() ==
pCurCrsr->GetMark()->nNode.GetIndex() )
{
SwTxtNode* pTxtNd = pCurCrsr->GetNode()->GetTxtNode();
if( pTxtNd )
aTxt = pTxtNd->GetTxt().Copy(
pCurCrsr->GetPoint()->nContent.GetIndex() );
}
return aTxt;
}
// hole vom Start/Ende der akt. SSelection das nte Zeichen
sal_Unicode SwCrsrShell::GetChar( sal_Bool bEnd, long nOffset )
{
if( IsTableMode() ) // im TabelleMode nicht moeglich
return 0;
const SwPosition* pPos = !pCurCrsr->HasMark() ? pCurCrsr->GetPoint()
: bEnd ? pCurCrsr->End() : pCurCrsr->Start();
SwTxtNode* pTxtNd = pPos->nNode.GetNode().GetTxtNode();
if( !pTxtNd )
return 0;
xub_StrLen nPos = pPos->nContent.GetIndex();
const String& rStr = pTxtNd->GetTxt();
sal_Unicode cCh = 0;
if( ((nPos+nOffset) >= 0 ) && (nPos+nOffset) < rStr.Len() )
cCh = rStr.GetChar( static_cast<xub_StrLen>(nPos+nOffset) );
return cCh;
}
// erweiter die akt. SSelection am Anfang/Ende um n Zeichen
sal_Bool SwCrsrShell::ExtendSelection( sal_Bool bEnd, xub_StrLen nCount )
{
if( !pCurCrsr->HasMark() || IsTableMode() )
return sal_False; // keine Selektion
SwPosition* pPos = bEnd ? pCurCrsr->End() : pCurCrsr->Start();
SwTxtNode* pTxtNd = pPos->nNode.GetNode().GetTxtNode();
ASSERT( pTxtNd, "kein TextNode, wie soll erweitert werden?" );
xub_StrLen nPos = pPos->nContent.GetIndex();
if( bEnd )
{
if( ( nPos + nCount ) <= pTxtNd->GetTxt().Len() )
nPos = nPos + nCount;
else
return sal_False; // nicht mehr moeglich
}
else if( nPos >= nCount )
nPos = nPos - nCount;
else
return sal_False; // nicht mehr moeglich
SwCallLink aLk( *this ); // Crsr-Moves ueberwachen,
pPos->nContent = nPos;
UpdateCrsr();
return sal_True;
}
// setze nur den sichtbaren Cursor an die angegebene Dokument-Pos.
// returnt sal_False: wenn der SPoint vom Layout korrigiert wurde.
sal_Bool SwCrsrShell::SetVisCrsr( const Point &rPt )
{
SET_CURR_SHELL( this );
Point aPt( rPt );
SwPosition aPos( *pCurCrsr->GetPoint() );
SwCrsrMoveState aTmpState( MV_SETONLYTEXT );
aTmpState.bSetInReadOnly = IsReadOnlyAvailable();
aTmpState.bRealHeight = sal_True;
sal_Bool bRet = GetLayout()->GetCrsrOfst( &aPos, aPt /*, &aTmpState*/ );
SetInFrontOfLabel( sal_False ); // #i27615#
// nur in TextNodes anzeigen !!
SwTxtNode* pTxtNd = aPos.nNode.GetNode().GetTxtNode();
if( !pTxtNd )
return sal_False;
const SwSectionNode* pSectNd = pTxtNd->FindSectionNode();
if( pSectNd && (pSectNd->GetSection().IsHiddenFlag() ||
( !IsReadOnlyAvailable() &&
pSectNd->GetSection().IsProtectFlag())) )
return sal_False;
SwCntntFrm *pFrm = pTxtNd->getLayoutFrm( GetLayout(), &aPt, &aPos );
if ( Imp()->IsIdleAction() )
pFrm->PrepareCrsr();
SwRect aTmp( aCharRect );
pFrm->GetCharRect( aCharRect, aPos, &aTmpState );
// ALIGNRECT( aCharRect );
if( aTmp == aCharRect && // BUG 10137: bleibt der Cursor auf der
pVisCrsr->IsVisible() ) // Position nicht hidden & showen
return sal_True;
pVisCrsr->Hide(); // sichtbaren Cursor immer verstecken
if( IsScrollMDI( this, aCharRect ))
{
MakeVisible( aCharRect );
pCurCrsr->Show();
}
// Bug 29584: bei Rahmenselektion ist der Cursor versteckt, aber den
// D&D-Cursor will man trotzdem haben
// if( bSVCrsrVis )
{
if( aTmpState.bRealHeight )
aCrsrHeight = aTmpState.aRealHeight;
else
{
aCrsrHeight.X() = 0;
aCrsrHeight.Y() = aCharRect.Height();
}
pVisCrsr->SetDragCrsr( sal_True );
pVisCrsr->Show(); // wieder anzeigen
}
return bRet;
}
sal_Bool SwCrsrShell::IsOverReadOnlyPos( const Point& rPt ) const
{
Point aPt( rPt );
SwPaM aPam( *pCurCrsr->GetPoint() );
GetLayout()->GetCrsrOfst( aPam.GetPoint(), aPt );
return aPam.HasReadonlySel( GetViewOptions()->IsFormView() );
}
// returne die Anzahl der Cursor im Ring (Flag besagt ob man nur
// aufgepspannte haben will - sprich etwas selektiert ist (Basic))
sal_uInt16 SwCrsrShell::GetCrsrCnt( sal_Bool bAll ) const
{
Ring* pTmp = GetCrsr()->GetNext();
sal_uInt16 n = (bAll || ( pCurCrsr->HasMark() &&
*pCurCrsr->GetPoint() != *pCurCrsr->GetMark())) ? 1 : 0;
while( pTmp != pCurCrsr )
{
if( bAll || ( ((SwPaM*)pTmp)->HasMark() &&
*((SwPaM*)pTmp)->GetPoint() != *((SwPaM*)pTmp)->GetMark()))
++n;
pTmp = pTmp->GetNext();
}
return n;
}
sal_Bool SwCrsrShell::IsStartOfDoc() const
{
if( pCurCrsr->GetPoint()->nContent.GetIndex() )
return sal_False;
// Hinter EndOfIcons kommt die Content-Section (EndNd+StNd+CntntNd)
SwNodeIndex aIdx( GetDoc()->GetNodes().GetEndOfExtras(), 2 );
if( !aIdx.GetNode().IsCntntNode() )
GetDoc()->GetNodes().GoNext( &aIdx );
return aIdx == pCurCrsr->GetPoint()->nNode;
}
sal_Bool SwCrsrShell::IsEndOfDoc() const
{
SwNodeIndex aIdx( GetDoc()->GetNodes().GetEndOfContent(), -1 );
SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
if( !pCNd )
pCNd = GetDoc()->GetNodes().GoPrevious( &aIdx );
return aIdx == pCurCrsr->GetPoint()->nNode &&
pCNd->Len() == pCurCrsr->GetPoint()->nContent.GetIndex();
}
// loesche alle erzeugten Crsr, setze den Tabellen-Crsr und den letzten
// Cursor auf seinen TextNode (oder StartNode?).
// Beim naechsten ::GetCrsr werden sie wieder alle erzeugt
// Wird fuers Drag&Drop / ClipBorad-Paste in Tabellen benoetigt.
sal_Bool SwCrsrShell::ParkTblCrsr()
{
if( !pTblCrsr )
return sal_False;
pTblCrsr->ParkCrsr();
while( pCurCrsr->GetNext() != pCurCrsr )
delete pCurCrsr->GetNext();
// vom Cursor !immer! SPoint und Mark umsetzen
pCurCrsr->SetMark();
*pCurCrsr->GetMark() = *pCurCrsr->GetPoint() = *pTblCrsr->GetPoint();
pCurCrsr->DeleteMark();
return sal_True;
}
/***********************************************************************
#* Class : SwCrsrShell
#* Methode : ParkCrsr
#* Beschreibung: Vernichtet Selektionen und zus. Crsr aller Shell der
#* verbleibende Crsr der Shell wird geparkt.
#* Datum : MA 05. Nov. 92
#* Update : JP 19.09.97
#***********************************************************************/
void SwCrsrShell::_ParkPams( SwPaM* pDelRg, SwShellCrsr** ppDelRing )
{
const SwPosition *pStt = pDelRg->Start(),
*pEnd = pDelRg->GetPoint() == pStt ? pDelRg->GetMark() : pDelRg->GetPoint();
SwPaM *pTmpDel = 0, *pTmp = *ppDelRing;
// durchsuche den gesamten Ring
sal_Bool bGoNext;
do {
const SwPosition *pTmpStt = pTmp->Start(),
*pTmpEnd = pTmp->GetPoint() == pTmpStt ?
pTmp->GetMark() : pTmp->GetPoint();
/*
* liegt ein SPoint oder GetMark innerhalb vom Crsr-Bereich
* muss der alte Bereich aufgehoben werden.
* Beim Vergleich ist darauf zu achten, das End() nicht mehr zum
* Bereich gehoert !
*/
if( *pStt <= *pTmpStt )
{
if( *pEnd > *pTmpStt ||
( *pEnd == *pTmpStt && *pEnd == *pTmpEnd ))
pTmpDel = pTmp;
}
else
if( *pStt < *pTmpEnd )
pTmpDel = pTmp;
bGoNext = sal_True;
if( pTmpDel ) // ist der Pam im Bereich ?? loesche ihn
{
sal_Bool bDelete = sal_True;
if( *ppDelRing == pTmpDel )
{
if( *ppDelRing == pCurCrsr )
{
if( sal_True == ( bDelete = GoNextCrsr() ))
{
bGoNext = sal_False;
pTmp = (SwPaM*)pTmp->GetNext();
}
}
else
bDelete = sal_False; // StackCrsr nie loeschen !!
}
if( bDelete )
delete pTmpDel; // hebe alten Bereich auf
else
{
pTmpDel->GetPoint()->nContent.Assign( 0, 0 );
pTmpDel->GetPoint()->nNode = 0;
pTmpDel->SetMark();
pTmpDel->DeleteMark();
}
pTmpDel = 0;
}
else if( !pTmp->HasMark() ) // sorge auf jedenfall dafuer, das
{ // nicht benutzte Indizies beachtet werden!
pTmp->SetMark(); // SPoint liegt nicht im Bereich,
pTmp->DeleteMark(); // aber vielleicht GetMark, also setzen
}
if( bGoNext )
pTmp = (SwPaM*)pTmp->GetNext();
} while( !bGoNext || *ppDelRing != pTmp );
}
void SwCrsrShell::ParkCrsr( const SwNodeIndex &rIdx )
{
SwNode *pNode = &rIdx.GetNode();
// erzeuge einen neuen Pam
SwPaM * pNew = new SwPaM( *GetCrsr()->GetPoint() );
if( pNode->GetStartNode() )
{
if( ( pNode = pNode->StartOfSectionNode())->IsTableNode() )
{
// der angegebene Node steht in einer Tabelle, also Parke
// den Crsr auf dem Tabellen-Node (ausserhalb der Tabelle)
pNew->GetPoint()->nNode = *pNode->StartOfSectionNode();
}
else // also auf dem StartNode selbst.
// Dann immer ueber seinen EndNode den StartNode erfragen !!!
// (StartOfSection vom StartNode ist der Parent !)
pNew->GetPoint()->nNode = *pNode->EndOfSectionNode()->StartOfSectionNode();
}
else
pNew->GetPoint()->nNode = *pNode->StartOfSectionNode();
pNew->SetMark();
pNew->GetPoint()->nNode = *pNode->EndOfSectionNode();
//Alle Shells wollen etwas davon haben.
ViewShell *pTmp = this;
do {
if( pTmp->IsA( TYPE( SwCrsrShell )))
{
SwCrsrShell* pSh = (SwCrsrShell*)pTmp;
if( pSh->pCrsrStk )
pSh->_ParkPams( pNew, &pSh->pCrsrStk );
pSh->_ParkPams( pNew, &pSh->pCurCrsr );
if( pSh->pTblCrsr )
{
// setze den Tabellen Cursor immer auf 0, den aktuellen
// immer auf den Anfang der Tabelle
SwPaM* pTCrsr = pSh->GetTblCrs();
SwNode* pTblNd = pTCrsr->GetPoint()->nNode.GetNode().FindTableNode();
if ( pTblNd )
{
pTCrsr->GetPoint()->nContent.Assign( 0, 0 );
pTCrsr->GetPoint()->nNode = 0;
pTCrsr->SetMark();
pTCrsr->DeleteMark();
pSh->pCurCrsr->GetPoint()->nNode = *pTblNd;
}
}
}
} while ( this != (pTmp = (ViewShell*)pTmp->GetNext() ));
delete pNew;
}
//=========================================================================
/*
* der Copy-Constructor
* Cursor-Position kopieren, in den Ring eingetragen.
* Alle Ansichten eines Dokumentes stehen im Ring der Shells.
*/
SwCrsrShell::SwCrsrShell( SwCrsrShell& rShell, Window *pInitWin )
: ViewShell( rShell, pInitWin ),
SwModify( 0 ), pCrsrStk( 0 ), pBlockCrsr( 0 ), pTblCrsr( 0 ),
pBoxIdx( 0 ), pBoxPtr( 0 ), nCrsrMove( 0 ), nBasicActionCnt( 0 ),
eMvState( MV_NONE ),
// --> OD 2008-04-02 #refactorlists#
sMarkedListId(),
nMarkedListLevel( 0 )
// <--
{
SET_CURR_SHELL( this );
// Nur die Position vom aktuellen Cursor aus der Copy-Shell uebernehmen
pCurCrsr = new SwShellCrsr( *this, *(rShell.pCurCrsr->GetPoint()) );
pCurCrsr->GetCntntNode()->Add( this );
bAllProtect = bVisPortChgd = bChgCallFlag = bInCMvVisportChgd =
bGCAttr = bIgnoreReadonly = bSelTblCells = bBasicHideCrsr =
bOverwriteCrsr = sal_False;
bCallChgLnk = bHasFocus = bSVCrsrVis = bAutoUpdateCells = sal_True;
bSetCrsrInReadOnly = sal_True;
pVisCrsr = new SwVisCrsr( this );
// UpdateCrsr( 0 );
// OD 11.02.2003 #100556#
mbMacroExecAllowed = rShell.IsMacroExecAllowed();
oldColFrm = NULL;
}
/*
* der normale Constructor
*/
SwCrsrShell::SwCrsrShell( SwDoc& rDoc, Window *pInitWin,
const SwViewOption *pInitOpt )
: ViewShell( rDoc, pInitWin, pInitOpt ),
SwModify( 0 ), pCrsrStk( 0 ), pBlockCrsr( 0 ), pTblCrsr( 0 ),
pBoxIdx( 0 ), pBoxPtr( 0 ), nCrsrMove( 0 ), nBasicActionCnt( 0 ),
eMvState( MV_NONE ), // state for crsr-travelling - GetCrsrOfst
// --> OD 2008-04-02 #refactorlists#
sMarkedListId(),
nMarkedListLevel( 0 )
// <--
{
SET_CURR_SHELL( this );
/*
* Erzeugen des initialen Cursors, wird auf die erste
* Inhaltsposition gesetzt
*/
SwNodes& rNds = rDoc.GetNodes();
SwNodeIndex aNodeIdx( *rNds.GetEndOfContent().StartOfSectionNode() );
SwCntntNode* pCNd = rNds.GoNext( &aNodeIdx ); // gehe zum 1. ContentNode
pCurCrsr = new SwShellCrsr( *this, SwPosition( aNodeIdx, SwIndex( pCNd, 0 )));
// melde die Shell beim akt. Node als abhaengig an, dadurch koennen alle
// Attribut-Aenderungen ueber den Link weiter gemeldet werden.
pCNd->Add( this );
bAllProtect = bVisPortChgd = bChgCallFlag = bInCMvVisportChgd =
bGCAttr = bIgnoreReadonly = bSelTblCells = bBasicHideCrsr =
bOverwriteCrsr = sal_False;
bCallChgLnk = bHasFocus = bSVCrsrVis = bAutoUpdateCells = sal_True;
bSetCrsrInReadOnly = sal_True;
pVisCrsr = new SwVisCrsr( this );
// UpdateCrsr( 0 );
// OD 11.02.2003 #100556#
mbMacroExecAllowed = true;
}
SwCrsrShell::~SwCrsrShell()
{
// wenn es nicht die letzte View so sollte zu mindest das
// Feld noch geupdatet werden.
if( GetNext() != this )
CheckTblBoxCntnt( pCurCrsr->GetPoint() );
else
ClearTblBoxCntnt();
delete pVisCrsr;
delete pBlockCrsr;
delete pTblCrsr;
/*
* Freigabe der Cursor
*/
while(pCurCrsr->GetNext() != pCurCrsr)
delete pCurCrsr->GetNext();
delete pCurCrsr;
// Stack freigeben
if( pCrsrStk )
{
while( pCrsrStk->GetNext() != pCrsrStk )
delete pCrsrStk->GetNext();
delete pCrsrStk;
}
// JP 27.07.98: Bug 54025 - ggfs. den HTML-Parser, der als Client in
// der CursorShell haengt keine Chance geben, sich an den
// TextNode zu haengen.
if( GetRegisteredIn() )
GetRegisteredInNonConst()->Remove( this );
}
SwShellCrsr* SwCrsrShell::getShellCrsr( bool bBlock )
{
if( pTblCrsr )
return pTblCrsr;
if( pBlockCrsr && bBlock )
return &pBlockCrsr->getShellCrsr();
return pCurCrsr;
}
//Sollte fuer das Clipboard der WaitPtr geschaltet werden?
//Warten bei TableMode, Mehrfachselektion und mehr als x Selektieren Absaetzen.
sal_Bool SwCrsrShell::ShouldWait() const
{
if ( IsTableMode() || GetCrsrCnt() > 1 )
return sal_True;
if( HasDrawView() && GetDrawView()->GetMarkedObjectList().GetMarkCount() )
return sal_True;
SwPaM* pPam = GetCrsr();
return pPam->Start()->nNode.GetIndex() + 10 <
pPam->End()->nNode.GetIndex();
}
sal_uInt16 SwCrsrShell::UpdateTblSelBoxes()
{
if( pTblCrsr && ( pTblCrsr->IsChgd() || !pTblCrsr->GetBoxesCount() ))
GetLayout()->MakeTblCrsrs( *pTblCrsr );
return pTblCrsr ? pTblCrsr->GetBoxesCount() : 0;
}
// zeige das akt. selektierte "Object" an
void SwCrsrShell::MakeSelVisible()
{
ASSERT( bHasFocus, "kein Focus aber Cursor sichtbar machen?" );
if( aCrsrHeight.Y() < aCharRect.Height() && aCharRect.Height() > VisArea().Height() )
{
SwRect aTmp( aCharRect );
long nDiff = aCharRect.Height() - VisArea().Height();
if( nDiff < aCrsrHeight.X() )
aTmp.Top( nDiff + aCharRect.Top() );
else
{
aTmp.Top( aCrsrHeight.X() + aCharRect.Top() );
aTmp.Height( aCrsrHeight.Y() );
}
if( !aTmp.HasArea() )
{
aTmp.SSize().Height() += 1;
aTmp.SSize().Width() += 1;
}
MakeVisible( aTmp );
}
else
{
if( aCharRect.HasArea() )
MakeVisible( aCharRect );
else
{
SwRect aTmp( aCharRect );
aTmp.SSize().Height() += 1; aTmp.SSize().Width() += 1;
MakeVisible( aTmp );
}
}
}
// suche eine gueltige ContentPosition (nicht geschuetzt/nicht versteckt)
sal_Bool SwCrsrShell::FindValidCntntNode( sal_Bool bOnlyText )
{
if( pTblCrsr ) // was soll ich jetzt machen ??
{
ASSERT( !this, "TabellenSelection nicht aufgehoben!" );
return sal_False;
}
//JP 28.10.97: Bug 45129 - im UI-ReadOnly ist alles erlaubt
if( !bAllProtect && GetDoc()->GetDocShell() &&
GetDoc()->GetDocShell()->IsReadOnlyUI() )
return sal_True;
// dann raus da!
if( pCurCrsr->HasMark() )
ClearMark();
// als erstes mal auf Rahmen abpruefen
SwNodeIndex& rNdIdx = pCurCrsr->GetPoint()->nNode;
sal_uLong nNdIdx = rNdIdx.GetIndex(); // sichern
SwNodes& rNds = pDoc->GetNodes();
SwCntntNode* pCNd = rNdIdx.GetNode().GetCntntNode();
const SwCntntFrm * pFrm;
if( pCNd && 0 != (pFrm = pCNd->getLayoutFrm( GetLayout(),0,pCurCrsr->GetPoint(),sal_False)) &&
!IsReadOnlyAvailable() && pFrm->IsProtected() &&
nNdIdx < rNds.GetEndOfExtras().GetIndex() )
{
// geschuetzter Rahmen ueberspringen
SwPaM aPam( *pCurCrsr->GetPoint() );
aPam.SetMark();
aPam.GetMark()->nNode = rNds.GetEndOfContent();
aPam.GetPoint()->nNode = *pCNd->EndOfSectionNode();
sal_Bool bFirst = sal_False;
if( 0 == (pCNd = ::GetNode( aPam, bFirst, fnMoveForward, sal_False )))
{
aPam.GetMark()->nNode = *rNds.GetEndOfPostIts().StartOfSectionNode();
pCNd = ::GetNode( aPam, bFirst, fnMoveBackward, sal_False );
}
if( !pCNd ) // sollte nie passieren !!!
{
rNdIdx = nNdIdx; // alten Node zurueck
return sal_False;
}
*pCurCrsr->GetPoint() = *aPam.GetPoint();
}
else if( bOnlyText && pCNd && pCNd->IsNoTxtNode() )
{
// dann auf den Anfang vom Doc stellen
rNdIdx = pDoc->GetNodes().GetEndOfExtras();
pCurCrsr->GetPoint()->nContent.Assign( pDoc->GetNodes().GoNext(
&rNdIdx ), 0 );
nNdIdx = rNdIdx.GetIndex();
}
sal_Bool bOk = sal_True;
// #i9059# cursor may not stand in protected cells
// (unless cursor in protected areas is OK.)
const SwTableNode* pTableNode = rNdIdx.GetNode().FindTableNode();
if( !IsReadOnlyAvailable() &&
pTableNode != NULL && rNdIdx.GetNode().IsProtect() )
{
// we're in a table, and we're in a protected area, so we're
// probably in a protected cell.
// move forward into non-protected area.
SwPaM aPam( rNdIdx.GetNode(), 0 );
while( aPam.GetNode()->IsProtect() &&
aPam.Move( fnMoveForward, fnGoCntnt ) )
; // nothing to do in the loop; the aPam.Move does the moving!
// didn't work? then go backwards!
if( aPam.GetNode()->IsProtect() )
{
SwPaM aTmpPaM( rNdIdx.GetNode(), 0 );
aPam = aTmpPaM;
while( aPam.GetNode()->IsProtect() &&
aPam.Move( fnMoveBackward, fnGoCntnt ) )
; // nothing to do in the loop; the aPam.Move does the moving!
}
// if we're successful, set the new position
if( ! aPam.GetNode()->IsProtect() )
{
*pCurCrsr->GetPoint() = *aPam.GetPoint();
}
}
// in einem geschuetzten Bereich
const SwSectionNode* pSectNd = rNdIdx.GetNode().FindSectionNode();
if( pSectNd && ( pSectNd->GetSection().IsHiddenFlag() ||
( !IsReadOnlyAvailable() &&
pSectNd->GetSection().IsProtectFlag() )) )
{
typedef SwCntntNode* (SwNodes:: *FNGoSection)( SwNodeIndex *, int, int ) const;
FNGoSection funcGoSection = &SwNodes::GoNextSection;
bOk = sal_False;
for( int nLoopCnt = 0; !bOk && nLoopCnt < 2; ++nLoopCnt )
{
sal_Bool bWeiter;
do {
bWeiter = sal_False;
while( 0 != ( pCNd = (rNds.*funcGoSection)( &rNdIdx,
sal_True, !IsReadOnlyAvailable() )) )
{
// in eine Tabelle verschoben -> pruefe ob die
// vielleicht geschuetzt ist
if( pCNd->FindTableNode() )
{
SwCallLink aTmp( *this );
SwCrsrSaveState aSaveState( *pCurCrsr );
aTmp.nNdTyp = 0; // im DTOR nichts machen!
if( !pCurCrsr->IsInProtectTable( sal_True, sal_True ) )
{
const SwSectionNode* pSNd = pCNd->FindSectionNode();
if( !pSNd || !pSNd->GetSection().IsHiddenFlag()
|| (!IsReadOnlyAvailable() &&
pSNd->GetSection().IsProtectFlag() ))
{
bOk = sal_True;
break; // eine nicht geschuetzte Zelle gef.
}
continue; // dann weiter suchen
}
}
else
{
bOk = sal_True;
break; // eine nicht geschuetzte Zelle gef.
}
}
if( bOk && rNdIdx.GetIndex() < rNds.GetEndOfExtras().GetIndex() )
{
// Teste mal auf Fly - kann auch noch geschuetzt sein!!
if( 0 == (pFrm = pCNd->getLayoutFrm( GetLayout(),0,0,sal_False)) ||
( !IsReadOnlyAvailable() && pFrm->IsProtected() ) ||
( bOnlyText && pCNd->IsNoTxtNode() ) )
{
// dann weiter suchen!
bOk = sal_False;
bWeiter = sal_True;
}
}
} while( bWeiter );
if( !bOk )
{
if( !nLoopCnt )
funcGoSection = &SwNodes::GoPrevSection;
rNdIdx = nNdIdx;
}
}
}
if( bOk )
{
pCNd = rNdIdx.GetNode().GetCntntNode();
// sal_uInt16 nCntnt = Min( pCNd->Len(), pCurCrsr->GetPoint()->nContent.GetIndex() );
xub_StrLen nCntnt = rNdIdx.GetIndex() < nNdIdx ? pCNd->Len() : 0;
pCurCrsr->GetPoint()->nContent.Assign( pCNd, nCntnt );
}
else
{
pCNd = rNdIdx.GetNode().GetCntntNode();
// falls Cursor im versteckten Bereich ist, auf jedenfall schon mal
// verschieben!!
if( !pCNd || !pCNd->getLayoutFrm( GetLayout(),0,0,sal_False) )
{
SwCrsrMoveState aTmpState( MV_NONE );
aTmpState.bSetInReadOnly = IsReadOnlyAvailable();
GetLayout()->GetCrsrOfst( pCurCrsr->GetPoint(), pCurCrsr->GetPtPos(),
&aTmpState );
}
}
return bOk;
}
sal_Bool SwCrsrShell::IsCrsrReadonly() const
{
if ( GetViewOptions()->IsReadonly() ||
GetViewOptions()->IsFormView() ) // Formular view
{
SwFrm *pFrm = GetCurrFrm( sal_False );
const SwFlyFrm* pFly;
const SwSection* pSection;
if( pFrm && pFrm->IsInFly() &&
(pFly = pFrm->FindFlyFrm())->GetFmt()->GetEditInReadonly().GetValue() &&
pFly->Lower() &&
!pFly->Lower()->IsNoTxtFrm() &&
!GetDrawView()->GetMarkedObjectList().GetMarkCount() )
{
return sal_False;
}
// edit in readonly sections
else if ( pFrm && pFrm->IsInSct() &&
0 != ( pSection = pFrm->FindSctFrm()->GetSection() ) &&
pSection->IsEditInReadonlyFlag() )
{
return sal_False;
}
else if ( !IsMultiSelection() && CrsrInsideInputFld() )
{
return sal_False;
}
return sal_True;
}
return sal_False;
}
// darf der Cursor in ReadOnlyBereiche?
void SwCrsrShell::SetReadOnlyAvailable( sal_Bool bFlag )
{
// im GlobalDoc darf NIE umgeschaltet werden
if( (!GetDoc()->GetDocShell() ||
!GetDoc()->GetDocShell()->IsA( SwGlobalDocShell::StaticType() )) &&
bFlag != bSetCrsrInReadOnly )
{
// wenn das Flag ausgeschaltet wird, dann muessen erstmal alle
// Selektionen aufgehoben werden. Denn sonst wird sich darauf
// verlassen, das nichts geschuetztes selektiert ist!
if( !bFlag )
{
ClearMark();
}
bSetCrsrInReadOnly = bFlag;
UpdateCrsr();
}
}
sal_Bool SwCrsrShell::HasReadonlySel() const
{
sal_Bool bRet = sal_False;
if ( IsReadOnlyAvailable() || GetViewOptions()->IsFormView() )
{
if ( pTblCrsr != NULL )
{
bRet = pTblCrsr->HasReadOnlyBoxSel()
|| pTblCrsr->HasReadonlySel( GetViewOptions()->IsFormView() );
}
else
{
const SwPaM* pCrsr = pCurCrsr;
do
{
if ( pCrsr->HasReadonlySel( GetViewOptions()->IsFormView() ) )
{
bRet = sal_True;
}
pCrsr = (SwPaM*)pCrsr->GetNext();
} while ( !bRet && pCrsr != pCurCrsr );
}
}
return bRet;
}
sal_Bool SwCrsrShell::IsSelFullPara() const
{
sal_Bool bRet = sal_False;
if( pCurCrsr->GetPoint()->nNode.GetIndex() ==
pCurCrsr->GetMark()->nNode.GetIndex() && pCurCrsr == pCurCrsr->GetNext() )
{
xub_StrLen nStt = pCurCrsr->GetPoint()->nContent.GetIndex(),
nEnd = pCurCrsr->GetMark()->nContent.GetIndex();
if( nStt > nEnd )
{
xub_StrLen nTmp = nStt;
nStt = nEnd;
nEnd = nTmp;
}
const SwCntntNode* pCNd = pCurCrsr->GetCntntNode();
bRet = pCNd && !nStt && nEnd == pCNd->Len();
}
return bRet;
}
short SwCrsrShell::GetTextDirection( const Point* pPt ) const
{
SwPosition aPos( *pCurCrsr->GetPoint() );
Point aPt( pPt ? *pPt : pCurCrsr->GetPtPos() );
if( pPt )
{
SwCrsrMoveState aTmpState( MV_NONE );
aTmpState.bSetInReadOnly = IsReadOnlyAvailable();
GetLayout()->GetCrsrOfst( &aPos, aPt, &aTmpState );
}
return pDoc->GetTextDirection( aPos, &aPt );
}
sal_Bool SwCrsrShell::IsInVerticalText( const Point* pPt ) const
{
const short nDir = GetTextDirection( pPt );
return FRMDIR_VERT_TOP_RIGHT == nDir || FRMDIR_VERT_TOP_LEFT == nDir;
}
sal_Bool SwCrsrShell::IsInRightToLeftText( const Point* pPt ) const
{
const short nDir = GetTextDirection( pPt );
// GetTextDirection uses FRMDIR_VERT_TOP_LEFT to indicate RTL in
// vertical environment
return FRMDIR_VERT_TOP_LEFT == nDir || FRMDIR_HORI_RIGHT_TOP == nDir;
}
//
// If the current cursor position is inside a hidden range, the hidden range
// is selected:
//
bool SwCrsrShell::SelectHiddenRange()
{
bool bRet = false;
if ( !GetViewOptions()->IsShowHiddenChar() && !pCurCrsr->HasMark() )
{
SwPosition& rPt = *(SwPosition*)pCurCrsr->GetPoint();
const SwTxtNode* pNode = rPt.nNode.GetNode().GetTxtNode();
if ( pNode )
{
const xub_StrLen nPos = rPt.nContent.GetIndex();
// check if nPos is in hidden range
xub_StrLen nHiddenStart;
xub_StrLen nHiddenEnd;
SwScriptInfo::GetBoundsOfHiddenRange( *pNode, nPos, nHiddenStart, nHiddenEnd );
if ( STRING_LEN != nHiddenStart )
{
// make selection:
pCurCrsr->SetMark();
pCurCrsr->GetMark()->nContent = nHiddenEnd;
bRet = true;
}
}
}
return bRet;
}
/* */
// die Suchfunktionen
sal_uLong SwCrsrShell::Find( const SearchOptions& rSearchOpt, sal_Bool bSearchInNotes,
SwDocPositions eStart, SwDocPositions eEnde,
sal_Bool& bCancel,
FindRanges eRng, int bReplace )
{
if( pTblCrsr )
GetCrsr();
delete pTblCrsr, pTblCrsr = 0;
SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen
sal_uLong nRet = pCurCrsr->Find( rSearchOpt, bSearchInNotes, eStart, eEnde, bCancel, eRng, bReplace );
if( nRet || bCancel )
UpdateCrsr();
return nRet;
}
sal_uLong SwCrsrShell::Find( const SwTxtFmtColl& rFmtColl,
SwDocPositions eStart, SwDocPositions eEnde,
sal_Bool& bCancel,
FindRanges eRng, const SwTxtFmtColl* pReplFmt )
{
if( pTblCrsr )
GetCrsr();
delete pTblCrsr, pTblCrsr = 0;
SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen
sal_uLong nRet = pCurCrsr->Find( rFmtColl, eStart, eEnde, bCancel, eRng, pReplFmt );
if( nRet )
UpdateCrsr();
return nRet;
}
sal_uLong SwCrsrShell::Find( const SfxItemSet& rSet, sal_Bool bNoCollections,
SwDocPositions eStart, SwDocPositions eEnde,
sal_Bool& bCancel,
FindRanges eRng, const SearchOptions* pSearchOpt,
const SfxItemSet* rReplSet )
{
if( pTblCrsr )
GetCrsr();
delete pTblCrsr, pTblCrsr = 0;
SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen
sal_uLong nRet = pCurCrsr->Find( rSet, bNoCollections, eStart, eEnde, bCancel,
eRng, pSearchOpt, rReplSet );
if( nRet )
UpdateCrsr();
return nRet;
}
void SwCrsrShell::SetSelection( const SwPaM& rCrsr )
{
StartAction();
SwPaM* pCrsr = GetCrsr();
*pCrsr->GetPoint() = *rCrsr.GetPoint();
if(rCrsr.HasMark())
{
pCrsr->SetMark();
*pCrsr->GetMark() = *rCrsr.GetMark();
}
if((SwPaM*)rCrsr.GetNext() != &rCrsr)
{
const SwPaM *_pStartCrsr = (SwPaM*)rCrsr.GetNext();
do
{
SwPaM* pCurrentCrsr = CreateCrsr();
*pCurrentCrsr->GetPoint() = *_pStartCrsr->GetPoint();
if(_pStartCrsr->HasMark())
{
pCurrentCrsr->SetMark();
*pCurrentCrsr->GetMark() = *_pStartCrsr->GetMark();
}
} while( (_pStartCrsr=(SwPaM *)_pStartCrsr->GetNext()) != &rCrsr );
}
EndAction();
}
void lcl_RemoveMark( SwPaM* pPam )
{
ASSERT( pPam->HasMark(), "Don't remove pPoint!" )
pPam->GetMark()->nContent.Assign( 0, 0 );
pPam->GetMark()->nNode = 0;
pPam->DeleteMark();
}
const SwStartNode* lcl_NodeContext( const SwNode& rNode )
{
const SwStartNode *pRet = rNode.StartOfSectionNode();
while( pRet->IsSectionNode() || pRet->IsTableNode() ||
pRet->GetStartNodeType() == SwTableBoxStartNode )
{
pRet = pRet->StartOfSectionNode();
}
return pRet;
}
/**
Checks if a position is valid. To be valid the position's node must
be a content node and the content must not be unregistered.
@param aPos the position to check.
*/
bool lcl_PosOk(const SwPosition & aPos)
{
return NULL != aPos.nNode.GetNode().GetCntntNode() &&
SwIndexReg::pEmptyIndexArray != aPos.nContent.GetIdxReg();
}
/**
Checks if a PaM is valid. For a PaM to be valid its point must be
valid. Additionaly if the PaM has a mark this has to be valid, too.
@param aPam the PaM to check
*/
static bool lcl_CrsrOk(SwPaM & aPam)
{
return lcl_PosOk(*aPam.GetPoint()) && (! aPam.HasMark()
|| lcl_PosOk(*aPam.GetMark()));
}
void SwCrsrShell::ClearUpCrsrs()
{
// start of the ring
SwPaM * pStartCrsr = GetCrsr();
// start loop with second entry of the ring
SwPaM * pCrsr = (SwPaM *) pStartCrsr->GetNext();
SwPaM * pTmpCrsr;
bool bChanged = false;
/*
For all entries in the ring except the start entry delete the
entry if it is invalid.
*/
while (pCrsr != pStartCrsr)
{
pTmpCrsr = (SwPaM *) pCrsr->GetNext();
if ( ! lcl_CrsrOk(*pCrsr))
{
delete pCrsr;
bChanged = true;
}
pCrsr = pTmpCrsr;
}
if( pStartCrsr->HasMark() && !lcl_PosOk( *pStartCrsr->GetMark() ) )
{
lcl_RemoveMark( pStartCrsr );
bChanged = true;
}
if( !lcl_PosOk( *pStartCrsr->GetPoint() ) )
{
SwNodes & aNodes = GetDoc()->GetNodes();
const SwNode* pStart = lcl_NodeContext( pStartCrsr->GetPoint()->nNode.GetNode() );
SwNodeIndex aIdx( pStartCrsr->GetPoint()->nNode );
SwNode * pNode = aNodes.GoPrevious(&aIdx);
if( pNode == NULL || lcl_NodeContext( *pNode ) != pStart )
aNodes.GoNext( &aIdx );
if( pNode == NULL || lcl_NodeContext( *pNode ) != pStart )
{
/*
If the start entry of the ring is invalid replace it with a
cursor pointing to the beginning of the first content node in
the document.
*/
aIdx = (*(aNodes.GetEndOfContent().StartOfSectionNode()));
pNode = aNodes.GoNext( &aIdx );
}
bool bFound = (pNode != NULL);
ASSERT(bFound, "no content node found");
if (bFound)
{
SwPaM aTmpPam(*pNode);
*pStartCrsr = aTmpPam;
}
bChanged = true;
}
/*
If at least one of the cursors in the ring have been deleted or
replaced, remove the table cursor.
*/
if (pTblCrsr != NULL && bChanged)
TblCrsrToCursor();
}
// #111827#
String SwCrsrShell::GetCrsrDescr() const
{
String aResult;
if (IsMultiSelection())
aResult += String(SW_RES(STR_MULTISEL));
else
aResult = GetDoc()->GetPaMDescr(*GetCrsr());
return aResult;
}
// SMARTTAGS
void lcl_FillRecognizerData( uno::Sequence< rtl::OUString >& rSmartTagTypes,
uno::Sequence< uno::Reference< container::XStringKeyMap > >& rStringKeyMaps,
const SwWrongList& rSmartTagList, xub_StrLen nCurrent )
{
// Insert smart tag information
std::vector< rtl::OUString > aSmartTagTypes;
std::vector< uno::Reference< container::XStringKeyMap > > aStringKeyMaps;
for ( sal_uInt16 i = 0; i < rSmartTagList.Count(); ++i )
{
const xub_StrLen nSTPos = rSmartTagList.Pos( i );
const xub_StrLen nSTLen = rSmartTagList.Len( i );
if ( nSTPos <= nCurrent && nCurrent < nSTPos + nSTLen )
{
const SwWrongArea* pArea = rSmartTagList.GetElement( i );
if ( pArea )
{
aSmartTagTypes.push_back( pArea->maType );
aStringKeyMaps.push_back( pArea->mxPropertyBag );
}
}
}
if ( aSmartTagTypes.size() )
{
rSmartTagTypes.realloc( aSmartTagTypes.size() );
rStringKeyMaps.realloc( aSmartTagTypes.size() );
std::vector< rtl::OUString >::const_iterator aTypesIter = aSmartTagTypes.begin();
sal_uInt16 i = 0;
for ( aTypesIter = aSmartTagTypes.begin(); aTypesIter != aSmartTagTypes.end(); ++aTypesIter )
rSmartTagTypes[i++] = *aTypesIter;
std::vector< uno::Reference< container::XStringKeyMap > >::const_iterator aMapsIter = aStringKeyMaps.begin();
i = 0;
for ( aMapsIter = aStringKeyMaps.begin(); aMapsIter != aStringKeyMaps.end(); ++aMapsIter )
rStringKeyMaps[i++] = *aMapsIter;
}
}
void lcl_FillTextRange( uno::Reference<text::XTextRange>& rRange,
SwTxtNode& rNode, xub_StrLen nBegin, xub_StrLen nLen )
{
// create SwPosition for nStartIndex
SwIndex aIndex( &rNode, nBegin );
SwPosition aStartPos( rNode, aIndex );
// create SwPosition for nEndIndex
SwPosition aEndPos( aStartPos );
aEndPos.nContent = nBegin + nLen;
const uno::Reference<text::XTextRange> xRange =
SwXTextRange::CreateXTextRange(*rNode.GetDoc(), aStartPos, &aEndPos);
rRange = xRange;
}
void SwCrsrShell::GetSmartTagTerm( uno::Sequence< rtl::OUString >& rSmartTagTypes,
uno::Sequence< uno::Reference< container::XStringKeyMap > >& rStringKeyMaps,
uno::Reference< text::XTextRange>& rRange ) const
{
if ( !SwSmartTagMgr::Get().IsSmartTagsEnabled() )
return;
SwPaM* pCrsr = GetCrsr();
SwPosition aPos( *pCrsr->GetPoint() );
SwTxtNode *pNode = aPos.nNode.GetNode().GetTxtNode();
if ( pNode && !pNode->IsInProtectSect() )
{
const SwWrongList *pSmartTagList = pNode->GetSmartTags();
if ( pSmartTagList )
{
xub_StrLen nCurrent = aPos.nContent.GetIndex();
xub_StrLen nBegin = nCurrent;
xub_StrLen nLen = 1;
if( pSmartTagList->InWrongWord( nBegin, nLen ) && !pNode->IsSymbol(nBegin) )
{
const sal_uInt16 nIndex = pSmartTagList->GetWrongPos( nBegin );
const SwWrongList* pSubList = pSmartTagList->SubList( nIndex );
if ( pSubList )
{
pSmartTagList = pSubList;
nCurrent = 0;
}
lcl_FillRecognizerData( rSmartTagTypes, rStringKeyMaps, *pSmartTagList, nCurrent );
lcl_FillTextRange( rRange, *pNode, nBegin, nLen );
}
}
}
}
// see also SwEditShell::GetCorrection( const Point* pPt, SwRect& rSelectRect )
void SwCrsrShell::GetSmartTagTerm( const Point& rPt, SwRect& rSelectRect,
uno::Sequence< rtl::OUString >& rSmartTagTypes,
uno::Sequence< uno::Reference< container::XStringKeyMap > >& rStringKeyMaps,
uno::Reference<text::XTextRange>& rRange )
{
if ( !SwSmartTagMgr::Get().IsSmartTagsEnabled() )
return;
SwPaM* pCrsr = GetCrsr();
SwPosition aPos( *pCrsr->GetPoint() );
Point aPt( rPt );
SwCrsrMoveState eTmpState( MV_SETONLYTEXT );
SwSpecialPos aSpecialPos;
eTmpState.pSpecialPos = &aSpecialPos;
SwTxtNode *pNode;
const SwWrongList *pSmartTagList;
if( GetLayout()->GetCrsrOfst( &aPos, aPt, &eTmpState ) &&
0 != (pNode = aPos.nNode.GetNode().GetTxtNode()) &&
0 != (pSmartTagList = pNode->GetSmartTags()) &&
!pNode->IsInProtectSect() )
{
xub_StrLen nCurrent = aPos.nContent.GetIndex();
xub_StrLen nBegin = nCurrent;
xub_StrLen nLen = 1;
if( pSmartTagList->InWrongWord( nBegin, nLen ) && !pNode->IsSymbol(nBegin) )
{
const sal_uInt16 nIndex = pSmartTagList->GetWrongPos( nBegin );
const SwWrongList* pSubList = pSmartTagList->SubList( nIndex );
if ( pSubList )
{
pSmartTagList = pSubList;
nCurrent = eTmpState.pSpecialPos->nCharOfst;
}
lcl_FillRecognizerData( rSmartTagTypes, rStringKeyMaps, *pSmartTagList, nCurrent );
lcl_FillTextRange( rRange, *pNode, nBegin, nLen );
// get smarttag word
String aText( pNode->GetTxt().Copy( nBegin, nLen ) );
//save the start and end positons of the line and the starting point
Push();
LeftMargin();
xub_StrLen nLineStart = GetCrsr()->GetPoint()->nContent.GetIndex();
RightMargin();
xub_StrLen nLineEnd = GetCrsr()->GetPoint()->nContent.GetIndex();
Pop(sal_False);
// make sure the selection build later from the
// data below does not include footnotes and other
// "in word" character to the left and right in order
// to preserve those. Therefore count those "in words"
// in order to modify the selection accordingly.
const sal_Unicode* pChar = aText.GetBuffer();
xub_StrLen nLeft = 0;
while (pChar && *pChar++ == CH_TXTATR_INWORD)
++nLeft;
pChar = aText.Len() ? aText.GetBuffer() + aText.Len() - 1 : 0;
xub_StrLen nRight = 0;
while (pChar && *pChar-- == CH_TXTATR_INWORD)
++nRight;
aPos.nContent = nBegin + nLeft;
pCrsr = GetCrsr();
*pCrsr->GetPoint() = aPos;
pCrsr->SetMark();
ExtendSelection( sal_True, nLen - nLeft - nRight );
//no determine the rectangle in the current line
xub_StrLen nWordStart = (nBegin + nLeft) < nLineStart ? nLineStart : nBegin + nLeft;
//take one less than the line end - otherwise the next line would be calculated
xub_StrLen nWordEnd = (nBegin + nLen - nLeft - nRight) > nLineEnd ? nLineEnd - 1: (nBegin + nLen - nLeft - nRight);
Push();
pCrsr->DeleteMark();
SwIndex& rContent = GetCrsr()->GetPoint()->nContent;
rContent = nWordStart;
SwRect aStartRect;
SwCrsrMoveState aState;
aState.bRealWidth = sal_True;
SwCntntNode* pCntntNode = pCrsr->GetCntntNode();
SwCntntFrm *pCntntFrame = pCntntNode->getLayoutFrm( GetLayout(), &rPt, pCrsr->GetPoint(), sal_False);
pCntntFrame->GetCharRect( aStartRect, *pCrsr->GetPoint(), &aState );
rContent = nWordEnd;
SwRect aEndRect;
pCntntFrame->GetCharRect( aEndRect, *pCrsr->GetPoint(),&aState );
rSelectRect = aStartRect.Union( aEndRect );
Pop(sal_False);
}
}
}