Files
libreoffice/sw/source/core/docnode/ndsect.cxx
Jens-Heiner Rechtien 84a3db80b4 initial import
2000-09-18 23:08:29 +00:00

1379 lines
44 KiB
C++

/*************************************************************************
*
* $RCSfile: ndsect.cxx,v $
*
* $Revision: 1.1.1.1 $
*
* last change: $Author: hr $ $Date: 2000-09-19 00:08:17 $
*
* The Contents of this file are made available subject to the terms of
* either of the following licenses
*
* - GNU Lesser General Public License Version 2.1
* - Sun Industry Standards Source License Version 1.1
*
* Sun Microsystems Inc., October, 2000
*
* GNU Lesser General Public License Version 2.1
* =============================================
* Copyright 2000 by Sun Microsystems, Inc.
* 901 San Antonio Road, Palo Alto, CA 94303, USA
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library 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 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
*
* Sun Industry Standards Source License Version 1.1
* =================================================
* The contents of this file are subject to the Sun Industry Standards
* Source License Version 1.1 (the "License"); You may not use this file
* except in compliance with the License. You may obtain a copy of the
* License at http://www.openoffice.org/license.html.
*
* Software provided under this License is provided on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
* WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
* MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
* See the License for the specific provisions governing your rights and
* obligations concerning the Software.
*
* The Initial Developer of the Original Code is: Sun Microsystems, Inc.
*
* Copyright: 2000 by Sun Microsystems, Inc.
*
* All Rights Reserved.
*
* Contributor(s): _______________________________________
*
*
************************************************************************/
#ifdef PRECOMPILED
#include "core_pch.hxx"
#endif
#pragma hdrstop
#ifndef _HINTIDS_HXX
#include <hintids.hxx>
#endif
#ifndef _SVXLINKMGR_HXX
#include <svx/linkmgr.hxx>
#endif
#ifndef _SFXITEMITER_HXX //autogen
#include <svtools/itemiter.hxx>
#endif
#ifndef _FMTCNTNT_HXX //autogen
#include <fmtcntnt.hxx>
#endif
#ifndef _FMTANCHR_HXX //autogen
#include <fmtanchr.hxx>
#endif
#ifndef _TXTFTN_HXX //autogen
#include <txtftn.hxx>
#endif
#ifndef _FMTCLDS_HXX //autogen
#include <fmtclds.hxx>
#endif
#ifndef _DOC_HXX
#include <doc.hxx>
#endif
#ifndef _ROOTFRM_HXX
#include <rootfrm.hxx>
#endif
#ifndef _PAM_HXX
#include <pam.hxx>
#endif
#ifndef _NDTXT_HXX
#include <ndtxt.hxx>
#endif
#ifndef _SECTION_HXX
#include <section.hxx>
#endif
#ifndef _UNDOBJ_HXX
#include <undobj.hxx>
#endif
#ifndef _SWUNDO_HXX
#include <swundo.hxx>
#endif
#ifndef _CALC_HXX
#include <calc.hxx>
#endif
#ifndef _SWTABLE_HXX
#include <swtable.hxx>
#endif
#ifndef _SWSERV_HXX
#include <swserv.hxx>
#endif
#ifndef _FRMFMT_HXX
#include <frmfmt.hxx>
#endif
#ifndef _FTNIDX_HXX
#include <ftnidx.hxx>
#endif
#ifndef _DOCARY_HXX
#include <docary.hxx>
#endif
#ifndef _NDINDEX_HXX
#include <ndindex.hxx>
#endif
#ifndef _REDLINE_HXX
#include <redline.hxx>
#endif
#ifndef _SECTFRM_HXX
#include <sectfrm.hxx>
#endif
#ifndef _PAGEFRM_HXX
#include <pagefrm.hxx>
#endif
#ifndef _CNTFRM_HXX
#include <cntfrm.hxx>
#endif
#ifndef _NODE2LAY_HXX
#include <node2lay.hxx>
#endif
#ifndef _DOCTXM_HXX
#include <doctxm.hxx>
#endif
#ifndef _FMTFTNTX_HXX
#include <fmtftntx.hxx>
#endif
#ifndef _HINTS_HXX
#include <hints.hxx>
#endif
#ifndef _COMCORE_HRC
#include <comcore.hrc>
#endif
SO2_IMPL_REF( SwServerObject )
int lcl_IsInSameTblBox( SwNodes& rNds, const SwNode& rNd,
const SwNodeIndex& rIdx2 )
{
const SwTableNode* pTblNd = rNd.FindTableNode();
if( !pTblNd )
return TRUE;
// dann suche den StartNode der Box
const SwTableSortBoxes& rSortBoxes = pTblNd->GetTable().GetTabSortBoxes();
ULONG nIdx = rNd.GetIndex();
for( USHORT n = 0; n < rSortBoxes.Count(); ++n )
{
const SwStartNode* pNd = rSortBoxes[ n ]->GetSttNd();
if( pNd->GetIndex() < nIdx &&
nIdx < pNd->EndOfSectionIndex() )
{
// dann muss der andere Index in derselben Section liegen
nIdx = rIdx2.GetIndex();
return pNd->GetIndex() < nIdx && nIdx < pNd->EndOfSectionIndex();
}
}
return TRUE;
}
void lcl_CheckEmptyLayFrm( SwNodes& rNds, SwSection& rSect,
const SwNode& rStt, const SwNode& rEnd )
{
SwNodeIndex aIdx( rStt );
if( !rNds.GoPrevSection( &aIdx, TRUE, FALSE ) ||
!CheckNodesRange( rStt, aIdx, TRUE ) ||
!lcl_IsInSameTblBox( rNds, rStt, aIdx ))
{
aIdx = rEnd;
if( !rNds.GoNextSection( &aIdx, TRUE, FALSE ) ||
!CheckNodesRange( rEnd, aIdx, TRUE ) ||
!lcl_IsInSameTblBox( rNds, rEnd, aIdx ))
rSect.SetHidden( FALSE );
}
}
SwSection* SwDoc::Insert( const SwPaM& rRange, const SwSection& rNew,
const SfxItemSet* pAttr, BOOL bUpdate )
{
const SwNode* pPrvNd = 0;
USHORT nRegionRet = 0;
if( rRange.HasMark() &&
0 == ( nRegionRet = IsInsRegionAvailable( rRange, &pPrvNd ) ))
{
ASSERT( !this, "Selection ueber verschiedene Sections" );
return 0;
}
// Teste ob das gesamte Dokument versteckt werden soll,
// koennen wir zur Zeit nicht !!!!
if( rNew.IsHidden() && rRange.HasMark() )
{
const SwPosition *pStt = rRange.Start(), *pEnd = rRange.End();
if( !pStt->nContent.GetIndex() &&
pEnd->nNode.GetNode().GetCntntNode()->Len() ==
pEnd->nContent.GetIndex() )
::lcl_CheckEmptyLayFrm( GetNodes(), (SwSection&)rNew,
pStt->nNode.GetNode(),
pEnd->nNode.GetNode() );
}
SwUndoInsSection* pUndoInsSect = 0;
if( DoesUndo() )
{
ClearRedo();
pUndoInsSect = new SwUndoInsSection( rRange, rNew, pAttr );
AppendUndo( pUndoInsSect );
DoUndo( FALSE );
}
SwSectionFmt* pFmt = MakeSectionFmt( 0 );
if( pAttr )
pFmt->SetAttr( *pAttr );
SwSectionNode* pNewSectNode = 0;
SwRedlineMode eOld = GetRedlineMode();
SetRedlineMode_intern( (eOld & ~REDLINE_SHOW_MASK) | REDLINE_IGNORE );
if( rRange.HasMark() )
{
SwPosition *pSttPos = (SwPosition*)rRange.Start(),
*pEndPos = (SwPosition*)rRange.End();
if( pPrvNd && 3 == nRegionRet )
{
ASSERT( pPrvNd, "der SectionNode fehlt" );
SwNodeIndex aStt( pSttPos->nNode ), aEnd( pEndPos->nNode, +1 );
while( pPrvNd != aStt.GetNode().FindStartNode() )
aStt--;
while( pPrvNd != aEnd.GetNode().FindStartNode() )
aEnd++;
--aEnd; // im InsertSection ist Ende inclusive
pNewSectNode = GetNodes().InsertSection( aStt, *pFmt, rNew, &aEnd );
}
else
{
if( pUndoInsSect )
{
SwTxtNode* pTNd;
if( !( pPrvNd && 1 == nRegionRet ) &&
pSttPos->nContent.GetIndex() &&
0 != ( pTNd = pSttPos->nNode.GetNode().GetTxtNode() ))
pUndoInsSect->SaveSplitNode( pTNd, TRUE );
if( !( pPrvNd && 2 == nRegionRet ) &&
0 != ( pTNd = pEndPos->nNode.GetNode().GetTxtNode() ) &&
pTNd->GetTxt().Len() != pEndPos->nContent.GetIndex() )
pUndoInsSect->SaveSplitNode( pTNd, FALSE );
}
const SwCntntNode* pCNd;
if( pPrvNd && 1 == nRegionRet )
{
pSttPos->nNode.Assign( *pPrvNd );
pSttPos->nContent.Assign( pSttPos->nNode.GetNode().GetCntntNode(), 0 );
}
else if( pSttPos->nContent.GetIndex() )
SplitNode( *pSttPos );
if( pPrvNd && 2 == nRegionRet )
{
pEndPos->nNode.Assign( *pPrvNd );
pEndPos->nContent.Assign( pEndPos->nNode.GetNode().GetCntntNode(), 0 );
}
else
{
pCNd = pEndPos->nNode.GetNode().GetCntntNode();
if( pCNd && pCNd->Len() != pEndPos->nContent.GetIndex() )
{
xub_StrLen nCntnt = pSttPos->nContent.GetIndex();
SplitNode( *pEndPos );
SwTxtNode* pTNd;
if( pEndPos->nNode.GetIndex() == pSttPos->nNode.GetIndex() )
{
pSttPos->nNode--;
pEndPos->nNode--;
pTNd = pSttPos->nNode.GetNode().GetTxtNode();
pSttPos->nContent.Assign( pTNd, nCntnt );
}
else
{
// wieder ans Ende vom vorherigen setzen
pEndPos->nNode--;
pTNd = pEndPos->nNode.GetNode().GetTxtNode();
}
if( pTNd ) nCntnt = pTNd->GetTxt().Len(); else nCntnt = 0;
pEndPos->nContent.Assign( pTNd, nCntnt );
}
}
pNewSectNode = GetNodes().InsertSection( pSttPos->nNode, *pFmt, rNew,
&pEndPos->nNode );
}
}
else
{
const SwPosition* pPos = rRange.GetPoint();
const SwCntntNode* pCNd = pPos->nNode.GetNode().GetCntntNode();
if( !pPos->nContent.GetIndex() )
{
pNewSectNode = GetNodes().InsertSection( pPos->nNode, *pFmt, rNew, 0, TRUE );
}
else if( pPos->nContent.GetIndex() == pCNd->Len() )
{
pNewSectNode = GetNodes().InsertSection( pPos->nNode, *pFmt, rNew, 0, FALSE );
}
else
{
if( pUndoInsSect && pCNd->IsTxtNode() )
pUndoInsSect->SaveSplitNode( (SwTxtNode*)pCNd, TRUE );
SplitNode( *pPos );
pNewSectNode = GetNodes().InsertSection( pPos->nNode, *pFmt, rNew, 0, TRUE );
}
}
//FEATURE::CONDCOLL
pNewSectNode->CheckSectionCondColl();
//FEATURE::CONDCOLL
SetRedlineMode_intern( eOld );
if( IsRedlineOn() || (!IsIgnoreRedline() && pRedlineTbl->Count() ))
{
SwPaM aPam( *pNewSectNode->EndOfSectionNode(), *pNewSectNode, 1 );
if( IsRedlineOn() )
AppendRedline( new SwRedline( REDLINE_INSERT, aPam ));
else
SplitRedline( aPam );
}
// ist eine Condition gesetzt
if( rNew.IsHidden() && rNew.GetCondition().Len() )
{
// dann berechne bis zu dieser Position
SwCalc aCalc( *this );
FldsToCalc( aCalc, pNewSectNode->GetIndex() );
SwSection& rNewSect = pNewSectNode->GetSection();
rNewSect.SetCondHidden( aCalc.Calculate( rNewSect.GetCondition() ).GetBool() );
}
BOOL bUpdateFtn = FALSE;
if( GetFtnIdxs().Count() && pAttr )
{
USHORT nVal = ((SwFmtFtnAtTxtEnd&)pAttr->Get(
RES_FTN_AT_TXTEND )).GetValue();
if( ( FTNEND_ATTXTEND_OWNNUMSEQ == nVal ||
FTNEND_ATTXTEND_OWNNUMANDFMT == nVal ) ||
( FTNEND_ATTXTEND_OWNNUMSEQ == ( nVal = ((SwFmtEndAtTxtEnd&)
pAttr->Get( RES_END_AT_TXTEND )).GetValue() ) ||
FTNEND_ATTXTEND_OWNNUMANDFMT == nVal ))
bUpdateFtn = TRUE;
}
if( pUndoInsSect )
{
pUndoInsSect->SetSectNdPos( pNewSectNode->GetIndex() );
pUndoInsSect->SetUpdtFtnFlag( bUpdateFtn );
DoUndo( TRUE );
}
if( rNew.IsLinkType() )
pNewSectNode->GetSection().CreateLink( bUpdate ? CREATE_UPDATE : CREATE_CONNECT );
if( bUpdateFtn )
GetFtnIdxs().UpdateFtn( SwNodeIndex( *pNewSectNode ));
SetModified();
return &pNewSectNode->GetSection();
}
USHORT SwDoc::IsInsRegionAvailable( const SwPaM& rRange,
const SwNode** ppSttNd ) const
{
USHORT nRet = 1;
if( rRange.HasMark() )
{
// teste ob es sich um eine gueltige Selektion handelt
const SwPosition* pStt = rRange.Start(),
* pEnd = rRange.End();
const SwCntntNode* pCNd = pEnd->nNode.GetNode().GetCntntNode();
const SwNode* pNd = &pStt->nNode.GetNode();
const SwSectionNode* pSectNd = pNd->FindSectionNode();
const SwSectionNode* pEndSectNd = pCNd->FindSectionNode();
if( pSectNd && pEndSectNd && pSectNd != pCNd->FindSectionNode() )
{
// versuche eine umschliessende Section zu erzeugen
// Aber, nur wenn der Start am Sectionanfang und das Ende am
// Section Ende liegt!
nRet = 0;
if( !pStt->nContent.GetIndex() && pSectNd->GetIndex()
== pStt->nNode.GetIndex() - 1 && pEnd->nContent.GetIndex() ==
pCNd->Len() )
{
SwNodeIndex aIdx( pStt->nNode, -1 );
ULONG nCmp = pEnd->nNode.GetIndex();
const SwStartNode* pPrvNd;
const SwEndNode* pNxtNd;
while( 0 != ( pPrvNd = (pNd = &aIdx.GetNode())->GetSectionNode() ) &&
!( aIdx.GetIndex() < nCmp &&
nCmp < pPrvNd->EndOfSectionIndex() ) )
{
aIdx--;
}
if( !pPrvNd )
pPrvNd = pNd->IsStartNode() ? (SwStartNode*)pNd
: pNd->FindStartNode();
aIdx = pEnd->nNode.GetIndex() + 1;
nCmp = pStt->nNode.GetIndex();
while( 0 != ( pNxtNd = (pNd = &aIdx.GetNode())->GetEndNode() ) &&
pNxtNd->FindStartNode()->IsSectionNode() &&
!( pNxtNd->StartOfSectionIndex() < nCmp &&
nCmp < aIdx.GetIndex() ) )
{
aIdx++;
}
if( !pNxtNd )
pNxtNd = pNd->EndOfSectionNode();
if( pPrvNd && pNxtNd && pPrvNd == pNxtNd->FindStartNode() )
{
nRet = 3;
if( ppSttNd )
*ppSttNd = pPrvNd;
}
}
}
else if( !pSectNd && pEndSectNd )
{
// versuche eine umschliessende Section zu erzeugen
// Aber, nur wenn das Ende am Section Ende liegt!
nRet = 0;
if( pEnd->nContent.GetIndex() == pCNd->Len() )
{
SwNodeIndex aIdx( pEnd->nNode, 1 );
if( aIdx.GetNode().IsEndNode() &&
0 != aIdx.GetNode().FindSectionNode() )
{
do {
aIdx++;
} while( aIdx.GetNode().IsEndNode() &&
0 != aIdx.GetNode().FindSectionNode() );
// if( !aIdx.GetNode().IsEndNode() )
{
nRet = 2;
if( ppSttNd )
{
aIdx--;
*ppSttNd = &aIdx.GetNode();
}
}
}
}
}
else if( pSectNd && !pEndSectNd )
{
// versuche eine umschliessende Section zu erzeugen
// Aber, nur wenn der Start am Section Anfang liegt!
nRet = 0;
if( !pStt->nContent.GetIndex() )
{
SwNodeIndex aIdx( pStt->nNode, -1 );
if( aIdx.GetNode().IsSectionNode() )
{
do {
aIdx--;
} while( aIdx.GetNode().IsSectionNode() );
if( !aIdx.GetNode().IsSectionNode() )
{
nRet = 1;
if( ppSttNd )
{
aIdx++;
*ppSttNd = &aIdx.GetNode();
}
}
}
}
}
}
return nRet;
}
SwSection* SwDoc::GetCurrSection( const SwPosition& rPos ) const
{
const SwSectionNode* pSectNd = rPos.nNode.GetNode().FindSectionNode();
if( pSectNd )
return (SwSection*)&pSectNd->GetSection();
return 0;
}
SwSectionFmt* SwDoc::MakeSectionFmt( SwSectionFmt *pDerivedFrom )
{
if( !pDerivedFrom )
pDerivedFrom = (SwSectionFmt*)pDfltFrmFmt;
SwSectionFmt* pNew = new SwSectionFmt( pDerivedFrom, this );
pSectionFmtTbl->Insert( pNew, pSectionFmtTbl->Count() );
return pNew;
}
void SwDoc::DelSectionFmt( SwSectionFmt *pFmt, BOOL bDelNodes )
{
USHORT nPos = pSectionFmtTbl->GetPos( pFmt );
if( USHRT_MAX != nPos )
{
const SwNodeIndex* pIdx = pFmt->GetCntnt( FALSE ).GetCntntIdx();
const SfxPoolItem* pFtnEndAtTxtEnd;
if( SFX_ITEM_SET != pFmt->GetItemState(
RES_FTN_AT_TXTEND, TRUE, &pFtnEndAtTxtEnd ) ||
SFX_ITEM_SET != pFmt->GetItemState(
RES_END_AT_TXTEND, TRUE, &pFtnEndAtTxtEnd ))
pFtnEndAtTxtEnd = 0;
const SwSectionNode* pSectNd;
if( DoesUndo() )
{
ClearRedo();
if( bDelNodes && pIdx && &GetNodes() == &pIdx->GetNodes() &&
0 != (pSectNd = pIdx->GetNode().GetSectionNode() ))
{
SwNodeIndex aUpdIdx( *pIdx );
ClearRedo();
SwPaM aPaM( *pSectNd->EndOfSectionNode(), *pSectNd );
AppendUndo( new SwUndoDelete( aPaM ));
if( pFtnEndAtTxtEnd )
GetFtnIdxs().UpdateFtn( aUpdIdx );
SetModified();
return ;
}
AppendUndo( new SwUndoDelSection( *pFmt ) );
}
else if( bDelNodes && pIdx && &GetNodes() == &pIdx->GetNodes() &&
0 != (pSectNd = pIdx->GetNode().GetSectionNode() ))
{
SwNodeIndex aUpdIdx( *pIdx );
DeleteSection( (SwNode*)pSectNd );
if( pFtnEndAtTxtEnd )
GetFtnIdxs().UpdateFtn( aUpdIdx );
SetModified();
return ;
}
{
SwPtrMsgPoolItem aMsgHint( RES_REMOVE_UNO_OBJECT, pFmt );
pFmt->Modify( &aMsgHint, &aMsgHint );
}
// ACHTUNG: erst aus dem Array entfernen und dann loeschen.
// Der Section-DTOR versucht selbst noch sein Format
// zu loeschen!
pSectionFmtTbl->Remove( nPos );
//FEATURE::CONDCOLL
ULONG nCnt = 0, nSttNd = 0;
if( pIdx && &GetNodes() == &pIdx->GetNodes() &&
0 != (pSectNd = pIdx->GetNode().GetSectionNode() ))
{
nSttNd = pSectNd->GetIndex();
nCnt = pSectNd->EndOfSectionIndex() - nSttNd - 1;
}
//FEATURE::CONDCOLL
delete pFmt;
if( nSttNd && pFtnEndAtTxtEnd )
{
SwNodeIndex aUpdIdx( GetNodes(), nSttNd );
GetFtnIdxs().UpdateFtn( aUpdIdx );
}
//FEATURE::CONDCOLL
SwCntntNode* pCNd;
for( ; nCnt--; ++nSttNd )
if( 0 != (pCNd = GetNodes()[ nSttNd ]->GetCntntNode() ) &&
RES_CONDTXTFMTCOLL == pCNd->GetFmtColl()->Which() )
pCNd->ChkCondColl();
//FEATURE::CONDCOLL
}
SetModified();
}
void SwDoc::ChgSection( USHORT nPos, const SwSection& rSect,
const SfxItemSet* pAttr )
{
SwSectionFmt* pFmt = (*pSectionFmtTbl)[ nPos ];
SwSection* pSection = pFmt->GetSection();
if( *pSection == rSect )
{
// die Attribute ueberpruefen
BOOL bOnlyAttrChg = FALSE;
if( pAttr && pAttr->Count() )
{
SfxItemIter aIter( *pAttr );
USHORT nWhich = aIter.GetCurItem()->Which();
while( TRUE )
{
if( pFmt->GetAttr( nWhich ) != *aIter.GetCurItem() )
{
bOnlyAttrChg = TRUE;
break;
}
if( aIter.IsAtEnd() )
break;
nWhich = aIter.NextItem()->Which();
}
}
if( bOnlyAttrChg )
{
if( DoesUndo() )
{
ClearRedo();
AppendUndo( new SwUndoChgSection( *pFmt, TRUE ) );
}
pFmt->SetAttr( *pAttr );
SetModified();
}
return;
}
// Teste ob eine gesamte Content-Section (Dokument/TabellenBox/Fly)
// versteckt werden soll, koennen wir zur Zeit nicht !!!!
const SwNodeIndex* pIdx = 0;
{
const SwSectionNode* pSectNd;
if( rSect.IsHidden() && 0 != (pIdx = pFmt->GetCntnt().GetCntntIdx() )
&& 0 != (pSectNd = pIdx->GetNode().GetSectionNode() ) )
{
::lcl_CheckEmptyLayFrm( GetNodes(), (SwSection&)rSect,
*pSectNd, *pSectNd->EndOfSectionNode() );
}
}
if( DoesUndo() )
{
ClearRedo();
AppendUndo( new SwUndoChgSection( *pFmt, FALSE ) );
}
// #56167# Der LinkFileName koennte auch nur aus Separatoren bestehen
String sCompareString = cTokenSeperator;
sCompareString += cTokenSeperator;
BOOL bUpdate = ( !pSection->IsLinkType() && rSect.IsLinkType() ) ||
( rSect.GetLinkFileName().Len() &&
rSect.GetLinkFileName() != sCompareString &&
rSect.GetLinkFileName() !=
pSection->GetLinkFileName());
String sSectName( rSect.GetName() );
if( sSectName != pSection->GetName() )
GetUniqueSectionName( &sSectName );
else
sSectName.Erase();
*pSection = rSect;
if( pAttr )
pSection->GetFmt()->SetAttr( *pAttr );
if( sSectName.Len() )
pSection->SetName( sSectName );
// ist eine Condition gesetzt
if( pSection->IsHidden() && pSection->GetCondition().Len() )
{
// dann berechne bis zu dieser Position
SwCalc aCalc( *this );
if( !pIdx )
pIdx = pFmt->GetCntnt().GetCntntIdx();
FldsToCalc( aCalc, pIdx->GetIndex() );
pSection->SetCondHidden( aCalc.Calculate( pSection->GetCondition() ).GetBool() );
}
if( bUpdate )
pSection->CreateLink( CREATE_UPDATE );
else if( !pSection->IsLinkType() && pSection->IsConnected() )
{
pSection->Disconnect();
GetLinkManager().Remove( pSection->GetBaseLink() );
}
SetModified();
}
void SwDoc::ChgSectionPasswd( const String& sNew )
{
if( DoesUndo() )
{
ClearRedo();
AppendUndo( new SwUndoChgSectPsswd( sSectionPasswd ) );
}
sSectionPasswd = sNew;
SetModified();
}
/* -----------------19.02.99 09:31-------------------
* LockFrms wurde im InsertSection genutzt, um zu verhindern, dass
* SectionFrms durch das DelFrms zerstoert werden. Dies ist durch
* den Destroy-Listen-Mechanismus ueberfluessig geworden.
* Falls diese Methode doch noch einmal reanimiert wird, bietet es
* sich vielleicht an, beim Entlocken die SectionFrms auf Inhalt zu
* pruefen und dann ggf. zur Zerstoerung anzumelden.
* --------------------------------------------------*/
// und dann waren da noch die Fussnoten:
void lcl_DeleteFtn( SwSectionNode *pNd, ULONG nStt, ULONG nEnd )
{
SwFtnIdxs& rFtnArr = pNd->GetDoc()->GetFtnIdxs();
if( rFtnArr.Count() )
{
USHORT nPos;
rFtnArr.SeekEntry( SwNodeIndex( *pNd ), &nPos );
SwTxtFtn* pSrch;
// loesche erstmal alle, die dahinter stehen
while( nPos < rFtnArr.Count() &&
_SwTxtFtn_GetIndex( (pSrch = rFtnArr[ nPos ]) ) <= nEnd )
{
// Werden die Nodes nicht geloescht mussen sie bei den Seiten
// abmeldet (Frms loeschen) werden, denn sonst bleiben sie
// stehen (Undo loescht sie nicht!)
pSrch->DelFrms();
++nPos;
}
while( nPos-- &&
_SwTxtFtn_GetIndex( (pSrch = rFtnArr[ nPos ]) ) >= nStt )
{
// Werden die Nodes nicht geloescht mussen sie bei den Seiten
// abmeldet (Frms loeschen) werden, denn sonst bleiben sie
// stehen (Undo loescht sie nicht!)
pSrch->DelFrms();
}
}
}
inline BOOL lcl_IsTOXSection( const SwSection& rSection )
{
return TOX_CONTENT_SECTION == rSection.GetType() ||
TOX_HEADER_SECTION == rSection.GetType();
}
SwSectionNode* SwNodes::InsertSection( const SwNodeIndex& rNdIdx,
SwSectionFmt& rSectionFmt,
const SwSection& rSection,
const SwNodeIndex* pEnde,
BOOL bInsAtStart, BOOL bCreateFrms )
{
SwNodeIndex aInsPos( rNdIdx );
if( !pEnde ) // kein Bereich also neue Section davor/hinter anlegen
{
if( bInsAtStart )
{
if( !lcl_IsTOXSection( rSection ))
{
do {
aInsPos--;
} while( aInsPos.GetNode().IsSectionNode() );
aInsPos++;
}
}
else
{
SwNode* pNd;
aInsPos++;
if( !lcl_IsTOXSection( rSection ))
while( aInsPos.GetIndex() < Count() - 1 &&
( pNd = &aInsPos.GetNode())->IsEndNode() &&
pNd->FindStartNode()->IsSectionNode())
aInsPos++;
}
}
SwSectionNode* pSectNd = new SwSectionNode( aInsPos, rSectionFmt );
if( pEnde )
{
// Sonderfall fuer die Reader/Writer
if( &pEnde->GetNode() != &GetEndOfContent() )
aInsPos = pEnde->GetIndex()+1;
}
else
{
SwTxtNode* pCpyTNd = rNdIdx.GetNode().GetTxtNode();
if( pCpyTNd )
{
SwTxtNode* pTNd = new SwTxtNode( aInsPos, pCpyTNd->GetTxtColl() );
if( pCpyTNd->GetpSwAttrSet() )
{
// Task 70955 - move PageDesc/Break to the first Node of the
// section
const SfxItemSet& rSet = *pCpyTNd->GetpSwAttrSet();
if( SFX_ITEM_SET == rSet.GetItemState( RES_BREAK ) ||
SFX_ITEM_SET == rSet.GetItemState( RES_PAGEDESC ))
{
SfxItemSet aSet( rSet );
if( bInsAtStart )
pCpyTNd->ResetAttr( RES_PAGEDESC, RES_BREAK );
else
{
aSet.ClearItem( RES_PAGEDESC );
aSet.ClearItem( RES_BREAK );
}
pTNd->SwCntntNode::SetAttr( aSet );
}
else
pTNd->SwCntntNode::SetAttr( rSet );
}
// den Frame anlegen nicht vergessen !!
pCpyTNd->MakeFrms( *pTNd );
}
else
new SwTxtNode( aInsPos, (SwTxtFmtColl*)GetDoc()->GetDfltTxtFmtColl() );
}
SwEndNode* pEndNd = new SwEndNode( aInsPos, *pSectNd );
pSectNd->GetSection() = rSection;
SwSectionFmt* pSectFmt = pSectNd->GetSection().GetFmt();
// Hier bietet sich als Optimierung an, vorhandene Frames nicht zu
// zerstoeren und wieder neu anzulegen, sondern nur umzuhaengen.
BOOL bInsFrm = bCreateFrms && !pSectNd->GetSection().IsHidden() &&
GetDoc()->GetRootFrm();
SwNode2Layout *pNode2Layout = NULL;
if( bInsFrm )
{
SwNodeIndex aTmp( *pSectNd );
if( !pSectNd->GetNodes().FindPrvNxtFrmNode( aTmp, pSectNd->EndOfSectionNode() ) )
// dann sammel mal alle Uppers ein
pNode2Layout = new SwNode2Layout( *pSectNd );
}
// jetzt noch bei allen im Bereich den richtigen StartNode setzen
ULONG nEnde = pSectNd->EndOfSectionIndex();
ULONG nStart = pSectNd->GetIndex()+1;
ULONG nSkipIdx = ULONG_MAX;
for( ULONG n = nStart; n < nEnde; ++n )
{
SwNode* pNd = (*this)[n];
//JP 30.04.99: Bug 65644 - alle in der NodeSection liegenden
// Sections unter die neue haengen
if( ULONG_MAX == nSkipIdx )
pNd->pStartOfSection = pSectNd;
else if( n >= nSkipIdx )
nSkipIdx = ULONG_MAX;
if( pNd->IsStartNode() )
{
// die Verschachtelung der Formate herstellen!
if( pNd->IsSectionNode() )
{
((SwSectionNode*)pNd)->GetSection().GetFmt()->
SetDerivedFrom( pSectFmt );
((SwSectionNode*)pNd)->DelFrms();
n = pNd->EndOfSectionIndex();
}
else
{
if( pNd->IsTableNode() )
((SwTableNode*)pNd)->DelFrms();
if( ULONG_MAX == nSkipIdx )
nSkipIdx = pNd->EndOfSectionIndex();
}
}
else if( pNd->IsCntntNode() )
((SwCntntNode*)pNd)->DelFrms();
}
lcl_DeleteFtn( pSectNd, nStart, nEnde );
if( bInsFrm )
{
if( pNode2Layout )
{
ULONG nIdx = pSectNd->GetIndex();
pNode2Layout->RestoreUpperFrms( pSectNd->GetNodes(), nIdx, nIdx + 1 );
delete pNode2Layout;
}
else
pSectNd->MakeFrms( &aInsPos );
}
return pSectNd;
}
SwSectionNode* SwNode::FindSectionNode()
{
if( IsSectionNode() )
return GetSectionNode();
SwStartNode* pTmp = pStartOfSection;
while( !pTmp->IsSectionNode() && pTmp->GetIndex() )
#if defined( ALPHA ) && defined( UNX )
pTmp = ((SwNode*)pTmp)->pStartOfSection;
#else
pTmp = pTmp->pStartOfSection;
#endif
return pTmp->GetSectionNode();
}
//---------
// SwSectionNode
//---------
SwSectionNode::SwSectionNode( const SwNodeIndex& rIdx, SwSectionFmt& rFmt )
: SwStartNode( rIdx, ND_SECTIONNODE )
{
SwSectionNode* pParent = FindStartNode()->FindSectionNode();
if( pParent )
{
// das Format beim richtigen Parent anmelden.
rFmt.SetDerivedFrom( pParent->GetSection().GetFmt() );
}
pSection = new SwSection( CONTENT_SECTION, rFmt.GetName(), &rFmt );
// jetzt noch die Verbindung von Format zum Node setzen
// Modify unterdruecken, interresiert keinen
rFmt.LockModify();
rFmt.SetAttr( SwFmtCntnt( this ) );
rFmt.UnlockModify();
}
//Hier werden ueberfluessige SectionFrms entfernt
SwFrm* SwClearDummies( SwFrm* pFrm )
{
SwFrm* pTmp = pFrm;
while( pTmp )
{
ASSERT( !pTmp->GetUpper(), "SwClearDummies: No Upper allowed!" );
if( pTmp->IsSctFrm() )
{
SwSectionFrm* pSectFrm = (SwSectionFrm*)pFrm;
pTmp = pTmp->GetNext();
if( !pSectFrm->GetLower() )
{
if( pSectFrm->GetPrev() )
pSectFrm->GetPrev()->pNext = pTmp;
else
pFrm = pTmp;
if( pTmp )
pTmp->pPrev = pSectFrm->GetPrev();
delete pSectFrm;
}
}
else
pTmp = pTmp->GetNext();
}
return pFrm;
}
SwSectionNode::~SwSectionNode()
{
{
SwClientIter aIter( *(pSection->GetFmt()) );
SwClient *pLast = aIter.GoStart();
while ( pLast )
{
if ( pLast->IsA( TYPE(SwFrm) ) )
{
SwSectionFrm *pSectFrm = (SwSectionFrm*)pLast;
SwSectionFrm::MoveCntntAndDelete( pSectFrm, TRUE );
pLast = aIter.GoStart();
}
else
pLast = aIter++;
}
}
SwDoc* pDoc = GetDoc();
SwSectionFmt* pFmt = pSection->GetFmt();
if( pFmt )
{
// das Attribut entfernen, weil die Section ihr Format loescht
// und falls das Cntnt-Attribut vorhanden ist, die Section aufhebt.
pFmt->LockModify();
pFmt->ResetAttr( RES_CNTNT );
pFmt->UnlockModify();
}
BOOL bUndo = pDoc->DoesUndo();
// verhinder beim Loeschen aus der Undo/Redo-History einen rekursiven Aufruf
if( bUndo && &pDoc->GetNodes() != &GetNodes() )
pDoc->DoUndo( FALSE );
DELETEZ( pSection );
pDoc->DoUndo( bUndo );
}
// setze ein neues SectionObject. Erstmal nur gedacht fuer die
// neuen VerzeichnisSections. Der geht ueber in den Besitz des Nodes!
void SwSectionNode::SetNewSection( SwSection* pNewSection )
{
ASSERT( pNewSection, "ohne Pointer geht hier nichts" );
if( pNewSection )
{
SwNode2Layout aN2L( *this );
// einige Flags sollten ueber nommen werden!
pNewSection->bProtectFlag = pSection->bProtectFlag;
pNewSection->bHiddenFlag = pSection->bHiddenFlag;
pNewSection->bHidden = pSection->bHidden;
pNewSection->bCondHiddenFlag = pSection->bCondHiddenFlag;
// The section frame contains a pointer to the section. That for,
// the frame must be destroyed before deleting the section.
DelFrms();
delete pSection;
pSection = pNewSection;
ULONG nIdx = GetIndex();
aN2L.RestoreUpperFrms( GetNodes(), nIdx, nIdx + 1 );
}
}
SwFrm *SwSectionNode::MakeFrm()
{
pSection->bHiddenFlag = FALSE;
return new SwSectionFrm( *pSection );
}
//Methode erzeugt fuer den vorhergehenden Node alle Ansichten vom
//Dokument. Die erzeugten Contentframes werden in das entsprechende
//Layout gehaengt.
void SwSectionNode::MakeFrms(const SwNodeIndex & rIdx )
{
// also nehme meinen nachfolgenden oder vorhergehenden ContentFrame:
SwNodes& rNds = GetNodes();
if( rNds.IsDocNodes() && rNds.GetDoc()->GetRootFrm() )
{
if( GetSection().IsHidden() || IsCntntHidden() )
{
SwNodeIndex aIdx( *EndOfSectionNode() );
SwCntntNode* pCNd = rNds.GoNextSection( &aIdx, TRUE, FALSE );
if( !pCNd )
{
aIdx = *this;
if( 0 == ( pCNd = rNds.GoPrevSection( &aIdx, TRUE, FALSE )) )
return ;
}
pCNd = rNds[ aIdx ]->GetCntntNode();
pCNd->MakeFrms( (SwCntntNode&)rIdx.GetNode() );
}
else
{
SwNode2Layout aNode2Layout( *this, rIdx.GetIndex() );
SwFrm *pFrm, *pNew;
while( 0 != (pFrm = aNode2Layout.NextFrm()) )
{
ASSERT( pFrm->IsSctFrm(), "Depend von Section keine Section." );
pNew = rIdx.GetNode().GetCntntNode()->MakeFrm();
SwSectionNode *pS = rIdx.GetNode().FindSectionNode();
// if the node is in a section, the sectionframe now
// has to be created..
if( pS )
{
SwSectionFrm *pSct = new SwSectionFrm( pS->GetSection() );
SwLayoutFrm* pUp = pSct;
while( pUp->Lower() ) // for columned sections
{
ASSERT( pUp->Lower()->IsLayoutFrm(),"Who's in there?" );
pUp = (SwLayoutFrm*)pUp->Lower();
}
pNew->Paste( pUp, NULL );
pNew = pSct;
}
// wird ein Node vorher oder nachher mit Frames versehen
if ( rIdx < GetIndex() )
// der neue liegt vor mir
pNew->Paste( pFrm->GetUpper(), pFrm );
else
// der neue liegt hinter mir
pNew->Paste( pFrm->GetUpper(), pFrm->GetNext() );
}
}
}
}
//Fuer jedes vorkommen im Layout einen SectionFrm anlegen und vor den
//entsprechenden CntntFrm pasten.
void SwSectionNode::MakeFrms( SwNodeIndex* pIdxBehind, SwNodeIndex* pEndIdx )
{
ASSERT( pIdxBehind, "kein Index" );
SwNodes& rNds = GetNodes();
SwDoc* pDoc = rNds.GetDoc();
*pIdxBehind = *this;
pSection->bHiddenFlag = TRUE;
if( rNds.IsDocNodes() )
{
SwNodeIndex *pEnd = pEndIdx ? pEndIdx :
new SwNodeIndex( *EndOfSectionNode(), 1 );
::MakeFrms( pDoc, *pIdxBehind, *pEnd );
if( !pEndIdx )
delete pEnd;
}
}
void SwSectionNode::DelFrms()
{
ULONG nStt = GetIndex()+1, nEnd = EndOfSectionIndex();
if( nStt >= nEnd )
{
// unser Flag muessen wir noch aktualisieren
// pSection->bHiddenFlag = TRUE;
return ;
}
SwNodes& rNds = GetNodes();
pSection->GetFmt()->DelFrms();
// unser Flag muessen wir noch aktualisieren
pSection->bHiddenFlag = TRUE;
// Bug 30582: falls der Bereich in Fly oder TabellenBox ist, dann
// kann er nur "gehiddet" werden, wenn weiterer Content
// vorhanden ist, der "Frames" haelt. Sonst hat der
// Fly/TblBox-Frame keinen Lower !!!
{
SwNodeIndex aIdx( *this );
if( !rNds.GoPrevSection( &aIdx, TRUE, FALSE ) ||
!CheckNodesRange( *this, aIdx, TRUE ) ||
!lcl_IsInSameTblBox( rNds, *this, aIdx ))
{
aIdx = *EndOfSectionNode();
if( !rNds.GoNextSection( &aIdx, TRUE, FALSE ) ||
!CheckNodesRange( *EndOfSectionNode(), aIdx, TRUE ) ||
!lcl_IsInSameTblBox( rNds, *EndOfSectionNode(), aIdx ))
pSection->bHiddenFlag = FALSE;
}
}
}
SwSectionNode* SwSectionNode::MakeCopy( SwDoc* pDoc, const SwNodeIndex& rIdx ) const
{
// in welchen Array steht ich denn: Nodes, UndoNodes ??
const SwNodes& rNds = GetNodes();
// das SectionFrmFmt kopieren
SwSectionFmt* pSectFmt = pDoc->MakeSectionFmt( 0 );
pSectFmt->CopyAttrs( *GetSection().GetFmt() );
SwSectionNode* pSectNd = new SwSectionNode( rIdx, *pSectFmt );
SwEndNode* pEndNd = new SwEndNode( rIdx, *pSectNd );
SwNodeIndex aInsPos( *pEndNd );
// Werte uebertragen
SwSection* pNewSect = pSectNd->pSection;
switch( GetSection().GetType() )
{
case TOX_CONTENT_SECTION:
{
ASSERT( GetSection().ISA( SwTOXBaseSection ), "keine TOXBaseSection!" );
SwTOXBaseSection& rTOXSect = (SwTOXBaseSection&)GetSection();
SwTOXBase aTmp( rTOXSect, pDoc );
SwTOXBaseSection* pNew = new SwTOXBaseSection( aTmp );
pNewSect = pNew;
pSectFmt->Add( pNewSect );
pSectNd->SetNewSection( pNew );
}
break;
default:
// beim Move den Namen beibehalten
if( rNds.GetDoc() == pDoc && pDoc->IsCopyIsMove() )
pNewSect->SetName( GetSection().GetName() );
else
pNewSect->SetName( pDoc->GetUniqueSectionName(
&GetSection().GetName() ) );
break;
}
pNewSect->SetType( GetSection().GetType() );
pNewSect->SetCondition( GetSection().GetCondition() );
pNewSect->SetLinkFileName( GetSection().GetLinkFileName() );
if( !pNewSect->IsHiddenFlag() && GetSection().IsHidden() )
pNewSect->SetHidden( TRUE );
if( !pNewSect->IsProtectFlag() && GetSection().IsProtect() )
pNewSect->SetProtect( TRUE );
SwNodeRange aRg( *this, +1, *EndOfSectionNode() ); // (wo stehe in denn nun ??)
rNds._Copy( aRg, aInsPos, FALSE );
// loesche alle Frames vom kopierten Bereich, diese werden beim
// erzeugen des SectionFrames angelegt !
pSectNd->DelFrms();
// dann kopiere auch noch die Links/Server
if( pNewSect->IsLinkType() ) // den Link eintragen
pNewSect->CreateLink( pDoc->GetRootFrm() ? CREATE_CONNECT
: CREATE_NONE );
// falls als Server aus dem Undo kopiert wird, wieder eintragen
if( pSection->IsServer() && pDoc->GetUndoNds() == &rNds )
{
pNewSect->SetRefObject( pSection->GetObject() );
pDoc->GetLinkManager().InsertServer( pNewSect->GetObject() );
}
return pSectNd;
}
BOOL SwSectionNode::IsCntntHidden() const
{
ASSERT( !pSection->IsHidden(), "That's simple: Hidden Section => Hidden Content" );
SwNodeIndex aTmp( *this, 1 );
ULONG nEnd = EndOfSectionIndex();
while( aTmp < nEnd )
{
if( aTmp.GetNode().IsSectionNode() )
{
const SwSection& rSect = ((SwSectionNode&)aTmp.GetNode()).GetSection();
if( rSect.IsHiddenFlag() )
// dann diese Section ueberspringen
aTmp = *aTmp.GetNode().EndOfSectionNode();
}
else
{
if( aTmp.GetNode().IsCntntNode() || aTmp.GetNode().IsTableNode() )
return FALSE; // Nicht versteckter Inhalt wurde gefunden
ASSERT( aTmp.GetNode().IsEndNode(), "EndNode expected" );
}
aTmp++;
}
return TRUE; // Alles versteckt
}
void SwSectionNode::NodesArrChgd()
{
SwSectionFmt* pFmt = pSection->GetFmt();
if( pFmt )
{
SwNodes& rNds = GetNodes();
SwDoc* pDoc = pFmt->GetDoc();
if( !rNds.IsDocNodes() )
{
SwPtrMsgPoolItem aMsgHint( RES_REMOVE_UNO_OBJECT, pFmt );
pFmt->Modify( &aMsgHint, &aMsgHint );
}
pFmt->LockModify();
pFmt->SetAttr( SwFmtCntnt( this ));
pFmt->UnlockModify();
SwSectionNode* pSectNd = FindStartNode()->FindSectionNode();
// set the correct parent from the new section
pFmt->SetDerivedFrom( pSectNd ? pSectNd->GetSection().GetFmt()
: pDoc->GetDfltFrmFmt() );
// jetzt noch bei allen im Bereich den richtigen StartNode setzen
ULONG nStart = GetIndex()+1, nEnde = EndOfSectionIndex();
for( ULONG n = nStart; n < nEnde; ++n )
// die Verschachtelung der Formate herstellen!
if( 0 != ( pSectNd = rNds[ n ]->GetSectionNode() ) )
{
pSectNd->GetSection().GetFmt()->SetDerivedFrom( pFmt );
n = pSectNd->EndOfSectionIndex();
}
// verschieben vom Nodes- ins UndoNodes-Array?
if( rNds.IsDocNodes() )
{
ASSERT( pDoc == GetDoc(),
"verschieben in unterschiedliche Documente?" );
if( pSection->IsLinkType() ) // den Link austragen
pSection->CreateLink( pDoc->GetRootFrm() ? CREATE_CONNECT
: CREATE_NONE );
if( pSection->IsServer() ) // als Server austragen
pDoc->GetLinkManager().InsertServer( pSection->GetObject() );
}
else
{
if( CONTENT_SECTION != pSection->GetType() ) // den Link austragen
pDoc->GetLinkManager().Remove( pSection->GetBaseLink() );
if( pSection->IsServer() ) // als Server austragen
pDoc->GetLinkManager().RemoveServer( pSection->GetObject() );
}
}
}
String SwDoc::GetUniqueSectionName( const String* pChkStr ) const
{
ResId aId( STR_REGION_DEFNAME, pSwResMgr );
String aName( aId );
xub_StrLen nNmLen = aName.Len();
USHORT nNum, nTmp, nFlagSize = ( pSectionFmtTbl->Count() / 8 ) +2;
BYTE* pSetFlags = new BYTE[ nFlagSize ];
memset( pSetFlags, 0, nFlagSize );
const SwSectionNode* pSectNd;
for( USHORT n = 0; n < pSectionFmtTbl->Count(); ++n )
if( 0 != ( pSectNd = (*pSectionFmtTbl)[ n ]->GetSectionNode( FALSE ) ))
{
const String& rNm = pSectNd->GetSection().GetName();
if( rNm.Match( aName ) == nNmLen )
{
// Nummer bestimmen und das Flag setzen
nNum = rNm.Copy( nNmLen ).ToInt32();
if( nNum-- && nNum < pSectionFmtTbl->Count() )
pSetFlags[ nNum / 8 ] |= (0x01 << ( nNum & 0x07 ));
}
if( pChkStr && pChkStr->Equals( rNm ) )
pChkStr = 0;
}
if( !pChkStr )
{
// alle Nummern entsprechend geflag, also bestimme die richtige Nummer
nNum = pSectionFmtTbl->Count();
for( n = 0; n < nFlagSize; ++n )
if( 0xff != ( nTmp = pSetFlags[ n ] ))
{
// also die Nummer bestimmen
nNum = n * 8;
while( nTmp & 1 )
++nNum, nTmp >>= 1;
break;
}
}
__DELETE( nFlagSize ) pSetFlags;
if( pChkStr )
return *pChkStr;
return aName += String::CreateFromInt32( ++nNum );
}