diff options
Diffstat (limited to 'sw/source/core/crsr')
25 files changed, 16077 insertions, 0 deletions
diff --git a/sw/source/core/crsr/BlockCursor.cxx b/sw/source/core/crsr/BlockCursor.cxx new file mode 100644 index 000000000000..589549c0ade8 --- /dev/null +++ b/sw/source/core/crsr/BlockCursor.cxx @@ -0,0 +1,106 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <IBlockCursor.hxx> +#include <viscrs.hxx> +#include "BlockCursor.hxx" + +/** The implementation of the block cursor interface + + It's simply an aggregation of a SwShellCrsr and a rectangle defined by + a start and an end point. +*/ +class SwBlockCursor : public IBlockCursor +{ + SwShellCrsr aCursor; + Point *pStartPt; + Point *pEndPt; +public: + SwBlockCursor( const SwCrsrShell& rCrsrSh, const SwPosition &rPos ) : + aCursor( rCrsrSh, rPos ), pStartPt(0), pEndPt(0) {} + virtual SwShellCrsr& getShellCrsr(); + virtual void setStartPoint( const Point &rPt ); + virtual void setEndPoint( const Point &rPt ); + virtual const Point* getStartPoint() const; + virtual const Point* getEndPoint() const; + virtual void clearPoints(); + virtual ~SwBlockCursor(); +}; + +SwBlockCursor::~SwBlockCursor() +{ + delete pStartPt; + delete pEndPt; +} + +SwShellCrsr& SwBlockCursor::getShellCrsr() +{ + return aCursor; +} + +void SwBlockCursor::setStartPoint( const Point &rPt ) +{ + if( pStartPt ) + *pStartPt = rPt; + else + pStartPt = new Point( rPt ); +} + +void SwBlockCursor::setEndPoint( const Point &rPt ) +{ + if( pEndPt ) + *pEndPt = rPt; + else + pEndPt = new Point( rPt ); +} + +const Point* SwBlockCursor::getStartPoint() const +{ + return pStartPt; +} + +const Point* SwBlockCursor::getEndPoint() const +{ + return pEndPt; +} + +void SwBlockCursor::clearPoints() +{ + delete pStartPt; + delete pEndPt; + pStartPt = 0; + pEndPt = 0; +} + +IBlockCursor *createBlockCursor( const SwCrsrShell& rCrsrSh, const SwPosition &rPos ) +{ + return new SwBlockCursor( rCrsrSh, rPos ); +} + diff --git a/sw/source/core/crsr/BlockCursor.hxx b/sw/source/core/crsr/BlockCursor.hxx new file mode 100644 index 000000000000..a3acb0bac187 --- /dev/null +++ b/sw/source/core/crsr/BlockCursor.hxx @@ -0,0 +1,36 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _BLOCKCURSOR_HXX +#define _BLOCKCURSOR_HXX + +class IBlockCursor; +class SwCrsrShell; +struct SwPosition; + +IBlockCursor *createBlockCursor(const SwCrsrShell& rCrsrSh, const SwPosition &rPos); + +#endif //_BLOCKURSOR_HXX diff --git a/sw/source/core/crsr/IBlockCursor.hxx b/sw/source/core/crsr/IBlockCursor.hxx new file mode 100644 index 000000000000..99b5cf3b734a --- /dev/null +++ b/sw/source/core/crsr/IBlockCursor.hxx @@ -0,0 +1,95 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef IBLOCKCURSOR_HXX_INCLUDED +#define IBLOCKCURSOR_HXX_INCLUDED + +class SwShellCrsr; +class Point; + + /** Access to the block cursor + + A block cursor contains a SwShellCrsr and additional information about + the rectangle which has been created by pressing the mouse button and + moving the mouse. + This interface provides access to the SwShellCrsr and to start and end + point of the mouse movement. + */ + class IBlockCursor + { + public: +/** Access to the shell cursor + + @return SwShellCrsr& which represents the start and end position of the + current block selection +*/ + virtual SwShellCrsr& getShellCrsr() = 0; + +/** Defines the starting vertex of the block selection + + @param rPt + rPt should contain the document coordinates of the mouse cursor when + the block selection starts (MouseButtonDown) +*/ + virtual void setStartPoint( const Point &rPt ) = 0; + +/** Defines the ending vertex of the block selection + + @param rPt + rPt should contain the document coordinates of the mouse cursor when + the block selection has started and the mouse has been moved (MouseMove) +*/ + virtual void setEndPoint( const Point &rPt ) = 0; + +/** The document coordinates where the block selection has been started + + @return 0, if no start point has been set +*/ + virtual const Point* getStartPoint() const = 0; + + +/** The document coordinates where the block selection ends (at the moment) + + @return 0, if no end point has been set +*/ + virtual const Point* getEndPoint() const = 0; + +/** Deletion of the mouse created rectangle + + When start and end points exist, the block cursor depends on this. If the + cursor is moved by cursor keys (e.g. up/down, home/end) the mouse rectangle + is obsolet and has to be deleted. +*/ + virtual void clearPoints() = 0; + +/** Destructor of the block curosr interface +*/ + virtual ~IBlockCursor() {}; + }; + +#endif // IBLOCKCURSOR_HXX_INCLUDED + diff --git a/sw/source/core/crsr/bookmrk.cxx b/sw/source/core/crsr/bookmrk.cxx new file mode 100644 index 000000000000..11060352b6c3 --- /dev/null +++ b/sw/source/core/crsr/bookmrk.cxx @@ -0,0 +1,346 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <bookmrk.hxx> +#include <IDocumentMarkAccess.hxx> +#include <doc.hxx> +#include <errhdl.hxx> +#include <ndtxt.hxx> +#include <pam.hxx> +#include <swserv.hxx> +#include <sfx2/linkmgr.hxx> +#include <swtypes.hxx> +#include <undobj.hxx> +#include <unobookmark.hxx> +#include <rtl/random.h> +#include <xmloff/odffields.hxx> + + +SV_IMPL_REF( SwServerObject ) + +using namespace ::sw::mark; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +namespace +{ + static void lcl_FixPosition(SwPosition& rPos) + { + // make sure the position has 1) the proper node, and 2) a proper index + SwTxtNode* pTxtNode = rPos.nNode.GetNode().GetTxtNode(); + if(pTxtNode == NULL && rPos.nContent.GetIndex() > 0) + { + OSL_TRACE( + "bookmrk.cxx::lcl_FixPosition" + " - illegal position: %d without proper TxtNode", rPos.nContent.GetIndex()); + rPos.nContent.Assign(NULL, 0); + } + else if(pTxtNode != NULL && rPos.nContent.GetIndex() > pTxtNode->Len()) + { + OSL_TRACE( + "bookmrk.cxx::lcl_FixPosition" + " - illegal position: %d is beyond %d", rPos.nContent.GetIndex(), pTxtNode->Len()); + rPos.nContent.Assign(pTxtNode, pTxtNode->Len()); + } + }; + + static void lcl_AssureFieldMarksSet(Fieldmark* const pField, + SwDoc* const io_pDoc, + const sal_Unicode aStartMark, + const sal_Unicode aEndMark) + { + SwPosition& rStart = pField->GetMarkStart(); + SwPosition& rEnd = pField->GetMarkEnd(); + SwTxtNode const * const pStartTxtNode = io_pDoc->GetNodes()[rStart.nNode]->GetTxtNode(); + SwTxtNode const * const pEndTxtNode = io_pDoc->GetNodes()[rEnd.nNode]->GetTxtNode(); + const sal_Unicode ch_start=pStartTxtNode->GetTxt().GetChar(rStart.nContent.GetIndex()); + const sal_Unicode ch_end=pEndTxtNode->GetTxt().GetChar(rEnd.nContent.GetIndex()-1); + SwPaM aStartPaM(rStart); + SwPaM aEndPaM(rEnd); + io_pDoc->StartUndo(UNDO_UI_REPLACE, NULL); + if(ch_start != aStartMark) + { + io_pDoc->InsertString(aStartPaM, aStartMark); + } + if ( aEndMark && ( ch_end != aEndMark ) && ( rStart != rEnd ) ) + { + io_pDoc->InsertString(aEndPaM, aEndMark); + } + io_pDoc->EndUndo(UNDO_UI_REPLACE, NULL); + }; +} + +namespace sw { namespace mark +{ + MarkBase::MarkBase(const SwPaM& aPaM, + const ::rtl::OUString& rName) + : SwModify(0) + , m_pPos1(new SwPosition(*(aPaM.GetPoint()))) + , m_aName(rName) + { + lcl_FixPosition(*m_pPos1); + if(aPaM.HasMark()) + { + MarkBase::SetOtherMarkPos(*(aPaM.GetMark())); + lcl_FixPosition(*m_pPos2); + } + } + + bool MarkBase::IsCoveringPosition(const SwPosition& rPos) const + { + return GetMarkStart() <= rPos && rPos <= GetMarkEnd(); + } + + void MarkBase::SetMarkPos(const SwPosition& rNewPos) + { + ::boost::scoped_ptr<SwPosition>(new SwPosition(rNewPos)).swap(m_pPos1); + //lcl_FixPosition(*m_pPos1); + } + + void MarkBase::SetOtherMarkPos(const SwPosition& rNewPos) + { + ::boost::scoped_ptr<SwPosition>(new SwPosition(rNewPos)).swap(m_pPos2); + //lcl_FixPosition(*m_pPos2); + } + + rtl::OUString MarkBase::ToString( ) const + { + rtl::OUStringBuffer buf; + buf.appendAscii( "Mark: ( Name, [ Node1, Index1 ] ): ( " ); + buf.append( m_aName ).appendAscii( ", [ " ); + buf.append( sal_Int32( GetMarkPos().nNode.GetIndex( ) ) ).appendAscii( ", " ); + buf.append( sal_Int32( GetMarkPos().nContent.GetIndex( ) ) ).appendAscii( " ] )" ); + + return buf.makeStringAndClear( ); + } + + MarkBase::~MarkBase() + { } + + ::rtl::OUString MarkBase::GenerateNewName(const ::rtl::OUString& rPrefix) + { + static rtlRandomPool aPool = rtl_random_createPool(); + static ::rtl::OUString sUniquePostfix; + static sal_Int32 nCount = SAL_MAX_INT32; + ::rtl::OUStringBuffer aResult(rPrefix); + if(nCount == SAL_MAX_INT32) + { + sal_Int32 nRandom; + ::rtl::OUStringBuffer sUniquePostfixBuffer; + rtl_random_getBytes(aPool, &nRandom, sizeof(nRandom)); + sUniquePostfix = ::rtl::OUStringBuffer(13).appendAscii("_").append(static_cast<sal_Int32>(abs(nRandom))).makeStringAndClear(); + nCount = 0; + } + // putting the counter in front of the random parts will speed up string comparisons + return aResult.append(nCount++).append(sUniquePostfix).makeStringAndClear(); + } + + + void MarkBase::Modify(SfxPoolItem *pOld, SfxPoolItem *pNew) + { + SwModify::Modify(pOld, pNew); + if (pOld && (RES_REMOVE_UNO_OBJECT == pOld->Which())) + { // invalidate cached uno object + SetXBookmark(uno::Reference<text::XTextContent>(0)); + } + } + + + NavigatorReminder::NavigatorReminder(const SwPaM& rPaM) + : MarkBase(rPaM, our_sNamePrefix) + { } + + const ::rtl::OUString NavigatorReminder::our_sNamePrefix = ::rtl::OUString::createFromAscii("__NavigatorReminder__"); + + UnoMark::UnoMark(const SwPaM& aPaM) + : MarkBase(aPaM, MarkBase::GenerateNewName(our_sNamePrefix)) + { } + + const ::rtl::OUString UnoMark::our_sNamePrefix = ::rtl::OUString::createFromAscii("__UnoMark__"); + + DdeBookmark::DdeBookmark(const SwPaM& aPaM) + : MarkBase(aPaM, MarkBase::GenerateNewName(our_sNamePrefix)) + , m_aRefObj(NULL) + { } + + void DdeBookmark::SetRefObject(SwServerObject* pObj) + { + m_aRefObj = pObj; + } + + const ::rtl::OUString DdeBookmark::our_sNamePrefix = ::rtl::OUString::createFromAscii("__DdeLink__"); + + void DdeBookmark::DeregisterFromDoc(SwDoc* const pDoc) + { + if(m_aRefObj.Is()) + pDoc->GetLinkManager().RemoveServer(m_aRefObj); + } + + DdeBookmark::~DdeBookmark() + { + if( m_aRefObj.Is() ) + { + if(m_aRefObj->HasDataLinks()) + { + ::sfx2::SvLinkSource* p = &m_aRefObj; + p->SendDataChanged(); + } + m_aRefObj->SetNoServer(); + } + } + + Bookmark::Bookmark(const SwPaM& aPaM, + const KeyCode& rCode, + const ::rtl::OUString& rName, + const ::rtl::OUString& rShortName) + : DdeBookmark(aPaM) + , ::sfx2::Metadatable() + , m_aCode(rCode) + , m_sShortName(rShortName) + { + m_aName = rName; + } + + void Bookmark::InitDoc(SwDoc* const io_pDoc) + { + if(io_pDoc->DoesUndo()) + { + io_pDoc->ClearRedo(); + io_pDoc->AppendUndo(new SwUndoInsBookmark(*this)); + } + io_pDoc->SetModified(); + } + + // ::sfx2::Metadatable + ::sfx2::IXmlIdRegistry& Bookmark::GetRegistry() + { + SwDoc *const pDoc( GetMarkPos().GetDoc() ); + OSL_ENSURE(pDoc, "Bookmark::MakeUnoObject: no doc?"); + return pDoc->GetXmlIdRegistry(); + } + + bool Bookmark::IsInClipboard() const + { + SwDoc *const pDoc( GetMarkPos().GetDoc() ); + OSL_ENSURE(pDoc, "Bookmark::IsInClipboard: no doc?"); + return pDoc->IsClipBoard(); + } + + bool Bookmark::IsInUndo() const + { + return false; + } + + bool Bookmark::IsInContent() const + { + SwDoc *const pDoc( GetMarkPos().GetDoc() ); + OSL_ENSURE(pDoc, "Bookmark::IsInContent: no doc?"); + return !pDoc->IsInHeaderFooter( SwNodeIndex(GetMarkPos().nNode) ); + } + + uno::Reference< rdf::XMetadatable > Bookmark::MakeUnoObject() + { + // create new SwXBookmark + SwDoc *const pDoc( GetMarkPos().GetDoc() ); + OSL_ENSURE(pDoc, "Bookmark::MakeUnoObject: no doc?"); + const uno::Reference< rdf::XMetadatable> xMeta( + SwXBookmark::CreateXBookmark(*pDoc, *this), uno::UNO_QUERY); + return xMeta; + } + + + Fieldmark::Fieldmark(const SwPaM& rPaM) + : MarkBase(rPaM, MarkBase::GenerateNewName(our_sNamePrefix)) + { + if(!IsExpanded()) + SetOtherMarkPos(GetMarkPos()); + } + + rtl::OUString Fieldmark::ToString( ) const + { + rtl::OUStringBuffer buf; + buf.appendAscii( "Fieldmark: ( Name, Type, [ Nd1, Id1 ], [ Nd2, Id2 ] ): ( " ); + buf.append( m_aName ).appendAscii( ", " ); + buf.append( m_aFieldname ).appendAscii( ", [ " ); + buf.append( sal_Int32( GetMarkPos().nNode.GetIndex( ) ) ).appendAscii( ", " ); + buf.append( sal_Int32( GetMarkPos( ).nContent.GetIndex( ) ) ).appendAscii( " ], [" ); + buf.append( sal_Int32( GetOtherMarkPos().nNode.GetIndex( ) ) ).appendAscii( ", " ); + buf.append( sal_Int32( GetOtherMarkPos( ).nContent.GetIndex( ) ) ).appendAscii( " ] ) " ); + + return buf.makeStringAndClear( ); + } + + void Fieldmark::Invalidate( ) + { + // @TODO: Does exist a better solution to trigger a format of the + // fieldmark portion? If yes, please use it. + SwPaM aPaM( this->GetMarkPos(), this->GetOtherMarkPos() ); + aPaM.InvalidatePaM(); + } + + const ::rtl::OUString Fieldmark::our_sNamePrefix = ::rtl::OUString::createFromAscii("__Fieldmark__"); + + TextFieldmark::TextFieldmark(const SwPaM& rPaM) + : Fieldmark(rPaM) + { } + + void TextFieldmark::InitDoc(SwDoc* const io_pDoc) + { + lcl_AssureFieldMarksSet(this, io_pDoc, CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDEND); + } + + CheckboxFieldmark::CheckboxFieldmark(const SwPaM& rPaM) + : Fieldmark(rPaM) + { } + + void CheckboxFieldmark::InitDoc(SwDoc* const io_pDoc) + { + lcl_AssureFieldMarksSet(this, io_pDoc, CH_TXT_ATR_FORMELEMENT, CH_TXT_ATR_FIELDEND); + + // For some reason the end mark is moved from 1 by the Insert: we don't + // want this for checkboxes + this->GetMarkEnd( ).nContent--; + } + void CheckboxFieldmark::SetChecked(bool checked) + { + (*GetParameters())[::rtl::OUString::createFromAscii(ODF_FORMCHECKBOX_RESULT)] = makeAny(checked); + } + + bool CheckboxFieldmark::IsChecked() const + { + bool bResult = false; + parameter_map_t::const_iterator pResult = GetParameters()->find(::rtl::OUString::createFromAscii(ODF_FORMCHECKBOX_RESULT)); + if(pResult != GetParameters()->end()) + pResult->second >>= bResult; + return bResult; + } + +}} diff --git a/sw/source/core/crsr/callnk.cxx b/sw/source/core/crsr/callnk.cxx new file mode 100644 index 000000000000..bf06a19d83b0 --- /dev/null +++ b/sw/source/core/crsr/callnk.cxx @@ -0,0 +1,221 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <hintids.hxx> + +#ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_ +#include <com/sun/star/i18n/ScriptType.hdl> +#endif +#include <fmtcntnt.hxx> +#include <txatbase.hxx> +#include <frmatr.hxx> +#include <viscrs.hxx> +#include <callnk.hxx> +#include <crsrsh.hxx> +#include <doc.hxx> +#include <frmfmt.hxx> +#include <txtfrm.hxx> +#include <ndtxt.hxx> +#include <flyfrm.hxx> +#include <breakit.hxx> + + +SwCallLink::SwCallLink( SwCrsrShell & rSh, ULONG nAktNode, xub_StrLen nAktCntnt, + BYTE nAktNdTyp, long nLRPos, bool bAktSelection ) + : rShell( rSh ), nNode( nAktNode ), nCntnt( nAktCntnt ), + nNdTyp( nAktNdTyp ), nLeftFrmPos( nLRPos ), + bHasSelection( bAktSelection ) +{ +} + + +SwCallLink::SwCallLink( SwCrsrShell & rSh ) + : rShell( rSh ) +{ + // SPoint-Werte vom aktuellen Cursor merken + SwPaM* pCrsr = rShell.IsTableMode() ? rShell.GetTblCrs() : rShell.GetCrsr(); + SwNode& rNd = pCrsr->GetPoint()->nNode.GetNode(); + nNode = rNd.GetIndex(); + nCntnt = pCrsr->GetPoint()->nContent.GetIndex(); + nNdTyp = rNd.GetNodeType(); + bHasSelection = ( *pCrsr->GetPoint() != *pCrsr->GetMark() ); + + if( ND_TEXTNODE & nNdTyp ) + nLeftFrmPos = SwCallLink::GetFrm( (SwTxtNode&)rNd, nCntnt, + !rShell.ActionPend() ); + else + { + nLeftFrmPos = 0; + + // eine Sonderbehandlung fuer die SwFeShell: diese setzt beim Loeschen + // der Kopf-/Fusszeile, Fussnoten den Cursor auf NULL (Node + Content) + // steht der Cursor auf keinem CntntNode, wird sich das im NdType + // gespeichert. + if( ND_CONTENTNODE & nNdTyp ) + nNdTyp = 0; + } +} + + +SwCallLink::~SwCallLink() +{ + if( !nNdTyp || !rShell.bCallChgLnk ) // siehe ctor + return ; + + // wird ueber Nodes getravellt, Formate ueberpruefen und im neuen + // Node wieder anmelden + SwPaM* pCurCrsr = rShell.IsTableMode() ? rShell.GetTblCrs() : rShell.GetCrsr(); + SwCntntNode * pCNd = pCurCrsr->GetCntntNode(); + if( !pCNd ) + return; + + xub_StrLen nCmp, nAktCntnt = pCurCrsr->GetPoint()->nContent.GetIndex(); + USHORT nNdWhich = pCNd->GetNodeType(); + ULONG nAktNode = pCurCrsr->GetPoint()->nNode.GetIndex(); + + // melde die Shell beim akt. Node als abhaengig an, dadurch koennen + // alle Attribut-Aenderungen ueber den Link weiter gemeldet werden. + pCNd->Add( &rShell ); + + if( nNdTyp != nNdWhich || nNode != nAktNode ) + { + /* immer, wenn zwischen Nodes gesprungen wird, kann es + * vorkommen, das neue Attribute gelten; die Text-Attribute. + * Es muesste also festgestellt werden, welche Attribute + * jetzt gelten; das kann auch gleich der Handler machen + */ + rShell.CallChgLnk(); + } + else if( !bHasSelection != !(*pCurCrsr->GetPoint() != *pCurCrsr->GetMark()) ) + { + // always call change link when selection changes + rShell.CallChgLnk(); + } + else if( rShell.aChgLnk.IsSet() && ND_TEXTNODE == nNdWhich && + nCntnt != nAktCntnt ) + { + // nur wenn mit Left/right getravellt, dann Text-Hints pruefen + // und sich nicht der Frame geaendert hat (Spalten!) + if( nLeftFrmPos == SwCallLink::GetFrm( (SwTxtNode&)*pCNd, nAktCntnt, + !rShell.ActionPend() ) && + (( nCmp = nCntnt ) + 1 == nAktCntnt || // Right + nCntnt -1 == ( nCmp = nAktCntnt )) ) // Left + { + if( nCmp == nAktCntnt && pCurCrsr->HasMark() ) // left & Sele + ++nCmp; + if ( ((SwTxtNode*)pCNd)->HasHints() ) + { + + const SwpHints &rHts = ((SwTxtNode*)pCNd)->GetSwpHints(); + USHORT n; + xub_StrLen nStart; + const xub_StrLen *pEnd; + + for( n = 0; n < rHts.Count(); n++ ) + { + const SwTxtAttr* pHt = rHts[ n ]; + pEnd = pHt->GetEnd(); + nStart = *pHt->GetStart(); + + // nur Start oder Start und Ende gleich, dann immer + // beim Ueberlaufen von Start callen + if( ( !pEnd || ( nStart == *pEnd ) ) && + ( nStart == nCntnt || nStart == nAktCntnt) ) + { + rShell.CallChgLnk(); + return; + } + + // hat das Attribut einen Bereich und dieser nicht leer + else if( pEnd && nStart < *pEnd && + // dann teste, ob ueber Start/Ende getravellt wurde + ( nStart == nCmp || + ( pHt->DontExpand() ? nCmp == *pEnd-1 + : nCmp == *pEnd ) )) + { + rShell.CallChgLnk(); + return; + } + nStart = 0; + } + } + + if( pBreakIt->GetBreakIter().is() ) + { + const String& rTxt = ((SwTxtNode*)pCNd)->GetTxt(); + if( !nCmp || + pBreakIt->GetBreakIter()->getScriptType( rTxt, nCmp ) + != pBreakIt->GetBreakIter()->getScriptType( rTxt, nCmp - 1 )) + { + rShell.CallChgLnk(); + return; + } + } + } + else + /* wenn mit Home/End/.. mehr als 1 Zeichen getravellt, dann + * immer den ChgLnk rufen, denn es kann hier nicht + * festgestellt werden, was sich geaendert; etwas kann + * veraendert sein. + */ + rShell.CallChgLnk(); + } + + const SwFrm* pFrm; + const SwFlyFrm *pFlyFrm; + if( !rShell.ActionPend() && 0 != ( pFrm = pCNd->GetFrm(0,0,FALSE) ) && + 0 != ( pFlyFrm = pFrm->FindFlyFrm() ) && !rShell.IsTableMode() ) + { + const SwNodeIndex* pIndex = pFlyFrm->GetFmt()->GetCntnt().GetCntntIdx(); + ASSERT( pIndex, "Fly ohne Cntnt" ); + const SwNode& rStNd = pIndex->GetNode(); + + if( rStNd.EndOfSectionNode()->StartOfSectionIndex() > nNode || + nNode > rStNd.EndOfSectionIndex() ) + rShell.GetFlyMacroLnk().Call( (void*)pFlyFrm->GetFmt() ); + } +} + +long SwCallLink::GetFrm( SwTxtNode& rNd, xub_StrLen nCntPos, BOOL bCalcFrm ) +{ + SwTxtFrm* pFrm = (SwTxtFrm*)rNd.GetFrm(0,0,bCalcFrm), *pNext = pFrm; + if ( pFrm && !pFrm->IsHiddenNow() ) + { + if( pFrm->HasFollow() ) + while( 0 != ( pNext = (SwTxtFrm*)pFrm->GetFollow() ) && + nCntPos >= pNext->GetOfst() ) + pFrm = pNext; + + return pFrm->Frm().Left(); + } + return 0; +} + diff --git a/sw/source/core/crsr/callnk.hxx b/sw/source/core/crsr/callnk.hxx new file mode 100644 index 000000000000..f85e0c5db123 --- /dev/null +++ b/sw/source/core/crsr/callnk.hxx @@ -0,0 +1,56 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _CALLNK_HXX +#define _CALLNK_HXX + +#include <tools/solar.h> + +class SwCrsrShell; +class SwTxtNode; + +class SwCallLink +{ +public: + SwCrsrShell & rShell; + ULONG nNode; + xub_StrLen nCntnt; + BYTE nNdTyp; + long nLeftFrmPos; + bool bHasSelection; + + SwCallLink( SwCrsrShell & rSh ); + SwCallLink( SwCrsrShell & rSh, ULONG nAktNode, xub_StrLen nAktCntnt, + BYTE nAktNdTyp, long nLRPos, + bool bAktSelection ); + ~SwCallLink(); + + static long GetFrm( SwTxtNode& rNd, xub_StrLen nCntPos, BOOL bCalcFrm ); +}; + + + +#endif // _CALLNK_HXX diff --git a/sw/source/core/crsr/crbm.cxx b/sw/source/core/crsr/crbm.cxx new file mode 100644 index 000000000000..0ef82902ff08 --- /dev/null +++ b/sw/source/core/crsr/crbm.cxx @@ -0,0 +1,260 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include "crsrsh.hxx" +#include "ndtxt.hxx" +#include <docary.hxx> +#include <boost/bind.hpp> + +#include "IMark.hxx" +#include "callnk.hxx" +#include "swcrsr.hxx" +#include <IDocumentMarkAccess.hxx> +#include <IDocumentSettingAccess.hxx> + +using namespace std; + +namespace +{ + struct CrsrStateHelper + { + CrsrStateHelper(SwCrsrShell& rShell) + : m_aLink(rShell) + , m_pCrsr(rShell.GetSwCrsr()) + , m_aSaveState(*m_pCrsr) + { } + + void SetCrsrToMark(::sw::mark::IMark const * const pMark) + { + *(m_pCrsr->GetPoint()) = pMark->GetMarkStart(); + if(pMark->IsExpanded()) + { + m_pCrsr->SetMark(); + *(m_pCrsr->GetMark()) = pMark->GetMarkEnd(); + } + } + + // returns true if the Cursor had been rolled back + bool RollbackIfIllegal() + { + if(m_pCrsr->IsSelOvr(nsSwCursorSelOverFlags::SELOVER_CHECKNODESSECTION + | nsSwCursorSelOverFlags::SELOVER_TOGGLE)) + { + m_pCrsr->DeleteMark(); + m_pCrsr->RestoreSavePos(); + return true; + } + return false; + } + + SwCallLink m_aLink; + SwCursor* m_pCrsr; + SwCrsrSaveState m_aSaveState; + }; + + + static bool lcl_ReverseMarkOrderingByEnd(const IDocumentMarkAccess::pMark_t& rpFirst, + const IDocumentMarkAccess::pMark_t& rpSecond) + { + return rpFirst->GetMarkEnd() > rpSecond->GetMarkEnd(); + } + + static bool lcl_IsInvisibleBookmark(IDocumentMarkAccess::pMark_t pMark) + { + return IDocumentMarkAccess::GetType(*pMark) != IDocumentMarkAccess::BOOKMARK; + } +} + +// at CurCrsr.SPoint +::sw::mark::IMark* SwCrsrShell::SetBookmark( + const KeyCode& rCode, + const ::rtl::OUString& rName, + const ::rtl::OUString& rShortName, + IDocumentMarkAccess::MarkType eMark) +{ + StartAction(); + ::sw::mark::IMark* pMark = getIDocumentMarkAccess()->makeMark( + *GetCrsr(), + rName, + eMark); + ::sw::mark::IBookmark* pBookmark = dynamic_cast< ::sw::mark::IBookmark* >(pMark); + if(pBookmark) + { + pBookmark->SetKeyCode(rCode); + pBookmark->SetShortName(rShortName); + } + EndAction(); + return pMark; +} +// setzt CurCrsr.SPoint + +bool SwCrsrShell::GotoMark(const ::sw::mark::IMark* const pMark, bool bAtStart) +{ + // watch Crsr-Moves + CrsrStateHelper aCrsrSt(*this); + if ( bAtStart ) + *(aCrsrSt.m_pCrsr)->GetPoint() = pMark->GetMarkStart(); + else + *(aCrsrSt.m_pCrsr)->GetPoint() = pMark->GetMarkEnd(); + if(aCrsrSt.RollbackIfIllegal()) return false; + + UpdateCrsr(SwCrsrShell::SCROLLWIN|SwCrsrShell::CHKRANGE|SwCrsrShell::READONLY); + return true; +} + +bool SwCrsrShell::GotoMark(const ::sw::mark::IMark* const pMark) +{ + // watch Crsr-Moves + CrsrStateHelper aCrsrSt(*this); + aCrsrSt.SetCrsrToMark(pMark); + + if(aCrsrSt.RollbackIfIllegal()) return false; + + UpdateCrsr(SwCrsrShell::SCROLLWIN|SwCrsrShell::CHKRANGE|SwCrsrShell::READONLY); + return true; +} + +bool SwCrsrShell::GoNextBookmark() +{ + IDocumentMarkAccess* const pMarkAccess = getIDocumentMarkAccess(); + IDocumentMarkAccess::container_t vCandidates; + remove_copy_if( + upper_bound( + pMarkAccess->getBookmarksBegin(), + pMarkAccess->getBookmarksEnd(), + *GetCrsr()->GetPoint(), + bind(&::sw::mark::IMark::StartsAfter, _2, _1)), // finds the first that is starting after + pMarkAccess->getBookmarksEnd(), + back_inserter(vCandidates), + &lcl_IsInvisibleBookmark); + + // watch Crsr-Moves + CrsrStateHelper aCrsrSt(*this); + IDocumentMarkAccess::const_iterator_t ppMark = vCandidates.begin(); + for(; ppMark!=vCandidates.end(); ++ppMark) + { + aCrsrSt.SetCrsrToMark(ppMark->get()); + if(!aCrsrSt.RollbackIfIllegal()) + break; // found legal move + } + if(ppMark==vCandidates.end()) + { + SttEndDoc(false); + return false; + } + + UpdateCrsr(SwCrsrShell::SCROLLWIN|SwCrsrShell::CHKRANGE|SwCrsrShell::READONLY); + return true; +} + +bool SwCrsrShell::GoPrevBookmark() +{ + IDocumentMarkAccess* const pMarkAccess = getIDocumentMarkAccess(); + // candidates from which to choose the mark before + // no need to consider marks starting after rPos + IDocumentMarkAccess::container_t vCandidates; + remove_copy_if( + pMarkAccess->getBookmarksBegin(), + upper_bound( + pMarkAccess->getBookmarksBegin(), + pMarkAccess->getBookmarksEnd(), + *GetCrsr()->GetPoint(), + bind(&::sw::mark::IMark::StartsAfter, _2, _1)), + back_inserter(vCandidates), + &lcl_IsInvisibleBookmark); + sort( + vCandidates.begin(), + vCandidates.end(), + &lcl_ReverseMarkOrderingByEnd); + + // watch Crsr-Moves + CrsrStateHelper aCrsrSt(*this); + IDocumentMarkAccess::const_iterator_t ppMark = vCandidates.begin(); + for(; ppMark!=vCandidates.end(); ++ppMark) + { + // ignoring those not ending before the Crsr + // (we were only able to eliminate those starting + // behind the Crsr by the upper_bound(..) + // above) + if(!(**ppMark).EndsBefore(*GetCrsr()->GetPoint())) + continue; + aCrsrSt.SetCrsrToMark(ppMark->get()); + if(!aCrsrSt.RollbackIfIllegal()) + break; // found legal move + } + if(ppMark==vCandidates.end()) + { + SttEndDoc(true); + return false; + } + + UpdateCrsr(SwCrsrShell::SCROLLWIN|SwCrsrShell::CHKRANGE|SwCrsrShell::READONLY); + return true; +} + +bool SwCrsrShell::IsFormProtected() +{ + return getIDocumentSettingAccess()->get(IDocumentSettingAccess::PROTECT_FORM); +} + +::sw::mark::IFieldmark* SwCrsrShell::GetCurrentFieldmark() +{ + // TODO: Refactor + SwPosition pos(*GetCrsr()->GetPoint()); + return getIDocumentMarkAccess()->getFieldmarkFor(pos); +} + +::sw::mark::IFieldmark* SwCrsrShell::GetFieldmarkAfter() +{ + SwPosition pos(*GetCrsr()->GetPoint()); + return getIDocumentMarkAccess()->getFieldmarkAfter(pos); +} + +::sw::mark::IFieldmark* SwCrsrShell::GetFieldmarkBefore() +{ + SwPosition pos(*GetCrsr()->GetPoint()); + return getIDocumentMarkAccess()->getFieldmarkBefore(pos); +} + +bool SwCrsrShell::GotoFieldmark(::sw::mark::IFieldmark const * const pMark) +{ + if(pMark==NULL) return false; + + // watch Crsr-Moves + CrsrStateHelper aCrsrSt(*this); + aCrsrSt.SetCrsrToMark(pMark); + //aCrsrSt.m_pCrsr->GetPoint()->nContent--; + //aCrsrSt.m_pCrsr->GetMark()->nContent++; + if(aCrsrSt.RollbackIfIllegal()) return false; + + UpdateCrsr(SwCrsrShell::SCROLLWIN|SwCrsrShell::CHKRANGE|SwCrsrShell::READONLY); + return true; +} diff --git a/sw/source/core/crsr/crossrefbookmark.cxx b/sw/source/core/crsr/crossrefbookmark.cxx new file mode 100644 index 000000000000..dc083801ee8e --- /dev/null +++ b/sw/source/core/crsr/crossrefbookmark.cxx @@ -0,0 +1,102 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <crossrefbookmark.hxx> +#include <ndtxt.hxx> + +using namespace rtl; + +namespace sw { namespace mark +{ + CrossRefBookmark::CrossRefBookmark(const SwPaM& rPaM, + const KeyCode& rCode, + const OUString& rName, + const OUString& rShortName, + const OUString& rPrefix) + : Bookmark(rPaM, rCode, rName, rShortName) + { + if(rPaM.HasMark()) + OSL_ENSURE((rPaM.GetMark()->nNode == rPaM.GetPoint()->nNode && + rPaM.Start()->nContent.GetIndex() == 0 && + rPaM.End()->nContent.GetIndex() == rPaM.GetPoint()->nNode.GetNode().GetTxtNode()->Len()), + "<CrossRefBookmark::CrossRefBookmark(..)>" + "- creation of cross-reference bookmark with an expanded PaM that does not expand over exactly one whole paragraph."); + SetMarkPos(*rPaM.Start()); + if(!rName.getLength()) + m_aName = MarkBase::GenerateNewName(rPrefix); + } + + void CrossRefBookmark::SetMarkPos(const SwPosition& rNewPos) + { + OSL_PRECOND(rNewPos.nNode.GetNode().GetTxtNode(), + "<SwCrossRefBookmark::SetMarkPos(..)>" + " - new bookmark position for cross-reference bookmark doesn't mark text node"); + OSL_PRECOND(rNewPos.nContent.GetIndex() == 0, + "<SwCrossRefBookmark::SetMarkPos(..)>" + " - new bookmark position for cross-reference bookmark doesn't mark start of text node"); + MarkBase::SetMarkPos(rNewPos); + } + + SwPosition& CrossRefBookmark::GetOtherMarkPos() const + { + OSL_PRECOND(false, + "<SwCrossRefBookmark::GetOtherMarkPos(..)>" + " - this should never be called!"); + return *static_cast<SwPosition*>(NULL); + } + + CrossRefHeadingBookmark::CrossRefHeadingBookmark(const SwPaM& rPaM, + const KeyCode& rCode, + const OUString& rName, + const OUString& rShortName) + : CrossRefBookmark(rPaM, rCode, rName, rShortName, our_sNamePrefix) + { } + + const ::rtl::OUString CrossRefHeadingBookmark::our_sNamePrefix = ::rtl::OUString::createFromAscii("__RefHeading__"); + + bool CrossRefHeadingBookmark::IsLegalName(const ::rtl::OUString& rName) + { + return rName.match(our_sNamePrefix); + } + + CrossRefNumItemBookmark::CrossRefNumItemBookmark(const SwPaM& rPaM, + const KeyCode& rCode, + const OUString& rName, + const OUString& rShortName) + : CrossRefBookmark(rPaM, rCode, rName, rShortName, our_sNamePrefix) + { } + + const ::rtl::OUString CrossRefNumItemBookmark::our_sNamePrefix = ::rtl::OUString::createFromAscii("__RefNumPara__"); + + bool CrossRefNumItemBookmark::IsLegalName(const ::rtl::OUString& rName) + { + return rName.match(our_sNamePrefix); + } +}} diff --git a/sw/source/core/crsr/crsrsh.cxx b/sw/source/core/crsr/crsrsh.cxx new file mode 100644 index 000000000000..9cf698a3a709 --- /dev/null +++ b/sw/source/core/crsr/crsrsh.cxx @@ -0,0 +1,3495 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 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 + + +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 FALSE; + + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, + SwCursor* pNextCrsr = (SwCursor*)pCurCrsr->GetNext(); + delete pCurCrsr; + pCurCrsr = dynamic_cast<SwShellCrsr*>(pNextCrsr); + UpdateCrsr(); + return TRUE; +} + + +// gebe den aktuellen zurueck + +SwPaM* SwCrsrShell::GetCrsr( 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->GetFrm() && + 0 != ( pCNd = pTblCrsr->GetCntntNode(FALSE) ) && pCNd->GetFrm()) + { + 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::GetFrm( (SwTxtNode&)rNd, nAktCntnt, TRUE ); + else + nLeftFrmPos = 0; + } + ViewShell::StartAction(); // zur ViewShell +} + + +void SwCrsrShell::EndAction( const 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; + } +*/ + + 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( USHORT 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. + BOOL bSavSVCrsrVis = bSVCrsrVis; + bSVCrsrVis = 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, (BYTE)nAktNdTyp, + nLeftFrmPos, bAktSelection ); + + } + if( bCallChgLnk && bChgCallFlag && aChgLnk.IsSet() ) + { + aChgLnk.Call( this ); + bChgCallFlag = FALSE; // Flag zuruecksetzen + } + } + return; + } + + USHORT nParm = SwCrsrShell::CHKRANGE; + if ( !bIdleEnd ) + nParm |= SwCrsrShell::SCROLLWIN; + UpdateCrsr( nParm, bIdleEnd ); // Cursor-Aenderungen anzeigen + + { + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, + aLk.nNode = nAktNode; // evt. Link callen + aLk.nNdTyp = (BYTE)nAktNdTyp; + aLk.nCntnt = nAktCntnt; + aLk.nLeftFrmPos = nLeftFrmPos; + + if( !nCrsrMove || + ( 1 == nCrsrMove && bInCMvVisportChgd ) ) + ShowCrsrs( bSVCrsrVis ? TRUE : FALSE ); // Cursor & Selektionen wieder anzeigen + } + // falls noch ein ChgCall vorhanden ist, dann rufe ihn + if( bCallChgLnk && bChgCallFlag && aChgLnk.IsSet() ) + { + aChgLnk.Call( this ); + bChgCallFlag = FALSE; // Flag zuruecksetzen + } +} + + +#if defined(DBG_UTIL) + +void SwCrsrShell::SttCrsrMove() +{ + ASSERT( nCrsrMove < USHRT_MAX, "To many nested CrsrMoves." ); + ++nCrsrMove; + StartAction(); +} + +void SwCrsrShell::EndCrsrMove( const BOOL bIdleEnd ) +{ + ASSERT( nCrsrMove, "EndCrsrMove() ohne SttCrsrMove()." ); + EndAction( bIdleEnd ); + if( !--nCrsrMove ) + bInCMvVisportChgd = FALSE; +} + +#endif + + +BOOL SwCrsrShell::LeftRight( BOOL bLeft, USHORT nCnt, USHORT nMode, + BOOL bVisualAllowed ) +{ + if( IsTableMode() ) + return bLeft ? GoPrevCell() : GoNextCell(); + + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + BOOL bRet = 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( FALSE ); + bRet = 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( TRUE ); + bRet = TRUE; + } + // + // 3. CASE: Regular cursor move. Reset the bInFrontOfLabel flag: + // + else + { + const 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( FALSE ); + bRet = pShellCrsr->LeftRight( bLeft, nCnt, nMode, bVisualAllowed, + bSkipHidden, !IsOverwriteCrsr() ); + if ( !bRet && bLeft && bResetOfInFrontOfLabel ) + { + // undo reset of <bInFrontOfLabel> flag + SetInFrontOfLabel( TRUE ); + } + // <-- + } + + if( bRet ) + { + UpdateCrsr(); + } + return bRet; +} + +// --> 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, FALSE ); + + if ( sListId.Len() > 0 ) + { + pDoc->MarkListLevel( sListId, nListLevel, TRUE ); + } + + sMarkedListId = sListId; + nMarkedListLevel = nListLevel; + } +} + +void SwCrsrShell::UpdateMarkedListLevel() +{ + SwTxtNode * pTxtNd = _GetCrsr()->GetNode()->GetTxtNode(); + + if ( pTxtNd ) + { + if ( !pTxtNd->IsNumbered() ) + { + pCurCrsr->_SetInFrontOfLabel( 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 ); + } + } +} +// <-- + +BOOL SwCrsrShell::UpDown( BOOL bUp, USHORT nCnt ) +{ + SET_CURR_SHELL( this ); + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + + BOOL bTableMode = IsTableMode(); + SwShellCrsr* pTmpCrsr = getShellCrsr( true ); + + BOOL bRet = pTmpCrsr->UpDown( bUp, nCnt ); + // --> FME 2005-01-10 #i40019# UpDown should always reset the + // bInFrontOfLabel flag: + bRet = SetInFrontOfLabel(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<USHORT>(eUpdtMode) ); + } + } + return bRet; +} + + +BOOL SwCrsrShell::LRMargin( BOOL bLeft, BOOL bAPI) +{ + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + SET_CURR_SHELL( this ); + eMvState = MV_LEFTMARGIN; // Status fuers Crsr-Travelling - GetCrsrOfst + + const BOOL bTableMode = IsTableMode(); + SwShellCrsr* pTmpCrsr = getShellCrsr( true ); + + if( pBlockCrsr ) + pBlockCrsr->clearPoints(); + + const BOOL bWasAtLM = + ( 0 == _GetCrsr()->GetPoint()->nContent.GetIndex() ); + + BOOL bRet = pTmpCrsr->LeftRightMargin( bLeft, bAPI ); + + if ( bLeft && !bTableMode && bRet && bWasAtLM && !_GetCrsr()->HasMark() ) + { + const SwTxtNode * pTxtNd = _GetCrsr()->GetNode()->GetTxtNode(); + if ( pTxtNd && pTxtNd->HasVisibleNumberingOrBullet() ) + SetInFrontOfLabel( TRUE ); + } + else if ( !bLeft ) + { + bRet = SetInFrontOfLabel( FALSE ) || bRet; + } + + if( bRet ) + { + UpdateCrsr(); + } + return bRet; +} + +BOOL SwCrsrShell::IsAtLRMargin( BOOL bLeft, BOOL bAPI ) const +{ + const SwShellCrsr* pTmpCrsr = getShellCrsr( true ); + return pTmpCrsr->IsAtLeftRightMargin( bLeft, bAPI ); +} + + +BOOL SwCrsrShell::SttEndDoc( BOOL bStt ) +{ + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + + SwShellCrsr* pTmpCrsr = pBlockCrsr ? &pBlockCrsr->getShellCrsr() : pCurCrsr; + 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 ); +} + +BOOL SwCrsrShell::MovePage( SwWhichPage fnWhichPage, SwPosPage fnPosPage ) +{ + BOOL bRet = 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()-> + GetFrm( &rPt, pCurCrsr->GetPoint() ); + if( pFrm && TRUE == ( bRet = GetFrmInPage( pFrm, fnWhichPage, + fnPosPage, pCurCrsr ) ) && + !pCurCrsr->IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE | + nsSwCursorSelOverFlags::SELOVER_CHANGEPOS )) + UpdateCrsr(); + else + bRet = FALSE; + } + return bRet; +} + + +BOOL SwCrsrShell::MovePara(SwWhichPara fnWhichPara, SwPosPara fnPosPara ) +{ + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + SwCursor* pTmpCrsr = getShellCrsr( true ); + BOOL bRet = pTmpCrsr->MovePara( fnWhichPara, fnPosPara ); + if( bRet ) + UpdateCrsr(); + return bRet; +} + + +BOOL SwCrsrShell::MoveSection( SwWhichSection fnWhichSect, + SwPosSection fnPosSect) +{ + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + SwCursor* pTmpCrsr = getShellCrsr( true ); + 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->GetFrm( &rPt, 0, FALSE )->GetUpper(); + while( pFrm && !pFrm->IsHeaderFrm() && !pFrm->IsFooterFrm() ) + pFrm = pFrm->IsFlyFrm() ? ((SwFlyFrm*)pFrm)->AnchorFrm() + : pFrm->GetUpper(); + } + return pFrm; +} + +BOOL SwCrsrShell::IsInHeaderFooter( 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, 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 = TRUE; // #i27615# + } + else + { + aTmpState.bInFrontOfLabel = 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()).GetFrm( + &aCharRect.Pos(), 0, FALSE ); + SwFrm* pNew = ((SwCntntNode&)aPos.nNode.GetNode()).GetFrm( + &aPt, 0, 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, 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 ) ) + { + USHORT 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 = TRUE; + if( GetDoc()->GetDocShell() ) + { + GetDoc()->GetDocShell()->SetReadOnlyUI( 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(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. + + +BOOL SwCrsrShell::ChgCurrPam( const Point & rPt, + BOOL bTstOnly, 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 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 TRUE; // return ohne Update + + pCurCrsr = pCmp; + UpdateCrsr(); // Cursor steht schon richtig + return TRUE; + } + } while( pCurCrsr != + ( pCmp = dynamic_cast<SwShellCrsr*>(pCmp->GetNext()) ) ); + return 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; +} + + +BOOL SwCrsrShell::IsSttPara() const +{ return( pCurCrsr->GetPoint()->nContent == 0 ? TRUE : FALSE ); } + + +BOOL SwCrsrShell::IsEndPara() const +{ return( pCurCrsr->GetPoint()->nContent == pCurCrsr->GetCntntNode()->Len() ? TRUE : FALSE ); } + + +BOOL SwCrsrShell::IsInFrontOfLabel() const +{ + return pCurCrsr->IsInFrontOfLabel(); +} + +bool SwCrsrShell::SetInFrontOfLabel( BOOL bNew ) +{ + if ( bNew != IsInFrontOfLabel() ) + { + pCurCrsr->_SetInFrontOfLabel( bNew ); + UpdateMarkedListLevel(); + return true; + } + return false; +} + +BOOL SwCrsrShell::GotoPage( USHORT nPage ) +{ + SET_CURR_SHELL( this ); + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + SwCrsrSaveState aSaveState( *pCurCrsr ); + 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( USHORT &rnPhyNum, USHORT &rnVirtNum, + BOOL bAtCrsrPos, const 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; +} + + +USHORT SwCrsrShell::GetNextPrevPageNum( 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; +} + + +USHORT SwCrsrShell::GetPageCnt() +{ + SET_CURR_SHELL( this ); + // gebe die Anzahl der Seiten zurueck + return GetLayout()->GetPageNum(); +} + +// Gehe zur naechsten SSelection + + +BOOL SwCrsrShell::GoNextCrsr() +{ + // besteht ueberhaupt ein Ring ? + if( pCurCrsr->GetNext() == pCurCrsr ) + return 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 TRUE; +} + +// gehe zur vorherigen SSelection + + +BOOL SwCrsrShell::GoPrevCrsr() +{ + // besteht ueberhaupt ein Ring ? + if( pCurCrsr->GetNext() == pCurCrsr ) + return 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 TRUE; +} + + +void SwCrsrShell::Paint( const Rectangle &rRect) +{ + SET_CURR_SHELL( this ); + + // beim Painten immer alle Cursor ausschalten + SwRect aRect( rRect ); + + BOOL bVis = FALSE; + // ist Cursor sichtbar, dann verstecke den SV-Cursor + if( pVisCrsr->IsVisible() && !aRect.IsOver( aCharRect ) ) //JP 18.06.97: ??? + { + bVis = 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 ); + BOOL bVis; // beim Scrollen immer alle Cursor ausschalten + + // ist Cursor sichtbar, dann verstecke den SV-Cursor + if( TRUE == ( bVis = pVisCrsr->IsVisible() )) + pVisCrsr->Hide(); + + bVisPortChgd = 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 = TRUE; + + bVisPortChgd = 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->GetFrm( &pShellCrsr->GetPtPos(), pShellCrsr->GetPoint() ) :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( USHORT eFlags, 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 = TRUE; + return; // wenn nicht, dann kein Update !! + } + + // --> OD 2005-12-14 #i27301# + SwNotifyAccAboutInvalidTextSelections aInvalidateTextSelections( *this ); + // <-- + + if ( bIgnoreReadonly ) + { + bIgnoreReadonly = 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( TRUE )->StartOfSectionNode() != + pTstCrsr->GetNode( 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()-> + GetFrm( &aTmpPt, pPos ); + + 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( FALSE )->GetFrm( &aTmpMk, pITmpCrsr->GetMark() ); + 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 = 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 ); + BOOL bChgState = 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 = FALSE; + else + { + eMvState = MV_NONE; // Status fuers Crsr-Travelling + bAllProtect = TRUE; + if( GetDoc()->GetDocShell() ) + { + GetDoc()->GetDocShell()->SetReadOnlyUI( TRUE ); + CallChgLnk(); // UI bescheid sagen! + } + return; + } + } + } + if( bChgState ) + { + BOOL bWasAllProtect = bAllProtect; + bAllProtect = FALSE; + if( bWasAllProtect && GetDoc()->GetDocShell() && + GetDoc()->GetDocShell()->IsReadOnlyUI() ) + { + GetDoc()->GetDocShell()->SetReadOnlyUI( 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 ); + BOOL bFirst = TRUE; + SwCntntFrm *pFrm; + int nLoopCnt = 100; + SwShellCrsr* pShellCrsr = getShellCrsr( true ); + + do { + BOOL bAgainst; + do { + bAgainst = FALSE; + pFrm = pShellCrsr->GetCntntNode()->GetFrm( + &pShellCrsr->GetPtPos(), pShellCrsr->GetPoint() ); + // 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()->GetFrm( + &pShellCrsr->GetPtPos(), pShellCrsr->GetPoint() ); + } 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 + BOOL bChgState = TRUE; + if( !FindValidCntntNode(!HasDrawView() || + 0 == Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount())) + { + // alles ist geschuetzt / versteckt -> besonderer Mode + if( bAllProtect ) + bChgState = FALSE; + else + { + eMvState = MV_NONE; // Status fuers Crsr-Travelling + bAllProtect = TRUE; + if( GetDoc()->GetDocShell() ) + { + GetDoc()->GetDocShell()->SetReadOnlyUI( TRUE ); + CallChgLnk(); // UI bescheid sagen! + } + return; + } + } + + if( bChgState ) + { + BOOL bWasAllProtect = bAllProtect; + bAllProtect = FALSE; + if( bWasAllProtect && GetDoc()->GetDocShell() && + GetDoc()->GetDocShell()->IsReadOnlyUI() ) + { + GetDoc()->GetDocShell()->SetReadOnlyUI( FALSE ); + CallChgLnk(); // UI bescheid sagen! + } + bAllProtect = FALSE; + bAgainst = TRUE; // nochmal den richigen Frm suchen + } + } + } while( bAgainst ); + + if( !( eFlags & SwCrsrShell::NOCALRECT )) + { + SwCrsrMoveState aTmpState( eMvState ); + aTmpState.bSetInReadOnly = IsReadOnlyAvailable(); + aTmpState.bRealHeight = 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 = 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. + BOOL bSav = bSVCrsrVis; bSVCrsrVis = 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()->GetFrm( &aPt, rBlock.GetPoint() ); + 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 = TRUE ) + * - den aktuellen und der auf dem Stack stehende wird zum aktuellen + * + * Return: es war auf dem Stack noch einer vorhanden + */ + + +BOOL SwCrsrShell::Pop( BOOL bOldCrsr ) +{ + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + + // noch weitere vorhanden ? + if( 0 == pCrsrStk ) + return 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( TRUE ) && + !pCurCrsr->IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE | + nsSwCursorSelOverFlags::SELOVER_CHANGEPOS ) ) + UpdateCrsr(); // akt. Cursor Updaten + } + return 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, TRUE ); +#else + if( !CheckNodesRange( pCrsrStk->GetMark()->nNode, pCurCrsr->GetPoint()->nNode, 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( 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( 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 = TRUE; + UpdateCrsr(); + } +} + + +void SwCrsrShell::HideCrsr() +{ + if( !bBasicHideCrsr ) + { + bSVCrsrVis = FALSE; + // evt. die sel. Bereiche aufheben !! + SET_CURR_SHELL( this ); + pVisCrsr->Hide(); + } +} + + +void SwCrsrShell::ShLooseFcs() +{ + if( !bBasicHideCrsr ) + HideCrsrs(); + bHasFocus = FALSE; +} + + +void SwCrsrShell::ShGetFcs( BOOL bUpdate ) +{ + bHasFocus = TRUE; + if( !bBasicHideCrsr && VisArea().Width() ) + { + UpdateCrsr( static_cast<USHORT>( bUpdate ? + SwCrsrShell::CHKRANGE|SwCrsrShell::SCROLLWIN + : SwCrsrShell::CHKRANGE ) ); + ShowCrsrs( bSVCrsrVis ? TRUE : FALSE ); + } +} + +// gebe den aktuellen Frame, in dem der Cursor steht, zurueck + +SwCntntFrm *SwCrsrShell::GetCurrFrm( const BOOL bCalcFrm ) const +{ + SET_CURR_SHELL( (ViewShell*)this ); + SwCntntFrm *pRet = 0; + SwCntntNode *pNd = pCurCrsr->GetCntntNode(); + if ( pNd ) + { + if ( bCalcFrm ) + { + const USHORT* pST = &nStartAction; + ++(*((USHORT*)pST)); + const Size aOldSz( GetDocSize() ); + pRet = pNd->GetFrm( &pCurCrsr->GetPtPos(), pCurCrsr->GetPoint() ); + --(*((USHORT*)pST)); + if( aOldSz != GetDocSize() ) + ((SwCrsrShell*)this)->SizeChgNotify(); + } + else + pRet = pNd->GetFrm( &pCurCrsr->GetPtPos(), pCurCrsr->GetPoint(), FALSE); + } + return pRet; +} + + +// alle Attribut/Format-Aenderungen am akt. Node werden an den +// Link weitergeleitet. + + +void SwCrsrShell::Modify( SfxPoolItem* pOld, SfxPoolItem* pNew ) +{ + const USHORT nWhich = pOld ? + pOld->Which() : + pNew ? + pNew->Which() : + sal::static_int_cast<USHORT>(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*, USHORT) 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. + + +BOOL SwCrsrShell::HasSelection() const +{ + const SwPaM* pCrsr = getShellCrsr( true ); + return( IsTableMode() || ( pCrsr->HasMark() && + *pCrsr->GetPoint() != *pCrsr->GetMark()) + ? TRUE : 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 = TRUE; // das Change merken + else if( aChgLnk.IsSet() ) + { + if( bCallChgLnk ) + aChgLnk.Call( this ); + bChgCallFlag = 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( 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 + + +BOOL SwCrsrShell::ExtendSelection( BOOL bEnd, xub_StrLen nCount ) +{ + if( !pCurCrsr->HasMark() || IsTableMode() ) + return 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 FALSE; // nicht mehr moeglich + } + else if( nPos >= nCount ) + nPos = nPos - nCount; + else + return FALSE; // nicht mehr moeglich + + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, + + pPos->nContent = nPos; + UpdateCrsr(); + + return TRUE; +} + +// setze nur den sichtbaren Cursor an die angegebene Dokument-Pos. +// returnt FALSE: wenn der SPoint vom Layout korrigiert wurde. + +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 = TRUE; + + BOOL bRet = GetLayout()->GetCrsrOfst( &aPos, aPt /*, &aTmpState*/ ); + + SetInFrontOfLabel( FALSE ); // #i27615# + + // nur in TextNodes anzeigen !! + SwTxtNode* pTxtNd = aPos.nNode.GetNode().GetTxtNode(); + if( !pTxtNd ) + return FALSE; + + const SwSectionNode* pSectNd = pTxtNd->FindSectionNode(); + if( pSectNd && (pSectNd->GetSection().IsHiddenFlag() || + ( !IsReadOnlyAvailable() && + pSectNd->GetSection().IsProtectFlag())) ) + return FALSE; + + SwCntntFrm *pFrm = pTxtNd->GetFrm( &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 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( TRUE ); + pVisCrsr->Show(); // wieder anzeigen + } + return bRet; +} + +BOOL SwCrsrShell::IsOverReadOnlyPos( const Point& rPt ) const +{ + Point aPt( rPt ); + SwPaM aPam( *pCurCrsr->GetPoint() ); + GetLayout()->GetCrsrOfst( aPam.GetPoint(), aPt ); + // --> FME 2004-06-29 #114856# Formular view + 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)) +USHORT SwCrsrShell::GetCrsrCnt( BOOL bAll ) const +{ + Ring* pTmp = GetCrsr()->GetNext(); + USHORT 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; +} + + +BOOL SwCrsrShell::IsStartOfDoc() const +{ + if( pCurCrsr->GetPoint()->nContent.GetIndex() ) + return 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; +} + + +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. +BOOL SwCrsrShell::ParkTblCrsr() +{ + if( !pTblCrsr ) + return 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 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 + 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 = TRUE; + if( pTmpDel ) // ist der Pam im Bereich ?? loesche ihn + { + BOOL bDelete = TRUE; + if( *ppDelRing == pTmpDel ) + { + if( *ppDelRing == pCurCrsr ) + { + if( TRUE == ( bDelete = GoNextCrsr() )) + { + bGoNext = FALSE; + pTmp = (SwPaM*)pTmp->GetNext(); + } + } + else + bDelete = 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 = FALSE; + bCallChgLnk = bHasFocus = bSVCrsrVis = bAutoUpdateCells = TRUE; + bSetCrsrInReadOnly = TRUE; + pVisCrsr = new SwVisCrsr( this ); +// UpdateCrsr( 0 ); + // OD 11.02.2003 #100556# + mbMacroExecAllowed = rShell.IsMacroExecAllowed(); +} + + +/* + * 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 = FALSE; + bCallChgLnk = bHasFocus = bSVCrsrVis = bAutoUpdateCells = TRUE; + bSetCrsrInReadOnly = 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() ) + pRegisteredIn->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. + +BOOL SwCrsrShell::ShouldWait() const +{ + if ( IsTableMode() || GetCrsrCnt() > 1 ) + return TRUE; + + if( HasDrawView() && GetDrawView()->GetMarkedObjectList().GetMarkCount() ) + return TRUE; + + SwPaM* pPam = GetCrsr(); + return pPam->Start()->nNode.GetIndex() + 10 < + pPam->End()->nNode.GetIndex(); +} + + +USHORT 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) +BOOL SwCrsrShell::FindValidCntntNode( BOOL bOnlyText ) +{ + if( pTblCrsr ) // was soll ich jetzt machen ?? + { + ASSERT( !this, "TabellenSelection nicht aufgehoben!" ); + return FALSE; + } + + //JP 28.10.97: Bug 45129 - im UI-ReadOnly ist alles erlaubt + if( !bAllProtect && GetDoc()->GetDocShell() && + GetDoc()->GetDocShell()->IsReadOnlyUI() ) + return TRUE; + + // dann raus da! + if( pCurCrsr->HasMark() ) + ClearMark(); + + // als erstes mal auf Rahmen abpruefen + SwNodeIndex& rNdIdx = pCurCrsr->GetPoint()->nNode; + ULONG nNdIdx = rNdIdx.GetIndex(); // sichern + SwNodes& rNds = pDoc->GetNodes(); + SwCntntNode* pCNd = rNdIdx.GetNode().GetCntntNode(); + const SwCntntFrm * pFrm; + + if( pCNd && 0 != (pFrm = pCNd->GetFrm(0,pCurCrsr->GetPoint(),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(); + + BOOL bFirst = FALSE; + if( 0 == (pCNd = ::GetNode( aPam, bFirst, fnMoveForward, FALSE ))) + { + aPam.GetMark()->nNode = *rNds.GetEndOfPostIts().StartOfSectionNode(); + pCNd = ::GetNode( aPam, bFirst, fnMoveBackward, FALSE ); + } + + if( !pCNd ) // sollte nie passieren !!! + { + rNdIdx = nNdIdx; // alten Node zurueck + return 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(); + } + + BOOL bOk = 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 = FALSE; + + for( int nLoopCnt = 0; !bOk && nLoopCnt < 2; ++nLoopCnt ) + { + BOOL bWeiter; + do { + bWeiter = FALSE; + while( 0 != ( pCNd = (rNds.*funcGoSection)( &rNdIdx, + 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( TRUE, TRUE ) ) + { + const SwSectionNode* pSNd = pCNd->FindSectionNode(); + if( !pSNd || !pSNd->GetSection().IsHiddenFlag() + || (!IsReadOnlyAvailable() && + pSNd->GetSection().IsProtectFlag() )) + { + bOk = TRUE; + break; // eine nicht geschuetzte Zelle gef. + } + continue; // dann weiter suchen + } + } + else + { + bOk = 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->GetFrm(0,0,FALSE)) || + ( !IsReadOnlyAvailable() && pFrm->IsProtected() ) || + ( bOnlyText && pCNd->IsNoTxtNode() ) ) + { + // dann weiter suchen! + bOk = FALSE; + bWeiter = TRUE; + } + } + } while( bWeiter ); + + if( !bOk ) + { + if( !nLoopCnt ) + funcGoSection = &SwNodes::GoPrevSection; + rNdIdx = nNdIdx; + } + } + } + if( bOk ) + { + pCNd = rNdIdx.GetNode().GetCntntNode(); +// USHORT 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->GetFrm(0,0,FALSE) ) + { + SwCrsrMoveState aTmpState( MV_NONE ); + aTmpState.bSetInReadOnly = IsReadOnlyAvailable(); + GetLayout()->GetCrsrOfst( pCurCrsr->GetPoint(), pCurCrsr->GetPtPos(), + &aTmpState ); + } + } + return bOk; +} + + +void SwCrsrShell::NewCoreSelection() +{ +} + + +BOOL SwCrsrShell::IsCrsrReadonly() const +{ + if ( GetViewOptions()->IsReadonly() || + // --> FME 2004-06-29 #114856# Formular view + GetViewOptions()->IsFormView() ) + // <-- + { + SwFrm *pFrm = GetCurrFrm( 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 FALSE; + } + // --> FME 2004-06-22 #114856# edit in readonly sections + else if ( pFrm && pFrm->IsInSct() && + 0 != ( pSection = pFrm->FindSctFrm()->GetSection() ) && + pSection->IsEditInReadonlyFlag() ) + { + return FALSE; + } + // <-- + + return TRUE; + } + return FALSE; +} + + +// darf der Cursor in ReadOnlyBereiche? +void SwCrsrShell::SetReadOnlyAvailable( 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(); + } +} + +BOOL SwCrsrShell::HasReadonlySel() const +{ + BOOL bRet = FALSE; + if( IsReadOnlyAvailable() || + // --> FME 2004-06-29 #114856# Formular view + GetViewOptions()->IsFormView() ) + // <-- + { + if( pTblCrsr ) + bRet = pTblCrsr->HasReadOnlyBoxSel() || + pTblCrsr->HasReadonlySel( + // --> FME 2004-06-29 #114856# Formular view + GetViewOptions()->IsFormView() ); + // <-- + else + { + const SwPaM* pCrsr = pCurCrsr; + + do { + if( pCrsr->HasReadonlySel( + // --> FME 2004-06-29 #114856# Formular view + GetViewOptions()->IsFormView() ) ) + // <-- + bRet = TRUE; + } while( !bRet && pCurCrsr != ( pCrsr = (SwPaM*)pCrsr->GetNext() )); + } + } + return bRet; +} + +BOOL SwCrsrShell::IsSelFullPara() const +{ + BOOL bRet = 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 ); +} + +BOOL SwCrsrShell::IsInVerticalText( const Point* pPt ) const +{ + const short nDir = GetTextDirection( pPt ); + return FRMDIR_VERT_TOP_RIGHT == nDir || FRMDIR_VERT_TOP_LEFT == nDir; +} + +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 +ULONG SwCrsrShell::Find( const SearchOptions& rSearchOpt, BOOL bSearchInNotes, + SwDocPositions eStart, SwDocPositions eEnde, + BOOL& bCancel, + FindRanges eRng, int bReplace ) +{ + if( pTblCrsr ) + GetCrsr(); + delete pTblCrsr, pTblCrsr = 0; + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + ULONG nRet = pCurCrsr->Find( rSearchOpt, bSearchInNotes, eStart, eEnde, bCancel, eRng, bReplace ); + if( nRet || bCancel ) + UpdateCrsr(); + return nRet; +} + +ULONG SwCrsrShell::Find( const SwTxtFmtColl& rFmtColl, + SwDocPositions eStart, SwDocPositions eEnde, + BOOL& bCancel, + FindRanges eRng, const SwTxtFmtColl* pReplFmt ) +{ + if( pTblCrsr ) + GetCrsr(); + delete pTblCrsr, pTblCrsr = 0; + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + ULONG nRet = pCurCrsr->Find( rFmtColl, eStart, eEnde, bCancel, eRng, pReplFmt ); + if( nRet ) + UpdateCrsr(); + return nRet; +} + +ULONG SwCrsrShell::Find( const SfxItemSet& rSet, BOOL bNoCollections, + SwDocPositions eStart, SwDocPositions eEnde, + 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 + 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 ( USHORT 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(); + USHORT 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 USHORT 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 USHORT 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(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 = TRUE; + SwCntntNode* pCntntNode = pCrsr->GetCntntNode(); + SwCntntFrm *pCntntFrame = pCntntNode->GetFrm( &rPt, pCrsr->GetPoint(), FALSE); + + pCntntFrame->GetCharRect( aStartRect, *pCrsr->GetPoint(), &aState ); + rContent = nWordEnd; + SwRect aEndRect; + pCntntFrame->GetCharRect( aEndRect, *pCrsr->GetPoint(),&aState ); + rSelectRect = aStartRect.Union( aEndRect ); + Pop(FALSE); + } + } +} + diff --git a/sw/source/core/crsr/crstrvl.cxx b/sw/source/core/crsr/crstrvl.cxx new file mode 100644 index 000000000000..c11092c5fd9d --- /dev/null +++ b/sw/source/core/crsr/crstrvl.cxx @@ -0,0 +1,2216 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <hintids.hxx> +#include <svl/itemiter.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/adjitem.hxx> +#include <editeng/brkitem.hxx> +#include <svx/svdobj.hxx> +#include <crsrsh.hxx> +#include <doc.hxx> +#include <pagefrm.hxx> +#include <cntfrm.hxx> +#include <rootfrm.hxx> +#include <pam.hxx> +#include <ndtxt.hxx> +#include <fldbas.hxx> +#include <swtable.hxx> // SwTxtFld +#include <docary.hxx> +#include <txtfld.hxx> +#include <fmtfld.hxx> +#include <txtftn.hxx> +#include <txtinet.hxx> +#include <fmtinfmt.hxx> +#include <txttxmrk.hxx> +#include <frmfmt.hxx> +#include <flyfrm.hxx> +#include <viscrs.hxx> +#include <callnk.hxx> +#include <doctxm.hxx> +#include <docfld.hxx> +#include <expfld.hxx> +#include <reffld.hxx> +#include <flddat.hxx> // SwTxtFld +#include <cellatr.hxx> +#include <swundo.hxx> +#include <redline.hxx> +#include <fmtcntnt.hxx> +#include <fmthdft.hxx> +#include <pagedesc.hxx> +#include <fesh.hxx> +#include <charfmt.hxx> +#include <fmturl.hxx> +#include "txtfrm.hxx" +#include <wrong.hxx> + +#include <vcl/window.hxx> +#include <docufld.hxx> // OD 2008-06-19 #i90516# + +using namespace ::com::sun::star; + + +// zum naechsten/vorhergehenden Punkt auf gleicher Ebene +BOOL SwCrsrShell::GotoNextNum() +{ + BOOL bRet = GetDoc()->GotoNextNum( *pCurCrsr->GetPoint() ); + if( bRet ) + { + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, + SwCrsrSaveState aSaveState( *pCurCrsr ); + if( !ActionPend() ) + { + SET_CURR_SHELL( this ); + // dann versuche den Cursor auf die Position zu setzen, + // auf halber Heohe vom Char-SRectangle + Point aPt( pCurCrsr->GetPtPos() ); + SwCntntFrm * pFrm = pCurCrsr->GetCntntNode()->GetFrm( &aPt, + pCurCrsr->GetPoint() ); + pFrm->GetCharRect( aCharRect, *pCurCrsr->GetPoint() ); + pFrm->Calc(); + if( pFrm->IsVertical() ) + { + aPt.X() = aCharRect.Center().X(); + aPt.Y() = pFrm->Frm().Top() + nUpDownX; + } + else + { + aPt.Y() = aCharRect.Center().Y(); + aPt.X() = pFrm->Frm().Left() + nUpDownX; + } + pFrm->GetCrsrOfst( pCurCrsr->GetPoint(), aPt ); + bRet = !pCurCrsr->IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE | + nsSwCursorSelOverFlags::SELOVER_CHANGEPOS ); + if( bRet ) + UpdateCrsr(SwCrsrShell::UPDOWN | + SwCrsrShell::SCROLLWIN | SwCrsrShell::CHKRANGE | + SwCrsrShell::READONLY ); + } + } + return bRet; +} + + +BOOL SwCrsrShell::GotoPrevNum() +{ + BOOL bRet = GetDoc()->GotoPrevNum( *pCurCrsr->GetPoint() ); + if( bRet ) + { + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, + SwCrsrSaveState aSaveState( *pCurCrsr ); + if( !ActionPend() ) + { + SET_CURR_SHELL( this ); + // dann versuche den Cursor auf die Position zu setzen, + // auf halber Heohe vom Char-SRectangle + Point aPt( pCurCrsr->GetPtPos() ); + SwCntntFrm * pFrm = pCurCrsr->GetCntntNode()->GetFrm( &aPt, + pCurCrsr->GetPoint() ); + pFrm->GetCharRect( aCharRect, *pCurCrsr->GetPoint() ); + pFrm->Calc(); + if( pFrm->IsVertical() ) + { + aPt.X() = aCharRect.Center().X(); + aPt.Y() = pFrm->Frm().Top() + nUpDownX; + } + else + { + aPt.Y() = aCharRect.Center().Y(); + aPt.X() = pFrm->Frm().Left() + nUpDownX; + } + pFrm->GetCrsrOfst( pCurCrsr->GetPoint(), aPt ); + bRet = !pCurCrsr->IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE | + nsSwCursorSelOverFlags::SELOVER_CHANGEPOS ); + if( bRet ) + UpdateCrsr(SwCrsrShell::UPDOWN | + SwCrsrShell::SCROLLWIN | SwCrsrShell::CHKRANGE | + SwCrsrShell::READONLY ); + } + } + return bRet; +} + +// springe aus dem Content zum Header + +BOOL SwCrsrShell::GotoHeaderTxt() +{ + const SwFrm* pFrm = GetCurrFrm()->FindPageFrm(); + while( pFrm && !pFrm->IsHeaderFrm() ) + pFrm = pFrm->GetLower(); + // Header gefunden, dann suche den 1.Cntnt-Frame + while( pFrm && !pFrm->IsCntntFrm() ) + pFrm = pFrm->GetLower(); + if( pFrm ) + { + SET_CURR_SHELL( this ); + // hole den Header-Frame + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, + SwCursor *pTmpCrsr = getShellCrsr( true ); + SwCrsrSaveState aSaveState( *pTmpCrsr ); + pFrm->Calc(); + Point aPt( pFrm->Frm().Pos() + pFrm->Prt().Pos() ); + pFrm->GetCrsrOfst( pTmpCrsr->GetPoint(), aPt ); + if( !pTmpCrsr->IsSelOvr() ) + UpdateCrsr(); + else + pFrm = 0; + } + return 0 != pFrm; +} + + +// springe aus dem Content zum Footer + +BOOL SwCrsrShell::GotoFooterTxt() +{ + const SwPageFrm* pFrm = GetCurrFrm()->FindPageFrm(); + if( pFrm ) + { + const SwFrm* pLower = pFrm->GetLastLower(); + + while( pLower && !pLower->IsFooterFrm() ) + pLower = pLower->GetLower(); + // Header gefunden, dann suche den 1.Cntnt-Frame + while( pLower && !pLower->IsCntntFrm() ) + pLower = pLower->GetLower(); + + if( pLower ) + { + SwCursor *pTmpCrsr = getShellCrsr( true ); + SET_CURR_SHELL( this ); + // hole eine Position im Footer + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, + SwCrsrSaveState aSaveState( *pTmpCrsr ); + pLower->Calc(); + Point aPt( pLower->Frm().Pos() + pLower->Prt().Pos() ); + pLower->GetCrsrOfst( pTmpCrsr->GetPoint(), aPt ); + if( !pTmpCrsr->IsSelOvr() ) + UpdateCrsr(); + else + pFrm = 0; + } + else + pFrm = 0; + } + else + pFrm = 0; + return 0 != pFrm; +} + +BOOL SwCrsrShell::SetCrsrInHdFt( USHORT nDescNo, BOOL bInHeader ) +{ + BOOL bRet = FALSE; + SwDoc *pMyDoc = GetDoc(); + + SET_CURR_SHELL( this ); + + if( USHRT_MAX == nDescNo ) + { + // dann den akt. nehmen + const SwPageFrm* pPage = GetCurrFrm()->FindPageFrm(); + if( pPage ) + for( USHORT i = 0; i < pMyDoc->GetPageDescCnt(); ++i ) + if( pPage->GetPageDesc() == + &const_cast<const SwDoc *>(pMyDoc)->GetPageDesc( i ) ) + { + nDescNo = i; + break; + } + } + + if( USHRT_MAX != nDescNo && nDescNo < pMyDoc->GetPageDescCnt() ) + { + //dann teste mal, ob ueberhaupt das Attribut vorhanden ist. + const SwPageDesc& rDesc = const_cast<const SwDoc *>(pMyDoc) + ->GetPageDesc( nDescNo ); + const SwFmtCntnt* pCnt = 0; + if( bInHeader ) + { + // gespiegelte Seiten??? erstmal nicht beachten + const SwFmtHeader& rHd = rDesc.GetMaster().GetHeader(); + if( rHd.GetHeaderFmt() ) + pCnt = &rHd.GetHeaderFmt()->GetCntnt(); + } + else + { + const SwFmtFooter& rFt = rDesc.GetMaster().GetFooter(); + if( rFt.GetFooterFmt() ) + pCnt = &rFt.GetFooterFmt()->GetCntnt(); + } + + if( pCnt && pCnt->GetCntntIdx() ) + { + SwNodeIndex aIdx( *pCnt->GetCntntIdx(), 1 ); + SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode(); + if( !pCNd ) + pCNd = pMyDoc->GetNodes().GoNext( &aIdx ); + + const SwFrm* pFrm; + Point aPt( pCurCrsr->GetPtPos() ); + + if( pCNd && 0 != ( pFrm = pCNd->GetFrm( &aPt, 0, FALSE ) )) + { + // dann kann der Cursor ja auch hinein gesetzt werden + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + SwCrsrSaveState aSaveState( *pCurCrsr ); + + ClearMark(); + + SwPosition& rPos = *pCurCrsr->GetPoint(); + rPos.nNode = *pCNd; + rPos.nContent.Assign( pCNd, 0 ); + + bRet = !pCurCrsr->IsSelOvr(); + if( bRet ) + UpdateCrsr( SwCrsrShell::SCROLLWIN | SwCrsrShell::CHKRANGE | + SwCrsrShell::READONLY ); + } + } + } + return bRet; +} + +// springe zum naechsten Verzeichnis + +BOOL SwCrsrShell::GotoNextTOXBase( const String* pName ) +{ + BOOL bRet = FALSE; + + const SwSectionFmts& rFmts = GetDoc()->GetSections(); + SwCntntNode* pFnd = 0; + for( USHORT n = rFmts.Count(); n; ) + { + const SwSection* pSect = rFmts[ --n ]->GetSection(); + const SwSectionNode* pSectNd; + if( TOX_CONTENT_SECTION == pSect->GetType() && + 0 != ( pSectNd = pSect->GetFmt()->GetSectionNode() ) && + pCurCrsr->GetPoint()->nNode < pSectNd->GetIndex() && + ( !pFnd || pFnd->GetIndex() > pSectNd->GetIndex() ) && +// JP 10.12.96: solange wir nur 3 Typen kennen und UI-seitig keine anderen +// einstellbar sind, muss ueber den Titel gesucht werden! +// ( !pName || *pName == ((SwTOXBaseSection*)pSect)->GetTypeName() ) && + ( !pName || *pName == ((SwTOXBaseSection*)pSect)->GetTOXName() ) + ) + { + SwNodeIndex aIdx( *pSectNd, 1 ); + SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode(); + if( !pCNd ) + pCNd = GetDoc()->GetNodes().GoNext( &aIdx ); + const SwCntntFrm* pCFrm; + if( pCNd && + pCNd->EndOfSectionIndex() <= pSectNd->EndOfSectionIndex() && + 0 != ( pCFrm = pCNd->GetFrm() ) && + ( IsReadOnlyAvailable() || !pCFrm->IsProtected() )) + { + pFnd = pCNd; + } + } + } + if( pFnd ) + { + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, + SwCrsrSaveState aSaveState( *pCurCrsr ); + pCurCrsr->GetPoint()->nNode = *pFnd; + pCurCrsr->GetPoint()->nContent.Assign( pFnd, 0 ); + bRet = !pCurCrsr->IsSelOvr(); + if( bRet ) + UpdateCrsr(SwCrsrShell::SCROLLWIN|SwCrsrShell::CHKRANGE|SwCrsrShell::READONLY); + } + return bRet; +} + +// springe zum vorherigen Verzeichnis + + +BOOL SwCrsrShell::GotoPrevTOXBase( const String* pName ) +{ + BOOL bRet = FALSE; + + const SwSectionFmts& rFmts = GetDoc()->GetSections(); + SwCntntNode* pFnd = 0; + for( USHORT n = rFmts.Count(); n; ) + { + const SwSection* pSect = rFmts[ --n ]->GetSection(); + const SwSectionNode* pSectNd; + if( TOX_CONTENT_SECTION == pSect->GetType() && + 0 != ( pSectNd = pSect->GetFmt()->GetSectionNode() ) && + pCurCrsr->GetPoint()->nNode > pSectNd->EndOfSectionIndex() && + ( !pFnd || pFnd->GetIndex() < pSectNd->GetIndex() ) && +// JP 10.12.96: solange wir nur 3 Typen kennen und UI-seitig keine anderen +// einstellbar sind, muss ueber den Titel gesucht werden! +// ( !pName || *pName == ((SwTOXBaseSection*)pSect)->GetTypeName() ) && + ( !pName || *pName == ((SwTOXBaseSection*)pSect)->GetTOXName() ) + ) + { + SwNodeIndex aIdx( *pSectNd, 1 ); + SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode(); + if( !pCNd ) + pCNd = GetDoc()->GetNodes().GoNext( &aIdx ); + const SwCntntFrm* pCFrm; + if( pCNd && + pCNd->EndOfSectionIndex() <= pSectNd->EndOfSectionIndex() && + 0 != ( pCFrm = pCNd->GetFrm() ) && + ( IsReadOnlyAvailable() || !pCFrm->IsProtected() )) + { + pFnd = pCNd; + } + } + } + + if( pFnd ) + { + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, + SwCrsrSaveState aSaveState( *pCurCrsr ); + pCurCrsr->GetPoint()->nNode = *pFnd; + pCurCrsr->GetPoint()->nContent.Assign( pFnd, 0 ); + bRet = !pCurCrsr->IsSelOvr(); + if( bRet ) + UpdateCrsr(SwCrsrShell::SCROLLWIN|SwCrsrShell::CHKRANGE|SwCrsrShell::READONLY); + } + return bRet; +} + +// springe zum Verzeichnis vom TOXMark + +BOOL SwCrsrShell::GotoTOXMarkBase() +{ + BOOL bRet = FALSE; + + SwTOXMarks aMarks; + USHORT nCnt = GetDoc()->GetCurTOXMark( *pCurCrsr->GetPoint(), aMarks ); + if( nCnt ) + { + // dann nehme den 1. und hole den Verzeichnis-Typ. + // Suche in seiner Abhaengigkeitsliste nach dem eigentlichem + // Verzeichnis + SwModify* pType = (SwModify*)aMarks[0]->GetRegisteredIn(); + SwClientIter aIter( *pType ); + const SwSectionNode* pSectNd; + const SwSectionFmt* pSectFmt; + + for( SwTOXBase* pTOX = + (SwTOXBase*)aIter.First( TYPE( SwTOXBase )); + pTOX; pTOX = (SwTOXBase*)aIter.Next() ) + if( pTOX->ISA( SwTOXBaseSection ) && + 0 != ( pSectFmt = ((SwTOXBaseSection*)pTOX)->GetFmt() ) && + 0 != ( pSectNd = pSectFmt->GetSectionNode() )) + { + SwNodeIndex aIdx( *pSectNd, 1 ); + SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode(); + if( !pCNd ) + pCNd = GetDoc()->GetNodes().GoNext( &aIdx ); + const SwCntntFrm* pCFrm; + if( pCNd && + pCNd->EndOfSectionIndex() < pSectNd->EndOfSectionIndex() && + 0 != ( pCFrm = pCNd->GetFrm() ) && + ( IsReadOnlyAvailable() || !pCFrm->IsProtected() )) + { + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, + SwCrsrSaveState aSaveState( *pCurCrsr ); + pCurCrsr->GetPoint()->nNode = *pCNd; + pCurCrsr->GetPoint()->nContent.Assign( pCNd, 0 ); + bRet = !pCurCrsr->IsInProtectTable() && + !pCurCrsr->IsSelOvr(); + if( bRet ) + UpdateCrsr(SwCrsrShell::SCROLLWIN|SwCrsrShell::CHKRANGE|SwCrsrShell::READONLY); + break; + } + } + } + return bRet; +} + + + // springe zur naechsten (vorherigen) Tabellenformel + // optional auch nur zu kaputten Formeln springen +BOOL SwCrsrShell::GotoNxtPrvTblFormula( BOOL bNext, BOOL bOnlyErrors ) +{ + if( IsTableMode() ) + return FALSE; + + BOOL bFnd = FALSE; + SwPosition& rPos = *pCurCrsr->GetPoint(); + + Point aPt; + SwPosition aFndPos( GetDoc()->GetNodes().GetEndOfContent() ); + if( !bNext ) + aFndPos.nNode = 0; + _SetGetExpFld aFndGEF( aFndPos ), aCurGEF( rPos ); + + { + const SwNode* pSttNd = rPos.nNode.GetNode().FindTableBoxStartNode(); + if( pSttNd ) + { + const SwTableBox* pTBox = pSttNd->FindTableNode()->GetTable(). + GetTblBox( pSttNd->GetIndex() ); + if( pTBox ) + aCurGEF = _SetGetExpFld( *pTBox ); + } + } + + if( rPos.nNode < GetDoc()->GetNodes().GetEndOfExtras() ) + // auch beim Einsammeln wird nur der erste Frame benutzt! + aCurGEF.SetBodyPos( *rPos.nNode.GetNode().GetCntntNode()->GetFrm( + &aPt, &rPos, FALSE ) ); + + { + const SfxPoolItem* pItem; + const SwTableBox* pTBox; + USHORT n, nMaxItems = GetDoc()->GetAttrPool().GetItemCount( RES_BOXATR_FORMULA ); + + for( n = 0; n < nMaxItems; ++n ) + if( 0 != (pItem = GetDoc()->GetAttrPool().GetItem( + RES_BOXATR_FORMULA, n ) ) && + 0 != (pTBox = ((SwTblBoxFormula*)pItem)->GetTableBox() ) && + pTBox->GetSttNd() && + pTBox->GetSttNd()->GetNodes().IsDocNodes() && + ( !bOnlyErrors || + !((SwTblBoxFormula*)pItem)->HasValidBoxes() ) ) + { + const SwCntntFrm* pCFrm; + SwNodeIndex aIdx( *pTBox->GetSttNd() ); + const SwCntntNode* pCNd = GetDoc()->GetNodes().GoNext( &aIdx ); + if( pCNd && 0 != ( pCFrm = pCNd->GetFrm( &aPt, 0, FALSE ) ) && + (IsReadOnlyAvailable() || !pCFrm->IsProtected() )) + { + _SetGetExpFld aCmp( *pTBox ); + aCmp.SetBodyPos( *pCFrm ); + + if( bNext ? ( aCurGEF < aCmp && aCmp < aFndGEF ) + : ( aCmp < aCurGEF && aFndGEF < aCmp )) + { + aFndGEF = aCmp; + bFnd = TRUE; + } + } + } + } + + if( bFnd ) + { + SET_CURR_SHELL( this ); + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + SwCrsrSaveState aSaveState( *pCurCrsr ); + + aFndGEF.GetPosOfContent( rPos ); + pCurCrsr->DeleteMark(); + + bFnd = !pCurCrsr->IsSelOvr(); + if( bFnd ) + UpdateCrsr( SwCrsrShell::SCROLLWIN | SwCrsrShell::CHKRANGE | + SwCrsrShell::READONLY ); + } + return bFnd; +} + +// springe zum naechsten (vorherigen) Verzeichniseintrag +BOOL SwCrsrShell::GotoNxtPrvTOXMark( BOOL bNext ) +{ + if( IsTableMode() ) + return FALSE; + + BOOL bFnd = FALSE; + SwPosition& rPos = *pCurCrsr->GetPoint(); + + Point aPt; + SwPosition aFndPos( GetDoc()->GetNodes().GetEndOfContent() ); + if( !bNext ) + aFndPos.nNode = 0; + _SetGetExpFld aFndGEF( aFndPos ), aCurGEF( rPos ); + + if( rPos.nNode.GetIndex() < GetDoc()->GetNodes().GetEndOfExtras().GetIndex() ) + // auch beim Einsammeln wird nur der erste Frame benutzt! + aCurGEF.SetBodyPos( *rPos.nNode.GetNode(). + GetCntntNode()->GetFrm( &aPt, &rPos, FALSE ) ); + + { + const SfxPoolItem* pItem; + const SwCntntFrm* pCFrm; + const SwTxtNode* pTxtNd; + const SwTxtTOXMark* pTxtTOX; + USHORT n, nMaxItems = GetDoc()->GetAttrPool().GetItemCount( RES_TXTATR_TOXMARK ); + + for( n = 0; n < nMaxItems; ++n ) + if( 0 != (pItem = GetDoc()->GetAttrPool().GetItem( + RES_TXTATR_TOXMARK, n ) ) && + 0 != (pTxtTOX = ((SwTOXMark*)pItem)->GetTxtTOXMark() ) && + ( pTxtNd = &pTxtTOX->GetTxtNode())->GetNodes().IsDocNodes() && + 0 != ( pCFrm = pTxtNd->GetFrm( &aPt, 0, FALSE )) && + ( IsReadOnlyAvailable() || !pCFrm->IsProtected() )) + { + SwNodeIndex aNdIndex( *pTxtNd ); // UNIX benoetigt dieses Obj. + _SetGetExpFld aCmp( aNdIndex, *pTxtTOX, 0 ); + aCmp.SetBodyPos( *pCFrm ); + + if( bNext ? ( aCurGEF < aCmp && aCmp < aFndGEF ) + : ( aCmp < aCurGEF && aFndGEF < aCmp )) + { + aFndGEF = aCmp; + bFnd = TRUE; + } + } + } + + if( bFnd ) + { + SET_CURR_SHELL( this ); + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + SwCrsrSaveState aSaveState( *pCurCrsr ); + + aFndGEF.GetPosOfContent( rPos ); + + bFnd = !pCurCrsr->IsSelOvr(); + if( bFnd ) + UpdateCrsr( SwCrsrShell::SCROLLWIN | SwCrsrShell::CHKRANGE | + SwCrsrShell::READONLY ); + } + return bFnd; +} + +/*-------------------------------------------------------------------- + Beschreibung: Traveling zwischen Markierungen + --------------------------------------------------------------------*/ + +const SwTOXMark& SwCrsrShell::GotoTOXMark( const SwTOXMark& rStart, + SwTOXSearch eDir ) +{ + SET_CURR_SHELL( this ); + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + SwCrsrSaveState aSaveState( *pCurCrsr ); + + const SwTOXMark& rNewMark = GetDoc()->GotoTOXMark( rStart, eDir, + IsReadOnlyAvailable() ); + // Position setzen + SwPosition& rPos = *GetCrsr()->GetPoint(); + rPos.nNode = rNewMark.GetTxtTOXMark()->GetTxtNode(); + rPos.nContent.Assign( rPos.nNode.GetNode().GetCntntNode(), + *rNewMark.GetTxtTOXMark()->GetStart() ); + + if( !pCurCrsr->IsSelOvr() ) + UpdateCrsr( SwCrsrShell::SCROLLWIN | SwCrsrShell::CHKRANGE | + SwCrsrShell::READONLY ); + + return rNewMark; +} + +// springe zum naechsten / vorherigen FeldTypen + +void lcl_MakeFldLst( _SetGetExpFlds& rLst, const SwFieldType& rFldType, + USHORT nSubType, BOOL bInReadOnly, + BOOL bChkInpFlag = FALSE ) +{ + // es muss immer der 1. Frame gesucht werden + Point aPt; + SwTxtFld* pTxtFld; + SwClientIter aIter( (SwFieldType&)rFldType ); + BOOL bSubType = nSubType != USHRT_MAX; + for( SwClient* pLast = aIter.First( TYPE( SwFmtFld )); pLast; pLast = aIter.Next() ) + if( 0 != ( pTxtFld = ((SwFmtFld*)pLast)->GetTxtFld() ) && + ( !bChkInpFlag || ((SwSetExpField*)pTxtFld->GetFld().GetFld()) + ->GetInputFlag() ) && + (!bSubType || (((SwFmtFld*)pLast)->GetFld()->GetSubType() + & 0xff ) == nSubType )) + { + SwCntntFrm* pCFrm; + const SwTxtNode& rTxtNode = pTxtFld->GetTxtNode(); + if( 0 != ( pCFrm = rTxtNode.GetFrm( &aPt, 0, FALSE )) && + ( bInReadOnly || !pCFrm->IsProtected() )) + { + _SetGetExpFld* pNew = new _SetGetExpFld( + SwNodeIndex( rTxtNode ), pTxtFld ); + pNew->SetBodyPos( *pCFrm ); + rLst.Insert( pNew ); + } + } +} + + +BOOL SwCrsrShell::MoveFldType( const SwFieldType* pFldType, BOOL bNext, + USHORT nSubType, USHORT nResType ) +{ + // sortierte Liste aller Felder + _SetGetExpFlds aSrtLst( 64 ); + + if (pFldType) + { + if( RES_INPUTFLD != pFldType->Which() && !pFldType->GetDepends() ) + return FALSE; + + // Modify-Object gefunden, trage alle Felder ins Array ein + ::lcl_MakeFldLst( aSrtLst, *pFldType, nSubType, IsReadOnlyAvailable() ); + + if( RES_INPUTFLD == pFldType->Which() ) + { + // es gibt noch versteckte InputFelder in den SetExp. Feldern + const SwFldTypes& rFldTypes = *pDoc->GetFldTypes(); + const USHORT nSize = rFldTypes.Count(); + + // Alle Typen abklappern + for( USHORT i=0; i < nSize; ++i ) + if( RES_SETEXPFLD == ( pFldType = rFldTypes[ i ] )->Which() ) + ::lcl_MakeFldLst( aSrtLst, *pFldType, nSubType, + IsReadOnlyAvailable(), TRUE ); + } + } + else + { + const SwFldTypes& rFldTypes = *pDoc->GetFldTypes(); + const USHORT nSize = rFldTypes.Count(); + + // Alle Typen abklappern + for( USHORT i=0; i < nSize; ++i ) + if( nResType == ( pFldType = rFldTypes[ i ] )->Which() ) + ::lcl_MakeFldLst( aSrtLst, *pFldType, nSubType, + IsReadOnlyAvailable() ); + } + + // keine Felder gefunden? + if( !aSrtLst.Count() ) + return FALSE; + + USHORT nPos; + SwCursor* pCrsr = getShellCrsr( true ); + { + // JP 19.08.98: es muss immer ueber das Feld gesucht werden, damit + // auch immer das richtige gefunden wird, wenn welche in + // Rahmen stehen, die in einem Absatz verankert sind, + // in dem ein Feld steht - siehe auch Bug 55247 + const SwPosition& rPos = *pCrsr->GetPoint(); + + SwTxtNode* pTNd = rPos.nNode.GetNode().GetTxtNode(); + ASSERT( pTNd, "Wo ist mein CntntNode?" ); + + SwTxtFld * pTxtFld = static_cast<SwTxtFld *>( + pTNd->GetTxtAttrForCharAt(rPos.nContent.GetIndex(), + RES_TXTATR_FIELD)); + BOOL bDelFld = 0 == pTxtFld; + if( bDelFld ) + { + SwFmtFld* pFmtFld = new SwFmtFld( SwDateTimeField( + (SwDateTimeFieldType*)pDoc->GetSysFldType( RES_DATETIMEFLD ) ) ); + + pTxtFld = new SwTxtFld( *pFmtFld, rPos.nContent.GetIndex(), + pDoc->IsClipBoard() ); + pTxtFld->ChgTxtNode( pTNd ); + } + + _SetGetExpFld aSrch( rPos.nNode, pTxtFld, &rPos.nContent ); + if( rPos.nNode.GetIndex() < pDoc->GetNodes().GetEndOfExtras().GetIndex() ) + { + // auch beim Einsammeln wird nur der erste Frame benutzt! + Point aPt; + aSrch.SetBodyPos( *pTNd->GetFrm( &aPt, &rPos, FALSE ) ); + } + + BOOL bFound = aSrtLst.Seek_Entry( &aSrch, &nPos ); + if( bDelFld ) + { + delete (SwFmtFld*)&pTxtFld->GetAttr(); + delete pTxtFld; + } + + if( bFound ) // stehe auf einem ? + { + if( bNext ) + { + if( ++nPos >= aSrtLst.Count() ) + return FALSE; // schon am Ende + } + else if( !nPos-- ) + return FALSE; // weiter nach vorne geht nicht + } + else if( bNext ? nPos >= aSrtLst.Count() : !nPos--) + return FALSE; + } + const _SetGetExpFld& rFnd = **( aSrtLst.GetData() + nPos ); + + + SET_CURR_SHELL( this ); + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + SwCrsrSaveState aSaveState( *pCrsr ); + + rFnd.GetPosOfContent( *pCrsr->GetPoint() ); + BOOL bRet = !pCurCrsr->IsSelOvr( nsSwCursorSelOverFlags::SELOVER_CHECKNODESSECTION | + nsSwCursorSelOverFlags::SELOVER_TOGGLE ); + if( bRet ) + UpdateCrsr(SwCrsrShell::SCROLLWIN|SwCrsrShell::CHKRANGE|SwCrsrShell::READONLY); + return bRet; +} + + +BOOL SwCrsrShell::GotoFld( const SwFmtFld& rFld ) +{ + BOOL bRet = FALSE; + if( rFld.GetTxtFld() ) + { + SET_CURR_SHELL( this ); + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + + SwCursor* pCrsr = getShellCrsr( true ); + SwCrsrSaveState aSaveState( *pCrsr ); + + SwTxtNode* pTNd = (SwTxtNode*)rFld.GetTxtFld()->GetpTxtNode(); + pCrsr->GetPoint()->nNode = *pTNd; + pCrsr->GetPoint()->nContent.Assign( pTNd, *rFld.GetTxtFld()->GetStart() ); + + bRet = !pCrsr->IsSelOvr(); + if( bRet ) + UpdateCrsr(SwCrsrShell::SCROLLWIN|SwCrsrShell::CHKRANGE|SwCrsrShell::READONLY); + } + return bRet; +} + + +void SwCrsrShell::GotoOutline( USHORT nIdx ) +{ + SwCursor* pCrsr = getShellCrsr( true ); + + SET_CURR_SHELL( this ); + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + SwCrsrSaveState aSaveState( *pCrsr ); + + const SwNodes& rNds = GetDoc()->GetNodes(); + SwTxtNode* pTxtNd = (SwTxtNode*)rNds.GetOutLineNds()[ nIdx ]->GetTxtNode(); + pCrsr->GetPoint()->nNode = *pTxtNd; + pCrsr->GetPoint()->nContent.Assign( pTxtNd, 0 ); + + if( !pCrsr->IsSelOvr() ) + UpdateCrsr(SwCrsrShell::SCROLLWIN|SwCrsrShell::CHKRANGE|SwCrsrShell::READONLY); +} + + +BOOL SwCrsrShell::GotoOutline( const String& rName ) +{ + SwCursor* pCrsr = getShellCrsr( true ); + + SET_CURR_SHELL( this ); + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + SwCrsrSaveState aSaveState( *pCrsr ); + + BOOL bRet = FALSE; + if( pDoc->GotoOutline( *pCrsr->GetPoint(), rName ) && !pCrsr->IsSelOvr() ) + { + UpdateCrsr(SwCrsrShell::SCROLLWIN|SwCrsrShell::CHKRANGE|SwCrsrShell::READONLY); + bRet = TRUE; + } + return bRet; +} + + + +BOOL SwCrsrShell::GotoNextOutline() // naechster Node mit Outline-Num. +{ + SwCursor* pCrsr = getShellCrsr( true ); + const SwNodes& rNds = GetDoc()->GetNodes(); + + SwNode* pNd = pCrsr->GetNode(); + USHORT nPos; + if( rNds.GetOutLineNds().Seek_Entry( pNd, &nPos )) + ++nPos; + + if( nPos == rNds.GetOutLineNds().Count() ) + return FALSE; + + pNd = rNds.GetOutLineNds()[ nPos ]; + + SET_CURR_SHELL( this ); + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + SwCrsrSaveState aSaveState( *pCrsr ); + pCrsr->GetPoint()->nNode = *pNd; + pCrsr->GetPoint()->nContent.Assign( (SwTxtNode*)pNd, 0 ); + + BOOL bRet = !pCrsr->IsSelOvr(); + if( bRet ) + UpdateCrsr(SwCrsrShell::SCROLLWIN|SwCrsrShell::CHKRANGE|SwCrsrShell::READONLY); + return bRet; +} + + +BOOL SwCrsrShell::GotoPrevOutline() // vorheriger Node mit Outline-Num. +{ + SwCursor* pCrsr = getShellCrsr( true ); + const SwNodes& rNds = GetDoc()->GetNodes(); + + SwNode* pNd = pCrsr->GetNode(); + USHORT nPos; + rNds.GetOutLineNds().Seek_Entry( pNd, &nPos ); + + BOOL bRet = FALSE; + if( nPos ) + { + --nPos; // davor + + pNd = rNds.GetOutLineNds()[ nPos ]; + if( pNd->GetIndex() > pCrsr->GetPoint()->nNode.GetIndex() ) + return FALSE; + + SET_CURR_SHELL( this ); + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + SwCrsrSaveState aSaveState( *pCrsr ); + pCrsr->GetPoint()->nNode = *pNd; + pCrsr->GetPoint()->nContent.Assign( (SwTxtNode*)pNd, 0 ); + + bRet = !pCrsr->IsSelOvr(); + if( bRet ) + UpdateCrsr(SwCrsrShell::SCROLLWIN|SwCrsrShell::CHKRANGE|SwCrsrShell::READONLY); + } + return bRet; +} + + + // suche die "Outline-Position" vom vorherigen Outline-Node mit dem + // Level. +USHORT SwCrsrShell::GetOutlinePos( BYTE nLevel ) +{ + SwPaM* pCrsr = getShellCrsr( true ); + const SwNodes& rNds = GetDoc()->GetNodes(); + + SwNode* pNd = pCrsr->GetNode(); + USHORT nPos; + if( rNds.GetOutLineNds().Seek_Entry( pNd, &nPos )) + nPos++; // steht auf der Position, fuers while zum Naechsten + + while( nPos-- ) // immer den davor testen ! + { + pNd = rNds.GetOutLineNds()[ nPos ]; + + //if( ((SwTxtNode*)pNd)->GetTxtColl()->GetOutlineLevel() <= nLevel )//#outline level,zhaojianwei + if( ((SwTxtNode*)pNd)->GetAttrOutlineLevel()-1 <= nLevel )//<-end,zhaojianwei + return nPos; + + } + return USHRT_MAX; // davor keiner mehr also Ende +} + + +BOOL SwCrsrShell::MakeOutlineSel( USHORT nSttPos, USHORT nEndPos, + BOOL bWithChilds ) +{ + const SwNodes& rNds = GetDoc()->GetNodes(); + const SwOutlineNodes& rOutlNds = rNds.GetOutLineNds(); + if( !rOutlNds.Count() ) // wie jetzt ??? + return FALSE; + + SET_CURR_SHELL( this ); + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + + if( nSttPos > nEndPos ) // sollte jemand das vertauscht haben? + { + ASSERT( !this, "Start- > Ende-Position im Array" ); + USHORT nTmp = nSttPos; + nSttPos = nEndPos; + nEndPos = nTmp; + } + + SwNode* pSttNd = rOutlNds[ nSttPos ]; + SwNode* pEndNd = rOutlNds[ nEndPos ]; + + if( bWithChilds ) + { + //BYTE nLevel = pEndNd->GetTxtNode()->GetTxtColl()->GetOutlineLevel();//#outline level,zhaojianwei + const int nLevel = pEndNd->GetTxtNode()->GetAttrOutlineLevel()-1;//<-end.zhaojianwei + for( ++nEndPos; nEndPos < rOutlNds.Count(); ++nEndPos ) + { + pEndNd = rOutlNds[ nEndPos ]; + //BYTE nNxtLevel = pEndNd->GetTxtNode()->GetTxtColl()->GetOutlineLevel();//#outline level,zhaojianwei + const int nNxtLevel = pEndNd->GetTxtNode()->GetAttrOutlineLevel()-1;//<-end,zhaojianwei + if( nNxtLevel <= nLevel ) + break; // EndPos steht jetzt auf dem naechsten + } + } + // ohne Childs, dann aber zumindest auf den naechsten + else if( ++nEndPos < rOutlNds.Count() ) + pEndNd = rOutlNds[ nEndPos ]; + + if( nEndPos == rOutlNds.Count() ) // kein Ende gefunden + pEndNd = &rNds.GetEndOfContent(); + + KillPams(); + + SwCrsrSaveState aSaveState( *pCurCrsr ); + + // Jetzt das Ende ans Ende vom voherigen ContentNode setzen + pCurCrsr->GetPoint()->nNode = *pSttNd; + pCurCrsr->GetPoint()->nContent.Assign( pSttNd->GetCntntNode(), 0 ); + pCurCrsr->SetMark(); + pCurCrsr->GetPoint()->nNode = *pEndNd; + pCurCrsr->Move( fnMoveBackward, fnGoNode ); // ans Ende vom Vorgaenger + + // und schon ist alles selektiert + BOOL bRet = !pCurCrsr->IsSelOvr(); + if( bRet ) + UpdateCrsr(SwCrsrShell::SCROLLWIN|SwCrsrShell::CHKRANGE|SwCrsrShell::READONLY); + return bRet; +} + + +// springe zu dieser Refmark +BOOL SwCrsrShell::GotoRefMark( const String& rRefMark, USHORT nSubType, + USHORT nSeqNo ) +{ + SET_CURR_SHELL( this ); + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + SwCrsrSaveState aSaveState( *pCurCrsr ); + + USHORT nPos; + SwTxtNode* pTxtNd = SwGetRefFieldType::FindAnchor( GetDoc(), rRefMark, + nSubType, nSeqNo, &nPos ); + if( pTxtNd && pTxtNd->GetNodes().IsDocNodes() ) + { + pCurCrsr->GetPoint()->nNode = *pTxtNd; + pCurCrsr->GetPoint()->nContent.Assign( pTxtNd, nPos ); + + if( !pCurCrsr->IsSelOvr() ) + { + UpdateCrsr(SwCrsrShell::SCROLLWIN|SwCrsrShell::CHKRANGE|SwCrsrShell::READONLY); + return TRUE; + } + } + return FALSE; +} + +BOOL SwCrsrShell::IsPageAtPos( const Point &rPt ) const +{ + if( GetLayout() ) + return 0 != GetLayout()->GetPageAtPos( rPt ); + return FALSE; +} + +BOOL SwCrsrShell::GetContentAtPos( const Point& rPt, + SwContentAtPos& rCntntAtPos, + BOOL bSetCrsr, + SwRect* pFldRect ) +{ + SET_CURR_SHELL( this ); + BOOL bRet = FALSE; + + if( !IsTableMode() ) + { + Point aPt( rPt ); + SwPosition aPos( *pCurCrsr->GetPoint() ); + + SwTxtNode* pTxtNd; + SwCntntFrm *pFrm(0); + SwTxtAttr* pTxtAttr; + SwCrsrMoveState aTmpState; + aTmpState.bFieldInfo = TRUE; + aTmpState.bExactOnly = !( SwContentAtPos::SW_OUTLINE & rCntntAtPos.eCntntAtPos ); + aTmpState.bCntntCheck = (SwContentAtPos::SW_CONTENT_CHECK & rCntntAtPos.eCntntAtPos) ? TRUE : FALSE; + aTmpState.bSetInReadOnly = IsReadOnlyAvailable(); + + SwSpecialPos aSpecialPos; + aTmpState.pSpecialPos = ( SwContentAtPos::SW_SMARTTAG & rCntntAtPos.eCntntAtPos ) ? + &aSpecialPos : 0; + + const BOOL bCrsrFoundExact = GetLayout()->GetCrsrOfst( &aPos, aPt, &aTmpState ); + pTxtNd = aPos.nNode.GetNode().GetTxtNode(); + + const SwNodes& rNds = GetDoc()->GetNodes(); + if( pTxtNd && SwContentAtPos::SW_OUTLINE & rCntntAtPos.eCntntAtPos + && rNds.GetOutLineNds().Count() ) + { + const SwTxtNode* pONd = pTxtNd->FindOutlineNodeOfLevel( MAXLEVEL-1); + if( pONd ) + { + rCntntAtPos.eCntntAtPos = SwContentAtPos::SW_OUTLINE; + rCntntAtPos.sStr = pONd->GetExpandTxt( 0, STRING_LEN, true ); + bRet = TRUE; + } + } + // --> FME 2005-05-13 #i43742# New function: SW_CONTENT_CHECK + else if ( SwContentAtPos::SW_CONTENT_CHECK & rCntntAtPos.eCntntAtPos && + bCrsrFoundExact ) + { + bRet = TRUE; + } + // <-- + // #i23726# + else if( pTxtNd && + SwContentAtPos::SW_NUMLABEL & rCntntAtPos.eCntntAtPos) + { + bRet = aTmpState.bInNumPortion; + rCntntAtPos.aFnd.pNode = pTxtNd; + + Size aSizeLogic(aTmpState.nInNumPostionOffset, 0); + Size aSizePixel = GetWin()->LogicToPixel(aSizeLogic); + rCntntAtPos.nDist = aSizePixel.Width(); + } + else if( bCrsrFoundExact && pTxtNd ) + { + if( !aTmpState.bPosCorr ) + { + if( !bRet && SwContentAtPos::SW_SMARTTAG & rCntntAtPos.eCntntAtPos + && !aTmpState.bFtnNoInfo ) + { + const SwWrongList* pSmartTagList = pTxtNd->GetSmartTags(); + xub_StrLen nCurrent = aPos.nContent.GetIndex(); + xub_StrLen nBegin = nCurrent; + xub_StrLen nLen = 1; + + if ( pSmartTagList && pSmartTagList->InWrongWord( nCurrent, nLen ) && !pTxtNd->IsSymbol(nBegin) ) + { + const USHORT nIndex = pSmartTagList->GetWrongPos( nBegin ); + const SwWrongList* pSubList = pSmartTagList->SubList( nIndex ); + if ( pSubList ) + { + nCurrent = aTmpState.pSpecialPos->nCharOfst; + + if ( pSubList->InWrongWord( nCurrent, nLen ) ) + bRet = TRUE; + } + else + bRet = TRUE; + + if( bRet && bSetCrsr ) + { + SwCrsrSaveState aSaveState( *pCurCrsr ); + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + pCurCrsr->DeleteMark(); + *pCurCrsr->GetPoint() = aPos; + if( pCurCrsr->IsSelOvr( nsSwCursorSelOverFlags::SELOVER_CHECKNODESSECTION | + nsSwCursorSelOverFlags::SELOVER_TOGGLE) ) + bRet = FALSE; + else + UpdateCrsr(); + } + if( bRet ) + { +// rCntntAtPos.sStr = pTxtNd->GetExpandTxt( +// *pTxtAttr->GetStart(), +// *pTxtAttr->GetEnd() - *pTxtAttr->GetStart(), +// FALSE ); + +// rCntntAtPos.aFnd.pAttr = &pTxtAttr->GetAttr(); + rCntntAtPos.eCntntAtPos = SwContentAtPos::SW_SMARTTAG; +// rCntntAtPos.pFndTxtAttr = pTxtAttr; + + if( pFldRect && 0 != ( pFrm = pTxtNd->GetFrm( &aPt ) ) ) + pFrm->GetCharRect( *pFldRect, aPos, &aTmpState ); + } + } + } + + if( !bRet && ( SwContentAtPos::SW_FIELD | SwContentAtPos::SW_CLICKFIELD ) + & rCntntAtPos.eCntntAtPos && !aTmpState.bFtnNoInfo ) + { + pTxtAttr = pTxtNd->GetTxtAttrForCharAt( + aPos.nContent.GetIndex(), RES_TXTATR_FIELD ); + const SwField* pFld = pTxtAttr + ? pTxtAttr->GetFld().GetFld() + : 0; + if( SwContentAtPos::SW_CLICKFIELD & rCntntAtPos.eCntntAtPos && + pFld && !pFld->HasClickHdl() ) + pFld = 0; + + if( pFld ) + { + if( pFldRect && 0 != ( pFrm = pTxtNd->GetFrm( &aPt ) ) ) + pFrm->GetCharRect( *pFldRect, aPos, &aTmpState ); + + if( bSetCrsr ) + { + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + SwCrsrSaveState aSaveState( *pCurCrsr ); + pCurCrsr->DeleteMark(); + *pCurCrsr->GetPoint() = aPos; + if( pCurCrsr->IsSelOvr() ) + { + // Click-Felder in geschuetzten Bereichen zulassen + // Nur Platzhalter geht nicht! + if( SwContentAtPos::SW_FIELD & rCntntAtPos.eCntntAtPos + || RES_JUMPEDITFLD == pFld->Which() ) + pFld = 0; + } + else + UpdateCrsr(); + } + else if( RES_TABLEFLD == pFld->Which() && + ((SwTblField*)pFld)->IsIntrnlName() ) + { + // erzeuge aus der internen (fuer CORE) + // die externe (fuer UI) Formel + const SwTableNode* pTblNd = pTxtNd->FindTableNode(); + if( pTblNd ) // steht in einer Tabelle + ((SwTblField*)pFld)->PtrToBoxNm( &pTblNd->GetTable() ); + } + } + + if( pFld ) + { + rCntntAtPos.aFnd.pFld = pFld; + rCntntAtPos.pFndTxtAttr = pTxtAttr; + rCntntAtPos.eCntntAtPos = SwContentAtPos::SW_FIELD; + bRet = TRUE; + } + } + + if( !bRet && SwContentAtPos::SW_FORMCTRL & rCntntAtPos.eCntntAtPos ) + { + IDocumentMarkAccess* pMarksAccess = GetDoc()->getIDocumentMarkAccess( ); + sw::mark::IFieldmark* pFldBookmark = pMarksAccess->getFieldmarkFor( aPos ); + if( bCrsrFoundExact && pTxtNd && pFldBookmark) { + rCntntAtPos.eCntntAtPos = SwContentAtPos::SW_FORMCTRL; + rCntntAtPos.aFnd.pFldmark = pFldBookmark; + bRet=TRUE; + } + } + + if( !bRet && SwContentAtPos::SW_FTN & rCntntAtPos.eCntntAtPos ) + { + if( aTmpState.bFtnNoInfo ) + { + // stehe ueber dem Zeichen der Fussnote (??) + bRet = TRUE; + if( bSetCrsr ) + { + *pCurCrsr->GetPoint() = aPos; + if( !GotoFtnAnchor() ) + bRet = FALSE; + } + if( bRet ) + rCntntAtPos.eCntntAtPos = SwContentAtPos::SW_FTN; + } + else if ( 0 != ( pTxtAttr = pTxtNd->GetTxtAttrForCharAt( + aPos.nContent.GetIndex(), RES_TXTATR_FTN )) ) + { + bRet = TRUE; + if( bSetCrsr ) + { + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, + SwCrsrSaveState aSaveState( *pCurCrsr ); + pCurCrsr->GetPoint()->nNode = *((SwTxtFtn*)pTxtAttr)->GetStartNode(); + SwCntntNode* pCNd = GetDoc()->GetNodes().GoNextSection( + &pCurCrsr->GetPoint()->nNode, + TRUE, !IsReadOnlyAvailable() ); + + if( pCNd ) + { + pCurCrsr->GetPoint()->nContent.Assign( pCNd, 0 ); + if( pCurCrsr->IsSelOvr( nsSwCursorSelOverFlags::SELOVER_CHECKNODESSECTION | + nsSwCursorSelOverFlags::SELOVER_TOGGLE )) + bRet = FALSE; + else + UpdateCrsr(); + } + else + bRet = FALSE; + } + + if( bRet ) + { + rCntntAtPos.eCntntAtPos = SwContentAtPos::SW_FTN; + rCntntAtPos.pFndTxtAttr = pTxtAttr; + rCntntAtPos.aFnd.pAttr = &pTxtAttr->GetAttr(); + + if( pFldRect && 0 != ( pFrm = pTxtNd->GetFrm( &aPt ) ) ) + pFrm->GetCharRect( *pFldRect, aPos, &aTmpState ); + } + } + } + + if( !bRet && ( SwContentAtPos::SW_TOXMARK | + SwContentAtPos::SW_REFMARK ) & + rCntntAtPos.eCntntAtPos && !aTmpState.bFtnNoInfo ) + { + pTxtAttr = 0; + if( SwContentAtPos::SW_TOXMARK & rCntntAtPos.eCntntAtPos ) + { + ::std::vector<SwTxtAttr *> const marks( + pTxtNd->GetTxtAttrsAt( + aPos.nContent.GetIndex(), RES_TXTATR_TOXMARK)); + if (marks.size()) + { // hmm... can only return 1 here + pTxtAttr = *marks.begin(); + } + } + + if( !pTxtAttr && + SwContentAtPos::SW_REFMARK & rCntntAtPos.eCntntAtPos ) + { + ::std::vector<SwTxtAttr *> const marks( + pTxtNd->GetTxtAttrsAt( + aPos.nContent.GetIndex(), RES_TXTATR_REFMARK)); + if (marks.size()) + { // hmm... can only return 1 here + pTxtAttr = *marks.begin(); + } + } + + if( pTxtAttr ) + { + bRet = TRUE; + if( bSetCrsr ) + { + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, + SwCrsrSaveState aSaveState( *pCurCrsr ); + pCurCrsr->DeleteMark(); + *pCurCrsr->GetPoint() = aPos; + if( pCurCrsr->IsSelOvr( nsSwCursorSelOverFlags::SELOVER_CHECKNODESSECTION | + nsSwCursorSelOverFlags::SELOVER_TOGGLE ) ) + bRet = FALSE; + else + UpdateCrsr(); + } + + if( bRet ) + { + const xub_StrLen* pEnd = pTxtAttr->GetEnd(); + if( pEnd ) + rCntntAtPos.sStr = pTxtNd->GetExpandTxt( + *pTxtAttr->GetStart(), + *pEnd - *pTxtAttr->GetStart() ); + else if( RES_TXTATR_TOXMARK == pTxtAttr->Which()) + rCntntAtPos.sStr = pTxtAttr->GetTOXMark(). + GetAlternativeText(); + + rCntntAtPos.eCntntAtPos = + RES_TXTATR_TOXMARK == pTxtAttr->Which() + ? SwContentAtPos::SW_TOXMARK + : SwContentAtPos::SW_REFMARK; + rCntntAtPos.pFndTxtAttr = pTxtAttr; + rCntntAtPos.aFnd.pAttr = &pTxtAttr->GetAttr(); + + if( pFldRect && 0 != ( pFrm = pTxtNd->GetFrm( &aPt ) ) ) + pFrm->GetCharRect( *pFldRect, aPos, &aTmpState ); + } + } + } + + if( !bRet && SwContentAtPos::SW_INETATTR & rCntntAtPos.eCntntAtPos + && !aTmpState.bFtnNoInfo ) + { + pTxtAttr = pTxtNd->GetTxtAttrAt( + aPos.nContent.GetIndex(), RES_TXTATR_INETFMT); + // nur INetAttrs mit URLs "erkennen" + if( pTxtAttr && pTxtAttr->GetINetFmt().GetValue().Len() ) + { + bRet = TRUE; + if( bSetCrsr ) + { + SwCrsrSaveState aSaveState( *pCurCrsr ); + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + pCurCrsr->DeleteMark(); + *pCurCrsr->GetPoint() = aPos; + if( pCurCrsr->IsSelOvr( nsSwCursorSelOverFlags::SELOVER_CHECKNODESSECTION | + nsSwCursorSelOverFlags::SELOVER_TOGGLE) ) + bRet = FALSE; + else + UpdateCrsr(); + } + if( bRet ) + { + rCntntAtPos.sStr = pTxtNd->GetExpandTxt( + *pTxtAttr->GetStart(), + *pTxtAttr->GetEnd() - *pTxtAttr->GetStart() ); + + rCntntAtPos.aFnd.pAttr = &pTxtAttr->GetAttr(); + rCntntAtPos.eCntntAtPos = SwContentAtPos::SW_INETATTR; + rCntntAtPos.pFndTxtAttr = pTxtAttr; + + if( pFldRect && 0 != ( pFrm = pTxtNd->GetFrm( &aPt ) ) ) + pFrm->GetCharRect( *pFldRect, aPos, &aTmpState ); + } + } + } + + if( !bRet && SwContentAtPos::SW_REDLINE & rCntntAtPos.eCntntAtPos ) + { + const SwRedline* pRedl = GetDoc()->GetRedline(aPos, NULL); + if( pRedl ) + { + rCntntAtPos.aFnd.pRedl = pRedl; + rCntntAtPos.eCntntAtPos = SwContentAtPos::SW_REDLINE; + rCntntAtPos.pFndTxtAttr = 0; + bRet = TRUE; + + if( pFldRect && 0 != ( pFrm = pTxtNd->GetFrm( &aPt ) ) ) + pFrm->GetCharRect( *pFldRect, aPos, &aTmpState ); + } + } + } + + if( !bRet && ( + SwContentAtPos::SW_TABLEBOXFML & rCntntAtPos.eCntntAtPos +#ifdef DBG_UTIL + || SwContentAtPos::SW_TABLEBOXVALUE & rCntntAtPos.eCntntAtPos +#endif + )) + { + const SwTableNode* pTblNd; + const SwTableBox* pBox; + const SwStartNode* pSttNd = pTxtNd->FindTableBoxStartNode(); + const SfxPoolItem* pItem; + if( pSttNd && 0 != ( pTblNd = pTxtNd->FindTableNode()) && + 0 != ( pBox = pTblNd->GetTable().GetTblBox( + pSttNd->GetIndex() )) && +#ifdef DBG_UTIL + ( SFX_ITEM_SET == pBox->GetFrmFmt()->GetItemState( + RES_BOXATR_FORMULA, FALSE, &pItem ) || + SFX_ITEM_SET == pBox->GetFrmFmt()->GetItemState( + RES_BOXATR_VALUE, FALSE, &pItem )) +#else + SFX_ITEM_SET == pBox->GetFrmFmt()->GetItemState( + RES_BOXATR_FORMULA, FALSE, &pItem ) +#endif + ) + { + SwFrm* pF = pTxtNd->GetFrm( &aPt ); + if( pF ) + { + // dann aber den CellFrame + pFrm = (SwCntntFrm*)pF; + while( pF && !pF->IsCellFrm() ) + pF = pF->GetUpper(); + } + + // es wurde ein + if( aTmpState.bPosCorr ) + { + if( pF && !pF->Frm().IsInside( aPt )) + pF = 0; + } + else if( !pF ) + pF = pFrm; + + if( pF ) // nur dann ist es gueltig!! + { + // erzeuge aus der internen (fuer CORE) + // die externe (fuer UI) Formel + rCntntAtPos.eCntntAtPos = SwContentAtPos::SW_TABLEBOXFML; +#ifdef DBG_UTIL + if( RES_BOXATR_VALUE == pItem->Which() ) + rCntntAtPos.eCntntAtPos = SwContentAtPos::SW_TABLEBOXVALUE; + else +#endif + ((SwTblBoxFormula*)pItem)->PtrToBoxNm( &pTblNd->GetTable() ); + + bRet = TRUE; + if( bSetCrsr ) + { + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, + SwCrsrSaveState aSaveState( *pCurCrsr ); + *pCurCrsr->GetPoint() = aPos; + if( pCurCrsr->IsSelOvr( nsSwCursorSelOverFlags::SELOVER_CHECKNODESSECTION | + nsSwCursorSelOverFlags::SELOVER_TOGGLE) ) + bRet = FALSE; + else + UpdateCrsr(); + } + + if( bRet ) + { + if( pFldRect ) + { + *pFldRect = pF->Prt(); + *pFldRect += pF->Frm().Pos(); + } + rCntntAtPos.pFndTxtAttr = 0; + rCntntAtPos.aFnd.pAttr = pItem; + } + } + } + } + +#ifdef DBG_UTIL + if( !bRet && SwContentAtPos::SW_CURR_ATTRS & rCntntAtPos.eCntntAtPos ) + { + xub_StrLen n = aPos.nContent.GetIndex(); + SfxItemSet aSet( GetDoc()->GetAttrPool(), POOLATTR_BEGIN, + POOLATTR_END - 1 ); + if( pTxtNd->GetpSwpHints() ) + { + for( USHORT i = 0; i < pTxtNd->GetSwpHints().Count(); ++i ) + { + const SwTxtAttr* pHt = pTxtNd->GetSwpHints()[i]; + xub_StrLen nAttrStart = *pHt->GetStart(); + if( nAttrStart > n ) // ueber den Bereich hinaus + break; + + if( 0 != pHt->GetEnd() && ( + ( nAttrStart < n && + ( pHt->DontExpand() ? n < *pHt->GetEnd() + : n <= *pHt->GetEnd() )) || + ( n == nAttrStart && + ( nAttrStart == *pHt->GetEnd() || !n ))) ) + { + aSet.Put( pHt->GetAttr() ); + } + } + if( pTxtNd->HasSwAttrSet() && + pTxtNd->GetpSwAttrSet()->Count() ) + { + SfxItemSet aFmtSet( pTxtNd->GetSwAttrSet() ); + // aus dem Format-Set alle entfernen, die im TextSet auch gesetzt sind + aFmtSet.Differentiate( aSet ); + // jetzt alle zusammen "mergen" + aSet.Put( aFmtSet ); + } + } + else + pTxtNd->SwCntntNode::GetAttr( aSet ); + + rCntntAtPos.sStr.AssignAscii( + RTL_CONSTASCII_STRINGPARAM( "Pos: (" )); + rCntntAtPos.sStr += String::CreateFromInt32( aPos.nNode.GetIndex()); + rCntntAtPos.sStr += ':'; + rCntntAtPos.sStr += String::CreateFromInt32( aPos.nContent.GetIndex()); + rCntntAtPos.sStr += ')'; + rCntntAtPos.sStr.AppendAscii( + RTL_CONSTASCII_STRINGPARAM( "\nAbs.Vorl.: " )); + rCntntAtPos.sStr += pTxtNd->GetFmtColl()->GetName(); + if( pTxtNd->GetCondFmtColl() ) + rCntntAtPos.sStr.AppendAscii( + RTL_CONSTASCII_STRINGPARAM( "\nBed.Vorl.: " )) + += pTxtNd->GetCondFmtColl()->GetName(); + + if( aSet.Count() ) + { + String sAttrs; + SfxItemIter aIter( aSet ); + const SfxPoolItem* pItem = aIter.FirstItem(); + while( TRUE ) + { + if( !IsInvalidItem( pItem )) + { + String aStr; + GetDoc()->GetAttrPool().GetPresentation( *pItem, + SFX_ITEM_PRESENTATION_COMPLETE, + SFX_MAPUNIT_CM, aStr ); + if( sAttrs.Len() ) + sAttrs.AppendAscii( + RTL_CONSTASCII_STRINGPARAM( ", " )); + sAttrs += aStr; + } + if( aIter.IsAtEnd() ) + break; + pItem = aIter.NextItem(); + } + if( sAttrs.Len() ) + { + if( rCntntAtPos.sStr.Len() ) + rCntntAtPos.sStr += '\n'; + rCntntAtPos.sStr.AppendAscii( + RTL_CONSTASCII_STRINGPARAM( "Attr: " ) ) + += sAttrs; + } + } + bRet = TRUE; + rCntntAtPos.eCntntAtPos = SwContentAtPos::SW_CURR_ATTRS; + } +#endif + } + } + + if( !bRet ) + { + rCntntAtPos.eCntntAtPos = SwContentAtPos::SW_NOTHING; + rCntntAtPos.aFnd.pFld = 0; + } + return bRet; +} + +// --> OD 2008-06-19 #i90516# +const SwPostItField* SwCrsrShell::GetPostItFieldAtCursor() const +{ + const SwPostItField* pPostItFld = 0; + + if ( !IsTableMode() ) + { + const SwPosition* pCursorPos = _GetCrsr()->GetPoint(); + const SwTxtNode* pTxtNd = pCursorPos->nNode.GetNode().GetTxtNode(); + if ( pTxtNd ) + { + SwTxtAttr* pTxtAttr = pTxtNd->GetTxtAttrForCharAt( + pCursorPos->nContent.GetIndex(), RES_TXTATR_FIELD ); + const SwField* pFld = pTxtAttr ? pTxtAttr->GetFld().GetFld() : 0; + if ( pFld && pFld->Which()== RES_POSTITFLD ) + { + pPostItFld = static_cast<const SwPostItField*>(pFld); + } + } + } + + return pPostItFld; +} +// <-- + +// befindet sich der Node in einem geschuetzten Bereich? +BOOL SwContentAtPos::IsInProtectSect() const +{ + const SwTxtNode* pNd = 0; + if( pFndTxtAttr ) + { + switch( eCntntAtPos ) + { + case SW_FIELD: + case SW_CLICKFIELD: + pNd = ((SwTxtFld*)pFndTxtAttr)->GetpTxtNode(); + break; + + case SW_FTN: + pNd = &((SwTxtFtn*)pFndTxtAttr)->GetTxtNode(); + break; + + case SW_INETATTR: + pNd = ((SwTxtINetFmt*)pFndTxtAttr)->GetpTxtNode(); + break; + + default: + break; + } + } + + const SwCntntFrm* pFrm; + return pNd && ( pNd->IsInProtectSect() || + ( 0 != ( pFrm = pNd->GetFrm(0,0,FALSE)) && + pFrm->IsProtected() )); +} +bool SwContentAtPos::IsInRTLText()const +{ + bool bRet = false; + const SwTxtNode* pNd = 0; + if (pFndTxtAttr && (eCntntAtPos == SW_FTN)) + { + const SwTxtFtn* pTxtFtn = static_cast<const SwTxtFtn*>(pFndTxtAttr); + if(pTxtFtn->GetStartNode()) + { + SwStartNode* pSttNd = pTxtFtn->GetStartNode()->GetNode().GetStartNode(); + SwPaM aTemp( *pSttNd ); + aTemp.Move(fnMoveForward, fnGoNode); + SwCntntNode* pCntntNode = aTemp.GetCntntNode(); + if(pCntntNode && pCntntNode->IsTxtNode()) + pNd = static_cast<SwTxtNode*>(pCntntNode); + } + } + if(pNd) + { + SwClientIter aClientIter( * const_cast<SwTxtNode*>(pNd) ); + SwClient* pLast = aClientIter.GoStart(); + while( pLast ) + { + if ( pLast->ISA( SwTxtFrm ) ) + { + SwTxtFrm* pTmpFrm = static_cast<SwTxtFrm*>( pLast ); + if ( !pTmpFrm->IsFollow()) + { + bRet = pTmpFrm->IsRightToLeft(); + break; + } + } + pLast = ++aClientIter; + } + } + return bRet; +} + +BOOL SwCrsrShell::SelectTxtAttr( USHORT nWhich, BOOL bExpand, + const SwTxtAttr* pTxtAttr ) +{ + SET_CURR_SHELL( this ); + BOOL bRet = FALSE; + + if( !IsTableMode() ) + { + SwPosition& rPos = *pCurCrsr->GetPoint(); + if( !pTxtAttr ) + { + SwTxtNode* pTxtNd = rPos.nNode.GetNode().GetTxtNode(); + pTxtAttr = (pTxtNd) + ? pTxtNd->GetTxtAttrAt(rPos.nContent.GetIndex(), + static_cast<RES_TXTATR>(nWhich), + (bExpand) ? SwTxtNode::EXPAND : SwTxtNode::DEFAULT) + : 0; + } + + if( pTxtAttr ) + { + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, + SwCrsrSaveState aSaveState( *pCurCrsr ); + + pCurCrsr->DeleteMark(); + rPos.nContent = *pTxtAttr->GetStart(); + pCurCrsr->SetMark(); + const xub_StrLen* pEnd = pTxtAttr->GetEnd(); + rPos.nContent = pEnd ? *pEnd : *pTxtAttr->GetStart() + 1; + + if( !pCurCrsr->IsSelOvr() ) + { + UpdateCrsr(); + bRet = TRUE; + } + } + } + return bRet; +} + + +BOOL SwCrsrShell::GotoINetAttr( const SwTxtINetFmt& rAttr ) +{ + BOOL bRet = FALSE; + if( rAttr.GetpTxtNode() ) + { + SwCursor* pCrsr = getShellCrsr( true ); + + SET_CURR_SHELL( this ); + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + SwCrsrSaveState aSaveState( *pCrsr ); + + pCrsr->GetPoint()->nNode = *rAttr.GetpTxtNode(); + pCrsr->GetPoint()->nContent.Assign( (SwTxtNode*)rAttr.GetpTxtNode(), + *rAttr.GetStart() ); + bRet = !pCrsr->IsSelOvr(); + if( bRet ) + UpdateCrsr(SwCrsrShell::SCROLLWIN|SwCrsrShell::CHKRANGE|SwCrsrShell::READONLY); + } + return bRet; +} + + +const SwFmtINetFmt* SwCrsrShell::FindINetAttr( const String& rName ) const +{ + return pDoc->FindINetAttr( rName ); +} + +BOOL SwCrsrShell::GetShadowCrsrPos( const Point& rPt, SwFillMode eFillMode, + SwRect& rRect, sal_Int16& rOrient ) +{ + + SET_CURR_SHELL( this ); + BOOL bRet = FALSE; + + if( !IsTableMode() && !HasSelection() && GetDoc()->DoesUndo() ) + { + Point aPt( rPt ); + SwPosition aPos( *pCurCrsr->GetPoint() ); + + SwFillCrsrPos aFPos( eFillMode ); + SwCrsrMoveState aTmpState( &aFPos ); + + if( GetLayout()->GetCrsrOfst( &aPos, aPt, &aTmpState ) && + !aPos.nNode.GetNode().IsProtect()) + { + // Start-Position im geschuetzten Bereich? + rRect = aFPos.aCrsr; + rOrient = aFPos.eOrient; + bRet = TRUE; + } + } + return bRet; +} + +BOOL SwCrsrShell::SetShadowCrsrPos( const Point& rPt, SwFillMode eFillMode ) +{ + SET_CURR_SHELL( this ); + BOOL bRet = FALSE; + + if( !IsTableMode() && !HasSelection() && GetDoc()->DoesUndo() ) + { + Point aPt( rPt ); + SwPosition aPos( *pCurCrsr->GetPoint() ); + + SwFillCrsrPos aFPos( eFillMode ); + SwCrsrMoveState aTmpState( &aFPos ); + + if( GetLayout()->GetCrsrOfst( &aPos, aPt, &aTmpState ) ) + { + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen + StartAction(); + + SwCntntNode* pCNd = aPos.nNode.GetNode().GetCntntNode(); + SwUndoId nUndoId = UNDO_INS_FROM_SHADOWCRSR; + // Werden nur die Absatzattribute Adjust oder LRSpace gesetzt, + // dann sollte der naechste Aufruf die NICHT wieder entfernen. + if( 0 == aFPos.nParaCnt + aFPos.nColumnCnt && + ( FILL_INDENT == aFPos.eMode || + ( text::HoriOrientation::NONE != aFPos.eOrient && + 0 == aFPos.nTabCnt + aFPos.nSpaceCnt )) && + pCNd && pCNd->Len() ) + nUndoId = UNDO_EMPTY; + + GetDoc()->StartUndo( nUndoId, NULL ); + + SwTxtFmtColl* pNextFmt = 0; + SwTxtNode* pTNd = pCNd->GetTxtNode(); + if( pTNd ) + pNextFmt = &pTNd->GetTxtColl()->GetNextTxtFmtColl(); + + const SwSectionNode* pSectNd = pCNd->FindSectionNode(); + if( pSectNd && aFPos.nParaCnt ) + { + SwNodeIndex aEnd( aPos.nNode, 1 ); + while( aEnd.GetNode().IsEndNode() && + (const SwNode*)&aEnd.GetNode() != + pSectNd->EndOfSectionNode() ) + aEnd++; + + if( aEnd.GetNode().IsEndNode() && + pCNd->Len() == aPos.nContent.GetIndex() ) + aPos.nNode = *pSectNd->EndOfSectionNode(); + } + + for( USHORT n = 0; n < aFPos.nParaCnt + aFPos.nColumnCnt; ++n ) + { + GetDoc()->AppendTxtNode( aPos ); + if( !n && pNextFmt ) + { + *pCurCrsr->GetPoint() = aPos; + GetDoc()->SetTxtFmtColl( *pCurCrsr, pNextFmt, false ); + //JP 04.11.97: erstmal keine Folgevorlage der + // Folgevorlage beachten + // pNextFmt = pNextFmt->GetNextTxtFmtColl(); + } + if( n < aFPos.nColumnCnt ) + { + *pCurCrsr->GetPoint() = aPos; + GetDoc()->InsertPoolItem( *pCurCrsr, + SvxFmtBreakItem( SVX_BREAK_COLUMN_BEFORE, RES_BREAK ), 0); + } + } + + *pCurCrsr->GetPoint() = aPos; + switch( aFPos.eMode ) + { + case FILL_INDENT: + if( 0 != (pCNd = aPos.nNode.GetNode().GetCntntNode() )) + { + SfxItemSet aSet( GetDoc()->GetAttrPool(), + RES_LR_SPACE, RES_LR_SPACE, + RES_PARATR_ADJUST, RES_PARATR_ADJUST, + 0 ); + SvxLRSpaceItem aLR( (SvxLRSpaceItem&) + pCNd->GetAttr( RES_LR_SPACE ) ); + aLR.SetTxtLeft( aFPos.nTabCnt ); + aLR.SetTxtFirstLineOfst( 0 ); + aSet.Put( aLR ); + + const SvxAdjustItem& rAdj = (SvxAdjustItem&)pCNd-> + GetAttr( RES_PARATR_ADJUST ); + if( SVX_ADJUST_LEFT != rAdj.GetAdjust() ) + aSet.Put( SvxAdjustItem( SVX_ADJUST_LEFT, RES_PARATR_ADJUST ) ); + + GetDoc()->InsertItemSet( *pCurCrsr, aSet, 0 ); + } + else { + ASSERT( !this, "wo ist mein CntntNode?" ); + } + break; + + case FILL_TAB: + case FILL_SPACE: + { + String sInsert; + if( aFPos.nTabCnt ) + sInsert.Fill( aFPos.nTabCnt, '\t' ); + if( aFPos.nSpaceCnt ) + { + String sSpace; + sSpace.Fill( aFPos.nSpaceCnt ); + sInsert += sSpace; + } + if( sInsert.Len() ) + { + GetDoc()->InsertString( *pCurCrsr, sInsert ); + } + } + // kein break - Ausrichtung muss noch gesetzt werden + case FILL_MARGIN: + if( text::HoriOrientation::NONE != aFPos.eOrient ) + { + SvxAdjustItem aAdj( SVX_ADJUST_LEFT, RES_PARATR_ADJUST ); + switch( aFPos.eOrient ) + { + case text::HoriOrientation::CENTER: + aAdj.SetAdjust( SVX_ADJUST_CENTER ); + break; + case text::HoriOrientation::RIGHT: + aAdj.SetAdjust( SVX_ADJUST_RIGHT ); + break; + default: + break; + } + GetDoc()->InsertPoolItem( *pCurCrsr, aAdj, 0 ); + } + break; + } + + GetDoc()->EndUndo( nUndoId, NULL ); + EndAction(); + + bRet = TRUE; + } + } + return bRet; +} + +const SwRedline* SwCrsrShell::SelNextRedline() +{ + const SwRedline* pFnd = 0; + if( !IsTableMode() ) + { + SET_CURR_SHELL( this ); + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + SwCrsrSaveState aSaveState( *pCurCrsr ); + + pFnd = GetDoc()->SelNextRedline( *pCurCrsr ); + if( pFnd && !pCurCrsr->IsInProtectTable() && !pCurCrsr->IsSelOvr() ) + UpdateCrsr( SwCrsrShell::SCROLLWIN|SwCrsrShell::CHKRANGE|SwCrsrShell::READONLY); + else + pFnd = 0; + } + return pFnd; +} + +const SwRedline* SwCrsrShell::SelPrevRedline() +{ + const SwRedline* pFnd = 0; + if( !IsTableMode() ) + { + SET_CURR_SHELL( this ); + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + SwCrsrSaveState aSaveState( *pCurCrsr ); + + pFnd = GetDoc()->SelPrevRedline( *pCurCrsr ); + if( pFnd && !pCurCrsr->IsInProtectTable() && !pCurCrsr->IsSelOvr() ) + UpdateCrsr( SwCrsrShell::SCROLLWIN|SwCrsrShell::CHKRANGE|SwCrsrShell::READONLY); + else + pFnd = 0; + } + return pFnd; +} + +const SwRedline* SwCrsrShell::_GotoRedline( USHORT nArrPos, BOOL bSelect ) +{ + const SwRedline* pFnd = 0; + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + SwCrsrSaveState aSaveState( *pCurCrsr ); + + pFnd = GetDoc()->GetRedlineTbl()[ nArrPos ]; + if( pFnd ) + { + *pCurCrsr->GetPoint() = *pFnd->Start(); + + SwCntntNode* pCNd; + SwNodeIndex* pIdx = &pCurCrsr->GetPoint()->nNode; + if( !pIdx->GetNode().IsCntntNode() && + 0 != ( pCNd = GetDoc()->GetNodes().GoNextSection( pIdx, + TRUE, IsReadOnlyAvailable() )) ) + { + if( *pIdx <= pFnd->End()->nNode ) + pCurCrsr->GetPoint()->nContent.Assign( pCNd, 0 ); + else + pFnd = 0; + } + + if( pFnd && bSelect ) + { + pCurCrsr->SetMark(); + if( nsRedlineType_t::REDLINE_FMTCOLL == pFnd->GetType() ) + { + pCNd = pIdx->GetNode().GetCntntNode(); + pCurCrsr->GetPoint()->nContent.Assign( pCNd, pCNd->Len() ); + pCurCrsr->GetMark()->nContent.Assign( pCNd, 0 ); + } + else + *pCurCrsr->GetPoint() = *pFnd->End(); + + pIdx = &pCurCrsr->GetPoint()->nNode; + if( !pIdx->GetNode().IsCntntNode() && + 0 != ( pCNd = GetDoc()->GetNodes().GoPrevSection( pIdx, + TRUE, IsReadOnlyAvailable() )) ) + { + if( *pIdx >= pCurCrsr->GetMark()->nNode ) + pCurCrsr->GetPoint()->nContent.Assign( pCNd, pCNd->Len() ); + else + pFnd = 0; + } + } + + if( !pFnd ) + { + pCurCrsr->DeleteMark(); + pCurCrsr->RestoreSavePos(); + } + else if( bSelect && *pCurCrsr->GetMark() == *pCurCrsr->GetPoint() ) + pCurCrsr->DeleteMark(); + + if( pFnd && !pCurCrsr->IsInProtectTable() && !pCurCrsr->IsSelOvr() ) + UpdateCrsr( SwCrsrShell::SCROLLWIN | SwCrsrShell::CHKRANGE + | SwCrsrShell::READONLY ); + else + { + pFnd = 0; + if( bSelect ) + pCurCrsr->DeleteMark(); + } + } + return pFnd; +} + +const SwRedline* SwCrsrShell::GotoRedline( USHORT nArrPos, BOOL bSelect ) +{ + const SwRedline* pFnd = 0; + if( !IsTableMode() ) + { + SET_CURR_SHELL( this ); + + const SwRedlineTbl& rTbl = GetDoc()->GetRedlineTbl(); + const SwRedline* pTmp = rTbl[ nArrPos ]; + USHORT nSeqNo = pTmp->GetSeqNo(); + if( nSeqNo && bSelect ) + { + BOOL bCheck = FALSE; + int nLoopCnt = 2; + USHORT nArrSavPos = nArrPos; + + do { + pTmp = _GotoRedline( nArrPos, TRUE ); + + if( !pFnd ) + pFnd = pTmp; + + if( pTmp && bCheck ) + { + // checke auf Ueberlappungen. Das kann durch + // FmtColl-Redlines kommen, die auf den gesamten Absatz + // aus gedehnt werden. + + SwPaM* pCur = pCurCrsr; + SwPaM* pNextPam = (SwPaM*)pCur->GetNext(); + SwPosition* pCStt = pCur->Start(), *pCEnd = pCur->End(); + while( pCur != pNextPam ) + { + const SwPosition *pNStt = pNextPam->Start(), + *pNEnd = pNextPam->End(); + + BOOL bDel = TRUE; + switch( ::ComparePosition( *pCStt, *pCEnd, + *pNStt, *pNEnd )) + { + case POS_INSIDE: // Pos1 liegt vollstaendig in Pos2 + if( !pCur->HasMark() ) + { + pCur->SetMark(); + *pCur->GetMark() = *pNStt; + } + else + *pCStt = *pNStt; + *pCEnd = *pNEnd; + break; + + case POS_OUTSIDE: // Pos2 liegt vollstaendig in Pos1 + case POS_EQUAL: // Pos1 ist genauso gross wie Pos2 + break; + + case POS_OVERLAP_BEFORE: // Pos1 ueberlappt Pos2 am Anfang + if( !pCur->HasMark() ) + pCur->SetMark(); + *pCEnd = *pNEnd; + break; + case POS_OVERLAP_BEHIND: // Pos1 ueberlappt Pos2 am Ende + if( !pCur->HasMark() ) + { + pCur->SetMark(); + *pCur->GetMark() = *pNStt; + } + else + *pCStt = *pNStt; + break; + + default: + bDel = FALSE; + } + + if( bDel ) + { + // den brauchen wir nicht mehr + SwPaM* pPrevPam = (SwPaM*)pNextPam->GetPrev(); + delete pNextPam; + pNextPam = pPrevPam; + } + pNextPam = (SwPaM*)pNextPam->GetNext(); + } + } + + USHORT nFndPos = 2 == nLoopCnt + ? rTbl.FindNextOfSeqNo( nArrPos ) + : rTbl.FindPrevOfSeqNo( nArrPos ); + if( USHRT_MAX != nFndPos || + ( 0 != ( --nLoopCnt ) && USHRT_MAX != ( + nFndPos = rTbl.FindPrevOfSeqNo( nArrSavPos ))) ) + { + if( pTmp ) + { + // neuen Cursor erzeugen + CreateCrsr(); + bCheck = TRUE; + } + nArrPos = nFndPos; + } + else + nLoopCnt = 0; + + } while( nLoopCnt ); + } + else + pFnd = _GotoRedline( nArrPos, bSelect ); + } + return pFnd; +} + + +BOOL SwCrsrShell::SelectNxtPrvHyperlink( BOOL bNext ) +{ + SwNodes& rNds = GetDoc()->GetNodes(); + const SwNode* pBodyEndNd = &rNds.GetEndOfContent(); + const SwNode* pBodySttNd = pBodyEndNd->StartOfSectionNode(); + ULONG nBodySttNdIdx = pBodySttNd->GetIndex(); + Point aPt; + + _SetGetExpFld aCmpPos( SwPosition( bNext ? *pBodyEndNd : *pBodySttNd ) ); + _SetGetExpFld aCurPos( bNext ? *pCurCrsr->End() : *pCurCrsr->Start() ); + if( aCurPos.GetNode() < nBodySttNdIdx ) + { + const SwCntntNode* pCNd = aCurPos.GetNodeFromCntnt()->GetCntntNode(); + SwCntntFrm* pFrm; + if( pCNd && 0 != ( pFrm = pCNd->GetFrm( &aPt )) ) + aCurPos.SetBodyPos( *pFrm ); + } + + // check first all the hyperlink fields + { + const SwTxtNode* pTxtNd; + const SwCharFmts* pFmts = GetDoc()->GetCharFmts(); + for( USHORT n = pFmts->Count(); 1 < n; ) + { + SwClientIter aIter( *(*pFmts)[ --n ] ); + + for( SwClient* pFnd = aIter.First(TYPE( SwTxtINetFmt )); + pFnd; pFnd = aIter.Next() ) + if( 0 != ( pTxtNd = ((SwTxtINetFmt*)pFnd)->GetpTxtNode()) && + pTxtNd->GetNodes().IsDocNodes() ) + { + SwTxtINetFmt& rAttr = *(SwTxtINetFmt*)pFnd; + SwPosition aTmpPos( *pTxtNd ); + _SetGetExpFld aPos( aTmpPos.nNode, rAttr ); + SwCntntFrm* pFrm; + if( pTxtNd->GetIndex() < nBodySttNdIdx && + 0 != ( pFrm = pTxtNd->GetFrm( &aPt )) ) + aPos.SetBodyPos( *pFrm ); + + if( bNext + ? ( aPos < aCmpPos && aCurPos < aPos ) + : ( aCmpPos < aPos && aPos < aCurPos )) + { + String sTxt( pTxtNd->GetExpandTxt( *rAttr.GetStart(), + *rAttr.GetEnd() - *rAttr.GetStart() ) ); + + sTxt.EraseAllChars( 0x0a ); + sTxt.EraseLeadingChars().EraseTrailingChars(); + + if( sTxt.Len() ) + aCmpPos = aPos; + } + } + } + } + // then check all the Flys with a URL or imapge map + { + const SwSpzFrmFmts* pFmts = GetDoc()->GetSpzFrmFmts(); + for( USHORT n = 0, nEnd = pFmts->Count(); n < nEnd; ++n ) + { + SwFlyFrmFmt* pFmt = (SwFlyFrmFmt*)(*pFmts)[ n ]; + const SwFmtURL& rURLItem = pFmt->GetURL(); + if( rURLItem.GetMap() || rURLItem.GetURL().Len() ) + { + SwFlyFrm* pFly = pFmt->GetFrm( &aPt, FALSE ); + SwPosition aTmpPos( *pBodySttNd ); + if( pFly && + GetBodyTxtNode( *GetDoc(), aTmpPos, *pFly->GetLower() ) ) + { + _SetGetExpFld aPos( *pFmt, &aTmpPos ); + + if( bNext + ? ( aPos < aCmpPos && aCurPos < aPos ) + : ( aCmpPos < aPos && aPos < aCurPos )) + aCmpPos = aPos; + } + } + } + } + + // found any URL ? + BOOL bRet = FALSE; + const SwTxtINetFmt* pFndAttr = aCmpPos.GetINetFmt(); + const SwFlyFrmFmt* pFndFmt = aCmpPos.GetFlyFmt(); + if( pFndAttr || pFndFmt ) + { + SET_CURR_SHELL( this ); + SwCallLink aLk( *this ); + + // find a text attribute ? + if( pFndAttr ) + { + SwCrsrSaveState aSaveState( *pCurCrsr ); + + aCmpPos.GetPosOfContent( *pCurCrsr->GetPoint() ); + pCurCrsr->DeleteMark(); + pCurCrsr->SetMark(); + pCurCrsr->GetPoint()->nContent = *pFndAttr->SwTxtAttr::GetEnd(); + + if( !pCurCrsr->IsInProtectTable() && !pCurCrsr->IsSelOvr() ) + { + UpdateCrsr( SwCrsrShell::SCROLLWIN|SwCrsrShell::CHKRANGE| + SwCrsrShell::READONLY ); + bRet = TRUE; + } + } + // find a draw object ? + else if( RES_DRAWFRMFMT == pFndFmt->Which() ) + { + const SdrObject* pSObj = pFndFmt->FindSdrObject(); + ((SwFEShell*)this)->SelectObj( pSObj->GetCurrentBoundRect().Center() ); + MakeSelVisible(); + bRet = TRUE; + } + else // then is it a fly + { + SwFlyFrm* pFly = pFndFmt->GetFrm(&aPt, FALSE ); + if( pFly ) + { + ((SwFEShell*)this)->SelectFlyFrm( *pFly, TRUE ); + MakeSelVisible(); + bRet = TRUE; + } + } + } + return bRet; +} + diff --git a/sw/source/core/crsr/crstrvl1.cxx b/sw/source/core/crsr/crstrvl1.cxx new file mode 100644 index 000000000000..53790c2ac28f --- /dev/null +++ b/sw/source/core/crsr/crstrvl1.cxx @@ -0,0 +1,105 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <crsrsh.hxx> +#include <viscrs.hxx> +#include <callnk.hxx> + +BOOL SwCrsrShell::IsStartWord( sal_Int16 nWordType ) const +{ + return pCurCrsr->IsStartWord( nWordType ); +} + +BOOL SwCrsrShell::IsEndWord( sal_Int16 nWordType ) const +{ + return pCurCrsr->IsEndWord( nWordType ); +} + +BOOL SwCrsrShell::IsInWord( sal_Int16 nWordType ) const +{ + return pCurCrsr->IsInWord( nWordType ); +} + +BOOL SwCrsrShell::IsStartSentence() const +{ + return pCurCrsr->IsStartEndSentence( false ); +} + +BOOL SwCrsrShell::IsEndSentence() const +{ + return pCurCrsr->IsStartEndSentence( true ); +} + + +BOOL SwCrsrShell::GoStartWord() +{ + return CallCrsrFN( &SwCursor::GoStartWord ); +} +BOOL SwCrsrShell::GoEndWord() +{ + return CallCrsrFN( &SwCursor::GoEndWord ); +} +BOOL SwCrsrShell::GoNextWord() +{ + return CallCrsrFN( &SwCursor::GoNextWord ); +} +BOOL SwCrsrShell::GoPrevWord() +{ + return CallCrsrFN( &SwCursor::GoPrevWord ); +} +BOOL SwCrsrShell::GoNextSentence() +{ + return CallCrsrFN( &SwCursor::GoNextSentence ); +} +BOOL SwCrsrShell::GoEndSentence() +{ + return CallCrsrFN( &SwCursor::GoEndSentence ); +} + +BOOL SwCrsrShell::GoPrevSentence() +{ + return CallCrsrFN( &SwCursor::GoPrevSentence ); +} +BOOL SwCrsrShell::GoStartSentence() +{ + return CallCrsrFN( &SwCursor::GoStartSentence ); +} + +BOOL SwCrsrShell::SelectWord( const Point* pPt ) +{ + return pCurCrsr->SelectWord( pPt ); +} + +BOOL SwCrsrShell::ExpandToSentenceBorders() +{ + return pCurCrsr->ExpandToSentenceBorders(); +} + diff --git a/sw/source/core/crsr/findattr.cxx b/sw/source/core/crsr/findattr.cxx new file mode 100644 index 000000000000..be581b17735d --- /dev/null +++ b/sw/source/core/crsr/findattr.cxx @@ -0,0 +1,1309 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/util/SearchOptions.hpp> +#include <com/sun/star/util/SearchFlags.hpp> +#include <i18npool/mslangid.hxx> +#include <hintids.hxx> +#include <vcl/svapp.hxx> +#include <svl/itemiter.hxx> +#include <svl/whiter.hxx> +#include <editeng/brkitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/fontitem.hxx> +#include <fmtpdsc.hxx> +#include <txatbase.hxx> +#include <fchrfmt.hxx> +#include <charfmt.hxx> +#include <doc.hxx> +#include <swcrsr.hxx> +#include <editsh.hxx> +#include <ndtxt.hxx> +#include <pamtyp.hxx> +#include <swundo.hxx> +#include <crsskip.hxx> +#include <undobj.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::util; + +SV_DECL_PTRARR_SORT( SwpFmts, SwFmt*, 0, 4 ) +SV_IMPL_PTRARR_SORT( SwpFmts, SwFmt* ) + + // Sonderbehandlung fuer SvxFontItem, nur den Namen vergleichen: +int CmpAttr( const SfxPoolItem& rItem1, const SfxPoolItem& rItem2 ) +{ + switch( rItem1.Which() ) + { + case RES_CHRATR_FONT: + return ((SvxFontItem&)rItem1).GetFamilyName() == + ((SvxFontItem&)rItem2).GetFamilyName(); + + case RES_CHRATR_COLOR: + return ((SvxColorItem&)rItem1).GetValue().IsRGBEqual( + ((SvxColorItem&)rItem2).GetValue() ); + case RES_PAGEDESC: + return ((SwFmtPageDesc&)rItem1).GetNumOffset() == + ((SwFmtPageDesc&)rItem2).GetNumOffset() && + ((SwFmtPageDesc&)rItem1).GetPageDesc() == + ((SwFmtPageDesc&)rItem2).GetPageDesc(); + } + return rItem1 == rItem2; +} + + +const SwTxtAttr* GetFrwrdTxtHint( const SwpHints& rHtsArr, USHORT& rPos, + xub_StrLen nCntntPos ) +{ + while( rPos < rHtsArr.Count() ) + { + const SwTxtAttr *pTxtHt = rHtsArr.GetStart( rPos++ ); + // der Start vom Attribut muss innerhalb des Bereiches liegen !! + if( *pTxtHt->GetStart() >= nCntntPos ) + return pTxtHt; // gueltiges TextAttribut + } + return 0; // kein gueltiges TextAttribut +} + + +const SwTxtAttr* GetBkwrdTxtHint( const SwpHints& rHtsArr, USHORT& rPos, + xub_StrLen nCntntPos ) +{ + while( rPos > 0 ) + { + //Hack mit cast fuer das Update + const SwTxtAttr *pTxtHt = rHtsArr.GetStart( --rPos ); + // der Start vom Attribut muss innerhalb des Bereiches liegen !! + if( *pTxtHt->GetStart() < nCntntPos ) + return pTxtHt; // gueltiges TextAttribut + } + return 0; // kein gueltiges TextAttribut +} + + +void lcl_SetAttrPam( SwPaM & rPam, xub_StrLen nStart, const xub_StrLen* pEnde, + const BOOL bSaveMark ) +{ + xub_StrLen nCntntPos; + if( bSaveMark ) + nCntntPos = rPam.GetMark()->nContent.GetIndex(); + else + nCntntPos = rPam.GetPoint()->nContent.GetIndex(); + BOOL bTstEnde = rPam.GetPoint()->nNode == rPam.GetMark()->nNode; + + SwCntntNode* pCNd = rPam.GetCntntNode(); + rPam.GetPoint()->nContent.Assign( pCNd, nStart ); + rPam.SetMark(); // Point == GetMark + + // Point zeigt auf das Ende vom SuchBereich oder Ende vom Attribut + if( pEnde ) + { + if( bTstEnde && *pEnde > nCntntPos ) + rPam.GetPoint()->nContent = nCntntPos; + else + rPam.GetPoint()->nContent = *pEnde; + } +} + +//------------------ Suche nach einem Text Attribut ----------------------- + +// diese Funktion sucht in einem TextNode nach dem vorgegebenen Attribut. +// Wird es gefunden, dann hat der SwPaM den Bereich der das Attribut +// umspannt, unter Beachtung des Suchbereiches + + +BOOL lcl_Search( const SwTxtNode& rTxtNd, SwPaM& rPam, + const SfxPoolItem& rCmpItem, + SwMoveFn fnMove, BOOL bValue ) +{ + if ( !rTxtNd.HasHints() ) + return FALSE; + const SwTxtAttr *pTxtHt = 0; + BOOL bForward = fnMove == fnMoveForward; + USHORT nPos = bForward ? 0 : rTxtNd.GetSwpHints().Count(); + xub_StrLen nCntntPos = rPam.GetPoint()->nContent.GetIndex(); + + while( 0 != ( pTxtHt=(*fnMove->fnGetHint)(rTxtNd.GetSwpHints(),nPos,nCntntPos))) + if( pTxtHt->Which() == rCmpItem.Which() && + ( !bValue || CmpAttr( pTxtHt->GetAttr(), rCmpItem ))) + { + lcl_SetAttrPam( rPam, *pTxtHt->GetStart(), pTxtHt->GetEnd(), bForward ); + return TRUE; + } + return FALSE; +} + + +//------------------ Suche nach mehren Text Attributen ------------------- + +struct _SwSrchChrAttr +{ + USHORT nWhich; + xub_StrLen nStt, nEnd; + + _SwSrchChrAttr( const SfxPoolItem& rItem, + xub_StrLen nStart, xub_StrLen nAnyEnd ) + : nWhich( rItem.Which() ), nStt( nStart ), nEnd( nAnyEnd ) + {} +}; + +class SwAttrCheckArr +{ + _SwSrchChrAttr *pFndArr, *pStackArr; + xub_StrLen nNdStt, nNdEnd; + USHORT nArrStart, nArrLen; + USHORT nFound, nStackCnt; + SfxItemSet aCmpSet; + BOOL bNoColls; + BOOL bForward; + +public: + SwAttrCheckArr( const SfxItemSet& rSet, int bForward, int bNoCollections ); + ~SwAttrCheckArr(); + + void SetNewSet( const SwTxtNode& rTxtNd, const SwPaM& rPam ); + + // wieviele Attribute ueberhaupt ?? + USHORT Count() const { return aCmpSet.Count(); } + int Found() const { return nFound == aCmpSet.Count(); } + int CheckStack(); + + xub_StrLen Start() const; + xub_StrLen End() const; + + xub_StrLen GetNdStt() const { return nNdStt; } + xub_StrLen GetNdEnd() const { return nNdEnd; } + + int SetAttrFwd( const SwTxtAttr& rAttr ); + int SetAttrBwd( const SwTxtAttr& rAttr ); +}; + + + +SwAttrCheckArr::SwAttrCheckArr( const SfxItemSet& rSet, int bFwd, + int bNoCollections ) + : aCmpSet( *rSet.GetPool(), RES_CHRATR_BEGIN, RES_TXTATR_END-1 ) +{ + aCmpSet.Put( rSet, FALSE ); + bNoColls = 0 != bNoCollections; + + bForward = 0 != bFwd; + + // Bestimmen den Bereich des Fnd/Stack-Arrays (Min/Max) + SfxItemIter aIter( aCmpSet ); + nArrStart = aCmpSet.GetWhichByPos( aIter.GetFirstPos() ); + nArrLen = aCmpSet.GetWhichByPos( aIter.GetLastPos() ) - nArrStart+1; + + char* pFndChar = new char[ nArrLen * sizeof(_SwSrchChrAttr) ]; + char* pStackChar = new char[ nArrLen * sizeof(_SwSrchChrAttr) ]; + + pFndArr = (_SwSrchChrAttr*)pFndChar; + pStackArr = (_SwSrchChrAttr*)pStackChar; +} + +SwAttrCheckArr::~SwAttrCheckArr() +{ + delete[] (char*)pFndArr; + delete[] (char*)pStackArr; +} + +void SwAttrCheckArr::SetNewSet( const SwTxtNode& rTxtNd, const SwPaM& rPam ) +{ + memset( pFndArr, 0, nArrLen * sizeof(_SwSrchChrAttr) ); + memset( pStackArr, 0, nArrLen * sizeof(_SwSrchChrAttr) ); + nFound = 0; + nStackCnt = 0; + + if( bForward ) + { + nNdStt = rPam.GetPoint()->nContent.GetIndex(); + nNdEnd = rPam.GetPoint()->nNode == rPam.GetMark()->nNode + ? rPam.GetMark()->nContent.GetIndex() + : rTxtNd.GetTxt().Len(); + } + else + { + nNdEnd = rPam.GetPoint()->nContent.GetIndex(); + nNdStt = rPam.GetPoint()->nNode == rPam.GetMark()->nNode + ? rPam.GetMark()->nContent.GetIndex() + : 0; + } + + if( bNoColls && !rTxtNd.HasSwAttrSet() ) + return ; + + const SfxItemSet& rSet = rTxtNd.GetSwAttrSet(); +// if( !rSet.Count() ) +// return; + + SfxItemIter aIter( aCmpSet ); + const SfxPoolItem* pItem = aIter.GetCurItem(); + const SfxPoolItem* pFndItem; + USHORT nWhich; + + while( TRUE ) + { + // nur testen, ob vorhanden ist ? + if( IsInvalidItem( pItem ) ) + { + nWhich = aCmpSet.GetWhichByPos( aIter.GetCurPos() ); + if( RES_TXTATR_END <= nWhich ) + break; // Ende der TextAttribute + + if( SFX_ITEM_SET == rSet.GetItemState( nWhich, !bNoColls, &pFndItem ) + && !CmpAttr( *pFndItem, rSet.GetPool()->GetDefaultItem( nWhich ) )) + { + pFndArr[ nWhich - nArrStart ] = + _SwSrchChrAttr( *pFndItem, nNdStt, nNdEnd ); + nFound++; + } + } + else + { + if( RES_TXTATR_END <= (nWhich = pItem->Which() )) + break; // Ende der TextAttribute + +//JP 27.02.95: wenn nach defaults gesucht wird, dann muss man bis zum Pool +// runter +// if( SFX_ITEM_SET == rSet.GetItemState( nWhich, !bNoColls, &pFndItem ) +// && *pFndItem == *pItem ) + if( CmpAttr( rSet.Get( nWhich, !bNoColls ), *pItem ) ) + { + pFndArr[ nWhich - nArrStart ] = + _SwSrchChrAttr( *pItem, nNdStt, nNdEnd ); + nFound++; + } + } + + if( aIter.IsAtEnd() ) + break; + pItem = aIter.NextItem(); + } +} +int SwAttrCheckArr::SetAttrFwd( const SwTxtAttr& rAttr ) +{ + _SwSrchChrAttr aTmp( rAttr.GetAttr(), *rAttr.GetStart(), *rAttr.GetAnyEnd() ); + // alle die nicht im Bereich sind -> ignorieren + if( aTmp.nEnd <= nNdStt || aTmp.nStt >= nNdEnd ) + return Found(); + + const SfxPoolItem* pItem; + +// -------------------------------------------------------------- +// Hier wird jetzt ausdruecklich auch in Zeichenvorlagen gesucht +// -------------------------------------------------------------- + USHORT nWhch = rAttr.Which(); + SfxWhichIter* pIter = NULL; + const SfxPoolItem* pTmpItem = NULL; + const SfxItemSet* pSet = NULL; + if( RES_TXTATR_CHARFMT == nWhch || RES_TXTATR_AUTOFMT == nWhch ) + { + if( bNoColls && RES_TXTATR_CHARFMT == nWhch ) + return Found(); + pTmpItem = NULL; + pSet = CharFmt::GetItemSet( rAttr.GetAttr() ); + if ( pSet ) + { + pIter = new SfxWhichIter( *pSet ); + nWhch = pIter->FirstWhich(); + while( nWhch && + SFX_ITEM_SET != pSet->GetItemState( nWhch, TRUE, &pTmpItem ) ) + nWhch = pIter->NextWhich(); + if( !nWhch ) + pTmpItem = NULL; + } + } + else + pTmpItem = &rAttr.GetAttr(); + while( pTmpItem ) + { + SfxItemState eState = aCmpSet.GetItemState( nWhch, FALSE, &pItem ); + if( SFX_ITEM_DONTCARE == eState || SFX_ITEM_SET == eState ) + { + USHORT n; + _SwSrchChrAttr* pCmp; + + // loesche erstmal alle, die bis zu der Start Position schon wieder + // ungueltig sind: + + _SwSrchChrAttr* pArrPtr; + if( nFound ) + for( pArrPtr = pFndArr, n = 0; n < nArrLen; + ++n, ++pArrPtr ) + if( pArrPtr->nWhich && pArrPtr->nEnd <= aTmp.nStt ) + { + pArrPtr->nWhich = 0; // geloescht + nFound--; + } + + // loesche erstmal alle, die bis zu der Start Position schon wieder + // ungueltig sind. Und verschiebe alle die "offen" sind, heisst ueber + // die Start Position ragen, vom Stack in den FndSet + + if( nStackCnt ) + for( pArrPtr = pStackArr, n=0; n < nArrLen; ++n, ++pArrPtr ) + { + if( !pArrPtr->nWhich ) + continue; + + if( pArrPtr->nEnd <= aTmp.nStt ) + { + pArrPtr->nWhich = 0; // geloescht + if( !--nStackCnt ) + break; + } + else if( pArrPtr->nStt <= aTmp.nStt ) + { + if( ( pCmp = &pFndArr[ n ])->nWhich ) + { + if( pCmp->nEnd < pArrPtr->nEnd ) // erweitern + pCmp->nEnd = pArrPtr->nEnd; + } + else + { + *pCmp = *pArrPtr; + nFound++; + } + pArrPtr->nWhich = 0; + if( !--nStackCnt ) + break; + } + } + + BOOL bContinue = FALSE; + + if( SFX_ITEM_DONTCARE == eState ) + { + // wird Attribut gueltig ? + if( !CmpAttr( aCmpSet.GetPool()->GetDefaultItem( nWhch ), + *pTmpItem )) + { + // suche das Attribut und erweiter es gegebenenfalls + if( !( pCmp = &pFndArr[ nWhch - nArrStart ])->nWhich ) + { + *pCmp = aTmp; // nicht gefunden, eintragen + nFound++; + } + else if( pCmp->nEnd < aTmp.nEnd ) // erweitern ? + pCmp->nEnd = aTmp.nEnd; + + bContinue = TRUE; + } + } + // wird Attribut gueltig ? + else if( CmpAttr( *pItem, *pTmpItem ) ) + { + pFndArr[ nWhch - nArrStart ] = aTmp; + ++nFound; + bContinue = TRUE; + } + + // tja, dann muss es auf den Stack + if( !bContinue && ( pCmp = &pFndArr[ nWhch - nArrStart ])->nWhich ) + { + // vorhanden, auf den Stack. Aber nur wenn es noch grosser ist + if( pCmp->nEnd > aTmp.nEnd ) + { + ASSERT( !pStackArr[ nWhch - nArrStart ].nWhich, + "Stack-Platz ist noch belegt" ); + + // --------- + // JP 22.08.96: nur Ende manipulieren reicht nicht. Bug 30547 + // pCmp->nStt = aTmp.nEnd; + if( aTmp.nStt <= pCmp->nStt ) + pCmp->nStt = aTmp.nEnd; + else + pCmp->nEnd = aTmp.nStt; + // --------- + + pStackArr[ nWhch - nArrStart ] = *pCmp; + nStackCnt++; + } + pCmp->nWhich = 0; + nFound--; + } + } + if( pIter ) + { + nWhch = pIter->NextWhich(); + while( nWhch && + SFX_ITEM_SET != pSet->GetItemState( nWhch, TRUE, &pTmpItem ) ) + nWhch = pIter->NextWhich(); + if( !nWhch ) + break; + } + else + break; + } + return Found(); +} + + +int SwAttrCheckArr::SetAttrBwd( const SwTxtAttr& rAttr ) +{ + _SwSrchChrAttr aTmp( rAttr.GetAttr(), *rAttr.GetStart(), *rAttr.GetAnyEnd() ); + // alle die nicht im Bereich sind -> ignorieren + if( aTmp.nEnd < nNdStt || aTmp.nStt >= nNdEnd ) + return Found(); + + const SfxPoolItem* pItem; +// -------------------------------------------------------------- +// Hier wird jetzt ausdruecklich auch in Zeichenvorlagen gesucht +// -------------------------------------------------------------- + USHORT nWhch = rAttr.Which(); + SfxWhichIter* pIter = NULL; + const SfxPoolItem* pTmpItem = NULL; + const SfxItemSet* pSet = NULL; + if( RES_TXTATR_CHARFMT == nWhch || RES_TXTATR_AUTOFMT == nWhch ) + { + if( bNoColls && RES_TXTATR_CHARFMT == nWhch ) + return Found(); + + pSet = CharFmt::GetItemSet( rAttr.GetAttr() ); + if ( pSet ) + { + pIter = new SfxWhichIter( *pSet ); + nWhch = pIter->FirstWhich(); + while( nWhch && + SFX_ITEM_SET != pSet->GetItemState( nWhch, TRUE, &pTmpItem ) ) + nWhch = pIter->NextWhich(); + if( !nWhch ) + pTmpItem = NULL; + } + } + else + pTmpItem = &rAttr.GetAttr(); + while( pTmpItem ) + { + SfxItemState eState = aCmpSet.GetItemState( nWhch, FALSE, &pItem ); + if( SFX_ITEM_DONTCARE == eState || SFX_ITEM_SET == eState ) + { + USHORT n; + _SwSrchChrAttr* pCmp; + + // loesche erstmal alle, die bis zu der Start Position schon wieder + // ungueltig sind: + + _SwSrchChrAttr* pArrPtr; + if( nFound ) + for( pArrPtr = pFndArr, n = 0; n < nArrLen; ++n, ++pArrPtr ) + if( pArrPtr->nWhich && pArrPtr->nStt >= aTmp.nEnd ) + { + pArrPtr->nWhich = 0; // geloescht + nFound--; + } + + // loesche erstmal alle, die bis zu der Start Position schon wieder + // ungueltig sind. Und verschiebe alle die "offen" sind, heisst ueber + // die Start Position ragen, vom Stack in den FndSet + + if( nStackCnt ) + for( pArrPtr = pStackArr, n = 0; n < nArrLen; ++n, ++pArrPtr ) + { + if( !pArrPtr->nWhich ) + continue; + + if( pArrPtr->nStt >= aTmp.nEnd ) + { + pArrPtr->nWhich = 0; // geloescht + if( !--nStackCnt ) + break; + } + else if( pArrPtr->nEnd >= aTmp.nEnd ) + { + if( ( pCmp = &pFndArr[ n ])->nWhich ) + { + if( pCmp->nStt > pArrPtr->nStt ) // erweitern + pCmp->nStt = pArrPtr->nStt; + } + else + { + *pCmp = *pArrPtr; + nFound++; + } + pArrPtr->nWhich = 0; + if( !--nStackCnt ) + break; + } + } + + BOOL bContinue = FALSE; + if( SFX_ITEM_DONTCARE == eState ) + { + // wird Attribut gueltig ? + if( !CmpAttr( aCmpSet.GetPool()->GetDefaultItem( nWhch ), + *pTmpItem ) ) + { + // suche das Attribut und erweiter es gegebenenfalls + if( !( pCmp = &pFndArr[ nWhch - nArrStart ])->nWhich ) + { + *pCmp = aTmp; // nicht gefunden, eintragen + nFound++; + } + else if( pCmp->nStt > aTmp.nStt ) // erweitern ? + pCmp->nStt = aTmp.nStt; + + bContinue = TRUE; + } + } + // wird Attribut gueltig ? + else if( CmpAttr( *pItem, *pTmpItem )) + { + pFndArr[ nWhch - nArrStart ] = aTmp; + ++nFound; + bContinue = TRUE; + } + + // tja, dann muss es auf den Stack + if( !bContinue && ( pCmp = &pFndArr[ nWhch - nArrStart ])->nWhich ) + { + // vorhanden, auf den Stack. Aber nur wenn es noch grosser ist + if( pCmp->nStt < aTmp.nStt ) + { + ASSERT( !pStackArr[ nWhch - nArrStart ].nWhich, + "Stack-Platz ist noch belegt" ); + +// --------- +// JP 22.08.96: nur Ende manipulieren reicht nicht. Bug 30547 +// pCmp->nEnd = aTmp.nStt; + if( aTmp.nEnd <= pCmp->nEnd ) + pCmp->nEnd = aTmp.nStt; + else + pCmp->nStt = aTmp.nEnd; +// --------- + + pStackArr[ nWhch - nArrStart ] = *pCmp; + nStackCnt++; + } + pCmp->nWhich = 0; + nFound--; + } + } + if( pIter ) + { + nWhch = pIter->NextWhich(); + while( nWhch && + SFX_ITEM_SET != pSet->GetItemState( nWhch, TRUE, &pTmpItem ) ) + nWhch = pIter->NextWhich(); + if( !nWhch ) + break; + } + else + break; + } + return Found(); +} + + +xub_StrLen SwAttrCheckArr::Start() const +{ + xub_StrLen nStart = nNdStt; + _SwSrchChrAttr* pArrPtr = pFndArr; + for( USHORT n = 0; n < nArrLen; ++n, ++pArrPtr ) + if( pArrPtr->nWhich && pArrPtr->nStt > nStart ) + nStart = pArrPtr->nStt; + + return nStart; +} + + +xub_StrLen SwAttrCheckArr::End() const +{ + _SwSrchChrAttr* pArrPtr = pFndArr; + xub_StrLen nEnd = nNdEnd; + for( USHORT n = 0; n < nArrLen; ++n, ++pArrPtr ) + if( pArrPtr->nWhich && pArrPtr->nEnd < nEnd ) + nEnd = pArrPtr->nEnd; + + return nEnd; +} + + +int SwAttrCheckArr::CheckStack() +{ + if( !nStackCnt ) + return FALSE; + + USHORT n; + xub_StrLen nSttPos = Start(), nEndPos = End(); + _SwSrchChrAttr* pArrPtr; + for( pArrPtr = pStackArr, n = 0; n < nArrLen; ++n, ++pArrPtr ) + { + if( !pArrPtr->nWhich ) + continue; + + if( bForward ? pArrPtr->nEnd <= nSttPos : pArrPtr->nStt >= nEndPos ) + { + pArrPtr->nWhich = 0; // geloescht + if( !--nStackCnt ) + return nFound == aCmpSet.Count(); + } + else if( bForward ? pArrPtr->nStt < nEndPos : pArrPtr->nEnd > nSttPos ) + { + // alle die "offen" sind, heisst ueber die Start Position ragen, + // im FndSet setzen + ASSERT( !pFndArr[ n ].nWhich, "Array-Platz ist noch belegt" ); + pFndArr[ n ] = *pArrPtr; + pArrPtr->nWhich = 0; + nFound++; + if( !--nStackCnt ) + return nFound == aCmpSet.Count(); + } + } + return nFound == aCmpSet.Count(); +} + + + +int lcl_SearchForward( const SwTxtNode& rTxtNd, SwAttrCheckArr& rCmpArr, + SwPaM& rPam ) +{ + xub_StrLen nEndPos, nSttPos; + rCmpArr.SetNewSet( rTxtNd, rPam ); + if( !rTxtNd.HasHints() ) + { + if( !rCmpArr.Found() ) + return FALSE; + nEndPos = rCmpArr.GetNdEnd(); + lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, TRUE ); + return TRUE; + } + + // dann gehe mal durch das nach "Start" sortierte Array + const SwpHints& rHtArr = rTxtNd.GetSwpHints(); + const SwTxtAttr* pAttr; + USHORT nPos = 0; + + // sollte jetzt schon alles vorhanden sein, dann teste, mit welchem + // das wieder beendet wird. + if( rCmpArr.Found() ) + { + for( ; nPos < rHtArr.Count(); ++nPos ) + if( !rCmpArr.SetAttrFwd( *( pAttr = rHtArr.GetStart( nPos )) ) ) + { + if( rCmpArr.GetNdStt() < *pAttr->GetStart() ) + { + // dann haben wir unser Ende: + lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), + pAttr->GetStart(), TRUE ); + return TRUE; + } + // ansonsten muessen wir weiter suchen + break; + } + + if( nPos == rHtArr.Count() && rCmpArr.Found() ) + { + // dann haben wir unseren Bereich + nEndPos = rCmpArr.GetNdEnd(); + lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, TRUE ); + return TRUE; + } + } + + for( ; nPos < rHtArr.Count(); ++nPos ) + if( rCmpArr.SetAttrFwd( *( pAttr = rHtArr.GetStart( nPos )) ) ) + { + // sollten noch mehr auf der gleichen Position anfangen ?? + // auch die noch mit testen !! + nSttPos = *pAttr->GetStart(); + while( ++nPos < rHtArr.Count() && nSttPos == + *( pAttr = rHtArr.GetStart( nPos ))->GetStart() && + rCmpArr.SetAttrFwd( *pAttr ) ) + ; + if( !rCmpArr.Found() ) + continue; + + // dann haben wir den Bereich zusammen + if( (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) ) + return FALSE; + lcl_SetAttrPam( rPam, nSttPos, &nEndPos, TRUE ); + return TRUE; + } + + if( !rCmpArr.CheckStack() || + (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) ) + return FALSE; + lcl_SetAttrPam( rPam, nSttPos, &nEndPos, TRUE ); + return TRUE; +} + + +int lcl_SearchBackward( const SwTxtNode& rTxtNd, SwAttrCheckArr& rCmpArr, + SwPaM& rPam ) +{ + xub_StrLen nEndPos, nSttPos; + rCmpArr.SetNewSet( rTxtNd, rPam ); + if( !rTxtNd.HasHints() ) + { + if( !rCmpArr.Found() ) + return FALSE; + nEndPos = rCmpArr.GetNdEnd(); + lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, FALSE ); + return TRUE; + } + + // dann gehe mal durch das nach "Start" sortierte Array + const SwpHints& rHtArr = rTxtNd.GetSwpHints(); + const SwTxtAttr* pAttr; + USHORT nPos = rHtArr.Count(); + + // sollte jetzt schon alles vorhanden sein, dann teste, mit welchem + // das wieder beendet wird. + if( rCmpArr.Found() ) + { + while( nPos ) + if( !rCmpArr.SetAttrBwd( *( pAttr = rHtArr.GetEnd( --nPos )) ) ) + { + nSttPos = *pAttr->GetAnyEnd(); + if( nSttPos < rCmpArr.GetNdEnd() ) + { + // dann haben wir unser Ende: + nEndPos = rCmpArr.GetNdEnd(); + lcl_SetAttrPam( rPam, nSttPos, &nEndPos, FALSE ); + return TRUE; + } + + // ansonsten muessen wir weiter suchen + break; + } + + if( !nPos && rCmpArr.Found() ) + { + // dann haben wir unseren Bereich + nEndPos = rCmpArr.GetNdEnd(); + lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, FALSE ); + return TRUE; + } + } + + while( nPos ) + if( rCmpArr.SetAttrBwd( *( pAttr = rHtArr.GetEnd( --nPos )) ) ) + { + // sollten noch mehr auf der gleichen Position anfangen ?? + // auch die noch mit testen !! + if( nPos ) + { + nEndPos = *pAttr->GetAnyEnd(); + while( --nPos && nEndPos == + *( pAttr = rHtArr.GetEnd( nPos ))->GetAnyEnd() && + rCmpArr.SetAttrBwd( *pAttr ) ) + ; + } + if( !rCmpArr.Found() ) + continue; + + + // dann haben wir den Bereich zusammen + if( (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) ) + return FALSE; + lcl_SetAttrPam( rPam, nSttPos, &nEndPos, FALSE ); + return TRUE; + } + + if( !rCmpArr.CheckStack() || + (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) ) + return FALSE; + lcl_SetAttrPam( rPam, nSttPos, &nEndPos, FALSE ); + return TRUE; +} + + +int lcl_Search( const SwCntntNode& rCNd, const SfxItemSet& rCmpSet, BOOL bNoColls ) +{ + // nur die harte Attributierung suchen ? + if( bNoColls && !rCNd.HasSwAttrSet() ) + return FALSE; + + const SfxItemSet& rNdSet = rCNd.GetSwAttrSet(); + SfxItemIter aIter( rCmpSet ); + const SfxPoolItem* pItem = aIter.GetCurItem(); + const SfxPoolItem* pNdItem; + USHORT nWhich; + + while( TRUE ) + { + // nur testen, ob vorhanden ist ? + if( IsInvalidItem( pItem )) + { + nWhich = rCmpSet.GetWhichByPos( aIter.GetCurPos() ); + if( SFX_ITEM_SET != rNdSet.GetItemState( nWhich, !bNoColls, &pNdItem ) + || CmpAttr( *pNdItem, rNdSet.GetPool()->GetDefaultItem( nWhich ) )) + return FALSE; + } + else + { + nWhich = pItem->Which(); +//JP 27.02.95: wenn nach defaults gesucht wird, dann muss man bis zum Pool +// runter +// if( SFX_ITEM_SET != rNdSet.GetItemState( nWhich, !bNoColls, &pNdItem ) +// || *pNdItem != *pItem ) + if( !CmpAttr( rNdSet.Get( nWhich, !bNoColls ), *pItem )) + return FALSE; + } + + if( aIter.IsAtEnd() ) + break; + pItem = aIter.NextItem(); + } + return TRUE; // wurde gefunden +} + + +BOOL SwPaM::Find( const SfxPoolItem& rAttr, BOOL bValue, SwMoveFn fnMove, + const SwPaM *pRegion, BOOL bInReadOnly ) +{ + // stelle fest welches Attribut gesucht wird: + USHORT nWhich = rAttr.Which(); + int bCharAttr = isCHRATR(nWhich) || isTXTATR(nWhich); + + SwPaM* pPam = MakeRegion( fnMove, pRegion ); + + BOOL bFound = FALSE; + BOOL bFirst = TRUE; + BOOL bSrchForward = fnMove == fnMoveForward; + SwCntntNode * pNode; + const SfxPoolItem* pItem; + SwpFmts aFmtArr; + + // Wenn am Anfang/Ende, aus dem Node moven + if( bSrchForward + ? pPam->GetPoint()->nContent.GetIndex() == pPam->GetCntntNode()->Len() + : !pPam->GetPoint()->nContent.GetIndex() ) + { + if( !(*fnMove->fnNds)( &pPam->GetPoint()->nNode, FALSE )) + { + delete pPam; + return FALSE; + } + SwCntntNode *pNd = pPam->GetCntntNode(); + xub_StrLen nTmpPos = bSrchForward ? 0 : pNd->Len(); + pPam->GetPoint()->nContent.Assign( pNd, nTmpPos ); + } + + while( 0 != ( pNode = ::GetNode( *pPam, bFirst, fnMove, bInReadOnly ) ) ) + { + if( bCharAttr ) + { + if( !pNode->IsTxtNode() ) // CharAttr sind nur in TextNodes + continue; + + if( ((SwTxtNode*)pNode)->HasHints() && + lcl_Search( *(SwTxtNode*)pNode, *pPam, rAttr, fnMove, bValue )) + { + // setze auf die Werte vom Attribut + SetMark(); + *GetPoint() = *pPam->GetPoint(); + *GetMark() = *pPam->GetMark(); + bFound = TRUE; + break; + } + else if (isTXTATR(nWhich)) + continue; // --> also weiter + } + + // keine harte Attributierung, dann pruefe, ob die Vorlage schon + // mal nach dem Attribut befragt wurde + if( !pNode->HasSwAttrSet() ) + { + const SwFmt* pTmpFmt = pNode->GetFmtColl(); + if( aFmtArr.Count() && aFmtArr.Seek_Entry( pTmpFmt )) + continue; // die Collection wurde schon mal befragt + aFmtArr.Insert( pTmpFmt ); + } + + if( SFX_ITEM_SET == pNode->GetSwAttrSet().GetItemState( nWhich, + TRUE, &pItem ) && ( !bValue || *pItem == rAttr ) ) + { + // FORWARD: Point an das Ende, GetMark zum Anfanf vom Node + // BACKWARD: Point zum Anfang, GetMark an das Ende vom Node + // und immer nach der Logik: inkl. Start, exkl. End !!! + *GetPoint() = *pPam->GetPoint(); + SetMark(); + pNode->MakeEndIndex( &GetPoint()->nContent ); + bFound = TRUE; + break; + } + } + + // beim rueckwaerts Suchen noch Point und Mark vertauschen + if( bFound && !bSrchForward ) + Exchange(); + + delete pPam; + return bFound; +} + + +typedef int (*FnSearchAttr)( const SwTxtNode&, SwAttrCheckArr&, SwPaM& ); + +BOOL SwPaM::Find( const SfxItemSet& rSet, BOOL bNoColls, SwMoveFn fnMove, + const SwPaM *pRegion, BOOL bInReadOnly, BOOL bMoveFirst ) +{ + SwPaM* pPam = MakeRegion( fnMove, pRegion ); + + BOOL bFound = FALSE; + BOOL bFirst = TRUE; + BOOL bSrchForward = fnMove == fnMoveForward; + SwCntntNode * pNode; + SwpFmts aFmtArr; + + // teste doch mal welche Text/Char-Attribute gesucht werden + SwAttrCheckArr aCmpArr( rSet, bSrchForward, bNoColls ); + SfxItemSet aOtherSet( GetDoc()->GetAttrPool(), + RES_PARATR_BEGIN, RES_GRFATR_END-1 ); + aOtherSet.Put( rSet, FALSE ); // alle Invalid-Items erhalten! + + FnSearchAttr fnSearch = bSrchForward + ? (&::lcl_SearchForward) + : (&::lcl_SearchBackward); + + // Wenn am Anfang/Ende, aus dem Node moven + // Wenn am Anfang/Ende, aus dem Node moven + if( bMoveFirst && + ( bSrchForward + ? pPam->GetPoint()->nContent.GetIndex() == pPam->GetCntntNode()->Len() + : !pPam->GetPoint()->nContent.GetIndex() ) ) + { + if( !(*fnMove->fnNds)( &pPam->GetPoint()->nNode, FALSE )) + { + delete pPam; + return FALSE; + } + SwCntntNode *pNd = pPam->GetCntntNode(); + xub_StrLen nTmpPos = bSrchForward ? 0 : pNd->Len(); + pPam->GetPoint()->nContent.Assign( pNd, nTmpPos ); + } + + + while( 0 != ( pNode = ::GetNode( *pPam, bFirst, fnMove, bInReadOnly ) ) ) + { + if( aCmpArr.Count() ) + { + if( !pNode->IsTxtNode() ) // CharAttr sind nur in TextNodes + continue; + + if( (!aOtherSet.Count() || + lcl_Search( *pNode, aOtherSet, bNoColls )) && + (*fnSearch)( *(SwTxtNode*)pNode, aCmpArr, *pPam )) + { + // setze auf die Werte vom Attribut + SetMark(); + *GetPoint() = *pPam->GetPoint(); + *GetMark() = *pPam->GetMark(); + bFound = TRUE; + break; + } + continue; // TextAttribute + } + + if( !aOtherSet.Count() ) + continue; + + // keine harte Attributierung, dann pruefe, ob die Vorlage schon + // mal nach dem Attribut befragt wurde + if( !pNode->HasSwAttrSet() ) + { + const SwFmt* pTmpFmt = pNode->GetFmtColl(); + if( aFmtArr.Count() && aFmtArr.Seek_Entry( pTmpFmt )) + continue; // die Collection wurde schon mal befragt + aFmtArr.Insert( pTmpFmt ); + } + + if( lcl_Search( *pNode, aOtherSet, bNoColls )) + { + // FORWARD: Point an das Ende, GetMark zum Anfanf vom Node + // BACKWARD: Point zum Anfang, GetMark an das Ende vom Node + // und immer nach der Logik: inkl. Start, exkl. End !!! + *GetPoint() = *pPam->GetPoint(); + SetMark(); + pNode->MakeEndIndex( &GetPoint()->nContent ); + bFound = TRUE; + break; + } + } + + // beim rueckwaerts Suchen noch Point und Mark vertauschen + if( bFound && !bSrchForward ) + Exchange(); + + delete pPam; + return bFound; +} + +//------------------ Methoden vom SwCursor --------------------------- + +// Parameter fuer das Suchen vom Attributen +struct SwFindParaAttr : public SwFindParas +{ + BOOL bValue; + const SfxItemSet *pSet, *pReplSet; + const SearchOptions *pSearchOpt; + SwCursor& rCursor; + utl::TextSearch* pSTxt; + + SwFindParaAttr( const SfxItemSet& rSet, BOOL bNoCollection, + const SearchOptions* pOpt, const SfxItemSet* pRSet, + SwCursor& rCrsr ) + : bValue( bNoCollection ), pSet( &rSet ), pReplSet( pRSet ), + pSearchOpt( pOpt ), rCursor( rCrsr ),pSTxt( 0 ) {} + + virtual ~SwFindParaAttr() { delete pSTxt; } + + virtual int Find( SwPaM* , SwMoveFn , const SwPaM*, BOOL bInReadOnly ); + virtual int IsReplaceMode() const; +}; + + +int SwFindParaAttr::Find( SwPaM* pCrsr, SwMoveFn fnMove, const SwPaM* pRegion, + BOOL bInReadOnly ) +{ + // String ersetzen ?? (nur wenn Text angegeben oder nicht attributiert + // gesucht wird) + BOOL bReplaceTxt = pSearchOpt && ( pSearchOpt->replaceString.getLength() || + !pSet->Count() ); + BOOL bReplaceAttr = pReplSet && pReplSet->Count(); + BOOL bMoveFirst = !bReplaceAttr; + if( bInReadOnly && (bReplaceAttr || bReplaceTxt )) + bInReadOnly = FALSE; + + // wir suchen nach Attributen, soll zusaetzlich Text gesucht werden ? + { + SwPaM aRegion( *pRegion->GetMark(), *pRegion->GetPoint() ); + SwPaM* pTextRegion = &aRegion; + SwPaM aSrchPam( *pCrsr->GetPoint() ); + + while( TRUE ) + { + if( pSet->Count() ) // gibts ueberhaupt Attributierung? + { + // zuerst die Attributierung + if( !aSrchPam.Find( *pSet, bValue, fnMove, &aRegion, bInReadOnly, bMoveFirst ) ) +//JP 17.11.95: was ist mit Attributen in leeren Absaetzen !! +// || *pCrsr->GetMark() == *pCrsr->GetPoint() ) // kein Bereich ?? + return FIND_NOT_FOUND; + bMoveFirst = TRUE; + + if( !pSearchOpt ) + break; // ok, nur Attribute, also gefunden + + pTextRegion = &aSrchPam; + } + else if( !pSearchOpt ) + return FIND_NOT_FOUND; + + // dann darin den Text + if( !pSTxt ) + { + SearchOptions aTmp( *pSearchOpt ); + + // search in selection + aTmp.searchFlag |= (SearchFlags::REG_NOT_BEGINOFLINE | + SearchFlags::REG_NOT_ENDOFLINE); + + MsLangId::convertLanguageToLocale( LANGUAGE_SYSTEM, aTmp.Locale ); + + pSTxt = new utl::TextSearch( aTmp ); + } + + // todo/mba: searching for attributes in Outliner text?! + BOOL bSearchInNotes = FALSE; + + // Bug 24665: suche im richtigen Bereich weiter (pTextRegion!) + if( aSrchPam.Find( *pSearchOpt, bSearchInNotes, *pSTxt, fnMove, pTextRegion, bInReadOnly ) && + *aSrchPam.GetMark() != *aSrchPam.GetPoint() ) // gefunden ? + break; // also raus + else if( !pSet->Count() ) + return FIND_NOT_FOUND; // nur Text und nicht gefunden + +/* // --> FME 2007-4-12 #i74765 # Why should we move the position? + Moving the position results in bugs when there are two adjacent + portions which both have the requested attributes set. I suspect this + should be only be an optimization. Therefore I boldly remove it now! + + // JP: und wieder neu aufsetzen, aber eine Position weiter + //JP 04.11.97: Bug 44897 - aber den Mark wieder aufheben, damit + // weiterbewegt werden kann! + { + BOOL bCheckRegion = TRUE; + SwPosition* pPos = aSrchPam.GetPoint(); + if( !(*fnMove->fnNd)( &pPos->nNode.GetNode(), + &pPos->nContent, CRSR_SKIP_CHARS )) + { + if( (*fnMove->fnNds)( &pPos->nNode, FALSE )) + { + SwCntntNode *pNd = pPos->nNode.GetNode().GetCntntNode(); + xub_StrLen nCPos; + if( fnMove == fnMoveForward ) + nCPos = 0; + else + nCPos = pNd->Len(); + pPos->nContent.Assign( pNd, nCPos ); + } + else + bCheckRegion = FALSE; + } + if( !bCheckRegion || *aRegion.GetPoint() <= *pPos ) + return FIND_NOT_FOUND; // nicht gefunden + }*/ + *aRegion.GetMark() = *aSrchPam.GetPoint(); + } + + *pCrsr->GetPoint() = *aSrchPam.GetPoint(); + pCrsr->SetMark(); + *pCrsr->GetMark() = *aSrchPam.GetMark(); + } + + if( bReplaceTxt ) + { + const bool bRegExp( + SearchAlgorithms_REGEXP == pSearchOpt->algorithmType); + SwIndex& rSttCntIdx = pCrsr->Start()->nContent; + xub_StrLen nSttCnt = rSttCntIdx.GetIndex(); + + // damit die Region auch verschoben wird, in den Shell-Cursr-Ring + // mit aufnehmen !! + Ring *pPrevRing = 0; + if( bRegExp ) + { + pPrevRing = pRegion->GetPrev(); + ((Ring*)pRegion)->MoveRingTo( &rCursor ); + } + + ::std::auto_ptr<String> pRepl( (bRegExp) ? + ReplaceBackReferences( *pSearchOpt, pCrsr ) : 0 ); + rCursor.GetDoc()->ReplaceRange( *pCrsr, + (pRepl.get()) ? *pRepl : String(pSearchOpt->replaceString), + bRegExp ); + rCursor.SaveTblBoxCntnt( pCrsr->GetPoint() ); + + if( bRegExp ) + { + // und die Region wieder herausnehmen: + Ring *p, *pNext = (Ring*)pRegion; + do { + p = pNext; + pNext = p->GetNext(); + p->MoveTo( (Ring*)pRegion ); + } while( p != pPrevRing ); + } + rSttCntIdx = nSttCnt; + } + + if( bReplaceAttr ) + { + // --- Ist die Selection noch da ?????? + + // und noch die Attribute setzen +#ifdef OLD + pCrsr->GetDoc()->Insert( *pCrsr, *pReplSet, 0 ); +#else + //JP 13.07.95: alle gesuchten Attribute werden, wenn nicht im + // ReplaceSet angegeben, auf Default zurueck gesetzt + + if( !pSet->Count() ) + { + pCrsr->GetDoc()->InsertItemSet( *pCrsr, *pReplSet, 0 ); + } + else + { + SfxItemPool* pPool = pReplSet->GetPool(); + SfxItemSet aSet( *pPool, pReplSet->GetRanges() ); + + SfxItemIter aIter( *pSet ); + const SfxPoolItem* pItem = aIter.GetCurItem(); + while( TRUE ) + { + // alle die nicht gesetzt sind mit Pool-Defaults aufuellen + if( !IsInvalidItem( pItem ) && SFX_ITEM_SET != + pReplSet->GetItemState( pItem->Which(), FALSE )) + aSet.Put( pPool->GetDefaultItem( pItem->Which() )); + + if( aIter.IsAtEnd() ) + break; + pItem = aIter.NextItem(); + } + aSet.Put( *pReplSet ); + pCrsr->GetDoc()->InsertItemSet( *pCrsr, aSet, 0 ); + } +#endif + return FIND_NO_RING; + } + + else + return FIND_FOUND; +} + + +int SwFindParaAttr::IsReplaceMode() const +{ + return ( pSearchOpt && pSearchOpt->replaceString.getLength() ) || + ( pReplSet && pReplSet->Count() ); +} + +// Suchen nach Attributen + + +ULONG SwCursor::Find( const SfxItemSet& rSet, BOOL bNoCollections, + SwDocPositions nStart, SwDocPositions nEnde, BOOL& bCancel, + FindRanges eFndRngs, + const SearchOptions* pSearchOpt, const SfxItemSet* pReplSet ) +{ + // OLE-Benachrichtigung abschalten !! + SwDoc* pDoc = GetDoc(); + Link aLnk( pDoc->GetOle2Link() ); + pDoc->SetOle2Link( Link() ); + + BOOL bReplace = ( pSearchOpt && ( pSearchOpt->replaceString.getLength() || + !rSet.Count() ) ) || + (pReplSet && pReplSet->Count()); + BOOL bSttUndo = pDoc->DoesUndo() && bReplace; + if( bSttUndo ) + pDoc->StartUndo( UNDO_REPLACE, NULL ); + + SwFindParaAttr aSwFindParaAttr( rSet, bNoCollections, pSearchOpt, + pReplSet, *this ); + + ULONG nRet = FindAll(aSwFindParaAttr, nStart, nEnde, eFndRngs, bCancel ); + pDoc->SetOle2Link( aLnk ); + if( nRet && bReplace ) + pDoc->SetModified(); + + if( bSttUndo ) + pDoc->EndUndo( UNDO_REPLACE, NULL ); + + return nRet; +} + + + diff --git a/sw/source/core/crsr/findcoll.cxx b/sw/source/core/crsr/findcoll.cxx new file mode 100644 index 000000000000..4bb594ceb4ca --- /dev/null +++ b/sw/source/core/crsr/findcoll.cxx @@ -0,0 +1,119 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <swcrsr.hxx> +#include <doc.hxx> +#include <pamtyp.hxx> +#include <swundo.hxx> +#include <undobj.hxx> +#ifndef _COMCORE_HRC +#include <comcore.hrc> +#endif +#include <tools/resid.hxx> + +//------------------ Methoden der CrsrShell --------------------------- + +// Parameter fuer das Suchen vom FormatCollections +struct SwFindParaFmtColl : public SwFindParas +{ + const SwTxtFmtColl *pFmtColl, *pReplColl; + SwCursor& rCursor; + SwFindParaFmtColl( const SwTxtFmtColl& rFmtColl, + const SwTxtFmtColl* pRpColl, SwCursor& rCrsr ) + : pFmtColl( &rFmtColl ), pReplColl( pRpColl ), rCursor( rCrsr ) + {} + virtual int Find( SwPaM* , SwMoveFn , const SwPaM*, BOOL bInReadOnly ); + virtual int IsReplaceMode() const; +}; + + +int SwFindParaFmtColl::Find( SwPaM* pCrsr, SwMoveFn fnMove, const SwPaM* pRegion, + BOOL bInReadOnly ) +{ + int nRet = FIND_FOUND; + if( bInReadOnly && pReplColl ) + bInReadOnly = FALSE; + + if( !pCrsr->Find( *pFmtColl, fnMove, pRegion, bInReadOnly ) ) + nRet = FIND_NOT_FOUND; + else if( pReplColl ) + { + pCrsr->GetDoc()->SetTxtFmtColl( *pCrsr, (SwTxtFmtColl*)pReplColl ); + nRet = FIND_NO_RING; + } + return nRet; +} + + +int SwFindParaFmtColl::IsReplaceMode() const +{ + return 0 != pReplColl; +} + + +// Suchen nach Format-Collections + + +ULONG SwCursor::Find( const SwTxtFmtColl& rFmtColl, + SwDocPositions nStart, SwDocPositions nEnde, BOOL& bCancel, + FindRanges eFndRngs, const SwTxtFmtColl* pReplFmtColl ) +{ + // OLE-Benachrichtigung abschalten !! + SwDoc* pDoc = GetDoc(); + Link aLnk( pDoc->GetOle2Link() ); + pDoc->SetOle2Link( Link() ); + + BOOL bSttUndo = pDoc->DoesUndo() && pReplFmtColl; + if( bSttUndo ) + { + SwRewriter aRewriter; + aRewriter.AddRule(UNDO_ARG1, rFmtColl.GetName()); + aRewriter.AddRule(UNDO_ARG2, SW_RES(STR_YIELDS)); + aRewriter.AddRule(UNDO_ARG3, pReplFmtColl->GetName()); + + pDoc->StartUndo( UNDO_UI_REPLACE_STYLE, &aRewriter ); + } + + SwFindParaFmtColl aSwFindParaFmtColl( rFmtColl, pReplFmtColl, *this ); + + ULONG nRet = FindAll( aSwFindParaFmtColl, nStart, nEnde, eFndRngs, bCancel ); + pDoc->SetOle2Link( aLnk ); + + if( nRet && pReplFmtColl ) + pDoc->SetModified(); + + if( bSttUndo ) + pDoc->EndUndo( UNDO_UI_REPLACE_STYLE, NULL ); + return nRet; +} + + + diff --git a/sw/source/core/crsr/findfmt.cxx b/sw/source/core/crsr/findfmt.cxx new file mode 100644 index 000000000000..bf3492ae0a65 --- /dev/null +++ b/sw/source/core/crsr/findfmt.cxx @@ -0,0 +1,84 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <doc.hxx> +#include <pamtyp.hxx> + + +BOOL SwPaM::Find( const SwFmt& rFmt, SwMoveFn fnMove, + const SwPaM *pRegion, BOOL bInReadOnly ) +{ + BOOL bFound = FALSE; + BOOL bSrchForward = fnMove == fnMoveForward; + SwPaM* pPam = MakeRegion( fnMove, pRegion ); + + // Wenn am Anfang/Ende, aus dem Node moven + if( bSrchForward + ? pPam->GetPoint()->nContent.GetIndex() == pPam->GetCntntNode()->Len() + : !pPam->GetPoint()->nContent.GetIndex() ) + { + if( !(*fnMove->fnNds)( &pPam->GetPoint()->nNode, FALSE )) + { + delete pPam; + return FALSE; + } + SwCntntNode *pNd = pPam->GetPoint()->nNode.GetNode().GetCntntNode(); + xub_StrLen nTmpPos = bSrchForward ? 0 : pNd->Len(); + pPam->GetPoint()->nContent.Assign( pNd, nTmpPos ); + } + + BOOL bFirst = TRUE; + SwCntntNode* pNode; + while( !bFound && + 0 != ( pNode = ::GetNode( *pPam, bFirst, fnMove, bInReadOnly ))) + { + if( 0 != ( bFound = pNode->GetFmtColl() == &rFmt )) + { + // wurde die FormatCollection gefunden, dann handelt es sich auf + // jedenfall um einen SwCntntNode !! + + // FORWARD: SPoint an das Ende, GetMark zum Anfanf vom Node + // BACKWARD: SPoint zum Anfang, GetMark an das Ende vom Node + // und immer nach der Logik: inkl. Start, exkl. End !!! + *GetPoint() = *pPam->GetPoint(); + SetMark(); + pNode->MakeEndIndex( &GetPoint()->nContent ); + GetMark()->nContent = 0; + if( !bSrchForward ) // rueckwaerts Suche? + Exchange(); // SPoint und GetMark tauschen + break; + } + } + delete pPam; + return bFound; +} + + diff --git a/sw/source/core/crsr/findtxt.cxx b/sw/source/core/crsr/findtxt.cxx new file mode 100644 index 000000000000..4a0697692975 --- /dev/null +++ b/sw/source/core/crsr/findtxt.cxx @@ -0,0 +1,707 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 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/util/SearchFlags.hpp> + + + +#define _SVSTDARR_USHORTS +#define _SVSTDARR_ULONGS +#include <svl/svstdarr.hxx> +#include <vcl/svapp.hxx> +#include <txatritr.hxx> +#include <fldbas.hxx> +#include <fmtfld.hxx> +#include <txtatr.hxx> +#include <txtfld.hxx> +#include <swcrsr.hxx> +#include <doc.hxx> +#include <pamtyp.hxx> +#include <ndtxt.hxx> +#include <swundo.hxx> +#include <breakit.hxx> + +#include <docsh.hxx> +#include <PostItMgr.hxx> +#include <viewsh.hxx> +#include <vcl/window.hxx> + +using namespace ::com::sun::star; +using namespace util; + +String *ReplaceBackReferences( const SearchOptions& rSearchOpt, SwPaM* pPam ); + +String& lcl_CleanStr( const SwTxtNode& rNd, xub_StrLen nStart, + xub_StrLen& rEnde, SvULongs& rArr, String& rRet, + bool bRemoveSoftHyphen ) +{ + rRet = rNd.GetTxt(); + if( rArr.Count() ) + rArr.Remove( 0, rArr.Count() ); + + const SwpHints *pHts = rNd.GetpSwpHints(); + + USHORT n = 0; + xub_StrLen nSoftHyphen = nStart; + xub_StrLen nHintStart = STRING_LEN; + bool bNewHint = true; + bool bNewSoftHyphen = true; + const xub_StrLen nEnd = rEnde; + SvUShorts aReplaced; + + do + { + if ( bNewHint ) + nHintStart = pHts && n < pHts->Count() ? + *(*pHts)[n]->GetStart() : + STRING_LEN; + + if ( bNewSoftHyphen ) + nSoftHyphen = bRemoveSoftHyphen ? + rNd.GetTxt().Search( CHAR_SOFTHYPHEN, nSoftHyphen ) : + STRING_LEN; + + bNewHint = false; + bNewSoftHyphen = false; + + xub_StrLen nStt = 0; + + // Check if next stop is a hint. + if ( STRING_LEN != nHintStart && nHintStart < nSoftHyphen && nHintStart < nEnd ) + { + nStt = nHintStart; + bNewHint = true; + } + // Check if next stop is a soft hyphen. + else if ( STRING_LEN != nSoftHyphen && nSoftHyphen < nHintStart && nSoftHyphen < nEnd ) + { + nStt = nSoftHyphen; + bNewSoftHyphen = true; + } + // If nSoftHyphen == nHintStart, the current hint *must* be a hint with an end. + else if ( STRING_LEN != nSoftHyphen && nSoftHyphen == nHintStart ) + { + nStt = nSoftHyphen; + bNewHint = true; + bNewSoftHyphen = true; + } + else + break; + + const xub_StrLen nAkt = nStt - rArr.Count(); + + if ( bNewHint ) + { + const SwTxtAttr* pHt = (*pHts)[n]; + if ( pHt->HasDummyChar() && (nStt >= nStart) ) + { + //JP 17.05.00: Task 75806 ask for ">=" and not for ">" + switch( pHt->Which() ) + { + case RES_TXTATR_FLYCNT: + case RES_TXTATR_FTN: + case RES_TXTATR_FIELD: + case RES_TXTATR_REFMARK: + case RES_TXTATR_TOXMARK: + case RES_TXTATR_META: + case RES_TXTATR_METAFIELD: + { + // JP 06.05.98: mit Bug 50100 werden sie als Trenner erwuenscht und nicht + // mehr zum Wort dazu gehoerend. + // MA 23.06.98: mit Bug 51215 sollen sie konsequenterweise auch am + // Satzanfang und -ende ignoriert werden wenn sie Leer sind. + // Dazu werden sie schlicht entfernt. Fuer den Anfang entfernen + // wir sie einfach. + // Fuer das Ende merken wir uns die Ersetzungen und entferenen + // hinterher alle am Stringende (koenten ja 'normale' 0x7f drinstehen + BOOL bEmpty = RES_TXTATR_FIELD != pHt->Which() || + !(static_cast<SwTxtFld const*>(pHt) + ->GetFld().GetFld()->ExpandField( + rNd.GetDoc()->IsClipBoard()).Len()); + if ( bEmpty && nStart == nAkt ) + { + rArr.Insert( nAkt, rArr.Count() ); + --rEnde; + rRet.Erase( nAkt, 1 ); + } + else + { + if ( bEmpty ) + aReplaced.Insert( nAkt, aReplaced.Count() ); + rRet.SetChar( nAkt, '\x7f' ); + } + } + break; + default: + ASSERT( false, "unknown case in lcl_CleanStr" ) + break; + } + } + ++n; + } + + if ( bNewSoftHyphen ) + { + rArr.Insert( nAkt, rArr.Count() ); + --rEnde; + rRet.Erase( nAkt, 1 ); + ++nSoftHyphen; + } + } + while ( true ); + + for( USHORT i = aReplaced.Count(); i; ) + { + const xub_StrLen nTmp = aReplaced[ --i ]; + if( nTmp == rRet.Len() - 1 ) + { + rRet.Erase( nTmp ); + rArr.Insert( nTmp, rArr.Count() ); + --rEnde; + } + } + + return rRet; +} + +// skip all non SwPostIts inside the array +xub_StrLen GetPostIt(xub_StrLen aCount,const SwpHints *pHts) +{ + xub_StrLen aIndex = 0; + while (aCount) + { + for (xub_StrLen i = 0; i <pHts->Count();i++) + { + aIndex++; + const SwTxtAttr* pTxtAttr = (*pHts)[i]; + if ( (pTxtAttr->Which()==RES_TXTATR_FIELD) && + (pTxtAttr->GetFld().GetFld()->Which()==RES_POSTITFLD)) + { + aCount--; + if (!aCount) + break; + } + } + } + // throw away all following non postits + for (xub_StrLen i = aIndex; i <pHts->Count();i++) + { + const SwTxtAttr* pTxtAttr = (*pHts)[i]; + if ( (pTxtAttr->Which()==RES_TXTATR_FIELD) && + (pTxtAttr->GetFld().GetFld()->Which()==RES_POSTITFLD)) + break; + else + aIndex++; + } + return aIndex; +} + +BYTE SwPaM::Find( const SearchOptions& rSearchOpt, BOOL bSearchInNotes , utl::TextSearch& rSTxt, + SwMoveFn fnMove, const SwPaM * pRegion, + BOOL bInReadOnly ) +{ + if( !rSearchOpt.searchString.getLength() ) + return FALSE; + + SwPaM* pPam = MakeRegion( fnMove, pRegion ); + BOOL bSrchForward = fnMove == fnMoveForward; + SwNodeIndex& rNdIdx = pPam->GetPoint()->nNode; + SwIndex& rCntntIdx = pPam->GetPoint()->nContent; + + // Wenn am Anfang/Ende, aus dem Node moven + // beim leeren Node nicht weiter + if( bSrchForward + ? ( rCntntIdx.GetIndex() == pPam->GetCntntNode()->Len() && + rCntntIdx.GetIndex() ) + : !rCntntIdx.GetIndex() && pPam->GetCntntNode()->Len() ) + { + if( !(*fnMove->fnNds)( &rNdIdx, FALSE )) + { + delete pPam; + return FALSE; + } + SwCntntNode *pNd = rNdIdx.GetNode().GetCntntNode(); + xub_StrLen nTmpPos = bSrchForward ? 0 : pNd->Len(); + rCntntIdx.Assign( pNd, nTmpPos ); + } + + /* + * Ist bFound == TRUE, dann wurde der String gefunden und in + * nStart und nEnde steht der gefundenen String + */ + BOOL bFound = FALSE; + /* + * StartPostion im Text oder Anfangsposition + */ + BOOL bFirst = TRUE; + SwCntntNode * pNode; + //testarea + //String sCleanStr; + //SvULongs aFltArr; + //const SwNode* pSttNd = &rNdIdx.GetNode(); + + xub_StrLen nStart, nEnde, nTxtLen; + + BOOL bRegSearch = SearchAlgorithms_REGEXP == rSearchOpt.algorithmType; + BOOL bChkEmptyPara = bRegSearch && 2 == rSearchOpt.searchString.getLength() && + ( !rSearchOpt.searchString.compareToAscii( "^$" ) || + !rSearchOpt.searchString.compareToAscii( "$^" ) ); + BOOL bChkParaEnd = bRegSearch && 1 == rSearchOpt.searchString.getLength() && + !rSearchOpt.searchString.compareToAscii( "$" ); + +// LanguageType eLastLang = 0; + while( 0 != ( pNode = ::GetNode( *pPam, bFirst, fnMove, bInReadOnly ) )) + { + if( pNode->IsTxtNode() ) + { + nTxtLen = ((SwTxtNode*)pNode)->GetTxt().Len(); + if( rNdIdx == pPam->GetMark()->nNode ) + nEnde = pPam->GetMark()->nContent.GetIndex(); + else + nEnde = bSrchForward ? nTxtLen : 0; + nStart = rCntntIdx.GetIndex(); + + /* #i80135# */ + // if there are SwPostItFields inside our current node text, we split the text into seperate pieces + // and search for text inside the pieces as well as inside the fields + const SwpHints *pHts = ((SwTxtNode*)pNode)->GetpSwpHints(); + + // count postitfields by looping over all fields + xub_StrLen aNumberPostits = 0; + xub_StrLen aIgnore = 0; + if (pHts && bSearchInNotes) + { + if (!bSrchForward) + { + xub_StrLen swap = nEnde; + nEnde = nStart; + nStart = swap; + } + + for (xub_StrLen i = 0; i <pHts->Count();i++) + { + xub_StrLen aPos = *(*pHts)[i]->GetStart(); + const SwTxtAttr* pTxtAttr = (*pHts)[i]; + if ( (pTxtAttr->Which()==RES_TXTATR_FIELD) && + (pTxtAttr->GetFld().GetFld()->Which()==RES_POSTITFLD)) + { + if ( (aPos >= nStart) && (aPos <= nEnde) ) + aNumberPostits++; + else + { + if (bSrchForward) + aIgnore++; + } + } + } + + if (!bSrchForward) + { + xub_StrLen swap = nEnde; + nEnde = nStart; + nStart = swap; + } + + } + + SwDocShell *const pDocShell = pNode->GetDoc()->GetDocShell(); + ViewShell *const pWrtShell = (pDocShell) ? (ViewShell*)(pDocShell->GetWrtShell()) : 0; + SwPostItMgr *const pPostItMgr = (pWrtShell) ? pWrtShell->GetPostItMgr() : 0; + + xub_StrLen aStart = 0; + // do we need to finish a note? + if (pPostItMgr && pPostItMgr->HasActiveSidebarWin()) + { + if (bSearchInNotes) + { + if (bSrchForward) + aStart++; + else + { + if (aNumberPostits) + --aNumberPostits; + } + //search inside and finsih and put focus back into the doc + if (pPostItMgr->FinishSearchReplace(rSearchOpt,bSrchForward)) + { + bFound = true ; + break; + } + } + else + { + pPostItMgr->SetActiveSidebarWin(0); + } + } + + if (aNumberPostits) + { + // now we have to split + xub_StrLen nStartInside = 0; + xub_StrLen nEndeInside = 0; + sal_Int16 aLoop= bSrchForward ? aStart : aNumberPostits; + + while ( (aLoop>=0) && (aLoop<=aNumberPostits)) + { + if (bSrchForward) + { + nStartInside = aLoop==0 ? nStart : *(*pHts)[GetPostIt(aLoop+aIgnore-1,pHts)]->GetStart()+1; + nEndeInside = aLoop==aNumberPostits? nEnde : *(*pHts)[GetPostIt(aLoop+aIgnore,pHts)]->GetStart(); + nTxtLen = nEndeInside-nStartInside; + } + else + { + nStartInside = aLoop==aNumberPostits ? nStart : *(*pHts)[GetPostIt(aLoop+aIgnore,pHts)]->GetStart(); + nEndeInside = aLoop==0 ? nEnde : *(*pHts)[GetPostIt(aLoop+aIgnore-1,pHts)]->GetStart()+1; + nTxtLen = nStartInside-nEndeInside; + } + // search inside the text between a note + bFound = DoSearch(rSearchOpt,rSTxt,fnMove,bSrchForward,bRegSearch,bChkEmptyPara,bChkParaEnd, + nStartInside,nEndeInside,nTxtLen, pNode,pPam); + if (bFound) + break; + else + { + // we should now be right in front of a note, search inside + if ( (bSrchForward && (GetPostIt(aLoop + aIgnore,pHts) < pHts->Count()) ) || ( !bSrchForward && (aLoop!=0) )) + { + const SwTxtAttr* pTxtAttr = bSrchForward ? (*pHts)[GetPostIt(aLoop+aIgnore,pHts)] : (*pHts)[GetPostIt(aLoop+aIgnore-1,pHts)]; + if ( pPostItMgr && pPostItMgr->SearchReplace(((SwTxtFld*)pTxtAttr)->GetFld(),rSearchOpt,bSrchForward) ) + { + bFound = true ; + break; + } + } + } + aLoop = bSrchForward ? aLoop+1 : aLoop-1; + } + } + else + { + // if there is no SwPostItField inside or searching inside notes is disabled, we search the whole length just like before + bFound = DoSearch(rSearchOpt,rSTxt,fnMove,bSrchForward,bRegSearch,bChkEmptyPara,bChkParaEnd, + nStart,nEnde,nTxtLen, pNode,pPam); + } + if (bFound) + break; + } + } + delete pPam; + return bFound; +} + +bool SwPaM::DoSearch( const SearchOptions& rSearchOpt, utl::TextSearch& rSTxt, + SwMoveFn fnMove, + BOOL bSrchForward, BOOL bRegSearch, BOOL bChkEmptyPara, BOOL bChkParaEnd, + xub_StrLen &nStart, xub_StrLen &nEnde, xub_StrLen nTxtLen,SwNode* pNode, SwPaM* pPam) +{ + bool bFound = false; + SwNodeIndex& rNdIdx = pPam->GetPoint()->nNode; + const SwNode* pSttNd = &rNdIdx.GetNode(); + String sCleanStr; + SvULongs aFltArr; + LanguageType eLastLang = 0; + // if the search string contains a soft hypen, we don't strip them from the text: + bool bRemoveSoftHyphens = true; + if ( bRegSearch ) + { + const rtl::OUString a00AD( rtl::OUString::createFromAscii( "\\x00AD" ) ); + if ( -1 != rSearchOpt.searchString.indexOf( a00AD ) ) + bRemoveSoftHyphens = false; + } + else + { + if ( 1 == rSearchOpt.searchString.getLength() && + CHAR_SOFTHYPHEN == rSearchOpt.searchString.toChar() ) + bRemoveSoftHyphens = false; + } + + if( bSrchForward ) + lcl_CleanStr( *(SwTxtNode*)pNode, nStart, nEnde, + aFltArr, sCleanStr, bRemoveSoftHyphens ); + else + lcl_CleanStr( *(SwTxtNode*)pNode, nEnde, nStart, + aFltArr, sCleanStr, bRemoveSoftHyphens ); + + SwScriptIterator* pScriptIter = 0; + USHORT nSearchScript = 0; + USHORT nCurrScript = 0; + + if ( SearchAlgorithms_APPROXIMATE == rSearchOpt.algorithmType && + pBreakIt->GetBreakIter().is() ) + { + pScriptIter = new SwScriptIterator( sCleanStr, nStart, bSrchForward ); + nSearchScript = pBreakIt->GetRealScriptOfText( rSearchOpt.searchString, 0 ); + } + + xub_StrLen nStringEnd = nEnde; + while ( (bSrchForward && nStart < nStringEnd) || + (! bSrchForward && nStart > nStringEnd) ) + { + // SearchAlgorithms_APPROXIMATE works on a per word base + // so we have to provide the text searcher with the correct + // locale, because it uses the breakiterator + if ( pScriptIter ) + { + nEnde = pScriptIter->GetScriptChgPos(); + nCurrScript = pScriptIter->GetCurrScript(); + if ( nSearchScript == nCurrScript ) + { + const LanguageType eCurrLang = + ((SwTxtNode*)pNode)->GetLang( bSrchForward ? + nStart : + nEnde ); + + if ( eCurrLang != eLastLang ) + { + const lang::Locale aLocale( + pBreakIt->GetLocale( eCurrLang ) ); + rSTxt.SetLocale( rSearchOpt, aLocale ); + eLastLang = eCurrLang; + } + } + pScriptIter->Next(); + } + + if( nSearchScript == nCurrScript && + (rSTxt.*fnMove->fnSearch)( sCleanStr, &nStart, &nEnde, 0 )) + { + // setze den Bereich richtig + *GetPoint() = *pPam->GetPoint(); + SetMark(); + + // Start und Ende wieder korrigieren !! + if( aFltArr.Count() ) + { + xub_StrLen n, nNew; + // bei Rueckwaertssuche die Positionen temp. vertauschen + if( !bSrchForward ) { n = nStart; nStart = nEnde; nEnde = n; } + + for( n = 0, nNew = nStart; + n < aFltArr.Count() && aFltArr[ n ] <= nStart; + ++n, ++nNew ) + ; + nStart = nNew; + for( n = 0, nNew = nEnde; + n < aFltArr.Count() && aFltArr[ n ] < nEnde; + ++n, ++nNew ) + ; + nEnde = nNew; + + // bei Rueckwaertssuche die Positionen temp. vertauschen + if( !bSrchForward ) { n = nStart; nStart = nEnde; nEnde = n; } + } + GetMark()->nContent = nStart; // Startposition setzen + GetPoint()->nContent = nEnde; + + if( !bSrchForward ) // rueckwaerts Suche? + Exchange(); // Point und Mark tauschen + bFound = TRUE; + break; + } + + nStart = nEnde; + } // end of script while + + delete pScriptIter; + + if ( bFound ) + return true; + else if( ( bChkEmptyPara && !nStart && !nTxtLen ) || bChkParaEnd ) + { + *GetPoint() = *pPam->GetPoint(); + GetPoint()->nContent = bChkParaEnd ? nTxtLen : 0; + SetMark(); + if( (bSrchForward || pSttNd != &rNdIdx.GetNode()) && + Move( fnMoveForward, fnGoCntnt ) && + (!bSrchForward || pSttNd != &GetPoint()->nNode.GetNode()) && + 1 == Abs( (int)( GetPoint()->nNode.GetIndex() - + GetMark()->nNode.GetIndex()) ) ) + { + if( !bSrchForward ) // rueckwaerts Suche? + Exchange(); // Point und Mark tauschen + //bFound = TRUE; + //break; + return true; + } + } + return bFound; +} + +// Parameter fuers Suchen und Ersetzen von Text +struct SwFindParaText : public SwFindParas +{ + const SearchOptions& rSearchOpt; + SwCursor& rCursor; + utl::TextSearch aSTxt; + BOOL bReplace; + BOOL bSearchInNotes; + + SwFindParaText( const SearchOptions& rOpt, BOOL bSearchNotes, int bRepl, SwCursor& rCrsr ) + : rSearchOpt( rOpt ), rCursor( rCrsr ), aSTxt( rOpt ), bReplace( 0 != bRepl ), bSearchInNotes( bSearchNotes ) + {} + virtual int Find( SwPaM* , SwMoveFn , const SwPaM*, BOOL bInReadOnly ); + virtual int IsReplaceMode() const; + virtual ~SwFindParaText(); +}; + +SwFindParaText::~SwFindParaText() +{ +} + +int SwFindParaText::Find( SwPaM* pCrsr, SwMoveFn fnMove, + const SwPaM* pRegion, BOOL bInReadOnly ) +{ + if( bInReadOnly && bReplace ) + bInReadOnly = FALSE; + + BOOL bFnd = (BOOL)pCrsr->Find( rSearchOpt, bSearchInNotes, aSTxt, fnMove, pRegion, bInReadOnly ); + + /* #i80135# if we found something in a note, Mark and Point is the same + if( bFnd && *pCrsr->GetMark() == *pCrsr->GetPoint() ) + return FIND_NOT_FOUND; + */ + + if( bFnd && bReplace ) // String ersetzen ?? + { + // Replace-Methode vom SwDoc benutzen + const bool bRegExp(SearchAlgorithms_REGEXP == rSearchOpt.algorithmType); + SwIndex& rSttCntIdx = pCrsr->Start()->nContent; + xub_StrLen nSttCnt = rSttCntIdx.GetIndex(); + // damit die Region auch verschoben wird, in den Shell-Cursr-Ring + // mit aufnehmen !! + Ring *pPrev(0); + if( bRegExp ) + { + pPrev = pRegion->GetPrev(); + ((Ring*)pRegion)->MoveRingTo( &rCursor ); + } + + ::std::auto_ptr<String> pRepl( (bRegExp) + ? ReplaceBackReferences( rSearchOpt, pCrsr ) : 0 ); + rCursor.GetDoc()->ReplaceRange( *pCrsr, + (pRepl.get()) ? *pRepl : String(rSearchOpt.replaceString), + bRegExp ); + rCursor.SaveTblBoxCntnt( pCrsr->GetPoint() ); + + if( bRegExp ) + { + // und die Region wieder herausnehmen: + Ring *p, *pNext = (Ring*)pRegion; + do { + p = pNext; + pNext = p->GetNext(); + p->MoveTo( (Ring*)pRegion ); + } while( p != pPrev ); + } + pCrsr->Start()->nContent = nSttCnt; + return FIND_NO_RING; + } + return bFnd ? FIND_FOUND : FIND_NOT_FOUND; +} + + +int SwFindParaText::IsReplaceMode() const +{ + return bReplace; +} + + +ULONG SwCursor::Find( const SearchOptions& rSearchOpt, BOOL bSearchInNotes, + SwDocPositions nStart, SwDocPositions nEnde, + BOOL& bCancel, + FindRanges eFndRngs, int bReplace ) +{ + // OLE-Benachrichtigung abschalten !! + SwDoc* pDoc = GetDoc(); + Link aLnk( pDoc->GetOle2Link() ); + pDoc->SetOle2Link( Link() ); + + BOOL bSttUndo = pDoc->DoesUndo() && bReplace; + if( bSttUndo ) + pDoc->StartUndo( UNDO_REPLACE, NULL ); + + BOOL bSearchSel = 0 != (rSearchOpt.searchFlag & SearchFlags::REG_NOT_BEGINOFLINE); + if( bSearchSel ) + eFndRngs = (FindRanges)(eFndRngs | FND_IN_SEL); + SwFindParaText aSwFindParaText( rSearchOpt, bSearchInNotes, bReplace, *this ); + ULONG nRet = FindAll( aSwFindParaText, nStart, nEnde, eFndRngs, bCancel ); + pDoc->SetOle2Link( aLnk ); + if( nRet && bReplace ) + pDoc->SetModified(); + + if( bSttUndo ) + pDoc->EndUndo( UNDO_REPLACE, NULL ); + return nRet; +} + +String *ReplaceBackReferences( const SearchOptions& rSearchOpt, SwPaM* pPam ) +{ + String *pRet = 0; + if( pPam && pPam->HasMark() && + SearchAlgorithms_REGEXP == rSearchOpt.algorithmType ) + { + const SwCntntNode* pTxtNode = pPam->GetCntntNode( TRUE ); + if( pTxtNode && pTxtNode->IsTxtNode() && pTxtNode == pPam->GetCntntNode( FALSE ) ) + { + utl::TextSearch aSTxt( rSearchOpt ); + String aStr( pPam->GetTxt() ); + String aSearchStr( rSearchOpt.searchString ); + String aReplaceStr( rSearchOpt.replaceString ); + aStr.EraseAllChars( CH_TXTATR_BREAKWORD ); + aStr.EraseAllChars( CH_TXTATR_INWORD ); + xub_StrLen nStart = 0; + String sX( 'x' ); + if( pPam->Start()->nContent > 0 ) + { + aStr.Insert( sX, 0 ); + ++nStart; + } + xub_StrLen nEnd = aStr.Len(); + bool bDeleteLastX = false; + if( pPam->End()->nContent < (static_cast<const SwTxtNode*>(pTxtNode))->GetTxt().Len() ) + { + aStr.Insert( sX ); + bDeleteLastX = true; + } + SearchResult aResult; + if( aSTxt.SearchFrwrd( aStr, &nStart, &nEnd, &aResult ) ) + { + if( bDeleteLastX ) + aStr.Erase( aStr.Len() - 1 ); + aSTxt.ReplaceBackReferences( aReplaceStr, aStr, aResult ); + pRet = new String( aReplaceStr ); + } + } + } + return pRet; +} + + diff --git a/sw/source/core/crsr/makefile.mk b/sw/source/core/crsr/makefile.mk new file mode 100644 index 000000000000..a2571901c068 --- /dev/null +++ b/sw/source/core/crsr/makefile.mk @@ -0,0 +1,83 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/..$/.. + +PRJNAME=sw +TARGET=crsr + +AUTOSEG=true + +# --- Settings ----------------------------------------------------- + +.INCLUDE : $(PRJ)$/inc$/swpre.mk +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/inc$/sw.mk + +.IF "$(mydebug)" != "" +CDEFS+=-Dmydebug +.ENDIF + +# --- Files -------------------------------------------------------- + +EXCEPTIONSFILES= \ + $(SLO)$/crbm.obj \ + $(SLO)$/crsrsh.obj \ + $(SLO)$/bookmrk.obj \ + $(SLO)$/viscrs.obj + +SLOFILES = \ + $(SLO)$/BlockCursor.obj \ + $(SLO)$/bookmrk.obj \ + $(SLO)$/callnk.obj \ + $(SLO)$/crbm.obj \ + $(SLO)$/crsrsh.obj \ + $(SLO)$/crstrvl.obj \ + $(SLO)$/crstrvl1.obj \ + $(SLO)$/findattr.obj \ + $(SLO)$/findcoll.obj \ + $(SLO)$/findfmt.obj \ + $(SLO)$/findtxt.obj \ + $(SLO)$/pam.obj \ + $(SLO)$/paminit.obj \ + $(SLO)$/swcrsr.obj \ + $(SLO)$/trvlcol.obj \ + $(SLO)$/trvlfnfl.obj \ + $(SLO)$/trvlreg.obj \ + $(SLO)$/trvltbl.obj \ + $(SLO)$/unocrsr.obj \ + $(SLO)$/viscrs.obj \ + $(SLO)$/crossrefbookmark.obj + +.IF "$(mydebug)" != "" +SLOFILES += \ + $(SLO)$/pamio.obj +.ENDIF + +# --- Tagets ------------------------------------------------------- + +.INCLUDE : target.mk diff --git a/sw/source/core/crsr/pam.cxx b/sw/source/core/crsr/pam.cxx new file mode 100644 index 000000000000..ec30b5aefbe0 --- /dev/null +++ b/sw/source/core/crsr/pam.cxx @@ -0,0 +1,1246 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <hintids.hxx> +#include <editeng/protitem.hxx> +#include <cntfrm.hxx> +#include <pagefrm.hxx> +#include <doc.hxx> +#include <docary.hxx> +#include <pam.hxx> +#include <pamtyp.hxx> +#include <txtfrm.hxx> +#include <section.hxx> +#include <fmtcntnt.hxx> +#include <frmatr.hxx> +#include <swtable.hxx> +#include <crsskip.hxx> + +// --> FME 2004-06-29 #114856# Formular view +#include <flyfrm.hxx> +#include <fmteiro.hxx> +#include <section.hxx> +#include <sectfrm.hxx> +// <-- +#include <ndtxt.hxx> // #111827# + +#include <IMark.hxx> +#include <hints.hxx> + +// fuer den dummen ?MSC-? Compiler +inline xub_StrLen GetSttOrEnd( BOOL bCondition, const SwCntntNode& rNd ) +{ + return bCondition ? 0 : rNd.Len(); +} + +/************************************************************************* +|* +|* SwPosition +|* +|* Beschreibung PAM.DOC +|* Ersterstellung VB 4.3.91 +|* Letzte Aenderung VB 4.3.91 +|* +*************************************************************************/ + + +SwPosition::SwPosition( const SwNodeIndex & rNodeIndex, const SwIndex & rCntnt ) + : nNode( rNodeIndex ), nContent( rCntnt ) +{ +} + +SwPosition::SwPosition( const SwNodeIndex & rNodeIndex ) + : nNode( rNodeIndex ), nContent( nNode.GetNode().GetCntntNode() ) +{ +} + +SwPosition::SwPosition( const SwNode& rNode ) + : nNode( rNode ), nContent( nNode.GetNode().GetCntntNode() ) +{ +} + +SwPosition::SwPosition( SwCntntNode & rNode, const xub_StrLen nOffset ) + : nNode( rNode ), nContent( &rNode, nOffset ) +{ +} + + +SwPosition::SwPosition( const SwPosition & rPos ) + : nNode( rPos.nNode ), nContent( rPos.nContent ) +{ +} + +SwPosition &SwPosition::operator=(const SwPosition &rPos) +{ + nNode = rPos.nNode; + nContent = rPos.nContent; + return *this; +} + + +BOOL SwPosition::operator<(const SwPosition &rPos) const +{ + if( nNode < rPos.nNode ) + return TRUE; + if( nNode == rPos.nNode ) + return ( nContent < rPos.nContent ); + return FALSE; +} + + +BOOL SwPosition::operator>(const SwPosition &rPos) const +{ + if(nNode > rPos.nNode ) + return TRUE; + if( nNode == rPos.nNode ) + return ( nContent > rPos.nContent ); + return FALSE; +} + + +BOOL SwPosition::operator<=(const SwPosition &rPos) const +{ + if(nNode < rPos.nNode ) + return TRUE; + if( nNode == rPos.nNode ) + return ( nContent <= rPos.nContent ); + return FALSE; +} + + +BOOL SwPosition::operator>=(const SwPosition &rPos) const +{ + if(nNode > rPos.nNode ) + return TRUE; + if( nNode == rPos.nNode ) + return ( nContent >= rPos.nContent ); + return FALSE; +} + + +BOOL SwPosition::operator==(const SwPosition &rPos) const +{ + return + ( ( nNode == rPos.nNode ) && ( nContent == rPos.nContent ) ? + TRUE: FALSE); +} + + +BOOL SwPosition::operator!=(const SwPosition &rPos) const +{ + if( nNode != rPos.nNode ) + return TRUE; + return ( nContent != rPos.nContent ); +} + +SwDoc * SwPosition::GetDoc() const +{ + return nNode.GetNode().GetDoc(); +} + +SwComparePosition ComparePosition( + const SwPosition& rStt1, const SwPosition& rEnd1, + const SwPosition& rStt2, const SwPosition& rEnd2 ) +{ + SwComparePosition nRet; + if( rStt1 < rStt2 ) + { + if( rEnd1 > rStt2 ) + { + if( rEnd1 >= rEnd2 ) + nRet = POS_OUTSIDE; + else + nRet = POS_OVERLAP_BEFORE; + + } + else if( rEnd1 == rStt2 ) + nRet = POS_COLLIDE_END; + else + nRet = POS_BEFORE; + } + else if( rEnd2 > rStt1 ) + { + if( rEnd2 >= rEnd1 ) + { + if( rEnd2 == rEnd1 && rStt2 == rStt1 ) + nRet = POS_EQUAL; + else + nRet = POS_INSIDE; + } + else + { + if (rStt1 == rStt2) + nRet = POS_OUTSIDE; + else + nRet = POS_OVERLAP_BEHIND; + } + } + else if( rEnd2 == rStt1 ) + nRet = POS_COLLIDE_START; + else + nRet = POS_BEHIND; + return nRet; +} + +SwComparePosition ComparePosition( + const unsigned long nStt1, const unsigned long nEnd1, + const unsigned long nStt2, const unsigned long nEnd2 ) +{ + SwComparePosition nRet; + if( nStt1 < nStt2 ) + { + if( nEnd1 > nStt2 ) + { + if( nEnd1 >= nEnd2 ) + nRet = POS_OUTSIDE; + else + nRet = POS_OVERLAP_BEFORE; + + } + else if( nEnd1 == nStt2 ) + nRet = POS_COLLIDE_END; + else + nRet = POS_BEFORE; + } + else if( nEnd2 > nStt1 ) + { + if( nEnd2 >= nEnd1 ) + { + if( nEnd2 == nEnd1 && nStt2 == nStt1 ) + nRet = POS_EQUAL; + else + nRet = POS_INSIDE; + } + else + { + if (nStt1 == nStt2) + nRet = POS_OUTSIDE; + else + nRet = POS_OVERLAP_BEHIND; + } + } + else if( nEnd2 == nStt1 ) + nRet = POS_COLLIDE_START; + else + nRet = POS_BEHIND; + return nRet; +} + +/* */ + +enum CHKSECTION { Chk_Both, Chk_One, Chk_None }; + + +CHKSECTION lcl_TstIdx( ULONG nSttIdx, ULONG nEndIdx, const SwNode& rEndNd ) +{ + ULONG nStt = rEndNd.StartOfSectionIndex(), nEnd = rEndNd.GetIndex(); + CHKSECTION eSec = nStt < nSttIdx && nEnd >= nSttIdx ? Chk_One : Chk_None; + if( nStt < nEndIdx && nEnd >= nEndIdx ) + return( eSec == Chk_One ? Chk_Both : Chk_One ); + return eSec; +} + + +BOOL lcl_ChkOneRange( CHKSECTION eSec, BOOL bChkSections, + const SwNode& rBaseEnd, ULONG nStt, ULONG nEnd ) +{ + if( eSec != Chk_Both ) + return FALSE; + + if( !bChkSections ) + return TRUE; + + // suche die umspannende Section + const SwNodes& rNds = rBaseEnd.GetNodes(); + const SwNode *pTmp, *pNd = rNds[ nStt ]; + if( !pNd->IsStartNode() ) + pNd = pNd->StartOfSectionNode(); + + if( pNd == rNds[ nEnd ]->StartOfSectionNode() ) + return TRUE; // der gleiche StartNode, die selbe Section + + // steht schon auf einem GrundSection Node ? Fehler !!! + if( !pNd->StartOfSectionIndex() ) + return FALSE; + + while( ( pTmp = pNd->StartOfSectionNode())->EndOfSectionNode() != + &rBaseEnd ) + pNd = pTmp; + + ULONG nSttIdx = pNd->GetIndex(), nEndIdx = pNd->EndOfSectionIndex(); + return nSttIdx <= nStt && nStt <= nEndIdx && + nSttIdx <= nEnd && nEnd <= nEndIdx ? TRUE : FALSE; +} + + +BOOL CheckNodesRange( const SwNodeIndex& rStt, + const SwNodeIndex& rEnd, BOOL bChkSection ) +{ + const SwNodes& rNds = rStt.GetNodes(); + ULONG nStt = rStt.GetIndex(), nEnd = rEnd.GetIndex(); + CHKSECTION eSec = lcl_TstIdx( nStt, nEnd, rNds.GetEndOfContent() ); + if( Chk_None != eSec ) return eSec == Chk_Both ? TRUE : FALSE; + + eSec = lcl_TstIdx( nStt, nEnd, rNds.GetEndOfAutotext() ); + if( Chk_None != eSec ) + return lcl_ChkOneRange( eSec, bChkSection, + rNds.GetEndOfAutotext(), nStt, nEnd ); + + eSec = lcl_TstIdx( nStt, nEnd, rNds.GetEndOfPostIts() ); + if( Chk_None != eSec ) + return lcl_ChkOneRange( eSec, bChkSection, + rNds.GetEndOfPostIts(), nStt, nEnd ); + + eSec = lcl_TstIdx( nStt, nEnd, rNds.GetEndOfInserts() ); + if( Chk_None != eSec ) + return lcl_ChkOneRange( eSec, bChkSection, + rNds.GetEndOfInserts(), nStt, nEnd ); + + eSec = lcl_TstIdx( nStt, nEnd, rNds.GetEndOfRedlines() ); + if( Chk_None != eSec ) + return lcl_ChkOneRange( eSec, bChkSection, + rNds.GetEndOfRedlines(), nStt, nEnd ); + + return FALSE; // liegt irgendwo dazwischen, FEHLER +} + + +BOOL GoNext(SwNode* pNd, SwIndex * pIdx, USHORT nMode ) +{ + if( pNd->IsCntntNode() ) + return ((SwCntntNode*)pNd)->GoNext( pIdx, nMode ); + return FALSE; +} + + +BOOL GoPrevious( SwNode* pNd, SwIndex * pIdx, USHORT nMode ) +{ + if( pNd->IsCntntNode() ) + return ((SwCntntNode*)pNd)->GoPrevious( pIdx, nMode ); + return FALSE; +} + + +SwCntntNode* GoNextNds( SwNodeIndex* pIdx, BOOL bChk ) +{ + SwNodeIndex aIdx( *pIdx ); + SwCntntNode* pNd = aIdx.GetNodes().GoNext( &aIdx ); + if( pNd ) + { + if( bChk && 1 != aIdx.GetIndex() - pIdx->GetIndex() && + !CheckNodesRange( *pIdx, aIdx, TRUE ) ) + pNd = 0; + else + *pIdx = aIdx; + } + return pNd; +} + + +SwCntntNode* GoPreviousNds( SwNodeIndex * pIdx, BOOL bChk ) +{ + SwNodeIndex aIdx( *pIdx ); + SwCntntNode* pNd = aIdx.GetNodes().GoPrevious( &aIdx ); + if( pNd ) + { + if( bChk && 1 != pIdx->GetIndex() - aIdx.GetIndex() && + !CheckNodesRange( *pIdx, aIdx, TRUE ) ) + pNd = 0; + else + *pIdx = aIdx; + } + return pNd; +} + +// ---------------------------------------------------------------------- + +/************************************************************************* +|* +|* SwPointAndMark +|* +|* Beschreibung PAM.DOC +|* Ersterstellung VB 4.3.91 +|* Letzte Aenderung JP 6.5.91 +|* +*************************************************************************/ + +SwPaM::SwPaM( const SwPosition& rPos, SwPaM* pRing ) + : Ring( pRing ) + , m_Bound1( rPos ) + , m_Bound2( rPos.nNode.GetNode().GetNodes() ) // default initialize + , m_pPoint( &m_Bound1 ) + , m_pMark( m_pPoint ) + , m_bIsInFrontOfLabel( false ) +{ +} + +SwPaM::SwPaM( const SwPosition& rMark, const SwPosition& rPoint, SwPaM* pRing ) + : Ring( pRing ) + , m_Bound1( rMark ) + , m_Bound2( rPoint ) + , m_pPoint( &m_Bound2 ) + , m_pMark( &m_Bound1 ) + , m_bIsInFrontOfLabel( false ) +{ +} + +SwPaM::SwPaM( const SwNodeIndex& rMark, const SwNodeIndex& rPoint, + long nMarkOffset, long nPointOffset, SwPaM* pRing ) + : Ring( pRing ) + , m_Bound1( rMark ) + , m_Bound2( rPoint ) + , m_pPoint( &m_Bound2 ) + , m_pMark( &m_Bound1 ) + , m_bIsInFrontOfLabel( false ) +{ + if ( nMarkOffset ) + { + m_pMark->nNode += nMarkOffset; + } + if ( nPointOffset ) + { + m_pPoint->nNode += nPointOffset; + } + + m_Bound1.nContent.Assign( m_Bound1.nNode.GetNode().GetCntntNode(), 0 ); + m_Bound2.nContent.Assign( m_Bound2.nNode.GetNode().GetCntntNode(), 0 ); +} + +SwPaM::SwPaM( const SwNode& rMark, const SwNode& rPoint, + long nMarkOffset, long nPointOffset, SwPaM* pRing ) + : Ring( pRing ) + , m_Bound1( rMark ) + , m_Bound2( rPoint ) + , m_pPoint( &m_Bound2 ) + , m_pMark( &m_Bound1 ) + , m_bIsInFrontOfLabel( false ) +{ + if ( nMarkOffset ) + { + m_pMark->nNode += nMarkOffset; + } + if ( nPointOffset ) + { + m_pPoint->nNode += nPointOffset; + } + + m_Bound1.nContent.Assign( m_Bound1.nNode.GetNode().GetCntntNode(), 0 ); + m_Bound2.nContent.Assign( m_Bound2.nNode.GetNode().GetCntntNode(), 0 ); +} + +SwPaM::SwPaM( const SwNodeIndex& rMark , xub_StrLen nMarkCntnt, + const SwNodeIndex& rPoint, xub_StrLen nPointCntnt, SwPaM* pRing ) + : Ring( pRing ) + , m_Bound1( rMark ) + , m_Bound2( rPoint ) + , m_pPoint( &m_Bound2 ) + , m_pMark( &m_Bound1 ) + , m_bIsInFrontOfLabel( false ) +{ + m_pPoint->nContent.Assign( rPoint.GetNode().GetCntntNode(), nPointCntnt); + m_pMark ->nContent.Assign( rMark .GetNode().GetCntntNode(), nMarkCntnt ); +} + +SwPaM::SwPaM( const SwNode& rMark , xub_StrLen nMarkCntnt, + const SwNode& rPoint, xub_StrLen nPointCntnt, SwPaM* pRing ) + : Ring( pRing ) + , m_Bound1( rMark ) + , m_Bound2( rPoint ) + , m_pPoint( &m_Bound2 ) + , m_pMark( &m_Bound1 ) + , m_bIsInFrontOfLabel( false ) +{ + m_pPoint->nContent.Assign( m_pPoint->nNode.GetNode().GetCntntNode(), + nPointCntnt); + m_pMark ->nContent.Assign( m_pMark ->nNode.GetNode().GetCntntNode(), + nMarkCntnt ); +} + +SwPaM::SwPaM( const SwNode& rNode, xub_StrLen nCntnt, SwPaM* pRing ) + : Ring( pRing ) + , m_Bound1( rNode ) + , m_Bound2( m_Bound1.nNode.GetNode().GetNodes() ) // default initialize + , m_pPoint( &m_Bound1 ) + , m_pMark( &m_Bound1 ) + , m_bIsInFrontOfLabel( false ) +{ + m_pPoint->nContent.Assign( m_pPoint->nNode.GetNode().GetCntntNode(), + nCntnt ); +} + +SwPaM::SwPaM( const SwNodeIndex& rNodeIdx, xub_StrLen nCntnt, SwPaM* pRing ) + : Ring( pRing ) + , m_Bound1( rNodeIdx ) + , m_Bound2( rNodeIdx.GetNode().GetNodes() ) // default initialize + , m_pPoint( &m_Bound1 ) + , m_pMark( &m_Bound1 ) + , m_bIsInFrontOfLabel( false ) +{ + m_pPoint->nContent.Assign( rNodeIdx.GetNode().GetCntntNode(), nCntnt ); +} + +SwPaM::~SwPaM() {} + +// @@@ semantic: no copy ctor. +SwPaM::SwPaM( SwPaM &rPam ) + : Ring( &rPam ) + , m_Bound1( *(rPam.m_pPoint) ) + , m_Bound2( *(rPam.m_pMark) ) + , m_pPoint( &m_Bound1 ), m_pMark( rPam.HasMark() ? &m_Bound2 : m_pPoint ) + , m_bIsInFrontOfLabel( false ) +{ +} + +// @@@ semantic: no copy assignment for super class Ring. +SwPaM &SwPaM::operator=( const SwPaM &rPam ) +{ + *m_pPoint = *( rPam.m_pPoint ); + if ( rPam.HasMark() ) + { + SetMark(); + *m_pMark = *( rPam.m_pMark ); + } + else + { + DeleteMark(); + } + return *this; +} + +void SwPaM::SetMark() +{ + if (m_pPoint == &m_Bound1) + { + m_pMark = &m_Bound2; + } + else + { + m_pMark = &m_Bound1; + } + (*m_pMark) = (*m_pPoint); +} + +#ifdef DBG_UTIL + +void SwPaM::Exchange() +{ + if (m_pPoint != m_pMark) + { + SwPosition *pTmp = m_pPoint; + m_pPoint = m_pMark; + m_pMark = pTmp; + } +} +#endif + +// Bewegen des Cursors + + +BOOL SwPaM::Move( SwMoveFn fnMove, SwGoInDoc fnGo ) +{ + BOOL bRet = (*fnGo)( *this, fnMove ); + + m_bIsInFrontOfLabel = false; + + return bRet; +} + + +/************************************************************************* +|* +|* void SwPaM::MakeRegion( SwMoveFn, SwPaM*, const SwPaM* ) +|* +|* Beschreibung Setzt den 1. SwPaM auf den uebergebenen SwPaM +|* oder setzt auf den Anfang oder Ende vom Document. +|* SPoint bleibt auf der Position stehen, GetMark aendert +|* sich entsprechend ! +|* +|* Parameter SwDirection gibt an, ob an Anfang / Ende +|* SwPaM * der zu setzende Bereich +|* const SwPaM& der enventuell vorgegeben Bereich +|* Return-Werte SwPaM* der entsprehend neu gesetzte Bereich +|* +|* Ersterstellung JP 26.04.91 +|* Letzte Aenderung JP 26.04.91 +|* +*************************************************************************/ + + +SwPaM* SwPaM::MakeRegion( SwMoveFn fnMove, const SwPaM * pOrigRg ) +{ + SwPaM* pPam; + if( pOrigRg == 0 ) + { + pPam = new SwPaM( *m_pPoint ); + pPam->SetMark(); // setze Anfang fest + pPam->Move( fnMove, fnGoSection); // an Anfang / Ende vom Node + + // stelle SPoint wieder auf alte Position, GetMark auf das "Ende" + pPam->Exchange(); + } + else + { + pPam = new SwPaM( *(SwPaM*)pOrigRg ); // die Suchregion ist vorgegeben + // sorge dafuer, dass SPoint auf dem "echten" StartPunkt steht + // FORWARD --> SPoint immer kleiner als GetMark + // BACKWARD --> SPoint immer groesser als GetMark + if( (pPam->GetMark()->*fnMove->fnCmpOp)( *pPam->GetPoint() ) ) + pPam->Exchange(); + } + return pPam; +} + +SwPaM & SwPaM::Normalize(BOOL bPointFirst) +{ + if (HasMark()) + if ( ( bPointFirst && *m_pPoint > *m_pMark) || + (!bPointFirst && *m_pPoint < *m_pMark) ) + { + Exchange(); + } + + return *this; +} + +USHORT SwPaM::GetPageNum( BOOL bAtPoint, const Point* pLayPos ) +{ + // return die Seitennummer am Cursor + // (fuer Reader + Seitengebundene Rahmen) + const SwCntntFrm* pCFrm; + const SwPageFrm *pPg; + const SwCntntNode *pNd ; + const SwPosition* pPos = bAtPoint ? m_pPoint : m_pMark; + + if( 0 != ( pNd = pPos->nNode.GetNode().GetCntntNode() ) && + 0 != ( pCFrm = pNd->GetFrm( pLayPos, pPos, FALSE )) && + 0 != ( pPg = pCFrm->FindPageFrm() )) + return pPg->GetPhyPageNum(); + return 0; +} + +// --> FME 2004-06-29 #114856# Formular view +// See also SwCrsrShell::IsCrsrReadonly() +const SwFrm* lcl_FindEditInReadonlyFrm( const SwFrm& rFrm ) +{ + const SwFrm* pRet = 0; + + const SwFlyFrm* pFly; + const SwSectionFrm* pSectionFrm; + + if( rFrm.IsInFly() && + (pFly = rFrm.FindFlyFrm())->GetFmt()->GetEditInReadonly().GetValue() && + pFly->Lower() && + !pFly->Lower()->IsNoTxtFrm() ) + { + pRet = pFly; + } + else if ( rFrm.IsInSct() && + 0 != ( pSectionFrm = rFrm.FindSctFrm() )->GetSection() && + pSectionFrm->GetSection()->IsEditInReadonlyFlag() ) + { + pRet = pSectionFrm; + } + + return pRet; +} +// <-- + +// steht in etwas geschuetztem oder in die Selektion umspannt +// etwas geschuetztes. +BOOL SwPaM::HasReadonlySel( bool bFormView ) const +{ + BOOL bRet = FALSE; + Point aTmpPt; + const SwCntntNode *pNd; + const SwCntntFrm *pFrm; + + if( 0 != ( pNd = GetPoint()->nNode.GetNode().GetCntntNode() )) + pFrm = pNd->GetFrm( &aTmpPt, GetPoint(), FALSE ); + else + pFrm = 0; + + // --> FME 2004-06-29 #114856# Formular view + // Will be set if point/mark are inside edit-in-readonly environment + const SwFrm* pSttEIRFrm = 0; + const SwFrm* pEndEIRFrm = 0; + + if( pFrm && ( pFrm->IsProtected() || + // --> FME 2004-06-29 #114856# Formular view + ( bFormView && + 0 == ( pSttEIRFrm = lcl_FindEditInReadonlyFrm( *pFrm ) ) ) ) ) + // <-- + bRet = TRUE; + else if( pNd ) + { + const SwSectionNode* pSNd = pNd->GetSectionNode(); + if( pSNd && ( pSNd->GetSection().IsProtectFlag() || + // --> FME 2004-06-29 #114856# Formular view + (bFormView && !pSNd->GetSection().IsEditInReadonlyFlag()) ) ) + // <-- + bRet = TRUE; + } + + if( !bRet && HasMark() && GetPoint()->nNode != GetMark()->nNode ) + { + if( 0 != ( pNd = GetMark()->nNode.GetNode().GetCntntNode() )) + pFrm = pNd->GetFrm( &aTmpPt, GetMark(), FALSE ); + else + pFrm = 0; + + if( pFrm && ( pFrm->IsProtected() || + // --> FME 2004-06-29 #114856# Formular view + ( bFormView && + 0 == ( pEndEIRFrm = lcl_FindEditInReadonlyFrm( *pFrm ) ) ) ) ) + // <-- + bRet = TRUE; + else if( pNd ) + { + const SwSectionNode* pSNd = pNd->GetSectionNode(); + if( pSNd && ( pSNd->GetSection().IsProtectFlag() || + // --> FME 2004-06-29 #114856# Formular view + (bFormView && !pSNd->GetSection().IsEditInReadonlyFlag()) ) ) + // <-- + bRet = TRUE; + } + + // --> FME 2004-06-29 #114856# Formular view + if ( !bRet && bFormView ) + { + // Check if start and end frame are inside the _same_ + // edit-in-readonly-environment. Otherwise we better return 'true' + if ( pSttEIRFrm != pEndEIRFrm ) + bRet = TRUE; + } + // <-- + + // oder sollte eine geschuetzte Section innerhalb der + // Selektion liegen? + if( !bRet ) + { + ULONG nSttIdx = GetMark()->nNode.GetIndex(), + nEndIdx = GetPoint()->nNode.GetIndex(); + if( nEndIdx <= nSttIdx ) + { + ULONG nTmp = nSttIdx; + nSttIdx = nEndIdx; + nEndIdx = nTmp; + } + + // wenn ein geschuetzter Bereich zwischen den Nodes stehen soll, + // muss die Selektion selbst schon x Nodes umfassen. + // (TxtNd, SectNd, TxtNd, EndNd, TxtNd ) + if( nSttIdx + 3 < nEndIdx ) + { + const SwSectionFmts& rFmts = GetDoc()->GetSections(); + for( USHORT n = rFmts.Count(); n; ) + { + const SwSectionFmt* pFmt = rFmts[ --n ]; + if( pFmt->GetProtect().IsCntntProtected() ) + { + const SwFmtCntnt& rCntnt = pFmt->GetCntnt(FALSE); + ASSERT( rCntnt.GetCntntIdx(), "wo ist der SectionNode?" ); + ULONG nIdx = rCntnt.GetCntntIdx()->GetIndex(); + if( nSttIdx <= nIdx && nEndIdx >= nIdx && + rCntnt.GetCntntIdx()->GetNode().GetNodes().IsDocNodes() ) + { +/* // ist es keine gelinkte Section, dann kann sie auch + // nicht mitselektiert werden + const SwSection& rSect = *pFmt->GetSection(); + if( CONTENT_SECTION == rSect.GetType() ) + { + RestoreSavePos(); + return TRUE; + } +*/ + bRet = TRUE; + break; + } + } + } + +#ifdef CHECK_CELL_READONLY +//JP 22.01.99: bisher wurden Tabelle, die in der Text-Selektion standen +// nicht beachtet. Wollte man das haben, dann muss dieser +// Code freigeschaltet werden + + if( !bRet ) + { + // dann noch ueber alle Tabellen + const SwFrmFmts& rFmts = *GetDoc()->GetTblFrmFmts(); + for( n = rFmts.Count(); n ; ) + { + SwFrmFmt* pFmt = (SwFrmFmt*)rFmts[ --n ]; + const SwTable* pTbl = SwTable::FindTable( pFmt ); + ULONG nIdx = pTbl ? pTbl->GetTabSortBoxes()[0]->GetSttIdx() + : 0; + if( nSttIdx <= nIdx && nEndIdx >= nIdx ) + { + // dann teste mal alle Boxen + const SwTableSortBoxes& rBoxes = pTbl->GetTabSortBoxes(); + + for( USHORT i = rBoxes.Count(); i; ) + if( rBoxes[ --i ]->GetFrmFmt()->GetProtect(). + IsCntntProtected() ) + { + bRet = TRUE; + break; + } + + if( bRet ) + break; + } + } + } +#endif + } + } + } + //FIXME FieldBk + // TODO: Form Protection when Enhanced Fields are enabled + if (!bRet) { + const SwDoc *pDoc = GetDoc(); + sw::mark::IMark* pA = NULL; + sw::mark::IMark* pB = NULL; + if ( pDoc ) + { + const IDocumentMarkAccess* pMarksAccess = pDoc->getIDocumentMarkAccess( ); + pA = GetPoint() ? pMarksAccess->getFieldmarkFor( *GetPoint( ) ) : NULL; + pB = GetMark( ) ? pMarksAccess->getFieldmarkFor( *GetMark( ) ) : pA; + bRet = ( pA != pB ); + } + bool bProtectForm = pDoc->get( IDocumentSettingAccess::PROTECT_FORM ); + if ( bProtectForm ) + bRet |= ( pA == NULL || pB == NULL ); + } + return bRet; +} + +//-------------------- Suche nach Formaten( FormatNamen ) ----------------- + +// die Funktion gibt in Suchrichtung den folgenden Node zurueck. +// Ist in der Richtung keiner mehr vorhanden oder ist dieser ausserhalb +// des Bereiches, wird ein 0 Pointer returnt. +// Das rbFirst gibt an, ob es man zu erstenmal einen Node holt. Ist das der +// Fall, darf die Position vom Pam nicht veraendert werden! + + +SwCntntNode* GetNode( SwPaM & rPam, BOOL& rbFirst, SwMoveFn fnMove, + BOOL bInReadOnly ) +{ + SwCntntNode * pNd = 0; + SwCntntFrm* pFrm; + if( ((*rPam.GetPoint()).*fnMove->fnCmpOp)( *rPam.GetMark() ) || + ( *rPam.GetPoint() == *rPam.GetMark() && rbFirst ) ) + { + if( rbFirst ) + { + rbFirst = FALSE; + pNd = rPam.GetCntntNode(); + if( pNd ) + { + if( + ( + 0 == ( pFrm = pNd->GetFrm()) || + ( !bInReadOnly && pFrm->IsProtected() ) || + (pFrm->IsTxtFrm() && ((SwTxtFrm*)pFrm)->IsHiddenNow()) + ) || + ( !bInReadOnly && pNd->FindSectionNode() && + pNd->FindSectionNode()->GetSection().IsProtect() + ) + ) + { + pNd = 0; + } + } + } + + if( !pNd ) // steht Cursor auf keinem ContentNode ? + { + SwPosition aPos( *rPam.GetPoint() ); + BOOL bSrchForward = fnMove == fnMoveForward; + SwNodes& rNodes = aPos.nNode.GetNodes(); + + // zum naechsten / vorherigen ContentNode +// Funktioniert noch alles, wenn die Uerbpruefung vom ueberspringen der +// Sektions herausgenommen wird ?? +// if( (*fnMove->fnNds)( rNodes, &aPos.nNode ) ) + while( TRUE ) + { + pNd = bSrchForward + ? rNodes.GoNextSection( &aPos.nNode, TRUE, !bInReadOnly ) + : rNodes.GoPrevSection( &aPos.nNode, TRUE, !bInReadOnly ); + if( pNd ) + { + aPos.nContent.Assign( pNd, ::GetSttOrEnd( bSrchForward,*pNd )); + // liegt Position immer noch im Bereich ? + if( (aPos.*fnMove->fnCmpOp)( *rPam.GetMark() ) ) + { + // nur in der AutoTextSection koennen Node stehen, die + // nicht angezeigt werden !! + if( 0 == ( pFrm = pNd->GetFrm()) || + ( !bInReadOnly && pFrm->IsProtected() ) || + ( pFrm->IsTxtFrm() && + ((SwTxtFrm*)pFrm)->IsHiddenNow() ) ) + +// rNodes[ rNodes.EndOfAutotext ]->StartOfSection().GetIndex() +// < aPos.nNode.GetIndex() && aPos.nNode.GetIndex() +// < rNodes.EndOfAutotext.GetIndex() && +// 0 == ( pFrm = pNd->GetFrm()) && +// pFrm->IsProtected() ) + { + pNd = 0; + continue; // suche weiter + } + *(SwPosition*)rPam.GetPoint() = aPos; + } + else + pNd = 0; // kein gueltiger Node + break; + } + break; + } + } + } + return pNd; +} + +// ---------------------------------------------------------------------- + +// hier folgen die Move-Methoden ( Foward, Backward; Content, Node, Doc ) + + +void GoStartDoc( SwPosition * pPos ) +{ + SwNodes& rNodes = pPos->nNode.GetNodes(); + pPos->nNode = *rNodes.GetEndOfContent().StartOfSectionNode(); + // es muss immer ein ContentNode gefunden werden !! + SwCntntNode* pCNd = rNodes.GoNext( &pPos->nNode ); + if( pCNd ) + pCNd->MakeStartIndex( &pPos->nContent ); +} + + +void GoEndDoc( SwPosition * pPos ) +{ + SwNodes& rNodes = pPos->nNode.GetNodes(); + pPos->nNode = rNodes.GetEndOfContent(); + SwCntntNode* pCNd = GoPreviousNds( &pPos->nNode, TRUE ); + if( pCNd ) + pCNd->MakeEndIndex( &pPos->nContent ); +} + + +void GoStartSection( SwPosition * pPos ) +{ + // springe zum Anfang der Section + SwNodes& rNodes = pPos->nNode.GetNodes(); + USHORT nLevel = rNodes.GetSectionLevel( pPos->nNode ); + if( pPos->nNode < rNodes.GetEndOfContent().StartOfSectionIndex() ) + nLevel--; + do { rNodes.GoStartOfSection( &pPos->nNode ); } while( nLevel-- ); + + // steht jetzt schon auf einem CntntNode + pPos->nNode.GetNode().GetCntntNode()->MakeStartIndex( &pPos->nContent ); +} + +// gehe an das Ende der akt. Grund-Section + + +void GoEndSection( SwPosition * pPos ) +{ + // springe zum Anfang/Ende der Section + SwNodes& rNodes = pPos->nNode.GetNodes(); + USHORT nLevel = rNodes.GetSectionLevel( pPos->nNode ); + if( pPos->nNode < rNodes.GetEndOfContent().StartOfSectionIndex() ) + nLevel--; + do { rNodes.GoEndOfSection( &pPos->nNode ); } while( nLevel-- ); + + // steht jetzt auf einem EndNode, also zum vorherigen CntntNode + if( GoPreviousNds( &pPos->nNode, TRUE ) ) + pPos->nNode.GetNode().GetCntntNode()->MakeEndIndex( &pPos->nContent ); +} + + + +BOOL GoInDoc( SwPaM & rPam, SwMoveFn fnMove ) +{ + (*fnMove->fnDoc)( rPam.GetPoint() ); + return TRUE; +} + + +BOOL GoInSection( SwPaM & rPam, SwMoveFn fnMove ) +{ + (*fnMove->fnSections)( (SwPosition*)rPam.GetPoint() ); + return TRUE; +} + + +BOOL GoInNode( SwPaM & rPam, SwMoveFn fnMove ) +{ + SwCntntNode *pNd = (*fnMove->fnNds)( &rPam.GetPoint()->nNode, TRUE ); + if( pNd ) + rPam.GetPoint()->nContent.Assign( pNd, + ::GetSttOrEnd( fnMove == fnMoveForward, *pNd ) ); + return 0 != pNd; +} + + +BOOL GoInCntnt( SwPaM & rPam, SwMoveFn fnMove ) +{ + if( (*fnMove->fnNd)( &rPam.GetPoint()->nNode.GetNode(), + &rPam.GetPoint()->nContent, CRSR_SKIP_CHARS )) + return TRUE; + return GoInNode( rPam, fnMove ); +} + +BOOL GoInCntntCells( SwPaM & rPam, SwMoveFn fnMove ) +{ + if( (*fnMove->fnNd)( &rPam.GetPoint()->nNode.GetNode(), + &rPam.GetPoint()->nContent, CRSR_SKIP_CELLS )) + return TRUE; + return GoInNode( rPam, fnMove ); +} + +BOOL GoInCntntSkipHidden( SwPaM & rPam, SwMoveFn fnMove ) +{ + if( (*fnMove->fnNd)( &rPam.GetPoint()->nNode.GetNode(), + &rPam.GetPoint()->nContent, CRSR_SKIP_CHARS | CRSR_SKIP_HIDDEN ) ) + return TRUE; + return GoInNode( rPam, fnMove ); +} + +BOOL GoInCntntCellsSkipHidden( SwPaM & rPam, SwMoveFn fnMove ) +{ + if( (*fnMove->fnNd)( &rPam.GetPoint()->nNode.GetNode(), + &rPam.GetPoint()->nContent, CRSR_SKIP_CELLS | CRSR_SKIP_HIDDEN ) ) + return TRUE; + return GoInNode( rPam, fnMove ); +} + + + +// --------- Funktionsdefinitionen fuer die SwCrsrShell -------------- + + +BOOL GoPrevPara( SwPaM & rPam, SwPosPara aPosPara ) +{ + if( rPam.Move( fnMoveBackward, fnGoNode ) ) + { + // steht immer auf einem ContentNode ! + SwPosition& rPos = *rPam.GetPoint(); + SwCntntNode * pNd = rPos.nNode.GetNode().GetCntntNode(); + rPos.nContent.Assign( pNd, + ::GetSttOrEnd( aPosPara == fnMoveForward, *pNd ) ); + return TRUE; + } + return FALSE; +} + + +BOOL GoCurrPara( SwPaM & rPam, SwPosPara aPosPara ) +{ + SwPosition& rPos = *rPam.GetPoint(); + SwCntntNode * pNd = rPos.nNode.GetNode().GetCntntNode(); + if( pNd ) + { + xub_StrLen nOld = rPos.nContent.GetIndex(), + nNew = aPosPara == fnMoveForward ? 0 : pNd->Len(); + // stand er schon auf dem Anfang/Ende dann zum naechsten/vorherigen + if( nOld != nNew ) + { + rPos.nContent.Assign( pNd, nNew ); + return TRUE; + } + } + // den Node noch etwas bewegen ( auf den naechsten/vorh. CntntNode) + if( ( aPosPara==fnParaStart && 0 != ( pNd = + GoPreviousNds( &rPos.nNode, TRUE ))) || + ( aPosPara==fnParaEnd && 0 != ( pNd = + GoNextNds( &rPos.nNode, TRUE ))) ) + { + rPos.nContent.Assign( pNd, + ::GetSttOrEnd( aPosPara == fnMoveForward, *pNd )); + return TRUE; + } + return FALSE; +} + + +BOOL GoNextPara( SwPaM & rPam, SwPosPara aPosPara ) +{ + if( rPam.Move( fnMoveForward, fnGoNode ) ) + { + // steht immer auf einem ContentNode ! + SwPosition& rPos = *rPam.GetPoint(); + SwCntntNode * pNd = rPos.nNode.GetNode().GetCntntNode(); + rPos.nContent.Assign( pNd, + ::GetSttOrEnd( aPosPara == fnMoveForward, *pNd ) ); + return TRUE; + } + return FALSE; +} + + + +BOOL GoCurrSection( SwPaM & rPam, SwMoveFn fnMove ) +{ + SwPosition& rPos = *rPam.GetPoint(); + SwPosition aSavePos( rPos ); // eine Vergleichsposition + SwNodes& rNds = aSavePos.nNode.GetNodes(); + (rNds.*fnMove->fnSection)( &rPos.nNode ); + SwCntntNode *pNd; + if( 0 == ( pNd = rPos.nNode.GetNode().GetCntntNode()) && + 0 == ( pNd = (*fnMove->fnNds)( &rPos.nNode, TRUE )) ) + { + rPos = aSavePos; // Cusror nicht veraendern + return FALSE; + } + + rPos.nContent.Assign( pNd, + ::GetSttOrEnd( fnMove == fnMoveForward, *pNd ) ); + return aSavePos != rPos; +} + + +BOOL GoNextSection( SwPaM & rPam, SwMoveFn fnMove ) +{ + SwPosition& rPos = *rPam.GetPoint(); + SwPosition aSavePos( rPos ); // eine Vergleichsposition + SwNodes& rNds = aSavePos.nNode.GetNodes(); + rNds.GoEndOfSection( &rPos.nNode ); + + // kein weiterer ContentNode vorhanden ? + if( !GoInCntnt( rPam, fnMoveForward ) ) + { + rPos = aSavePos; // Cusror nicht veraendern + return FALSE; + } + (rNds.*fnMove->fnSection)( &rPos.nNode ); + SwCntntNode *pNd = rPos.nNode.GetNode().GetCntntNode(); + rPos.nContent.Assign( pNd, + ::GetSttOrEnd( fnMove == fnMoveForward, *pNd ) ); + return TRUE; +} + + +BOOL GoPrevSection( SwPaM & rPam, SwMoveFn fnMove ) +{ + SwPosition& rPos = *rPam.GetPoint(); + SwPosition aSavePos( rPos ); // eine Vergleichsposition + SwNodes& rNds = aSavePos.nNode.GetNodes(); + rNds.GoStartOfSection( &rPos.nNode ); + + // kein weiterer ContentNode vorhanden ? + if( !GoInCntnt( rPam, fnMoveBackward )) + { + rPos = aSavePos; // Cusror nicht veraendern + return FALSE; + } + (rNds.*fnMove->fnSection)( &rPos.nNode ); + SwCntntNode *pNd = rPos.nNode.GetNode().GetCntntNode(); + rPos.nContent.Assign( pNd, + ::GetSttOrEnd( fnMove == fnMoveForward, *pNd )); + return TRUE; +} + +// #111827# +String SwPaM::GetTxt() const +{ + String aResult; + + SwNodeIndex aNodeIndex = Start()->nNode; + + /* The first node can be the end node. A first end node must be + handled, too. There fore do ... while and no incrementing of + aNodeIndex in the first pass. + */ + bool bFirst = true; + do + { + if (! bFirst) + { + aNodeIndex++; + } + + bFirst = false; + + SwTxtNode * pTxtNode = aNodeIndex.GetNode().GetTxtNode(); + + if (pTxtNode != NULL) + { + const String & aTmpStr = pTxtNode->GetTxt(); + + if (aNodeIndex == Start()->nNode) + { + xub_StrLen nEnd; + if (End()->nNode == aNodeIndex) + nEnd = End()->nContent.GetIndex(); + else + nEnd = aTmpStr.Len(); + + aResult += aTmpStr.Copy(Start()->nContent.GetIndex(), + nEnd - Start()->nContent.GetIndex()) ; + } + else if (aNodeIndex == End()->nNode) + aResult += aTmpStr.Copy(0, End()->nContent.GetIndex()); + else + aResult += aTmpStr; + } + } + while (aNodeIndex != End()->nNode); + + return aResult; +} + +BOOL SwPaM::Overlap(const SwPaM & a, const SwPaM & b) +{ + return !(*b.End() <= *a.Start() || *a.End() <= *b.End()); +} + +void SwPaM::InvalidatePaM() +{ + const SwNode *_pNd=this->GetNode(); + const SwTxtNode *_pTxtNd=(_pNd!=NULL?_pNd->GetTxtNode():NULL); + if (_pTxtNd!=NULL) + { + // pretent that the PaM marks inserted text to recalc the portion... + SwInsTxt aHint( Start()->nContent.GetIndex(), + End()->nContent.GetIndex() - Start()->nContent.GetIndex() + 1 ); + SwModify *_pModify=(SwModify*)_pTxtNd; + _pModify->Modify( 0, &aHint); + } +} + +BOOL SwPaM::LessThan(const SwPaM & a, const SwPaM & b) +{ + return (*a.Start() < *b.Start()) || (*a.Start() == *b.Start() && *a.End() < *b.End()); +} diff --git a/sw/source/core/crsr/paminit.cxx b/sw/source/core/crsr/paminit.cxx new file mode 100644 index 000000000000..56f497215f91 --- /dev/null +++ b/sw/source/core/crsr/paminit.cxx @@ -0,0 +1,131 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <pamtyp.hxx> + + +static SwMoveFnCollection aFwrd = { + /* fnNd */ &GoNext, + /* fnNds */ &GoNextNds, + /* fnDoc */ &GoEndDoc, + /* fnSections */ &GoEndSection, + /* fnCmpOp */ &SwPosition::operator<, + /* fnGetHint */ &GetFrwrdTxtHint, + /* fnSearch */ &utl::TextSearch::SearchFrwrd, + /* fnSection */ &SwNodes::GoStartOfSection +}; + +static SwMoveFnCollection aBwrd = { + /* fnNd */ &GoPrevious, + /* fnNds */ &GoPreviousNds, + /* fnDoc */ &GoStartDoc, + /* fnSections */ &GoStartSection, + /* fnCmpOp */ &SwPosition::operator>, + /* fnGetHint */ &GetBkwrdTxtHint, + /* fnSearch */ &utl::TextSearch::SearchBkwrd, + /* fnSection */ &SwNodes::GoEndOfSection +}; + +SwGoInDoc fnGoDoc = &GoInDoc; +SwGoInDoc fnGoSection = &GoInSection; +SwGoInDoc fnGoNode = &GoInNode; +SwGoInDoc fnGoCntnt = &GoInCntnt; +SwGoInDoc fnGoCntntCells = &GoInCntntCells; +SwGoInDoc fnGoCntntSkipHidden = &GoInCntntSkipHidden; +SwGoInDoc fnGoCntntCellsSkipHidden = &GoInCntntCellsSkipHidden; + +SwWhichPara fnParaPrev = &GoPrevPara; +SwWhichPara fnParaCurr = &GoCurrPara; +SwWhichPara fnParaNext = &GoNextPara; +SwPosPara fnParaStart = &aFwrd; +SwPosPara fnParaEnd = &aBwrd; + +SwWhichSection fnSectionPrev = &GoPrevSection; +SwWhichSection fnSectionCurr = &GoCurrSection; +SwWhichSection fnSectionNext = &GoNextSection; +SwPosSection fnSectionStart = &aFwrd; +SwPosSection fnSectionEnd = &aBwrd; + +// Travelling in Tabellen +BOOL GotoPrevTable( SwPaM&, SwPosTable, BOOL bInReadOnly ); +BOOL GotoCurrTable( SwPaM&, SwPosTable, BOOL bInReadOnly ); +BOOL GotoNextTable( SwPaM&, SwPosTable, BOOL bInReadOnly ); + +SwWhichTable fnTablePrev = &GotoPrevTable; +SwWhichTable fnTableCurr = &GotoCurrTable; +SwWhichTable fnTableNext = &GotoNextTable; +SwPosTable fnTableStart = &aFwrd; +SwPosTable fnTableEnd = &aBwrd; + +// Travelling in Bereichen +BOOL GotoPrevRegion( SwPaM&, SwPosRegion, BOOL bInReadOnly ); +BOOL GotoCurrRegion( SwPaM&, SwPosRegion, BOOL bInReadOnly ); +BOOL GotoCurrRegionAndSkip( SwPaM&, SwPosRegion, BOOL bInReadOnly ); +BOOL GotoNextRegion( SwPaM&, SwPosRegion, BOOL bInReadOnly ); + +SwWhichRegion fnRegionPrev = &GotoPrevRegion; +SwWhichRegion fnRegionCurr = &GotoCurrRegion; +SwWhichRegion fnRegionCurrAndSkip = &GotoCurrRegionAndSkip; +SwWhichRegion fnRegionNext = &GotoNextRegion; +SwPosRegion fnRegionStart = &aFwrd; +SwPosRegion fnRegionEnd = &aBwrd; + +SwMoveFn fnMoveBackward = &aBwrd; +SwMoveFn fnMoveForward = &aFwrd; + +SwWhichPara GetfnParaCurr() +{ + return fnParaCurr; +} +SwPosPara GetfnParaStart() +{ + return fnParaStart; +} +SwWhichTable GetfnTablePrev() +{ + return fnTablePrev; +} +SwPosPara GetfnParaEnd() +{ + return fnParaEnd; +} +SwPosTable GetfnTableStart() +{ + return fnTableStart; +} +SwWhichTable GetfnTableCurr() +{ + return fnTableCurr; +} +SwPosTable GetfnTableEnd() +{ + return fnTableEnd; +} diff --git a/sw/source/core/crsr/swcrsr.cxx b/sw/source/core/crsr/swcrsr.cxx new file mode 100644 index 000000000000..7637df0a67b4 --- /dev/null +++ b/sw/source/core/crsr/swcrsr.cxx @@ -0,0 +1,2360 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <hintids.hxx> +#include <editeng/protitem.hxx> + +#include <com/sun/star/i18n/WordType.hdl> +#include <com/sun/star/i18n/CharType.hdl> + +#include <unotools/charclass.hxx> +#include <svl/ctloptions.hxx> +#include <swmodule.hxx> +#include <fmtcntnt.hxx> +#include <swtblfmt.hxx> +#include <swcrsr.hxx> +#include <unocrsr.hxx> +#include <doc.hxx> +#include <docary.hxx> +#include <ndtxt.hxx> +#include <section.hxx> +#include <swtable.hxx> +#include <cntfrm.hxx> +#include <rootfrm.hxx> +#include <txtfrm.hxx> +#include <scriptinfo.hxx> +#include <crstate.hxx> +#include <docsh.hxx> +#include <frmatr.hxx> +#include <breakit.hxx> +#include <crsskip.hxx> +#include <vcl/msgbox.hxx> +#include <mdiexp.hxx> // ...Percent() +#ifndef _STATSTR_HRC +#include <statstr.hrc> // ResId fuer Statusleiste +#endif +#include <redline.hxx> // SwRedline + + +using namespace ::com::sun::star::i18n; + + +static const USHORT coSrchRplcThreshold = 60000; + +struct _PercentHdl +{ + SwDocShell* pDSh; + ULONG nActPos; + BOOL bBack, bNodeIdx; + + _PercentHdl( ULONG nStt, ULONG nEnd, SwDocShell* pSh ) + : pDSh( pSh ) + { + nActPos = nStt; + if( 0 != ( bBack = (nStt > nEnd )) ) + { + ULONG n = nStt; nStt = nEnd; nEnd = n; + } + ::StartProgress( STR_STATSTR_SEARCH, nStt, nEnd, 0 ); + } + + _PercentHdl( const SwPaM& rPam ) + : pDSh( (SwDocShell*)rPam.GetDoc()->GetDocShell() ) + { + ULONG nStt, nEnd; + if( rPam.GetPoint()->nNode == rPam.GetMark()->nNode ) + { + bNodeIdx = FALSE; + nStt = rPam.GetMark()->nContent.GetIndex(); + nEnd = rPam.GetPoint()->nContent.GetIndex(); + } + else + { + bNodeIdx = TRUE; + nStt = rPam.GetMark()->nNode.GetIndex(); + nEnd = rPam.GetPoint()->nNode.GetIndex(); + } + nActPos = nStt; + if( 0 != ( bBack = (nStt > nEnd )) ) + { + ULONG n = nStt; nStt = nEnd; nEnd = n; + } + ::StartProgress( STR_STATSTR_SEARCH, nStt, nEnd, pDSh ); + } + + ~_PercentHdl() { ::EndProgress( pDSh ); } + + void NextPos( ULONG nPos ) const + { ::SetProgressState( bBack ? nActPos - nPos : nPos, pDSh ); } + + void NextPos( SwPosition& rPos ) const + { + ULONG nPos; + if( bNodeIdx ) + nPos = rPos.nNode.GetIndex(); + else + nPos = rPos.nContent.GetIndex(); + ::SetProgressState( bBack ? nActPos - nPos : nPos, pDSh ); + } +}; + +SwCursor::SwCursor( const SwPosition &rPos, SwPaM* pRing, bool bColumnSel ) + : SwPaM( rPos, pRing ), pSavePos( 0 ), mnRowSpanOffset( 0 ), nCursorBidiLevel( 0 ), + mbColumnSelection( bColumnSel ) +{ +} + +// @@@ semantic: no copy ctor. +SwCursor::SwCursor( SwCursor& rCpy ) + : SwPaM( rCpy ), pSavePos( 0 ), mnRowSpanOffset( rCpy.mnRowSpanOffset ), + nCursorBidiLevel( rCpy.nCursorBidiLevel ), mbColumnSelection( rCpy.mbColumnSelection ) +{ +} + +SwCursor::~SwCursor() +{ + while( pSavePos ) + { + _SwCursor_SavePos* pNxt = pSavePos->pNext; + delete pSavePos; + pSavePos = pNxt; + } +} + +SwCursor* SwCursor::Create( SwPaM* pRing ) const +{ + return new SwCursor( *GetPoint(), pRing, false ); +} + +bool SwCursor::IsReadOnlyAvailable() const +{ + return false; +} + +BOOL SwCursor::IsSkipOverHiddenSections() const +{ + return TRUE; +} + +BOOL SwCursor::IsSkipOverProtectSections() const +{ + return !IsReadOnlyAvailable(); +} + + +// Sicher die aktuelle Position, damit ggfs. auf diese zurueck +// gefallen werden kann. Die SavePos Objekte werden als Stack verwaltet, +// damit das auch alles bei verschachtelten Aufrufen funktioniert. +// Das CreateNewSavePos ist virtual, damit abgeleitete Klassen vom Cursor +// gegebenenfalls eigene SaveObjecte anlegen und in den virtuellen +// Check-Routinen verwenden koennen. + +void SwCursor::SaveState() +{ + _SwCursor_SavePos* pNew = CreateNewSavePos(); + pNew->pNext = pSavePos; + pSavePos = pNew; +} + +void SwCursor::RestoreState() +{ + if( pSavePos ) // Robust + { + _SwCursor_SavePos* pDel = pSavePos; + pSavePos = pSavePos->pNext; + delete pDel; + } +} + +_SwCursor_SavePos* SwCursor::CreateNewSavePos() const +{ + return new _SwCursor_SavePos( *this ); +} + +// stelle fest, ob sich der Point ausserhalb des Content-Bereichs +// vom Nodes-Array befindet +BOOL SwCursor::IsNoCntnt() const +{ + return GetPoint()->nNode.GetIndex() < + GetDoc()->GetNodes().GetEndOfExtras().GetIndex(); +} + +bool SwCursor::IsSelOvrCheck(int) +{ + return false; +} + +// extracted from IsSelOvr() +bool SwTableCursor::IsSelOvrCheck(int eFlags) +{ + SwNodes& rNds = GetDoc()->GetNodes(); + // check sections of nodes array + if( (nsSwCursorSelOverFlags::SELOVER_CHECKNODESSECTION & eFlags) + && HasMark() ) + { + SwNodeIndex aOldPos( rNds, GetSavePos()->nNode ); + if( !CheckNodesRange( aOldPos, GetPoint()->nNode, TRUE )) + { + GetPoint()->nNode = aOldPos; + GetPoint()->nContent.Assign( GetCntntNode(), GetSavePos()->nCntnt ); + return true; + } + } + return SwCursor::IsSelOvrCheck(eFlags); +} + +BOOL SwCursor::IsSelOvr( int eFlags ) +{ + SwDoc* pDoc = GetDoc(); + SwNodes& rNds = pDoc->GetNodes(); + + BOOL bSkipOverHiddenSections = IsSkipOverHiddenSections(); + BOOL bSkipOverProtectSections = IsSkipOverProtectSections(); + + if ( IsSelOvrCheck( eFlags ) ) + { + return TRUE; + } + +// neu: Bereiche ueberpruefen +// Anfang + if( pSavePos->nNode != GetPoint()->nNode.GetIndex() && + //JP 28.10.97: Bug 45129 - im UI-ReadOnly ist alles erlaubt + ( !pDoc->GetDocShell() || !pDoc->GetDocShell()->IsReadOnlyUI() )) + { + // teste doch mal die neuen Sections: + SwNodeIndex& rPtIdx = GetPoint()->nNode; + const SwSectionNode* pSectNd = rPtIdx.GetNode().FindSectionNode(); + if( pSectNd && + ((bSkipOverHiddenSections && pSectNd->GetSection().IsHiddenFlag() ) || + (bSkipOverProtectSections && pSectNd->GetSection().IsProtectFlag() ))) + { + if( 0 == ( nsSwCursorSelOverFlags::SELOVER_CHANGEPOS & eFlags ) ) + { + // dann wars das schon + RestoreSavePos(); + return TRUE; + } + + // dann setze den Cursor auf die neue Position: + SwNodeIndex aIdx( rPtIdx ); + xub_StrLen nCntntPos = pSavePos->nCntnt; + int bGoNxt = pSavePos->nNode < rPtIdx.GetIndex(); + SwCntntNode* pCNd = bGoNxt + ? rNds.GoNextSection( &rPtIdx, bSkipOverHiddenSections, bSkipOverProtectSections) + : rNds.GoPrevSection( &rPtIdx, bSkipOverHiddenSections, bSkipOverProtectSections); + if( !pCNd && ( nsSwCursorSelOverFlags::SELOVER_ENABLEREVDIREKTION & eFlags )) + { + bGoNxt = !bGoNxt; + pCNd = bGoNxt ? rNds.GoNextSection( &rPtIdx, bSkipOverHiddenSections, bSkipOverProtectSections) + : rNds.GoPrevSection( &rPtIdx, bSkipOverHiddenSections, bSkipOverProtectSections); + } + + int bIsValidPos = 0 != pCNd; + BOOL bValidNodesRange = bIsValidPos && + ::CheckNodesRange( rPtIdx, aIdx, TRUE ); + if( !bValidNodesRange ) + { + rPtIdx = pSavePos->nNode; + if( 0 == ( pCNd = rPtIdx.GetNode().GetCntntNode() ) ) + { + bIsValidPos = FALSE; + nCntntPos = 0; + rPtIdx = aIdx; + if( 0 == ( pCNd = rPtIdx.GetNode().GetCntntNode() ) ) + { + // dann auf den Anfang vom Doc + rPtIdx = rNds.GetEndOfExtras(); + pCNd = rNds.GoNext( &rPtIdx ); + } + } + } + + // ContentIndex noch anmelden: + xub_StrLen nTmpPos = bIsValidPos ? (bGoNxt ? 0 : pCNd->Len()) : nCntntPos; + GetPoint()->nContent.Assign( pCNd, nTmpPos ); + if( !bIsValidPos || !bValidNodesRange || + // sollten wir in einer Tabelle gelandet sein? + IsInProtectTable( TRUE ) ) + return TRUE; + } + + // oder sollte eine geschuetzte Section innerhalb der Selektion liegen? + if( HasMark() && bSkipOverProtectSections) + { + ULONG nSttIdx = GetMark()->nNode.GetIndex(), + nEndIdx = GetPoint()->nNode.GetIndex(); + if( nEndIdx <= nSttIdx ) + { + ULONG nTmp = nSttIdx; + nSttIdx = nEndIdx; + nEndIdx = nTmp; + } + + const SwSectionFmts& rFmts = pDoc->GetSections(); + for( USHORT n = 0; n < rFmts.Count(); ++n ) + { + const SwSectionFmt* pFmt = rFmts[n]; + const SvxProtectItem& rProtect = pFmt->GetProtect(); + if( rProtect.IsCntntProtected() ) + { + const SwFmtCntnt& rCntnt = pFmt->GetCntnt(FALSE); + ASSERT( rCntnt.GetCntntIdx(), "wo ist der SectionNode?" ); + ULONG nIdx = rCntnt.GetCntntIdx()->GetIndex(); + if( nSttIdx <= nIdx && nEndIdx >= nIdx ) + { + // ist es keine gelinkte Section, dann kann sie auch + // nicht mitselektiert werden + const SwSection& rSect = *pFmt->GetSection(); + if( CONTENT_SECTION == rSect.GetType() ) + { + RestoreSavePos(); + return TRUE; + } + } + } + } + } + + } +// Ende +// neu: Bereiche ueberpruefen + + const SwNode* pNd = &GetPoint()->nNode.GetNode(); + if( pNd->IsCntntNode() && !dynamic_cast<SwUnoCrsr*>(this) ) + { + const SwCntntFrm* pFrm = ((SwCntntNode*)pNd)->GetFrm(); + if( pFrm && pFrm->IsValid() && 0 == pFrm->Frm().Height() && + 0 != ( nsSwCursorSelOverFlags::SELOVER_CHANGEPOS & eFlags ) ) + { + // skip to the next / prev valid paragraph with a layout + SwNodeIndex& rPtIdx = GetPoint()->nNode; + int bGoNxt = pSavePos->nNode < rPtIdx.GetIndex(); + while( 0 != ( pFrm = ( bGoNxt ? pFrm->GetNextCntntFrm() + : pFrm->GetPrevCntntFrm() )) && + 0 == pFrm->Frm().Height() ) + ; + + // --> LIJIAN/FME 2007-11-27 #i72394# skip to prev /next valid paragraph + // with a layout in case the first search did not succeed: + if( !pFrm ) + { + bGoNxt = !bGoNxt; + pFrm = ((SwCntntNode*)pNd)->GetFrm(); + while ( pFrm && 0 == pFrm->Frm().Height() ) + { + pFrm = bGoNxt ? pFrm->GetNextCntntFrm() + : pFrm->GetPrevCntntFrm(); + } + } + // <-- + + SwCntntNode* pCNd; + if( pFrm && 0 != (pCNd = (SwCntntNode*)pFrm->GetNode()) ) + { + // set this cntntNode as new position + rPtIdx = *pCNd; + pNd = pCNd; + + // ContentIndex noch anmelden: + xub_StrLen nTmpPos = bGoNxt ? 0 : pCNd->Len(); + GetPoint()->nContent.Assign( pCNd, nTmpPos ); + + // sollten wir in einer Tabelle gelandet sein? + if( IsInProtectTable( TRUE ) ) + pFrm = 0; + } + } + + if( !pFrm ) + { + DeleteMark(); + RestoreSavePos(); + return TRUE; // ohne Frames geht gar nichts! + } + } + + // darf der Cursor in geschuetzen "Nodes" stehen? + if( 0 == ( nsSwCursorSelOverFlags::SELOVER_CHANGEPOS & eFlags ) && !IsAtValidPos() ) + { + DeleteMark(); + RestoreSavePos(); + return TRUE; + } + + if( !HasMark() ) + return FALSE; + + //JP 19.08.98: teste mal auf ungueltige Selektion - sprich ueber + // GrundSections: + if( !::CheckNodesRange( GetMark()->nNode, GetPoint()->nNode, TRUE )) + { + DeleteMark(); + RestoreSavePos(); + return TRUE; // ohne Frames geht gar nichts! + } + + const SwTableNode* pPtNd = pNd->FindTableNode(); + + if( (pNd = &GetMark()->nNode.GetNode())->IsCntntNode() && + !((SwCntntNode*)pNd)->GetFrm() && !dynamic_cast<SwUnoCrsr*>(this) ) + { + DeleteMark(); + RestoreSavePos(); + return TRUE; // ohne Frames geht gar nichts! + } + + const SwTableNode* pMrkNd = pNd->FindTableNode(); + + // beide in keinem oder beide im gleichen TableNode + if( ( !pMrkNd && !pPtNd ) || pPtNd == pMrkNd ) + return FALSE; + + // in unterschiedlichen Tabellen oder nur Mark in der Tabelle + if( ( pPtNd && pMrkNd ) || pMrkNd ) + { // dann lasse das nicht zu, alte Pos zurueck + RestoreSavePos(); + // Crsr bleibt an der alten Position + return TRUE; + } + + // ACHTUNG: dieses kann nicht im TableMode geschehen !! + if( pPtNd ) // nur Point in Tabelle, dann gehe hinter/vor diese + { + if( nsSwCursorSelOverFlags::SELOVER_CHANGEPOS & eFlags ) + { + BOOL bSelTop = GetPoint()->nNode.GetIndex() < + (( nsSwCursorSelOverFlags::SELOVER_TOGGLE & eFlags ) ? pSavePos->nNode + : GetMark()->nNode.GetIndex()); + + do { + // in Schleife fuer Tabelle hinter Tabelle + ULONG nSEIdx = pPtNd->EndOfSectionIndex(); + ULONG nSttEndTbl = nSEIdx + 1; // dflt. Sel. nach unten + + if( bSelTop ) // Sel. nach oben + nSttEndTbl = rNds[ nSEIdx ]->StartOfSectionIndex() - 1; + + GetPoint()->nNode = nSttEndTbl; + const SwNode* pMyNd = GetNode(); + + if( pMyNd->IsSectionNode() || ( pMyNd->IsEndNode() && + pMyNd->StartOfSectionNode()->IsSectionNode() ) ) + { + // die lassen wir zu: + pMyNd = bSelTop + ? rNds.GoPrevSection( &GetPoint()->nNode,TRUE,FALSE ) + : rNds.GoNextSection( &GetPoint()->nNode,TRUE,FALSE ); + + /* #i12312# Handle failure of Go{Prev|Next}Section */ + if ( 0 == pMyNd) + break; + + if( 0 != ( pPtNd = pMyNd->FindTableNode() )) + continue; + } + + if( pMyNd->IsCntntNode() && // ist es ein ContentNode ?? + ::CheckNodesRange( GetMark()->nNode, + GetPoint()->nNode, TRUE )) + { + // TABLE IN TABLE + const SwTableNode* pOuterTableNd = pMyNd->FindTableNode(); + if ( pOuterTableNd ) + pMyNd = pOuterTableNd; + else + { + SwCntntNode* pCNd = (SwCntntNode*)pMyNd; + xub_StrLen nTmpPos = bSelTop ? pCNd->Len() : 0; + GetPoint()->nContent.Assign( pCNd, nTmpPos ); + return FALSE; + } + } + if( bSelTop + ? ( !pMyNd->IsEndNode() || 0 == ( pPtNd = pMyNd->FindTableNode() )) + : 0 == ( pPtNd = pMyNd->GetTableNode() )) + break; + } while( TRUE ); + } + + // dann verbleibe auf der alten Position + RestoreSavePos(); + return TRUE; // Crsr bleibt an der alten Position + } + return FALSE; // was bleibt noch ?? +} + +#if defined( UNX ) +#define IDX (*pCellStt) +#else +#define IDX aCellStt +#endif + + +BOOL SwCursor::IsInProtectTable( BOOL bMove, BOOL bChgCrsr ) +{ + SwCntntNode* pCNd = GetCntntNode(); + if( !pCNd ) + return FALSE; + + // No table, no protected cell: + const SwTableNode* pTableNode = pCNd->FindTableNode(); + if ( !pTableNode ) + return FALSE; + + // Current position == last save position? + if ( pSavePos->nNode == GetPoint()->nNode.GetIndex() ) + return FALSE; + + // Check for convered cell: + bool bInCoveredCell = false; + const SwStartNode* pTmpSttNode = pCNd->FindTableBoxStartNode(); + ASSERT( pTmpSttNode, "In table, therefore I expect to get a SwTableBoxStartNode" ) + const SwTableBox* pBox = pTmpSttNode ? pTableNode->GetTable().GetTblBox( pTmpSttNode->GetIndex() ) : 0; //Robust #151355 + if ( pBox && pBox->getRowSpan() < 1 ) // Robust #151270 + bInCoveredCell = true; + + // Positions of covered cells are not acceptable: + if ( !bInCoveredCell ) + { + // Position not protected? + if ( !pCNd->IsProtect() ) + return FALSE; + + // Cursor in protected cells allowed? + if ( IsReadOnlyAvailable() ) + return FALSE; + } + + // If we reach this point, we are in a protected or covered table cell! + + if( !bMove ) + { + if( bChgCrsr ) + // restore the last save position + RestoreSavePos(); + return TRUE; // Crsr bleibt an der alten Position + } + + // wir stehen in einer geschuetzten TabellenZelle + // von Oben nach Unten Traveln ? + if( pSavePos->nNode < GetPoint()->nNode.GetIndex() ) + { + // suche die naechste "gueltige" Box + + // folgt nach dem EndNode der Zelle ein weiterer StartNode, dann + // gibt es auch eine naechste Zelle +#if defined( UNX ) + SwNodeIndex* pCellStt = new SwNodeIndex( *GetNode()-> + FindTableBoxStartNode()->EndOfSectionNode(), 1 ); +#else + SwNodeIndex aCellStt( *GetNode()->FindTableBoxStartNode()->EndOfSectionNode(), 1 ); +#endif + BOOL bProt = TRUE; +GoNextCell: + do { + if( !IDX.GetNode().IsStartNode() ) + break; + IDX++; + if( 0 == ( pCNd = IDX.GetNode().GetCntntNode() )) + pCNd = IDX.GetNodes().GoNext( &IDX ); + if( 0 == ( bProt = pCNd->IsProtect() )) + break; + IDX.Assign( *pCNd->FindTableBoxStartNode()->EndOfSectionNode(), 1 ); + } while( bProt ); + +SetNextCrsr: + if( !bProt ) // eine freie Zelle gefunden + { + GetPoint()->nNode = IDX; +#if defined( UNX ) + delete pCellStt; +#endif + SwCntntNode* pTmpCNd = GetCntntNode(); + if( pTmpCNd ) + { + GetPoint()->nContent.Assign( pTmpCNd, 0 ); + return FALSE; + } + return IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE | + nsSwCursorSelOverFlags::SELOVER_CHANGEPOS ); + } + // am Ende der Tabelle, also setze hinter diese + IDX++; // auf den naechsten Node + SwNode* pNd; + if( ( pNd = &IDX.GetNode())->IsEndNode() || HasMark()) + { + // Tabelle allein in einem FlyFrame oder SSelection, + // dann verbleibe auf der alten Position + if( bChgCrsr ) + RestoreSavePos(); +#if defined( UNX ) + delete pCellStt; +#endif + return TRUE; // Crsr bleibt an der alten Position + } + else if( pNd->IsTableNode() && IDX++ ) + goto GoNextCell; + + bProt = FALSE; // Index steht jetzt auf einem ContentNode + goto SetNextCrsr; + } + + // suche die vorherige "gueltige" Box + { + // liegt vor dem StartNode der Zelle ein weiterer EndNode, dann + // gibt es auch eine vorherige Zelle +#if defined( UNX ) + SwNodeIndex* pCellStt = new SwNodeIndex( + *GetNode()->FindTableBoxStartNode(), -1 ); +#else + SwNodeIndex aCellStt( *GetNode()->FindTableBoxStartNode(), -1 ); +#endif + SwNode* pNd; + BOOL bProt = TRUE; +GoPrevCell: + do { + if( !( pNd = &IDX.GetNode())->IsEndNode() ) + break; + IDX.Assign( *pNd->StartOfSectionNode(), +1 ); + if( 0 == ( pCNd = IDX.GetNode().GetCntntNode() )) + pCNd = pNd->GetNodes().GoNext( &IDX ); + if( 0 == ( bProt = pCNd->IsProtect() )) + break; + IDX.Assign( *pNd->FindTableBoxStartNode(), -1 ); + } while( bProt ); + +SetPrevCrsr: + if( !bProt ) // eine freie Zelle gefunden + { + GetPoint()->nNode = IDX; +#if defined( UNX ) + delete pCellStt; +#endif + SwCntntNode* pTmpCNd = GetCntntNode(); + if( pTmpCNd ) + { + GetPoint()->nContent.Assign( pTmpCNd, 0 ); + return FALSE; + } + return IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE | + nsSwCursorSelOverFlags::SELOVER_CHANGEPOS ); + } + // am Start der Tabelle, also setze vor diese + IDX--; // auf den naechsten Node + if( ( pNd = &IDX.GetNode())->IsStartNode() || HasMark() ) + { + // Tabelle allein in einem FlyFrame oder Selektion, + // dann verbleibe auf der alten Position + if( bChgCrsr ) + RestoreSavePos(); +#if defined( UNX ) + delete pCellStt; +#endif + return TRUE; // Crsr bleibt an der alten Position + } + else if( pNd->StartOfSectionNode()->IsTableNode() && IDX-- ) + goto GoPrevCell; + + bProt = FALSE; // Index steht jetzt auf einem ContentNode + goto SetPrevCrsr; + } +} + +// TRUE: an die Position kann der Cursor gesetzt werden +BOOL SwCursor::IsAtValidPos( BOOL bPoint ) const +{ + const SwDoc* pDoc = GetDoc(); + const SwPosition* pPos = bPoint ? GetPoint() : GetMark(); + const SwNode* pNd = &pPos->nNode.GetNode(); + + if( pNd->IsCntntNode() && !((SwCntntNode*)pNd)->GetFrm() && + !dynamic_cast<const SwUnoCrsr*>(this) ) + { + return FALSE; + } + + //JP 28.10.97: Bug 45129 - im UI-ReadOnly ist alles erlaubt + if( !pDoc->GetDocShell() || !pDoc->GetDocShell()->IsReadOnlyUI() ) + return TRUE; + + BOOL bCrsrInReadOnly = IsReadOnlyAvailable(); + if( !bCrsrInReadOnly && pNd->IsProtect() ) + return FALSE; + + const SwSectionNode* pSectNd = pNd->FindSectionNode(); + if( pSectNd && (pSectNd->GetSection().IsHiddenFlag() || + ( !bCrsrInReadOnly && pSectNd->GetSection().IsProtectFlag() ))) + return FALSE; + + return TRUE; +} + +void SwCursor::SaveTblBoxCntnt( const SwPosition* ) {} + +// setze den SRange fuer das Suchen im Dokument +SwMoveFnCollection* SwCursor::MakeFindRange( SwDocPositions nStart, + SwDocPositions nEnd, SwPaM* pRange ) const +{ + pRange->SetMark(); + FillFindPos( nStart, *pRange->GetMark() ); + FillFindPos( nEnd, *pRange->GetPoint() ); + + // bestimme die Richtung, in der zu suchen ist + // ( GetPoint > GetMark -> vorwaerts, sonst rueckwaerts ) + return ( DOCPOS_START == nStart || DOCPOS_OTHERSTART == nStart || + (DOCPOS_CURR == nStart && + (DOCPOS_END == nEnd || DOCPOS_OTHEREND == nEnd ) )) + ? fnMoveForward : fnMoveBackward; +} + + +ULONG lcl_FindSelection( SwFindParas& rParas, SwCursor* pCurCrsr, + SwMoveFn fnMove, SwCursor*& pFndRing, + SwPaM& aRegion, FindRanges eFndRngs, + BOOL bInReadOnly, BOOL& bCancel ) +{ + SwDoc* pDoc = pCurCrsr->GetDoc(); + BOOL bDoesUndo = pDoc->DoesUndo(); + int nFndRet = 0; + ULONG nFound = 0; + int bSrchBkwrd = fnMove == fnMoveBackward, bEnde = FALSE; + SwPaM *pTmpCrsr = pCurCrsr, *pSaveCrsr = pCurCrsr; + + // only create progress-bar for ShellCrsr + bool bIsUnoCrsr = 0 != dynamic_cast<SwUnoCrsr*>(pCurCrsr); + _PercentHdl* pPHdl = 0; + USHORT nCrsrCnt = 0; + if( FND_IN_SEL & eFndRngs ) + { + while( pCurCrsr != ( pTmpCrsr = (SwPaM*)pTmpCrsr->GetNext() )) + ++nCrsrCnt; + if( nCrsrCnt && !bIsUnoCrsr ) + pPHdl = new _PercentHdl( 0, nCrsrCnt, pDoc->GetDocShell() ); + } + else + pSaveCrsr = (SwPaM*)pSaveCrsr->GetPrev(); + + do { + aRegion.SetMark(); + // egal in welche Richtung, SPoint ist immer groesser als Mark, + // wenn der Suchbereich gueltig ist !! + SwPosition *pSttPos = aRegion.GetMark(), + *pEndPos = aRegion.GetPoint(); + *pSttPos = *pTmpCrsr->Start(); + *pEndPos = *pTmpCrsr->End(); + if( bSrchBkwrd ) + aRegion.Exchange(); + + if( !nCrsrCnt && !pPHdl && !bIsUnoCrsr ) + pPHdl = new _PercentHdl( aRegion ); + + // solange gefunden und nicht auf gleicher Position haengen bleibt + while( *pSttPos <= *pEndPos && + 0 != ( nFndRet = rParas.Find( pCurCrsr, fnMove, + &aRegion, bInReadOnly )) && + ( !pFndRing || + *pFndRing->GetPoint() != *pCurCrsr->GetPoint() || + *pFndRing->GetMark() != *pCurCrsr->GetMark() )) + { + if( !( FIND_NO_RING & nFndRet )) + { + // Bug 24084: Ring richtig herum aufbauen -> gleiche Mimik + // wie beim CreateCrsr !!!! + + SwCursor* pNew = pCurCrsr->Create( pFndRing ); + if( !pFndRing ) + pFndRing = pNew; + + pNew->SetMark(); + *pNew->GetMark() = *pCurCrsr->GetMark(); + } + + ++nFound; + + if( !( eFndRngs & FND_IN_SELALL) ) + { + bEnde = TRUE; + break; + } + + if( coSrchRplcThreshold == nFound && pDoc->DoesUndo() + && rParas.IsReplaceMode()) + { + short nRet = pCurCrsr->MaxReplaceArived(); + if( RET_YES == nRet ) + { + pDoc->DelAllUndoObj(); + pDoc->DoUndo( FALSE ); + } + else + { + bEnde = TRUE; + if(RET_CANCEL == nRet) + { + bCancel = TRUE; + //unwind() ?? + } + break; + } + } + + if( bSrchBkwrd ) + // bewege pEndPos vor den gefundenen Bereich + *pEndPos = *pCurCrsr->Start(); + else + // bewege pSttPos hinter den gefundenen Bereich + *pSttPos = *pCurCrsr->End(); + + if( *pSttPos == *pEndPos ) // im Bereich, aber am Ende + break; // fertig + + if( !nCrsrCnt && pPHdl ) + { + pPHdl->NextPos( *aRegion.GetMark() ); + } + } + + if( bEnde || !( eFndRngs & ( FND_IN_SELALL | FND_IN_SEL )) ) + break; + + pTmpCrsr = ((SwPaM*)pTmpCrsr->GetNext()); + if( nCrsrCnt && pPHdl ) + { + pPHdl->NextPos( ++pPHdl->nActPos ); + } + + } while( pTmpCrsr != pSaveCrsr ); + + if( nFound && !pFndRing ) // falls kein Ring aufgebaut werden soll + pFndRing = pCurCrsr->Create(); + + delete pPHdl; + pDoc->DoUndo( bDoesUndo ); + return nFound; +} + + +int lcl_MakeSelFwrd( const SwNode& rSttNd, const SwNode& rEndNd, + SwPaM& rPam, int bFirst ) +{ + if( rSttNd.GetIndex() + 1 == rEndNd.GetIndex() ) + return FALSE; + + SwNodes& rNds = rPam.GetDoc()->GetNodes(); + rPam.DeleteMark(); + SwCntntNode* pCNd; + if( !bFirst ) + { + rPam.GetPoint()->nNode = rSttNd; + pCNd = rNds.GoNext( &rPam.GetPoint()->nNode ); + if( !pCNd ) + return FALSE; + pCNd->MakeStartIndex( &rPam.GetPoint()->nContent ); + } + else if( rSttNd.GetIndex() > rPam.GetPoint()->nNode.GetIndex() || + rPam.GetPoint()->nNode.GetIndex() >= rEndNd.GetIndex() ) + return FALSE; // steht nicht in dieser Section + + rPam.SetMark(); + rPam.GetPoint()->nNode = rEndNd; + pCNd = rNds.GoPrevious( &rPam.GetPoint()->nNode ); + if( !pCNd ) + return FALSE; + pCNd->MakeEndIndex( &rPam.GetPoint()->nContent ); + + return *rPam.GetMark() < *rPam.GetPoint(); +} + + +int lcl_MakeSelBkwrd( const SwNode& rSttNd, const SwNode& rEndNd, + SwPaM& rPam, int bFirst ) +{ + if( rEndNd.GetIndex() + 1 == rSttNd.GetIndex() ) + return FALSE; + + SwNodes& rNds = rPam.GetDoc()->GetNodes(); + rPam.DeleteMark(); + SwCntntNode* pCNd; + if( !bFirst ) + { + rPam.GetPoint()->nNode = rSttNd; + pCNd = rNds.GoPrevious( &rPam.GetPoint()->nNode ); + if( !pCNd ) + return FALSE; + pCNd->MakeEndIndex( &rPam.GetPoint()->nContent ); + } + else if( rEndNd.GetIndex() > rPam.GetPoint()->nNode.GetIndex() || + rPam.GetPoint()->nNode.GetIndex() >= rSttNd.GetIndex() ) + return FALSE; // steht nicht in dieser Section + + rPam.SetMark(); + rPam.GetPoint()->nNode = rEndNd; + pCNd = rNds.GoNext( &rPam.GetPoint()->nNode ); + if( !pCNd ) + return FALSE; + pCNd->MakeStartIndex( &rPam.GetPoint()->nContent ); + + return *rPam.GetPoint() < *rPam.GetMark(); +} + + +// diese Methode "sucht" fuer alle Anwendungsfaelle, denn in SwFindParas +// steht immer die richtigen Parameter und die entsprechende Find-Methode + +ULONG SwCursor::FindAll( SwFindParas& rParas, + SwDocPositions nStart, SwDocPositions nEnde, + FindRanges eFndRngs, BOOL& bCancel ) +{ + bCancel = FALSE; + SwCrsrSaveState aSaveState( *this ); + + // Region erzeugen, ohne das diese in den Ring aufgenommen wird ! + SwPaM aRegion( *GetPoint() ); + SwMoveFn fnMove = MakeFindRange( nStart, nEnde, &aRegion ); + + ULONG nFound = 0; + int bMvBkwrd = fnMove == fnMoveBackward; + BOOL bInReadOnly = IsReadOnlyAvailable(); + + SwCursor* pFndRing = 0; + SwNodes& rNds = GetDoc()->GetNodes(); + + // suche in Bereichen ? + if( FND_IN_SEL & eFndRngs ) + { + // String nicht im Bereich gefunden, dann erhalte alle Bereiche, + // der Cursor beleibt unveraendert + if( 0 == ( nFound = lcl_FindSelection( rParas, this, fnMove, + pFndRing, aRegion, eFndRngs, + bInReadOnly, bCancel ) )) + return nFound; + + // der String wurde ein- bis mehrmals gefunden. Das steht alles + // im neuen Crsr-Ring. Darum hebe erstmal den alten Ring auf + while( GetNext() != this ) + delete GetNext(); + + *GetPoint() = *pFndRing->GetPoint(); + SetMark(); + *GetMark() = *pFndRing->GetMark(); + pFndRing->MoveRingTo( this ); + delete pFndRing; + } + else if( FND_IN_OTHER & eFndRngs ) + { + // Cursor als Kopie vom akt. und in den Ring aufnehmen + // Verkettung zeigt immer auf den zuerst erzeugten, also vorwaerts + SwCursor* pSav = Create( this ); // sicher den aktuellen Crsr + + // wenn schon ausserhalb vom Bodytext, suche von der Position, + // ansonsten beginne mit der 1. GrundSection + if( bMvBkwrd + ? lcl_MakeSelBkwrd( rNds.GetEndOfExtras(), + *rNds.GetEndOfPostIts().StartOfSectionNode(), + *this, rNds.GetEndOfExtras().GetIndex() >= + GetPoint()->nNode.GetIndex() ) + : lcl_MakeSelFwrd( *rNds.GetEndOfPostIts().StartOfSectionNode(), + rNds.GetEndOfExtras(), *this, + rNds.GetEndOfExtras().GetIndex() >= + GetPoint()->nNode.GetIndex() )) + { + nFound = lcl_FindSelection( rParas, this, fnMove, pFndRing, + aRegion, eFndRngs, bInReadOnly, bCancel ); + } + + if( !nFound ) + { + // den alten wieder zurueck + *GetPoint() = *pSav->GetPoint(); + if( pSav->HasMark() ) + { + SetMark(); + *GetMark() = *pSav->GetMark(); + } + else + DeleteMark(); + return 0; + } + + delete pSav; + if( !( FND_IN_SELALL & eFndRngs )) + { + // es sollte nur einer gesucht werden, also fuege in dazu + // egal in welche Richtung, SPoint ist immer groesser als Mark, + // wenn der Suchbereich gueltig ist !! + *GetPoint() = *pFndRing->GetPoint(); + SetMark(); + *GetMark() = *pFndRing->GetMark(); + } + else + { + // es wurde ein- bis mehrmals gefunden. Das steht alles + // im neuen Crsr-Ring. Darum hebe erstmal den alten Ring auf + while( GetNext() != this ) + delete GetNext(); + + *GetPoint() = *pFndRing->GetPoint(); + SetMark(); + *GetMark() = *pFndRing->GetMark(); + pFndRing->MoveRingTo( this ); + } + delete pFndRing; + } + else if( FND_IN_SELALL & eFndRngs ) + { + SwCursor* pSav = Create( this ); // sicher den aktuellen Crsr + + const SwNode* pSttNd = ( FND_IN_BODYONLY & eFndRngs ) + ? rNds.GetEndOfContent().StartOfSectionNode() + : rNds.GetEndOfPostIts().StartOfSectionNode(); + + if( bMvBkwrd + ? lcl_MakeSelBkwrd( rNds.GetEndOfContent(), *pSttNd,*this, FALSE ) + : lcl_MakeSelFwrd( *pSttNd, rNds.GetEndOfContent(), *this, FALSE )) + { + nFound = lcl_FindSelection( rParas, this, fnMove, pFndRing, + aRegion, eFndRngs, bInReadOnly, bCancel ); + } + + if( !nFound ) + { + // den alten wieder zurueck + *GetPoint() = *pSav->GetPoint(); + if( pSav->HasMark() ) + { + SetMark(); + *GetMark() = *pSav->GetMark(); + } + else + DeleteMark(); + return 0; + } + // es wurde ein- bis mehrmals gefunden. Das steht alles + // im neuen Crsr-Ring. Darum hebe erstmal den alten Ring auf + delete pSav; + + while( GetNext() != this ) + delete GetNext(); + + *GetPoint() = *pFndRing->GetPoint(); + SetMark(); + *GetMark() = *pFndRing->GetMark(); + pFndRing->MoveRingTo( this ); + delete pFndRing; + } + else + { + // ist ein GetMark gesetzt, dann wird bei gefundenem Object + // der GetMark beibehalten !! Dadurch kann ein Bereich mit der Suche + // aufgespannt werden. + SwPosition aMarkPos( *GetMark() ); + int bMarkPos = HasMark() && !eFndRngs; + + if( 0 != (nFound = rParas.Find( this, fnMove, + &aRegion, bInReadOnly ) ? 1 : 0) + && bMarkPos ) + *GetMark() = aMarkPos; + } + + if( nFound && SwCursor::IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE ) ) + nFound = 0; + return nFound; +} + + +void SwCursor::FillFindPos( SwDocPositions ePos, SwPosition& rPos ) const +{ + BOOL bIsStart = TRUE; + SwCntntNode* pCNd = 0; + SwNodes& rNds = GetDoc()->GetNodes(); + + switch( ePos ) + { + case DOCPOS_START: + rPos.nNode = *rNds.GetEndOfContent().StartOfSectionNode(); + pCNd = rNds.GoNext( &rPos.nNode ); + break; + + case DOCPOS_END: + rPos.nNode = rNds.GetEndOfContent(); + pCNd = rNds.GoPrevious( &rPos.nNode ); + bIsStart = FALSE; + break; + + case DOCPOS_OTHERSTART: + rPos.nNode = *rNds[ ULONG(0) ]; + pCNd = rNds.GoNext( &rPos.nNode ); + break; + + case DOCPOS_OTHEREND: + rPos.nNode = *rNds.GetEndOfContent().StartOfSectionNode(); + pCNd = rNds.GoPrevious( &rPos.nNode ); + bIsStart = FALSE; + break; + +// case DOCPOS_CURR: + default: + rPos = *GetPoint(); + } + + if( pCNd ) + { + xub_StrLen nCPos = 0; + if( !bIsStart ) + nCPos = pCNd->Len(); + rPos.nContent.Assign( pCNd, nCPos ); + } +} + +short SwCursor::MaxReplaceArived() +{ + return RET_YES; +} + + +BOOL SwCursor::IsStartWord( sal_Int16 nWordType ) const +{ + return IsStartWordWT( nWordType ); +} + +BOOL SwCursor::IsEndWord( sal_Int16 nWordType ) const +{ + return IsEndWordWT( nWordType ); +} + +BOOL SwCursor::IsInWord( sal_Int16 nWordType ) const +{ + return IsInWordWT( nWordType ); +} + +BOOL SwCursor::GoStartWord() +{ + return GoStartWordWT( WordType::ANYWORD_IGNOREWHITESPACES ); +} + +BOOL SwCursor::GoEndWord() +{ + return GoEndWordWT( WordType::ANYWORD_IGNOREWHITESPACES ); +} + +BOOL SwCursor::GoNextWord() +{ + return GoNextWordWT( WordType::ANYWORD_IGNOREWHITESPACES ); +} + +BOOL SwCursor::GoPrevWord() +{ + return GoPrevWordWT( WordType::ANYWORD_IGNOREWHITESPACES ); +} + +BOOL SwCursor::SelectWord( const Point* pPt ) +{ + return SelectWordWT( WordType::ANYWORD_IGNOREWHITESPACES, pPt ); +} + +BOOL SwCursor::IsStartWordWT( sal_Int16 nWordType ) const +{ + BOOL bRet = FALSE; + const SwTxtNode* pTxtNd = GetNode()->GetTxtNode(); + if( pTxtNd && pBreakIt->GetBreakIter().is() ) + { + xub_StrLen nPtPos = GetPoint()->nContent.GetIndex(); + bRet = pBreakIt->GetBreakIter()->isBeginWord( + pTxtNd->GetTxt(), nPtPos, + pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos )), + nWordType ); + } + return bRet; +} + +BOOL SwCursor::IsEndWordWT( sal_Int16 nWordType ) const +{ + BOOL bRet = FALSE; + const SwTxtNode* pTxtNd = GetNode()->GetTxtNode(); + if( pTxtNd && pBreakIt->GetBreakIter().is() ) + { + xub_StrLen nPtPos = GetPoint()->nContent.GetIndex(); + bRet = pBreakIt->GetBreakIter()->isEndWord( + pTxtNd->GetTxt(), nPtPos, + pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos ) ), + nWordType ); + + } + return bRet; +} + +BOOL SwCursor::IsInWordWT( sal_Int16 nWordType ) const +{ + BOOL bRet = FALSE; + const SwTxtNode* pTxtNd = GetNode()->GetTxtNode(); + if( pTxtNd && pBreakIt->GetBreakIter().is() ) + { + xub_StrLen nPtPos = GetPoint()->nContent.GetIndex(); + Boundary aBoundary = pBreakIt->GetBreakIter()->getWordBoundary( + pTxtNd->GetTxt(), nPtPos, + pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos ) ), + nWordType, + TRUE ); + + bRet = aBoundary.startPos != aBoundary.endPos && + aBoundary.startPos <= nPtPos && + nPtPos <= aBoundary.endPos; + if(bRet) + { + const CharClass& rCC = GetAppCharClass(); + bRet = rCC.isLetterNumeric( pTxtNd->GetTxt(), static_cast<xub_StrLen>(aBoundary.startPos) ); + } + } + return bRet; +} + +BOOL SwCursor::IsStartEndSentence( bool bEnd ) const +{ + BOOL bRet = bEnd ? + GetCntntNode() && GetPoint()->nContent == GetCntntNode()->Len() : + GetPoint()->nContent.GetIndex() == 0; + + if( !bRet ) + { + SwCursor aCrsr(*GetPoint(), 0, false); + SwPosition aOrigPos = *aCrsr.GetPoint(); + aCrsr.GoSentence( bEnd ? SwCursor::END_SENT : SwCursor::START_SENT ); + bRet = aOrigPos == *aCrsr.GetPoint(); + } + + return bRet; +} + +BOOL SwCursor::GoStartWordWT( sal_Int16 nWordType ) +{ + BOOL bRet = FALSE; + const SwTxtNode* pTxtNd = GetNode()->GetTxtNode(); + if( pTxtNd && pBreakIt->GetBreakIter().is() ) + { + SwCrsrSaveState aSave( *this ); + xub_StrLen nPtPos = GetPoint()->nContent.GetIndex(); + nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->getWordBoundary( + pTxtNd->GetTxt(), nPtPos, + pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos ) ), + nWordType, + FALSE ).startPos; + + if( nPtPos < pTxtNd->GetTxt().Len() ) + { + GetPoint()->nContent = nPtPos; + if( !IsSelOvr() ) + bRet = TRUE; + } + } + return bRet; +} + +BOOL SwCursor::GoEndWordWT( sal_Int16 nWordType ) +{ + BOOL bRet = FALSE; + const SwTxtNode* pTxtNd = GetNode()->GetTxtNode(); + if( pTxtNd && pBreakIt->GetBreakIter().is() ) + { + SwCrsrSaveState aSave( *this ); + xub_StrLen nPtPos = GetPoint()->nContent.GetIndex(); + nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->getWordBoundary( + pTxtNd->GetTxt(), nPtPos, + pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos ) ), + nWordType, + TRUE ).endPos; + + if( nPtPos <= pTxtNd->GetTxt().Len() && + GetPoint()->nContent.GetIndex() != nPtPos ) + { + GetPoint()->nContent = nPtPos; + if( !IsSelOvr() ) + bRet = TRUE; + } + } + return bRet; +} + +BOOL SwCursor::GoNextWordWT( sal_Int16 nWordType ) +{ + BOOL bRet = FALSE; + const SwTxtNode* pTxtNd = GetNode()->GetTxtNode(); + if( pTxtNd && pBreakIt->GetBreakIter().is() ) + { + SwCrsrSaveState aSave( *this ); + xub_StrLen nPtPos = GetPoint()->nContent.GetIndex(); + + nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->nextWord( + pTxtNd->GetTxt(), nPtPos, + pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos, 1 ) ), + nWordType ).startPos; + + if( nPtPos < pTxtNd->GetTxt().Len() ) + { + GetPoint()->nContent = nPtPos; + if( !IsSelOvr() ) + bRet = TRUE; + } + } + return bRet; +} + +BOOL SwCursor::GoPrevWordWT( sal_Int16 nWordType ) +{ + BOOL bRet = FALSE; + const SwTxtNode* pTxtNd = GetNode()->GetTxtNode(); + if( pTxtNd && pBreakIt->GetBreakIter().is() ) + { + SwCrsrSaveState aSave( *this ); + xub_StrLen nPtPos = GetPoint()->nContent.GetIndex(); + const xub_StrLen nPtStart = nPtPos; + + if( nPtPos ) + --nPtPos; + nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->previousWord( + pTxtNd->GetTxt(), nPtStart, + pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos, 1 ) ), + nWordType ).startPos; + + if( nPtPos < pTxtNd->GetTxt().Len() ) + { + GetPoint()->nContent = nPtPos; + if( !IsSelOvr() ) + bRet = TRUE; + } + } + return bRet; +} + +BOOL SwCursor::SelectWordWT( sal_Int16 nWordType, const Point* pPt ) +{ + SwCrsrSaveState aSave( *this ); + + BOOL bRet = FALSE; + BOOL bForward = TRUE; + DeleteMark(); + SwRootFrm* pLayout; + if( pPt && 0 != (pLayout = GetDoc()->GetRootFrm()) ) + { + // set the cursor to the layout position + Point aPt( *pPt ); + pLayout->GetCrsrOfst( GetPoint(), aPt ); + } + + const SwTxtNode* pTxtNd = GetNode()->GetTxtNode(); + if( pTxtNd && pBreakIt->GetBreakIter().is() ) + { + xub_StrLen nPtPos = GetPoint()->nContent.GetIndex(); + Boundary aBndry( pBreakIt->GetBreakIter()->getWordBoundary( + pTxtNd->GetTxt(), nPtPos, + pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos ) ), + nWordType, + bForward )); + + if( aBndry.startPos != aBndry.endPos ) + { + GetPoint()->nContent = (xub_StrLen)aBndry.endPos; + if( !IsSelOvr() ) + { + SetMark(); + GetMark()->nContent = (xub_StrLen)aBndry.startPos; + if( !IsSelOvr() ) + bRet = TRUE; + } + } + } + + if( !bRet ) + { + DeleteMark(); + RestoreSavePos(); + } + return bRet; +} + +//----------------------------------------------------------------------------- + +static String lcl_MaskDeletedRedlines( const SwTxtNode* pTxtNd ) +{ + String aRes; + if (pTxtNd) + { + //mask deleted redlines + String sNodeText(pTxtNd->GetTxt()); + const SwDoc& rDoc = *pTxtNd->GetDoc(); + const bool nShowChg = IDocumentRedlineAccess::IsShowChanges( rDoc.GetRedlineMode() ); + if ( nShowChg ) + { + USHORT nAct = rDoc.GetRedlinePos( *pTxtNd, USHRT_MAX ); + for ( ; nAct < rDoc.GetRedlineTbl().Count(); nAct++ ) + { + const SwRedline* pRed = rDoc.GetRedlineTbl()[ nAct ]; + if ( pRed->Start()->nNode > pTxtNd->GetIndex() ) + break; + + if( nsRedlineType_t::REDLINE_DELETE == pRed->GetType() ) + { + xub_StrLen nStart, nEnd; + pRed->CalcStartEnd( pTxtNd->GetIndex(), nStart, nEnd ); + + while ( nStart < nEnd && nStart < sNodeText.Len() ) + sNodeText.SetChar( nStart++, CH_TXTATR_INWORD ); + } + } + } + aRes = sNodeText; + } + return aRes; +} + +BOOL SwCursor::GoSentence( SentenceMoveType eMoveType ) +{ + BOOL bRet = FALSE; + const SwTxtNode* pTxtNd = GetNode()->GetTxtNode(); + if( pTxtNd && pBreakIt->GetBreakIter().is() ) + { + String sNodeText( lcl_MaskDeletedRedlines( pTxtNd ) ); + + SwCrsrSaveState aSave( *this ); + xub_StrLen nPtPos = GetPoint()->nContent.GetIndex(); + switch ( eMoveType ) + { + case START_SENT: /* when modifying: see also ExpandToSentenceBorders below! */ + nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->beginOfSentence( + sNodeText, + nPtPos, pBreakIt->GetLocale( + pTxtNd->GetLang( nPtPos ) )); + break; + case END_SENT: /* when modifying: see also ExpandToSentenceBorders below! */ + nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->endOfSentence( + sNodeText, + nPtPos, pBreakIt->GetLocale( + pTxtNd->GetLang( nPtPos ) )); + break; + case NEXT_SENT: + { + nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->endOfSentence( + sNodeText, + nPtPos, pBreakIt->GetLocale( + pTxtNd->GetLang( nPtPos ) )); + while (nPtPos != (USHORT) -1 && ++nPtPos < sNodeText.Len() + && sNodeText.GetChar(nPtPos)== ' ' /*isWhiteSpace( aTxt.GetChar(nPtPos)*/ ) + ; + break; + } + case PREV_SENT: + nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->beginOfSentence( + sNodeText, + nPtPos, pBreakIt->GetLocale( + pTxtNd->GetLang( nPtPos ) )); + if (nPtPos == 0) + return FALSE; // the previous sentence is not in this paragraph + if (nPtPos > 0) + nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->beginOfSentence( + sNodeText, + nPtPos - 1, pBreakIt->GetLocale( + pTxtNd->GetLang( nPtPos ) )); + break; + } + + // it is allowed to place the PaM just behind the last + // character in the text thus <= ...Len + if( nPtPos <= pTxtNd->GetTxt().Len() ) + { + GetPoint()->nContent = nPtPos; + if( !IsSelOvr() ) + bRet = TRUE; + } + } + return bRet; +} + + +BOOL SwCursor::ExpandToSentenceBorders() +{ + BOOL bRes = FALSE; + const SwTxtNode* pStartNd = Start()->nNode.GetNode().GetTxtNode(); + const SwTxtNode* pEndNd = End()->nNode.GetNode().GetTxtNode(); + if (pStartNd && pEndNd && pBreakIt->GetBreakIter().is()) + { + if (!HasMark()) + SetMark(); + + String sStartText( lcl_MaskDeletedRedlines( pStartNd ) ); + String sEndText( pStartNd == pEndNd? sStartText : lcl_MaskDeletedRedlines( pEndNd ) ); + + SwCrsrSaveState aSave( *this ); + xub_StrLen nStartPos = Start()->nContent.GetIndex(); + xub_StrLen nEndPos = End()->nContent.GetIndex(); + + nStartPos = (xub_StrLen)pBreakIt->GetBreakIter()->beginOfSentence( + sStartText, nStartPos, + pBreakIt->GetLocale( pStartNd->GetLang( nStartPos ) ) ); + nEndPos = (xub_StrLen)pBreakIt->GetBreakIter()->endOfSentence( + sEndText, nEndPos, + pBreakIt->GetLocale( pEndNd->GetLang( nEndPos ) ) ); + + // it is allowed to place the PaM just behind the last + // character in the text thus <= ...Len + bool bChanged = false; + if (nStartPos <= pStartNd->GetTxt().Len()) + { + GetMark()->nContent = nStartPos; + bChanged = true; + } + if (nEndPos <= pEndNd->GetTxt().Len()) + { + GetPoint()->nContent = nEndPos; + bChanged = true; + } + if (bChanged && !IsSelOvr()) + bRes = TRUE; + } + return bRes; +} + + +BOOL SwTableCursor::LeftRight( BOOL bLeft, USHORT nCnt, USHORT /*nMode*/, + BOOL /*bVisualAllowed*/, BOOL /*bSkipHidden*/, BOOL /*bInsertCrsr*/ ) +{ + return bLeft ? GoPrevCell( nCnt ) + : GoNextCell( nCnt ); +} + + +// calculate cursor bidi level: extracted from LeftRight() +const SwCntntFrm* +SwCursor::DoSetBidiLevelLeftRight( + BOOL & io_rbLeft, BOOL bVisualAllowed, BOOL bInsertCrsr) +{ + // calculate cursor bidi level + const SwCntntFrm* pSttFrm = NULL; + SwNode& rNode = GetPoint()->nNode.GetNode(); + + if( rNode.IsTxtNode() ) + { + const SwTxtNode& rTNd = *rNode.GetTxtNode(); + SwIndex& rIdx = GetPoint()->nContent; + xub_StrLen nPos = rIdx.GetIndex(); + + const SvtCTLOptions& rCTLOptions = SW_MOD()->GetCTLOptions(); + if ( bVisualAllowed && rCTLOptions.IsCTLFontEnabled() && + SvtCTLOptions::MOVEMENT_VISUAL == + rCTLOptions.GetCTLCursorMovement() ) + { + // for visual cursor travelling (used in bidi layout) + // we first have to convert the logic to a visual position + Point aPt; + pSttFrm = rTNd.GetFrm( &aPt, GetPoint() ); + if( pSttFrm ) + { + BYTE nCrsrLevel = GetCrsrBidiLevel(); + sal_Bool bForward = ! io_rbLeft; + ((SwTxtFrm*)pSttFrm)->PrepareVisualMove( nPos, nCrsrLevel, + bForward, bInsertCrsr ); + rIdx = nPos; + SetCrsrBidiLevel( nCrsrLevel ); + io_rbLeft = ! bForward; + } + } + else + { + const SwScriptInfo* pSI = SwScriptInfo::GetScriptInfo( rTNd ); + if ( pSI ) + { + const xub_StrLen nMoveOverPos = io_rbLeft ? + ( nPos ? nPos - 1 : 0 ) : + nPos; + SetCrsrBidiLevel( pSI->DirType( nMoveOverPos ) ); + } + } + } + return pSttFrm; +} + +BOOL SwCursor::LeftRight( BOOL bLeft, USHORT nCnt, USHORT nMode, + BOOL bVisualAllowed,BOOL bSkipHidden, BOOL bInsertCrsr ) +{ + // calculate cursor bidi level + SwNode& rNode = GetPoint()->nNode.GetNode(); + const SwCntntFrm* pSttFrm = // may side-effect bLeft! + DoSetBidiLevelLeftRight(bLeft, bVisualAllowed, bInsertCrsr); + + // kann der Cursor n-mal weiterverschoben werden ? + SwCrsrSaveState aSave( *this ); + SwMoveFn fnMove = bLeft ? fnMoveBackward : fnMoveForward; + + SwGoInDoc fnGo; + if ( bSkipHidden ) + fnGo = CRSR_SKIP_CELLS == nMode ? fnGoCntntCellsSkipHidden : fnGoCntntSkipHidden; + else + fnGo = CRSR_SKIP_CELLS == nMode ? fnGoCntntCells : fnGoCntnt; + + // ASSERT( not in covered cell ) + + while( nCnt ) + { + SwNodeIndex aOldNodeIdx( GetPoint()->nNode ); + + bool bSuccess = Move( fnMove, fnGo ); + if ( !bSuccess ) + break; + + // If we were located inside a covered cell but our position has been + // corrected, we check if the last move has moved the cursor to a different + // table cell. In this case we set the cursor to the stored covered position + // and redo the move: + if ( mnRowSpanOffset ) + { + const SwNode* pOldTabBoxSttNode = aOldNodeIdx.GetNode().FindTableBoxStartNode(); + const SwTableNode* pOldTabSttNode = pOldTabBoxSttNode ? pOldTabBoxSttNode->FindTableNode() : 0; + const SwNode* pNewTabBoxSttNode = GetPoint()->nNode.GetNode().FindTableBoxStartNode(); + const SwTableNode* pNewTabSttNode = pNewTabBoxSttNode ? pNewTabBoxSttNode->FindTableNode() : 0; + + const bool bCellChanged = pOldTabSttNode && pNewTabSttNode && + pOldTabSttNode == pNewTabSttNode && + pOldTabBoxSttNode && pNewTabBoxSttNode && + pOldTabBoxSttNode != pNewTabBoxSttNode; + + if ( bCellChanged ) + { + // Set cursor to start/end of covered cell: + SwTableBox* pTableBox = pOldTabBoxSttNode->GetTblBox(); + const long nRowSpan = pTableBox->getRowSpan(); + if ( nRowSpan > 1 ) + { + pTableBox = & pTableBox->FindEndOfRowSpan( pOldTabSttNode->GetTable(), (USHORT)(pTableBox->getRowSpan() + mnRowSpanOffset ) ); + SwNodeIndex& rPtIdx = GetPoint()->nNode; + SwNodeIndex aNewIdx( *pTableBox->GetSttNd() ); + rPtIdx = aNewIdx; + + GetDoc()->GetNodes().GoNextSection( &rPtIdx, FALSE, FALSE ); + SwCntntNode* pCntntNode = GetCntntNode(); + if ( pCntntNode ) + { + const xub_StrLen nTmpPos = bLeft ? pCntntNode->Len() : 0; + GetPoint()->nContent.Assign( pCntntNode, nTmpPos ); + + // Redo the move: + bSuccess = Move( fnMove, fnGo ); + if ( !bSuccess ) + break; + } + } + + mnRowSpanOffset = 0; + } + } + + // Check if I'm inside a covered cell. Correct cursor if necessary and + // store covered cell: + const SwNode* pTableBoxStartNode = GetPoint()->nNode.GetNode().FindTableBoxStartNode(); + if ( pTableBoxStartNode ) + { + const SwTableBox* pTableBox = pTableBoxStartNode->GetTblBox(); + if ( pTableBox->getRowSpan() < 1 ) + { + // Store the row span offset: + mnRowSpanOffset = pTableBox->getRowSpan(); + + // Move cursor to non-covered cell: + const SwTableNode* pTblNd = pTableBoxStartNode->FindTableNode(); + pTableBox = & pTableBox->FindStartOfRowSpan( pTblNd->GetTable(), USHRT_MAX ); + SwNodeIndex& rPtIdx = GetPoint()->nNode; + SwNodeIndex aNewIdx( *pTableBox->GetSttNd() ); + rPtIdx = aNewIdx; + + GetDoc()->GetNodes().GoNextSection( &rPtIdx, FALSE, FALSE ); + SwCntntNode* pCntntNode = GetCntntNode(); + if ( pCntntNode ) + { + const xub_StrLen nTmpPos = bLeft ? pCntntNode->Len() : 0; + GetPoint()->nContent.Assign( pCntntNode, nTmpPos ); + } + } + } + + --nCnt; + } + + // here come some special rules for visual cursor travelling + if ( pSttFrm ) + { + SwNode& rTmpNode = GetPoint()->nNode.GetNode(); + if ( &rTmpNode != &rNode && rTmpNode.IsTxtNode() ) + { + Point aPt; + const SwCntntFrm* pEndFrm = ((SwTxtNode&)rTmpNode).GetFrm( &aPt, GetPoint() ); + if ( pEndFrm ) + { + if ( ! pEndFrm->IsRightToLeft() != ! pSttFrm->IsRightToLeft() ) + { + if ( ! bLeft ) + pEndFrm->RightMargin( this ); + else + pEndFrm->LeftMargin( this ); + } + } + } + } + + return 0 == nCnt && !IsInProtectTable( TRUE ) && + !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE | + nsSwCursorSelOverFlags::SELOVER_CHANGEPOS ); +} + +// calculate cursor bidi level: extracted from UpDown() +void SwCursor::DoSetBidiLevelUpDown() +{ + SwNode& rNode = GetPoint()->nNode.GetNode(); + if ( rNode.IsTxtNode() ) + { + const SwScriptInfo* pSI = + SwScriptInfo::GetScriptInfo( (SwTxtNode&)rNode ); + if ( pSI ) + { + SwIndex& rIdx = GetPoint()->nContent; + xub_StrLen nPos = rIdx.GetIndex(); + + if( nPos && nPos < ((SwTxtNode&)rNode).GetTxt().Len() ) + { + const BYTE nCurrLevel = pSI->DirType( nPos ); + const BYTE nPrevLevel = pSI->DirType( nPos - 1 ); + + if ( nCurrLevel % 2 != nPrevLevel % 2 ) + { + // set cursor level to the lower of the two levels + SetCrsrBidiLevel( Min( nCurrLevel, nPrevLevel ) ); + } + else + SetCrsrBidiLevel( nCurrLevel ); + } + } + } +} + +BOOL SwCursor::UpDown( BOOL bUp, USHORT nCnt, + Point* pPt, long nUpDownX ) +{ + SwTableCursor* pTblCrsr = dynamic_cast<SwTableCursor*>(this); + sal_Bool bAdjustTableCrsr = sal_False; + + // vom Tabellen Crsr Point/Mark in der gleichen Box ?? + // dann stelle den Point an den Anfang der Box + if( pTblCrsr && GetNode( TRUE )->StartOfSectionNode() == + GetNode( FALSE )->StartOfSectionNode() ) + { + if ( End() != GetPoint() ) + Exchange(); + bAdjustTableCrsr = sal_True; + } + + BOOL bRet = FALSE; + Point aPt; + if( pPt ) + aPt = *pPt; + SwCntntFrm* pFrm = GetCntntNode()->GetFrm( &aPt, GetPoint() ); + + if( pFrm ) + { + SwCrsrSaveState aSave( *this ); + + if( !pPt ) + { + SwRect aTmpRect; + pFrm->GetCharRect( aTmpRect, *GetPoint() ); + aPt = aTmpRect.Pos(); + + nUpDownX = pFrm->IsVertical() ? + aPt.Y() - pFrm->Frm().Top() : + aPt.X() - pFrm->Frm().Left(); + } + + // Bei Fussnoten ist auch die Bewegung in eine andere Fussnote erlaubt. + // aber keine Selection!! + const BOOL bChkRange = pFrm->IsInFtn() && !HasMark() + ? FALSE : TRUE; + const SwPosition aOldPos( *GetPoint() ); + BOOL bInReadOnly = IsReadOnlyAvailable(); + + if ( bAdjustTableCrsr && !bUp ) + { + // Special case: We have a table cursor but the start box + // has more than one paragraph. If we want to go down, we have to + // set the point to the last frame in the table box. This is + // only necessary if we do not already have a table selection + const SwStartNode* pTblNd = GetNode( TRUE )->FindTableBoxStartNode(); + ASSERT( pTblNd, "pTblCrsr without SwTableNode?" ) + + if ( pTblNd ) // safety first + { + const SwNode* pEndNd = pTblNd->EndOfSectionNode(); + GetPoint()->nNode = *pEndNd; + pTblCrsr->Move( fnMoveBackward, fnGoNode ); + pFrm = GetCntntNode()->GetFrm( &aPt, GetPoint() ); + } + } + + while( nCnt && + (bUp ? pFrm->UnitUp( this, nUpDownX, bInReadOnly ) + : pFrm->UnitDown( this, nUpDownX, bInReadOnly ) ) && + CheckNodesRange( aOldPos.nNode, GetPoint()->nNode, bChkRange )) + { + pFrm = GetCntntNode()->GetFrm( &aPt, GetPoint() ); + --nCnt; + } + + if( !nCnt && !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE | + nsSwCursorSelOverFlags::SELOVER_CHANGEPOS ) ) // die gesamte Anzahl durchlaufen ? + { + if( !pTblCrsr ) + { + // dann versuche den Cursor auf die Position zu setzen, + // auf halber Heohe vom Char-Rectangle + pFrm = GetCntntNode()->GetFrm( &aPt, GetPoint() ); + SwCrsrMoveState eTmpState( MV_UPDOWN ); + eTmpState.bSetInReadOnly = bInReadOnly; + SwRect aTmpRect; + pFrm->GetCharRect( aTmpRect, *GetPoint(), &eTmpState ); + if ( pFrm->IsVertical() ) + { + aPt.X() = aTmpRect.Center().X(); + pFrm->Calc(); + aPt.Y() = pFrm->Frm().Top() + nUpDownX; + } + else + { + aPt.Y() = aTmpRect.Center().Y(); + pFrm->Calc(); + aPt.X() = pFrm->Frm().Left() + nUpDownX; + } + pFrm->GetCrsrOfst( GetPoint(), aPt, &eTmpState ); + } + bRet = TRUE; + } + else + *GetPoint() = aOldPos; + + DoSetBidiLevelUpDown(); // calculate cursor bidi level + } + + return bRet; +} + +BOOL SwCursor::LeftRightMargin( BOOL bLeft, BOOL bAPI ) +{ + Point aPt; + SwCntntFrm * pFrm = GetCntntNode()->GetFrm( &aPt, GetPoint() ); + + // calculate cursor bidi level + if ( pFrm ) + SetCrsrBidiLevel( pFrm->IsRightToLeft() ? 1 : 0 ); + + return pFrm && (bLeft ? pFrm->LeftMargin( this ) : + pFrm->RightMargin( this, bAPI ) ); +} + +BOOL SwCursor::IsAtLeftRightMargin( BOOL bLeft, BOOL bAPI ) const +{ + BOOL bRet = FALSE; + Point aPt; + SwCntntFrm * pFrm = GetCntntNode()->GetFrm( &aPt, GetPoint() ); + if( pFrm ) + { + SwPaM aPam( *GetPoint() ); + if( !bLeft && aPam.GetPoint()->nContent.GetIndex() ) + aPam.GetPoint()->nContent--; + bRet = (bLeft ? pFrm->LeftMargin( &aPam ) + : pFrm->RightMargin( &aPam, bAPI )) + && *aPam.GetPoint() == *GetPoint(); + } + return bRet; +} + +BOOL SwCursor::SttEndDoc( BOOL bStt ) +{ + SwCrsrSaveState aSave( *this ); + + // Springe beim Selektieren nie ueber Section-Grenzen !! + // kann der Cursor weiterverschoben werden ? + SwMoveFn fnMove = bStt ? fnMoveBackward : fnMoveForward; + BOOL bRet = (!HasMark() || !IsNoCntnt() ) && + Move( fnMove, fnGoDoc ) && + !IsInProtectTable( TRUE ) && + !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE | + nsSwCursorSelOverFlags::SELOVER_CHANGEPOS | + nsSwCursorSelOverFlags::SELOVER_ENABLEREVDIREKTION ); + + return bRet; +} + +BOOL SwCursor::GoPrevNextCell( BOOL bNext, USHORT nCnt ) +{ + const SwTableNode* pTblNd = GetPoint()->nNode.GetNode().FindTableNode(); + if( !pTblNd ) + return FALSE; + + // liegt vor dem StartNode der Cell ein weiterer EndNode, dann + // gibt es auch eine vorherige Celle + SwCrsrSaveState aSave( *this ); + SwNodeIndex& rPtIdx = GetPoint()->nNode; + + while( nCnt-- ) + { + const SwNode* pTableBoxStartNode = rPtIdx.GetNode().FindTableBoxStartNode(); + const SwTableBox* pTableBox = pTableBoxStartNode->GetTblBox(); + + // Check if we have to move the cursor to a covered cell before + // proceeding: + if ( mnRowSpanOffset ) + { + if ( pTableBox->getRowSpan() > 1 ) + { + pTableBox = & pTableBox->FindEndOfRowSpan( pTblNd->GetTable(), (USHORT)(pTableBox->getRowSpan() + mnRowSpanOffset) ); + SwNodeIndex aNewIdx( *pTableBox->GetSttNd() ); + rPtIdx = aNewIdx; + pTableBoxStartNode = rPtIdx.GetNode().FindTableBoxStartNode(); + } + mnRowSpanOffset = 0; + } + + const SwNode* pTmpNode = bNext ? + pTableBoxStartNode->EndOfSectionNode() : + pTableBoxStartNode; + + SwNodeIndex aCellIdx( *pTmpNode, bNext ? 1 : -1 ); + if( (bNext && !aCellIdx.GetNode().IsStartNode()) || + (!bNext && !aCellIdx.GetNode().IsEndNode()) ) + return FALSE; + + rPtIdx = bNext ? aCellIdx : SwNodeIndex(*aCellIdx.GetNode().StartOfSectionNode()); + + pTableBoxStartNode = rPtIdx.GetNode().FindTableBoxStartNode(); + pTableBox = pTableBoxStartNode->GetTblBox(); + if ( pTableBox->getRowSpan() < 1 ) + { + mnRowSpanOffset = pTableBox->getRowSpan(); + // move cursor to non-covered cell: + pTableBox = & pTableBox->FindStartOfRowSpan( pTblNd->GetTable(), USHRT_MAX ); + SwNodeIndex aNewIdx( *pTableBox->GetSttNd() ); + rPtIdx = aNewIdx; + } + } + + rPtIdx++; + if( !rPtIdx.GetNode().IsCntntNode() ) + GetDoc()->GetNodes().GoNextSection( &rPtIdx, TRUE, FALSE ); + GetPoint()->nContent.Assign( GetCntntNode(), 0 ); + + return !IsInProtectTable( TRUE ); +} + +BOOL SwTableCursor::GotoTable( const String& /*rName*/ ) +{ + return FALSE; // invalid action +} + +BOOL SwCursor::GotoTable( const String& rName ) +{ + BOOL bRet = FALSE; + if ( !HasMark() ) + { + SwTable* pTmpTbl = SwTable::FindTable( GetDoc()->FindTblFmtByName( rName ) ); + if( pTmpTbl ) + { + // eine Tabelle im normalen NodesArr + SwCrsrSaveState aSave( *this ); + GetPoint()->nNode = *pTmpTbl->GetTabSortBoxes()[ 0 ]-> + GetSttNd()->FindTableNode(); + Move( fnMoveForward, fnGoCntnt ); + bRet = !IsSelOvr(); + } + } + return bRet; +} + +BOOL SwCursor::GotoTblBox( const String& rName ) +{ + BOOL bRet = FALSE; + const SwTableNode* pTblNd = GetPoint()->nNode.GetNode().FindTableNode(); + if( pTblNd ) + { + // erfrage die Box, mit dem Nanen + const SwTableBox* pTblBox = pTblNd->GetTable().GetTblBox( rName ); + if( pTblBox && pTblBox->GetSttNd() && + ( !pTblBox->GetFrmFmt()->GetProtect().IsCntntProtected() || + IsReadOnlyAvailable() ) ) + { + SwCrsrSaveState aSave( *this ); + GetPoint()->nNode = *pTblBox->GetSttNd(); + Move( fnMoveForward, fnGoCntnt ); + bRet = !IsSelOvr(); + } + } + return bRet; +} + +BOOL SwCursor::MovePara(SwWhichPara fnWhichPara, SwPosPara fnPosPara ) +{ + //JP 28.8.2001: for optimization test something before + const SwNode* pNd = &GetPoint()->nNode.GetNode(); + bool bShortCut = false; + if ( fnWhichPara == fnParaCurr ) + { + // --> FME 2005-02-21 #i41048# + // If fnWhichPara == fnParaCurr, (*fnWhichPara)( *this, fnPosPara ) + // can already move the cursor to a different text node. In this case + // we better check if IsSelOvr(). + const SwCntntNode* pCntntNd = pNd->GetCntntNode(); + if ( pCntntNd ) + { + const xub_StrLen nSttEnd = fnPosPara == fnMoveForward ? 0 : pCntntNd->Len(); + if ( GetPoint()->nContent.GetIndex() != nSttEnd ) + bShortCut = true; + } + // <-- + } + else + { + if ( pNd->IsTxtNode() && + pNd->GetNodes()[ pNd->GetIndex() + + (fnWhichPara == fnParaNext ? 1 : -1 ) ]->IsTxtNode() ) + bShortCut = true; + } + + if ( bShortCut ) + return (*fnWhichPara)( *this, fnPosPara ); + + // else we must use the SaveStructure, because the next/prev is not + // a same node type. + SwCrsrSaveState aSave( *this ); + return (*fnWhichPara)( *this, fnPosPara ) && + !IsInProtectTable( TRUE ) && + !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE | + nsSwCursorSelOverFlags::SELOVER_CHANGEPOS ); +} + + +BOOL SwCursor::MoveSection( SwWhichSection fnWhichSect, + SwPosSection fnPosSect) +{ + SwCrsrSaveState aSave( *this ); + return (*fnWhichSect)( *this, fnPosSect ) && + !IsInProtectTable( TRUE ) && + !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE | + nsSwCursorSelOverFlags::SELOVER_CHANGEPOS ); +} + +/* + BOOL MoveTable( SwWhichTable, SwPosTable ); + BOOL MoveColumn( SwWhichColumn, SwPosColumn ); + BOOL MoveRegion( SwWhichRegion, SwPosRegion ); +*/ + +void SwCursor::RestoreSavePos() // Point auf die SavePos setzen +{ + if( pSavePos ) + { + GetPoint()->nNode = pSavePos->nNode; + GetPoint()->nContent.Assign( GetCntntNode(), pSavePos->nCntnt ); + } +} + + +/* */ + +SwTableCursor::SwTableCursor( const SwPosition &rPos, SwPaM* pRing ) + : SwCursor( rPos, pRing, false ) +{ + bParked = FALSE; + bChg = FALSE; + nTblPtNd = 0, nTblMkNd = 0; + nTblPtCnt = 0, nTblMkCnt = 0; +} + +SwTableCursor::~SwTableCursor() {} + + +BOOL lcl_SeekEntry( const SwSelBoxes& rTmp, const SwStartNode* pSrch, USHORT& rFndPos ) +{ + ULONG nIdx = pSrch->GetIndex(); + + USHORT nO = rTmp.Count(), nM, nU = 0; + if( nO > 0 ) + { + nO--; + while( nU <= nO ) + { + nM = nU + ( nO - nU ) / 2; + if( rTmp[ nM ]->GetSttNd() == pSrch ) + { + rFndPos = nM; + return TRUE; + } + else if( rTmp[ nM ]->GetSttIdx() < nIdx ) + nU = nM + 1; + else if( nM == 0 ) + return FALSE; + else + nO = nM - 1; + } + } + return FALSE; +} + + +SwCursor* SwTableCursor::MakeBoxSels( SwCursor* pAktCrsr ) +{ + if( bChg ) // ??? + { + if( bParked ) + { + // wieder in den Inhalt schieben + Exchange(); + Move( fnMoveForward ); + Exchange(); + Move( fnMoveForward ); + bParked = FALSE; + } + + bChg = FALSE; + + // temp Kopie anlegen, damit alle Boxen, fuer die schon Cursor + // existieren, entfernt werden koennen. + SwSelBoxes aTmp; + aTmp.Insert( &aSelBoxes ); + + //Jetzt die Alten und die neuen abgleichen. + SwNodes& rNds = pAktCrsr->GetDoc()->GetNodes(); + USHORT nPos; + const SwStartNode* pSttNd; + SwPaM* pCur = pAktCrsr; + do { + BOOL bDel = FALSE; + pSttNd = pCur->GetPoint()->nNode.GetNode().FindTableBoxStartNode(); + if( !pCur->HasMark() || !pSttNd || + pSttNd != pCur->GetMark()->nNode.GetNode().FindTableBoxStartNode() ) + bDel = TRUE; + + else if( lcl_SeekEntry( aTmp, pSttNd, nPos )) + { + SwNodeIndex aIdx( *pSttNd, 1 ); + const SwNode* pNd = &aIdx.GetNode(); + if( !pNd->IsCntntNode() ) + pNd = rNds.GoNextSection( &aIdx, TRUE, FALSE ); + + SwPosition* pPos = pCur->GetMark(); + if( pNd != &pPos->nNode.GetNode() ) + pPos->nNode = *pNd; + pPos->nContent.Assign( (SwCntntNode*)pNd, 0 ); + + aIdx.Assign( *pSttNd->EndOfSectionNode(), - 1 ); + if( !( pNd = &aIdx.GetNode())->IsCntntNode() ) + pNd = rNds.GoPrevSection( &aIdx, TRUE, FALSE ); + + pPos = pCur->GetPoint(); + if( pNd != &pPos->nNode.GetNode() ) + pPos->nNode = *pNd; + pPos->nContent.Assign( (SwCntntNode*)pNd, ((SwCntntNode*)pNd)->Len() ); + + aTmp.Remove( nPos ); + } + else + bDel = TRUE; + + pCur = (SwPaM*)pCur->GetNext(); + if( bDel ) + { + SwPaM* pDel = (SwPaM*)pCur->GetPrev(); +/* +JP 20.07.98: der alte Code geht mit dem UNO-TableCrsr nicht + if( pDel == pAktCrsr ) + { + if( pAktCrsr->GetNext() == pAktCrsr ) + { + pAktCrsr->DeleteMark(); + break; // es gibt nichts mehr zu loeschen! + } + pAktCrsr = (SwCursor*)pDel->GetPrev(); + } + delete pDel; +*/ + + if( pDel == pAktCrsr ) + pAktCrsr->DeleteMark(); + else + delete pDel; + } + } while ( pAktCrsr != pCur ); + + for( nPos = 0; nPos < aTmp.Count(); ++nPos ) + { + pSttNd = aTmp[ nPos ]->GetSttNd(); + + SwNodeIndex aIdx( *pSttNd, 1 ); + if( &aIdx.GetNodes() != &rNds ) + break; + const SwNode* pNd = &aIdx.GetNode(); + if( !pNd->IsCntntNode() ) + pNd = rNds.GoNextSection( &aIdx, TRUE, FALSE ); + + SwPaM* pNew; + if( pAktCrsr->GetNext() == pAktCrsr && !pAktCrsr->HasMark() ) + { + pNew = pAktCrsr; + pNew->GetPoint()->nNode = *pNd; + pNew->GetPoint()->nContent.Assign( (SwCntntNode*)pNd, 0 ); + } + else + { + pNew = pAktCrsr->Create( pAktCrsr ); + pNew->GetPoint()->nNode = *pNd; + pNew->GetPoint()->nContent.Assign( (SwCntntNode*)pNd, 0 ); + } + pNew->SetMark(); + + SwPosition* pPos = pNew->GetPoint(); + pPos->nNode.Assign( *pSttNd->EndOfSectionNode(), - 1 ); + if( !( pNd = &pPos->nNode.GetNode())->IsCntntNode() ) + pNd = rNds.GoPrevSection( &pPos->nNode, TRUE, FALSE ); + + pPos->nContent.Assign( (SwCntntNode*)pNd, ((SwCntntNode*)pNd)->Len() ); + } + } + return pAktCrsr; +} + + +void SwTableCursor::InsertBox( const SwTableBox& rTblBox ) +{ + SwTableBox* pBox = (SwTableBox*)&rTblBox; + aSelBoxes.Insert( pBox ); + bChg = TRUE; +} + +bool SwTableCursor::NewTableSelection() +{ + bool bRet = false; + const SwNode *pStart = GetCntntNode()->FindTableBoxStartNode(); + const SwNode *pEnd = GetCntntNode(FALSE)->FindTableBoxStartNode(); + if( pStart && pEnd ) + { + const SwTableNode *pTableNode = pStart->FindTableNode(); + if( pTableNode == pEnd->FindTableNode() && + pTableNode->GetTable().IsNewModel() ) + { + bRet = true; + SwSelBoxes aNew; + aNew.Insert( &aSelBoxes ); + pTableNode->GetTable().CreateSelection( pStart, pEnd, aNew, + SwTable::SEARCH_NONE, false ); + ActualizeSelection( aNew ); + } + } + return bRet; +} + +void SwTableCursor::ActualizeSelection( const SwSelBoxes &rNew ) +{ + USHORT nOld = 0, nNew = 0; + while ( nOld < aSelBoxes.Count() && nNew < rNew.Count() ) + { + const SwTableBox* pPOld = *( aSelBoxes.GetData() + nOld ); + const SwTableBox* pPNew = *( rNew.GetData() + nNew ); + if( pPOld == pPNew ) + { // this box will stay + ++nOld; + ++nNew; + } + else if( pPOld->GetSttIdx() < pPNew->GetSttIdx() ) + DeleteBox( nOld ); // this box has to go + else + { + InsertBox( *pPNew ); // this is a new one + ++nOld; + ++nNew; + } + } + + while( nOld < aSelBoxes.Count() ) + DeleteBox( nOld ); // some more to delete + + for( ; nNew < rNew.Count(); ++nNew ) // some more to insert + InsertBox( **( rNew.GetData() + nNew ) ); +} + +BOOL SwTableCursor::IsCrsrMovedUpdt() +{ + if( !IsCrsrMoved() ) + return FALSE; + + nTblMkNd = GetMark()->nNode.GetIndex(); + nTblPtNd = GetPoint()->nNode.GetIndex(); + nTblMkCnt = GetMark()->nContent.GetIndex(); + nTblPtCnt = GetPoint()->nContent.GetIndex(); + return TRUE; +} + + +// Parke den Tabellen-Cursor auf dem StartNode der Boxen. +void SwTableCursor::ParkCrsr() +{ + // Index aus dem TextNode abmelden + SwNode* pNd = &GetPoint()->nNode.GetNode(); + if( !pNd->IsStartNode() ) + pNd = pNd->StartOfSectionNode(); + GetPoint()->nNode = *pNd; + GetPoint()->nContent.Assign( 0, 0 ); + + pNd = &GetMark()->nNode.GetNode(); + if( !pNd->IsStartNode() ) + pNd = pNd->StartOfSectionNode(); + GetMark()->nNode = *pNd; + GetMark()->nContent.Assign( 0, 0 ); + + bChg = TRUE; + bParked = TRUE; +} + + +BOOL SwTableCursor::HasReadOnlyBoxSel() const +{ + BOOL bRet = FALSE; + for( USHORT n = aSelBoxes.Count(); n; ) + if( aSelBoxes[ --n ]->GetFrmFmt()->GetProtect().IsCntntProtected() ) + { + bRet = TRUE; + break; + } + return bRet; +} + + diff --git a/sw/source/core/crsr/trvlcol.cxx b/sw/source/core/crsr/trvlcol.cxx new file mode 100644 index 000000000000..076af3be386c --- /dev/null +++ b/sw/source/core/crsr/trvlcol.cxx @@ -0,0 +1,133 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + + +#include <crsrsh.hxx> +#include <doc.hxx> +#include <layfrm.hxx> +#include <cntfrm.hxx> +#include <swcrsr.hxx> +#include <viscrs.hxx> +#include <callnk.hxx> + + + +SwLayoutFrm* GetCurrColumn( const SwLayoutFrm* pLayFrm ) +{ + while( pLayFrm && !pLayFrm->IsColumnFrm() ) + pLayFrm = pLayFrm->GetUpper(); + return (SwLayoutFrm*)pLayFrm; +} + + +SwLayoutFrm* GetNextColumn( const SwLayoutFrm* pLayFrm ) +{ + SwLayoutFrm* pActCol = GetCurrColumn( pLayFrm ); + return pActCol ? (SwLayoutFrm*)pActCol->GetNext() : 0; +} + + +SwLayoutFrm* GetPrevColumn( const SwLayoutFrm* pLayFrm ) +{ + SwLayoutFrm* pActCol = GetCurrColumn( pLayFrm ); + return pActCol ? (SwLayoutFrm*)pActCol->GetPrev() : 0; +} + + +SwCntntFrm* GetColumnStt( const SwLayoutFrm* pColFrm ) +{ + return pColFrm ? (SwCntntFrm*)pColFrm->ContainsCntnt() : 0; +} + + +SwCntntFrm* GetColumnEnd( const SwLayoutFrm* pColFrm ) +{ + SwCntntFrm *pRet = GetColumnStt( pColFrm ); + if( !pRet ) + return 0; + + SwCntntFrm *pNxt = pRet->GetNextCntntFrm(); + while( pNxt && pColFrm->IsAnLower( pNxt ) ) + { + pRet = pNxt; + pNxt = pNxt->GetNextCntntFrm(); + } + return pRet; +} + + +SwWhichColumn fnColumnPrev = &GetPrevColumn; +SwWhichColumn fnColumnCurr = &GetCurrColumn; +SwWhichColumn fnColumnNext = &GetNextColumn; +SwPosColumn fnColumnStart = &GetColumnStt; +SwPosColumn fnColumnEnd = &GetColumnEnd; + + +BOOL SwCrsrShell::MoveColumn( SwWhichColumn fnWhichCol, SwPosColumn fnPosCol ) +{ + BOOL bRet = FALSE; + if( !pTblCrsr ) + { + SwLayoutFrm* pLayFrm = GetCurrFrm()->GetUpper(); + if( pLayFrm && 0 != ( pLayFrm = (*fnWhichCol)( pLayFrm )) ) + { + SwCntntFrm* pCnt = (*fnPosCol)( pLayFrm ); + if( pCnt ) + { + SET_CURR_SHELL( this ); + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + SwCrsrSaveState aSaveState( *pCurCrsr ); + + pCnt->Calc(); // ??? + + Point aPt( pCnt->Frm().Pos() + pCnt->Prt().Pos() ); + if( fnPosCol == GetColumnEnd ) + { + aPt.X() += pCnt->Prt().Width(); + aPt.Y() += pCnt->Prt().Height(); + } + + pCnt->GetCrsrOfst( pCurCrsr->GetPoint(), aPt ); + + if( !pCurCrsr->IsInProtectTable( TRUE ) && + !pCurCrsr->IsSelOvr() ) + { + UpdateCrsr(); + bRet = TRUE; + } + } + } + } + return bRet; +} + + + diff --git a/sw/source/core/crsr/trvlfnfl.cxx b/sw/source/core/crsr/trvlfnfl.cxx new file mode 100644 index 000000000000..3edf3718eabe --- /dev/null +++ b/sw/source/core/crsr/trvlfnfl.cxx @@ -0,0 +1,359 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <svx/svdmodel.hxx> +#include <svx/svdpage.hxx> +#include <crsrsh.hxx> +#include <doc.hxx> +#include <pagefrm.hxx> +#include <cntfrm.hxx> +#include <ftnfrm.hxx> +#include <viewimp.hxx> +#include <swcrsr.hxx> +#include <dflyobj.hxx> +#include <ndtxt.hxx> +#include <flyfrm.hxx> +#include <txtfrm.hxx> +#include <txtftn.hxx> +#include <ftnidx.hxx> +#include <viscrs.hxx> +#include <callnk.hxx> + +BOOL SwCrsrShell::CallCrsrFN( FNCrsr fnCrsr ) +{ + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, + SwCursor* pCrsr = getShellCrsr( true ); + BOOL bRet = (pCrsr->*fnCrsr)(); + if( bRet ) + UpdateCrsr( SwCrsrShell::SCROLLWIN | SwCrsrShell::CHKRANGE | + SwCrsrShell::READONLY ); + return bRet; +} + +BOOL SwCursor::GotoFtnTxt() +{ + // springe aus dem Content zur Fussnote + BOOL bRet = FALSE; + SwTxtNode* pTxtNd = GetPoint()->nNode.GetNode().GetTxtNode(); + + SwTxtAttr *const pFtn( (pTxtNd) + ? pTxtNd->GetTxtAttrForCharAt( + GetPoint()->nContent.GetIndex(), RES_TXTATR_FTN) + : 0); + if (pFtn) + { + SwCrsrSaveState aSaveState( *this ); + GetPoint()->nNode = *((SwTxtFtn*)pFtn)->GetStartNode(); + + SwCntntNode* pCNd = GetDoc()->GetNodes().GoNextSection( + &GetPoint()->nNode, + TRUE, !IsReadOnlyAvailable() ); + if( pCNd ) + { + GetPoint()->nContent.Assign( pCNd, 0 ); + bRet = !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_CHECKNODESSECTION | + nsSwCursorSelOverFlags::SELOVER_TOGGLE ); + } + } + return bRet; +} + +BOOL SwCrsrShell::GotoFtnTxt() +{ + BOOL bRet = CallCrsrFN( &SwCursor::GotoFtnTxt ); + if( !bRet ) + { + SwTxtNode* pTxtNd = _GetCrsr() ? + _GetCrsr()->GetPoint()->nNode.GetNode().GetTxtNode() : NULL; + if( pTxtNd ) + { + const SwFrm *pFrm = pTxtNd->GetFrm( &_GetCrsr()->GetSttPos(), + _GetCrsr()->Start() ); + const SwFtnBossFrm* pFtnBoss; + sal_Bool bSkip = pFrm && pFrm->IsInFtn(); + while( pFrm && 0 != ( pFtnBoss = pFrm->FindFtnBossFrm() ) ) + { + if( 0 != ( pFrm = pFtnBoss->FindFtnCont() ) ) + { + if( bSkip ) + bSkip = sal_False; + else + { + const SwCntntFrm* pCnt = static_cast<const SwLayoutFrm*> + (pFrm)->ContainsCntnt(); + if( pCnt ) + { + const SwCntntNode* pNode = pCnt->GetNode(); + _GetCrsr()->GetPoint()->nNode = *pNode; + _GetCrsr()->GetPoint()->nContent.Assign( + const_cast<SwCntntNode*>(pNode), + static_cast<const SwTxtFrm*>(pCnt)->GetOfst() ); + UpdateCrsr( SwCrsrShell::SCROLLWIN | + SwCrsrShell::CHKRANGE | SwCrsrShell::READONLY ); + bRet = sal_True; + break; + } + } + } + if( pFtnBoss->GetNext() && !pFtnBoss->IsPageFrm() ) + pFrm = pFtnBoss->GetNext(); + else + pFrm = pFtnBoss->GetUpper(); + } + } + } + return bRet; +} + + +BOOL SwCursor::GotoFtnAnchor() +{ + // springe aus der Fussnote zum Anker + const SwNode* pSttNd = GetNode()->FindFootnoteStartNode(); + if( pSttNd ) + { + // durchsuche alle Fussnoten im Dokument nach diesem StartIndex + const SwTxtFtn* pTxtFtn; + const SwFtnIdxs& rFtnArr = pSttNd->GetDoc()->GetFtnIdxs(); + for( USHORT n = 0; n < rFtnArr.Count(); ++n ) + if( 0 != ( pTxtFtn = rFtnArr[ n ])->GetStartNode() && + pSttNd == &pTxtFtn->GetStartNode()->GetNode() ) + { + SwCrsrSaveState aSaveState( *this ); + + SwTxtNode& rTNd = (SwTxtNode&)pTxtFtn->GetTxtNode(); + + GetPoint()->nNode = rTNd; + GetPoint()->nContent.Assign( &rTNd, *pTxtFtn->GetStart() ); + + return !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_CHECKNODESSECTION | + nsSwCursorSelOverFlags::SELOVER_TOGGLE ); + } + } + return FALSE; +} + +BOOL SwCrsrShell::GotoFtnAnchor() +{ + // springe aus der Fussnote zum Anker + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, + BOOL bRet = pCurCrsr->GotoFtnAnchor(); + if( bRet ) + { + // BUG 5996: Tabellen-Kopfzeile sonderbehandeln + pCurCrsr->GetPtPos() = Point(); + UpdateCrsr( SwCrsrShell::SCROLLWIN | SwCrsrShell::CHKRANGE | + SwCrsrShell::READONLY ); + } + return bRet; +} + +inline sal_Bool CmpLE( const SwTxtFtn& rFtn, ULONG nNd, xub_StrLen nCnt ) +{ + ULONG nTNd = rFtn.GetTxtNode().GetIndex(); + return nTNd < nNd || ( nTNd == nNd && *rFtn.GetStart() <= nCnt ); +} +inline sal_Bool CmpL( const SwTxtFtn& rFtn, ULONG nNd, xub_StrLen nCnt ) +{ + ULONG nTNd = rFtn.GetTxtNode().GetIndex(); + return nTNd < nNd || ( nTNd == nNd && *rFtn.GetStart() < nCnt ); +} + +BOOL SwCursor::GotoNextFtnAnchor() +{ + const SwFtnIdxs& rFtnArr = GetDoc()->GetFtnIdxs(); + const SwTxtFtn* pTxtFtn = 0; + USHORT nPos; + + if( rFtnArr.SeekEntry( GetPoint()->nNode, &nPos )) + { + // es gibt eine Fussnote mit dem Index, suche also die + // naechstgelegene + if( nPos < rFtnArr.Count() ) + { + ULONG nNdPos = GetPoint()->nNode.GetIndex(); + xub_StrLen nCntPos = GetPoint()->nContent.GetIndex(); + + pTxtFtn = rFtnArr[ nPos ]; + // suche vorewaerts zur naechsten + if( CmpLE( *pTxtFtn, nNdPos, nCntPos ) ) + { + pTxtFtn = 0; + for( ++nPos; nPos < rFtnArr.Count(); ++nPos ) + { + pTxtFtn = rFtnArr[ nPos ]; + if( !CmpLE( *pTxtFtn, nNdPos, nCntPos ) ) + break; // gefunden + pTxtFtn = 0; + } + } + else if( nPos ) + { + // suche rueckwaerts zur vorherigen + pTxtFtn = 0; + while( nPos ) + { + pTxtFtn = rFtnArr[ --nPos ]; + if( CmpLE( *pTxtFtn, nNdPos, nCntPos ) ) + { + pTxtFtn = rFtnArr[ ++nPos ]; + break; // gefunden + } +// pTxtFtn = 0; + } + } + } + } + else if( nPos < rFtnArr.Count() ) + pTxtFtn = rFtnArr[ nPos ]; + + BOOL bRet = 0 != pTxtFtn; + if( bRet ) + { + SwCrsrSaveState aSaveState( *this ); + + SwTxtNode& rTNd = (SwTxtNode&)pTxtFtn->GetTxtNode(); + GetPoint()->nNode = rTNd; + GetPoint()->nContent.Assign( &rTNd, *pTxtFtn->GetStart() ); + bRet = !IsSelOvr(); + } + return bRet; +} + +BOOL SwCursor::GotoPrevFtnAnchor() +{ + const SwFtnIdxs& rFtnArr = GetDoc()->GetFtnIdxs(); + const SwTxtFtn* pTxtFtn = 0; + USHORT nPos; + + if( rFtnArr.SeekEntry( GetPoint()->nNode, &nPos ) ) + { + // es gibt eine Fussnote mit dem Index, suche also die + // naechstgelegene + ULONG nNdPos = GetPoint()->nNode.GetIndex(); + xub_StrLen nCntPos = GetPoint()->nContent.GetIndex(); + + pTxtFtn = rFtnArr[ nPos ]; + // suche vorwaerts zur naechsten + if( CmpL( *pTxtFtn, nNdPos, nCntPos )) + { + for( ++nPos; nPos < rFtnArr.Count(); ++nPos ) + { + pTxtFtn = rFtnArr[ nPos ]; + if( !CmpL( *pTxtFtn, nNdPos, nCntPos ) ) + { + pTxtFtn = rFtnArr[ nPos-1 ]; + break; + } + } + } + else if( nPos ) + { + // suche rueckwaerts zur vorherigen + pTxtFtn = 0; + while( nPos ) + { + pTxtFtn = rFtnArr[ --nPos ]; + if( CmpL( *pTxtFtn, nNdPos, nCntPos )) + break; // gefunden + pTxtFtn = 0; + } + } + else + pTxtFtn = 0; + } + else if( nPos ) + pTxtFtn = rFtnArr[ nPos-1 ]; + + BOOL bRet = 0 != pTxtFtn; + if( bRet ) + { + SwCrsrSaveState aSaveState( *this ); + + SwTxtNode& rTNd = (SwTxtNode&)pTxtFtn->GetTxtNode(); + GetPoint()->nNode = rTNd; + GetPoint()->nContent.Assign( &rTNd, *pTxtFtn->GetStart() ); + bRet = !IsSelOvr(); + } + return bRet; +} + +BOOL SwCrsrShell::GotoNextFtnAnchor() +{ + return CallCrsrFN( &SwCursor::GotoNextFtnAnchor ); +} + +BOOL SwCrsrShell::GotoPrevFtnAnchor() +{ + return CallCrsrFN( &SwCursor::GotoPrevFtnAnchor ); +} + +// springe aus dem Rahmen zum Anker + + +BOOL SwCrsrShell::GotoFlyAnchor() +{ + SET_CURR_SHELL( this ); + const SwFrm* pFrm = GetCurrFrm(); + do { + pFrm = pFrm->GetUpper(); + } while( pFrm && !pFrm->IsFlyFrm() ); + + if( !pFrm ) // ist kein FlyFrame + return FALSE; + + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, + SwCrsrSaveState aSaveState( *pCurCrsr ); + + // springe in den BodyFrame, der am naechsten vom Fly liegt + SwRect aTmpRect( aCharRect ); + if( !pFrm->Frm().IsInside( aTmpRect )) + aTmpRect = pFrm->Frm(); + Point aPt( aTmpRect.Left(), aTmpRect.Top() + + ( aTmpRect.Bottom() - aTmpRect.Top() ) / 2 ); + aPt.X() = aPt.X() > (pFrm->Frm().Left() + (pFrm->Frm().SSize().Width() / 2 )) + ? pFrm->Frm().Right() + : pFrm->Frm().Left(); + + const SwPageFrm* pPageFrm = pFrm->FindPageFrm(); + const SwCntntFrm* pFndFrm = pPageFrm->GetCntntPos( aPt, FALSE, TRUE ); + pFndFrm->GetCrsrOfst( pCurCrsr->GetPoint(), aPt ); + + BOOL bRet = !pCurCrsr->IsInProtectTable() && !pCurCrsr->IsSelOvr(); + if( bRet ) + UpdateCrsr( SwCrsrShell::SCROLLWIN | SwCrsrShell::CHKRANGE | + SwCrsrShell::READONLY ); + return bRet; +} + + + + diff --git a/sw/source/core/crsr/trvlreg.cxx b/sw/source/core/crsr/trvlreg.cxx new file mode 100644 index 000000000000..bf6343e77bc0 --- /dev/null +++ b/sw/source/core/crsr/trvlreg.cxx @@ -0,0 +1,291 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <crsrsh.hxx> +#include <doc.hxx> +#include <swcrsr.hxx> +#include <docary.hxx> +#include <fmtcntnt.hxx> +#include <viscrs.hxx> +#include <callnk.hxx> +#include <pamtyp.hxx> +#include <section.hxx> + + + +BOOL GotoPrevRegion( SwPaM& rCurCrsr, SwPosRegion fnPosRegion, + BOOL bInReadOnly ) +{ + SwNodeIndex aIdx( rCurCrsr.GetPoint()->nNode ); + SwSectionNode* pNd = aIdx.GetNode().FindSectionNode(); + if( pNd ) + aIdx.Assign( *pNd, - 1 ); + + do { + while( aIdx.GetIndex() && + 0 == ( pNd = aIdx.GetNode().StartOfSectionNode()->GetSectionNode()) ) + aIdx--; + + if( pNd ) // gibt einen weiteren SectionNode ? + { + if( pNd->GetSection().IsHiddenFlag() || + ( !bInReadOnly && + pNd->GetSection().IsProtectFlag() )) + { + // geschuetzte/versteckte ueberspringen wir + aIdx.Assign( *pNd, - 1 ); + } + else if( fnPosRegion == fnMoveForward ) + { + aIdx = *pNd; + SwCntntNode* pCNd = pNd->GetNodes().GoNextSection( &aIdx, + TRUE, !bInReadOnly ); + if( !pCNd ) + { + aIdx--; + continue; + } + rCurCrsr.GetPoint()->nContent.Assign( pCNd, 0 ); + } + else + { + aIdx = *pNd->EndOfSectionNode(); + SwCntntNode* pCNd = pNd->GetNodes().GoPrevSection( &aIdx, + TRUE, !bInReadOnly ); + if( !pCNd ) + { + aIdx.Assign( *pNd, - 1 ); + continue; + } + rCurCrsr.GetPoint()->nContent.Assign( pCNd, pCNd->Len() ); + } + + rCurCrsr.GetPoint()->nNode = aIdx; + return TRUE; + } + } while( pNd ); + return FALSE; +} + + +BOOL GotoNextRegion( SwPaM& rCurCrsr, SwPosRegion fnPosRegion, + BOOL bInReadOnly ) +{ + SwNodeIndex aIdx( rCurCrsr.GetPoint()->nNode ); + SwSectionNode* pNd = aIdx.GetNode().FindSectionNode(); + if( pNd ) + aIdx.Assign( *pNd->EndOfSectionNode(), - 1 ); + + ULONG nEndCount = aIdx.GetNode().GetNodes().Count()-1; + do { + while( aIdx.GetIndex() < nEndCount && + 0 == ( pNd = aIdx.GetNode().GetSectionNode()) ) + aIdx++; + + if( pNd ) // gibt einen weiteren SectionNode ? + { + if( pNd->GetSection().IsHiddenFlag() || + ( !bInReadOnly && + pNd->GetSection().IsProtectFlag() )) + { + // geschuetzte/versteckte ueberspringen wir + aIdx.Assign( *pNd->EndOfSectionNode(), +1 ); + } + else if( fnPosRegion == fnMoveForward ) + { + aIdx = *pNd; + SwCntntNode* pCNd = pNd->GetNodes().GoNextSection( &aIdx, + TRUE, !bInReadOnly ); + if( !pCNd ) + { + aIdx.Assign( *pNd->EndOfSectionNode(), +1 ); + continue; + } + rCurCrsr.GetPoint()->nContent.Assign( pCNd, 0 ); + } + else + { + aIdx = *pNd->EndOfSectionNode(); + SwCntntNode* pCNd = pNd->GetNodes().GoPrevSection( &aIdx, + TRUE, !bInReadOnly ); + if( !pCNd ) + { + aIdx++; + continue; + } + rCurCrsr.GetPoint()->nContent.Assign( pCNd, pCNd->Len() ); + } + + rCurCrsr.GetPoint()->nNode = aIdx; + return TRUE; + } + } while( pNd ); + return FALSE; +} + + +BOOL GotoCurrRegion( SwPaM& rCurCrsr, SwPosRegion fnPosRegion, + BOOL bInReadOnly ) +{ + SwSectionNode* pNd = rCurCrsr.GetNode()->FindSectionNode(); + if( !pNd ) + return FALSE; + + SwPosition* pPos = rCurCrsr.GetPoint(); + BOOL bMoveBackward = fnPosRegion == fnMoveBackward; + + SwCntntNode* pCNd; + if( bMoveBackward ) + { + SwNodeIndex aIdx( *pNd->EndOfSectionNode() ); + pCNd = pNd->GetNodes().GoPrevSection( &aIdx, TRUE, !bInReadOnly ); + } + else + { + SwNodeIndex aIdx( *pNd ); + pCNd = pNd->GetNodes().GoNextSection( &aIdx, TRUE, !bInReadOnly ); + } + + if( pCNd ) + { + pPos->nNode = *pCNd; + xub_StrLen nTmpPos = bMoveBackward ? pCNd->Len() : 0; + pPos->nContent.Assign( pCNd, nTmpPos ); + } + return 0 != pCNd; +} + + +BOOL GotoCurrRegionAndSkip( SwPaM& rCurCrsr, SwPosRegion fnPosRegion, + BOOL bInReadOnly ) +{ + SwNode* pCurrNd = rCurCrsr.GetNode(); + SwSectionNode* pNd = pCurrNd->FindSectionNode(); + if( !pNd ) + return FALSE; + + SwPosition* pPos = rCurCrsr.GetPoint(); + xub_StrLen nCurrCnt = pPos->nContent.GetIndex(); + BOOL bMoveBackward = fnPosRegion == fnMoveBackward; + + do { + SwCntntNode* pCNd; + if( bMoveBackward ) // ans Ende vom Bereich + { + SwNodeIndex aIdx( *pNd->EndOfSectionNode() ); + pCNd = pNd->GetNodes().GoPrevSection( &aIdx, TRUE, !bInReadOnly ); + if( !pCNd ) + return FALSE; + pPos->nNode = aIdx; + } + else + { + SwNodeIndex aIdx( *pNd ); + pCNd = pNd->GetNodes().GoNextSection( &aIdx, TRUE, !bInReadOnly ); + if( !pCNd ) + return FALSE; + pPos->nNode = aIdx; + } + + xub_StrLen nTmpPos = bMoveBackward ? pCNd->Len() : 0; + pPos->nContent.Assign( pCNd, nTmpPos ); + + if( &pPos->nNode.GetNode() != pCurrNd || + pPos->nContent.GetIndex() != nCurrCnt ) + // es gab eine Veraenderung + return TRUE; + + // dann versuche mal den "Parent" dieser Section + SwSection* pParent = pNd->GetSection().GetParent(); + pNd = pParent ? pParent->GetFmt()->GetSectionNode() : 0; + } while( pNd ); + return FALSE; +} + + + +BOOL SwCursor::MoveRegion( SwWhichRegion fnWhichRegion, SwPosRegion fnPosRegion ) +{ + SwCrsrSaveState aSaveState( *this ); + return !dynamic_cast<SwTableCursor*>(this) && + (*fnWhichRegion)( *this, fnPosRegion, IsReadOnlyAvailable() ) && + !IsSelOvr() && + ( GetPoint()->nNode.GetIndex() != pSavePos->nNode || + GetPoint()->nContent.GetIndex() != pSavePos->nCntnt ); +} + +BOOL SwCrsrShell::MoveRegion( SwWhichRegion fnWhichRegion, SwPosRegion fnPosRegion ) +{ + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + BOOL bRet = !pTblCrsr && pCurCrsr->MoveRegion( fnWhichRegion, fnPosRegion ); + if( bRet ) + UpdateCrsr(); + return bRet; +} + + +BOOL SwCursor::GotoRegion( const String& rName ) +{ + BOOL bRet = FALSE; + const SwSectionFmts& rFmts = GetDoc()->GetSections(); + for( USHORT n = rFmts.Count(); n; ) + { + const SwSectionFmt* pFmt = rFmts[ --n ]; + const SwNodeIndex* pIdx; + const SwSection* pSect; + if( 0 != ( pSect = pFmt->GetSection() ) && + pSect->GetSectionName() == rName && + 0 != ( pIdx = pFmt->GetCntnt().GetCntntIdx() ) && + pIdx->GetNode().GetNodes().IsDocNodes() ) + { + // ein Bereich im normalen NodesArr + SwCrsrSaveState aSaveState( *this ); + + GetPoint()->nNode = *pIdx; + Move( fnMoveForward, fnGoCntnt ); + bRet = !IsSelOvr(); + } + } + return bRet; +} + +BOOL SwCrsrShell::GotoRegion( const String& rName ) +{ + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, + BOOL bRet = !pTblCrsr && pCurCrsr->GotoRegion( rName ); + if( bRet ) + UpdateCrsr( SwCrsrShell::SCROLLWIN | SwCrsrShell::CHKRANGE | + SwCrsrShell::READONLY ); // und den akt. Updaten + return bRet; +} + + + diff --git a/sw/source/core/crsr/trvltbl.cxx b/sw/source/core/crsr/trvltbl.cxx new file mode 100644 index 000000000000..d9a887e61ad9 --- /dev/null +++ b/sw/source/core/crsr/trvltbl.cxx @@ -0,0 +1,931 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" +#include <hintids.hxx> + +#include <vcl/svapp.hxx> +#include <editeng/protitem.hxx> +#include <crsrsh.hxx> +#include <doc.hxx> +#include <cntfrm.hxx> +#include <editsh.hxx> //EndAllAction gibts nur an der EditShell +#include <pam.hxx> +#include <swtable.hxx> +#include <docary.hxx> +#include <frmatr.hxx> +#include <frmfmt.hxx> +#include <viscrs.hxx> +#include <callnk.hxx> +#include <tabfrm.hxx> +#include <ndtxt.hxx> +#include <shellres.hxx> +#include <cellatr.hxx> +#include <cellfrm.hxx> +#include <rowfrm.hxx> + + +// setze Crsr in die naechsten/vorherigen Celle +BOOL SwCrsrShell::GoNextCell( BOOL bAppendLine ) +{ + BOOL bRet = FALSE; + const SwTableNode* pTblNd = 0; + + if( IsTableMode() || 0 != ( pTblNd = IsCrsrInTbl() )) + { + SwCursor* pCrsr = pTblCrsr ? pTblCrsr : pCurCrsr; + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, + bRet = TRUE; + + // Check if we have to move the cursor to a covered cell before + // proceeding: + const SwNode* pTableBoxStartNode = pCrsr->GetNode()->FindTableBoxStartNode(); + const SwTableBox* pTableBox = 0; + + if ( pCrsr->GetCrsrRowSpanOffset() ) + { + pTableBox = pTableBoxStartNode->GetTblBox(); + if ( pTableBox->getRowSpan() > 1 ) + { + if ( !pTblNd ) + pTblNd = IsCrsrInTbl(); + pTableBox = & pTableBox->FindEndOfRowSpan( pTblNd->GetTable(), + (USHORT)(pTableBox->getRowSpan() + pCrsr->GetCrsrRowSpanOffset() ) ); + pTableBoxStartNode = pTableBox->GetSttNd(); + } + } + + SwNodeIndex aCellStt( *pTableBoxStartNode->EndOfSectionNode(), 1 ); + + // folgt nach dem EndNode der Cell ein weiterer StartNode, dann + // gibt es auch eine naechste Celle + + if( !aCellStt.GetNode().IsStartNode() ) + { + if( pCrsr->HasMark() || !bAppendLine ) + bRet = FALSE; + else + { + // auf besonderen Wunsch: keine Line mehr vorhanden, dann + // mache doch eine neue: + if ( !pTableBox ) + pTableBox = pTblNd->GetTable().GetTblBox( + pCrsr->GetPoint()->nNode.GetNode(). + StartOfSectionIndex() ); + + ASSERT( pTableBox, "Box steht nicht in dieser Tabelle" ); + SwSelBoxes aBoxes; + + //Das Dokument veraendert sich evtl. ohne Action wuerden die Sichten + //nichts mitbekommen. + ((SwEditShell*)this)->StartAllAction(); + bRet = pDoc->InsertRow( pTblNd->GetTable(). + SelLineFromBox( pTableBox, aBoxes, FALSE )); + ((SwEditShell*)this)->EndAllAction(); + } + } + if( bRet && 0 != ( bRet = pCrsr->GoNextCell() )) + UpdateCrsr(); // und den akt. Updaten + } + return bRet; +} + + +BOOL SwCrsrShell::GoPrevCell() +{ + BOOL bRet = FALSE; + const SwTableNode* pTblNd; + if( IsTableMode() || 0 != ( pTblNd = IsCrsrInTbl() )) + { + SwCursor* pCrsr = pTblCrsr ? pTblCrsr : pCurCrsr; + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, + bRet = pCrsr->GoPrevCell(); + if( bRet ) + UpdateCrsr(); // und den akt. Updaten + } + return bRet; +} + +const SwFrm* lcl_FindMostUpperCellFrm( const SwFrm* pFrm ) +{ + while ( pFrm && + ( !pFrm->IsCellFrm() || + !pFrm->GetUpper()->GetUpper()->IsTabFrm() || + pFrm->GetUpper()->GetUpper()->GetUpper()->IsInTab() ) ) + { + pFrm = pFrm->GetUpper(); + } + return pFrm; +} + +BOOL SwCrsrShell::_SelTblRowOrCol( bool bRow, bool bRowSimple ) +{ + // pruefe ob vom aktuellen Crsr der SPoint/Mark in einer Tabelle stehen + SwFrm *pFrm = GetCurrFrm(); + if( !pFrm->IsInTab() ) + return FALSE; + + const SwTabFrm* pTabFrm = pFrm->FindTabFrm(); + const SwTabFrm* pMasterTabFrm = pTabFrm->IsFollow() ? pTabFrm->FindMaster( true ) : pTabFrm; + const SwTable* pTable = pTabFrm->GetTable(); + + SET_CURR_SHELL( this ); + + const SwTableBox* pStt = 0; + const SwTableBox* pEnd = 0; + + // lasse ueber das Layout die Boxen suchen + SwSelBoxes aBoxes; + SwTblSearchType eType = bRow ? nsSwTblSearchType::TBLSEARCH_ROW : nsSwTblSearchType::TBLSEARCH_COL; + const bool bCheckProtected = !IsReadOnlyAvailable(); + + if( bCheckProtected ) + eType = (SwTblSearchType)(eType | nsSwTblSearchType::TBLSEARCH_PROTECT); + + if ( !bRowSimple ) + { + GetTblSel( *this, aBoxes, eType ); + + if( !aBoxes.Count() ) + return FALSE; + + pStt = aBoxes[0]; + pEnd = aBoxes[aBoxes.Count() - 1]; + } + // --> FME 2004-07-30 #i32329# Enhanced table selection + else if ( pTable->IsNewModel() ) + { + const SwShellCrsr *pCrsr = _GetCrsr(); + SwTable::SearchType eSearchType = bRow ? SwTable::SEARCH_ROW : SwTable::SEARCH_COL; + pTable->CreateSelection( *pCrsr, aBoxes, eSearchType, bCheckProtected ); + if( !aBoxes.Count() ) + return FALSE; + + pStt = aBoxes[0]; + pEnd = aBoxes[aBoxes.Count() - 1]; + } + else + { + const SwShellCrsr *pCrsr = _GetCrsr(); + const SwFrm* pStartFrm = pFrm; + const SwCntntNode *pCNd = pCrsr->GetCntntNode( FALSE ); + const SwFrm* pEndFrm = pCNd ? pCNd->GetFrm( &pCrsr->GetMkPos() ) : 0; + + if ( bRow ) + { + pStartFrm = lcl_FindMostUpperCellFrm( pStartFrm ); + pEndFrm = lcl_FindMostUpperCellFrm( pEndFrm ); + } + + if ( !pStartFrm || !pEndFrm ) + return FALSE; + + const bool bVert = pFrm->ImplFindTabFrm()->IsVertical(); + + // If we select upwards it is sufficient to set pStt and pEnd + // to the first resp. last box of the selection obtained from + // GetTblSel. However, selecting downwards requires the frames + // located at the corners of the selection. This does not work + // for column selections in vertical tables: + const bool bSelectUp = ( bVert && !bRow ) || + *pCrsr->GetPoint() <= *pCrsr->GetMark(); + SwCellFrms aCells; + GetTblSel( static_cast<const SwCellFrm*>(pStartFrm), + static_cast<const SwCellFrm*>(pEndFrm), + aBoxes, bSelectUp ? 0 : &aCells, eType ); + + if( !aBoxes.Count() || ( !bSelectUp && 4 != aCells.Count() ) ) + return FALSE; + + if ( bSelectUp ) + { + pStt = aBoxes[0]; + pEnd = aBoxes[aBoxes.Count() - 1]; + } + else + { + pStt = aCells[ bVert ? (bRow ? 0 : 3) : (bRow ? 2 : 1) ]->GetTabBox(); // will become point of table cursor + pEnd = aCells[ bVert ? (bRow ? 3 : 0) : (bRow ? 1 : 2) ]->GetTabBox(); // will become mark of table cursor + } + } + // <-- + + // noch kein Tabellen-Cursor vorhanden, dann erzeuge einen + if( !pTblCrsr ) + { + pTblCrsr = new SwShellTableCrsr( *this, *pCurCrsr->GetPoint() ); + pCurCrsr->DeleteMark(); + pCurCrsr->SwSelPaintRects::Hide(); + } + + pTblCrsr->DeleteMark(); + + // dann setze mal Anfang und Ende der Spalte + pTblCrsr->GetPoint()->nNode = *pEnd->GetSttNd(); + pTblCrsr->Move( fnMoveForward, fnGoCntnt ); + pTblCrsr->SetMark(); + pTblCrsr->GetPoint()->nNode = *pStt->GetSttNd()->EndOfSectionNode(); + pTblCrsr->Move( fnMoveBackward, fnGoCntnt ); + + // set PtPos 'close' to the reference table, otherwise we might get problems with the + // repeated headlines check in UpdateCrsr(): + if ( !bRow ) + pTblCrsr->GetPtPos() = pMasterTabFrm->IsVertical() ? pMasterTabFrm->Frm().TopRight() : pMasterTabFrm->Frm().TopLeft(); + + UpdateCrsr(); // und den akt. Updaten + return TRUE; +} + +BOOL SwCrsrShell::SelTbl() +{ + // pruefe ob vom aktuellen Crsr der SPoint/Mark in einer Tabelle stehen + SwFrm *pFrm = GetCurrFrm(); + if( !pFrm->IsInTab() ) + return FALSE; + + const SwTabFrm *pTblFrm = pFrm->ImplFindTabFrm(); + const SwTabFrm* pMasterTabFrm = pTblFrm->IsFollow() ? pTblFrm->FindMaster( true ) : pTblFrm; + const SwTableNode* pTblNd = pTblFrm->GetTable()->GetTableNode(); + + SET_CURR_SHELL( this ); + + if( !pTblCrsr ) + { + pTblCrsr = new SwShellTableCrsr( *this, *pCurCrsr->GetPoint() ); + pCurCrsr->DeleteMark(); + pCurCrsr->SwSelPaintRects::Hide(); + } + + pTblCrsr->DeleteMark(); + pTblCrsr->GetPoint()->nNode = *pTblNd; + pTblCrsr->Move( fnMoveForward, fnGoCntnt ); + pTblCrsr->SetMark(); + // set MkPos 'close' to the master table, otherwise we might get problems with the + // repeated headlines check in UpdateCrsr(): + pTblCrsr->GetMkPos() = pMasterTabFrm->IsVertical() ? pMasterTabFrm->Frm().TopRight() : pMasterTabFrm->Frm().TopLeft(); + pTblCrsr->GetPoint()->nNode = *pTblNd->EndOfSectionNode(); + pTblCrsr->Move( fnMoveBackward, fnGoCntnt ); + UpdateCrsr(); // und den akt. Updaten + return TRUE; +} + + +BOOL SwCrsrShell::SelTblBox() +{ + // if we're in a table, create a table cursor, and select the cell + // that the current cursor's point resides in + + // search for start node of our table box. If not found, exit realy + const SwStartNode* pStartNode = + pCurCrsr->GetPoint()->nNode.GetNode().FindTableBoxStartNode(); + +#ifdef DBG_UTIL + // the old code checks whether we're in a table by asking the + // frame. This should yield the same result as searching for the + // table box start node, right? + SwFrm *pFrm = GetCurrFrm(); + DBG_ASSERT( !pFrm->IsInTab() == !(pStartNode != NULL), + "Schroedinger's table: We're in a box, and also we aren't." ); +#endif + + if( pStartNode == NULL ) + return FALSE; + + + SET_CURR_SHELL( this ); + + // create a table cursor, if there isn't one already + if( !pTblCrsr ) + { + pTblCrsr = new SwShellTableCrsr( *this, *pCurCrsr->GetPoint() ); + pCurCrsr->DeleteMark(); + pCurCrsr->SwSelPaintRects::Hide(); + } + + // select the complete box with our shiny new pTblCrsr + // 1. delete mark, and move point to first content node in box + // 2. set mark, and move point to last content node in box + // 3. exchange + + pTblCrsr->DeleteMark(); + *(pTblCrsr->GetPoint()) = SwPosition( *pStartNode ); + pTblCrsr->Move( fnMoveForward, fnGoNode ); + + pTblCrsr->SetMark(); + *(pTblCrsr->GetPoint()) = SwPosition( *(pStartNode->EndOfSectionNode()) ); + pTblCrsr->Move( fnMoveBackward, fnGoNode ); + + pTblCrsr->Exchange(); + + // with some luck, UpdateCrsr() will now update everything that + // needs updateing + UpdateCrsr(); + + return TRUE; +} + +// return the next non-protected cell inside a table +// rIdx - is on a table node +// return: +// true - Idx points to content in a suitable cell +// false - could not find a suitable cell +bool lcl_FindNextCell( SwNodeIndex& rIdx, BOOL bInReadOnly ) +{ + // ueberpruefe geschuetzte Zellen + SwNodeIndex aTmp( rIdx, 2 ); // TableNode + StartNode + + // the resulting cell should be in that table: + const SwTableNode* pTblNd = rIdx.GetNode().GetTableNode(); + + if ( !pTblNd ) + { + ASSERT( false, "lcl_FindNextCell not celled with table start node!" ) + return false; + } + + const SwNode* pTableEndNode = pTblNd->EndOfSectionNode(); + + SwNodes& rNds = aTmp.GetNode().GetNodes(); + SwCntntNode* pCNd = aTmp.GetNode().GetCntntNode(); + + // no content node => go to next content node + if( !pCNd ) + pCNd = rNds.GoNext( &aTmp ); + + // robust + if ( !pCNd ) + return false; + + SwCntntFrm* pFrm = pCNd->GetFrm(); + + if ( 0 == pFrm || pCNd->FindTableNode() != pTblNd || + (!bInReadOnly && pFrm->IsProtected() ) ) + { + // we are not located inside a 'valid' cell. We have to continue searching... + + // skip behind current section. This might be the end of the table cell + // or behind a inner section or or or... + aTmp.Assign( *pCNd->EndOfSectionNode(), 1 ); + + // loop to find a suitable cell... + for( ;; ) + { + SwNode* pNd = &aTmp.GetNode(); + + // we break this loop if we reached the end of the table. + // to make this code even more robust, we also break if we are + // already behind the table end node: + if( pNd == pTableEndNode || /*robust: */ pNd->GetIndex() > pTableEndNode->GetIndex() ) + return false; + + // ok, get the next content node: + pCNd = aTmp.GetNode().GetCntntNode(); + if( 0 == pCNd ) + pCNd = rNds.GoNext( &aTmp ); + + // robust: + if ( !pCNd ) + return false; + + // check if we have found a suitable table cell: + pFrm = pCNd->GetFrm(); + + if ( 0 != pFrm && pCNd->FindTableNode() == pTblNd && + (bInReadOnly || !pFrm->IsProtected() ) ) + { + // finally, we have found a suitable table cell => set index and return + rIdx = *pCNd; + return true; + } + + // continue behind the current section: + aTmp.Assign( *pCNd->EndOfSectionNode(), +1 ); + } + } + + rIdx = *pCNd; + return true; +} + +// comments see lcl_FindNextCell +bool lcl_FindPrevCell( SwNodeIndex& rIdx, BOOL bInReadOnly ) +{ + SwNodeIndex aTmp( rIdx, -2 ); // TableNode + EndNode + + const SwNode* pTableEndNode = &rIdx.GetNode(); + const SwTableNode* pTblNd = pTableEndNode->StartOfSectionNode()->GetTableNode(); + + if ( !pTblNd ) + { + ASSERT( false, "lcl_FindPrevCell not celled with table start node!" ) + return false; + } + + SwNodes& rNds = aTmp.GetNode().GetNodes(); + SwCntntNode* pCNd = aTmp.GetNode().GetCntntNode(); + + if( !pCNd ) + pCNd = rNds.GoPrevious( &aTmp ); + + if ( !pCNd ) + return false; + + SwCntntFrm* pFrm = pCNd->GetFrm(); + + if( 0 == pFrm || pCNd->FindTableNode() != pTblNd || + (!bInReadOnly && pFrm->IsProtected() )) + { + // skip before current section + aTmp.Assign( *pCNd->StartOfSectionNode(), -1 ); + for( ;; ) + { + SwNode* pNd = &aTmp.GetNode(); + + if( pNd == pTblNd || pNd->GetIndex() < pTblNd->GetIndex() ) + return false; + + pCNd = aTmp.GetNode().GetCntntNode(); + if( 0 == pCNd ) + pCNd = rNds.GoPrevious( &aTmp ); + + if ( !pCNd ) + return false; + + pFrm = pCNd->GetFrm(); + + if( 0 != pFrm && pCNd->FindTableNode() == pTblNd && + (bInReadOnly || !pFrm->IsProtected() ) ) + { + rIdx = *pCNd; + return true; // Ok, nicht geschuetzt + } + aTmp.Assign( *pCNd->StartOfSectionNode(), - 1 ); + } + } + + rIdx = *pCNd; + return true; +} + + +BOOL GotoPrevTable( SwPaM& rCurCrsr, SwPosTable fnPosTbl, + BOOL bInReadOnly ) +{ + SwNodeIndex aIdx( rCurCrsr.GetPoint()->nNode ); + + SwTableNode* pTblNd = aIdx.GetNode().FindTableNode(); + if( pTblNd ) + { + // #i26532#: If we are inside a table, we may not go backward + // to the table start node, because we would miss any tables + // inside this table. + SwTableNode* pInnerTblNd = 0; + SwNodeIndex aTmpIdx( aIdx ); + while( aTmpIdx.GetIndex() && + 0 == ( pInnerTblNd = aTmpIdx.GetNode().StartOfSectionNode()->GetTableNode()) ) + aTmpIdx--; + + if( pInnerTblNd == pTblNd ) + aIdx.Assign( *pTblNd, - 1 ); + } + + do { + while( aIdx.GetIndex() && + 0 == ( pTblNd = aIdx.GetNode().StartOfSectionNode()->GetTableNode()) ) + aIdx--; + + if( pTblNd ) // gibt einen weiteren TableNode ? + { + if( fnPosTbl == fnMoveForward ) // an Anfang ? + { + aIdx = *aIdx.GetNode().StartOfSectionNode(); + if( !lcl_FindNextCell( aIdx, bInReadOnly )) + { + // Tabelle ueberspringen + aIdx.Assign( *pTblNd, -1 ); + continue; + } + } + else + { + // ueberpruefe geschuetzte Zellen + if( !lcl_FindNextCell( aIdx, bInReadOnly )) + { + // Tabelle ueberspringen + aIdx.Assign( *pTblNd, -1 ); + continue; + } + } + + SwTxtNode* pTxtNode = aIdx.GetNode().GetTxtNode(); + if ( pTxtNode ) + { + rCurCrsr.GetPoint()->nNode = *pTxtNode; + rCurCrsr.GetPoint()->nContent.Assign( pTxtNode, fnPosTbl == fnMoveBackward ? + pTxtNode->Len() : + 0 ); + } + return TRUE; + } + } while( pTblNd ); + + return FALSE; +} + + +BOOL GotoNextTable( SwPaM& rCurCrsr, SwPosTable fnPosTbl, + BOOL bInReadOnly ) +{ + SwNodeIndex aIdx( rCurCrsr.GetPoint()->nNode ); + SwTableNode* pTblNd = aIdx.GetNode().FindTableNode(); + + if( pTblNd ) + aIdx.Assign( *pTblNd->EndOfSectionNode(), 1 ); + + ULONG nLastNd = rCurCrsr.GetDoc()->GetNodes().Count() - 1; + do { + while( aIdx.GetIndex() < nLastNd && + 0 == ( pTblNd = aIdx.GetNode().GetTableNode()) ) + aIdx++; + if( pTblNd ) // gibt einen weiteren TableNode ? + { + if( fnPosTbl == fnMoveForward ) // an Anfang ? + { + if( !lcl_FindNextCell( aIdx, bInReadOnly )) + { + // Tabelle ueberspringen + aIdx.Assign( *pTblNd->EndOfSectionNode(), + 1 ); + continue; + } + } + else + { + aIdx = *aIdx.GetNode().EndOfSectionNode(); + // ueberpruefe geschuetzte Zellen + if( !lcl_FindNextCell( aIdx, bInReadOnly )) + { + // Tabelle ueberspringen + aIdx.Assign( *pTblNd->EndOfSectionNode(), + 1 ); + continue; + } + } + + SwTxtNode* pTxtNode = aIdx.GetNode().GetTxtNode(); + if ( pTxtNode ) + { + rCurCrsr.GetPoint()->nNode = *pTxtNode; + rCurCrsr.GetPoint()->nContent.Assign( pTxtNode, fnPosTbl == fnMoveBackward ? + pTxtNode->Len() : + 0 ); + } + return TRUE; + } + } while( pTblNd ); + + return FALSE; +} + + +BOOL GotoCurrTable( SwPaM& rCurCrsr, SwPosTable fnPosTbl, + BOOL bInReadOnly ) +{ + SwTableNode* pTblNd = rCurCrsr.GetPoint()->nNode.GetNode().FindTableNode(); + if( !pTblNd ) + return FALSE; + + SwTxtNode* pTxtNode = 0; + if( fnPosTbl == fnMoveBackward ) // ans Ende der Tabelle + { + SwNodeIndex aIdx( *pTblNd->EndOfSectionNode() ); + if( !lcl_FindPrevCell( aIdx, bInReadOnly )) + return FALSE; + pTxtNode = aIdx.GetNode().GetTxtNode(); + } + else + { + SwNodeIndex aIdx( *pTblNd ); + if( !lcl_FindNextCell( aIdx, bInReadOnly )) + return FALSE; + pTxtNode = aIdx.GetNode().GetTxtNode(); + } + + if ( pTxtNode ) + { + rCurCrsr.GetPoint()->nNode = *pTxtNode; + rCurCrsr.GetPoint()->nContent.Assign( pTxtNode, fnPosTbl == fnMoveBackward ? + pTxtNode->Len() : + 0 ); + } + + return TRUE; +} + + +BOOL SwCursor::MoveTable( SwWhichTable fnWhichTbl, SwPosTable fnPosTbl ) +{ + BOOL bRet = FALSE; + SwTableCursor* pTblCrsr = dynamic_cast<SwTableCursor*>(this); + + if( pTblCrsr || !HasMark() ) // nur wenn kein Mark oder ein TblCrsr + { + SwCrsrSaveState aSaveState( *this ); + bRet = (*fnWhichTbl)( *this, fnPosTbl, IsReadOnlyAvailable() ) && + !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_CHECKNODESSECTION | + nsSwCursorSelOverFlags::SELOVER_TOGGLE ); + } + return bRet; +} + +BOOL SwCrsrShell::MoveTable( SwWhichTable fnWhichTbl, SwPosTable fnPosTbl ) +{ + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen + + SwShellCrsr* pCrsr = pTblCrsr ? pTblCrsr : pCurCrsr; + BOOL bCheckPos, bRet; + ULONG nPtNd = 0; + xub_StrLen nPtCnt = 0; + + if( !pTblCrsr && pCurCrsr->HasMark() ) // wenn Mark und kein TblCrsr, + { + // dann auf jedenfall in den Tabellen-Modus schalten + pTblCrsr = new SwShellTableCrsr( *this, *pCurCrsr->GetPoint() ); + pCurCrsr->DeleteMark(); + pCurCrsr->SwSelPaintRects::Hide(); + pTblCrsr->SetMark(); + pCrsr = pTblCrsr; + bCheckPos = FALSE; + } + else + { + bCheckPos = TRUE; + nPtNd = pCrsr->GetPoint()->nNode.GetIndex(); + nPtCnt = pCrsr->GetPoint()->nContent.GetIndex(); + } + + bRet = pCrsr->MoveTable( fnWhichTbl, fnPosTbl ); + + if( bRet ) + { + //JP 28.10.97: Bug 45028 - die "oberste" Position setzen fuer + // wiederholte Kopfzeilen + pCrsr->GetPtPos() = Point(); + + UpdateCrsr(SwCrsrShell::SCROLLWIN|SwCrsrShell::CHKRANGE|SwCrsrShell::READONLY); + + if( bCheckPos && + pCrsr->GetPoint()->nNode.GetIndex() == nPtNd && + pCrsr->GetPoint()->nContent.GetIndex() == nPtCnt ) + bRet = FALSE; + } + return bRet; +} + + +BOOL SwCrsrShell::IsTblComplex() const +{ + SwFrm *pFrm = GetCurrFrm( FALSE ); + if ( pFrm && pFrm->IsInTab() ) + return pFrm->FindTabFrm()->GetTable()->IsTblComplex(); + return FALSE; +} + + +BOOL SwCrsrShell::IsTblComplexForChart() +{ + BOOL bRet = FALSE; + + StartAction(); // IsTblComplexForChart() may trigger table formatting + // we better do that inside an action + + const SwTableNode* pTNd = pCurCrsr->GetPoint()->nNode.GetNode().FindTableNode(); + if( pTNd ) + { + // wir stehen in der Tabelle, dann teste mal, ob die Tabelle oder die + // Selektion ausgeglichen ist. + String sSel; + if( pTblCrsr ) + sSel = GetBoxNms(); + bRet = pTNd->GetTable().IsTblComplexForChart( sSel ); + } + + EndAction(); + + return bRet; +} + +String SwCrsrShell::GetBoxNms() const +{ + String sNm; + const SwPosition* pPos; + SwFrm* pFrm; + + if( IsTableMode() ) + { + SwCntntNode *pCNd = pTblCrsr->Start()->nNode.GetNode().GetCntntNode(); + pFrm = pCNd ? pCNd->GetFrm() : 0; + if( !pFrm ) + return sNm; + + do { + pFrm = pFrm->GetUpper(); + } while ( pFrm && !pFrm->IsCellFrm() ); + + ASSERT( pFrm, "kein Frame zur Box" ); + sNm = ((SwCellFrm*)pFrm)->GetTabBox()->GetName(); + sNm += ':'; + pPos = pTblCrsr->End(); + } + else + { + const SwTableNode* pTblNd = IsCrsrInTbl(); + if( !pTblNd ) + return sNm; + pPos = GetCrsr()->GetPoint(); + } + + SwCntntNode* pCNd = pPos->nNode.GetNode().GetCntntNode(); + pFrm = pCNd ? pCNd->GetFrm() : 0; + + if( pFrm ) + { + do { + pFrm = pFrm->GetUpper(); + } while ( pFrm && !pFrm->IsCellFrm() ); + + if( pFrm ) + sNm += ((SwCellFrm*)pFrm)->GetTabBox()->GetName(); + } + return sNm; +} + + +BOOL SwCrsrShell::GotoTable( const String& rName ) +{ + SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, + BOOL bRet = !pTblCrsr && pCurCrsr->GotoTable( rName ); + if( bRet ) + { + pCurCrsr->GetPtPos() = Point(); + UpdateCrsr( SwCrsrShell::SCROLLWIN | SwCrsrShell::CHKRANGE | + SwCrsrShell::READONLY ); // und den akt. Updaten + } + return bRet; +} + + +BOOL SwCrsrShell::CheckTblBoxCntnt( const SwPosition* pPos ) +{ + if( !pBoxIdx || !pBoxPtr || IsSelTblCells() || !IsAutoUpdateCells() ) + return FALSE; + + // ueberpruefe, ob der Box Inhalt mit dem angegebenen Format der Box + // ueber einstimmt. Wenn nicht, setze neu + SwTableBox* pChkBox = 0; + SwStartNode* pSttNd = 0; + if( !pPos ) + { + // gesicherte Position heraus holen. + if( pBoxIdx && pBoxPtr && + 0 != ( pSttNd = pBoxIdx->GetNode().GetStartNode() ) && + SwTableBoxStartNode == pSttNd->GetStartNodeType() && + pBoxPtr == pSttNd->FindTableNode()->GetTable(). + GetTblBox( pBoxIdx->GetIndex() ) ) + pChkBox = pBoxPtr; + } + else if( 0 != ( pSttNd = pPos->nNode.GetNode(). + FindSttNodeByType( SwTableBoxStartNode )) ) + { + pChkBox = pSttNd->FindTableNode()->GetTable().GetTblBox( pSttNd->GetIndex() ); + } + + + // Box mehr als 1 Absatz? + if( pChkBox && pSttNd->GetIndex() + 2 != pSttNd->EndOfSectionIndex() ) + pChkBox = 0; + + // jetzt sollten wir mal die Pointer zerstoeren, bevor eine erneute + // Actionklammerung kommt. + if( !pPos && !pChkBox ) + ClearTblBoxCntnt(); + + // liegt der Cursor nicht mehr in dem Bereich ? + if( pChkBox && !pPos && + ( pCurCrsr->HasMark() || pCurCrsr->GetNext() != pCurCrsr || + pSttNd->GetIndex() + 1 == pCurCrsr->GetPoint()->nNode.GetIndex() )) + pChkBox = 0; + + //JP 12.01.99: hat sich der Inhalt der Box ueberhaupt veraendert? + // Ist wichtig, wenn z.B. Undo nicht den richtigen Inhalt wieder + // herstellen konnte. + if( pChkBox ) + { + const SwTxtNode* pNd = GetDoc()->GetNodes()[ + pSttNd->GetIndex() + 1 ]->GetTxtNode(); + if( !pNd || + ( pNd->GetTxt() == ViewShell::GetShellRes()->aCalc_Error && + SFX_ITEM_SET == pChkBox->GetFrmFmt()-> + GetItemState( RES_BOXATR_FORMULA )) ) + pChkBox = 0; + } + + if( pChkBox ) + { + // jetzt sollten wir mal die Pointer zerstoeren, bevor ein weiterer + // aufruf kommt. + ClearTblBoxCntnt(); + StartAction(); + GetDoc()->ChkBoxNumFmt( *pChkBox, TRUE ); + EndAction(); + } + + return 0 != pChkBox; +} + + +void SwCrsrShell::SaveTblBoxCntnt( const SwPosition* pPos ) +{ + if( IsSelTblCells() || !IsAutoUpdateCells() ) + return ; + + if( !pPos ) + pPos = pCurCrsr->GetPoint(); + + SwStartNode* pSttNd = pPos->nNode.GetNode().FindSttNodeByType( SwTableBoxStartNode ); + + BOOL bCheckBox = FALSE; + if( pSttNd && pBoxIdx ) + { + if( pSttNd == &pBoxIdx->GetNode() ) + pSttNd = 0; // die haben wir schon + else + bCheckBox = TRUE; + } + else + bCheckBox = 0 != pBoxIdx; + + if( bCheckBox ) + { + // pBoxIdx Checken + SwPosition aPos( *pBoxIdx ); + CheckTblBoxCntnt( &aPos ); + } + + if( pSttNd ) + { + pBoxPtr = pSttNd->FindTableNode()->GetTable().GetTblBox( pSttNd->GetIndex() ); + + if( pBoxIdx ) + *pBoxIdx = *pSttNd; + else + pBoxIdx = new SwNodeIndex( *pSttNd ); + } +} + + +void SwCrsrShell::ClearTblBoxCntnt() +{ + delete pBoxIdx, pBoxIdx = 0; + pBoxPtr = 0; +} + +BOOL SwCrsrShell::EndAllTblBoxEdit() +{ + BOOL bRet = FALSE; + ViewShell *pSh = this; + do { + if( pSh->IsA( TYPE( SwCrsrShell ) ) ) + bRet |= ((SwCrsrShell*)pSh)->CheckTblBoxCntnt( + ((SwCrsrShell*)pSh)->pCurCrsr->GetPoint() ); + + } while( this != (pSh = (ViewShell *)pSh->GetNext()) ); + return bRet; +} + + + + diff --git a/sw/source/core/crsr/unocrsr.cxx b/sw/source/core/crsr/unocrsr.cxx new file mode 100644 index 000000000000..a4e0d6f79785 --- /dev/null +++ b/sw/source/core/crsr/unocrsr.cxx @@ -0,0 +1,280 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <unocrsr.hxx> +#include <doc.hxx> +#include <swtable.hxx> +#include <docary.hxx> +#include <rootfrm.hxx> + +SV_IMPL_PTRARR( SwUnoCrsrTbl, SwUnoCrsrPtr ) + +IMPL_FIXEDMEMPOOL_NEWDEL( SwUnoCrsr, 10, 10 ) + +SwUnoCrsr::SwUnoCrsr( const SwPosition &rPos, SwPaM* pRing ) + : SwCursor( rPos, pRing, false ), SwModify( 0 ), + bRemainInSection( TRUE ), + bSkipOverHiddenSections( FALSE ), + bSkipOverProtectSections( FALSE ) + +{} + +// @@@ semantic: no copy ctor. +SwUnoCrsr::SwUnoCrsr( SwUnoCrsr& rICrsr ) + : SwCursor( rICrsr ), SwModify( 0 ), + bRemainInSection( rICrsr.bRemainInSection ), + bSkipOverHiddenSections( rICrsr.bSkipOverHiddenSections ), + bSkipOverProtectSections( rICrsr.bSkipOverProtectSections ) +{} + +SwUnoCrsr::~SwUnoCrsr() +{ + SwDoc* pDoc = GetDoc(); + if( !pDoc->IsInDtor() ) + { + // dann muss der Cursor aus dem Array ausgetragen werden + SwUnoCrsrTbl& rTbl = (SwUnoCrsrTbl&)pDoc->GetUnoCrsrTbl(); + USHORT nDelPos = rTbl.GetPos( this ); + + if( USHRT_MAX != nDelPos ) + rTbl.Remove( nDelPos ); + else { + ASSERT( !this, "UNO Cursor nicht mehr im Array" ); + } + } + + // den gesamten Ring loeschen! + while( GetNext() != this ) + { + Ring* pNxt = GetNext(); + pNxt->MoveTo( 0 ); // ausketten + delete pNxt; // und loeschen + } +} + +SwUnoCrsr * SwUnoCrsr::Clone() const +{ + SwUnoCrsr * pNewCrsr = GetDoc()->CreateUnoCrsr( *GetPoint() ); + if (HasMark()) + { + pNewCrsr->SetMark(); + *pNewCrsr->GetMark() = *GetMark(); + } + return pNewCrsr; +} + +SwUnoTableCrsr * SwUnoTableCrsr::Clone() const +{ + SwUnoTableCrsr * pNewCrsr = dynamic_cast<SwUnoTableCrsr*>( + GetDoc()->CreateUnoCrsr( + *GetPoint(), sal_True /* create SwUnoTableCrsr */ ) ); + OSL_ENSURE(pNewCrsr, "Clone: cannot create SwUnoTableCrsr?"); + if (HasMark()) + { + pNewCrsr->SetMark(); + *pNewCrsr->GetMark() = *GetMark(); + } + return pNewCrsr; +} + + +bool SwUnoCrsr::IsReadOnlyAvailable() const +{ + return true; +} + +const SwCntntFrm* +SwUnoCrsr::DoSetBidiLevelLeftRight( BOOL &, BOOL, BOOL ) +{ + return 0; // not for uno cursor +} + +void SwUnoCrsr::DoSetBidiLevelUpDown() +{ + return; // not for uno cursor +} + +BOOL SwUnoCrsr::IsSelOvr( int eFlags ) +{ + if( bRemainInSection ) + { + SwDoc* pDoc = GetDoc(); + SwNodeIndex aOldIdx( *pDoc->GetNodes()[ GetSavePos()->nNode ] ); + SwNodeIndex& rPtIdx = GetPoint()->nNode; + SwStartNode *pOldSttNd = aOldIdx.GetNode().StartOfSectionNode(), + *pNewSttNd = rPtIdx.GetNode().StartOfSectionNode(); + if( pOldSttNd != pNewSttNd ) + { + BOOL bMoveDown = GetSavePos()->nNode < rPtIdx.GetIndex(); + BOOL bValidPos = FALSE; + + // search the correct surrounded start node - which the index + // can't leave. + while( pOldSttNd->IsSectionNode() ) + pOldSttNd = pOldSttNd->StartOfSectionNode(); + + // is the new index inside this surrounded section? + if( rPtIdx > *pOldSttNd && + rPtIdx < pOldSttNd->EndOfSectionIndex() ) + { + // check if it a valid move inside this section + // (only over SwSection's !) + const SwStartNode* pInvalidNode; + do { + pInvalidNode = 0; + pNewSttNd = rPtIdx.GetNode().StartOfSectionNode(); + + const SwStartNode *pSttNd = pNewSttNd, *pEndNd = pOldSttNd; + if( pSttNd->EndOfSectionIndex() > + pEndNd->EndOfSectionIndex() ) + { + pEndNd = pNewSttNd; + pSttNd = pOldSttNd; + } + + while( pSttNd->GetIndex() > pEndNd->GetIndex() ) + { + if( !pSttNd->IsSectionNode() ) + pInvalidNode = pSttNd; + pSttNd = pSttNd->StartOfSectionNode(); + } + if( pInvalidNode ) + { + if( bMoveDown ) + { + rPtIdx.Assign( *pInvalidNode->EndOfSectionNode(), 1 ); + + if( !rPtIdx.GetNode().IsCntntNode() && + ( !pDoc->GetNodes().GoNextSection( &rPtIdx ) || + rPtIdx > pOldSttNd->EndOfSectionIndex() ) ) + break; + } + else + { + rPtIdx.Assign( *pInvalidNode, -1 ); + + if( !rPtIdx.GetNode().IsCntntNode() && + ( !pDoc->GetNodes().GoPrevSection( &rPtIdx ) || + rPtIdx < *pOldSttNd ) ) + break; + } + } + else + bValidPos = TRUE; + } while ( pInvalidNode ); + } + + if( bValidPos ) + { + SwCntntNode* pCNd = GetCntntNode(); + USHORT nCnt = 0; + if( pCNd && !bMoveDown ) + nCnt = pCNd->Len(); + GetPoint()->nContent.Assign( pCNd, nCnt ); + } + else + { + rPtIdx = GetSavePos()->nNode; + GetPoint()->nContent.Assign( GetCntntNode(), GetSavePos()->nCntnt ); + return TRUE; + } + } + } + return SwCursor::IsSelOvr( eFlags ); +} + + +/* */ + +SwUnoTableCrsr::SwUnoTableCrsr(const SwPosition& rPos) + : SwCursor(rPos,0,false), SwUnoCrsr(rPos), SwTableCursor(rPos), aTblSel(rPos,0,false) +{ + SetRemainInSection(FALSE); +} + +SwUnoTableCrsr::~SwUnoTableCrsr() +{ + while( aTblSel.GetNext() != &aTblSel ) + delete aTblSel.GetNext(); // und loeschen +} + + +/* +SwCursor* SwUnoTableCrsr::Create( SwPaM* pRing ) const +{ + return SwUnoCrsr::Create( pRing ); +} +*/ + +BOOL SwUnoTableCrsr::IsSelOvr( int eFlags ) +{ + BOOL bRet = SwUnoCrsr::IsSelOvr( eFlags ); + if( !bRet ) + { + const SwTableNode* pTNd = GetPoint()->nNode.GetNode().FindTableNode(); + bRet = !(pTNd == GetDoc()->GetNodes()[ GetSavePos()->nNode ]-> + FindTableNode() && (!HasMark() || + pTNd == GetMark()->nNode.GetNode().FindTableNode() )); + } + return bRet; +} + +void SwUnoTableCrsr::MakeBoxSels() +{ + const SwCntntNode* pCNd; + bool bMakeTblCrsrs = true; + if( GetPoint()->nNode.GetIndex() && GetMark()->nNode.GetIndex() && + 0 != ( pCNd = GetCntntNode() ) && pCNd->GetFrm() && + 0 != ( pCNd = GetCntntNode(FALSE) ) && pCNd->GetFrm() ) + bMakeTblCrsrs = GetDoc()->GetRootFrm()->MakeTblCrsrs( *this ); + + if ( !bMakeTblCrsrs ) + { + SwSelBoxes& rTmpBoxes = (SwSelBoxes&)GetBoxes(); + USHORT nCount = 0; + while( nCount < rTmpBoxes.Count() ) + DeleteBox( nCount ); + } + + if( IsChgd() ) + { + SwTableCursor::MakeBoxSels( &aTblSel ); + if( !GetBoxesCount() ) + { + const SwTableBox* pBox; + const SwNode* pBoxNd = GetPoint()->nNode.GetNode().FindTableBoxStartNode(); + const SwTableNode* pTblNd = pBoxNd ? pBoxNd->FindTableNode() : 0; + if( pTblNd && 0 != ( pBox = pTblNd->GetTable().GetTblBox( pBoxNd->GetIndex() )) ) + InsertBox( *pBox ); + } + } +} + diff --git a/sw/source/core/crsr/viscrs.cxx b/sw/source/core/crsr/viscrs.cxx new file mode 100644 index 000000000000..214700c5e680 --- /dev/null +++ b/sw/source/core/crsr/viscrs.cxx @@ -0,0 +1,1006 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#ifndef _SVSTDARR_HXX +#define _SVSTDARR_USHORTS +#include <svl/svstdarr.hxx> +#endif + +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/wrkwin.hxx> +#include <viewopt.hxx> +#include <frmtool.hxx> +#include <viscrs.hxx> +#include <crsrsh.hxx> +#include <doc.hxx> +#include <swtable.hxx> +#include <viewimp.hxx> +#include <dview.hxx> +#include <rootfrm.hxx> +#include <txtfrm.hxx> // SwTxtFrm +#include <docary.hxx> +#include <extinput.hxx> +#include <ndtxt.hxx> +#include <scriptinfo.hxx> +#include <mdiexp.hxx> // GetSearchDialog +#ifndef _COMCORE_HRC +#include <comcore.hrc> // ResId fuer Abfrage wenn zu Search & Replaces +#endif + +#include <svx/sdr/overlay/overlaymanager.hxx> +#include <svx/sdrpaintwindow.hxx> +#include <vcl/svapp.hxx> +#include <svx/sdr/overlay/overlayselection.hxx> + +extern void SwCalcPixStatics( OutputDevice *pOut ); + +//Damit beim ShowCrsr nicht immer wieder die gleiche Size teuer ermittelt +//werden muss, hier statische Member, die beim Wechsel des MapModes +// angepasst werden + +long SwSelPaintRects::nPixPtX = 0; +long SwSelPaintRects::nPixPtY = 0; +MapMode* SwSelPaintRects::pMapMode = 0; + + +#ifdef SHOW_BOOKMARKS +// #include <IMark.hxx> +// +// class SwBookmarkRects : public SwSelPaintRects +// { +// virtual void Paint( const Rectangle& rRect ); +// virtual void FillRects(); +// +// public: +// SwBookmarkRects( const SwCrsrShell& rSh ) : SwSelPaintRects( rSh ) {} +// }; +// +// void SwBookmarkRects::Paint( const Rectangle& rRect ) +// { +// Window* pWin = GetShell()->GetWin(); +// +// RasterOp eOld( pWin->GetRasterOp() ); +// BOOL bLCol = pWin->IsLineColor(); +// Color aLCol( pWin->GetLineColor() ); +// BOOL bFCol = pWin->IsFillColor(); +// Color aFCol( pWin->GetFillColor() ); +// +// pWin->SetRasterOp( ROP_XOR ); +// Color aCol( RGB_COLORDATA( 0xF0, 0xC8, 0xF0 ) ^ COL_WHITE ); +// pWin->SetFillColor( aCol ); +// pWin->SetLineColor( aCol ); +// +// pWin->DrawRect( rRect ); +// +// if( bLCol ) pWin->SetLineColor( aLCol ); else pWin->SetLineColor(); +// if( bFCol ) pWin->SetFillColor( aFCol ); else pWin->SetFillColor(); +// pWin->SetRasterOp( eOld ); +// } +// +// void SwBookmarkRects::FillRects() +// { +// SwRegionRects aReg( GetShell()->VisArea() ); +// +// const SwBookmarks& rBkmkTbl = GetShell()->getIDocumentMarkAccess()->getBookmarks(); +// SwShellCrsr* pCrsr = 0; +// for( USHORT n = 0; n < rBkmkTbl.Count(); ++n ) +// { +// const SwBookmark& rBkmk = *rBkmkTbl[ n ]; +// if( rBkmk.IsBookMark() && rBkmk.GetOtherPos() ) +// { +// if( !pCrsr ) +// { +// pCrsr = new SwShellCrsr( *GetShell(), rBkmk.GetPos() ); +// pCrsr->SetMark(); +// } +// else +// *pCrsr->GetPoint() = rBkmk.GetPos(); +// *pCrsr->GetMark() = *rBkmk.GetOtherPos(); +// pCrsr->FillRects(); +// for( USHORT i = 0; i < pCrsr->Count(); ++i ) +// aReg -= (*pCrsr)[ i ]; +// +// pCrsr->Remove( 0, i ); +// } +// } +// if( pCrsr ) delete pCrsr; +// +// aReg.Invert(); +// SwRects::Insert( &aReg, 0 ); +// } +// +// SwBookmarkRects* pBookMarkRects = 0; +// +// void ShowBookmarks( const SwCrsrShell* pSh, int nAction, const SwRect* pRect = 0 ) +// { +// if( !pBookMarkRects && pSh->getIDocumentMarkAccess()->getBookmarks().Count() ) +// pBookMarkRects = new SwBookmarkRects( *pSh ); +// +// if( pBookMarkRects ) +// { +// switch( nAction ) +// { +// case 1: pBookMarkRects->Show(); break; +// case 2: pBookMarkRects->Hide(); break; +// case 3: pBookMarkRects->Invalidate( *pRect ); break; +// } +// +// if( !pBookMarkRects->Count() ) +// delete pBookMarkRects, pBookMarkRects = 0; +// } +// } +// +// #define SHOWBOOKMARKS1( nAct ) ShowBookmarks( GetShell(),nAct ); +// #define SHOWBOOKMARKS2( nAct, pRect ) ShowBookmarks( GetShell(),nAct, pRect ); + +#else + +#define SHOWBOOKMARKS1( nAct ) +#define SHOWBOOKMARKS2( nAct, pRect ) + +#endif + +#ifdef SHOW_REDLINES +#include <redline.hxx> + +class SwRedlineRects : public SwSelPaintRects +{ + USHORT nMode; + USHORT nNm; + + virtual void Paint( const Rectangle& rRect ); + virtual void FillRects(); + +public: + SwRedlineRects( const SwCrsrShell& rSh, USHORT nName, USHORT n ) + : SwSelPaintRects( rSh ), nMode( n ), nNm( nName ) + {} +}; + +void SwRedlineRects::Paint( const Rectangle& rRect ) +{ + Window* pWin = GetShell()->GetWin(); + + RasterOp eOld( pWin->GetRasterOp() ); + BOOL bLCol = pWin->IsLineColor(); + Color aLCol( pWin->GetLineColor() ); + BOOL bFCol = pWin->IsFillColor(); + Color aFCol( pWin->GetFillColor() ); + + pWin->SetRasterOp( ROP_XOR ); + Color aCol; + + UINT8 nVal = 0xc8 - ( (nMode / 4) * 16 ); + switch( nMode % 4 ) + { + case 0: aCol = RGB_COLORDATA( nVal, nVal, 0xFF ); break; + case 1: aCol = RGB_COLORDATA( 0xFF, 0xc8, nVal ); break; + case 2: aCol = RGB_COLORDATA( nVal, 0xFF, nVal ); break; + case 3: aCol = RGB_COLORDATA( 0xFF, nVal, nVal ); break; + } + aCol = aCol.GetColor() ^ COL_WHITE; + + pWin->SetFillColor( aCol ); + pWin->SetLineColor( aCol ); + + pWin->DrawRect( rRect ); + + if( bLCol ) pWin->SetLineColor( aLCol ); else pWin->SetLineColor(); + if( bFCol ) pWin->SetFillColor( aFCol ); else pWin->SetFillColor(); + pWin->SetRasterOp( eOld ); +} + +void SwRedlineRects::FillRects() +{ + SwRegionRects aReg( GetShell()->VisArea() ); + + const SwRedlineTbl& rTbl = GetShell()->GetDoc()->GetRedlineTbl(); + SwShellCrsr* pCrsr = 0; + for( USHORT n = 0; n < rTbl.Count(); ++n ) + { + const SwRedline& rRed = *rTbl[ n ]; + if( rRed.HasMark() && (nMode % 4 ) == rRed.GetType() && + nNm == rRed.GetAuthor() ) + { + if( !pCrsr ) + { + pCrsr = new SwShellCrsr( *GetShell(), *rRed.GetPoint() ); + pCrsr->SetMark(); + } + else + *pCrsr->GetPoint() = *rRed.GetPoint(); + *pCrsr->GetMark() = *rRed.GetMark(); + pCrsr->FillRects(); + for( USHORT i = 0; i < pCrsr->Count(); ++i ) + aReg -= (*pCrsr)[ i ]; + + pCrsr->Remove( 0, i ); + } + } + if( pCrsr ) delete pCrsr; + + aReg.Invert(); + SwRects::Insert( &aReg, 0 ); +} + +SwRedlineRects* aRedlines[ 10 * 4 ]; +static int bFirstCall = TRUE; + +void ShowRedlines( const SwCrsrShell* pSh, int nAction, const SwRect* pRect = 0 ) +{ + if( bFirstCall ) + { + memset( aRedlines, 0, sizeof(aRedlines)); + bFirstCall = FALSE; + } + + const SwRedlineTbl& rTbl = pSh->GetDoc()->GetRedlineTbl(); + const SwRedlineAuthorTbl& rAuthorTbl = pSh->GetDoc()->GetRedlineAuthorTbl(); + + for( USHORT n = 0; n < rAuthorTbl.Count(); ++n ) + { + for( int i = 0; i < 4; ++i ) + { + SwRedlineRects** ppRedRect = &aRedlines[ n * 4 + i ]; + if( rTbl.Count() && !*ppRedRect ) + *ppRedRect = new SwRedlineRects( *pSh, n, n * 4 + i ); + + if( *ppRedRect ) + { + switch( nAction ) + { + case 1: (*ppRedRect)->Show(); break; + case 2: (*ppRedRect)->Hide(); break; + case 3: (*ppRedRect)->Invalidate( *pRect ); break; + } + + if( !(*ppRedRect)->Count() ) + delete *ppRedRect, *ppRedRect = 0; + } + } + } +} + +#define SHOWREDLINES1( nAct ) ShowRedlines( GetShell(),nAct ); +#define SHOWREDLINES2( nAct, pRect ) ShowRedlines( GetShell(),nAct, pRect ); + +#else + +#define SHOWREDLINES1( nAct ) +#define SHOWREDLINES2( nAct, pRect ) + +#endif + +#ifdef JP_REDLINE + if( GetDoc()->GetRedlineTbl().Count() ) + { + SwRedlineTbl& rRedlineTbl = (SwRedlineTbl&)GetDoc()->GetRedlineTbl(); + for( USHORT i = 0; i < rRedlineTbl.Count(); ++i ) + rRedlineTbl[ i ]->HideRects( *GetShell() ); + } +#endif + +// -------- Ab hier Klassen / Methoden fuer den nicht Text-Cursor ------ + +SwVisCrsr::SwVisCrsr( const SwCrsrShell * pCShell ) + : pCrsrShell( pCShell ) +{ + pCShell->GetWin()->SetCursor( &aTxtCrsr ); + bIsVisible = aTxtCrsr.IsVisible(); + bIsDragCrsr = FALSE; + aTxtCrsr.SetWidth( 0 ); + +#ifdef SW_CRSR_TIMER + bTimerOn = TRUE; + SetTimeout( 50 ); // 50msec Verzoegerung +#endif +} + + + +SwVisCrsr::~SwVisCrsr() +{ +#ifdef SW_CRSR_TIMER + if( bTimerOn ) + Stop(); // Timer stoppen +#endif + + if( bIsVisible && aTxtCrsr.IsVisible() ) + aTxtCrsr.Hide(); + + pCrsrShell->GetWin()->SetCursor( 0 ); +} + + + + +void SwVisCrsr::Show() +{ + if( !bIsVisible ) + { + bIsVisible = TRUE; + + // muss ueberhaupt angezeigt werden ? + if( pCrsrShell->VisArea().IsOver( pCrsrShell->aCharRect ) ) +#ifdef SW_CRSR_TIMER + { + if( bTimerOn ) + Start(); // Timer aufsetzen + else + { + if( IsActive() ) + Stop(); // Timer Stoppen + + _SetPosAndShow(); + } + } +#else + _SetPosAndShow(); +#endif + } +} + + + +void SwVisCrsr::Hide() +{ + if( bIsVisible ) + { + bIsVisible = FALSE; + +#ifdef SW_CRSR_TIMER + if( IsActive() ) + Stop(); // Timer Stoppen +#endif + + if( aTxtCrsr.IsVisible() ) // sollten die Flags nicht gueltig sein? + aTxtCrsr.Hide(); + } +} + +#ifdef SW_CRSR_TIMER + +void __EXPORT SwVisCrsr::Timeout() +{ + ASSERT( !bIsDragCrsr, "Timer vorher abschalten" ); + if( bIsVisible ) + { + if ( !pCrsrShell->GetWin() ) //SwFrmFmt::GetGraphic setzt das Win temp aus! + Start(); + else + _SetPosAndShow(); + } +} + +BOOL SwCrsrShell::ChgCrsrTimerFlag( BOOL bTimerOn ) +{ + return pVisCrsr->ChgTimerFlag( bTimerOn ); +} + + +BOOL SwVisCrsr::ChgTimerFlag( BOOL bFlag ) +{ + bOld = bTimerOn; + if( !bFlag && bIsVisible && IsActive() ) + { + Stop(); // Timer Stoppen + _SetPosAndShow(); + } + bTimerOn = bFlag; + return bOld; +} + +#endif + + +void SwVisCrsr::_SetPosAndShow() +{ + SwRect aRect; + long nTmpY = pCrsrShell->aCrsrHeight.Y(); + if( 0 > nTmpY ) + { + nTmpY = -nTmpY; + aTxtCrsr.SetOrientation( 900 ); + aRect = SwRect( pCrsrShell->aCharRect.Pos(), + Size( pCrsrShell->aCharRect.Height(), nTmpY ) ); + aRect.Pos().X() += pCrsrShell->aCrsrHeight.X(); + if( pCrsrShell->IsOverwriteCrsr() ) + aRect.Pos().Y() += aRect.Width(); + } + else + { + aTxtCrsr.SetOrientation( 0 ); + aRect = SwRect( pCrsrShell->aCharRect.Pos(), + Size( pCrsrShell->aCharRect.Width(), nTmpY ) ); + aRect.Pos().Y() += pCrsrShell->aCrsrHeight.X(); + } + + // check if cursor should show the current cursor bidi level + aTxtCrsr.SetDirection( CURSOR_DIRECTION_NONE ); + const SwCursor* pTmpCrsr = pCrsrShell->_GetCrsr(); + + if ( pTmpCrsr && !pCrsrShell->IsOverwriteCrsr() ) + { + SwNode& rNode = pTmpCrsr->GetPoint()->nNode.GetNode(); + if( rNode.IsTxtNode() ) + { + const SwTxtNode& rTNd = *rNode.GetTxtNode(); + const SwFrm* pFrm = rTNd.GetFrm( 0, 0, FALSE ); + if ( pFrm ) + { + const SwScriptInfo* pSI = ((SwTxtFrm*)pFrm)->GetScriptInfo(); + // cursor level has to be shown + if ( pSI && pSI->CountDirChg() > 1 ) + { + aTxtCrsr.SetDirection( + ( pTmpCrsr->GetCrsrBidiLevel() % 2 ) ? + CURSOR_DIRECTION_RTL : + CURSOR_DIRECTION_LTR ); + } + + if ( pFrm->IsRightToLeft() ) + { + const OutputDevice *pOut = pCrsrShell->GetOut(); + if ( pOut ) + { + long nSize = pOut->GetSettings().GetStyleSettings().GetCursorSize(); + Size aSize( nSize, nSize ); + aSize = pOut->PixelToLogic( aSize ); + aRect.Left( aRect.Left() - aSize.Width() ); + } + } + } + } + } + + if( aRect.Height() ) + { + ::SwCalcPixStatics( pCrsrShell->GetOut() ); + ::SwAlignRect( aRect, (ViewShell*)pCrsrShell ); + } + if( !pCrsrShell->IsOverwriteCrsr() || bIsDragCrsr || + pCrsrShell->IsSelection() ) + aRect.Width( 0 ); + + aTxtCrsr.SetSize( aRect.SSize() ); + + aTxtCrsr.SetPos( aRect.Pos() ); + if ( !pCrsrShell->IsCrsrReadonly() || pCrsrShell->GetViewOptions()->IsSelectionInReadonly() ) + { + if ( pCrsrShell->GetDrawView() ) + ((SwDrawView*)pCrsrShell->GetDrawView())->SetAnimationEnabled( + !pCrsrShell->IsSelection() ); + + USHORT nStyle = bIsDragCrsr ? CURSOR_SHADOW : 0; + if( nStyle != aTxtCrsr.GetStyle() ) + { + aTxtCrsr.SetStyle( nStyle ); + aTxtCrsr.SetWindow( bIsDragCrsr ? pCrsrShell->GetWin() : 0 ); + } + + aTxtCrsr.Show(); + } +} + +////////////////////////////////////////////////////////////////////////////// + +SwSelPaintRects::SwSelPaintRects( const SwCrsrShell& rCSh ) +: SwRects( 0 ), + pCShell( &rCSh ), + mpCursorOverlay(0) +{ +} + +SwSelPaintRects::~SwSelPaintRects() +{ + Hide(); +} + +void SwSelPaintRects::swapContent(SwSelPaintRects& rSwap) +{ + SwRects aTempRects; + aTempRects.Insert(this, 0); + + Remove(0, Count()); + Insert(&rSwap, 0); + + rSwap.Remove(0, rSwap.Count()); + rSwap.Insert(&aTempRects, 0); + + // #i75172# also swap mpCursorOverlay + sdr::overlay::OverlayObject* pTempOverlay = getCursorOverlay(); + setCursorOverlay(rSwap.getCursorOverlay()); + rSwap.setCursorOverlay(pTempOverlay); +} + +void SwSelPaintRects::Hide() +{ + if(mpCursorOverlay) + { + delete mpCursorOverlay; + mpCursorOverlay = 0; + } + + SwRects::Remove( 0, Count() ); +} + +void SwSelPaintRects::Show() +{ + SdrView* pView = (SdrView*)pCShell->GetDrawView(); + + if(pView && pView->PaintWindowCount()) + { + // reset rects + SwRects::Remove( 0, SwRects::Count() ); + FillRects(); + + // get new rects + std::vector< basegfx::B2DRange > aNewRanges; + + for(sal_uInt16 a(0); a < Count(); a++) + { + const SwRect aNextRect((*this)[a]); + const Rectangle aPntRect(aNextRect.SVRect()); + + aNewRanges.push_back(basegfx::B2DRange( + aPntRect.Left(), aPntRect.Top(), + aPntRect.Right() + 1, aPntRect.Bottom() + 1)); + } + + if(mpCursorOverlay) + { + if(aNewRanges.size()) + { + static_cast< sdr::overlay::OverlaySelection* >(mpCursorOverlay)->setRanges(aNewRanges); + } + else + { + delete mpCursorOverlay; + mpCursorOverlay = 0; + } + } + else if(Count()) + { + SdrPaintWindow* pCandidate = pView->GetPaintWindow(0); + sdr::overlay::OverlayManager* pTargetOverlay = pCandidate->GetOverlayManager(); + + if(pTargetOverlay) + { + // #i97672# get the system's hilight color and limit it to the maximum + // allowed luminance. This is needed to react on too bright hilight colors + // which would otherwise vive a bad visualisation + const OutputDevice *pOut = Application::GetDefaultDevice(); + Color aHighlight(pOut->GetSettings().GetStyleSettings().GetHighlightColor()); + const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer; + const basegfx::BColor aSelection(aHighlight.getBColor()); + const double fLuminance(aSelection.luminance()); + const double fMaxLum(aSvtOptionsDrawinglayer.GetSelectionMaximumLuminancePercent() / 100.0); + + if(fLuminance > fMaxLum) + { + const double fFactor(fMaxLum / fLuminance); + const basegfx::BColor aNewSelection( + aSelection.getRed() * fFactor, + aSelection.getGreen() * fFactor, + aSelection.getBlue() * fFactor); + + aHighlight = Color(aNewSelection); + } + + // create correct selection + mpCursorOverlay = new sdr::overlay::OverlaySelection( + sdr::overlay::OVERLAY_TRANSPARENT, + aHighlight, + aNewRanges, + true); + + pTargetOverlay->add(*mpCursorOverlay); + } + } + } +} + +void SwSelPaintRects::Invalidate( const SwRect& rRect ) +{ + USHORT nSz = Count(); + if( !nSz ) + return; + + SwRegionRects aReg( GetShell()->VisArea() ); + aReg.Remove( 0, aReg.Count() ); + aReg.Insert( this, 0 ); + aReg -= rRect; + SwRects::Remove( 0, nSz ); + SwRects::Insert( &aReg, 0 ); + + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // Liegt die Selection rechts oder unten ausserhalb des sichtbaren + // Bereiches, so ist diese nie auf eine Pixel rechts/unten aligned. + // Das muss hier erkannt und ggf. das Rechteckt erweitert werden. + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + if( GetShell()->bVisPortChgd && 0 != ( nSz = Count()) ) + { + SwSelPaintRects::Get1PixelInLogic( *GetShell() ); + SwRect* pRect = (SwRect*)GetData(); + for( ; nSz--; ++pRect ) + { + if( pRect->Right() == GetShell()->aOldRBPos.X() ) + pRect->Right( pRect->Right() + nPixPtX ); + if( pRect->Bottom() == GetShell()->aOldRBPos.Y() ) + pRect->Bottom( pRect->Bottom() + nPixPtY ); + } + } +} + +void SwSelPaintRects::Paint( const Rectangle& /*rRect*/ ) +{ + // nothing to do with overlays +} + + +// check current MapMode of the shell and set possibly the static members. +// Optional set the parameters pX, pY +void SwSelPaintRects::Get1PixelInLogic( const ViewShell& rSh, + long* pX, long* pY ) +{ + const OutputDevice* pOut = rSh.GetWin(); + if ( ! pOut ) + pOut = rSh.GetOut(); + + const MapMode& rMM = pOut->GetMapMode(); + if( pMapMode->GetMapUnit() != rMM.GetMapUnit() || + pMapMode->GetScaleX() != rMM.GetScaleX() || + pMapMode->GetScaleY() != rMM.GetScaleY() ) + { + *pMapMode = rMM; + Size aTmp( 1, 1 ); + aTmp = pOut->PixelToLogic( aTmp ); + nPixPtX = aTmp.Width(); + nPixPtY = aTmp.Height(); + } + if( pX ) + *pX = nPixPtX; + if( pY ) + *pY = nPixPtY; +} + + +/* */ + +SwShellCrsr::SwShellCrsr( const SwCrsrShell& rCShell, const SwPosition &rPos ) + : SwCursor(rPos,0,false), SwSelPaintRects(rCShell), pPt(SwPaM::GetPoint()) +{} + + +SwShellCrsr::SwShellCrsr( const SwCrsrShell& rCShell, const SwPosition &rPos, + const Point& rPtPos, SwPaM* pRing ) + : SwCursor(rPos, pRing, false), SwSelPaintRects(rCShell), aMkPt(rPtPos), + aPtPt(rPtPos), pPt(SwPaM::GetPoint()) +{} + + +SwShellCrsr::SwShellCrsr( SwShellCrsr& rICrsr ) + : SwCursor(rICrsr), SwSelPaintRects(*rICrsr.GetShell()), + aMkPt(rICrsr.GetMkPos()), aPtPt(rICrsr.GetPtPos()), pPt(SwPaM::GetPoint()) +{} + +SwShellCrsr::~SwShellCrsr() {} + + +bool SwShellCrsr::IsReadOnlyAvailable() const +{ + return GetShell()->IsReadOnlyAvailable(); +} + +void SwShellCrsr::SetMark() +{ + if( SwPaM::GetPoint() == pPt ) + aMkPt = aPtPt; + else + aPtPt = aMkPt; + SwPaM::SetMark(); +} + +void SwShellCrsr::FillRects() +{ + // die neuen Rechtecke berechnen + if( HasMark() && + GetPoint()->nNode.GetNode().IsCntntNode() && + GetPoint()->nNode.GetNode().GetCntntNode()->GetFrm() && + (GetMark()->nNode == GetPoint()->nNode || + (GetMark()->nNode.GetNode().IsCntntNode() && + GetMark()->nNode.GetNode().GetCntntNode()->GetFrm() ) )) + GetDoc()->GetRootFrm()->CalcFrmRects( *this, GetShell()->IsTableMode() ); +} + + +void SwShellCrsr::Show() +{ + SwShellCrsr * pTmp = this; + do { + pTmp->SwSelPaintRects::Show(); + } while( this != ( pTmp = dynamic_cast<SwShellCrsr*>(pTmp->GetNext()) ) ); + + SHOWBOOKMARKS1( 1 ) + SHOWREDLINES1( 1 ) +} + + + // Dieses Rechteck wird neu gepaintet, also ist die SSelection in + // dem Bereich ungueltig +void SwShellCrsr::Invalidate( const SwRect& rRect ) +{ + SwShellCrsr * pTmp = this; + + do + { + pTmp->SwSelPaintRects::Invalidate( rRect ); + + // --> FME 2005-08-18 #125102# + // skip any non SwShellCrsr objects in the ring + // (see:SwAutoFormat::DeleteSel() + // <-- + Ring* pTmpRing = pTmp; + pTmp = 0; + do + { + pTmpRing = pTmpRing->GetNext(); + pTmp = dynamic_cast<SwShellCrsr*>(pTmpRing); + } + while ( !pTmp ); + } + while( this != pTmp ); + + SHOWBOOKMARKS2( 3, &rRect ) + SHOWREDLINES2( 3, &rRect ) +} + + +void SwShellCrsr::Hide() +{ + SwShellCrsr * pTmp = this; + do { + pTmp->SwSelPaintRects::Hide(); + } while( this != ( pTmp = dynamic_cast<SwShellCrsr*>(pTmp->GetNext()) ) ); + + SHOWBOOKMARKS1( 2 ) + SHOWREDLINES1( 2 ) +} + +SwCursor* SwShellCrsr::Create( SwPaM* pRing ) const +{ + return new SwShellCrsr( *GetShell(), *GetPoint(), GetPtPos(), pRing ); +} + + +short SwShellCrsr::MaxReplaceArived() +{ + short nRet = RET_YES; + Window* pDlg = LAYOUT_THIS_WINDOW (::GetSearchDialog()); + if( pDlg ) + { + // alte Actions beenden; die Tabellen-Frames werden angelegt und + // eine SSelection kann erzeugt werden + SvUShorts aArr; + USHORT nActCnt; + ViewShell *pShell = GetDoc()->GetRootFrm()->GetCurrShell(), + *pSh = pShell; + do { + for( nActCnt = 0; pSh->ActionPend(); ++nActCnt ) + pSh->EndAction(); + aArr.Insert( nActCnt, aArr.Count() ); + } while( pShell != ( pSh = (ViewShell*)pSh->GetNext() ) ); + + { + nRet = QueryBox( pDlg, SW_RES( MSG_COMCORE_ASKSEARCH )).Execute(); + } + + for( USHORT n = 0; n < aArr.Count(); ++n ) + { + for( nActCnt = aArr[n]; nActCnt--; ) + pSh->StartAction(); + pSh = (ViewShell*)pSh->GetNext(); + } + } + else + // ansonsten aus dem Basic, und dann auf RET_YES schalten + nRet = RET_YES; + + return nRet; +} + +void SwShellCrsr::SaveTblBoxCntnt( const SwPosition* pPos ) +{ + ((SwCrsrShell*)GetShell())->SaveTblBoxCntnt( pPos ); +} + +BOOL SwShellCrsr::UpDown( BOOL bUp, USHORT nCnt ) +{ + return SwCursor::UpDown( bUp, nCnt, + &GetPtPos(), GetShell()->GetUpDownX() ); +} + +#ifdef DBG_UTIL + +// JP 05.03.98: zum Testen des UNO-Crsr Verhaltens hier die Implementierung +// am sichtbaren Cursor + +BOOL SwShellCrsr::IsSelOvr( int eFlags ) +{ + return SwCursor::IsSelOvr( eFlags ); +} + +#endif + +// TRUE: an die Position kann der Cursor gesetzt werden +BOOL SwShellCrsr::IsAtValidPos( BOOL bPoint ) const +{ + if( GetShell() && ( GetShell()->IsAllProtect() || + GetShell()->GetViewOptions()->IsReadonly() || + ( GetShell()->Imp()->GetDrawView() && + GetShell()->Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount() ))) + return TRUE; + + return SwCursor::IsAtValidPos( bPoint ); +} + +/* */ + +SwShellTableCrsr::SwShellTableCrsr( const SwCrsrShell& rCrsrSh, + const SwPosition& rPos ) + : SwCursor(rPos,0,false), SwShellCrsr(rCrsrSh, rPos), SwTableCursor(rPos) +{ +} + +SwShellTableCrsr::SwShellTableCrsr( const SwCrsrShell& rCrsrSh, + const SwPosition& rMkPos, const Point& rMkPt, + const SwPosition& rPtPos, const Point& rPtPt ) + : SwCursor(rPtPos,0,false), SwShellCrsr(rCrsrSh, rPtPos), SwTableCursor(rPtPos) +{ + SetMark(); + *GetMark() = rMkPos; + GetMkPos() = rMkPt; + GetPtPos() = rPtPt; +} + +SwShellTableCrsr::~SwShellTableCrsr() {} + +void SwShellTableCrsr::SetMark() { SwShellCrsr::SetMark(); } + +SwCursor* SwShellTableCrsr::Create( SwPaM* pRing ) const +{ + return SwShellCrsr::Create( pRing ); +} +short SwShellTableCrsr::MaxReplaceArived() +{ + return SwShellCrsr::MaxReplaceArived(); +} +void SwShellTableCrsr::SaveTblBoxCntnt( const SwPosition* pPos ) +{ + SwShellCrsr::SaveTblBoxCntnt( pPos ); +} + + +void SwShellTableCrsr::FillRects() +{ + // die neuen Rechtecke berechnen + // JP 16.01.98: wenn der Cursor noch "geparkt" ist nichts machen!! + if( !aSelBoxes.Count() || bParked || + !GetPoint()->nNode.GetIndex() ) + return; + + SwRegionRects aReg( GetShell()->VisArea() ); + SwNodes& rNds = GetDoc()->GetNodes(); + for( USHORT n = 0; n < aSelBoxes.Count(); ++n ) + { + const SwStartNode* pSttNd = (*(aSelBoxes.GetData() + n ))->GetSttNd(); + const SwTableNode* pSelTblNd = pSttNd->FindTableNode(); + + SwNodeIndex aIdx( *pSttNd ); + SwCntntNode* pCNd = rNds.GoNextSection( &aIdx, TRUE, FALSE ); + + // TABLE IN TABLE + // (see also lcl_FindTopLevelTable in unoobj2.cxx for a different + // version to do this) + const SwTableNode* pCurTblNd = pCNd->FindTableNode(); + while ( pSelTblNd != pCurTblNd && pCurTblNd ) + { + aIdx = pCurTblNd->EndOfSectionIndex(); + pCNd = rNds.GoNextSection( &aIdx, TRUE, FALSE ); + pCurTblNd = pCNd->FindTableNode(); + } + + if( !pCNd ) + continue; + + SwFrm* pFrm = pCNd->GetFrm( &GetSttPos() ); + while( pFrm && !pFrm->IsCellFrm() ) + pFrm = pFrm->GetUpper(); + + ASSERT( pFrm, "Node nicht in einer Tabelle" ); + + while ( pFrm ) + { + if( pFrm && aReg.GetOrigin().IsOver( pFrm->Frm() ) ) + aReg -= pFrm->Frm(); + + pFrm = pFrm->GetNextCellLeaf( MAKEPAGE_NONE ); + } + } + aReg.Invert(); + Insert( &aReg, 0 ); +} + + +// Pruefe, ob sich der SPoint innerhalb der Tabellen-SSelection befindet +BOOL SwShellTableCrsr::IsInside( const Point& rPt ) const +{ + // die neuen Rechtecke berechnen + // JP 16.01.98: wenn der Cursor noch "geparkt" ist nichts machen!! + if( !aSelBoxes.Count() || bParked || + !GetPoint()->nNode.GetIndex() ) + return FALSE; + + SwNodes& rNds = GetDoc()->GetNodes(); + for( USHORT n = 0; n < aSelBoxes.Count(); ++n ) + { + SwNodeIndex aIdx( *(*(aSelBoxes.GetData() + n ))->GetSttNd() ); + SwCntntNode* pCNd = rNds.GoNextSection( &aIdx, TRUE, FALSE ); + if( !pCNd ) + continue; + + SwFrm* pFrm = pCNd->GetFrm( &GetPtPos() ); + while( pFrm && !pFrm->IsCellFrm() ) + pFrm = pFrm->GetUpper(); + ASSERT( pFrm, "Node nicht in einer Tabelle" ); + if( pFrm && pFrm->Frm().IsInside( rPt ) ) + return TRUE; + } + return FALSE; +} + +#ifdef DBG_UTIL + +// JP 05.03.98: zum Testen des UNO-Crsr Verhaltens hier die Implementierung +// am sichtbaren Cursor +BOOL SwShellTableCrsr::IsSelOvr( int eFlags ) +{ + return SwShellCrsr::IsSelOvr( eFlags ); +} + +#endif + +BOOL SwShellTableCrsr::IsAtValidPos( BOOL bPoint ) const +{ + return SwShellCrsr::IsAtValidPos( bPoint ); +} + |