/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * 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.
 *
 ************************************************************************/


#ifdef _MSC_VER
#pragma hdrstop
#endif

#include <osl/diagnose.h>


#include <horiornt.hxx>

#include <doc.hxx>
#include <ndtxt.hxx>
#include <fldbas.hxx>           // UpdateFlds der KapitelNummerierung
namespace binfilter {


//-------------------------------------------------------
// Gliederung

/*N*/ struct _OutlinePara
/*N*/ {
/*N*/   SwNodeNum aNum;
/*N*/   const SwNodes& rNds;
/*N*/   BYTE nMin, nNewLevel;
/*N*/     // array to remember, which level numbering has to be started.
/*N*/     bool aStartLevel[ MAXLEVEL ];
/*N*/
/*N*/   _OutlinePara( const SwNodes& rNodes, USHORT nSttPos, BYTE nOld, BYTE nNew );
/*N*/   BOOL UpdateOutline( SwTxtNode& rTxtNd );
/*N*/ };

/*N*/ _SV_IMPL_SORTAR_ALG( SwOutlineNodes, SwNodePtr )
/*N*/ BOOL SwOutlineNodes::Seek_Entry( const SwNodePtr rSrch, USHORT* pFndPos ) const
/*N*/ {
/*N*/   ULONG nIdx = rSrch->GetIndex();
/*N*/
/*N*/   register USHORT nO = Count(), nM, nU = 0;
/*N*/   if( nO > 0 )
/*N*/   {
/*N*/ // aufgrund des Bug 48592 - wo unter anderem nach Undo/Redo
/*N*/ //                Nodes aus dem falschen NodesArray im OutlineArray standen,
/*N*/ //                jetzt mal einen Check eingebaut.
/*N*/ #ifdef DBG_UTIL
/*N*/       {
/*N*/           for( register USHORT n = 1; n < nO; ++n )
/*N*/               if( &(*this)[ n-1 ]->GetNodes() !=
/*N*/                   &(*this)[ n ]->GetNodes() )
/*N*/               {
/*?*/                   OSL_ENSURE( !this, "Node im falschen Outline-Array" );
/*N*/               }
/*N*/       }
/*N*/ #endif
/*N*/
/*N*/       nO--;
/*N*/       while( nU <= nO )
/*N*/       {
/*N*/           nM = nU + ( nO - nU ) / 2;
/*N*/           if( (*this)[ nM ] == rSrch )
/*N*/           {
/*N*/               if( pFndPos )
/*N*/                   *pFndPos = nM;
/*N*/               return TRUE;
/*N*/           }
/*N*/           else if( (*this)[ nM ]->GetIndex() < nIdx )
/*N*/               nU = nM + 1;
/*N*/           else if( nM == 0 )
/*N*/           {
/*N*/               if( pFndPos )
/*N*/                   *pFndPos = nU;
/*N*/               return FALSE;
/*N*/           }
/*N*/           else
/*N*/               nO = nM - 1;
/*N*/       }
/*N*/   }
/*N*/   if( pFndPos )
/*N*/       *pFndPos = nU;
/*N*/   return FALSE;
/*N*/ }


/*N*/ _OutlinePara::_OutlinePara( const SwNodes& rNodes, USHORT nSttPos,
/*N*/                           BYTE nOld, BYTE nNew )
/*N*/   : aNum( NO_NUM > nNew ? nNew : 0 )
/*N*/   , rNds( rNodes )
/*N*/   , nMin( Min( nOld, nNew ))
/*N*/   , nNewLevel( nNew )
/*N*/ {
/*N*/     // init <aStartLevel[]> with defaults, only valid
/*N*/     // if update of outline numbering started at first outline numbering node.
/*N*/     for ( int i = 0; i < MAXLEVEL; ++i)
/*N*/         aStartLevel[i] = true;
/*N*/
/*N*/     // hole vom Vorgaenger die aktuelle Nummerierung
/*N*/   SwNode* pNd;
/*N*/   ULONG nEndOfExtras = rNds.GetEndOfExtras().GetIndex();
/*N*/     if ( nSttPos &&
/*N*/          (pNd = rNds.GetOutLineNds()[ --nSttPos ])->GetIndex() > nEndOfExtras &&
/*N*/          static_cast<SwTxtNode*>(pNd)->GetOutlineNum()
/*N*/        )
/*N*/   {
/*N*/       const SwNodeNum* pNum = ((SwTxtNode*)pNd)->GetOutlineNum();
/*N*/ #ifdef TASK_59308
/*N*/       if( pNum->GetLevel() & NO_NUMLEVEL )
/*N*/       {
/*N*/           // dann suche den mit richtigem Level:
/*N*/           BYTE nSrchLvl = aNum.GetLevel();
/*N*/           pNum = 0;
/*N*/           while( nSttPos-- )
/*N*/           {
/*N*/               if( ( pNd = rNds.GetOutLineNds()[ nSttPos ])->
/*N*/                   GetIndex() < nEndOfExtras )
/*N*/                   break;
/*N*/
/*N*/               if( 0 != ( pNum = ((SwTxtNode*)pNd)->GetOutlineNum() ))
/*N*/               {
/*N*/                   // uebergeordnete Ebene
/*N*/                   if( nSrchLvl > (pNum->GetLevel() &~ NO_NUMLEVEL ))
/*N*/                   {
/*N*/                       pNum = 0;
/*N*/                       break;
/*N*/                   }
/*N*/                   // gleiche Ebene und kein NO_NUMLEVEL
/*N*/                   if( nSrchLvl == (pNum->GetLevel() &~ NO_NUMLEVEL)
/*N*/                       && !( pNum->GetLevel() & NO_NUMLEVEL ))
/*N*/                       break;
/*N*/
/*N*/                   pNum = 0;
/*N*/               }
/*N*/           }
/*N*/       }
/*N*/
/*N*/ #endif
/*N*/       if( pNum )
/*N*/       {
/*N*/           aNum = *pNum;
/*N*/           aNum.SetStart( FALSE );
/*N*/           aNum.SetSetValue( USHRT_MAX );
/*N*/       }
/*N*/
/*N*/       if( aNum.GetLevel()+1 < MAXLEVEL )
/*N*/         {
/*N*/           memset( aNum.GetLevelVal() + (aNum.GetLevel()+1), 0,
/*N*/                   (MAXLEVEL - (aNum.GetLevel()+1)) * sizeof(aNum.GetLevelVal()[0]) );
/*N*/         }
/*N*/         // init array <aStartLevel[]>, not starting at first outline numbering node.
/*N*/         aStartLevel[ pNum->GetLevel() ] = false;
/*N*/         USHORT nHighestLevelFound = pNum->GetLevel();
/*N*/         while ( pNum->GetLevel() > 0 && nSttPos-- )
/*N*/         {
/*N*/             pNd = rNds.GetOutLineNds()[ nSttPos ];
/*N*/             if ( pNd->GetIndex() < nEndOfExtras )
/*N*/                 break;
/*N*/             pNum = static_cast<SwTxtNode*>(pNd)->GetOutlineNum();
/*N*/             if ( pNum && pNum->GetLevel() < nHighestLevelFound )
/*N*/             {
/*N*/                 aStartLevel[ pNum->GetLevel() ] = false;
/*N*/                 nHighestLevelFound = pNum->GetLevel();
/*N*/             }
/*N*/         }
/*N*/   }
/*N*/ }

/*N*/ BOOL _OutlinePara::UpdateOutline( SwTxtNode& rTxtNd )
/*N*/ {
/*N*/     // alle die ausserhalb des Fliesstextes liegen, NO_NUM zuweisen.
/*N*/   if( rTxtNd.GetIndex() < rNds.GetEndOfExtras().GetIndex() )
/*N*/   {
/*N*/       BYTE nTmpLevel = aNum.GetLevel();
/*N*/       aNum.SetLevel( NO_NUM );
/*N*/       rTxtNd.UpdateOutlineNum( aNum );
/*N*/       aNum.SetLevel( nTmpLevel );
/*N*/       return TRUE;
/*N*/   }
/*N*/
/*N*/   BYTE nLevel = rTxtNd.GetTxtColl()->GetOutlineLevel();
/*N*/   BOOL bRet = !(nMin > nLevel);
/*N*/   if( bRet )
/*N*/   {
/*N*/       // existierte am Node schon eine Nummerierung ??
/*N*/       // dann erfrage den "User definierten Wert"
/*N*/       USHORT nSetValue;
/*N*/       const SwNumRule* pOutlRule = rTxtNd.GetDoc()->GetOutlineNumRule();
/*N*/       const SwNodeNum* pOutlNum = rTxtNd.GetOutlineNum();
/*N*/
/*N*/ #ifdef TASK_59308
/*N*/       if( pOutlNum && ( pOutlNum->GetLevel() & NO_NUMLEVEL ) &&
/*N*/           GetRealLevel( pOutlNum->GetLevel() ) == nLevel )
/*N*/       {
/*N*/           // diesen nicht mit numerieren
/*N*/           BYTE nTmpLevel = aNum.GetLevel();
/*N*/           aNum.SetLevel( pOutlNum->GetLevel() );
/*N*/           rTxtNd.UpdateOutlineNum( aNum );
/*N*/           aNum.SetLevel( nTmpLevel );
/*N*/           return TRUE;
/*N*/       }
/*N*/ #endif
/*N*/
/*N*/         // determine, if level numbering has to be started.
/*N*/         // correct outline numbering, even for the first heading.
/*N*/         // Thus, state of <aStartLevel[]> always has to be
/*N*/         // consulted, not only on level change.
/*N*/         if( aStartLevel[ nLevel ] )
/*N*/       {
/*N*/           nSetValue= pOutlRule->Get( nLevel ).GetStart();
/*N*/             // reset <aStartLevel[nLevel]>
/*N*/             aStartLevel[ nLevel ] = false;
/*N*/       }
/*N*/       else
/*N*/           nSetValue = aNum.GetLevelVal()[ nLevel ] + 1;
/*N*/
/*N*/        // alle unter dem neuen Level liegenden auf 0 setzen
/*N*/       if( aNum.GetLevel() > nLevel && nLevel+1 < MAXLEVEL
/*N*/           /* ??? && NO_NUM > nNewLevel */ )
/*N*/         {
/*N*/           memset( aNum.GetLevelVal() + (nLevel+1), 0,
/*N*/                   (MAXLEVEL - ( nLevel+1 )) * sizeof(aNum.GetLevelVal()[0]) );
/*N*/             // all next level numberings have to be started.
/*N*/             for ( int i = nLevel+1; i < MAXLEVEL; ++i)
/*N*/                 aStartLevel[i] = true;
/*N*/         }
/*N*/
/*N*/       if( pOutlNum && USHRT_MAX != pOutlNum->GetSetValue() )
/*N*/           aNum.SetSetValue( nSetValue = pOutlNum->GetSetValue() );
/*N*/
/*N*/       aNum.GetLevelVal()[ nLevel ] = nSetValue;
/*N*/       aNum.SetLevel( nLevel );
/*N*/       rTxtNd.UpdateOutlineNum( aNum );
/*N*/       aNum.SetSetValue( USHRT_MAX );
/*N*/   }
/*N*/   return bRet;
/*N*/ }




/*N*/ BOOL lcl_UpdateOutline( const SwNodePtr& rpNd, void* pPara )
/*N*/ {
/*N*/   _OutlinePara* pOutlPara = (_OutlinePara*)pPara;
/*N*/   SwTxtNode* pTxtNd = rpNd->GetTxtNode();
/*N*/   OSL_ENSURE( pTxtNd, "kein TextNode als OutlineNode !" );
/*N*/
/*N*/   return pOutlPara->UpdateOutline( *pTxtNd );
/*N*/ }




/*N*/ void SwNodes::UpdateOutlineNode( const SwNode& rNd, BYTE nOldLevel,
/*N*/                               BYTE nNewLevel )
/*N*/ {
/*N*/   const SwNodePtr pSrch = (SwNodePtr)&rNd;
/*N*/   USHORT nSttPos;
/*N*/   BOOL bSeekIdx = pOutlineNds->Seek_Entry( pSrch, &nSttPos );
/*N*/
/*N*/   if( NO_NUMBERING == nOldLevel )         // neuen Level einfuegen
/*N*/   {
/*N*/       // nicht vorhanden, also einfuegen
/*N*/       OSL_ENSURE( !bSeekIdx, "Der Node ist schon als OutlineNode vorhanden" );
/*N*/
/*N*/       //JP 12.03.99: 63293 - Nodes vom RedlineBereich NIE aufnehmen
/*N*/       ULONG nNd = rNd.GetIndex();
/*N*/       if( nNd < GetEndOfRedlines().GetIndex() &&
/*N*/           nNd > GetEndOfRedlines().FindStartNode()->GetIndex() )
/*?*/           return ;
/*N*/
/*N*/       // jetzt noch alle nachfolgende Outline-Nodes updaten
/*N*/       pOutlineNds->Insert( pSrch );
/*N*/       if( NO_NUM <= nNewLevel )
/*?*/           return;     // keine Nummerierung dann kein Update
/*N*/   }
/*N*/   else if( NO_NUMBERING == nNewLevel )    // Level entfernen
/*N*/   {
/*?*/       if( !bSeekIdx )
/*?*/           return;
/*?*/
/*?*/       // jetzt noch alle nachfolgende Outline-Nodes updaten
/*?*/       pOutlineNds->Remove( nSttPos );
/*?*/       if( NO_NUM <= nOldLevel )
/*?*/           return;     // keine Nummerierung dann kein Update
/*N*/   }
/*N*/   else if( !bSeekIdx )        // Update und Index nicht gefunden ??
/*?*/       return ;
/*N*/
/*N*/   _OutlinePara aPara( *this, nSttPos, nOldLevel, nNewLevel );
/*N*/   pOutlineNds->ForEach( nSttPos, pOutlineNds->Count(),
/*N*/                       lcl_UpdateOutline, &aPara );
/*N*/
/*N*/ //FEATURE::CONDCOLL
/*N*/   {
/*N*/       SwCntntNode* pCNd;
/*N*/       ULONG nSttNd = rNd.GetIndex();
/*N*/       if( NO_NUMBERING != nNewLevel )
/*N*/           ++nSttPos;
/*N*/
/*N*/       ULONG nChkCount = ( nSttPos < pOutlineNds->Count()
/*N*/                               ? (*pOutlineNds)[ nSttPos ]->GetIndex()
/*N*/                               : GetEndOfContent().GetIndex()  )
/*N*/                           - nSttNd;
/*N*/       for( ; nChkCount--; ++nSttNd )
/*N*/           if( 0 != (pCNd = (*this)[ nSttNd ]->GetCntntNode() ) &&
/*N*/               RES_CONDTXTFMTCOLL == pCNd->GetFmtColl()->Which() )
/*N*/               pCNd->ChkCondColl();
/*N*/   }
/*N*/ //FEATURE::CONDCOLL
/*N*/
/*N*/   // die Gliederungs-Felder Updaten
/*N*/   GetDoc()->GetSysFldType( RES_CHAPTERFLD )->UpdateFlds();
/*N*/ }



/*N*/ void SwNodes::UpdtOutlineIdx( const SwNode& rNd )
/*N*/ {
/*N*/   if( !pOutlineNds->Count() )     // keine OutlineNodes vorhanden ?
/*N*/       return;
/*N*/
/*N*/   const SwNodePtr pSrch = (SwNodePtr)&rNd;
/*N*/   USHORT nPos;
/*N*/   pOutlineNds->Seek_Entry( pSrch, &nPos );
/*N*/   if( nPos == pOutlineNds->Count() )      // keine zum Updaten vorhanden ?
/*N*/       return;
/*N*/
/*N*/   if( nPos )
/*N*/       --nPos;
/*N*/
/*N*/   if( !GetDoc()->IsInDtor() && IsDocNodes() )
/*N*/       UpdateOutlineNode( *(*pOutlineNds)[ nPos ], 0, 0 );
/*N*/ }



/*N*/ void SwNodes::UpdateOutlineNodes()
/*N*/ {
/*N*/   if( pOutlineNds->Count() )      // OutlineNodes vorhanden ?
/*N*/       UpdateOutlineNode( *(*pOutlineNds)[ 0 ], 0, 0 );
/*N*/ }

}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
