Files
libreoffice/sw/source/core/doc/docnum.cxx

2188 lines
70 KiB
C++
Raw Normal View History

2000-09-18 23:08:29 +00:00
/*************************************************************************
*
* $RCSfile: docnum.cxx,v $
*
* $Revision: 1.1.1.1 $
*
* last change: $Author: hr $ $Date: 2000-09-19 00:08:15 $
*
* 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 _DATE_HXX //autogen
#include <tools/date.hxx>
#endif
#ifndef _TIME_HXX //autogen
#include <tools/time.hxx>
#endif
#ifndef _TOOLS_RESID_HXX //autogen
#include <tools/resid.hxx>
#endif
#ifndef _URLOBJ_HXX
#include <tools/urlobj.hxx>
#endif
#ifndef _SVX_LRSPITEM_HXX //autogen
#include <svx/lrspitem.hxx>
#endif
#ifndef _FTNINFO_HXX //autogen
#include <ftninfo.hxx>
#endif
#ifndef _FTNIDX_HXX //autogen
#include <ftnidx.hxx>
#endif
#ifndef _DOC_HXX
#include <doc.hxx>
#endif
#ifndef _PAM_HXX
#include <pam.hxx>
#endif
#ifndef _NDTXT_HXX
#include <ndtxt.hxx>
#endif
#ifndef _NUMRULE_HXX
#include <numrule.hxx>
#endif
#ifndef _DOCTXM_HXX
#include <doctxm.hxx> // pTOXBaseRing
#endif
#ifndef _POOLFMT_HXX
#include <poolfmt.hxx>
#endif
#ifndef _UNDOBJ_HXX
#include <undobj.hxx>
#endif
#ifndef _SWUNDO_HXX
#include <swundo.hxx>
#endif
#ifndef _ROLBCK_HXX
#include <rolbck.hxx>
#endif
#ifndef _PARATR_HXX
#include <paratr.hxx>
#endif
#ifndef _DOCARY_HXX
#include <docary.hxx>
#endif
#ifndef _MVSAVE_HXX
#include <mvsave.hxx>
#endif
#ifndef _HINTS_HXX
#include <hints.hxx>
#endif
#ifndef _TXTFRM_HXX
#include <txtfrm.hxx>
#endif
#ifndef _HINTS_HXX
#include <hints.hxx>
#endif
#ifndef _PAMTYP_HXX
#include <pamtyp.hxx>
#endif
#ifndef _REDLINE_HXX
#include <redline.hxx>
#endif
#ifndef _COMCORE_HRC
#include <comcore.hrc>
#endif
inline BYTE GetUpperLvlChg( BYTE nCurLvl, BYTE nLevel, USHORT nMask )
{
if( 1 < nLevel )
{
if( nCurLvl + 1 >= nLevel )
nCurLvl -= nLevel - 1;
else
nCurLvl = 0;
}
return (nMask - 1) & ~(( 1 << nCurLvl ) - 1);
}
void SwDoc::SetOutlineNumRule( const SwNumRule& rRule )
{
USHORT nChkLevel = 0, nChgFmtLevel = 0;
if( pOutlineRule )
{
USHORT nMask = 1;
for( BYTE n = 0; n < MAXLEVEL; ++n, nMask <<= 1 )
{
const SwNumFmt& rOld = pOutlineRule->Get( n ),
& rNew = rRule.Get( n );
if( rOld != rNew )
{
nChgFmtLevel |= nMask;
if( rOld.GetAbsLSpace() != rNew.GetAbsLSpace() ||
rOld.GetFirstLineOffset() != rNew.GetFirstLineOffset() )
nChkLevel |= nMask;
}
else if( SVX_NUM_NUMBER_NONE > rNew.eType && 1 < rNew.GetUpperLevel() &&
0 != (nChgFmtLevel & GetUpperLvlChg( n,
rNew.GetUpperLevel(), nMask )) )
nChgFmtLevel |= nMask;
}
(*pOutlineRule) = rRule;
}
else
{
nChgFmtLevel = nChkLevel = 0xffff;
pOutlineRule = new SwNumRule( rRule );
}
pOutlineRule->SetRuleType( OUTLINE_RULE );
pOutlineRule->SetName( String::CreateFromAscii(
SwNumRule::GetOutlineRuleName() ));
// teste ob die evt. gesetzen CharFormate in diesem Document
// definiert sind
pOutlineRule->CheckCharFmts( this );
// losche aus dem Array alle Nodes, die ohne Outline Nummerierung sind
SwOutlineNodes& rArr = (SwOutlineNodes&)GetNodes().GetOutLineNds();
{
SwNodeNum aNoNum( NO_NUMBERING );
for( USHORT n = 0; n < rArr.Count(); ++n )
{
SwTxtNode* pTxtNd = rArr[n]->GetTxtNode();
if( pTxtNd && NO_NUMBERING == pTxtNd->GetTxtColl()->GetOutlineLevel() )
{
pTxtNd->UpdateOutlineNum( aNoNum );
rArr.Remove( n-- );
}
}
}
// suche alle Nodes, die neu aufgenommen werden muessen !!
// (eigentlich koennte das auch per Modify am die Nodes propagiert
// werden !! )
ULONG nStt = GetNodes().GetEndOfContent().StartOfSectionIndex();
for( USHORT n = 0; n < pTxtFmtCollTbl->Count(); ++n )
{
SwTxtFmtColl* pColl = (*pTxtFmtCollTbl)[ n ];
BYTE nLevel = pColl->GetOutlineLevel();
if( NO_NUMBERING != nLevel )
{
#ifndef NUM_RELSPACE
// JP 08.07.98: Einzuege aus der Outline uebernehmen.
// ??Aber nur wenn sie veraendert wurden??
if( ( nLevel = GetRealLevel( nLevel )) < MAXLEVEL
/*&& 0 != (nChkLevel & (1 << nLevel ))*/ )
{
SvxLRSpaceItem aLR( (SvxLRSpaceItem&)pColl->GetAttr( RES_LR_SPACE ) );
const SwNumFmt& rNFmt = pOutlineRule->Get( nLevel );
// ohne Nummer immer ohne FirstLineOffset!!!!
short nFOfst;
if( pColl->GetOutlineLevel() & NO_NUMLEVEL )
nFOfst = 0;
else
nFOfst = rNFmt.GetFirstLineOffset();
if( aLR.GetTxtLeft() != rNFmt.GetAbsLSpace() ||
aLR.GetTxtFirstLineOfst() != nFOfst )
{
aLR.SetTxtFirstLineOfstValue( nFOfst );
aLR.SetTxtLeft( rNFmt.GetAbsLSpace() );
pColl->SetAttr( aLR );
}
}
#endif
SwClientIter aIter( *pColl );
for( SwTxtNode* pNd = (SwTxtNode*)aIter.First( TYPE( SwTxtNode ));
pNd; pNd = (SwTxtNode*)aIter.Next() )
if( pNd->GetNodes().IsDocNodes() && nStt < pNd->GetIndex() )
rArr.Insert( pNd );
}
}
for( n = 0; n < rArr.Count(); ++n )
{
SwTxtNode* pNd = rArr[ n ]->GetTxtNode();
ASSERT( pNd, "was ist das fuer ein Node?" );
if( ( 1 << (pNd->GetTxtColl()->GetOutlineLevel() & ~NO_NUMLEVEL )
& nChgFmtLevel ))
pNd->NumRuleChgd();
}
GetNodes().UpdateOutlineNodes(); // update der Nummern
// gibt es Fussnoten && gilt Kapitelweises Nummerieren, dann updaten
if( GetFtnIdxs().Count() && FTNNUM_CHAPTER == GetFtnInfo().eNum )
GetFtnIdxs().UpdateAllFtn();
UpdateExpFlds();
SetModified();
}
// Hoch-/Runterstufen
BOOL SwDoc::OutlineUpDown( const SwPaM& rPam, short nOffset )
{
if( !GetNodes().GetOutLineNds().Count() || !nOffset )
return FALSE;
// den Bereich feststellen
const SwOutlineNodes& rOutlNds = GetNodes().GetOutLineNds();
const SwNodePtr pSttNd = (SwNodePtr)&rPam.Start()->nNode.GetNode();
const SwNodePtr pEndNd = (SwNodePtr)&rPam.End()->nNode.GetNode();
USHORT nSttPos, nEndPos;
if( !rOutlNds.Seek_Entry( pSttNd, &nSttPos ) &&
!nSttPos-- )
// wir stehen in keiner "Outline-Section"
return FALSE;
if( rOutlNds.Seek_Entry( pEndNd, &nEndPos ) )
++nEndPos;
// jetzt haben wir unseren Bereich im OutlineNodes-Array
// dann prufe ersmal, ob nicht unterebenen aufgehoben werden
// (Stufung ueber die Grenzen)
register USHORT n;
if( 0 <= nOffset ) // nach unten
{
for( n = nSttPos; n < nEndPos; ++n )
if( rOutlNds[ n ]->GetTxtNode()->GetTxtColl()->
GetOutlineLevel() + nOffset >= MAXLEVEL )
return FALSE;
}
else
for( n = nSttPos; n < nEndPos; ++n )
if( rOutlNds[ n ]->GetTxtNode()->GetTxtColl()->
GetOutlineLevel() < -nOffset )
return FALSE;
// so, dann koennen wir:
// 1. Vorlagen-Array anlegen
SwTxtFmtColl* aCollArr[ MAXLEVEL ];
memset( aCollArr, 0, sizeof( SwTxtFmtColl* ) * MAXLEVEL );
for( n = 0; n < pTxtFmtCollTbl->Count(); ++n )
{
BYTE nLevel = (*pTxtFmtCollTbl)[ n ]->GetOutlineLevel();
if( nLevel < MAXLEVEL )
aCollArr[ nLevel ] = (*pTxtFmtCollTbl)[ n ];
}
for( n = 0; n < MAXLEVEL; ++n )
if( !aCollArr[ n ] )
aCollArr[ n ] = GetTxtCollFromPool( RES_POOLCOLL_HEADLINE1 + n );
if( DoesUndo() )
{
ClearRedo();
AppendUndo( new SwUndoOutlineLeftRight( rPam, nOffset ) );
}
// 2. allen Nodes die neue Vorlage zuweisen
for( n = nSttPos; n < nEndPos; ++n )
{
SwTxtNode* pTxtNd = rOutlNds[ n ]->GetTxtNode();
SwTxtFmtColl* pColl = pTxtNd->GetTxtColl();
pColl = aCollArr[ pColl->GetOutlineLevel() + nOffset ];
pColl = (SwTxtFmtColl*)pTxtNd->ChgFmtColl( pColl );
// Undo ???
}
SetModified();
return TRUE;
}
// Hoch-/Runter - Verschieben !
BOOL SwDoc::MoveOutlinePara( const SwPaM& rPam, short nOffset )
{
// kein Verschiebung in den Sonderbereichen
const SwPosition& rStt = *rPam.Start(),
& rEnd = &rStt == rPam.GetPoint() ? *rPam.GetMark()
: *rPam.GetPoint();
if( !GetNodes().GetOutLineNds().Count() || !nOffset ||
rStt.nNode.GetIndex() < aNodes.GetEndOfExtras().GetIndex() ||
rEnd.nNode.GetIndex() < aNodes.GetEndOfExtras().GetIndex() )
return FALSE;
USHORT nAktPos = 0;
SwNodeIndex aSttRg( rStt.nNode ), aEndRg( rEnd.nNode );
// nach vorne -> vom Start erfragen
// nach hinten -> vom End erfragen
if( 0 > nOffset ) // nach vorne
{
SwNode* pSrch = &aSttRg.GetNode();
if( !GetNodes().GetOutLineNds().Seek_Entry( pSrch, &nAktPos ) )
{
if( !nAktPos-- )
// wir stehen in keiner "Outline-Section"
return FALSE;
// dann sollten wir den Start korrigieren !!!
aSttRg = *GetNodes().GetOutLineNds()[ nAktPos ];
}
pSrch = &aEndRg.GetNode();
USHORT nTmp;
if( GetNodes().GetOutLineNds().Seek_Entry( pSrch, &nTmp ))
// wenn die Selection in einem OutlineNode endet, diesen noch
// mitnehmen
aEndRg++;
else
{
aEndRg = nTmp < GetNodes().GetOutLineNds().Count()
? *GetNodes().GetOutLineNds()[ nTmp ]
: GetNodes().GetEndOfContent();
}
if( aEndRg == aSttRg )
// kein Bereich, dann machen wir uns einen
aEndRg++;
}
// nach hinten
else
{
SwNode* pSrch = &aEndRg.GetNode();
if( GetNodes().GetOutLineNds().Seek_Entry( pSrch, &nAktPos ) )
++nAktPos;
aEndRg = nAktPos < GetNodes().GetOutLineNds().Count()
? *GetNodes().GetOutLineNds()[ nAktPos ]
: GetNodes().GetEndOfContent();
pSrch = &aSttRg.GetNode();
USHORT nTmp;
if( !GetNodes().GetOutLineNds().Seek_Entry( pSrch, &nTmp ) )
{
if( --nTmp )
aSttRg = *GetNodes().GetOutLineNds()[ nTmp ];
else
aSttRg = *GetNodes().GetEndOfContent().StartOfSectionNode();
}
}
// neue Position errechnen:
const SwNode* pNd;
if( nOffset < 0 && nAktPos < USHORT(-nOffset) )
pNd = GetNodes().GetEndOfContent().StartOfSectionNode();
else if( nAktPos + nOffset >= GetNodes().GetOutLineNds().Count() )
pNd = &GetNodes().GetEndOfContent();
else
pNd = GetNodes().GetOutLineNds()[ nAktPos + nOffset ];
ULONG nNewPos = pNd->GetIndex();
ASSERT( aSttRg.GetIndex() > nNewPos || nNewPos >= aEndRg.GetIndex(),
"Position liegt im MoveBereich" );
// wurde ein Position in den Sonderbereichen errechnet, dann
// setze die Position auf den Dokumentanfang.
// Sollten da Bereiche oder Tabellen stehen, so werden sie nach
// hinten verschoben.
nNewPos = Max( nNewPos, aNodes.GetEndOfExtras().GetIndex() + 2 );
long nOffs = nNewPos - ( 0 < nOffset ? aEndRg.GetIndex() : aSttRg.GetIndex());
SwPaM aPam( aSttRg, aEndRg, 0, -1 );
return MoveParagraph( aPam, nOffs, TRUE );
}
USHORT lcl_FindOutlineName( const SwNodes& rNds, const String& rName,
BOOL bExact )
{
USHORT nSavePos = USHRT_MAX;
const SwOutlineNodes& rOutlNds = rNds.GetOutLineNds();
String sName( INetURLObject::createFragment( rName ) );
for( USHORT n = 0; n < rOutlNds.Count(); ++n )
{
SwTxtNode* pTxtNd = rOutlNds[ n ]->GetTxtNode();
String sTxt( INetURLObject::createFragment( pTxtNd->GetExpandTxt() ));
if( sTxt.Equals( rName ) )
{
// "exact" gefunden, setze Pos auf den Node
nSavePos = n;
break;
}
else if( !bExact && USHRT_MAX == nSavePos &&
COMPARE_EQUAL == sTxt.CompareTo( rName, rName.Len()) )
{
// dann vielleicht nur den den 1.Teil vom Text gefunden
nSavePos = n;
}
}
return nSavePos;
}
USHORT lcl_FindOutlineNum( const SwNodes& rNds, String& rName )
{
// Gueltig Nummern sind (immer nur Offsets!!!):
// ([Nummer]+\.)+ (als regulaerer Ausdruck!)
// (Nummer gefolgt von Punkt, zum 5 Wiederholungen)
// also: "1.1.", "1.", "1.1.1."
xub_StrLen nPos = 0;
String sNum = rName.GetToken( 0, '.', nPos );
if( STRING_NOTFOUND == nPos )
return USHRT_MAX; // ungueltige Nummer!!!
USHORT nLevelVal[ MAXLEVEL ]; // Nummern aller Levels
memset( nLevelVal, 0, MAXLEVEL * sizeof( nLevelVal[0] ));
BYTE nLevel = 0;
String sName( rName );
while( STRING_NOTFOUND != nPos )
{
USHORT nVal = 0;
sal_Unicode c;
for( USHORT n = 0; n < sNum.Len(); ++n )
if( '0' <= ( c = sNum.GetChar( n )) && c <= '9' )
{
nVal *= 10; nVal += c - '0';
}
else if( nLevel )
break; // "fast" gueltige Nummer
else
return USHRT_MAX; // ungueltige Nummer!!!
if( MAXLEVEL > nLevel )
nLevelVal[ nLevel++ ] = nVal;
sName.Erase( 0, nPos );
nPos = 0;
sNum = sName.GetToken( 0, '.', nPos );
}
rName = sName; // das ist der nachfolgende Text.
// alle Levels gelesen, dann suche mal im Document nach dieser
// Gliederung:
const SwOutlineNodes& rOutlNds = rNds.GetOutLineNds();
// OS: ohne OutlineNodes lohnt die Suche nicht
// und man spart sich einen Absturz #42958#
if(!rOutlNds.Count())
return USHRT_MAX;
SwTxtNode* pNd;
nPos = 0;
BOOL bNextPos = FALSE;
for( BYTE n = 0; n < nLevel; ++n )
{
USHORT nOff = nLevelVal[ n ];
if( nOff )
{
USHORT nLastPos = nPos;
if( bNextPos )
++nPos;
bNextPos = FALSE;
for( ; nPos < rOutlNds.Count(); ++nPos )
{
pNd = rOutlNds[ nPos ]->GetTxtNode();
BYTE nLvl = pNd->GetTxtColl()->GetOutlineLevel();
if( nLvl == n )
{
nLastPos = nPos;
if( !--nOff )
{
bNextPos = TRUE; // auf jedenfall mit dem nachsten weiter
break;
}
}
else if( nLvl < n ) // nicht ueber den Level hinaus
{
nPos = nLastPos;
break;
}
}
if( nPos >= rOutlNds.Count() )
{
if( !n ) // auf oberster Ebene muss die
return USHRT_MAX; // Nummer gefunden werden
nPos = nLastPos;
}
}
else if( nPos+1 < rOutlNds.Count() )
{
pNd = rOutlNds[ nPos+1 ]->GetTxtNode();
if( n < pNd->GetTxtColl()->GetOutlineLevel() )
++nPos;
}
}
// jetzt sollte im nPos die richtige Position fuer den OutlineLevel
// stehen:
return nPos;
}
// zu diesem Gliederungspunkt
// JP 13.06.96:
// im Namen kann eine Nummer oder/und der Text stehen.
// zuerst wird ueber die Nummer versucht den richtigen Eintrag zu finden.
// Gibt es diesen, dann wird ueber den Text verglichen, od es der
// gewuenschte ist. Ist das nicht der Fall, wird noch mal nur ueber den
// Text gesucht. Wird dieser gefunden ist es der Eintrag. Ansonsten der,
// der ueber die Nummer gefunden wurde.
// Ist keine Nummer angegeben, dann nur den Text suchen.
BOOL SwDoc::GotoOutline( SwPosition& rPos, const String& rName ) const
{
if( rName.Len() )
{
const SwOutlineNodes& rOutlNds = GetNodes().GetOutLineNds();
// 1. Schritt: ueber die Nummer:
String sName( rName );
USHORT nFndPos = ::lcl_FindOutlineNum( GetNodes(), sName );
if( USHRT_MAX != nFndPos )
{
SwTxtNode* pNd = rOutlNds[ nFndPos ]->GetTxtNode();
String sTxt( pNd->GetExpandTxt() );
if( sTxt.Equals( sName ) )
{
USHORT nTmp = ::lcl_FindOutlineName( GetNodes(), sName, TRUE );
if( USHRT_MAX != nTmp ) // ueber den Namen gefunden
{
nFndPos = nTmp;
pNd = rOutlNds[ nFndPos ]->GetTxtNode();
}
}
rPos.nNode = *pNd;
rPos.nContent.Assign( pNd, 0 );
return TRUE;
}
nFndPos = ::lcl_FindOutlineName( GetNodes(), rName, FALSE );
if( USHRT_MAX != nFndPos )
{
SwTxtNode* pNd = rOutlNds[ nFndPos ]->GetTxtNode();
rPos.nNode = *pNd;
rPos.nContent.Assign( pNd, 0 );
return TRUE;
}
}
return FALSE;
}
void SwDoc::SetOutlineLSpace( BYTE nLevel, short nFirstLnOfst, USHORT nLSpace )
{
if( MAXLEVEL >= nLevel )
{
const SwNumFmt& rNFmt = pOutlineRule->Get( nLevel );
if( nLSpace != rNFmt.GetAbsLSpace() ||
nFirstLnOfst != rNFmt.GetFirstLineOffset() )
{
SwNumFmt aFmt( rNFmt );
aFmt.SetAbsLSpace( nLSpace );
aFmt.SetFirstLineOffset( nFirstLnOfst );
pOutlineRule->Set( nLevel, aFmt );
}
}
}
/* */
// --- Nummerierung -----------------------------------------
void SwNumRuleInfo::MakeList( SwDoc& rDoc )
{
SwModify* pMod;
const SfxPoolItem* pItem;
USHORT i, nMaxItems = rDoc.GetAttrPool().GetItemCount( RES_PARATR_NUMRULE);
for( i = 0; i < nMaxItems; ++i )
if( 0 != (pItem = rDoc.GetAttrPool().GetItem( RES_PARATR_NUMRULE, i ) ) &&
0 != ( pMod = (SwModify*)((SwNumRuleItem*)pItem)->GetDefinedIn()) &&
((SwNumRuleItem*)pItem)->GetValue().Len() &&
((SwNumRuleItem*)pItem)->GetValue() == rName )
{
if( pMod->IsA( TYPE( SwFmt )) )
pMod->GetInfo( *this );
else if( ((SwTxtNode*)pMod)->GetNodes().IsDocNodes() )
AddNode( *(SwTxtNode*)pMod );
}
}
void lcl_ChgNumRule( SwDoc& rDoc, const SwNumRule& rRule, SwHistory* pHist,
SwNumRuleInfo* pRuleInfo = 0 )
{
SwNumRule* pOld = rDoc.FindNumRulePtr( rRule.GetName() );
ASSERT( pOld, "ohne die alte NumRule geht gar nichts" );
USHORT nChkLevel = 0, nChgFmtLevel = 0, nMask = 1;
for( BYTE n = 0; n < MAXLEVEL; ++n, nMask <<= 1 )
{
const SwNumFmt& rOldFmt = pOld->Get( n ),
& rNewFmt = rRule.Get( n );
if( rOldFmt != rNewFmt )
{
nChgFmtLevel |= nMask;
if( rOldFmt.GetAbsLSpace() != rNewFmt.GetAbsLSpace() ||
rOldFmt.GetFirstLineOffset() != rNewFmt.GetFirstLineOffset() )
nChkLevel |= nMask;
}
else if( SVX_NUM_NUMBER_NONE > rNewFmt.eType && 1 < rNewFmt.GetUpperLevel() &&
0 != (nChgFmtLevel & GetUpperLvlChg( n, rNewFmt.GetUpperLevel(),nMask )) )
nChgFmtLevel |= nMask;
}
if( !nChgFmtLevel ) // es wurde nichts veraendert?
{
pOld->CheckCharFmts( &rDoc );
pOld->SetContinusNum( rRule.IsContinusNum() );
return ;
}
SwNumRuleInfo* pUpd;
if( !pRuleInfo )
{
pUpd = new SwNumRuleInfo( rRule.GetName() );
pUpd->MakeList( rDoc );
}
else
pUpd = pRuleInfo;
BYTE nLvl;
for( ULONG nFirst = 0, nLast = pUpd->GetList().Count();
nFirst < nLast; ++nFirst )
{
SwTxtNode* pTxtNd = pUpd->GetList().GetObject( nFirst );
if( pTxtNd->GetNum() && ( nLvl = (~NO_NUMLEVEL &
pTxtNd->GetNum()->GetLevel() ) ) < MAXLEVEL )
{
if( nChgFmtLevel & ( 1 << nLvl ))
{
pTxtNd->NumRuleChgd();
#ifndef NUM_RELSPACE
if( nChkLevel && (nChkLevel & ( 1 << nLvl )) &&
pOld->IsRuleLSpace( *pTxtNd ) )
pTxtNd->SetNumLSpace( TRUE );
if( pHist )
{
const SfxPoolItem& rItem =
pTxtNd->SwCntntNode::GetAttr( RES_LR_SPACE );
pHist->Add( &rItem, &rItem, pTxtNd->GetIndex() );
}
#endif
}
}
}
for( n = 0; n < MAXLEVEL; ++n )
if( nChgFmtLevel & ( 1 << n ))
pOld->Set( n, rRule.GetNumFmt( n ));
pOld->CheckCharFmts( &rDoc );
pOld->SetInvalidRule( TRUE );
pOld->SetContinusNum( rRule.IsContinusNum() );
if( !pRuleInfo )
delete pUpd;
}
void SwDoc::SetNumRule( const SwPaM& rPam, const SwNumRule& rRule,
BOOL bSetAbsLSpace )
{
SwUndoInsNum* pUndo;
if( DoesUndo() )
{
ClearRedo();
StartUndo( UNDO_START ); // Klammerung fuer die Attribute!
AppendUndo( pUndo = new SwUndoInsNum( rPam, rRule ) );
}
else
pUndo = 0;
ULONG nPamPos = rPam.Start()->nNode.GetIndex();
BOOL bSetItem = TRUE;
SwNumRule* pNew = FindNumRulePtr( rRule.GetName() );
if( !pNew )
pNew = (*pNumRuleTbl)[ MakeNumRule( rRule.GetName(), &rRule ) ];
else if( rRule.IsAutoRule() && !(*pNew == rRule) )
{
// die Rule existiert schon, wurde aber veraendert. Dann muss hier
// entschieden werden, in wie weit eine neue erzeugt wird oder
// die aktuelle geupdatet wird.
// neue erzeugen wenn:
// - der Pam einen Bereich hat
// - Nodes existieren, die mit der Rule neu Starten
if( rPam.HasMark() )
pNew = (*pNumRuleTbl)[ MakeNumRule( rRule.GetName(), &rRule ) ];
else
{
SwNumRuleInfo aUpd( rRule.GetName() );
aUpd.MakeList( *this );
// Position suchen und bestimme ob ein Node davor oder dahinter
// einen Start erzwingt
SwTxtNode* pTxtNd;
ULONG nFndPos, nFirst, nLast;
if( TABLE_ENTRY_NOTFOUND != aUpd.GetList().SearchKey( nPamPos, &nFndPos ))
++nFndPos;
for( nLast = nFndPos; nLast < aUpd.GetList().Count(); ++nLast )
if( ( pTxtNd = aUpd.GetList().GetObject( nLast ))->GetNum() &&
pTxtNd->GetNum()->IsStart() )
break;
for( nFirst = nFndPos; nFirst; )
if( ( pTxtNd = aUpd.GetList().GetObject( --nFirst ))->GetNum() &&
pTxtNd->GetNum()->IsStart() )
break;
bSetItem = FALSE;
nPamPos = ULONG_MAX;
if( !pNew->IsAutoRule() || nFirst || nLast != aUpd.GetList().Count() )
{
// dann neue Numerierung ueber diesen Bereich
// definieren und den Start am Anfang/Ende zurueck setzen
pTxtNd = aUpd.GetList().GetObject( nFirst );
if( pTxtNd->GetNum()->IsStart() )
{
((SwNodeNum*)pTxtNd->GetNum())->SetStart( FALSE );
if( pUndo )
pUndo->SetSttNum( pTxtNd->GetIndex() );
}
SwHistory* pHist = pUndo ? pUndo->GetHistory() : 0;
#ifndef NUM_RELSPACE
if( pHist )
{
// die LRSpaces muessen zuerst gesichert werden
for( ULONG n = nFirst; n < nLast; ++n )
{
pTxtNd = aUpd.GetList().GetObject( n );
SfxPoolItem* pItem = (SfxPoolItem*)
&pTxtNd->SwCntntNode::GetAttr( RES_LR_SPACE );
pHist->Add( pItem, pItem, pTxtNd->GetIndex() );
}
pUndo->SetLRSpaceEndPos();
}
#endif
SwRegHistory aRegH( pHist );
SwNumRule* pOld = pNew;
pNew = (*pNumRuleTbl)[ MakeNumRule( rRule.GetName(), &rRule ) ];
USHORT nChgFmtLevel = 0;
for( BYTE n = 0; n < MAXLEVEL; ++n )
{
const SwNumFmt& rOldFmt = pOld->Get( n ),
& rNewFmt = rRule.Get( n );
if( rOldFmt.GetAbsLSpace() != rNewFmt.GetAbsLSpace() ||
rOldFmt.GetFirstLineOffset() != rNewFmt.GetFirstLineOffset() )
nChgFmtLevel |= ( 1 << n );
}
SwNumRuleItem aRule( pNew->GetName() );
for( ; nFirst < nLast; ++nFirst )
{
pTxtNd = aUpd.GetList().GetObject( nFirst );
aRegH.RegisterInModify( pTxtNd, *pTxtNd );
#ifndef NUM_RELSPACE
BYTE nLvl = !pTxtNd->GetNum() ? NO_NUMBERING
: pTxtNd->GetNum()->GetLevel() & ~NO_NUMLEVEL;
if( nLvl < MAXLEVEL && (nChgFmtLevel & ( 1 << nLvl )) &&
pOld->IsRuleLSpace( *pTxtNd ) )
pTxtNd->SetNumLSpace( TRUE );
#endif
pTxtNd->SwCntntNode::SetAttr( aRule );
pTxtNd->NumRuleChgd();
}
}
else
{
// dann nur die Rule Updaten
SwHistory* pHist = 0;
if( pUndo )
{
pUndo->SaveOldNumRule( *pNew );
pHist = pUndo->GetHistory();
}
::lcl_ChgNumRule( *this, rRule, pHist, &aUpd );
if( pUndo )
pUndo->SetLRSpaceEndPos();
}
}
}
if( bSetItem )
{
#ifndef NUM_RELSPACE
if( pUndo )
{
SwHistory* pHist = pUndo->GetHistory();
SwCntntNode* pCNd;
for( ULONG n = nPamPos, nEndPos = rPam.End()->nNode.GetIndex();
n <= nEndPos; ++n )
if( 0 != ( pCNd = GetNodes()[ n ]->GetCntntNode() ))
{
const SfxPoolItem& rItem = pCNd->GetAttr( RES_LR_SPACE );
pHist->Add( &rItem, &rItem, n );
}
pUndo->SetLRSpaceEndPos();
}
#endif
Insert( rPam, SwNumRuleItem( pNew->GetName() ) );
}
UpdateNumRule( pNew->GetName(), nPamPos );
EndUndo( UNDO_END );
SetModified();
}
void SwDoc::SetNumRuleStart( const SwPosition& rPos, BOOL bFlag )
{
SwTxtNode* pTxtNd = rPos.nNode.GetNode().GetTxtNode();
const SwNumRule* pRule;
if( pTxtNd && pTxtNd->GetNum() && 0 != ( pRule = pTxtNd->GetNumRule() )
&& bFlag != pTxtNd->GetNum()->IsStart())
{
if( DoesUndo() )
{
ClearRedo();
AppendUndo( new SwUndoNumRuleStart( rPos, bFlag ));
}
SwNodeNum aNum( *pTxtNd->GetNum() );
aNum.SetStart( bFlag );
pTxtNd->UpdateNum( aNum );
UpdateNumRule( pRule->GetName(),
bFlag ? rPos.nNode.GetIndex() : ULONG_MAX );
SetModified();
}
}
void SwDoc::SetNodeNumStart( const SwPosition& rPos, USHORT nStt )
{
SwTxtNode* pTxtNd = rPos.nNode.GetNode().GetTxtNode();
const SwNumRule* pRule;
if( pTxtNd && pTxtNd->GetNum() && 0 != ( pRule = pTxtNd->GetNumRule() )
&& nStt != pTxtNd->GetNum()->GetSetValue() )
{
if( DoesUndo() )
{
ClearRedo();
AppendUndo( new SwUndoNumRuleStart( rPos, nStt ));
}
SwNodeNum aNum( *pTxtNd->GetNum() );
aNum.SetSetValue( nStt );
pTxtNd->UpdateNum( aNum );
UpdateNumRule( pRule->GetName(), USHRT_MAX != nStt
? rPos.nNode.GetIndex() : ULONG_MAX );
SetModified();
}
}
// loeschen geht nur, wenn die Rule niemand benutzt!
BOOL SwDoc::DelNumRule( const String& rName )
{
USHORT nPos = FindNumRule( rName );
if( USHRT_MAX != nPos && !IsUsed( *(*pNumRuleTbl)[ nPos ] ))
{
pNumRuleTbl->DeleteAndDestroy( nPos );
SetModified();
return TRUE;
}
return FALSE;
}
void SwDoc::ChgNumRuleFmts( const SwNumRule& rRule )
{
SwNumRule* pRule = FindNumRulePtr( rRule.GetName() );
if( pRule )
{
SwUndoInsNum* pUndo = 0;
SwHistory* pHistory = 0;
if( DoesUndo() && pRule->IsAutoRule() )
{
ClearRedo();
pUndo = new SwUndoInsNum( *pRule, rRule );
pHistory = pUndo->GetHistory();
AppendUndo( pUndo );
}
::lcl_ChgNumRule( *this, rRule, pHistory );
if( pUndo )
pUndo->SetLRSpaceEndPos();
SetModified();
}
}
void SwDoc::StopNumRuleAnimations( OutputDevice* pOut )
{
for( USHORT n = GetNumRuleTbl().Count(); n; )
{
SwNumRuleInfo aUpd( GetNumRuleTbl()[ --n ]->GetName() );
aUpd.MakeList( *this );
for( ULONG nFirst = 0, nLast = aUpd.GetList().Count();
nFirst < nLast; ++nFirst )
{
SwTxtNode* pTNd = aUpd.GetList().GetObject( nFirst );
SwClientIter aIter( *pTNd );
for( SwFrm* pFrm = (SwFrm*)aIter.First( TYPE(SwFrm) );
pFrm; pFrm = (SwFrm*)aIter.Next() )
if( ((SwTxtFrm*)pFrm)->HasAnimation() )
((SwTxtFrm*)pFrm)->StopAnimation( pOut );
}
}
}
BOOL SwDoc::ReplaceNumRule( const SwPosition& rPos,
const String& rOldRule, const String& rNewRule )
{
BOOL bRet = FALSE;
SwNumRule *pOldRule = FindNumRulePtr( rOldRule ),
*pNewRule = FindNumRulePtr( rNewRule );
if( pOldRule && pNewRule && pOldRule != pNewRule )
{
SwUndoInsNum* pUndo = 0;
if( DoesUndo() )
{
ClearRedo();
StartUndo( UNDO_START ); // Klammerung fuer die Attribute!
AppendUndo( pUndo = new SwUndoInsNum( rPos, *pNewRule, rOldRule ) );
}
SwNumRuleInfo aUpd( rOldRule );
aUpd.MakeList( *this );
// Position suchen und bestimme ob ein Node davor oder dahinter
// einen Start erzwingt
SwTxtNode* pTxtNd;
ULONG nFndPos, nFirst, nLast;
if( TABLE_ENTRY_NOTFOUND != aUpd.GetList().SearchKey(
rPos.nNode.GetIndex(), &nFndPos ))
++nFndPos;
for( nLast = nFndPos; nLast < aUpd.GetList().Count(); ++nLast )
if( ( pTxtNd = aUpd.GetList().GetObject( nLast ))->GetNum() &&
pTxtNd->GetNum()->IsStart() )
break;
for( nFirst = nFndPos; nFirst; )
if( ( pTxtNd = aUpd.GetList().GetObject( --nFirst ))->GetNum() &&
pTxtNd->GetNum()->IsStart() )
break;
// dann neue Numerierung ueber diesen Bereich
// definieren und den Start am Anfang/Ende zurueck setzen
pTxtNd = aUpd.GetList().GetObject( nFirst );
if( pTxtNd->GetNum()->IsStart() )
{
((SwNodeNum*)pTxtNd->GetNum())->SetStart( FALSE );
if( pUndo )
pUndo->SetSttNum( pTxtNd->GetIndex() );
}
SwRegHistory aRegH( pUndo ? pUndo->GetHistory() : 0 );
USHORT nChgFmtLevel = 0;
for( BYTE n = 0; n < MAXLEVEL; ++n )
{
const SwNumFmt& rOldFmt = pOldRule->Get( n ),
& rNewFmt = pNewRule->Get( n );
if( rOldFmt.GetAbsLSpace() != rNewFmt.GetAbsLSpace() ||
rOldFmt.GetFirstLineOffset() != rNewFmt.GetFirstLineOffset() )
nChgFmtLevel |= ( 1 << n );
}
SwNumRuleItem aRule( rNewRule );
for( ; nFirst < nLast; ++nFirst )
{
pTxtNd = aUpd.GetList().GetObject( nFirst );
aRegH.RegisterInModify( pTxtNd, *pTxtNd );
#ifndef NUM_RELSPACE
BYTE nLvl = !pTxtNd->GetNum() ? NO_NUMBERING
: pTxtNd->GetNum()->GetLevel() & ~NO_NUMLEVEL;
if( nLvl < MAXLEVEL && (nChgFmtLevel & ( 1 << nLvl )) &&
pOldRule->IsRuleLSpace( *pTxtNd ) )
pTxtNd->SetNumLSpace( TRUE );
#endif
pTxtNd->SwCntntNode::SetAttr( aRule );
pTxtNd->NumRuleChgd();
}
EndUndo( UNDO_END );
SetModified();
}
return bRet;
}
BOOL SwDoc::NoNum( const SwPaM& rPam )
{
#if 0
// Vielleich koennte man die Funktion auch so definieren:
// den Bereich auf nicht Nummeriert setzen - sprich NO_NUMLEVEL.
//
ULONG nStt = rPam.GetPoint()->nNode.GetIndex(),
nEnd = rPam.GetMark()->nNode.GetIndex();
if( nStt > nEnd )
{
ULONG nTmp = nStt; nStt = nEnd; nEnd = nTmp;
}
const SfxPoolItem* pItem;
const String* pName;
String sNumRule;
for( ; nStt <= nEnd; ++nStt )
{
SwTxtNode* pTNd = GetNodes()[ nStt ]->GetTxtNode();
if( pTNd && 0 != ( pItem = pTNd->GetNoCondAttr(
RES_PARATR_NUMRULE, TRUE ) ) &&
( pName = &((SwNumRuleItem*)pItem)->GetValue())->Len() )
{
SwNodeNum aNum;
if( pTNd->GetNum() )
aNum = *pTNd->GetNum();
aNum.SetLevel( aNum.GetLevel() | NO_NUMLEVEL );
pTNd->UpdateNum( aNum );
if( *pName != sNumRule )
{
sNumRule = *pName;
SwNumRule* pRule = FindNumRulePtr( *pName );
pRule->SetInvalidRule( TRUE );
}
}
}
// dann noch alle Updaten
UpdateNumRule();
// irgendetwas wurde geupdatet
return 0 != n;
#else
BOOL bRet = SplitNode( *rPam.GetPoint() );
// ist ueberhaupt Nummerierung im Spiel ?
if( bRet )
{
// NoNum setzen und Upaten
const SwNodeIndex& rIdx = rPam.GetPoint()->nNode;
SwTxtNode* pNd = rIdx.GetNode().GetTxtNode();
const SwNodeNum* pNum = pNd->GetNum();
const SwNumRule* pRule = pNd->GetNumRule();
if( pNum && pRule )
{
SwNodeNum aNum( *pNum );
aNum.SetLevel( aNum.GetLevel() | NO_NUMLEVEL );
pNd->UpdateNum( aNum );
#ifndef NUM_RELSPACE
pNd->SetNumLSpace( TRUE );
#endif
UpdateNumRule( pRule->GetName(), rIdx.GetIndex() );
SetModified();
}
else
bRet = FALSE; // keine Nummerierung , ?? oder immer TRUE ??
}
return bRet;
#endif
}
BOOL SwDoc::DelNumRules( const SwPaM& rPam )
{
ULONG nStt = rPam.GetPoint()->nNode.GetIndex(),
nEnd = rPam.GetMark()->nNode.GetIndex();
if( nStt > nEnd )
{
ULONG nTmp = nStt; nStt = nEnd; nEnd = nTmp;
}
SwUndoDelNum* pUndo;
if( DoesUndo() )
{
ClearRedo();
AppendUndo( pUndo = new SwUndoDelNum( rPam ) );
}
else
pUndo = 0;
SwRegHistory aRegH( pUndo ? pUndo->GetHistory() : 0 );
SwNumRuleItem aEmptyRule( aEmptyStr );
SvxLRSpaceItem aLRSpace;
String sNumRule;
const SfxPoolItem* pItem;
const String* pName;
SwNumRule* pRule;
const SwNode* pOutlNd = 0;
for( ; nStt <= nEnd; ++nStt )
{
SwTxtNode* pTNd = GetNodes()[ nStt ]->GetTxtNode();
if( pTNd && 0 != ( pItem = pTNd->GetNoCondAttr(
RES_PARATR_NUMRULE, TRUE ) ) &&
( pName = &((SwNumRuleItem*)pItem)->GetValue())->Len() )
{
if( *pName != sNumRule )
{
sNumRule = *pName;
pRule = FindNumRulePtr( *pName );
pRule->SetInvalidRule( TRUE );
}
// fuers Undo - Attribut Aenderungen merken
aRegH.RegisterInModify( pTNd, *pTNd );
BOOL bResetNumRule = FALSE;
const SwAttrSet* pAttrSet = pTNd->GetpSwAttrSet();
#ifndef NUM_RELSPACE
BYTE nLvl;
const SvxLRSpaceItem* pLRSpace;
if( pAttrSet && SFX_ITEM_SET == pAttrSet->GetItemState(
RES_LR_SPACE, FALSE, (const SfxPoolItem**)&pLRSpace ) &&
( !pTNd->GetNum() ||
(( nLvl = (~NO_NUMLEVEL & pTNd->GetNum()->GetLevel() )) <
MAXLEVEL && ( pRule->Get( nLvl ).GetAbsLSpace()
== pLRSpace->GetTxtLeft() )) ))
{
if( pLRSpace->GetRight() )
{
aLRSpace.SetRight( pLRSpace->GetRight() );
pTNd->SwCntntNode::SetAttr( aLRSpace );
}
else
{
pTNd->SwCntntNode::ResetAttr( RES_LR_SPACE );
pAttrSet = pTNd->GetpSwAttrSet();
}
bResetNumRule = TRUE;
}
#endif
if( pUndo )
pUndo->AddNode( *pTNd, bResetNumRule );
// kommt die Rule vom Node, dann Reseten, sonst auf leer setzen
if( pAttrSet && SFX_ITEM_SET == pAttrSet->GetItemState(
RES_PARATR_NUMRULE, FALSE ))
pTNd->SwCntntNode::ResetAttr( RES_PARATR_NUMRULE );
else
pTNd->SwCntntNode::SetAttr( aEmptyRule );
pTNd->UpdateNum( SwNodeNum( NO_NUMBERING ));
if( RES_CONDTXTFMTCOLL == pTNd->GetFmtColl()->Which() )
pTNd->ChkCondColl();
else if( !pOutlNd && NO_NUMBERING !=
((SwTxtFmtColl*)pTNd->GetFmtColl())->GetOutlineLevel() )
pOutlNd = pTNd;
}
}
// dann noch alle Updaten
UpdateNumRule();
if( pOutlNd )
GetNodes().UpdtOutlineIdx( *pOutlNd );
// irgendetwas wurde geupdatet
return 0 != sNumRule.Len();
}
// zum naechsten/vorhergehenden Punkt auf gleicher Ebene
BOOL lcl_IsNumOk( BYTE nSrchNum, BYTE& rLower, BYTE& rUpper,
BOOL bOverUpper, BYTE nNumber )
{
register BOOL bRet = FALSE;
if( nNumber < MAXLEVEL ) // keine Nummerierung ueberspringen
{
if( bOverUpper ? nSrchNum == nNumber : nSrchNum >= nNumber )
bRet = TRUE;
else if( nNumber > rLower )
rLower = nNumber;
else if( nNumber < rUpper )
rUpper = nNumber;
}
else if( nNumber & NO_NUMLEVEL )
{
nNumber &= ~NO_NUMLEVEL;
if( bOverUpper ? FALSE : nSrchNum > nNumber )
bRet = TRUE;
else if( nNumber > rLower )
rLower = nNumber;
else if( nNumber < rUpper )
rUpper = nNumber;
}
return bRet;
}
BOOL lcl_IsValidPrevNextNumNode( const SwNodeIndex& rIdx )
{
BOOL bRet = FALSE;
const SwNode& rNd = rIdx.GetNode();
switch( rNd.GetNodeType() )
{
case ND_ENDNODE:
bRet = SwTableBoxStartNode == rNd.FindStartNode()->GetStartNodeType() ||
rNd.FindStartNode()->IsSectionNode();
break;
case ND_STARTNODE:
bRet = SwTableBoxStartNode == ((SwStartNode&)rNd).GetStartNodeType();
break;
case ND_SECTIONNODE: // der ist erlaubt, also weiter
bRet = TRUE;
break;
}
return bRet;
}
BOOL lcl_GotoNextPrevNum( SwPosition& rPos, BOOL bNext,
BOOL bOverUpper, BYTE* pUpper, BYTE* pLower )
{
const SwTxtNode* pNd = rPos.nNode.GetNode().GetTxtNode();
const SwNumRule* pRule;
if( !pNd || 0 == ( pRule = pNd->GetNumRule() ) || !pNd->GetNum() )
return FALSE;
register BYTE nTmpNum = pNd->GetNum()->GetLevel(),
nSrchNum = nTmpNum & ~NO_NUMLEVEL;
SwNodeIndex aIdx( rPos.nNode );
if( nTmpNum & NO_NUMLEVEL )
{
// falls gerade mal NO_NUMLEVEL an ist, so such den vorherigen Node
// mit Nummerierung
BOOL bError = FALSE;
do {
aIdx--;
if( aIdx.GetNode().IsTxtNode() )
{
pNd = aIdx.GetNode().GetTxtNode();
if( pNd->GetNum() && pRule == pNd->GetNumRule() )
{
nTmpNum = pNd->GetNum()->GetLevel();
if( !( nTmpNum & NO_NUMLEVEL &&
(( nTmpNum & ~NO_NUMLEVEL ) >= nSrchNum )) )
break; // gefunden
}
else
bError = TRUE;
}
else
bError = !lcl_IsValidPrevNextNumNode( aIdx );
} while( !bError );
if( bError )
return FALSE;
}
BYTE nLower = nSrchNum, nUpper = nSrchNum;
BOOL bRet = FALSE;
const SwTxtNode* pLast;
if( bNext )
aIdx++, pLast = pNd;
else
aIdx--, pLast = 0;
while( bNext ? ( aIdx.GetIndex() < aIdx.GetNodes().Count() - 1 )
: aIdx.GetIndex() )
{
if( aIdx.GetNode().IsTxtNode() )
{
pNd = aIdx.GetNode().GetTxtNode();
if( pNd->GetNum() && pRule == pNd->GetNumRule() )
{
if( ::lcl_IsNumOk( nSrchNum, nLower, nUpper, bOverUpper,
pNd->GetNum()->GetLevel() ))
{
rPos.nNode = aIdx;
rPos.nContent.Assign( (SwTxtNode*)pNd, 0 );
bRet = TRUE;
break;
}
else
pLast = pNd;
}
else
break;
}
else if( !lcl_IsValidPrevNextNumNode( aIdx ))
break;
if( bNext )
aIdx++;
else
aIdx--;
}
if( !bRet && !bOverUpper && pLast ) // nicht ueber hoehere Nummmern, aber bis Ende
{
if( bNext )
{
rPos.nNode = aIdx;
if( aIdx.GetNode().IsCntntNode() )
rPos.nContent.Assign( aIdx.GetNode().GetCntntNode(), 0 );
}
else
{
rPos.nNode.Assign( *pLast );
rPos.nContent.Assign( (SwTxtNode*)pLast, 0 );
}
bRet = TRUE;
}
if( bRet )
{
if( pUpper )
*pUpper = nUpper;
if( pLower )
*pLower = nLower;
}
return bRet;
}
BOOL SwDoc::GotoNextNum( SwPosition& rPos, BOOL bOverUpper,
BYTE* pUpper, BYTE* pLower )
{
return ::lcl_GotoNextPrevNum( rPos, TRUE, bOverUpper, pUpper, pLower );
}
BOOL SwDoc::GotoPrevNum( SwPosition& rPos, BOOL bOverUpper,
BYTE* pUpper, BYTE* pLower )
{
return ::lcl_GotoNextPrevNum( rPos, FALSE, bOverUpper, pUpper, pLower );
}
BOOL SwDoc::NumUpDown( const SwPaM& rPam, BOOL bDown )
{
ULONG nStt = rPam.GetPoint()->nNode.GetIndex(),
nEnd = rPam.GetMark()->nNode.GetIndex();
if( nStt > nEnd )
{
ULONG nTmp = nStt; nStt = nEnd; nEnd = nTmp;
}
char nDiff = bDown ? 1 : -1;
if( DoesUndo() )
{
ClearRedo();
AppendUndo( new SwUndoNumUpDown( rPam, nDiff ) );
}
BOOL bRet = FALSE;
String sNumRule;
const SfxPoolItem* pItem;
const String* pName;
for( ; nStt <= nEnd; ++nStt )
{
SwTxtNode* pTNd = GetNodes()[ nStt ]->GetTxtNode();
if( pTNd && 0 != ( pItem = pTNd->GetNoCondAttr(
RES_PARATR_NUMRULE, TRUE ) ) &&
( pName = &((SwNumRuleItem*)pItem)->GetValue())->Len() )
{
BYTE nLevel = pTNd->GetNum()->GetLevel();
if( ( -1 == nDiff && 0 < ( nLevel & ~NO_NUMLEVEL )) ||
( 1 == nDiff && MAXLEVEL - 1 > ( nLevel & ~NO_NUMLEVEL ) ) )
{
nLevel += nDiff;
SwNodeNum aNum( *pTNd->GetNum() );
aNum.SetLevel( nLevel );
pTNd->UpdateNum( aNum );
#ifndef NUM_RELSPACE
pTNd->SetNumLSpace( TRUE );
#endif
if( *pName != sNumRule )
{
sNumRule = *pName;
SwNumRule* pRule = FindNumRulePtr( *pName );
pRule->SetInvalidRule( TRUE );
}
bRet = TRUE;
}
}
}
if( bRet )
{
UpdateNumRule();
SetModified();
}
return bRet;
}
BOOL SwDoc::MoveParagraph( const SwPaM& rPam, long nOffset, BOOL bIsOutlMv )
{
const SwPosition *pStt = rPam.Start(), *pEnd = rPam.End();
ULONG nStIdx = pStt->nNode.GetIndex();
ULONG nEndIdx = pEnd->nNode.GetIndex();
ULONG nInStIdx, nInEndIdx;
long nOffs = nOffset;
if( nOffset > 0 )
{
nInEndIdx = nEndIdx;
nEndIdx += nOffset;
++nOffs;
}
else
{
nInEndIdx = nStIdx - 1;
nStIdx += nOffset;
}
nInStIdx = nInEndIdx + 1;
// Folgende Absatzbloecke sollen vertauscht werden:
// [ nStIdx, nInEndIdx ] mit [ nInStIdx, nEndIdx ]
SwNode *pStartNd = GetNodes()[ nStIdx ];
SwNode *pEndNd = GetNodes()[ nEndIdx ];
if( !pStartNd->IsCntntNode() || !pEndNd->IsCntntNode() )
return FALSE;
pStartNd = pStartNd->FindStartNode();
pEndNd = pEndNd->FindStartNode();
// Es muss sich alles in einem Bereich abspielen
if( pStartNd != pEndNd )
return FALSE;
// auf Redlining testen - darf die Selektion ueberhaupt verschoben
// werden?
if( !IsIgnoreRedline() )
{
USHORT nRedlPos = GetRedlinePos( pStt->nNode.GetNode(), REDLINE_DELETE );
if( USHRT_MAX != nRedlPos )
{
SwPosition aStPos( *pStt ), aEndPos( *pEnd );
aStPos.nContent = 0;
SwCntntNode* pCNd = pEnd->nNode.GetNode().GetCntntNode();
aEndPos.nContent = pCNd ? pCNd->Len() : 1;
BOOL bCheckDel = TRUE;
// es existiert fuer den Bereich irgendein Redline-Delete-Object
for( ; nRedlPos < GetRedlineTbl().Count(); ++nRedlPos )
{
const SwRedline* pTmp = GetRedlineTbl()[ nRedlPos ];
if( !bCheckDel || REDLINE_DELETE == pTmp->GetType() )
{
const SwPosition *pRStt = pTmp->Start(), *pREnd = pTmp->End();
switch( ComparePosition( *pRStt, *pREnd, aStPos, aEndPos ))
{
case POS_BEHIND: // Pos1 liegt hinter Pos2
nRedlPos = GetRedlineTbl().Count();
break;
case POS_BEFORE: // Pos1 liegt vor Pos2
break;
case POS_INSIDE: // Pos1 liegt vollstaendig in Pos2
// ist erlaubt, aber checke dann alle nachfolgenden
// auf Ueberlappungen
bCheckDel = FALSE;
break;
case POS_OUTSIDE: // Pos2 liegt vollstaendig in Pos1
case POS_EQUAL: // Pos1 ist genauso gross wie Pos2
case POS_OVERLAP_BEFORE: // Pos1 ueberlappt Pos2 am Anfang
case POS_OVERLAP_BEHIND: // Pos1 ueberlappt Pos2 am Ende
return FALSE;
}
}
}
}
}
{
// DataChanged vorm verschieben verschicken, dann bekommt
// man noch mit, welche Objecte sich im Bereich befinden.
// Danach koennen sie vor/hinter der Position befinden.
SwDataChanged aTmp( rPam, 0 );
}
SwNodeIndex aIdx( nOffset > 0 ? pEnd->nNode : pStt->nNode, nOffs );
SwNodeRange aMvRg( pStt->nNode, 0, pEnd->nNode, +1 );
SwRedline* pOwnRedl = 0;
if( IsRedlineOn() )
{
// wenn der Bereich komplett im eigenen Redline liegt, kann es
// verschoben werden!
USHORT nRedlPos = GetRedlinePos( pStt->nNode.GetNode(), REDLINE_INSERT );
if( USHRT_MAX != nRedlPos )
{
SwRedline* pTmp = GetRedlineTbl()[ nRedlPos ];
const SwPosition *pRStt = pTmp->Start(), *pREnd = pTmp->End();
SwRedline aTmpRedl( REDLINE_INSERT, rPam );
const SwCntntNode* pCEndNd = pEnd->nNode.GetNode().GetCntntNode();
// liegt komplett im Bereich, und ist auch der eigene Redline?
if( aTmpRedl.IsOwnRedline( *pTmp ) &&
(pRStt->nNode < pStt->nNode ||
(pRStt->nNode == pStt->nNode && !pRStt->nContent.GetIndex()) ) &&
(pEnd->nNode < pREnd->nNode ||
(pEnd->nNode == pREnd->nNode &&
pCEndNd ? pREnd->nContent.GetIndex() == pCEndNd->Len()
: !pREnd->nContent.GetIndex() )) )
{
pOwnRedl = pTmp;
if( nRedlPos + 1 < GetRedlineTbl().Count() )
{
pTmp = GetRedlineTbl()[ nRedlPos+1 ];
if( *pTmp->Start() == *pREnd )
// dann doch nicht!
pOwnRedl = 0;
}
if( pOwnRedl &&
!( pRStt->nNode <= aIdx && aIdx <= pREnd->nNode ))
{
// nicht in sich selbst, dann auch nicht moven
pOwnRedl = 0;
}
}
}
if( !pOwnRedl )
{
StartUndo( UNDO_START );
// zuerst das Insert, dann das Loeschen
SwPosition aInsPos( aIdx );
aInsPos.nContent.Assign( aIdx.GetNode().GetCntntNode(), 0 );
SwPaM aPam( pStt->nNode, aMvRg.aEnd );
SwPaM& rOrigPam = (SwPaM&)rPam;
rOrigPam.DeleteMark();
rOrigPam.GetPoint()->nNode = aIdx.GetIndex() - 1;
BOOL bDelLastPara = !aInsPos.nNode.GetNode().IsCntntNode();
Copy( aPam, aInsPos );
if( bDelLastPara )
{
// dann muss der letzte leere Node wieder entfernt werden
aIdx = aInsPos.nNode;
SwCntntNode* pCNd = GetNodes().GoPrevious( &aInsPos.nNode );
xub_StrLen nCLen = 0; if( pCNd ) nCLen = pCNd->Len();
aInsPos.nContent.Assign( pCNd, nCLen );
// alle die im zu loeschenden Node stehen, mussen auf den
// naechsten umgestezt werden
SwPosition* pPos;
for( USHORT n = 0; n < GetRedlineTbl().Count(); ++n )
{
SwRedline* pTmp = GetRedlineTbl()[ n ];
if( ( pPos = &pTmp->GetBound(TRUE))->nNode == aIdx )
{
pPos->nNode++;
pPos->nContent.Assign( pPos->nNode.GetNode().GetCntntNode(),0);
}
if( ( pPos = &pTmp->GetBound(FALSE))->nNode == aIdx )
{
pPos->nNode++;
pPos->nContent.Assign( pPos->nNode.GetNode().GetCntntNode(),0);
}
}
CorrRel( aIdx, aInsPos, 0, FALSE );
pCNd->JoinNext();
}
rOrigPam.GetPoint()->nNode++;
rOrigPam.GetPoint()->nContent.Assign( rOrigPam.GetCntntNode(), 0 );
SwRedlineMode eOld = GetRedlineMode();
if( DoesUndo() )
{
//JP 06.01.98: MUSS noch optimiert werden!!!
SetRedlineMode( REDLINE_ON | REDLINE_SHOW_INSERT | REDLINE_SHOW_DELETE );
AppendUndo( new SwUndoRedlineDelete( aPam, UNDO_DELETE ));
}
AppendRedline( new SwRedline( REDLINE_DELETE, aPam ));
//JP 06.01.98: MUSS noch optimiert werden!!!
SetRedlineMode( eOld );
EndUndo( UNDO_END );
SetModified();
return TRUE;
}
}
if( !pOwnRedl && !IsIgnoreRedline() && GetRedlineTbl().Count() )
{
SplitRedline( SwPaM( aIdx ));
}
ULONG nRedlSttNd, nRedlEndNd;
if( pOwnRedl )
{
const SwPosition *pRStt = pOwnRedl->Start(), *pREnd = pOwnRedl->End();
nRedlSttNd = pRStt->nNode.GetIndex();
nRedlEndNd = pREnd->nNode.GetIndex();
}
SwUndoMoveNum* pUndo = 0;
if( DoesUndo() )
pUndo = new SwUndoMoveNum( rPam, nOffset, bIsOutlMv );
Move( aMvRg, aIdx, DOC_MOVEREDLINES );
if( pUndo )
{
ClearRedo();
pUndo->SetStartNode( rPam.Start()->nNode.GetIndex() );
AppendUndo( pUndo );
}
if( pOwnRedl )
{
SwPosition *pRStt = pOwnRedl->Start(), *pREnd = pOwnRedl->End();
if( pRStt->nNode.GetIndex() != nRedlSttNd )
{
pRStt->nNode = nRedlSttNd;
pRStt->nContent.Assign( pRStt->nNode.GetNode().GetCntntNode(),0);
}
if( pREnd->nNode.GetIndex() != nRedlEndNd )
{
pREnd->nNode = nRedlEndNd;
SwCntntNode* pCNd = pREnd->nNode.GetNode().GetCntntNode();
xub_StrLen nL = 0; if( pCNd ) nL = pCNd->Len();
pREnd->nContent.Assign( pCNd, nL );
}
}
SetModified();
return TRUE;
}
BOOL SwDoc::NumOrNoNum( const SwNodeIndex& rIdx, BOOL bDel, BOOL bOutline )
{
BOOL bRet = FALSE;
const SwNodeNum* pNum;
const SfxPoolItem* pItem;
const SwNumRule* pRule;
SwTxtNode* pTNd = rIdx.GetNode().GetTxtNode();
if( pTNd &&
( bOutline
? (NO_NUMBERING != pTNd->GetTxtColl()->GetOutlineLevel() &&
0 != ( pNum = pTNd->GetOutlineNum()) &&
0 != ( pRule = GetOutlineNumRule()) )
: ( 0 != (pItem = pTNd->GetNoCondAttr(RES_PARATR_NUMRULE,TRUE)) &&
((SwNumRuleItem*)pItem)->GetValue().Len() &&
0 != ( pNum = pTNd->GetNum()) &&
0 != ( pRule = FindNumRulePtr(
((SwNumRuleItem*)pItem)->GetValue() )) )) &&
(bDel ? 0 != ( pNum->GetLevel() & NO_NUMLEVEL )
: 0 == ( pNum->GetLevel() & NO_NUMLEVEL ) ) &&
SVX_NUM_NUMBER_NONE != pRule->Get( GetRealLevel(pNum->GetLevel()) ).eType )
{
if( DoesUndo() )
{
ClearRedo();
AppendUndo( new SwUndoNumOrNoNum( rIdx, bDel, bOutline ) );
}
SwNodeNum aNum( *pNum );
if( bDel )
aNum.SetLevel( aNum.GetLevel() & ~NO_NUMLEVEL );
else
aNum.SetLevel( aNum.GetLevel() | NO_NUMLEVEL );
if( bOutline )
{
pTNd->UpdateOutlineNum( aNum );
GetNodes().UpdtOutlineIdx( *pTNd );
}
else
{
pTNd->UpdateNum( aNum );
#ifndef NUM_RELSPACE
pTNd->SetNumLSpace( TRUE );
#endif
((SwNumRule*)pRule)->SetInvalidRule( TRUE );
UpdateNumRule( pRule->GetName(), rIdx.GetIndex() );
}
bRet = TRUE;
SetModified();
}
return bRet;
}
SwNumRule* SwDoc::GetCurrNumRule( const SwPosition& rPos ) const
{
SwNumRule* pRet = 0;
const SfxPoolItem* pItem;
SwTxtNode* pTNd = rPos.nNode.GetNode().GetTxtNode();
if( pTNd && 0 != ( pItem = pTNd->GetNoCondAttr( RES_PARATR_NUMRULE, TRUE ) ) &&
((SwNumRuleItem*)pItem)->GetValue().Len() )
pRet = FindNumRulePtr( ((SwNumRuleItem*)pItem)->GetValue() );
return pRet;
}
USHORT SwDoc::FindNumRule( const String& rName ) const
{
for( USHORT n = pNumRuleTbl->Count(); n; )
if( (*pNumRuleTbl)[ --n ]->GetName() == rName )
return n;
/*
//JP 20.11.97: sollte man im Find neue Rule anlegen??
erstmal nicht
USHORT nPoolId = GetPoolId( rName, GET_POOLID_NUMRULE );
if( USHRT_MAX != nPoolId )
{
SwDoc* pThis = (SwDoc*)this;
SwNumRule* pR = pThis->GetNumRuleFromPool( nPoolId );
for( n = pNumRuleTbl->Count(); n; )
if( (*pNumRuleTbl)[ --n ] == pR )
return n;
}
*/
return USHRT_MAX;
}
SwNumRule* SwDoc::FindNumRulePtr( const String& rName ) const
{
for( USHORT n = pNumRuleTbl->Count(); n; )
if( (*pNumRuleTbl)[ --n ]->GetName() == rName )
return (*pNumRuleTbl)[ n ];
/*
//JP 20.11.97: sollte man im Find neue Rule anlegen??
erstmal nicht
USHORT nPoolId = GetPoolId( rName, GET_POOLID_NUMRULE );
if( USHRT_MAX != nPoolId )
{
SwDoc* pThis = (SwDoc*)this;
return pThis->GetNumRuleFromPool( nPoolId );
}
*/
return 0;
}
USHORT SwDoc::MakeNumRule( const String &rName, const SwNumRule* pCpy )
{
SwNumRule* pNew;
if( pCpy )
{
pNew = new SwNumRule( *pCpy );
pNew->SetName( GetUniqueNumRuleName( &rName ));
if( pNew->GetName() != rName )
{
pNew->SetPoolFmtId( USHRT_MAX );
pNew->SetPoolHelpId( USHRT_MAX );
pNew->SetPoolHlpFileId( UCHAR_MAX );
}
pNew->CheckCharFmts( this );
}
else
pNew = new SwNumRule( GetUniqueNumRuleName( &rName ) );
USHORT nRet = pNumRuleTbl->Count();
pNumRuleTbl->Insert( pNew, nRet );
return nRet;
}
String SwDoc::GetUniqueNumRuleName( const String* pChkStr, BOOL bAutoNum ) const
{
String aName;
if( bAutoNum )
{
long n = Time().GetTime();
n += Date().GetDate();
aName = String::CreateFromInt32( n );
if( pChkStr && !pChkStr->Len() )
pChkStr = 0;
}
else if( pChkStr && pChkStr->Len() )
aName = *pChkStr;
else
{
pChkStr = 0;
aName = SW_RESSTR( STR_NUMRULE_DEFNAME );
}
USHORT nNum, nTmp, nFlagSize = ( pNumRuleTbl->Count() / 8 ) +2;
BYTE* pSetFlags = new BYTE[ nFlagSize ];
memset( pSetFlags, 0, nFlagSize );
xub_StrLen nNmLen = aName.Len();
if( !bAutoNum && pChkStr )
{
while( nNmLen-- && '0' <= aName.GetChar( nNmLen ) &&
'9' >= aName.GetChar( nNmLen ) )
; //nop
if( ++nNmLen < aName.Len() )
{
aName.Erase( nNmLen );
pChkStr = 0;
}
}
const SwNumRule* pNumRule;
for( USHORT n = 0; n < pNumRuleTbl->Count(); ++n )
if( 0 != ( pNumRule = (*pNumRuleTbl)[ n ] ) )
{
const String& rNm = pNumRule->GetName();
if( rNm.Match( aName ) == nNmLen )
{
// Nummer bestimmen und das Flag setzen
nNum = rNm.Copy( nNmLen ).ToInt32();
if( nNum-- && nNum < pNumRuleTbl->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 = pNumRuleTbl->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 && pChkStr->Len() )
return *pChkStr;
return aName += String::CreateFromInt32( ++nNum );
}
const SwNode* lcl_FindBaseNode( const SwNode& rNd )
{
const SwNodes& rNds = rNd.GetNodes();
ULONG nNdIdx = rNd.GetIndex();
if( nNdIdx > rNds.GetEndOfExtras().GetIndex() )
return rNds.GetEndOfContent().FindStartNode();
const SwNode* pSttNd = rNds[ ULONG(0) ]->FindStartNode();
const SwNode* pNd = rNd.FindStartNode();
while( pSttNd != pNd->FindStartNode()->FindStartNode() )
pNd = pNd->FindStartNode();
return pNd;
}
void SwDoc::UpdateNumRule()
{
SwNumRuleTbl& rNmTbl = GetNumRuleTbl();
for( USHORT n = 0; n < rNmTbl.Count(); ++n )
if( rNmTbl[ n ]->IsInvalidRule() )
UpdateNumRule( rNmTbl[ n ]->GetName(), ULONG_MAX );
}
void SwDoc::UpdateNumRule( const String& rName, ULONG nUpdPos )
{
SwNumRuleInfo aUpd( rName );
aUpd.MakeList( *this );
if( ULONG_MAX == nUpdPos )
nUpdPos = 0;
else
aUpd.GetList().SearchKey( nUpdPos, &nUpdPos );
SwNumRule* pRule = FindNumRulePtr( rName );
if( nUpdPos < aUpd.GetList().Count() )
{
USHORT nInitLevels = USHRT_MAX; // Bitfeld fuer die Levels!
// TRUE: starte mit NumFmt Start
USHORT nNumVal = 0;
SwNodeNum aNum( 0 );
if( pRule->IsContinusNum() )
nNumVal = pRule->Get( 0 ).GetStartValue();
SwTxtNode* pStt = aUpd.GetList().GetObject( nUpdPos );
SwTxtNode* pPrev = nUpdPos ? aUpd.GetList().GetObject( nUpdPos-1 ) : 0;
const SwNode* pBaseNd = lcl_FindBaseNode( *pStt );
if( pPrev && lcl_FindBaseNode( *pPrev ) == pBaseNd )
{
if( pPrev->GetNum() )
{
const SwNodeNum* pPrevNdNum = pPrev->GetNum();
if( pPrevNdNum->GetLevel() & NO_NUMLEVEL )
{
BYTE nSrchLvl = GetRealLevel( pPrevNdNum->GetLevel() );
pPrevNdNum = 0;
ULONG nArrPos = nUpdPos-1;
while( nArrPos-- )
{
pPrev = aUpd.GetList().GetObject( nArrPos );
if( lcl_FindBaseNode( *pPrev ) != pBaseNd )
break;
if( 0 != ( pPrevNdNum = pPrev->GetNum() ))
{
// uebergeordnete Ebene
if( nSrchLvl > (pPrevNdNum->GetLevel() &~ NO_NUMLEVEL))
{
pPrevNdNum = 0;
break;
}
// gleiche Ebene und kein NO_NUMLEVEL
if( nSrchLvl == (pPrevNdNum->GetLevel() &~ NO_NUMLEVEL)
&& !( pPrevNdNum->GetLevel() & NO_NUMLEVEL ))
break;
pPrevNdNum = 0;
}
}
}
if( pPrevNdNum )
{
aNum = *pPrevNdNum;
aNum.SetStart( FALSE );
aNum.SetSetValue( USHRT_MAX );
}
}
nInitLevels = 0;
nNumVal = aNum.GetLevelVal()[ GetRealLevel( aNum.GetLevel() ) ];
}
const SwNode* pOutlNd = 0;
for( ; nUpdPos < aUpd.GetList().Count(); ++nUpdPos )
{
pStt = aUpd.GetList().GetObject( nUpdPos );
const SwNode* pTmpBaseNd = lcl_FindBaseNode( *pStt );
if( pTmpBaseNd != pBaseNd )
{
aNum.SetLevel( 0 );
memset( aNum.GetLevelVal(), 0,
(MAXLEVEL) * sizeof( aNum.GetLevelVal()[0]) );
pBaseNd = pTmpBaseNd;
}
BYTE nLevel = aNum.GetLevel();
BYTE nNdOldLvl = MAXLEVEL;
if( pStt->GetNum() )
{
if( NO_NUMBERING != pStt->GetNum()->GetLevel() )
nNdOldLvl = nLevel = pStt->GetNum()->GetLevel();
if( pStt->GetNum()->IsStart() )
{
aNum.SetStart( TRUE );
memset( aNum.GetLevelVal(), 0,
(MAXLEVEL) * sizeof( aNum.GetLevelVal()[0]) );
if( pRule->IsContinusNum() )
{
nNumVal = pRule->Get( 0 ).GetStartValue();
nInitLevels |= 1;
}
else
nInitLevels |= ( 1 << GetRealLevel( nLevel ));
}
else if( USHRT_MAX != pStt->GetNum()->GetSetValue() )
aNum.SetSetValue( nNumVal = pStt->GetNum()->GetSetValue() );
}
if( NO_NUMLEVEL & nLevel ) // NoNum mit Ebene
{
BYTE nPrevLvl = GetRealLevel( aNum.GetLevel() ),
nCurrLvl = GetRealLevel( nLevel );
if( nPrevLvl < nCurrLvl )
{
if( !(nInitLevels & ( 1 << nPrevLvl )) )
++nPrevLvl;
for( ; nPrevLvl < nCurrLvl; ++nPrevLvl )
nInitLevels |= ( 1 << nPrevLvl );
}
aNum.SetLevel( nLevel );
pStt->UpdateNum( aNum );
}
else if( NO_NUM != nLevel )
{
// beim Format mit Bitmap die Graphicen schon mal anfordern
const SwNumFmt* pNumFmt = pRule->GetNumFmt( GetRealLevel( nLevel ));
if( pNumFmt && SVX_NUM_BITMAP == pNumFmt->eType )
pNumFmt->GetGraphic();
if( pRule->IsContinusNum() )
{
if( !(nInitLevels & 1) &&
!( pNumFmt && (SVX_NUM_CHAR_SPECIAL == pNumFmt->eType ||
SVX_NUM_BITMAP == pNumFmt->eType ||
SVX_NUM_NUMBER_NONE == pNumFmt->eType )))
++nNumVal;
aNum.GetLevelVal()[ nLevel ] = nNumVal;
}
else
{
BYTE nPrevLvl = GetRealLevel( aNum.GetLevel() );
if( nPrevLvl < nLevel )
{
// Erfrage wie geloescht werden soll:
// z.B von Stufe 0 -> 1: 1 -> 0.1 ; wenn nStart = 1
// aber Stufe 1 -> 2: 1.1 -> 1.1.1 !!, nur 0.1 -> 0.0.1
if( !(nInitLevels & ( 1 << nPrevLvl )) )
++nPrevLvl;
for( int ii = nPrevLvl; ii < nLevel; ++ii )
{
nInitLevels &= ~( 1 << ii );
aNum.GetLevelVal()[ ii ] =
pRule->Get( ii ).GetStartValue();
}
aNum.GetLevelVal()[ nLevel ] =
USHRT_MAX == aNum.GetSetValue()
? pRule->Get( nLevel ).GetStartValue()
: aNum.GetSetValue();
}
else if( USHRT_MAX != aNum.GetSetValue() )
aNum.GetLevelVal()[ nLevel ] = aNum.GetSetValue();
else if( nInitLevels & ( 1 << nLevel ))
aNum.GetLevelVal()[ nLevel ] =
pRule->Get( nLevel ).GetStartValue();
else
aNum.GetLevelVal()[ nLevel ]++;
}
nInitLevels &= ~( 1 << nLevel );
aNum.SetLevel( nLevel );
pStt->UpdateNum( aNum );
}
//FEATURE::CONDCOLL
BOOL bCheck = TRUE;
if( RES_CONDTXTFMTCOLL == pStt->GetFmtColl()->Which() )
{
// SwFmtColl* pChgColl = pStt->GetCondFmtColl();
pStt->ChkCondColl();
/*
//JP 19.11.97:
// setzen der bedingten Vorlage aendert nichts an den Einzuegen, die bleiben
// als harte vorhanden
if( pStt->GetCondFmtColl() )
{
// es gab eine Aenderung -> harte Einzuege entfernen
if( pChgColl != pStt->GetCondFmtColl() )
pStt->ResetAttr( RES_LR_SPACE );
bCheck = FALSE;
}
*/
}
else if( !pOutlNd && NO_NUMBERING !=
((SwTxtFmtColl*)pStt->GetFmtColl())->GetOutlineLevel() )
pOutlNd = pStt;
//FEATURE::CONDCOLL
#ifndef NUM_RELSPACE
// hat sich eine Level - Aenderung ergeben, so setze jetzt die
// gueltigen Einzuege
if( bCheck && ( nLevel != nNdOldLvl || pStt->IsSetNumLSpace())
&& GetRealLevel( nLevel ) < MAXLEVEL )
{
SvxLRSpaceItem aLR( ((SvxLRSpaceItem&)pStt->SwCntntNode::GetAttr(
RES_LR_SPACE )) );
const SwNumFmt& rNFmt = pRule->Get( GetRealLevel( nLevel ));
// ohne Nummer immer ohne FirstLineOffset!!!!
short nFOfst = rNFmt.GetFirstLineOffset();
if( nLevel & NO_NUMLEVEL ) nFOfst = 0;
aLR.SetTxtFirstLineOfstValue( nFOfst );
aLR.SetTxtLeft( rNFmt.GetAbsLSpace() );
pStt->SwCntntNode::SetAttr( aLR );
}
// Flag immer loeschen!
pStt->SetNumLSpace( FALSE );
#endif
aNum.SetStart( FALSE );
aNum.SetSetValue( USHRT_MAX );
}
if( pOutlNd )
GetNodes().UpdtOutlineIdx( *pOutlNd );
}
ASSERT( pRule, "die NumRule sollte schon vorhanden sein!" );
if( pRule )
pRule->SetInvalidRule( FALSE );
}