Logo Search packages:      
Sourcecode: abiword version File versions

fl_SectionLayout.cpp

/* AbiWord
 * Copyright (C) 1998 AbiSource, Inc.
 * Copyright (C) 2002 Martin Sevior (msevior@physics.unimelb.edu.au>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 */

#include <string.h>
#include <stdlib.h>

#include "ut_types.h"
#include "ut_string.h"

#include "ap_Prefs.h"
#include "fl_SectionLayout.h"
#include "fl_FootnoteLayout.h"
#include "fl_Layout.h"
#include "fl_DocLayout.h"
#include "fl_TOCLayout.h"
#include "fl_BlockLayout.h"
#include "fl_TableLayout.h"
#include "fp_TableContainer.h"
#include "fb_LineBreaker.h"
#include "fb_ColumnBreaker.h"
#include "fp_FootnoteContainer.h"
#include "fp_TOCContainer.h"
#include "fp_Page.h"
#include "fp_Line.h"
#include "fp_Column.h"
#include "pd_Document.h"
#include "pp_AttrProp.h"
#include "gr_Graphics.h"
#include "pp_Property.h"
#include "px_ChangeRecord.h"
#include "px_CR_Object.h"
#include "px_CR_ObjectChange.h"
#include "px_CR_Span.h"
#include "px_CR_SpanChange.h"
#include "px_CR_Strux.h"
#include "px_CR_StruxChange.h"
#include "px_CR_Glob.h"
#include "fv_View.h"
#include "fp_Run.h"
#include "ut_debugmsg.h"
#include "ut_assert.h"
#include "ut_units.h"
#include "fg_Graphic.h"
#include "pt_Types.h"
/*
  TODO this file is now really too long.  divide it up
  into smaller ones.
*/

fl_SectionLayout::fl_SectionLayout(FL_DocLayout* pLayout, PL_StruxDocHandle sdh, PT_AttrPropIndex indexAP, SectionType iType, fl_ContainerType iCType, PTStruxType iStrux, fl_ContainerLayout * pMyContainerLayout)
      : fl_ContainerLayout(pMyContainerLayout, sdh, indexAP,iStrux, iCType),
        m_iType(iType),
        m_pLayout(pLayout),
        m_bIsCollapsed(true),
        m_bNeedsReformat(true),
        m_bNeedsRedraw(true), 
        m_pGraphicImage(NULL),
        m_pImageImage(NULL),
        m_iGraphicTick(0),
        m_iDocImageWidth(0),
        m_iDocImageHeight(0)

{
      UT_ASSERT(pLayout);
      m_pDoc = pLayout->getDocument();
}

fl_SectionLayout::~fl_SectionLayout()
{
      DELETEP(m_pGraphicImage);
      DELETEP(m_pImageImage);
}

FL_DocLayout* fl_SectionLayout::getDocLayout(void) const
{
      if(m_pLayout == NULL)
      {
            return fl_ContainerLayout::getDocLayout();
      }
      return m_pLayout;
}

bool fl_SectionLayout::recalculateFields(UT_uint32 iUpdateCount)
{
      bool bResult = false;

      fl_ContainerLayout*     pL = getFirstLayout();

      while (pL)
      {
            bResult = pL->recalculateFields(iUpdateCount) || bResult;

            pL = pL->getNext();
      }

      return bResult;
}


void fl_SectionLayout::markAllRunsDirty(void)
{
      fl_ContainerLayout*     pL = getFirstLayout();
      while (pL)
      {
            pL->markAllRunsDirty();
            pL = pL->getNext();
      }
}

void fl_SectionLayout::_purgeLayout()
{
      fl_ContainerLayout*     pL = getLastLayout();

      while (pL)
      {
            fl_ContainerLayout* pNuke = pL;

            pL = pL->getPrev();
            pNuke->setNext(NULL);
            delete pNuke;
      }

      return;
}

void fl_SectionLayout::setNeedsReformat(UT_uint32 /*offset*/)
{
      m_bNeedsReformat = true;
      if(myContainingLayout() != NULL && static_cast<fl_SectionLayout *>(myContainingLayout()) != this)
      {
            static_cast<fl_SectionLayout *>(myContainingLayout())->setNeedsReformat();
      }
      if(getContainerType() == FL_CONTAINER_SHADOW)
      {
            fl_HdrFtrShadow * pShad = static_cast<fl_HdrFtrShadow *>(this);
            pShad->getHdrFtrSectionLayout()->setNeedsReformat(0);
      }
}


void fl_SectionLayout::setNeedsRedraw(void)
{
      m_bNeedsRedraw = true;
      if(myContainingLayout() != NULL  && static_cast<fl_SectionLayout *>(myContainingLayout()) != this)
      {
            static_cast<fl_SectionLayout *>(myContainingLayout())->setNeedsRedraw();
      }
}

bool fl_SectionLayout::bl_doclistener_populateSpan(fl_ContainerLayout* pBL, const PX_ChangeRecord_Span * pcrs, PT_BlockOffset blockOffset, UT_uint32 len)
{
    fl_HdrFtrSectionLayout * pHFSL = getHdrFtrLayout();
      if(pBL->getPrev()!= NULL && pBL->getPrev()->getLastContainer()==NULL)
      {
            UT_DEBUGMSG(("In bl_doclistner_pop no LastLine \n"));
            UT_DEBUGMSG(("getPrev = %d this = %d \n",pBL->getPrev(),pBL));
            //  UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
      }
      bool bres = true;
      if(pHFSL)
      {
            if(pBL)
            {
                  bres = pHFSL->bl_doclistener_populateSpan(pBL,pcrs,blockOffset,len);
            }
            else
            {
                  return false;
            }
            return bres;
      }

      return static_cast<fl_BlockLayout *>(pBL)->doclistener_populateSpan(pcrs, blockOffset, len);
}

bool fl_SectionLayout::bl_doclistener_populateObject(fl_ContainerLayout* pBL, PT_BlockOffset blockOffset, const PX_ChangeRecord_Object * pcro)
{
    fl_HdrFtrSectionLayout * pHFSL = getHdrFtrLayout();
      bool bres = true;
      if(pHFSL)
      {
            if(pBL)
            {
                  bres = pHFSL->bl_doclistener_populateObject(pBL,blockOffset,pcro);
            }
            else
            {
                  return false;
            }
            return bres;
      }
      return static_cast<fl_BlockLayout *>(pBL)->doclistener_populateObject(blockOffset, pcro);
}

bool fl_SectionLayout::bl_doclistener_insertSpan(fl_ContainerLayout* pBL, const PX_ChangeRecord_Span * pcrs)
{
    fl_HdrFtrSectionLayout * pHFSL = getHdrFtrLayout();
      bool bres = true;
      if(pHFSL)
      {
            if(pBL)
            {
                  bres = pHFSL->bl_doclistener_insertSpan(pBL,pcrs);
            }
            else
            {
                  return false;
            }
            pHFSL->checkAndAdjustCellSize(this);
            return bres;
      }
    bres = static_cast<fl_BlockLayout *>(pBL)->doclistener_insertSpan(pcrs);
      checkAndAdjustCellSize();
      return bres;
}

bool fl_SectionLayout::bl_doclistener_deleteSpan(fl_ContainerLayout* pBL, const PX_ChangeRecord_Span * pcrs)
{
    fl_HdrFtrSectionLayout * pHFSL = getHdrFtrLayout();
      bool bres = true;
      if(pHFSL)
      {
            if(pBL)
            {
                  bres = pHFSL->bl_doclistener_deleteSpan(pBL,pcrs);
            }
            else
            {
                  return false;
            }
            pHFSL->checkAndAdjustCellSize(this);
            return bres;
      }
      bres = static_cast<fl_BlockLayout *>(pBL)->doclistener_deleteSpan(pcrs);
      checkAndAdjustCellSize();
      return bres;
}

bool fl_SectionLayout::bl_doclistener_changeSpan(fl_ContainerLayout* pBL, const PX_ChangeRecord_SpanChange * pcrsc)
{
    fl_HdrFtrSectionLayout * pHFSL = getHdrFtrLayout();
      bool bres = true;
      if(pHFSL)
      {
            if(pBL)
            {
                  bres = pHFSL->bl_doclistener_changeSpan(pBL,pcrsc);
            }
            else
            {
                  return false;
            }
            pHFSL->checkAndAdjustCellSize(this);
            return bres;
      }
      bres = static_cast<fl_BlockLayout *>(pBL)->doclistener_changeSpan(pcrsc);
      checkAndAdjustCellSize();
      return bres;
}

bool fl_SectionLayout::bl_doclistener_deleteStrux(fl_ContainerLayout* pBL, const PX_ChangeRecord_Strux * pcrx)
{
    fl_HdrFtrSectionLayout * pHFSL = getHdrFtrLayout();
      bool bres = true;
      if(pHFSL)
      {
            if(pBL)
            {
                  bres = pHFSL->bl_doclistener_deleteStrux(pBL,pcrx);
            }
            else
            {
                  return false;
            }
            pHFSL->checkAndAdjustCellSize(this);
            return bres;
      }
      bres = static_cast<fl_BlockLayout *>(pBL)->doclistener_deleteStrux(pcrx);
      checkAndAdjustCellSize();
      return bres;
}

bool fl_SectionLayout::bl_doclistener_changeStrux(fl_ContainerLayout* pBL, const PX_ChangeRecord_StruxChange * pcrxc)
{
    fl_HdrFtrSectionLayout * pHFSL = getHdrFtrLayout();
      bool bres = true;
      if(pHFSL)
      {
            if(pBL)
            {
                  bres = pHFSL->bl_doclistener_changeStrux(pBL,pcrxc);
            }
            else
            {
                  return false;
            }
            pHFSL->checkAndAdjustCellSize(this);
            return bres;
      }
      bres = static_cast<fl_BlockLayout *>(pBL)->doclistener_changeStrux(pcrxc);
      checkAndAdjustCellSize();
      return bres;
}

bool fl_SectionLayout::bl_doclistener_insertBlock(fl_ContainerLayout* pBL, const PX_ChangeRecord_Strux * pcrx,
                                                                          PL_StruxDocHandle sdh,
                                                                          PL_ListenerId lid,
                                                                          void (* pfnBindHandles)(PL_StruxDocHandle sdhNew,
                                                                                                              PL_ListenerId lid,
                                                                                                              PL_StruxFmtHandle sfhNew))
{
    fl_HdrFtrSectionLayout * pHFSL = getHdrFtrLayout();
      bool bres = true;
      FV_View * pView = NULL;
      UT_ASSERT(m_pDoc->getAllowChangeInsPoint());
      if(pHFSL)
      {
            if(pBL)
            {
                  pHFSL->bl_doclistener_insertBlock(pBL,pcrx, sdh, lid, pfnBindHandles);
            }
            else
            {
                  pView = m_pLayout->getView();
                  // Insert the block at the beginning of the section
                  fl_BlockLayout*   pNewBL = static_cast<fl_BlockLayout *>(insert(sdh, NULL, pcrx->getIndexAP(),FL_CONTAINER_BLOCK));
                  if (!pNewBL)
                  {
                        UT_DEBUGMSG(("no memory for BlockLayout\n"));
                        return false;
                  }
                  bres = pNewBL->doclistener_insertFirstBlock(pcrx, sdh,
                                                                              lid, pfnBindHandles);               // Insert the block at the beginning of the section in the HDrFtr
            // Typically a cell of a table
                  bres = pHFSL->bl_doclistener_insertFirstBlock(this,pcrx, sdh, lid);
            }
            pHFSL->checkAndAdjustCellSize(this);
            UT_ASSERT(m_pDoc->getAllowChangeInsPoint());
            return bres;
      }
      if (pBL)
            return static_cast<fl_BlockLayout *>(pBL)->doclistener_insertBlock(pcrx, sdh, lid, pfnBindHandles);
      else
      {
            // Insert the block at the beginning of the section
            fl_BlockLayout*   pNewBL = static_cast<fl_BlockLayout *>(insert(sdh, NULL, pcrx->getIndexAP(),FL_CONTAINER_BLOCK));
            if (!pNewBL)
            {
                  UT_DEBUGMSG(("no memory for BlockLayout\n"));
                  return false;
            }
            UT_ASSERT(m_pDoc->getAllowChangeInsPoint());
            return pNewBL->doclistener_insertFirstBlock(pcrx, sdh,
                                                                              lid, pfnBindHandles);

      }
}

void fl_SectionLayout::checkAndAdjustCellSize(void)
{
      if(getContainerType() != FL_CONTAINER_CELL)
      {
            return;
      }     
      fl_CellLayout * pCell = static_cast<fl_CellLayout *>(this);
      pCell->checkAndAdjustCellSize();
}

bool fl_SectionLayout::bl_doclistener_insertSection(fl_ContainerLayout* pPrevL,
                                                                              SectionType iType,
                                                                              const PX_ChangeRecord_Strux * pcrx,
                                                                              PL_StruxDocHandle sdh,
                                                                              PL_ListenerId lid,
                                                                              void (* pfnBindHandles)(PL_StruxDocHandle sdhNew,
                                                                                                                  PL_ListenerId lid,
                                                                                                                  PL_StruxFmtHandle sfhNew))
{
      if(pPrevL->getContainerType() == FL_CONTAINER_BLOCK)
      {
            bool bres = static_cast<fl_BlockLayout *>(pPrevL)->doclistener_insertSection(pcrx, iType, sdh, lid, pfnBindHandles);
            return bres;
      }
      else if(iType == FL_SECTION_TOC)
      {
            PT_AttrPropIndex indexAP = pcrx->getIndexAP();
            fl_SectionLayout * pSL = static_cast<fl_SectionLayout *>(insert(sdh,pPrevL,indexAP, FL_CONTAINER_TOC));

            // Must call the bind function to complete the exchange of handles
            // with the document (piece table) *** before *** anything tries
            // to call down into the document (like all of the view
            // listeners).

            PL_StruxFmtHandle sfhNew = static_cast<PL_StruxFmtHandle>(pSL);
            //
            // Don't bind to shadows
            //
            if(pfnBindHandles)
            {
                  pfnBindHandles(sdh,lid,sfhNew);
            }
            //
            // That's all we need to do except update the view pointers I guess..
            //
            FV_View* pView = m_pLayout->getView();
            if (pView && (pView->isActive() || pView->isPreview()))
            {
                  pView->setPoint(pcrx->getPosition() + fl_BLOCK_STRUX_OFFSET);
            }
            else if(pView && pView->getPoint() > pcrx->getPosition())
            {
                  //
                  // For EndTOC
                  //
                  pView->setPoint(pView->getPoint() + fl_BLOCK_STRUX_OFFSET + fl_BLOCK_STRUX_OFFSET);
            }
            return true;

      }
      else if(((pPrevL->getContainerType() == FL_CONTAINER_FRAME) ||(pPrevL->getContainerType() == FL_CONTAINER_TABLE)) && (iType == FL_SECTION_HDRFTR))
      {
            fl_SectionLayout * pSL = new fl_HdrFtrSectionLayout(FL_HDRFTR_NONE,m_pLayout,NULL, sdh, pcrx->getIndexAP());
            fl_HdrFtrSectionLayout * pHFSL = static_cast<fl_HdrFtrSectionLayout *>(pSL);
            m_pLayout->addHdrFtrSection(pHFSL);
//
// Need to find the DocSectionLayout associated with this.
//
            const PP_AttrProp* pHFAP = NULL;
            PT_AttrPropIndex indexAP = pcrx->getIndexAP();
            bool bres = (m_pDoc->getAttrProp(indexAP, &pHFAP) && pHFAP);
            UT_ASSERT(bres);
            const XML_Char* pszNewID = NULL;
            pHFAP->getAttribute("id", pszNewID);
//
// pszHFID may not be defined yet. If not we can't do this stuff. If it is defined
// this step is essential
//
            if(pszNewID)
            {
              // plam mystery code
                  // plam, MES here, I need this code for inserting headers/footers.
              UT_DEBUGMSG(("new id: tell plam if you see this message\n"));
//            UT_ASSERT(0);
                  fl_DocSectionLayout* pDocSL = m_pLayout->findSectionForHdrFtr(static_cast<const char*>(pszNewID));
                  UT_ASSERT(pDocSL);
//
// Determine if this is a header or a footer.
//
                  const XML_Char* pszSectionType = NULL;
                  pHFAP->getAttribute("type", pszSectionType);

                  HdrFtrType hfType = FL_HDRFTR_NONE;
                  if (pszSectionType && *pszSectionType)
                  {
                        if(UT_strcmp(pszSectionType,"header") == 0)
                              hfType = FL_HDRFTR_HEADER;
                        else if (UT_strcmp(pszSectionType,"header-even") == 0)
                              hfType = FL_HDRFTR_HEADER_EVEN;
                        else if (UT_strcmp(pszSectionType,"header-first") == 0)
                              hfType = FL_HDRFTR_HEADER_FIRST;
                        else if (UT_strcmp(pszSectionType,"header-last") == 0)
                              hfType = FL_HDRFTR_HEADER_LAST;
                        else if (UT_strcmp(pszSectionType,"footer") == 0)
                              hfType = FL_HDRFTR_FOOTER;
                        else if (UT_strcmp(pszSectionType,"footer-even") == 0)
                              hfType = FL_HDRFTR_FOOTER_EVEN;
                        else if (UT_strcmp(pszSectionType,"footer-first") == 0)
                              hfType = FL_HDRFTR_FOOTER_FIRST;
                        else if (UT_strcmp(pszSectionType,"footer-last") == 0)
                              hfType = FL_HDRFTR_FOOTER_LAST;

                        if(hfType != FL_HDRFTR_NONE)
                        {
                              pHFSL->setDocSectionLayout(pDocSL);
                              pHFSL->setHdrFtr(hfType);
                              //
                              // Set the pointers to this header/footer
                              //
                              pDocSL->setHdrFtr(hfType, pHFSL);
                        }
                  }
            }
            else
            {
                  UT_DEBUGMSG(("NO ID found with insertSection HdrFtr \n"));
            }

      // Must call the bind function to complete the exchange of handles
      // with the document (piece table) *** before *** anything tries
      // to call down into the document (like all of the view
      // listeners).

            PL_StruxFmtHandle sfhNew = static_cast<PL_StruxFmtHandle>(pSL);
            //
            // Don't bind to shadows
            //
            if(pfnBindHandles)
            {
                  pfnBindHandles(sdh,lid,sfhNew);
            }

            fl_SectionLayout* pOldSL = getDocSectionLayout();
//
// Now move all the containers following into the new section
//
            fl_ContainerLayout* pCL = pPrevL->getNext();
      //
      // BUT!!! Don't move the immediate Footnotes or Endnotes
      //
            fl_ContainerLayout * pLastCL = pPrevL;

            while(pCL && (static_cast<fl_SectionLayout *>(pCL) == pSL))
            {
                  pCL = pCL->getNext();
            }
            while(pCL && ((pCL->getContainerType() == FL_CONTAINER_FOOTNOTE) ||
                                (pCL->getContainerType() == FL_CONTAINER_ENDNOTE)))
            {
                  pLastCL = pCL;
                  pCL = pCL->getNext();
            }
            fl_BlockLayout * pBL = NULL;
            while (pCL)
            {
                  fl_ContainerLayout* pNext = pCL->getNext();
                  pBL = NULL;
                  pCL->collapse();
                  if(pCL->getContainerType()==FL_CONTAINER_BLOCK)
                  {
                        pBL = static_cast<fl_BlockLayout *>(pCL);
                  } 
                  if(pBL && pBL->isHdrFtr())
                  {
                        fl_HdrFtrSectionLayout * pHF = static_cast<fl_HdrFtrSectionLayout *>(pBL->getSectionLayout());
                        pHF->collapseBlock(pBL);
                  }
                  pOldSL->remove(pCL);
                  pSL->add(pCL);
                  if(pBL)
                  {
                        pBL->setSectionLayout( pSL);
                        pBL->setNeedsReformat(0);
                  }
                  pCL = pNext;
            }

//
// Terminate blocklist here. This Block is the last in this section.
//
            if (pLastCL)
            {
                  pLastCL->setNext(NULL);
                  pOldSL->setLastLayout(pLastCL);
            }
            if(pszNewID)
            {
                  pSL->format();
                  pSL->redrawUpdate();
            }
            else
                  return true;

            FV_View* pView = m_pLayout->getView();
            if (pView && (pView->isActive() || pView->isPreview()))
            {
                  pView->setPoint(pcrx->getPosition() + fl_BLOCK_STRUX_OFFSET + fl_BLOCK_STRUX_OFFSET);
            }
            else if(pView && pView->getPoint() > pcrx->getPosition())
            {
                  pView->setPoint(pView->getPoint() + fl_BLOCK_STRUX_OFFSET + fl_BLOCK_STRUX_OFFSET);
            }
            return true;
      }
      return false;
}


fl_SectionLayout * fl_SectionLayout::bl_doclistener_insertTable(fl_ContainerLayout* pBL,
                                                                              SectionType iType,
                                                                              const PX_ChangeRecord_Strux * pcrx,
                                                                              PL_StruxDocHandle sdh,
                                                                              PL_ListenerId lid,
                                                                              void (* pfnBindHandles)(PL_StruxDocHandle sdhNew,
                                                                                                                  PL_ListenerId lid,
                                                                                                                  PL_StruxFmtHandle sfhNew))
{
      fl_SectionLayout * pSL = static_cast<fl_BlockLayout *>(pBL)->doclistener_insertTable(pcrx, iType, sdh, lid, pfnBindHandles);
      checkAndAdjustCellSize();
      return pSL;
}


fl_SectionLayout * fl_SectionLayout::bl_doclistener_insertFrame(fl_ContainerLayout* pBL,
                                                                              SectionType iType,
                                                                              const PX_ChangeRecord_Strux * pcrx,
                                                                              PL_StruxDocHandle sdh,
                                                                              PL_ListenerId lid,
                                                                              void (* pfnBindHandles)(PL_StruxDocHandle sdhNew,
                                                                                                                  PL_ListenerId lid,
                                                                                                                  PL_StruxFmtHandle sfhNew))
{
      fl_SectionLayout * pSL = static_cast<fl_BlockLayout *>(pBL)->doclistener_insertFrame(pcrx, iType, sdh, lid, pfnBindHandles);
      return pSL;
}

bool fl_SectionLayout::bl_doclistener_insertObject(fl_ContainerLayout* pBL, const PX_ChangeRecord_Object * pcro)
{
    fl_HdrFtrSectionLayout * pHFSL = getHdrFtrLayout();
      bool bres = true;
      if(pHFSL)
      {
            if(pBL)
            {
                  bres = pHFSL->bl_doclistener_insertObject(pBL,pcro);
            }
            else
            {
                  return false;
            }
            pHFSL->checkAndAdjustCellSize(this);
            return bres;
      }
      bres = static_cast<fl_BlockLayout *>(pBL)->doclistener_insertObject(pcro);
      checkAndAdjustCellSize();
      return bres;
}

bool fl_SectionLayout::bl_doclistener_deleteObject(fl_ContainerLayout* pBL, const PX_ChangeRecord_Object * pcro)
{
    fl_HdrFtrSectionLayout * pHFSL = getHdrFtrLayout();
      bool bres = true;
      if(pHFSL)
      {
            if(pBL)
            {
                  bres = pHFSL->bl_doclistener_deleteObject(pBL,pcro);
            }
            else
            {
                  return false;
            }
            pHFSL->checkAndAdjustCellSize(this);
            return bres;
      }
      bres = static_cast<fl_BlockLayout *>(pBL)->doclistener_deleteObject(pcro);
      checkAndAdjustCellSize();
      return bres;
}

bool fl_SectionLayout::bl_doclistener_changeObject(fl_ContainerLayout* pBL, const PX_ChangeRecord_ObjectChange * pcroc)
{
    fl_HdrFtrSectionLayout * pHFSL = getHdrFtrLayout();
      bool bres = true;
      if(pHFSL)
      {
            if(pBL)
            {
                  bres = pHFSL->bl_doclistener_changeObject(pBL,pcroc);
            }
            else
            {
                  return false;
            }
            pHFSL->checkAndAdjustCellSize(this);
            return bres;
      }

      bres = static_cast<fl_BlockLayout *>(pBL)->doclistener_changeObject(pcroc);
      checkAndAdjustCellSize();
      return bres;
}

bool fl_SectionLayout::bl_doclistener_insertFmtMark(fl_ContainerLayout* pBL, const PX_ChangeRecord_FmtMark * pcrfm)
{
    fl_HdrFtrSectionLayout * pHFSL = getHdrFtrLayout();
      bool bres = true;
      if(pHFSL)
      {
            if(pBL)
            {
                  bres = pHFSL->bl_doclistener_insertFmtMark(pBL,pcrfm);
            }
            else
            {
                  return false;
            }
            pHFSL->checkAndAdjustCellSize(this);
            return bres;
      }
      bres = static_cast<fl_BlockLayout *>(pBL)->doclistener_insertFmtMark(pcrfm);
      checkAndAdjustCellSize();
      return bres;
}

bool fl_SectionLayout::bl_doclistener_deleteFmtMark(fl_ContainerLayout* pBL, const PX_ChangeRecord_FmtMark * pcrfm)
{
    fl_HdrFtrSectionLayout * pHFSL = getHdrFtrLayout();
      bool bres = true;
      if(pHFSL)
      {
            if(pBL)
            {
                  bres = pHFSL->bl_doclistener_deleteFmtMark(pBL,pcrfm);
            }
            else
            {
                  return false;
            }
            pHFSL->checkAndAdjustCellSize(this);
            return bres;
      }
      bres = static_cast<fl_BlockLayout *>(pBL)->doclistener_deleteFmtMark(pcrfm);
      checkAndAdjustCellSize();
      return bres;
}

bool fl_SectionLayout::bl_doclistener_changeFmtMark(fl_ContainerLayout* pBL, const PX_ChangeRecord_FmtMarkChange * pcrfmc)
{
    fl_HdrFtrSectionLayout * pHFSL = getHdrFtrLayout();
      bool bres = true;
      if(pHFSL)
      {
            if(pBL)
            {
                  bres = pHFSL->bl_doclistener_changeFmtMark(pBL,pcrfmc);
            }
            else
            {
                  return false;
            }
            pHFSL->checkAndAdjustCellSize(this);
            return bres;
      }
      bres = static_cast<fl_BlockLayout *>(pBL)->doclistener_changeFmtMark(pcrfmc);
      checkAndAdjustCellSize();
      return bres;
}


void fl_SectionLayout::setImageWidth(UT_sint32 iWidth)
{
    m_iDocImageWidth = iWidth;
}

void  fl_SectionLayout::setImageHeight(UT_sint32 iHeight)
{
    m_iDocImageHeight = iHeight;
}

void fl_SectionLayout::checkGraphicTick(GR_Graphics * pG)
{
  if(getDocLayout()->getGraphicTick() != m_iGraphicTick)
    {
      UT_DEBUGMSG(("Current tick == %d layout Tick == %d \n",m_iGraphicTick,getDocLayout()->getGraphicTick()));
    }
      if(m_pImageImage && (getDocLayout()->getGraphicTick() != m_iGraphicTick))
      {
            DELETEP(m_pImageImage);
            m_pImageImage = m_pGraphicImage->regenerateImage(pG);
            const UT_Rect rec(0,0,m_iDocImageWidth,m_iDocImageHeight);  
            m_pImageImage->scaleImageTo(pG,rec);
            m_iGraphicTick = getDocLayout()->getGraphicTick();
      }
}


//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
#ifdef _MSC_VER   // MSVC++ warns about using 'this' in initializer list.
#pragma warning(disable: 4355)
#endif
fl_DocSectionLayout::fl_DocSectionLayout(FL_DocLayout* pLayout, PL_StruxDocHandle sdh, PT_AttrPropIndex indexAP, SectionType iType)
      : fl_SectionLayout(pLayout, sdh, indexAP, iType, FL_CONTAINER_DOCSECTION,PTX_Section, this),
        m_pHeaderSL(NULL),
        m_pFooterSL(NULL),
        m_pHeaderEvenSL(NULL),
        m_pFooterEvenSL(NULL),
        m_pHeaderFirstSL(NULL),
        m_pFooterFirstSL(NULL),
        m_pHeaderLastSL(NULL),
        m_pFooterLastSL(NULL),
        m_iNumColumns(1),
        m_iColumnGap(0),
        m_bColumnLineBetween(false),
        m_iColumnOrder(0),
        m_iSpaceAfter(0),
        m_bRestart(false),
        m_iRestartValue(0),

        m_iLeftMargin(0),
        m_dLeftMarginUserUnits(0.0),
        m_iRightMargin(0),
        m_dRightMarginUserUnits(0.0),
        m_iTopMargin(0),
        m_dTopMarginUserUnits(0.0),
        m_iBottomMargin(0),
        m_dBottomMarginUserUnits(0.0),
        m_iFooterMargin(0),
        m_dFooterMarginUserUnits(0.0),
        m_iHeaderMargin(0),
        m_dHeaderMarginUserUnits(0.0),
        m_iMaxSectionColumnHeight(0),
        m_dMaxSectionColumnHeight(0.0),
        m_iFootnoteLineThickness(0),
        m_iFootnoteYoff(0),

        m_bForceNewPage(false),
        m_pFirstColumn(NULL),
        m_pLastColumn(NULL),
        m_pFirstOwnedPage(NULL),

        m_bNeedsFormat(false),
        m_bNeedsRebuild(false),
        m_bNeedsSectionBreak(true),
        m_pFirstEndnoteContainer(NULL),
        m_pLastEndnoteContainer(NULL),
        m_bDeleteingBrokenContainers(false),
        m_iNewHdrHeight(0),
        m_iNewFtrHeight(0),
        m_pHdrFtrChangeTimer(NULL),
        m_bDoingCollapse(false)
{
      UT_ASSERT(iType == FL_SECTION_DOC);

      m_pDoc= pLayout->getDocument();
      
      m_sPaperColor.clear();
      m_sScreenColor.clear();
      lookupProperties();
}

fl_DocSectionLayout::~fl_DocSectionLayout()
{
// Remove any background HdrFtr change callbacks

      if(m_pHdrFtrChangeTimer)
      {
            m_pHdrFtrChangeTimer->stop();
            DELETEP(m_pHdrFtrChangeTimer);
      }

      // NB: be careful about the order of these
      _purgeLayout();

      UT_GenericVector<fl_HdrFtrSectionLayout*> vecHdrFtr;
      getVecOfHdrFtrs( &vecHdrFtr);
      UT_uint32 i = 0;
      fl_HdrFtrSectionLayout * pHdrFtr = NULL;
      for(i = 0; i < vecHdrFtr.getItemCount(); i++)
      {
            pHdrFtr = vecHdrFtr.getNthItem(i);
            delete pHdrFtr;
      }

      fp_Column* pCol = m_pFirstColumn;
      while (pCol)
      {
            fp_Column* pNext = static_cast<fp_Column *>(pCol->getNext());

            delete pCol;

            pCol = pNext;
      }
}

void fl_DocSectionLayout::setFirstEndnoteContainer(fp_EndnoteContainer * pECon)
{
      m_pFirstEndnoteContainer = pECon;
}


void fl_DocSectionLayout::setLastEndnoteContainer(fp_EndnoteContainer * pECon)
{
      m_pLastEndnoteContainer = pECon;
}


fp_Container * fl_DocSectionLayout::getFirstEndnoteContainer(void)
{
      fp_Container * pCon = static_cast<fp_Container *>(m_pFirstEndnoteContainer);
      return pCon;
}

fp_Container * fl_DocSectionLayout::getLastEndnoteContainer(void)
{
      fp_Container * pCon = static_cast<fp_Container *>(m_pLastEndnoteContainer);
      return pCon;
}


fl_FootnoteLayout * fl_DocSectionLayout::getFootnoteLayout(UT_uint32 pid)
{
      fl_ContainerLayout * pCL = getFirstLayout();
      fl_FootnoteLayout * pFL = NULL;
      bool bFound = false;
      while(pCL && !bFound)
      {
            if(pCL->getContainerType() == FL_CONTAINER_FOOTNOTE)
            {
                  pFL = static_cast<fl_FootnoteLayout *>(pCL);
                  if(pFL->getFootnotePID() == pid)
                  {
                        bFound = true;
                        break;
                  }
            }
            pCL = pCL->getNext();
      }
      if(bFound)
      {
            return pFL;
      }
      return NULL;
}

/*!
 * Returns the usuable height of the Column in logical units (after subtracting
 * top and bottom margins)
 */ 
UT_sint32 fl_DocSectionLayout::getActualColumnHeight(void)
{
      UT_sint32 Height = static_cast<UT_sint32>(getDocument()->m_docPageSize.Height(DIM_IN) * UT_LAYOUT_RESOLUTION /getDocument()->m_docPageSize.getScale());
      Height -= (getTopMargin() + getBottomMargin());
      if(m_iMaxSectionColumnHeight > 0)
      {
            Height = m_iMaxSectionColumnHeight;
      }
      return Height;
}


/*!
 * Returns the usuable width of the Column in logical units (after subtracting
 * left and right margins)
 */ 

UT_sint32 fl_DocSectionLayout::getActualColumnWidth(void)
{
      UT_sint32 width = static_cast<UT_sint32>(getDocument()->m_docPageSize.Width(DIM_IN) * UT_LAYOUT_RESOLUTION /getDocument()->m_docPageSize.getScale());
      width -= (getLeftMargin() + getRightMargin());
      if(m_iNumColumns > 1)
      {
            width -= m_iNumColumns*m_iColumnGap;
            width = width/m_iNumColumns;
      }
      return width;
}
                  
UT_sint32 fl_DocSectionLayout::getWidth(void)
{
      UT_sint32 ires = m_pLayout->getGraphics()->getResolution();
      UT_sint32 width = static_cast<UT_sint32>(ires * getDocument()->m_docPageSize.Width(DIM_IN));
      return width;
}

void fl_DocSectionLayout::setHdrFtr(HdrFtrType iType, fl_HdrFtrSectionLayout* pHFSL)
{
      if(pHFSL == NULL)
      {
            switch (iType)
            {
            case FL_HDRFTR_HEADER:
                  m_pHeaderSL = pHFSL; break;
            case FL_HDRFTR_HEADER_EVEN:
                  m_pHeaderEvenSL = pHFSL; break;
            case FL_HDRFTR_HEADER_FIRST:
                  m_pHeaderFirstSL = pHFSL; break;
            case FL_HDRFTR_HEADER_LAST:
                  m_pHeaderLastSL = pHFSL; break;
            case FL_HDRFTR_FOOTER:
                  m_pFooterSL = pHFSL; break;
            case FL_HDRFTR_FOOTER_EVEN:
                  m_pFooterEvenSL = pHFSL; break;
            case FL_HDRFTR_FOOTER_FIRST:
                  m_pFooterFirstSL = pHFSL; break;
            case FL_HDRFTR_FOOTER_LAST:
                  m_pFooterLastSL = pHFSL; break;
            case FL_HDRFTR_NONE:
                  UT_ASSERT(UT_SHOULD_NOT_HAPPEN); break;
            }
            checkAndRemovePages();
            return;
      }
      const char* pszID = pHFSL->getAttribute("id");

      const char* pszAtt = NULL;

      pszAtt = getAttribute("header");
      if (pszAtt && (0 == strcmp(pszAtt, pszID)) && (iType == FL_HDRFTR_HEADER) )
      {
            m_pHeaderSL = pHFSL;
            checkAndRemovePages();
            return;
      }

      pszAtt = getAttribute("header-even");
      if (pszAtt && (0 == strcmp(pszAtt, pszID))&& (iType == FL_HDRFTR_HEADER_EVEN) )
      {
            m_pHeaderEvenSL = pHFSL;
            checkAndRemovePages();
            return;
      }

      pszAtt = getAttribute("header-first");
      if (pszAtt && (0 == strcmp(pszAtt, pszID))&& (iType == FL_HDRFTR_HEADER_FIRST) )
      {
            m_pHeaderFirstSL = pHFSL;
            checkAndRemovePages();
            return;
      }

      pszAtt = getAttribute("header-last");
      if (pszAtt && (0 == strcmp(pszAtt, pszID))&& (iType == FL_HDRFTR_HEADER_LAST) )
      {
            m_pHeaderLastSL = pHFSL;
            checkAndRemovePages();
            return;
      }

      pszAtt = getAttribute("footer");
      if (pszAtt && (0 == strcmp(pszAtt, pszID))&& (iType == FL_HDRFTR_FOOTER))
      {
            m_pFooterSL = pHFSL;
            checkAndRemovePages();
            return;
      }

      pszAtt = getAttribute("footer-even");
      if (pszAtt && (0 == strcmp(pszAtt, pszID)) && (iType == FL_HDRFTR_FOOTER_EVEN)      )
      {
            m_pFooterEvenSL = pHFSL;
            checkAndRemovePages();
            return;
      }

      pszAtt = getAttribute("footer-first");
      if (pszAtt && (0 == strcmp(pszAtt, pszID)) && (iType == FL_HDRFTR_FOOTER_FIRST)     )
      {
            m_pFooterFirstSL = pHFSL;
            checkAndRemovePages();
            return;
      }

      pszAtt = getAttribute("footer-last");
      if (pszAtt && (0 == strcmp(pszAtt, pszID)) && (iType == FL_HDRFTR_FOOTER_LAST)      )
      {
            m_pFooterLastSL = pHFSL;
            checkAndRemovePages();
            return;
      }

      UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
}

/*!
 * The calback that implements the HdrFtr size change
 */
void fl_DocSectionLayout::_HdrFtrChangeCallback(UT_Worker * pWorker)
{
      UT_ASSERT(pWorker);
      UT_DEBUGMSG(("Doing HdrFtr change callback \n"));
      // Get the docSectionLayout
      fl_DocSectionLayout * pDSL = static_cast<fl_DocSectionLayout *>(pWorker->getInstanceData());
      UT_ASSERT(pDSL);

      // Win32 timers can fire prematurely on asserts (the dialog's
      // message pump releases the timers)
      if (!pDSL->getDocument())
      {
            return;
      }
      // Don't do anything while PT is changing
      PD_Document * pDoc = pDSL->getDocument();
      if(pDoc->isPieceTableChanging())
      {
            return;
      }
      if(pDSL->m_pLayout->isLayoutFilling())
      {
// FIXME:
// Don't resize on load for now. Put this back laters when I can workout
// how to avoid horrible slowdowns and crashes.
//
            pDSL->m_sHdrFtrChangeProps.clear();
            pDSL->m_pHdrFtrChangeTimer->stop();
            DELETEP(pDSL->m_pHdrFtrChangeTimer);
            return;
      }
      // Don't do anything while a redrawupdate is happening either...
      if(pDoc->isRedrawHappenning())
      {
            return;
      }
// Don't do anything until insertion point is allowed to change
      if (!pDoc->getAllowChangeInsPoint())
      {
            return;
      }
      fl_DocSectionLayout * pPrev = static_cast<fl_DocSectionLayout *>(pDSL->getPrev());
      bool bDoit = true;
      while(pPrev && bDoit)
      {
//
// If a timer has been set on a previous docsection don't do this until it's
// cleared.
//
            if(pPrev->m_pHdrFtrChangeTimer != NULL)
            {
                  return;
            }
            fl_DocSectionLayout * pPPrev = static_cast<fl_DocSectionLayout *>(pDSL->getPrev());
            if(pPPrev != pPrev)
            {
                  pPrev = pPPrev;
            }
            else
            {
                  bDoit = false;
                  break;
            }
      }
      const char * pProps = pDSL->m_sHdrFtrChangeProps.c_str();
      const XML_Char * pszAtts[4] = {"props",pProps,NULL,NULL};
      pDoc->notifyPieceTableChangeStart();
      FV_View * pView =  pDSL->m_pLayout->getView();
      PL_StruxDocHandle sdh = pDSL->getStruxDocHandle();
    PT_DocPosition insPos = pView->getPoint();
      fl_HdrFtrShadow * pShadow = pView->getEditShadow();
      HdrFtrType hfType = FL_HDRFTR_HEADER;
      if(pShadow)
      {
            hfType = pShadow->getHdrFtrSectionLayout()->getHFType();
      }
      UT_sint32 iPage = -1;
      if(pShadow)
      {
            iPage = pDSL->m_pLayout->findPage(pShadow->getPage());
      }
      pDoc->setMarginChangeOnly( true);
      pDoc->changeStruxFmtNoUndo(PTC_AddFmt,sdh,pszAtts,NULL);
      pDoc->setMarginChangeOnly(false);
//
// Stop the resizer and delete and clear it's pointer. It's job is done now.
//
      pDSL->m_pHdrFtrChangeTimer->stop();
//
// update the screen
//
      pDoc->signalListeners(PD_SIGNAL_UPDATE_LAYOUT);
      pDoc->notifyPieceTableChangeEnd();
      pDSL->m_sHdrFtrChangeProps.clear();
//
// Put the point at the right point in the header/footer on the right page.
//
      if(iPage >= 0)
      {
            fp_Page * pPage = pDSL->m_pLayout->getNthPage(iPage);
            if(pPage)
            {
                  fp_ShadowContainer* pShadowC = pPage->getHdrFtrP(hfType);
                  pShadow = pShadowC->getShadow();
                  pView->setHdrFtrEdit(pShadow);
            }
      }
    pView->setPoint(insPos);
      pView->notifyListeners(AV_CHG_MOTION | AV_CHG_HDRFTR );
    pView->setPoint(insPos);
      pView->ensureInsertionPointOnScreen();
      DELETEP(pDSL->m_pHdrFtrChangeTimer);
}

/*!
 * This method is called if the top and bottom margins of the pages
 * have changed following an auto-resize request from the header.
 * We try to avoid a complete rebuild.
 */
void fl_DocSectionLayout::doMarginChangeOnly(void)
{
      const PP_AttrProp* pAP = NULL;
      getAP(pAP);
      UT_return_if_fail(pAP);

      const XML_Char* pszSectionType = NULL;
      pAP->getAttribute("type", pszSectionType);
      lookupProperties();
      fp_Page * pMyPage = m_pLayout->getFirstPage();
      while(pMyPage && pMyPage->getOwningSection() != this)
      {
            pMyPage = pMyPage->getNext();
      }
      if(pMyPage == NULL)
      {
            return;
      }
//
// Remove broken tables. They need to be rebroken.
//
      deleteBrokenTablesFromHere(NULL);
      while(pMyPage && pMyPage->getOwningSection() == this)
      {
            pMyPage->TopBotMarginChanged();
            pMyPage = pMyPage->getNext();
      }
//
// Rebreak the document. Place containers on their new pages.
//
      fl_DocSectionLayout * pDSL = this;
      while(pDSL)
      {
            pDSL->completeBreakSection();
            pDSL = pDSL->getNextDocSection();
      }
}
/*!
 * Signal a PT change at the next opportunity to change the height of a Hdr
 * (true) or footer (false)
 *
 * newHeight is the value in layout units of the new height of the 
 * header/footer
 *
 * In both caes the header/footers grow "into" the document area.
 */
bool fl_DocSectionLayout::setHdrFtrHeightChange(bool bHdrFtr, UT_sint32 newHeight)
{
//
// Look to see if we've already sent a signal and if we have to adjust
// the height of the HdrFtr
//
      if(bHdrFtr)
      {
            if(newHeight <= m_iNewHdrHeight)
            {
                  return false;
            }
            m_iNewHdrHeight = newHeight;
            getDocument()->setNewHdrHeight(newHeight);
            UT_sint32 fullHeight = newHeight + getHeaderMargin();
            UT_String sHeight = m_pLayout->getGraphics()->invertDimension(DIM_IN, static_cast<double>(fullHeight));
            UT_String sProp = "page-margin-top";
            UT_String_setProperty(m_sHdrFtrChangeProps,sProp,sHeight);
      }
      else
      {
            if(newHeight <= m_iNewFtrHeight)
            {
                  return false;
            }
            m_iNewFtrHeight = newHeight;
            getDocument()->setNewFtrHeight(newHeight);
            UT_sint32 fullHeight = newHeight + getFooterMargin();
            UT_String sHeight = m_pLayout->getGraphics()->invertDimension(DIM_IN, static_cast<double>(fullHeight));
            UT_String sProp = "page-margin-bottom";
            UT_String_setProperty(m_sHdrFtrChangeProps,sProp,sHeight);
      }
//
// OK the idea is to run the timer in the idle loop until the Piecetable
// is clear and we're not redrawing
//
// This means the resize will happen at the first opportunity after the
// current edit is finished.
//
      if(m_pHdrFtrChangeTimer == NULL)
      {
          int inMode = UT_WorkerFactory::IDLE | UT_WorkerFactory::TIMER;
          UT_WorkerFactory::ConstructMode outMode = UT_WorkerFactory::NONE;

          m_pHdrFtrChangeTimer = UT_WorkerFactory::static_constructor (_HdrFtrChangeCallback, this, inMode, outMode, m_pLayout->getGraphics());

          UT_ASSERT(m_pHdrFtrChangeTimer);
          UT_ASSERT(outMode != UT_WorkerFactory::NONE);

            // If the worker is working on a timer instead of in the idle
            // time, set the frequency of the checks.
          if ( UT_WorkerFactory::TIMER == outMode )
            {
                  // this is really a timer, so it's safe to static_cast it
                  static_cast<UT_Timer*>(m_pHdrFtrChangeTimer)->set(100);
            }
          m_pHdrFtrChangeTimer->start();
      }
      return true;
}

fl_HdrFtrSectionLayout*   fl_DocSectionLayout::getHeader(void)
{
      return m_pHeaderSL;
}

fl_HdrFtrSectionLayout*   fl_DocSectionLayout::getFooter(void)
{
      return m_pFooterSL;
}


fl_HdrFtrSectionLayout*   fl_DocSectionLayout::getHeaderEven(void)
{
      return m_pHeaderEvenSL;
}

fl_HdrFtrSectionLayout*   fl_DocSectionLayout::getFooterEven(void)
{
      return m_pFooterEvenSL;
}


fl_HdrFtrSectionLayout*   fl_DocSectionLayout::getHeaderFirst(void)
{
      return m_pHeaderFirstSL;
}

fl_HdrFtrSectionLayout*   fl_DocSectionLayout::getFooterFirst(void)
{
      return m_pFooterFirstSL;
}


fl_HdrFtrSectionLayout*   fl_DocSectionLayout::getHeaderLast(void)
{
      return m_pHeaderLastSL;
}

fl_HdrFtrSectionLayout*   fl_DocSectionLayout::getFooterLast(void)
{
      return m_pFooterLastSL;
}


fp_Container* fl_DocSectionLayout::getFirstContainer() const
{
      return m_pFirstColumn;
}

fp_Container* fl_DocSectionLayout::getLastContainer() const
{
      return m_pLastColumn;
}

void fl_DocSectionLayout::setFirstContainer(fp_Container * pCon)
{
      UT_DEBUGMSG(("docSectionLayout: DocSec %x First container set to %x \n",this,pCon));
      m_pFirstColumn = static_cast<fp_Column *>(pCon);
}


void fl_DocSectionLayout::setLastContainer(fp_Container * pCon)
{
      m_pLastColumn = static_cast<fp_Column *>(pCon);
}

/*!
  Create new container
  \return The newly created container

  This creates a new column or row of same.

*/
fp_Container* fl_DocSectionLayout::getNewContainer(fp_Container * pFirstContainer)
{
      fp_Page* pPage = NULL;
      fp_Column* pLastColumn = static_cast<fp_Column*>(getLastContainer());
      fp_Column* pAfterColumn = NULL;
      UT_sint32 iNextCtrHeight = 0;

      if (pLastColumn)
      {
            fp_Container * prevContainer = NULL;
            fp_Page* pTmpPage = NULL;
            UT_sint32 pageHeight = 0;
            pTmpPage = pLastColumn->getPage();
            iNextCtrHeight = 0;
            if(pFirstContainer != NULL)
            {
                  prevContainer = static_cast<fp_Container *>(pFirstContainer->getPrevContainerInSection());
            }
//
// Calculate from the page height up to prevContainer
//
            pageHeight = pTmpPage->getFilledHeight(prevContainer);

            if(pFirstContainer != NULL)
            {
                  iNextCtrHeight = pFirstContainer->getHeight();
            }
            else if( pLastColumn->getLastContainer())
            {
                  iNextCtrHeight = pLastColumn->getLastContainer()->getHeight();
            }
            else
            {
                  iNextCtrHeight =12*14; // approximately one average line
            }
            UT_sint32 avail =  pTmpPage->getAvailableHeight();

            UT_sint32 newHeight = pageHeight+ 3*iNextCtrHeight;
            xxx_UT_DEBUGMSG(("SEVIOR: Pageheight =%d nextlineheight =%d newheight = %d availableheight =%d linepos %d \n",pageHeight,iNextCtrHeight,newHeight,avail));
            if( newHeight  >= avail || pFirstContainer == NULL)
            {
                  xxx_UT_DEBUGMSG(("SEVIOR: Container on new page \n"));
                  if (pTmpPage->getNext())
                  {
                        pPage = pTmpPage->getNext();
                  }
                  else
                  {
                        bool bIsFilling = m_pLayout->isLayoutFilling();
                        pPage = m_pLayout->addNewPage(this,bIsFilling);
                  }
            }
            else
            {
                  xxx_UT_DEBUGMSG(("SEVIOR: Container on current page \n"));
                  pPage = pTmpPage;
                  if(prevContainer == NULL)
                  {
                        pAfterColumn = pPage->getNthColumnLeader(pPage->countColumnLeaders()-1);
                  }
                  else
                  {
                        pAfterColumn = static_cast<fp_Column *>(prevContainer->getContainer())->getLeader();
                  }

            }
      }
      else
      {
            // We currently have no columns in this section.  Time to
            // create some.  If there is a previous section, then we need
            // to start our section right after that one.  If not, then we
            // start our section on the first page.  If there is no first
            // page, then we need to create one.
            fl_DocSectionLayout* pPrevSL = getPrevDocSection();
            if (pPrevSL)
            {
//
// This should make sure the last column in the previous section  has it's last container
// on a sane page.
//

#if 0
                  //
                  // Sevior this code should not be needed!
                  //
                  UT_DEBUGMSG(("code sez: this code should not be needed!\n"));
                  UT_ASSERT(0);

                  // says not needed, but clearly still is
#endif
                  fp_Column * pPrevCol = static_cast<fp_Column *>(pPrevSL->getLastContainer());
                  while(pPrevCol == NULL)
                  {
                        UT_DEBUGMSG(("BUG! BUG! Prev section has no last container! Attempting to fix this \n"));
                        pPrevSL->format();
                      pPrevCol = static_cast<fp_Column *>(pPrevSL->getLastContainer());
                  }
                  fp_Page* pTmpPage = pPrevSL->getLastContainer()->getPage();
                  fp_Container * prevContainer = NULL;
                  if(pFirstContainer != NULL)
                  {
                        prevContainer = static_cast<fp_Container *>(pFirstContainer->getPrevContainerInSection());
                  }

                  UT_sint32 pageHeight = pTmpPage->getFilledHeight(prevContainer);
                  if(pFirstContainer != NULL)
                  {
                        iNextCtrHeight = pFirstContainer->getHeight();
                  }
                  else if(pPrevCol->getLastContainer())
                  {
                        iNextCtrHeight = pPrevCol->getLastContainer()->getHeight();
                  }
                  else
                  {
                        iNextCtrHeight = 12*14; //average height!
                  }
                  bool bForce = (pageHeight + 2*iNextCtrHeight) >= pTmpPage->getAvailableHeight();
//
// Note that the HdrFtr Shadows are created BEFORE the columns are placed
// on the page.
//

                  if (m_bForceNewPage || bForce)
                  {
                        if (pTmpPage->getNext())
                        {
                              pPage = pTmpPage->getNext();
                        }
                        else
                        {
                              pPage = m_pLayout->addNewPage(this);
                        }
                  }
                  else
                  {
                        pPage = pTmpPage;
                        if(prevContainer == NULL)
                        {
                              pAfterColumn = pPage->getNthColumnLeader(pPage->countColumnLeaders()-1);
                        }
                        else
                        {
                              pAfterColumn = static_cast<fp_Column *>(prevContainer->getContainer())->getLeader();
                        }
                  }
            }
            else
            {
                  if (m_pLayout->countPages() > 0)
                  {
                        pPage = m_pLayout->getFirstPage();
                  }
                  else
                  {
                        pPage = m_pLayout->addNewPage(this,true);
                  }
            }
      }

      UT_ASSERT(pPage);

      // Create row of columns
      fp_Column* pLeaderColumn = NULL;
      fp_Column* pTail = NULL;
      UT_uint32 i = 0;
      for (i=0; i<m_iNumColumns; i++)
      {
            fp_Column* pCol = new fp_Column(this);
            if (pTail)
            {
                  pCol->setLeader(pLeaderColumn);
                  pTail->setFollower(pCol);
                  pTail->setNext(pCol);
                  pCol->setPrev(pTail);

                  pTail = pCol;
            }
            else
            {
                  pLeaderColumn = pTail = pCol;
                  pLeaderColumn->setLeader(pLeaderColumn);
            }
      }

      // Append added columns to any previous columns in this section.
      if (m_pLastColumn)
      {
            UT_ASSERT(m_pFirstColumn);

            m_pLastColumn->setNext(pLeaderColumn);
            pLeaderColumn->setPrev(m_pLastColumn);
      }
      else
      {
            UT_ASSERT(!m_pFirstColumn);
            UT_ASSERT(pLeaderColumn);
            m_pFirstColumn = pLeaderColumn;
      }

      // Find last added column and set that as the last in the section.
      fp_Column* pLastNewCol = pLeaderColumn;
      while (pLastNewCol->getFollower())
      {
            pLastNewCol = pLastNewCol->getFollower();
      }
      m_pLastColumn = pLastNewCol;
      UT_ASSERT(!(m_pLastColumn->getNext()));
      UT_ASSERT(!(m_pLastColumn->getFollower()));

      pPage->insertColumnLeader(pLeaderColumn, pAfterColumn);

      fp_Column* pTmpCol = pLeaderColumn;
      i = 0;
      while (pTmpCol)
      {
            UT_ASSERT(pTmpCol->getPage());

            pTmpCol = pTmpCol->getFollower();
            i++;
      }

      return pLeaderColumn;
}

void fl_DocSectionLayout::format(void)
{
      fl_ContainerLayout*     pBL = getFirstLayout();
      FV_View * pView = m_pLayout->getView();

      bool bShowHidden = pView && pView->getShowPara();
      FPVisibility eHidden;
      bool bHidden;

      while (pBL)
      {
            eHidden  = pBL->isHidden();
            bHidden = ((eHidden == FP_HIDDEN_TEXT && !bShowHidden)
                          || eHidden == FP_HIDDEN_REVISION
                          || eHidden == FP_HIDDEN_REVISION_AND_TEXT);

            if(!bHidden)
            {
                  pBL->format();
                  UT_sint32 count = 0;
                  while(pBL->getLastContainer() == NULL || pBL->getFirstContainer()==NULL)
                  {
                        UT_DEBUGMSG(("Error formatting a block try again \n"));
                        count = count + 1;
                        pBL->format();
                        if(count > 3)
                        {
                              UT_DEBUGMSG(("Give up trying to format. Hope for the best :-( \n"));
                              break;
                        }
                  }
            }

            pBL = pBL->getNext();
      }

      m_ColumnBreaker.breakSection(this);
      m_bNeedsFormat = false;
}

void fl_DocSectionLayout::markAllRunsDirty(void)
{
      fl_ContainerLayout*     pBL = getFirstLayout();
      while (pBL)
      {
            pBL->markAllRunsDirty();
            pBL = pBL->getNext();
      }
      if(m_pHeaderSL)
      {
            m_pHeaderSL->markAllRunsDirty();
      }
      if(m_pHeaderEvenSL)
      {
            m_pHeaderEvenSL->markAllRunsDirty();
      }
      if(m_pHeaderFirstSL)
      {
            m_pHeaderFirstSL->markAllRunsDirty();
      }
      if(m_pHeaderLastSL)
      {
            m_pHeaderLastSL->markAllRunsDirty();
      }
      if(m_pFooterSL)
      {
            m_pFooterSL->markAllRunsDirty();
      }
      if(m_pFooterEvenSL)
      {
            m_pFooterEvenSL->markAllRunsDirty();
      }
      if(m_pFooterFirstSL)
      {
            m_pFooterFirstSL->markAllRunsDirty();
      }
      if(m_pFooterLastSL)
      {
            m_pFooterLastSL->markAllRunsDirty();
      }
}

void fl_DocSectionLayout::updateLayout(void)
{
      fl_ContainerLayout*     pBL = getFirstLayout();
      FV_View * pView = m_pLayout->getView();
      bool bShowHidden = pView && pView->getShowPara();
      FPVisibility eHidden;
      bool bHidden;
      xxx_UT_DEBUGMSG(("Doing Update layout \n"));
      while (pBL)
      {
            eHidden  = pBL->isHidden();
            bHidden = ((eHidden == FP_HIDDEN_TEXT && !bShowHidden)
                          || eHidden == FP_HIDDEN_REVISION
                          || eHidden == FP_HIDDEN_REVISION_AND_TEXT);

            if(!bHidden)
            {
                  if (pBL->needsReformat())
                  {
                    if(!(m_pLayout->isLayoutFilling() && pBL->getContainerType() == FL_CONTAINER_TOC))
                    {
                        pBL->format();
                    }
                  }
                  if (pBL->getContainerType() != FL_CONTAINER_BLOCK && !getDocument()->isDontImmediateLayout())
                  {
                        pBL->updateLayout();
                  }
            }

            pBL = pBL->getNext();
      }
      if(needsSectionBreak() && !getDocument()->isDontImmediateLayout() )
      {
            m_ColumnBreaker.breakSection(this);
//          UT_ASSERT(!needsSectionBreak());
      }
      if(needsRebuild() && !getDocument()->isDontImmediateLayout() )
      {
//          UT_ASSERT(0);
            checkAndRemovePages();
            addValidPages();
      }
}

void fl_DocSectionLayout::setNeedsSectionBreak(bool bSet, fp_Page * pPage)
{
      m_bNeedsSectionBreak = bSet;
      fp_Page * pOldP = m_ColumnBreaker.getStartPage();
    UT_sint32 iOldP = 999999999;
      if(pPage == NULL)
      {
            m_ColumnBreaker.setStartPage(pPage);
            return;
      }     
      if(pPage->getOwningSection() != this)
      {
            m_ColumnBreaker.setStartPage(NULL);
            return;
      }     
      if(pOldP)
      {
            iOldP = getDocLayout()->findPage(pOldP);
      }
      UT_sint32 iNewP = getDocLayout()->findPage(pPage);
      xxx_UT_DEBUGMSG(("setNeedsSectionBreak: new Page %d OldPage %d \n",iNewP,iOldP));   
      if( (iNewP > -1) && (iNewP < iOldP))
      {
            xxx_UT_DEBUGMSG(("setNeedsSectionBreak: Rebuild from Page %x \n",pPage));     
            m_ColumnBreaker.setStartPage(pPage);
      }
}


void fl_DocSectionLayout::completeBreakSection(void)
{
      m_bNeedsSectionBreak = true;
      m_ColumnBreaker.setStartPage(NULL);
      m_ColumnBreaker.breakSection(this);
      m_bNeedsSectionBreak = false;
}

void fl_DocSectionLayout::redrawUpdate(void)
{
      fl_ContainerLayout*     pBL = getFirstLayout();

      // we only need to break and redo this section if its contents
      // have changed, i.e., if the field values changed
      xxx_UT_DEBUGMSG(("Doing redraw update \n"));
      while (pBL)
      {
            if(pBL->getContainerType() == FL_CONTAINER_BLOCK && static_cast<fl_BlockLayout *>(pBL)->hasUpdatableField())
            {
                  bool bReformat = pBL->recalculateFields(getDocLayout()->getRedrawCount());
                  if(bReformat)
                  {
                        pBL->format();
                  }
            }
            else
            {
                  pBL->recalculateFields(getDocLayout()->getRedrawCount());
            }
            if (pBL->needsRedraw())
            {
                  pBL->redrawUpdate();
            }

            pBL = pBL->getNext();
      }
      xxx_UT_DEBUGMSG(("Finished Doing redraw update \n"));
      fp_EndnoteContainer * pECon =  static_cast<fp_EndnoteContainer *>(getFirstEndnoteContainer());
      if(pECon)
      {
            fl_EndnoteLayout * pEL = static_cast<fl_EndnoteLayout *>(pECon->getSectionLayout());
            while(pEL)
            {
                  pEL->redrawUpdate();
                  pEL = static_cast<fl_EndnoteLayout *>(pEL->getNext());
            }
      }
      if(needsSectionBreak() || needsRebuild())
      {
            m_ColumnBreaker.breakSection(this);
      
            if(needsRebuild())
            {
//                UT_ASSERT(0);
                  checkAndRemovePages();
                  addValidPages();
            }
      }

}

bool fl_DocSectionLayout::doclistener_changeStrux(const PX_ChangeRecord_StruxChange * pcrxc)
{
      UT_ASSERT(pcrxc->getType()==PX_ChangeRecord::PXT_ChangeStrux);


      setAttrPropIndex(pcrxc->getIndexAP());
      return true;
}

void fl_DocSectionLayout::updateDocSection(void)
{

      const PP_AttrProp* pAP = NULL;
      getAP(pAP);
      UT_return_if_fail(pAP);

      const XML_Char* pszSectionType = NULL;
      pAP->getAttribute("type", pszSectionType);
      lookupProperties();

      // clear all the columns
    // Assume that all columns and formatting have already been removed via a collapseDocSection()
    //

      /*
        TODO to more closely mirror the architecture we're using for BlockLayout, this code
        should probably just set a flag, indicating the need to reformat this section.  Then,
        when it's time to update everything, we'll actually do the format.
      */

      FV_View * pView = m_pLayout->getView();
      if(pView)
      {
            pView->setScreenUpdateOnGeneralUpdate(false);
      }
      setNeedsSectionBreak(true,NULL);
      format();
      checkAndRemovePages();
      formatAllHdrFtr();
      markAllRunsDirty();

      if(pView)
      {
            pView->setScreenUpdateOnGeneralUpdate(true);
      }

//    if (pView)
//    {
//          pView->updateScreen(false);
//          pView->notifyListeners(AV_CHG_TYPING | AV_CHG_FMTSECTION);
//    }

      return;
}

void fl_DocSectionLayout::_lookupProperties(const PP_AttrProp* pSectionAP)
{
      UT_return_if_fail(pSectionAP);
// Now turn off the HdrFtr size change locks.

      m_iNewHdrHeight = 0;
      m_iNewFtrHeight = 0;
      getDocument()->setNewHdrHeight(0);
      getDocument()->setNewFtrHeight(0);
      m_sHdrFtrChangeProps.clear();


      /*
        TODO shouldn't we be using PP_evalProperty like
        the blockLayout does?

        Yes, since PP_evalProperty does a fallback to the
        last-chance defaults, whereas the code below is
        hard-coding its own defaults.  Bad idea.
      */

      const char* pszNumColumns = NULL;
      pSectionAP->getProperty("columns", (const XML_Char *&)pszNumColumns);
      if (pszNumColumns && pszNumColumns[0])
      {
            m_iNumColumns = atoi(pszNumColumns);
      }
      else
      {
            m_iNumColumns = 1;
      }

      const char* pszColumnGap = NULL;
      pSectionAP->getProperty("column-gap", (const XML_Char *&)pszColumnGap);
      if (pszColumnGap && pszColumnGap[0])
      {
            m_iColumnGap = UT_convertToLogicalUnits(pszColumnGap);
      }
      else
      {
            m_iColumnGap = UT_convertToLogicalUnits("0.25in");
      }
      UT_ASSERT(m_iColumnGap < 2000000);
      const char* pszColumnLineBetween = NULL;
      pSectionAP->getProperty("column-line", (const XML_Char *&)pszColumnLineBetween);
      if (pszColumnLineBetween && pszColumnLineBetween[0])
      {
            m_bColumnLineBetween = (strcmp(pszColumnLineBetween, "on") == 0) ? true : false;
      }
      else
      {
            m_bColumnLineBetween = false;
      }

      /* column-order */
      //we use the mechanism used by BlockLayout, since otherwise we
      //cannot recode the default value
      const PP_AttrProp * pSpanAP = NULL;
      const PP_AttrProp * pBlockAP = NULL;

      const char * pszColumnOrder = PP_evalProperty("dom-dir",pSpanAP,pBlockAP,pSectionAP,m_pDoc,false);
    UT_DEBUGMSG(("column order: %s\n", pszColumnOrder));

      FV_View * pView = m_pLayout->getView();

      if(pView && pView->getBidiOrder() != FV_Order_Visual)
      {
            if(pView->getBidiOrder() == FV_Order_Logical_LTR)
                  m_iColumnOrder = 0;
            else
                  m_iColumnOrder = 0;
      }
      else if(pszColumnOrder && pszColumnOrder[0])
      {
            m_iColumnOrder = strcmp(pszColumnOrder, "ltr")  ? 1 : 0;
      }
      else
      {
            m_iColumnOrder = 0;
      }

      const char* pszSpaceAfter = NULL;
      pSectionAP->getProperty("section-space-after", (const XML_Char *&)pszSpaceAfter);
      if (pszSpaceAfter && pszSpaceAfter[0])
      {
            m_iSpaceAfter = UT_convertToLogicalUnits(pszSpaceAfter);
      }
      else
      {
            m_iSpaceAfter = UT_convertToLogicalUnits("0in");
      }

      const char* pszRestart = NULL;
      pSectionAP->getProperty("section-restart", (const XML_Char *&)pszRestart);
      if (pszRestart && pszRestart[0])
      {
            m_bRestart = (UT_strcmp(pszRestart,"1")==0);
      }
      else
      {
            m_bRestart = false;
      }

      const char* pszRestartValue = NULL;
      pSectionAP->getProperty("section-restart-value", (const XML_Char *&)pszRestartValue);
      if (pszRestartValue && pszRestartValue[0])
      {
            m_iRestartValue = atoi(pszRestartValue);
      }
      else
      {
            m_iRestartValue = 1;
      }

      const char* pszLeftMargin = NULL;
      const char* pszTopMargin = NULL;
      const char* pszRightMargin = NULL;
      const char* pszBottomMargin = NULL;
      const char* pszFooterMargin = NULL;
      const char* pszHeaderMargin = NULL;
      const char* pszMaxColumnHeight = NULL;
      pSectionAP->getProperty("page-margin-left", (const XML_Char *&)pszLeftMargin);
      pSectionAP->getProperty("page-margin-top", (const XML_Char *&)pszTopMargin);
      pSectionAP->getProperty("page-margin-right", (const XML_Char *&)pszRightMargin);
      pSectionAP->getProperty("page-margin-bottom", (const XML_Char *&)pszBottomMargin);
      pSectionAP->getProperty("page-margin-footer", (const XML_Char *&)pszFooterMargin);
      pSectionAP->getProperty("page-margin-header", (const XML_Char *&)pszHeaderMargin);


      const XML_Char * szRulerUnits;
      UT_Dimension dim;
      if (XAP_App::getApp()->getPrefsValue(AP_PREF_KEY_RulerUnits,&szRulerUnits))
            dim = UT_determineDimension(szRulerUnits);
      else
            dim = DIM_IN;

      UT_String defaultMargin;
      switch(dim)
      {
      case DIM_IN:
            defaultMargin = "1.0in";
            break;

      case DIM_CM:
            defaultMargin = "2.54cm";
            break;

      case DIM_PI:
            defaultMargin = "6.0pi";
            break;

      case DIM_PT:
            defaultMargin= "72.0pt";
            break;

      case DIM_MM:
            defaultMargin= "25.4mm";
            break;

            // TODO: PX, and PERCENT
            // let them fall through to the default now
            // and we don't use them anyway
#if 0
      case DIM_PX:
      case DIM_PERCENT:
#endif
      case DIM_none:
      default:
            defaultMargin = "1.0in";      // TODO: what to do with this.
            break;

      }

      if(pszLeftMargin && pszLeftMargin[0])
      {
            m_iLeftMargin = UT_convertToLogicalUnits(pszLeftMargin);
            m_dLeftMarginUserUnits = UT_convertDimensionless(pszLeftMargin);
      }
      else
      {
            m_iLeftMargin = UT_convertToLogicalUnits(defaultMargin.c_str());
            m_dLeftMarginUserUnits = UT_convertDimensionless(defaultMargin.c_str());
      }

      if(pszTopMargin && pszTopMargin[0])
      {
            m_iTopMargin = UT_convertToLogicalUnits(pszTopMargin);
            m_dTopMarginUserUnits = UT_convertDimensionless(pszTopMargin);
      }
      else
      {
            m_iTopMargin = UT_convertToLogicalUnits(defaultMargin.c_str());
            m_dTopMarginUserUnits = UT_convertDimensionless(defaultMargin.c_str());
      }

      if(pszRightMargin && pszRightMargin[0])
      {
            m_iRightMargin = UT_convertToLogicalUnits(pszRightMargin);
            m_dRightMarginUserUnits = UT_convertDimensionless(pszRightMargin);
      }
      else
      {
            m_iRightMargin = UT_convertToLogicalUnits(defaultMargin.c_str());
            m_dRightMarginUserUnits = UT_convertDimensionless(defaultMargin.c_str());
      }

      if(pszBottomMargin && pszBottomMargin[0])
      {
            m_iBottomMargin = UT_convertToLogicalUnits(pszBottomMargin);
            m_dBottomMarginUserUnits = UT_convertDimensionless(pszBottomMargin);
      }
      else
      {
            m_iBottomMargin = UT_convertToLogicalUnits(defaultMargin.c_str());
            m_dBottomMarginUserUnits = UT_convertDimensionless(defaultMargin.c_str());
      }

      if(pszFooterMargin && pszFooterMargin[0])
      {
            m_iFooterMargin = UT_convertToLogicalUnits(pszFooterMargin);
            m_dFooterMarginUserUnits = UT_convertDimensionless(pszFooterMargin);
      }
      else
      {
            m_iFooterMargin = UT_convertToLogicalUnits("0.0in");
            m_dFooterMarginUserUnits = UT_convertDimensionless("0.0in");
      }

      if(pszHeaderMargin && pszHeaderMargin[0])
      {
            m_iHeaderMargin = UT_convertToLogicalUnits(pszHeaderMargin);
            m_dHeaderMarginUserUnits = UT_convertDimensionless(pszHeaderMargin);
      }
      else
      {
            m_iHeaderMargin = UT_convertToLogicalUnits("0.0in");
            m_dHeaderMarginUserUnits = UT_convertDimensionless("0.0in");
      }

      pSectionAP->getProperty("section-max-column-height", (const XML_Char *&)pszMaxColumnHeight);
      if (pszMaxColumnHeight && pszMaxColumnHeight[0])
      {
            m_iMaxSectionColumnHeight = UT_convertToLogicalUnits(pszMaxColumnHeight);
      }
      else
      {
            m_iMaxSectionColumnHeight = UT_convertToLogicalUnits("0in");
      }

      const XML_Char * pszFootnoteLine = NULL;
      pSectionAP->getProperty("section-footnote-line-thickness", (const XML_Char *&)pszFootnoteLine);
      if (pszFootnoteLine && pszFootnoteLine[0])
      {
            m_iFootnoteLineThickness = UT_convertToLogicalUnits(pszFootnoteLine);
      }
      else
      {
            m_iFootnoteLineThickness = UT_convertToLogicalUnits("0.005in");
      }


      const XML_Char * pszFootnoteYoff = NULL;
      pSectionAP->getProperty("section-footnote-yoff", (const XML_Char *&)pszFootnoteYoff);
      if (pszFootnoteYoff && pszFootnoteYoff[0])
      {
            m_iFootnoteYoff = UT_convertToLogicalUnits(pszFootnoteYoff);
      }
      else
      {
            m_iFootnoteYoff = UT_convertToLogicalUnits("0.01in");
      }

      const XML_Char * pszDataID = NULL;
      pSectionAP->getAttribute(PT_STRUX_IMAGE_DATAID, (const XML_Char *&)pszDataID);
      DELETEP(m_pGraphicImage);
      DELETEP(m_pImageImage);
      if(pszDataID && *pszDataID)
      {
            m_pGraphicImage = FG_Graphic::createFromStrux(this);
      }
      setPaperColor();
      m_bForceNewPage = false;
}

UT_sint32 fl_DocSectionLayout::getTopMargin(void) const
{
      return m_iTopMargin;
}

UT_sint32 fl_DocSectionLayout::getBottomMargin(void) const
{
      return m_iBottomMargin;
}

/*!
 * Set the color of the background paper in the following order of precedence
 * 1. If The section level proper "background-color" is present and is
 *    not transparent use that.
 * 2. If this section is being displayed to the screen use the
 *     ColorForTransparency preference item color.
 * 3. Otherwise use white
 */
void fl_DocSectionLayout::setPaperColor(void)
{
      const PP_AttrProp* pSectionAP = NULL;
      getAP(pSectionAP);
      UT_return_if_fail(pSectionAP);

      const char* pszClrPaper = NULL;
      pSectionAP->getProperty("background-color", (const XML_Char *&)pszClrPaper);
      FV_View * pView = m_pLayout->getView();
      if(pszClrPaper && UT_strcmp(pszClrPaper,"transparent") != 0)
      {
            m_sPaperColor = pszClrPaper;
            m_sScreenColor.clear();
      }
      else if( pView && pView->getGraphics()->queryProperties(GR_Graphics::DGP_SCREEN) )
      {
            XAP_App * pApp = pView->getApp();
            XAP_Prefs * pPrefs = pApp->getPrefs();
            const XML_Char * pszTransparentColor = NULL;
            pPrefs->getPrefsValue(static_cast<const XML_Char *>(XAP_PREF_KEY_ColorForTransparent),&pszTransparentColor);
            m_sPaperColor.clear();
            m_sScreenColor = pszTransparentColor;
      }
      else
      {
            m_sPaperColor.clear();
            m_sScreenColor.clear();
      }
}

/*!
 * Delete Empty Column containers in this section.
 */
void fl_DocSectionLayout::deleteEmptyColumns(void)
{
      fp_Column* pCol = m_pFirstColumn;
      while (pCol)
      {
            if (pCol->getLeader() == pCol)
            {
                  fp_Column* pCol2 = pCol;
                  bool bAllEmpty = true;
                  fp_Column* pLastInGroup = NULL;

                  while (pCol2)
                  {
                        if (!pCol2->isEmpty())
                        {
                              bAllEmpty = false;
                        }

                        if (!(pCol2->getFollower()))
                        {
                              pLastInGroup = pCol2;
                        }

                        pCol2 = pCol2->getFollower();
                  }

                  if (bAllEmpty)
                  {
                        UT_ASSERT(pLastInGroup);
                        if(pCol->getPage() != NULL)
                        {
                              pCol->getPage()->removeColumnLeader(pCol);
                        }
                        if (pCol == m_pFirstColumn)
                        {
                              m_pFirstColumn = static_cast<fp_Column *>(pLastInGroup->getNext());
                              UT_ASSERT(m_pFirstColumn);
                        }

                        if (pLastInGroup == m_pLastColumn)
                        {
                              m_pLastColumn = static_cast<fp_Column *>(pCol->getPrev());
                        }

                        if (pCol->getPrev())
                        {
                              pCol->getPrev()->setNext(pLastInGroup->getNext());
                        }

                        if (pLastInGroup->getNext())
                        {
                              pLastInGroup->getNext()->setPrev(pCol->getPrev());
                        }

                        fp_Column* pCol3 = pCol;
                        pCol = static_cast<fp_Column *>(pLastInGroup->getNext());
                        while (pCol3)
                        {
                              fp_Column* pNext = pCol3->getFollower();

                              delete pCol3;

                              pCol3 = pNext;
                        }
                  }
                  else
                  {
                        pCol = static_cast<fp_Column *>(pLastInGroup->getNext());
                  }
            }
            else
            {
                  pCol = static_cast<fp_Column *>(pCol->getNext());
            }
      }
}

UT_uint32 fl_DocSectionLayout::getNumColumns(void) const
{
      return m_iNumColumns;
}

UT_sint32 fl_DocSectionLayout::getColumnGap(void) const
{
      UT_ASSERT( m_iColumnGap < 200000);
      return m_iColumnGap;
}

UT_uint32 fl_DocSectionLayout::getColumnOrder(void) const
{
      return m_iColumnOrder;
}

void fl_DocSectionLayout::deleteBrokenTablesFromHere(fl_ContainerLayout * pTL)
{
      UT_DEBUGMSG(("Doing delete broken tables from here \n"));
      if(m_bDeleteingBrokenContainers)
      {
            return;
      }
      m_bDeleteingBrokenContainers = true;
      if(pTL == NULL)
      {
            pTL = getFirstLayout();
      }
      fl_ContainerLayout * pCL = pTL->getNext();
      while(pCL != NULL)
      {
            if(pCL->getContainerType() == FL_CONTAINER_TABLE)
            {
                  fl_TableLayout * pTabL = static_cast<fl_TableLayout *>(pCL);
                  fp_TableContainer * pTabC = static_cast<fp_TableContainer *>(pTabL->getFirstContainer());
                  if(pTabC != NULL)
                  {
                        pTabC->deleteBrokenTables(true);
                  }
            }
            else if(pCL->getContainerType() == FL_CONTAINER_TOC)
            {
                  fl_TOCLayout * pTOCL = static_cast<fl_TOCLayout *>(pCL);
                  fp_TOCContainer * pTOC = static_cast<fp_TOCContainer *>(pTOCL->getFirstContainer());
                  if(pTOC != NULL)
                  {
                        pTOC->deleteBrokenTOCs(true);
                  }
            }
            pCL = pCL->getNext();
      }
      m_bDeleteingBrokenContainers = false;
}


fl_DocSectionLayout* fl_DocSectionLayout::getNextDocSection(void) const
{
      fl_DocSectionLayout * pSL = static_cast<fl_DocSectionLayout *>(getNext());
      if(pSL != NULL && pSL->getType()== FL_SECTION_DOC)
            return pSL;
      return NULL;
}

fl_DocSectionLayout* fl_DocSectionLayout::getPrevDocSection(void) const
{
      fl_DocSectionLayout * pSL = static_cast<fl_DocSectionLayout *>(getPrev());
      while(pSL != NULL && pSL->getType()!= FL_SECTION_DOC)
      {
            pSL = static_cast<fl_DocSectionLayout *>(pSL->getPrev());
      }
      return pSL;
}

void fl_DocSectionLayout::collapse(void)
{
      UT_DEBUGMSG(("DocSectionLayout: Collapsing all content in %x \n",this));
      fp_Column* pCol = m_pFirstColumn;
      m_bDoingCollapse = true;
      while (pCol)
      {
            pCol->clearScreen();

            pCol = static_cast<fp_Column *>(pCol->getNext());
      }
      //
      // Clear the header/footers too
      //
      UT_GenericVector<fl_HdrFtrSectionLayout*> vecHdrFtr;
      getVecOfHdrFtrs( &vecHdrFtr);
      UT_uint32 i = 0;
      fl_HdrFtrSectionLayout * pHdrFtr = NULL;
      for(i = 0; i < vecHdrFtr.getItemCount(); i++)
      {
            pHdrFtr = vecHdrFtr.getNthItem(i);
            pHdrFtr->clearScreen();
      }
      //
      // Collapse the header/footers now
      //
      for(i = 0; i < vecHdrFtr.getItemCount(); i++)
      {
            pHdrFtr = vecHdrFtr.getNthItem(i);
            pHdrFtr->collapse();
      }
      // remove all the columns from their pages
      pCol = m_pFirstColumn;
      while (pCol)
      {
//
// The endnote in a column may originate from a totally different 
// docsection. We must collapse these endnotes first
//
            pCol->collapseEndnotes();
            if (pCol->getLeader() == pCol)
            {
                  pCol->getPage()->removeColumnLeader(pCol);
            }

            pCol = static_cast<fp_Column *>(pCol->getNext());
      }

      // get rid of all the layout information for every block
      fl_ContainerLayout*     pBL = getFirstLayout();
      while (pBL)
      {
            if(pBL->getContainerType() == FL_CONTAINER_ENDNOTE)
            {
                  fp_Container * pCon = pBL->getFirstContainer();
                  fp_Column * pCol = static_cast<fp_Column *>(pCon->getColumn());
                  UT_DEBUGMSG(("Got and endnote in this section!! \n"));
                  UT_DEBUGMSG(("Remove Endnote con %x from col %x \n",pCon,pCol));
                  pCol->removeContainer(pCon);
            }
            pBL->collapse();
            pBL = pBL->getNext();

      }

      // delete all our columns
      pCol = m_pFirstColumn;
      while (pCol)
      {
            if(pCol->countCons() > 0)
            {
                  UT_uint32 i = 0;
                  for(i=0; i<pCol->countCons();i++)
                  {
                        fp_ContainerObject * pCon = pCol->getNthCon(i);
                        UT_DEBUGMSG(("Still have a pointer to a container %x -removing pointer \n",pCon));
                        pCol->justRemoveNthCon(i);
                  }
            }
            fp_Column* pNext = static_cast<fp_Column *>(pCol->getNext());
            delete pCol;
            pCol = pNext;     
      }
      m_pFirstColumn = NULL;
      m_pLastColumn = NULL;
      setFirstEndnoteContainer(NULL);
      setLastEndnoteContainer(NULL);
//
// Remove all the empty pages thus created. Don't notify of the deletion though.
//
      fp_Page* pPage = m_ColumnBreaker.getStartPage();
      if (pPage && pPage->isEmpty())
            m_ColumnBreaker.setStartPage(NULL);
      getDocLayout()->deleteEmptyPages(true);
//
// This Doc Section No longer owns pages so this becomes NULL
//
      m_pFirstOwnedPage = NULL;
      m_bDoingCollapse = false;
}

bool fl_DocSectionLayout::doclistener_deleteStrux(const PX_ChangeRecord_Strux * pcrx)
{
      UT_ASSERT(pcrx->getType()==PX_ChangeRecord::PXT_DeleteStrux);
      UT_ASSERT(pcrx->getStruxType()==PTX_Section);
      UT_DEBUGMSG(("Doing Section delete \n"));
      fl_DocSectionLayout* pPrevSL = getPrevDocSection();
      UT_DEBUGMSG(("Deleting DocSec %x Prev DocSec %x \n",this,pPrevSL));
      if (!pPrevSL)
      {
            // TODO shouldn't this just assert?
            UT_DEBUGMSG(("no prior SectionLayout"));
            return false;
      }

//
// Collapse previous section too. We need this so it can be rebuilt properly.
//
      pPrevSL->collapse();

      // clear all the columns
      collapse();

      DELETEP(m_pHeaderSL);
      DELETEP(m_pHeaderEvenSL);
      DELETEP(m_pHeaderFirstSL);
      DELETEP(m_pHeaderLastSL);
      DELETEP(m_pFooterSL);
      DELETEP(m_pFooterEvenSL);
      DELETEP(m_pFooterFirstSL);
      DELETEP(m_pFooterLastSL);

//
// Collapse the subsequent sections too. These will be reformatted in a few lines.
//
      fl_DocSectionLayout * pDSL = getNextDocSection();
      while(pDSL != NULL)
      {
            pDSL->collapse();
            pDSL = pDSL->getNextDocSection();
      }
//
// OK set the links and move all blocks in this section into the previous section.
      if(getFirstLayout())
      {
            fl_ContainerLayout * pBCur = getFirstLayout();
            fl_ContainerLayout * pBPrev = pPrevSL->getLastLayout();
            UT_ASSERT(pBCur && pBPrev);
      
            pBCur->setPrev(pBPrev);
            pBPrev->setNext(pBCur);
            while(pBCur != NULL)
            {
                  xxx_UT_DEBUGMSG(("updating block %x \n",pBCur));
                  pBCur->setContainingLayout(pPrevSL);
                  if(pBCur->getContainerType() == FL_CONTAINER_BLOCK)
                  {
                        static_cast<fl_BlockLayout *>(pBCur)->
                              setSectionLayout(pPrevSL);
                  }
                  if(pBCur->getContainerType() == FL_CONTAINER_FOOTNOTE)
                  {
                        static_cast<fl_FootnoteLayout *>(pBCur)->
                              setDocSectionLayout(pPrevSL);
                  }
                  if(pBCur->getContainerType() == FL_CONTAINER_ENDNOTE)
                  {
                        static_cast<fl_EndnoteLayout *>(pBCur)->
                              setDocSectionLayout(pPrevSL);
                  }

                  pPrevSL->setLastLayout(pBCur);
                  pBCur = pBCur->getNext();
            }
      }
      setFirstLayout(NULL);
      setLastLayout(NULL);

//
// Get this before we remove this section from the run list!
//
    pDSL = getNextDocSection();
      m_pLayout->removeSection(this);
      pPrevSL->format();

      FV_View* pView = m_pLayout->getView();
      if (pView)
      {
            pView->_setPoint(pcrx->getPosition());
      }
//
// Update the following sections.
//
      while(pDSL != NULL)
      {
            pDSL->updateDocSection();
            pDSL = pDSL->getNextDocSection();
      }
      delete this;                  // TODO whoa!  this construct is VERY dangerous.

      return true;
}

void fl_DocSectionLayout::addOwnedPage(fp_Page* pPage)
{
      // TODO do we really need the vecOwnedPages member? YES!!!

      if(m_pFirstOwnedPage == NULL)
            m_pFirstOwnedPage = pPage;
      fp_Page * pPrev = m_pFirstOwnedPage;
      pPage->getFillType()->setDocLayout(getDocLayout());
      setImageWidth(pPage->getWidth());
      setImageHeight(pPage->getHeight());
      if(m_pGraphicImage)
      {
            if(m_pImageImage == NULL)
            {
                  const PP_AttrProp * pAP = NULL;
                  getAP(pAP);
                  GR_Image * pImage = m_pGraphicImage->generateImage(getDocLayout()->getGraphics(),pAP,pPage->getWidth(),pPage->getHeight());
                  m_iGraphicTick = getDocLayout()->getGraphicTick();
                  UT_Rect rec(0,0,pPage->getWidth(),pPage->getHeight());
                  pImage->scaleImageTo(getDocLayout()->getGraphics(),rec);
                  m_pImageImage = pImage;
            }
            pPage->getFillType()->setImagePointer(&m_pGraphicImage,&m_pImageImage);
      }
      else if(m_sPaperColor.size() > 0)
      {
            pPage->getFillType()->setColor(m_sPaperColor.c_str());
      }
      else if(m_sScreenColor.size() > 0)
      {
            pPage->getFillType()->setTransColor(m_sScreenColor.c_str());
            pPage->getFillType()->markTransparentForPrint();
      }           

//
// The addPage methods will add the page to the correct HdrFtrSL.
//
      UT_GenericVector<fl_HdrFtrSectionLayout *> vecHdrFtr;
      getVecOfHdrFtrs( &vecHdrFtr);
      UT_uint32 i = 0;
      for(i = 0; i < vecHdrFtr.getItemCount(); i++)
      {
            fl_HdrFtrSectionLayout * pHdrFtr = vecHdrFtr.getNthItem(i);
            if(pHdrFtr->getHFType() < FL_HDRFTR_FOOTER)
            {
                  if(pPrev && pPrev->getOwningSection() == this && pPrev->getHdrFtrP(FL_HDRFTR_HEADER) == NULL )
                        prependOwnedHeaderPage(pPrev);

                  pHdrFtr->addPage(pPage);
            }
            else
            {
                  if(pPrev && pPrev->getOwningSection() == this && pPrev->getHdrFtrP(FL_HDRFTR_FOOTER) == NULL)
                  {
                        prependOwnedFooterPage(pPrev);
                  }
                  pHdrFtr->addPage(pPage);
            }
      }
      fl_DocSectionLayout * pDSL = this;
      while(pDSL != NULL)
      {
            pDSL->checkAndRemovePages();
            pDSL->addValidPages();
            pDSL = pDSL->getNextDocSection();
      }
}

void fl_DocSectionLayout::prependOwnedHeaderPage(fp_Page* pPage)
{
      //
      // Skip back through the pages until the first owned page of this section
      //
      fp_Page * pPrev = pPage->getPrev();
      if(pPrev && pPrev->getOwningSection() == this && pPrev->getHdrFtrP(FL_HDRFTR_HEADER) == NULL)
      {
            prependOwnedHeaderPage(pPrev);
      }
//
// The addPage methods will add the page to the correct HdrFtrSL.
//
      UT_GenericVector<fl_HdrFtrSectionLayout *> vecHdrFtr;
      getVecOfHdrFtrs( &vecHdrFtr);
      UT_uint32 i = 0;
      for(i = 0; i < vecHdrFtr.getItemCount(); i++)
      {
            fl_HdrFtrSectionLayout * pHdrFtr = vecHdrFtr.getNthItem(i);
            if(pHdrFtr->getHFType() < FL_HDRFTR_FOOTER)
            {
                  xxx_UT_DEBUGMSG(("SEVIOR: prepending page %x \n",pPage));
                  pHdrFtr->addPage(pPage);
            }
      }
}


void fl_DocSectionLayout::prependOwnedFooterPage(fp_Page* pPage)
{
      //
      // Skip back through the pages until the first owned page of this section
      //
      fp_Page * pPrev = pPage->getPrev();
      if(pPrev && pPrev->getOwningSection() == this && pPrev->getHdrFtrP(FL_HDRFTR_FOOTER) == NULL)
      {
            prependOwnedFooterPage(pPrev);
      }
//
// The addPage methods will add the page to the correct HdrFtrSL.
//
      UT_GenericVector<fl_HdrFtrSectionLayout *> vecHdrFtr;
      getVecOfHdrFtrs( &vecHdrFtr);
      UT_uint32 i = 0;
      for(i = 0; i < vecHdrFtr.getItemCount(); i++)
      {
            fl_HdrFtrSectionLayout * pHdrFtr = vecHdrFtr.getNthItem(i);
            if(pHdrFtr->getHFType() >= FL_HDRFTR_FOOTER)
            {
                  pHdrFtr->addPage(pPage);
            }
      }
}


/*!
 * This fills a vector with all the valid header/footers.
 */
void fl_DocSectionLayout::getVecOfHdrFtrs(UT_GenericVector<fl_HdrFtrSectionLayout *> * vecHdrFtr)
{
      vecHdrFtr->clear();
      if (m_pHeaderFirstSL != NULL)
      {
            vecHdrFtr->addItem(m_pHeaderFirstSL);
      }
      if (m_pHeaderLastSL  != NULL)
      {
            vecHdrFtr->addItem(m_pHeaderLastSL);
      }
      if (m_pHeaderEvenSL  != NULL)
      {
            vecHdrFtr->addItem(m_pHeaderEvenSL);
      }
      if (m_pHeaderSL  != NULL)
      {
            vecHdrFtr->addItem(m_pHeaderSL);
      }
      if (m_pFooterFirstSL != NULL)
      {
            vecHdrFtr->addItem(m_pFooterFirstSL);
      }
      if (m_pFooterLastSL != NULL)
      {
            vecHdrFtr->addItem(m_pFooterLastSL);
      }
      if (m_pFooterEvenSL != NULL)
      {
            vecHdrFtr->addItem(m_pFooterEvenSL);
      }
      if (m_pFooterSL != NULL)
      {
            vecHdrFtr->addItem(m_pFooterSL);
      }
}

/*!
 * This method formats all the header/footers
 */
void fl_DocSectionLayout::formatAllHdrFtr(void)
{
      xxx_UT_DEBUGMSG(("SEVIOR: Doing formatAllHdrFtr \n"));
      UT_GenericVector<fl_HdrFtrSectionLayout *> vecHdrFtr;
      getVecOfHdrFtrs( &vecHdrFtr);
      UT_uint32 i = 0;
      for(i = 0; i < vecHdrFtr.getItemCount(); i++)
      {
            fl_HdrFtrSectionLayout * pHdrFtr = vecHdrFtr.getNthItem(i);
            xxx_UT_DEBUGMSG(("SEVIOR: Doing formatting %x in formatAllHdrFtr \n",pHdrFtr));
            pHdrFtr->format();
      }
}

/*!
 * This method checks each header for valid pages and removes the page if it's not
 * valid. ie it remove odd pages from even headers etc.
 */
void fl_DocSectionLayout::checkAndRemovePages(void)
{
      UT_GenericVector <fl_HdrFtrSectionLayout *> vecHdrFtr;
      getVecOfHdrFtrs( &vecHdrFtr);
      UT_uint32 i = 0;
      for(i = 0; i < vecHdrFtr.getItemCount(); i++)
      {
            fl_HdrFtrSectionLayout * pHdrFtr = vecHdrFtr.getNthItem(i);
            pHdrFtr->checkAndRemovePages();
      }
}


/*!
 * This method adds valid pages to every valid header/footer in the docsection if
 * they're not there already.
 */
void fl_DocSectionLayout::addValidPages(void)
{
      UT_GenericVector<fl_HdrFtrSectionLayout *> vecHdrFtr;
      getVecOfHdrFtrs( &vecHdrFtr);
      UT_uint32 i = 0;
      for(i = 0; i < vecHdrFtr.getItemCount(); i++)
      {
            fl_HdrFtrSectionLayout * pHdrFtr = vecHdrFtr.getNthItem(i);
            pHdrFtr->addValidPages();
      }
}

/*!
 * This method deletes the owned page from the DocSectionLayout and all
 * the header files.
 */
void fl_DocSectionLayout::deleteOwnedPage(fp_Page* pPage, bool bReallyDeleteIt)
{
      UT_GenericVector<fl_HdrFtrSectionLayout *> vecHdrFtr;
      getVecOfHdrFtrs( &vecHdrFtr);
      UT_uint32 i = 0;
      UT_DEBUGMSG(("Delete Owned Page %x \n",pPage));
      for(i = 0; i < vecHdrFtr.getItemCount(); i++)
      {
            fl_HdrFtrSectionLayout * pHdrFtr = vecHdrFtr.getNthItem(i);
            if(pHdrFtr->isPageHere(pPage))
            {
                  pHdrFtr->deletePage(pPage);
                  UT_DEBUGMSG(("Delete Owned Page %x from HdrFtr %x \n",pPage,pHdrFtr));
            }
      }
//
// Remove this page from the list of owned pages
//
      if(m_pFirstOwnedPage == pPage)
      {
            fp_Page * pNext = pPage->getNext();
            if(pNext && pNext->getOwningSection() == this)
            {
                  m_pFirstOwnedPage = pNext;
            }
            else
            {
                  m_pFirstOwnedPage = NULL;
            }
      }
      fl_DocSectionLayout * pDSL = this;
      if(!getDocLayout()->isLayoutDeleting() && bReallyDeleteIt)
      {
            UT_sint32 i = m_pLayout->findPage(pPage);
            if(i>0)
            {
                  UT_DEBUGMSG(("fl_DocSec: deleting page %x ReallyDeleteIt %d \n",pPage,bReallyDeleteIt));
                  m_pLayout->deletePage(pPage,true);
            }
            while(pDSL != NULL)
            {
                  pDSL->checkAndRemovePages();
                  pDSL->addValidPages();
                  pDSL = pDSL->getNextDocSection();
            }
      }
}

/*!
 * This method returns true if the pPage pointer matches the header/footer type
 * given.
\param hfType The type of the header/Footer
\param fp_Page * pThisPage pointer to the page queried.
 */
bool fl_DocSectionLayout::isThisPageValid(HdrFtrType hfType, fp_Page * pThisPage)
{
      if (!m_pFirstOwnedPage)
            return false;

    // No header/footerness assigned yet. Page is invalid.
      if(hfType == FL_HDRFTR_NONE)
            return false;

      if(hfType == FL_HDRFTR_HEADER_FIRST ||
         hfType == FL_HDRFTR_FOOTER_FIRST)
            return (pThisPage == m_pFirstOwnedPage);

//
// If there is a header page defined and this is a header page bail now!
//
      if ((pThisPage == m_pFirstOwnedPage) &&
             ((m_pHeaderFirstSL && hfType < FL_HDRFTR_FOOTER) ||
              (m_pFooterFirstSL && hfType >= FL_HDRFTR_FOOTER)))
            return false;

      fp_Page * pPage = m_pFirstOwnedPage;
      fp_Page * pNext = pPage->getNext();
      while(pNext && (pNext->getOwningSection() == this))
      {
            pPage = pNext;
            pNext = pNext->getNext();
      }

      if(hfType == FL_HDRFTR_HEADER_LAST ||
         hfType == FL_HDRFTR_FOOTER_LAST)
      {
            return (pPage == pThisPage);
      }
//
// If there is a Last SL defined and this is the last page in the SLpage bail now!
//
      if ((pThisPage == pPage) &&
             ((m_pHeaderLastSL && hfType < FL_HDRFTR_FOOTER) ||
              (m_pFooterLastSL && hfType >= FL_HDRFTR_FOOTER)))
            return false;

      UT_uint32 i = 0;
      for(i=0; i < getDocLayout()->countPages(); i++)
      {
            if (getDocLayout()->getNthPage(i) == pThisPage)
                  break;
      }

      UT_ASSERT(i < getDocLayout()->countPages());

      if((hfType == FL_HDRFTR_HEADER_EVEN) ||
         (hfType == FL_HDRFTR_FOOTER_EVEN))
      {
            if(i % 2 == 0)
                  return true;
            else
                  return false;
      }
//
// If there is an Even SL defined and this is an even page in the SL page bail now!
//
      if ((i % 2 == 0) &&
            ((m_pHeaderEvenSL && hfType < FL_HDRFTR_FOOTER) ||
             (m_pFooterEvenSL && hfType >= FL_HDRFTR_FOOTER)))
            return false;

      return true; //if we're here all pages are valid.
}

void fl_DocSectionLayout::checkAndAdjustColumnGap(UT_sint32 iLayoutWidth)
{
      // Check to make sure column gap is not to wide to fit on the page with the
      // given number of columns.
      UT_sint32 minColumnWidth =0;
      UT_sint32 iColWidth= 0;
      if(m_iNumColumns > 1)
      {
            minColumnWidth = UT_convertToLogicalUnits("0.5in");   //TODO should this dimension be hard coded.
            iColWidth = (iLayoutWidth - static_cast<UT_sint32>(((m_iNumColumns - 1) * m_iColumnGap))) / static_cast<UT_sint32>(m_iNumColumns);

            if(iColWidth < minColumnWidth)
            {
                  m_iColumnGap = (iLayoutWidth - minColumnWidth * static_cast<UT_sint32>(m_iNumColumns)) / (static_cast<UT_sint32>(m_iNumColumns) - 1);
            }

      }
      UT_ASSERT(m_iColumnGap < 2000000);
      if(m_iColumnGap < 30 || (m_iColumnGap > 200000))
      {
            m_iColumnGap = 30;
      }
}

//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////

class ABI_EXPORT _PageHdrFtrShadowPair
{
public:
      _PageHdrFtrShadowPair(void)
         {
                  m_pPage = NULL;
                  m_pShadow = NULL;
            }
      virtual ~_PageHdrFtrShadowPair(void)
            {
                  m_pPage = NULL;
                  m_pShadow = NULL;
            }
      void setPage (fp_Page * pPage) { m_pPage = pPage;}
      void setShadow (fl_HdrFtrShadow * pShadow) { m_pShadow = pShadow;}
      fp_Page * getPage(void) const {return m_pPage;}
      fl_HdrFtrShadow * getShadow(void) const {return m_pShadow;}
private:
      fp_Page*                m_pPage;
      fl_HdrFtrShadow*  m_pShadow;
};


fl_HdrFtrSectionLayout::fl_HdrFtrSectionLayout(HdrFtrType iHFType, FL_DocLayout* pLayout, fl_DocSectionLayout* pDocSL, PL_StruxDocHandle sdh, PT_AttrPropIndex indexAP)
      : fl_SectionLayout(pLayout, sdh, indexAP, FL_SECTION_HDRFTR,FL_CONTAINER_HDRFTR,PTX_SectionHdrFtr,pDocSL),
        m_pDocSL(pDocSL),
        m_iHFType(iHFType),
        m_pHdrFtrContainer(NULL)
{
      fl_Layout::setType(PTX_SectionHdrFtr); // Set the type of this strux
      UT_DEBUGMSG(("SEVIOR: Creating HFType =%d \n",m_iHFType));
//
// Since we're almost certainly removing blocks at the end of the doc, tell the
// view to remember the current position on the active view.
//
//    FV_View * pView = m_pLayout->getView();
//    if(pView && pView->isActive())
//    {
//          pView->markSavedPositionAsNeeded();
//    }
}

fl_HdrFtrSectionLayout::~fl_HdrFtrSectionLayout()
{
      xxx_UT_DEBUGMSG(("SEVIOR: Deleting HFType =%d \n",m_iHFType));
      UT_uint32 iCount = m_vecPages.getItemCount();
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = static_cast<_PageHdrFtrShadowPair*>(m_vecPages.getNthItem(i));

            delete pPair->getShadow();
      }
      _purgeLayout();
      DELETEP(m_pHdrFtrContainer);
//
// Take this section layout out of the linked list
//
      m_pLayout->removeHdrFtrSection(static_cast<fl_SectionLayout *>(this));
//
// Null out pointer to this HdrFtrSection in the attached DocLayoutSection
//
      m_pDocSL->setHdrFtr(m_iHFType, NULL);
//
// Since we're almost certainly removing blocks at the end of the doc, tell the
// view to remember the current position on the active view.
//
//    FV_View * pView = m_pLayout->getView();
//    if(pView && pView->isActive())
//    {
//          pView->markSavedPositionAsNeeded();
//    }
//
      UT_VECTOR_PURGEALL(_PageHdrFtrShadowPair*, m_vecPages);
}

/*!
 * This method removes all the lines and containers associated with the shadows
 * and the lines associated with this HdrFtrSectionLayout.
 *
 */
void fl_HdrFtrSectionLayout::collapse(void)
{
//
// If a view exists and we're editting a header footer take the pointer out of
// the header/footer. This will also clear the box around the header/footer
//
      FV_View * pView = m_pLayout->getView();
      if(pView && pView->isHdrFtrEdit())
      {
            pView->clearHdrFtrEdit();
            pView->warpInsPtToXY(0,0,false);
            pView->rememberCurrentPosition();
      }

      _localCollapse();
      UT_uint32 iCount = m_vecPages.getItemCount();
      UT_uint32 i;
      for (i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);
            fp_Page * ppPage = pPair->getPage();
            delete pPair->getShadow();
            ppPage->removeHdrFtr(getHFType());
            delete pPair;
      }
      m_vecPages.clear();
      DELETEP(m_pHdrFtrContainer);
}

/*!
 * This method removes the block pBlock from all the shadowLayouts.
 */
void fl_HdrFtrSectionLayout::collapseBlock(fl_ContainerLayout *pBlock)
{
      UT_uint32 iCount = m_vecPages.getItemCount();
      UT_uint32 i;
      for (i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);
            fl_ContainerLayout * pShadowBL = pPair->getShadow()->findMatchingContainer(pBlock);
            UT_ASSERT(pShadowBL);
            if(pShadowBL)
            {
                  // In case we've never checked this one
                  if(pShadowBL->getContainerType() == FL_CONTAINER_BLOCK)
                  {
                        m_pLayout->dequeueBlockForBackgroundCheck(static_cast<fl_BlockLayout *>(pShadowBL));
                  }
                  pPair->getShadow()->remove( pShadowBL);
                  delete pShadowBL;
                  pPair->getShadow()->format();
            }
      }
}

bool fl_HdrFtrSectionLayout::recalculateFields(UT_uint32 iUpdateCount)
{
      bool bResult = false;

      UT_uint32 iCount = m_vecPages.getItemCount();
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);
            UT_ASSERT(pPair->getShadow());
            bResult = pPair->getShadow()->recalculateFields(iUpdateCount) || bResult;
      }
      return bResult;
}


fl_HdrFtrShadow * fl_HdrFtrSectionLayout::getFirstShadow(void)
{
      UT_uint32 iCount = m_vecPages.getItemCount();
      if(iCount != 0)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(0);
            return pPair->getShadow();
      }
      return NULL;
}

fp_Container* fl_HdrFtrSectionLayout::getFirstContainer() const
{
      return m_pHdrFtrContainer;
}


fp_Container* fl_HdrFtrSectionLayout::getLastContainer() const
{
      return m_pHdrFtrContainer;
}

fp_Container* fl_HdrFtrSectionLayout::getNewContainer(fp_Container * pFirstContainer)
{
      DELETEP(m_pHdrFtrContainer);
      UT_sint32 iWidth = m_pDocSL->getFirstContainer()->getPage()->getWidth(); // why is this different than the next one ?
      m_pHdrFtrContainer = static_cast<fp_Container *>(new fp_HdrFtrContainer(iWidth, static_cast<fl_SectionLayout *>(this)));
      return m_pHdrFtrContainer;
}

bool fl_HdrFtrSectionLayout::isPageHere(fp_Page * pPage)
{
      return (_findShadow(pPage) >=0 );
}

fl_HdrFtrShadow *  fl_HdrFtrSectionLayout::findShadow(fp_Page* pPage)
{
       UT_sint32 iPage = _findShadow(pPage);
       if(iPage < 0)
              return NULL;
       _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(iPage);
       return pPair->getShadow();
}

UT_sint32 fl_HdrFtrSectionLayout::_findShadow(fp_Page* pPage)
{
      UT_uint32 iCount = m_vecPages.getItemCount();
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);

            if (pPair->getPage() == pPage)
            {
                  return i;
            }
      }

      return -1;
}
/*!
 * This method converts a previously existing section to this header/footer.
 * Code liberally stolen from fl_DocSectionLayout::doclistener_deleteStrux
 \param fl_DocSectionLayout * pSL sectionlayout to be converted to a
 *     HdrFtrSectionLayout
*/
void fl_HdrFtrSectionLayout::changeIntoHdrFtrSection( fl_DocSectionLayout * pSL)
{
      fl_DocSectionLayout* pPrevSL = pSL->getPrevDocSection();
      UT_ASSERT(pPrevSL);
      // clear all the columns
      fp_Column* pCol =NULL;

      pCol = static_cast<fp_Column *>(pSL->getFirstContainer());
      while (pCol)
      {
            pCol->clearScreen();

            pCol = static_cast<fp_Column *>(pCol->getNext());
      }

      // remove all the columns from their pages
      pCol = static_cast<fp_Column *>(pSL->getFirstContainer());
      while (pCol)
      {
            if (pCol->getLeader() == pCol)
            {
                  pCol->getPage()->removeColumnLeader(pCol);
            }

            pCol = static_cast<fp_Column *>(pCol->getNext());
      }


      // get rid of all the layout information for every block
      fl_ContainerLayout*     pBL = pSL->getFirstLayout();
      while (pBL)
      {
            pBL->collapse();

            pBL = pBL->getNext();
      }

      //
      // Change the section type
      //

      // transfer the Sections' blocks into this header/footer

      while (pSL->getFirstLayout())
      {
            pBL = pSL->getFirstLayout();
            pSL->remove(pBL);
            add(pBL);
            static_cast<fl_BlockLayout *>(pBL)->setSectionLayout(this);
            static_cast<fl_BlockLayout *>(pBL)->setHdrFtr();
      }
      //
      // Remove old section from the section linked list!!
      //
      m_pLayout->removeSection(pSL);
//
      DELETEP(pSL); // Old Section layout is totally gone
      //
      // Create and Format the shadows
      //
      format();

      // Finished! we now have a header/footer
}

/*!
 * Remove the strux identifing this as a seperate section has been deleted so
 * we have to remove this HdrFtrSectionLayout class and all the shadow sections
 * attached to it. The blocks in this class are moved to the DocSectionLayout
 * associated with this class.
 * I do this because I expect that this will be called as part
 * on an undo "Insert Header" command. The rest of the undo needs blocks to
 * delete so I'm putting them there to keep the rest of the undo code happy
\param pcrx the changerecord identifying this action as necesary.
\returns true
*/
bool fl_HdrFtrSectionLayout::doclistener_deleteStrux(const PX_ChangeRecord_Strux * pcrx)
{
      UT_ASSERT(pcrx->getType()==PX_ChangeRecord::PXT_DeleteStrux);
      UT_ASSERT(pcrx->getStruxType()==PTX_SectionHdrFtr);
//
// Get last doc section. Move all the blocks from here to there after deleting
// this strux.
//
      fl_DocSectionLayout* pPrevSL = m_pDocSL;
      if (!pPrevSL)
      {
            UT_DEBUGMSG(("no prior SectionLayout"));
            UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
      }
//
// Get rid of all the shadows, all the containers, and all the layout
// information for all the blocks.
//
      collapse();
//
// Now copy these line-less blocks into the previous docSectionLayout.
// Note: I expect that these blocks will be deleted by a later delete strux
// on these blocks.
//
      fl_ContainerLayout * pBL = NULL;
      while (getFirstLayout())
      {
            pBL = getFirstLayout();
            remove(pBL);
            pPrevSL->add(pBL);
      }
//
// Remove the pointer to this hdrftr
//
//
// Null out pointer to this HdrFtrSection in the attached DocLayoutSection
// This prevent a new page being created in the format statement that follows.
//
      m_pDocSL->setHdrFtr(m_iHFType, NULL);
//
// Format the new section containing the blocks.
//
      pPrevSL->format();
//
// Finally delete this HdrFtrSectionLayout. This could be done the docListener
// class but here I'm following the convention for the DocSectionLayout. It
// works there so I hope it works here. The HdrFtrSection destructor takes care
// of the details of unlinking the section etc.
//
      delete this;
      return true;
}

void fl_HdrFtrSectionLayout::addPage(fp_Page* pPage)
{
//
//  Sevior:
//  This triggers if we're rebuilding a section before page is defined like in a section change
//  strux. Reinstate if needed to find other bugs.
//    UT_ASSERT(0 > _findShadow(pPage));
//
//
// This might actually be called before we have any content to put in it. If so
// return and hope we get called later.
//
      if(getFirstLayout() == NULL)
      {
            UT_DEBUGMSG(("HdrFtr BUG. No content but we're asking to create a shadow !! \n"));
            UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
            return;
      }

      if(_findShadow(pPage) > -1)
            return;
//
// Check this page is valid for this type of hdrftr
//
      if(!getDocSectionLayout()->isThisPageValid(m_iHFType, pPage))
      {
            return;
      }
      //
      // see if this page has a shadow attached already. This can happen
    // is a page goes from being odd to even.
      //
      fp_ShadowContainer* pOldShadow = pPage->getHdrFtrP(m_iHFType);
      //
      // If so remove it.
      //
      if(pOldShadow != NULL)
      {
            pOldShadow->getHdrFtrSectionLayout()->deletePage(pPage);
      }

      _PageHdrFtrShadowPair* pPair = new _PageHdrFtrShadowPair();
      UT_return_if_fail( pPair );
      
      // TODO outofmem
      xxx_UT_DEBUGMSG(("SEVIOR: Add page %x to pair %x \n",pPage,pPair));
      pPair->setPage(pPage);
      pPair->setShadow(new fl_HdrFtrShadow(m_pLayout, pPage, this, getStruxDocHandle(), m_apIndex));
      //
      // Make sure we register the shadow before populating it.
      //
      m_vecPages.addItem(pPair);
      //
      // Populate the shadow
      //
      fl_ShadowListener* pShadowListener = new fl_ShadowListener(this, pPair->getShadow());
      UT_return_if_fail( pShadowListener );
      UT_DEBUGMSG(("shadow listener %x created \n",pShadowListener));
//
// Populate with just this section so find the start and end of it
//
      PT_DocPosition posStart,posEnd,posDocEnd;
      posStart = getFirstLayout()->getPosition(true) - 1;
      posEnd = getLastLayout()->getPosition(false);
      fp_Run * pRun = getLastLayout()->getFirstRun();

      if(pRun)
      {
            while(pRun->getNextRun() != NULL)
            {
                  pRun = pRun->getNextRun();
            }
            posEnd += pRun->getBlockOffset();
      }
      else
      {
            UT_ASSERT_HARMLESS( UT_SHOULD_NOT_HAPPEN );
      }
      
      PL_StruxDocHandle sdh=NULL;
      bool bres;
      bres = m_pDoc->getStruxOfTypeFromPosition(posEnd, PTX_Block, &sdh);
      m_pDoc->getBounds(true,posDocEnd);
      while(bres && sdh == getLastLayout()->getStruxDocHandle()
              && posEnd <= posDocEnd)
      {
            posEnd++;
            bres = m_pDoc->getStruxOfTypeFromPosition(posEnd, PTX_Block, &sdh);
      }
      posEnd--;
      UT_ASSERT(posEnd > posStart);
      PD_DocumentRange * docRange = new PD_DocumentRange(m_pDoc,posStart,posEnd);
      m_pDoc->tellListenerSubset(pShadowListener, docRange);
      delete docRange;
      delete pShadowListener;
      markAllRunsDirty();
}

bool fl_HdrFtrSectionLayout::isPointInHere(PT_DocPosition pos)
{
//
// Skip through the Containers in this shadow to find the one containing this
// point.
//
    fl_ContainerLayout* pBL = getFirstLayout();
      if(pBL == NULL)
            return false;
      if(pos < pBL->getPosition())
      {
//
// This corner case is that pos == position of the HdrFtr strux
//
            if(pos == (pBL->getPosition() - 1))
            {
                  return true;
            }
            return false;
      }
//
// OK see if the next hdrftr is ahead of the pos
//
      fl_HdrFtrSectionLayout * pHF = static_cast<fl_HdrFtrSectionLayout *>(getNext());
      if(pHF == NULL)
      {
            PT_DocPosition posEOD;
            m_pDoc->getBounds(true,posEOD);
            if(pos <= posEOD)
            {
                  return true;
            }
            // This happens when you're erasing the last character in the document.
            // Not sure if assert should stay or not.
            return false;
      }
      fl_ContainerLayout * ppBL = pHF->getFirstLayout();
      if(ppBL != NULL)
      {
            if(pos < (ppBL->getPosition()-1))
            {
                  return true;
            }
            return false;
      }

      fl_ContainerLayout* pNext = pBL->getNext();
      while(pNext != NULL && pNext->getPosition( true) < pos)
      {
            pBL = pNext;
            pNext = pNext->getNext();
      }
      if(pNext != NULL)
      {
            return true;
      }
      else if(pBL && pBL->getPosition() == pos)
      {
            return true;
      }
//
// Now the point MIGHT be in this last block. Use code from pd_Document
// to find out. Have to check whether we're out of docrange first
//
      PL_StruxDocHandle sdh=NULL;
      bool bres;
      bres = m_pDoc->getStruxOfTypeFromPosition(pos, PTX_Block, &sdh);
      if(bres && sdh == pBL->getStruxDocHandle())
      {
            return true;
      }
      return false;
}

/*!
 * Removes the shadow and the corresponding element pointing to the shadow for this
 * Page.
 */
void fl_HdrFtrSectionLayout::deletePage(fp_Page* pPage)
{
      UT_sint32 iShadow = _findShadow(pPage);
//
// This shadow might have already been deleted via the collapse method
//
      if(iShadow <  0)
            return;
      _PageHdrFtrShadowPair* pPair = static_cast<_PageHdrFtrShadowPair*>(m_vecPages.getNthItem(iShadow));
      UT_ASSERT(pPair);

      UT_ASSERT(pPair->getShadow());


      fp_Page * ppPage = pPair->getPage();
      UT_ASSERT(pPage == ppPage);
      delete pPair->getShadow();
      if(getDocLayout()->findPage(ppPage) >= 0)
      {
                  ppPage->removeHdrFtr(getHFType());
      }
      delete pPair;
      m_vecPages.deleteNthItem(iShadow);
}


/*!
 *  Just format the HdrFtrSectionLayout blocks for an insertBlock method.
 *  these blocks will be collapsed afterwards.
 */
void fl_HdrFtrSectionLayout::localFormat(void)
{
      xxx_UT_DEBUGMSG(("Doing a Local Format of the hdrftr section \n"));
      if(!getDocSectionLayout())
            return;
      fl_ContainerLayout*     pBL = getFirstLayout();
      UT_ASSERT(pBL->getContainerType() != FL_CONTAINER_HDRFTR);
      while (pBL)
      {
            if(pBL->getContainerType() == FL_CONTAINER_BLOCK)
            {
                  static_cast<fl_BlockLayout *>(pBL)->setHdrFtr();
            }
            pBL->format();
            pBL = pBL->getNext();
      }
}

/*!
 *  Just collapse the HdrFtrSectionLayout blocks for an insertBlock method.
 *  This removes all lines and references to containers but leaves the blocks
 *  and runs intact.
 */
void fl_HdrFtrSectionLayout::_localCollapse(void)
{
      fl_ContainerLayout*     pBL = getFirstLayout();
      while (pBL)
      {
            pBL->collapse();
            pBL = pBL->getNext();
      }
}

/*!
 * This routine returns the matching block within this HdrFtrSectionLayout of the
 * shadow.
 \param fl_ContainerLayout * Pointer to block in shadow
 \returns the pinter to the matching block in the HdrFtr
 */
fl_ContainerLayout* fl_HdrFtrSectionLayout::findMatchingContainer(fl_ContainerLayout* pBL)
{
      // This routine returns the matching block within the
      // hdrftrSectionlayout.
      //
      fl_ContainerLayout* ppBL = getFirstLayout();
      bool bInTable = false;
      while(ppBL && (ppBL->getStruxDocHandle() != pBL->getStruxDocHandle()))
      {
            if(ppBL && (ppBL->getContainerType() == FL_CONTAINER_TABLE))
            {
                  ppBL = ppBL->getFirstLayout();
                  bInTable = true;
            }
            else if(bInTable && ppBL->getContainerType() == FL_CONTAINER_CELL)
            {
                  ppBL = ppBL->getFirstLayout();
            }
            else if(bInTable && (ppBL->getNext() == NULL))
            {
                  if(ppBL->myContainingLayout()->getNext() == NULL)
                  {
                        ppBL = ppBL->myContainingLayout();
                        ppBL = ppBL->myContainingLayout()->getNext();
                        bInTable = false;
                  }
                  else
                  {
                        ppBL = ppBL->myContainingLayout()->getNext();
                  }
            }
            else
            {
                  ppBL = ppBL->getNext();
            }
      }
      UT_ASSERT(ppBL);
      //xxx_UT_DEBUGMSG(("This header/footer is %x in findmatchingBlock \n",this));
      return ppBL;
}

/*!
 * This method checks that the pages in this header are valid and removes them if
 * they're not.
 */
void fl_HdrFtrSectionLayout::checkAndRemovePages(void)
{
      UT_sint32 iCount = static_cast<UT_sint32>(m_vecPages.getItemCount());
//
// Check that the pages we have are still valid. Delete them if they're not.
//
      UT_sint32 i = 0;
      UT_GenericVector<fp_Page*> pageForDelete;
      for(i =0; i< iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);
            UT_ASSERT(pPair);
            UT_ASSERT(pPair->getShadow());

            fp_Page * ppPage = pPair->getPage();
            if(getDocLayout()->findPage(ppPage) >= 0)
            {
                  if(!getDocSectionLayout()->isThisPageValid(getHFType(),ppPage))
                  {
                        pageForDelete.addItem(ppPage);
                  }
            }
            else
            {
                  pageForDelete.addItem(ppPage);
            }
      }
      for(i=0; i< static_cast<UT_sint32>(pageForDelete.getItemCount()); i++)
      {
            fp_Page * pPage = pageForDelete.getNthItem(i);
            deletePage(pPage);
      }
      if( pageForDelete.getItemCount() > 0)
      {
            markAllRunsDirty();
      }
}

/*!
 * This method adds valid pages to the collection of shadows.
 */
void fl_HdrFtrSectionLayout::addValidPages(void)
{
      //
      // Check that all the pages this header/footer should have are
    // in place.
      // We have to extract this information from m_pDocSL
      // Loop through all the columns in m_pDocSl and find the pages owned
      // by m_pDocSL
      //
      fp_Column * pCol = static_cast<fp_Column *>(m_pDocSL->getFirstContainer());
      fp_Page * pOldPage = NULL;
      fp_Page * pNewPage = NULL;
      while(pCol)
      {
            pNewPage = pCol->getPage();
            if((pNewPage != NULL) && (pNewPage != pOldPage) && (getDocLayout()->findPage(pNewPage) >=0))
            {
                  fl_DocSectionLayout* pDocSec = pNewPage->getOwningSection();
                  if(pDocSec == m_pDocSL && _findShadow(pNewPage) < 0)
                  {
//
// The addPage Method checks that only valid pages are added to this HdrFtr based on
// the HFType
//
                        addPage(pNewPage);
                  }
            }
            pCol = static_cast<fp_Column *>(pCol->getNext());
      }
}

/*!
 * Format the overall HdrFtrSectionLayout in it's virtual container.
 * Also check that all the correct pages have been found for this HdrFtr. Then
 * format the Shadows.
 */
void fl_HdrFtrSectionLayout::format(void)
{
      if(getFirstLayout() == NULL)
      {
            return;
      }
      UT_sint32 iCount =0;
      UT_sint32 i = 0;
      localFormat();
      //
      // Fail safe code to add pages if we don't have them.
      //
      addValidPages();

      iCount = m_vecPages.getItemCount();

      for (i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);
            pPair->getShadow()->format();
      }
      layout();
}

void fl_HdrFtrSectionLayout::updateLayout(void)
{
      bool bredraw = false;
      fl_ContainerLayout*     pBL = getFirstLayout();
      if(needsReformat())
      {
            format();
            bredraw = true;
            m_bNeedsReformat = false;
      }
      while (pBL)
      {
            if (pBL->needsReformat())
            {
                  bredraw = true;
                  pBL->format();
            }

            pBL = pBL->getNext();
      }
      if(bredraw == true)
      {
            if(m_pHdrFtrContainer)
                  static_cast<fp_HdrFtrContainer *>(m_pHdrFtrContainer)->layout();
      }
      //
      // update Just the  blocks in the shadowlayouts
      //
      UT_uint32 iCount = m_vecPages.getItemCount();
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);

            pPair->getShadow()->updateLayout();
      }
}

/*!
 * Mark all runs and lines in the all shadows for redraw.
 */
void fl_HdrFtrSectionLayout::markAllRunsDirty(void)
{
      UT_uint32 iCount = m_vecPages.getItemCount();
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);

            pPair->getShadow()->markAllRunsDirty();
      }
}

/*!
 * Layout the overall HdrFtr and everything underneath it.
 */
void fl_HdrFtrSectionLayout::layout(void)
{
    if(m_pHdrFtrContainer)
      static_cast<fp_HdrFtrContainer *>(m_pHdrFtrContainer)->layout();
      //
      // update the shadowlayouts
      //
      UT_uint32 iCount = m_vecPages.getItemCount();
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);

            pPair->getShadow()->layout();
      }
}

void fl_HdrFtrSectionLayout::clearScreen(void)
{
      //
      // update Just the  blocks in the shadowlayouts
      //
      UT_uint32 iCount = m_vecPages.getItemCount();
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);

            pPair->getShadow()->clearScreen();
      }
}

void fl_HdrFtrSectionLayout::redrawUpdate(void)
{
//
// Do another layout but don't redraw.
//
      if(m_pHdrFtrContainer)
            static_cast<fp_HdrFtrContainer *>(m_pHdrFtrContainer)->layout();
      //
      // Don't need to draw here since this is never displayed on the screen?
      //
      UT_uint32 iCount = m_vecPages.getItemCount();
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);
            if(m_pLayout->findPage(pPair->getPage()) >= 0)
            {
                  pPair->getShadow()->redrawUpdate();
            }
      }

}

bool fl_HdrFtrSectionLayout::doclistener_changeStrux(const PX_ChangeRecord_StruxChange * pcrxc)
{
      UT_ASSERT(pcrxc->getType()==PX_ChangeRecord::PXT_ChangeStrux);

      setAttrPropIndex(pcrxc->getIndexAP());

      // TODO what happens here?

      UT_ASSERT(UT_SHOULD_NOT_HAPPEN);

      return false;
}

/*!
    this function is only to be called by fl_ContainerLayout::lookupProperties()
    all other code must call lookupProperties() instead
*/
void fl_HdrFtrSectionLayout::_lookupProperties(const PP_AttrProp* pAP)
{
}

bool fl_HdrFtrSectionLayout::bl_doclistener_populateSpan(fl_ContainerLayout* pBL, const PX_ChangeRecord_Span * pcrs, PT_BlockOffset blockOffset, UT_uint32 len)
{
//
// We need to populate block in the header/footer but to do that we need the
// header/footer to be fomatted. So do it then unformat after.
//
      bool bResult = true;
      fl_ContainerLayout * pShadowBL = NULL;
      UT_uint32 iCount = m_vecPages.getItemCount();
      m_pDoc->setDontChangeInsPoint();

      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);
            // Find matching block in this shadow.
            pShadowBL = pPair->getShadow()->findMatchingContainer(pBL);
            if(pShadowBL)
            {
                  bResult = static_cast<fl_BlockLayout *>(pShadowBL)->doclistener_populateSpan(pcrs,blockOffset,len)
                        && bResult;
            }
            else
            {
                  UT_ASSERT(0);
                  break;
            }
      }
      m_pDoc->allowChangeInsPoint();
      pBL = findMatchingContainer(pBL);
      if(pBL)
      {
        bResult = static_cast<fl_BlockLayout *>(pBL)->doclistener_populateSpan(pcrs,blockOffset,len)
          && bResult;
      }
      return bResult;
}

/*!
 * Now for all these methods which manipulate the shadow sections, turn off
 * Insertion Point changes while the shadows are manipulated.
 * Re Enabled insertion point changes for the overall hdrftrsection so it
 * is changed just once.
 */

bool fl_HdrFtrSectionLayout::bl_doclistener_populateObject(fl_ContainerLayout* pBL, PT_BlockOffset blockOffset, const PX_ChangeRecord_Object * pcro)
{
//
// We need to populate block in the header/footer but to do that we need the
// header/footer to be fomatted. So do it then unformat after.
//
      bool bResult = true;
      fl_ContainerLayout * pShadowBL = NULL;
      UT_uint32 iCount = m_vecPages.getItemCount();
      m_pDoc->setDontChangeInsPoint();
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);
            // Find matching block in this shadow.
            pShadowBL = pPair->getShadow()->findMatchingContainer(pBL);
            if(pShadowBL)
            {
                  bResult = static_cast<fl_BlockLayout *>(pShadowBL)->doclistener_populateObject(blockOffset,pcro)
                        && bResult;
            }
            else
            {
                  bResult = false;
            }
      }
      m_pDoc->allowChangeInsPoint();
      pBL = findMatchingContainer(pBL);
      if(pBL)
      {
            bResult = static_cast<fl_BlockLayout *>(pBL)->doclistener_populateObject(blockOffset,pcro)
                  && bResult;
      }
      else
      {
            bResult = false;
      }
      return bResult;
}

bool fl_HdrFtrSectionLayout::bl_doclistener_insertSpan(fl_ContainerLayout* pBL, const PX_ChangeRecord_Span * pcrs)
{
      bool bResult = true;
      fl_ContainerLayout * pShadowBL = NULL;
      UT_uint32 iCount = m_vecPages.getItemCount();
      m_pDoc->setDontChangeInsPoint();
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);

            // Find matching block in this shadow.

            pShadowBL = pPair->getShadow()->findMatchingContainer(pBL);
            if(pShadowBL)
            {
                  bResult = static_cast<fl_BlockLayout *>(pShadowBL)->doclistener_insertSpan(pcrs)
                        && bResult;
            }
      }
      m_pDoc->allowChangeInsPoint();
      // Update the overall block too.
      fl_BlockLayout * ppBL = static_cast<fl_BlockLayout *>(findMatchingContainer(pBL));
      if(ppBL)
      {
            bResult = static_cast<fl_BlockLayout *>(pBL)->doclistener_insertSpan(pcrs)
      && bResult;
      }
      return bResult;
}

bool fl_HdrFtrSectionLayout::bl_doclistener_deleteSpan(fl_ContainerLayout* pBL, const PX_ChangeRecord_Span * pcrs)
{
      bool bResult = true;
      fl_ContainerLayout * pShadowBL = NULL;
      UT_uint32 iCount = m_vecPages.getItemCount();
      m_pDoc->setDontChangeInsPoint();
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);

            // Find matching block in this shadow.

            pShadowBL = pPair->getShadow()->findMatchingContainer(pBL);
            if(pShadowBL)
            {
              bResult = static_cast<fl_BlockLayout *>(pShadowBL)->doclistener_deleteSpan(pcrs)
                && bResult;
            }
      }
      // Update the overall block too.

      m_pDoc->allowChangeInsPoint();
      pBL = findMatchingContainer(pBL);
      if(pBL)
        {
        bResult = static_cast<fl_BlockLayout *>(pBL)->doclistener_deleteSpan(pcrs)
          && bResult;
      }
      return bResult;
}

bool fl_HdrFtrSectionLayout::bl_doclistener_changeSpan(fl_ContainerLayout* pBL, const PX_ChangeRecord_SpanChange * pcrsc)
{
      bool bResult = true;
      fl_ContainerLayout * pShadowBL = NULL;
      UT_uint32 iCount = m_vecPages.getItemCount();
      m_pDoc->setDontChangeInsPoint();
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);

            // Find matching block in this shadow.

            pShadowBL = pPair->getShadow()->findMatchingContainer(pBL);
            if(pShadowBL)
            {
              bResult = static_cast<fl_BlockLayout *>(pShadowBL)->doclistener_changeSpan(pcrsc) && bResult;
            }
      }
      // Update the overall block too.

      m_pDoc->allowChangeInsPoint();
      pBL = findMatchingContainer(pBL);
      if(pBL)
      {
        bResult = static_cast<fl_BlockLayout *>(pBL)->doclistener_changeSpan(pcrsc)
            && bResult;
      }
      return bResult;
}

bool fl_HdrFtrSectionLayout::bl_doclistener_deleteStrux(fl_ContainerLayout* pBL, const PX_ChangeRecord_Strux * pcrx)
{
      bool bResult = true;
      fl_ContainerLayout * pShadowBL = NULL;
      UT_uint32 iCount = m_vecPages.getItemCount();
      m_pDoc->setDontChangeInsPoint();
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);

            // Find matching block in this shadow.

            pShadowBL = pPair->getShadow()->findMatchingContainer(pBL);
            if(pShadowBL)
            {
                  bResult = static_cast<fl_BlockLayout *>(pShadowBL)->doclistener_deleteStrux(pcrx)
                        && bResult;
            }
            else
            {
                  UT_ASSERT(0);
            }
      }
      // Update the overall block too.

      m_pDoc->allowChangeInsPoint();
      pBL = findMatchingContainer(pBL);
      if(pBL)
      {
            bResult = static_cast<fl_BlockLayout *>(pBL)->doclistener_deleteStrux(pcrx) && bResult;
      }
      return bResult;
}

/*!
 * Delete Just the cell struxes from the HdrFtr shadows
 */
bool fl_HdrFtrSectionLayout::bl_doclistener_deleteCellStrux(fl_ContainerLayout* pBL, const PX_ChangeRecord_Strux * pcrx)
{
      bool bResult = true;
      UT_ASSERT(pBL->getContainerType() == FL_CONTAINER_CELL);
      fl_ContainerLayout * pShadowBL = NULL;
      UT_uint32 iCount = m_vecPages.getItemCount();
      if(iCount <=0)
      {
            UT_ASSERT(0);
      }
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);

            // Find matching block in this shadow.

            pShadowBL = pPair->getShadow()->findMatchingContainer(pBL);
            if(pShadowBL)
            {
                  UT_ASSERT(pShadowBL->getContainerType() == FL_CONTAINER_CELL);
                  bResult = static_cast<fl_CellLayout *>(pShadowBL)->doclistener_deleteStrux(pcrx)
                        && bResult;
            }
            else
            {
                  UT_ASSERT(0);
            }
      }
      return bResult;
}


/*!
 * Delete Just the table struxes from the HdrFtr shadows
 */
bool fl_HdrFtrSectionLayout::bl_doclistener_deleteTableStrux(fl_ContainerLayout* pBL, const PX_ChangeRecord_Strux * pcrx)
{
      bool bResult = true;
      UT_ASSERT(pBL->getContainerType() == FL_CONTAINER_TABLE);
      fl_ContainerLayout * pShadowBL = NULL;
      UT_uint32 iCount = m_vecPages.getItemCount();
      if(iCount <=0)
      {
            UT_ASSERT(0);
      }
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);

            // Find matching block in this shadow.

            pShadowBL = pPair->getShadow()->findMatchingContainer(pBL);
            if(pShadowBL)
            {
                  UT_ASSERT(pShadowBL->getContainerType() == FL_CONTAINER_TABLE);
                  bResult = static_cast<fl_TableLayout *>(pShadowBL)->doclistener_deleteStrux(pcrx)
                        && bResult;
            }
            else
            {
                  UT_ASSERT(0);
            }
      }
      return bResult;
}


bool fl_HdrFtrSectionLayout::bl_doclistener_changeFmtMark(fl_ContainerLayout* pBL, const PX_ChangeRecord_FmtMarkChange * pcrfmc)
{
      bool bResult = true;
      fl_ContainerLayout * pShadowBL = NULL;
      UT_uint32 iCount = m_vecPages.getItemCount();
      m_pDoc->setDontChangeInsPoint();
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);

            // Find matching block in this shadow.

            pShadowBL = pPair->getShadow()->findMatchingContainer(pBL);
            if(pShadowBL)
            {
              bResult = static_cast<fl_BlockLayout *>(pShadowBL)->doclistener_changeFmtMark(pcrfmc)
                && bResult;
            }
      }
      // Update the overall block too.

      m_pDoc->allowChangeInsPoint();
      pBL = findMatchingContainer(pBL);
      if(pBL)
      {
        bResult = static_cast<fl_BlockLayout *>(pBL)->doclistener_changeFmtMark(pcrfmc) && bResult;
      }
      return bResult;
}

bool fl_HdrFtrSectionLayout::bl_doclistener_changeStrux(fl_ContainerLayout* pBL, const PX_ChangeRecord_StruxChange * pcrxc)
{
      bool bResult = true;
      fl_ContainerLayout * pShadowBL = NULL;
      UT_uint32 iCount = m_vecPages.getItemCount();
      m_pDoc->setDontChangeInsPoint();
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);

            // Find matching block in this shadow.

            pShadowBL = pPair->getShadow()->findMatchingContainer(pBL);
            if(pShadowBL)
            {
                  if(pShadowBL->getContainerType() == FL_CONTAINER_BLOCK)
                  {
                        bResult = static_cast<fl_BlockLayout *>(pShadowBL)->doclistener_changeStrux(pcrxc)
                              && bResult;
                  }
                  else if(pShadowBL->getContainerType() == FL_CONTAINER_TABLE)
                  {
                        bResult = static_cast<fl_TableLayout *>(pShadowBL)->doclistener_changeStrux(pcrxc)
                        && bResult;
                  }
                  else if(pShadowBL->getContainerType() == FL_CONTAINER_CELL)
                  {
                        bResult = static_cast<fl_CellLayout *>(pShadowBL)->doclistener_changeStrux(pcrxc)
                        && bResult;
                  }
            }
      }
      // Update the overall block too.

      m_pDoc->allowChangeInsPoint();
      pBL = findMatchingContainer(pBL);
      if(pBL && (pBL->getContainerType() == FL_CONTAINER_BLOCK))
      {
            bResult = static_cast<fl_BlockLayout *>(pBL)->doclistener_changeStrux(pcrxc)
                  && bResult;
      }
      return bResult;
}

/*!
 * Insert a cell into every table in the HdrFtr
 */
bool fl_HdrFtrSectionLayout::bl_doclistener_insertCell(fl_ContainerLayout* pCell,
                                                                    const PX_ChangeRecord_Strux * pcrx,
                                                                    PL_StruxDocHandle sdh,
                                                                    PL_ListenerId lid,
                                                                    fl_TableLayout * pTL)
{
      UT_uint32 iCount = m_vecPages.getItemCount();
      fl_ContainerLayout * pShadowBL = NULL;
      UT_DEBUGMSG(("fl_HdrFtrSectionLayout: insertCells into shadows \n"));
      m_pDoc->setDontChangeInsPoint();
      bool bResult = true;
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);

            // Find matching Table in this shadow.

            pShadowBL = pPair->getShadow()->findMatchingContainer(pTL);
            fl_ContainerLayout * pPrevCell = NULL;
            if(pCell)
            {
                  pPrevCell = pPair->getShadow()->findMatchingContainer(pCell);
            }
            UT_DEBUGMSG(("fl_HdrFtrSectionLayout: insertCell into Table shadow \n"));
            if(pShadowBL)
            {
                  bResult = static_cast<fl_TableLayout *>(pShadowBL)->bl_doclistener_insertCell(pPrevCell,pcrx,sdh,lid,NULL)
                        && bResult;
            }
      }
      m_pDoc->allowChangeInsPoint();
      return true;

}


/*!
 * Insert an endTable cell into every table in the HdrFtr
 */
bool fl_HdrFtrSectionLayout::bl_doclistener_insertEndTable(fl_ContainerLayout* pTab,
                                                                    const PX_ChangeRecord_Strux * pcrx,
                                                                    PL_StruxDocHandle sdh,
                                                                    PL_ListenerId lid)
{
      UT_uint32 iCount = m_vecPages.getItemCount();
      fl_ContainerLayout * pShadowBL = NULL;
      UT_DEBUGMSG(("fl_HdrFtrSectionLayout: insertEndTables into shadows \n"));
      m_pDoc->setDontChangeInsPoint();
      bool bResult = true;
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);

            // Find matching Table in this shadow.

            pShadowBL = pPair->getShadow()->findMatchingContainer(pTab);
            UT_DEBUGMSG(("fl_HdrFtrSectionLayout: insertEndTable into shadow \n"));
            if(pShadowBL)
            {
                  bResult = static_cast<fl_TableLayout *>(pShadowBL)->bl_doclistener_insertEndTable(NULL,pcrx,sdh,lid,NULL)
                        && bResult;
            }
      }
      m_pDoc->allowChangeInsPoint();
      return true;

}

fl_SectionLayout * fl_HdrFtrSectionLayout::bl_doclistener_insertTable(fl_ContainerLayout* pBL,
                                                                              SectionType iType,
                                                                              const PX_ChangeRecord_Strux * pcrx,
                                                                              PL_StruxDocHandle sdh,
                                                                              PL_ListenerId lid,
                                                                              void (* pfnBindHandles)(PL_StruxDocHandle sdhNew,
                                                                                                                  PL_ListenerId lid,
                                                                                                                  PL_StruxFmtHandle sfhNew))
{
      fl_SectionLayout * pSL = static_cast<fl_BlockLayout *>(pBL)->doclistener_insertTable(pcrx, iType, sdh, lid, pfnBindHandles);
//    UT_ASSERT(0);
      fl_SectionLayout::checkAndAdjustCellSize();
//
// FIXME: Propagate this to the shadows
//      : Write code to handle populate cases in the shadows
      bool bResult = true;
//
// Now insert it into all the shadows.
//
      UT_uint32 iCount = m_vecPages.getItemCount();
      fl_ContainerLayout * pShadowBL = NULL;
      UT_DEBUGMSG(("fl_HdrFtrSectionLayout: insertTable \n"));
      m_pDoc->setDontChangeInsPoint();
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);

            // Find matching block in this shadow.
            if(pBL)
            {
                  pShadowBL = pPair->getShadow()->findMatchingContainer(pBL);
                  UT_DEBUGMSG(("fl_HdrFtrSectionLayout: insertTable into shadow 1 \n"));
                  if(pShadowBL)
                  {
                        bResult = static_cast<fl_BlockLayout *>(pShadowBL)->doclistener_insertTable(pcrx,iType,sdh,lid,NULL)
                              && bResult;
                  }
                  pPair->getShadow()->checkAndAdjustCellSize();
            }
            else
//
// FIXME: Handle case of inserting a table at the start of the HdrFtr
//
            {
                  UT_ASSERT(0);
            }
      }
      m_pDoc->allowChangeInsPoint();
      return pSL;
}

/*!
 * Insert the first block of the container in HdrFtr. We need to propage this
 * to all the shadows.
 */
bool fl_HdrFtrSectionLayout::bl_doclistener_insertFirstBlock(fl_ContainerLayout* pCL, const PX_ChangeRecord_Strux * pcrx,PL_StruxDocHandle sdh,PL_ListenerId lid)
{
      UT_uint32 iCount = m_vecPages.getItemCount();
      fl_ContainerLayout * pShadowBL = NULL;
      UT_DEBUGMSG(("fl_HdrFtrSectionLayout: insert First block into shadow Cells \n"));
      m_pDoc->setDontChangeInsPoint();
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);

            // Find matching Table in this shadow.

            pShadowBL = pPair->getShadow()->findMatchingContainer(pCL);
            UT_DEBUGMSG(("fl_HdrFtrSectionLayout: insertFirstBlock into (CELL) shadow 1 \n"));
            if(pShadowBL)
            {
                  fl_BlockLayout*   pNewBL = static_cast<fl_BlockLayout *>(pShadowBL->insert(sdh, NULL, pcrx->getIndexAP(),FL_CONTAINER_BLOCK));
                  pNewBL->doclistener_insertFirstBlock(pcrx, sdh, lid, NULL);
            }
      }
      m_pDoc->allowChangeInsPoint();
      return true;

}

bool fl_HdrFtrSectionLayout::bl_doclistener_insertBlock(fl_ContainerLayout* pBL, const PX_ChangeRecord_Strux * pcrx,PL_StruxDocHandle sdh,PL_ListenerId lid,void (* pfnBindHandles)(PL_StruxDocHandle sdhNew,     PL_ListenerId lid, PL_StruxFmtHandle sfhNew))
{
      bool bResult = true;
//
// Now insert it into all the shadows.
//
      UT_uint32 iCount = m_vecPages.getItemCount();
      fl_ContainerLayout * pShadowBL = NULL;
      UT_DEBUGMSG(("fl_HdrFtrSectionLayout: insertBlock \n"));
      m_pDoc->setDontChangeInsPoint();
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);

            // Find matching block in this shadow.
            if(pBL)
            {
                  pShadowBL = pPair->getShadow()->findMatchingContainer(pBL);
                  xxx_UT_DEBUGMSG(("fl_HdrFtrSectionLayout: insertBlock into shadow 1 \n"));
                  if(pShadowBL)
                  {
                        bResult = static_cast<fl_BlockLayout *>(pShadowBL)->doclistener_insertBlock(pcrx,sdh,lid,NULL)
                              && bResult;
                  }
            }
            else
//
// This is the first block in the shadow
//
            {
                  fl_ContainerLayout*     pNewBL = pPair->getShadow()->insert(sdh, NULL, pcrx->getIndexAP(),FL_CONTAINER_BLOCK);
                  if (!pNewBL)
                  {
                        UT_DEBUGMSG(("no memory for BlockLayout\n"));
                        return false;
                  }
                  xxx_UT_DEBUGMSG(("fl_HdrFtrSectionLayout: insertBlock into shadow 2 \n"));
                  bResult = bResult && static_cast<fl_BlockLayout *>(pNewBL)->doclistener_insertFirstBlock(pcrx, sdh,
                                                                              lid, NULL);
            }
      }
//
// Find Matching Block in this HdrFtrSectionLayout!!
//
      m_pDoc->allowChangeInsPoint();
      if(pBL)
      {
            fl_ContainerLayout * ppBL = findMatchingContainer(pBL);
            if(ppBL)
            {
              static_cast<fl_BlockLayout *>(ppBL)->setHdrFtr();
              bResult = static_cast<fl_BlockLayout *>(ppBL)->doclistener_insertBlock(pcrx,sdh,lid,pfnBindHandles)
                  && bResult;
//
// Mark the Block as HdrFtr
//
              static_cast<fl_BlockLayout *>(ppBL->getNext())->setHdrFtr();
            }
            setNeedsReformat();
      }
      else
//
// First block in the section
//
      {
            fl_ContainerLayout*     pNewBL = insert(sdh, NULL, pcrx->getIndexAP(),FL_CONTAINER_BLOCK);
            if (!pNewBL)
            {
                  UT_DEBUGMSG(("no memory for BlockLayout\n"));
                  return false;
            }
            bResult = bResult && static_cast<fl_BlockLayout *>(pNewBL)->doclistener_insertFirstBlock(pcrx, sdh,
                                                                              lid, pfnBindHandles);
            static_cast<fl_BlockLayout *>(pNewBL)->setHdrFtr();
            setNeedsReformat();
      }
      return bResult;
}

bool fl_HdrFtrSectionLayout::bl_doclistener_insertSection(fl_ContainerLayout* pBL, const PX_ChangeRecord_Strux * pcrx,
                                                                                      PL_StruxDocHandle sdh,
                                                                                      PL_ListenerId lid,
                                                                                      void (* pfnBindHandles)(PL_StruxDocHandle sdhNew,
                                                                                                                          PL_ListenerId lid,
                                                                                                                          PL_StruxFmtHandle sfhNew))
{
      // TODO this should NEVER happen, right?
      UT_DEBUGMSG(("Insert Section is header/footer!!! \n"));
      UT_ASSERT(0);
      bool bResult = true;
      UT_uint32 iCount = m_vecPages.getItemCount();
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);

            bResult = pPair->getShadow()->bl_doclistener_insertSection(pBL, FL_SECTION_DOC, pcrx, sdh, lid, pfnBindHandles)
                  && bResult;
      }

      return bResult;
}

bool fl_HdrFtrSectionLayout::bl_doclistener_insertObject(fl_ContainerLayout* pBL, const PX_ChangeRecord_Object * pcro)
{
      bool bResult = true;
      fl_ContainerLayout * pShadowBL = NULL;
      UT_uint32 iCount = m_vecPages.getItemCount();
      m_pDoc->setDontChangeInsPoint();
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);
            // Find matching block in this shadow.
            pShadowBL = pPair->getShadow()->findMatchingContainer(pBL);
            if(pShadowBL)
            {
                  bResult = static_cast<fl_BlockLayout *>(pShadowBL)->doclistener_insertObject(pcro)
                        && bResult;
            }
      }
      // Update the overall block too.
      m_pDoc->allowChangeInsPoint();
      pBL = findMatchingContainer(pBL);
      if(pBL)
      {
            bResult = static_cast<fl_BlockLayout *>(pBL)->doclistener_insertObject(pcro) && bResult;
      }
      return bResult;
}

bool fl_HdrFtrSectionLayout::bl_doclistener_deleteObject(fl_ContainerLayout* pBL, const PX_ChangeRecord_Object * pcro)
{
      bool bResult = true;
      fl_ContainerLayout * pShadowBL = NULL;
      UT_uint32 iCount = m_vecPages.getItemCount();
      m_pDoc->setDontChangeInsPoint();
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);
            // Find matching block in this shadow.
            pShadowBL = pPair->getShadow()->findMatchingContainer(pBL);
            if(pShadowBL)
            {
                  bResult = static_cast<fl_BlockLayout *>(pShadowBL)->doclistener_deleteObject(pcro)
                        && bResult;
            }
      }
      // Update the overall block too.
      m_pDoc->allowChangeInsPoint();
      pBL = findMatchingContainer(pBL);
      if(pBL)
      {
            bResult = static_cast<fl_BlockLayout *>(pBL)->doclistener_deleteObject(pcro) && bResult;
      }
      return bResult;
}

bool fl_HdrFtrSectionLayout::bl_doclistener_changeObject(fl_ContainerLayout* pBL, const PX_ChangeRecord_ObjectChange * pcroc)
{
      bool bResult = true;
      fl_ContainerLayout * pShadowBL = NULL;
      UT_uint32 iCount = m_vecPages.getItemCount();
      m_pDoc->setDontChangeInsPoint();
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);
            // Find matching block in this shadow.
            pShadowBL = pPair->getShadow()->findMatchingContainer(pBL);
            if(pShadowBL)
            {
                  bResult = static_cast<fl_BlockLayout *>(pShadowBL)->doclistener_changeObject(pcroc)
                        && bResult;
            }
      }
      // Update the overall block too.
      m_pDoc->allowChangeInsPoint();
      pBL = findMatchingContainer(pBL);
      if(pBL)
      {
            bResult = static_cast<fl_BlockLayout *>(pBL)->doclistener_changeObject(pcroc) && bResult;
      }

      return bResult;
}

bool fl_HdrFtrSectionLayout::bl_doclistener_insertFmtMark(fl_ContainerLayout* pBL, const PX_ChangeRecord_FmtMark * pcrfm)
{
      bool bResult = true;
      fl_ContainerLayout * pShadowBL = NULL;
      UT_uint32 iCount = m_vecPages.getItemCount();
      m_pDoc->setDontChangeInsPoint();
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);
            // Find matching block in this shadow.
            pShadowBL = pPair->getShadow()->findMatchingContainer(pBL);
            if(pShadowBL)
            {
                  bResult = static_cast<fl_BlockLayout *>(pShadowBL)->doclistener_insertFmtMark(pcrfm)
                        && bResult;
            }
            else
            {
                  bResult = false;
            }
      }
      // Update the overall block too.
      m_pDoc->allowChangeInsPoint();
      pBL = findMatchingContainer(pBL);
      if(pBL)
      {
            bResult = static_cast<fl_BlockLayout *>(pBL)->doclistener_insertFmtMark(pcrfm) && bResult;
      }
      else
      {
            bResult = false;
      }
      return bResult;
}

bool fl_HdrFtrSectionLayout::bl_doclistener_deleteFmtMark(fl_ContainerLayout* pBL, const PX_ChangeRecord_FmtMark * pcrfm)
{
      bool bResult = true;
      fl_ContainerLayout * pShadowBL = NULL;
      UT_uint32 iCount = m_vecPages.getItemCount();
      m_pDoc->setDontChangeInsPoint();
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);
            // Find matching block in this shadow.
            pShadowBL = pPair->getShadow()->findMatchingContainer(pBL);
            if(pShadowBL)
            {
                  bResult = static_cast<fl_BlockLayout *>(pShadowBL)->doclistener_deleteFmtMark(pcrfm)
                        && bResult;
            }
            else
            {
                  bResult = false;
            }
      }
      // Update the overall block too.
      m_pDoc->allowChangeInsPoint();
      pBL = findMatchingContainer(pBL);
      if(pBL)
      {
            bResult = static_cast<fl_BlockLayout *>(pBL)->doclistener_deleteFmtMark(pcrfm)      && bResult;
      }
      else
      {
            bResult = false;
      }
      return bResult;
}

void fl_HdrFtrSectionLayout::checkAndAdjustCellSize(fl_ContainerLayout * pCL)
{
      if(pCL->getContainerType() != FL_CONTAINER_CELL)
      {
            return;
      }
      fl_ContainerLayout * pShadowBL = NULL;
      UT_uint32 iCount = m_vecPages.getItemCount();
      for (UT_uint32 i=0; i<iCount; i++)
      {
            _PageHdrFtrShadowPair* pPair = m_vecPages.getNthItem(i);
            // Find matching block in this shadow.
            pShadowBL = pPair->getShadow()->findMatchingContainer(pCL);
            if(pShadowBL)
            {
                  static_cast<fl_SectionLayout *>(pShadowBL)->checkAndAdjustCellSize();
            }
      }
      // Update the overall block too.

      fl_ContainerLayout * pBL = findMatchingContainer(pCL);
      if(pBL)
      {
            static_cast<fl_CellLayout *>(pBL)->checkAndAdjustCellSize();
      }
      return;
}

////////////////////////////////////////////////////////////////////////////

bool fl_DocSectionLayout::bl_doclistener_insertFootnote(fl_ContainerLayout* pFootnote,
                                                                    const PX_ChangeRecord_Strux * pcrx,
                                                                    PL_StruxDocHandle sdh,
                                                                    PL_ListenerId lid,
                                                                    void (* pfnBindHandles)(PL_StruxDocHandle sdhNew,
                                                                                                        PL_ListenerId lid,
                                                                                                        PL_StruxFmtHandle sfhNew))
{
      fl_ContainerLayout * pNewCL = NULL;
      fl_DocSectionLayout * pCol = static_cast<fl_DocSectionLayout *>(myContainingLayout());
      pNewCL = pCol->insert(sdh,pFootnote,pcrx->getIndexAP(), FL_CONTAINER_FOOTNOTE);
      
            // Must call the bind function to complete the exchange of handles
            // with the document (piece table) *** before *** anything tries
            // to call down into the document (like all of the view
            // listeners).
            
      PL_StruxFmtHandle sfhNew = static_cast<PL_StruxFmtHandle>(pNewCL);
      pfnBindHandles(sdh,lid,sfhNew);


//
// increment the insertion point in the view.
//
      FV_View* pView = m_pLayout->getView();
      if (pView && (pView->isActive() || pView->isPreview()))
      {
            pView->setPoint(pcrx->getPosition() +  fl_BLOCK_STRUX_OFFSET);
      }
      else if(pView && pView->getPoint() > pcrx->getPosition())
      {
            pView->setPoint(pView->getPoint() +  fl_BLOCK_STRUX_OFFSET);
      }
      return true;
}

//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////

fl_HdrFtrShadow::fl_HdrFtrShadow(FL_DocLayout* pLayout, fp_Page* pPage, fl_HdrFtrSectionLayout* pHdrFtrSL, PL_StruxDocHandle sdh, PT_AttrPropIndex indexAP)
      : fl_SectionLayout(pLayout, sdh, indexAP, FL_SECTION_SHADOW,FL_CONTAINER_SHADOW,PTX_Section,pHdrFtrSL->getDocSectionLayout()),
        m_pPage(pPage),
        m_pHdrFtrSL(pHdrFtrSL)
{
      // Force creation of the appropriate container object;
      // throw away return value.
      m_pPage->getHdrFtrContainer(m_pHdrFtrSL);
      UT_DEBUGMSG(("check that m_iType is indeed FL_SECTION_SHADOW \n"));
      UT_ASSERT(m_iType == FL_SECTION_SHADOW);
//    UT_ASSERT(0);
      fl_Layout::setType(PTX_Section); // Set the type of this strux
}

fl_HdrFtrShadow::~fl_HdrFtrShadow()
{
      _purgeLayout();
}

fp_Container* fl_HdrFtrShadow::getFirstContainer() const
{
      return m_pPage->getHdrFtrContainer(m_pHdrFtrSL);
}

fp_Container* fl_HdrFtrShadow::getLastContainer() const
{
      return m_pPage->getHdrFtrContainer(m_pHdrFtrSL);
}

fp_Container* fl_HdrFtrShadow::getNewContainer(fp_Container * pFirstContainer)
{
      UT_ASSERT(UT_SHOULD_NOT_HAPPEN);

      return NULL;
}

fl_ContainerLayout* fl_HdrFtrShadow::findMatchingContainer(fl_ContainerLayout* pBL)
{
      // This routine returns the matching block within this shadow of the
      // hdrftrSectionlayout.
      //
      fl_ContainerLayout* ppBL = getFirstLayout();
      bool bInTable = false;
      while(ppBL && (ppBL->getStruxDocHandle() != pBL->getStruxDocHandle()))
      {
            if(ppBL->getContainerType() == FL_CONTAINER_TABLE)
            {
                  ppBL = ppBL->getFirstLayout();
                  bInTable = true;
            }
            else if(bInTable && ppBL->getContainerType() == FL_CONTAINER_CELL)
            {
                  ppBL = ppBL->getFirstLayout();
            }
            else if(bInTable && (ppBL->getNext() == NULL))
            {
                  if(ppBL->myContainingLayout()->getNext() == NULL)
                  {
                        ppBL = ppBL->myContainingLayout();
                        ppBL = ppBL->myContainingLayout()->getNext();
                        bInTable = false;
                  }
                  else
                  {
                        ppBL = ppBL->myContainingLayout()->getNext();
                  }
            }
            else
            {
                  ppBL = ppBL->getNext();
            }
      }
      if(ppBL == NULL)
      {
            //UT_ASSERT(0);
            m_pDoc->miniDump(pBL->getStruxDocHandle(),6);
            if(pBL->getContainerType() == FL_CONTAINER_BLOCK)
            {
                  ppBL = getFirstLayout();
                  while(ppBL && ppBL->getStruxDocHandle() != pBL->getStruxDocHandle())
                  {
                        ppBL = ppBL->getNextBlockInDocument();
                  }
            }
      }
      //UT_ASSERT(ppBL);
      xxx_UT_DEBUGMSG(("Search for block in shadow %x \n",this));
      return ppBL;
}

void fl_HdrFtrShadow::format(void)
{
      fl_ContainerLayout*     pBL = getFirstLayout();
      while (pBL)
      {
            if(pBL->getContainerType() == FL_CONTAINER_TABLE)
            {
                  UT_DEBUGMSG(("!!!!Format Shadow Table!!!!!!!!!!\n"));
            }
            pBL->format();
            pBL = pBL->getNext();
      }
}

/*!
 * Scans through the shadow looking for the block at the specified Document
 * Position.
 \param pos the Document position
 \return A pointer to the block containing the point. Returns NULL if no block
         is found
 */
fl_ContainerLayout * fl_HdrFtrShadow::findBlockAtPosition(PT_DocPosition pos)
{
//
// Skip through the blocks in this shadow to find the one containing this
// point.
//
    fl_ContainerLayout* pBL = getFirstLayout();
      if(pBL == NULL)
            return NULL;
      if(pos < pBL->getPosition(true))
      {
//
// This corner case is that pos == position of the HdrFtr strux
//
            if(pos == (pBL->getPosition(true) - 1))
            {
                  if(pBL->getContainerType() != FL_CONTAINER_BLOCK)
                  {
                        pBL= pBL->getNextBlockInDocument();
                  }
                  return pBL;
            }
            return NULL;
      }
      fl_ContainerLayout* pNext = NULL;
      pNext = pBL->getNextBlockInDocument();
      bool doNext = false;
      if(pNext != NULL)
      {
            doNext = (pNext->getPosition(true) < pos);
      }
      while(doNext)
      {
            pBL = pNext;
            pNext = pNext->getNextBlockInDocument();
            if(pNext && (pNext->getPosition(true) < pos))
            {
                  if(getNext())
                  {
                        if(getNext()->getPosition(true) > pNext->getPosition(true))
                        {
                              doNext = true;
                        }
                        else
                        {
                              doNext = false;
                        }
                  }
                  else
                  {
                        doNext = true;
                  }
            }
            else
            {
                  doNext = false;
            }
      }

      if(pNext != NULL)
      {
            UT_ASSERT(pNext->getPosition(true) >= pos);
            if(pBL->getContainerType() == FL_CONTAINER_BLOCK)
            {
                  return pBL;
            }
            else if(pNext->getContainerType() == FL_CONTAINER_BLOCK)
            {
                  return pNext;
            }
      }
      else if(pBL && pBL->getPosition() == pos)
      {
            return pBL;
      }
      else
      {
            return NULL;
      }
//
// Next corner case. See if position is inside the edittableBounds of this
// section
//
      PT_DocPosition posEnd;
      FV_View * pView = m_pLayout->getView();
      if(pView)
      {
            pView->getEditableBounds(true,posEnd);
            if(pos <= posEnd)
                  return pBL;
      }
//
// Now the point MIGHT be in this last block. Use code from pd_Document
// to find out. Have to check whether we're out of docrange first
//
      m_pDoc->getBounds(true,posEnd);
      if(pos > posEnd)
            return NULL;
      PL_StruxDocHandle sdh=NULL;
      bool bres;
      bres = m_pDoc->getStruxOfTypeFromPosition(pos, PTX_Block, &sdh);
      if(bres && sdh == pBL->getStruxDocHandle())
            return pBL;
//
// Not here!!
//
      return NULL;
}

void fl_HdrFtrShadow::updateLayout(void)
{
      bool bredraw = false;
      xxx_UT_DEBUGMSG(("Doing Update layout in shadow %x \n",this));
      fl_ContainerLayout*     pBL = getFirstLayout();
      while (pBL)
      {
            if (pBL->needsReformat())
            {
                  bredraw = true;
                  pBL->format();
            }

            pBL = pBL->getNext();
      }
      if(bredraw)
      {
            //    clearScreen();
            static_cast<fp_ShadowContainer *>(getFirstContainer())->layout();
      }
}

void fl_HdrFtrShadow::layout(void)
{
      if(needsReformat())
      {
            format();
      }
      static_cast<fp_ShadowContainer *>(getFirstContainer())->layout();
}

void fl_HdrFtrShadow::clearScreen(void)
{
      UT_ASSERT(getFirstContainer());
      if(getFirstContainer())
            static_cast<fp_ShadowContainer *>(getFirstContainer())->clearScreen();
}

void fl_HdrFtrShadow::redrawUpdate(void)
{
      FV_View * pView = m_pLayout->getView();
      fl_ContainerLayout*     pBL = getFirstLayout();
      while (pBL && (pView != NULL))
      {
            if(pBL->getContainerType() == FL_CONTAINER_BLOCK && static_cast<fl_BlockLayout *>(pBL)->hasUpdatableField())
            {
                  bool bReformat = pBL->recalculateFields(getDocLayout()->getRedrawCount());
                  if(bReformat)
                  {
                        pBL->format();
                  }
            }
            else
            {
                  pBL->recalculateFields(getDocLayout()->getRedrawCount());
            }
            
            if(pView && pBL->needsRedraw())
            {
                  pBL->redrawUpdate();
            }
            pBL = pBL->getNext();
      }
      static_cast<fp_ShadowContainer *>(getFirstContainer())->layout();
}
bool fl_HdrFtrShadow::doclistener_changeStrux(const PX_ChangeRecord_StruxChange * pcrxc)
{
      UT_ASSERT(pcrxc->getType()==PX_ChangeRecord::PXT_ChangeStrux);

      setAttrPropIndex(pcrxc->getIndexAP());

      // TODO

      UT_ASSERT(UT_SHOULD_NOT_HAPPEN);

      return false;
}

/*!
    this function is only to be called by fl_ContainerLayout::lookupProperties()
    all other code must call lookupProperties() instead
*/
void fl_HdrFtrShadow::_lookupProperties(const PP_AttrProp* pAP)
{
}

//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////

fl_ShadowListener::fl_ShadowListener(fl_HdrFtrSectionLayout* pHFSL, fl_HdrFtrShadow* pShadow): 
      m_pDoc(pHFSL->getDocLayout()->getDocument()),
      m_pShadow(pShadow),
      m_bListening(false),
      m_pCurrentBL(NULL),
      m_pHFSL(pHFSL),
      m_pCurrentTL(NULL),
      m_pCurrentCell(NULL)
{
}

fl_ShadowListener::~fl_ShadowListener()
{
}

bool fl_ShadowListener::populate(PL_StruxFmtHandle sfh,
                                                 const PX_ChangeRecord * pcr)
{
      if (!m_bListening)
      {
            return true;
      }

      UT_ASSERT(m_pShadow);
//    UT_DEBUGMSG(("fl_ShadowListener::populate shadow %x \n",m_pShadow));

      bool bResult = false;
      FV_View* pView = m_pHFSL->getDocLayout()->getView();
      PT_DocPosition oldPos = 0;
      //
      // We're not printing
      //
      if(pView != NULL)
      {
            oldPos = pView->getPoint();
      }
      switch (pcr->getType())
      {
      case PX_ChangeRecord::PXT_InsertSpan:
      {
            const PX_ChangeRecord_Span * pcrs = static_cast<const PX_ChangeRecord_Span *> (pcr);

            {
                  const fl_Layout * pL = static_cast<const fl_Layout *>(sfh);
                  UT_ASSERT(pL->getType() == PTX_Block);
                  UT_ASSERT(m_pCurrentBL == (static_cast<const fl_ContainerLayout *>(pL)));
            }
            PT_BlockOffset blockOffset = pcrs->getBlockOffset();
            UT_uint32 len = pcrs->getLength();


            bResult = static_cast<fl_BlockLayout *>(m_pCurrentBL)->doclistener_populateSpan(pcrs, blockOffset, len);
            goto finish_up;
      }

      case PX_ChangeRecord::PXT_InsertObject:
      {
            const PX_ChangeRecord_Object * pcro = static_cast<const PX_ChangeRecord_Object *>(pcr);

            {
                  const fl_Layout * pL = static_cast<const fl_Layout *>(sfh);
                  UT_ASSERT(pL->getType() == PTX_Block);
                  UT_ASSERT(m_pCurrentBL == (static_cast<const fl_ContainerLayout *>(pL)));
            }
            PT_BlockOffset blockOffset = pcro->getBlockOffset();

// sterwill -- is this call to getSectionLayout() needed?  pBLSL is not used.

//                fl_SectionLayout* pBLSL = m_pCurrentBL->getSectionLayout();
            bResult = static_cast<fl_BlockLayout *>(m_pCurrentBL)->doclistener_populateObject(blockOffset,pcro);
            goto finish_up;
      }

      case PX_ChangeRecord::PXT_InsertFmtMark:
      {
            //    const PX_ChangeRecord_FmtMark * pcrfm = static_cast<const PX_ChangeRecord_FmtMark *>(pcr);

            {
                  const fl_Layout * pL = static_cast<const fl_Layout *>(sfh);
                  UT_ASSERT(pL->getType() == PTX_Block);
                  UT_ASSERT(m_pCurrentBL == (static_cast<const fl_ContainerLayout *>(pL)));
            }
            bResult = static_cast<fl_BlockLayout *>(m_pCurrentBL)->doclistener_insertFmtMark( reinterpret_cast<const PX_ChangeRecord_FmtMark *>(pcr));
            goto finish_up;
      }

      default:
            UT_DEBUGMSG(("Unknown Change record = %d \n",pcr->getType()));
            UT_ASSERT(0);
            //
            // We're not printing
            //
            if(pView != NULL && m_pDoc->getAllowChangeInsPoint())
            {
                  pView->setPoint(oldPos);
            }
            return false;
      }

 finish_up:
      //
      // We're not printing
      //
      if(pView != NULL && m_pDoc->getAllowChangeInsPoint())
      {
            pView->setPoint(oldPos);
      }
      return bResult;
}

bool fl_ShadowListener::populateStrux(PL_StruxDocHandle sdh,
                                                        const PX_ChangeRecord * pcr,
                                                        PL_StruxFmtHandle * psfh)
{
      UT_ASSERT(m_pShadow);
      UT_DEBUGMSG(("fl_ShadowListener::populateStrux\n"));

      UT_ASSERT(pcr->getType() == PX_ChangeRecord::PXT_InsertStrux);
      const PX_ChangeRecord_Strux * pcrx = static_cast<const PX_ChangeRecord_Strux *> (pcr);

      switch (pcrx->getStruxType())
      {
      case PTX_Section:
      {
            PT_AttrPropIndex indexAP = pcr->getIndexAP();
            const PP_AttrProp* pAP = NULL;

            // need to explode revision attribute
            m_pDoc->getAttrProp(indexAP, &pAP);
            if(pAP)
            {
                  UT_return_val_if_fail(m_pHFSL && m_pHFSL->getDocLayout(), false);
                  FV_View* pView = m_pHFSL->getDocLayout()->getView();
                  UT_return_val_if_fail(pView, false);

                  UT_uint32 iId  = pView->getRevisionLevel();
                  bool bShow     = pView->isShowRevisions();

                  PP_RevisionAttr * pRevisions = NULL; // must be NULL

                  
                  if(  pAP->getRevisedIndex() != 0xffffffff
                    && pAP->getRevisionState().isEqual(iId, bShow, m_pDoc->isMarkRevisions()))
                  {
                        // the revision has a valid index to an inflated AP, so we use it
                        PT_AttrPropIndex revAPI = pAP->getRevisedIndex();

                        m_pDoc->getAttrProp(revAPI, &pAP);
                  }
                  else
                  {
                        bool bHiddenRevision;
                        const PP_AttrProp * pNewAP = m_pDoc->explodeRevisions(pRevisions, pAP, bShow,
                                                                                                        iId, bHiddenRevision);

                        if(pNewAP)
                              pAP = pNewAP;
                  }
            }
            
            if (pAP)
            {
                  const XML_Char* pszSectionType = NULL;
                  pAP->getAttribute("type", pszSectionType);
                  if (
                        !pszSectionType
                        || (0 == UT_strcmp(pszSectionType, "doc"))
                        )
                  {
                        m_bListening = false;
                  }
                  else
                  {
                        if ( (0 == UT_strcmp(pszSectionType, "header"))
                              || (0 == UT_strcmp(pszSectionType, "footer"))
                               || (0 == UT_strcmp(pszSectionType, "header-first"))
                              || (0 == UT_strcmp(pszSectionType, "footer-first"))
                               || (0 == UT_strcmp(pszSectionType, "header-even"))
                              || (0 == UT_strcmp(pszSectionType, "footer-even"))
                               || (0 == UT_strcmp(pszSectionType, "header-last"))
                              || (0 == UT_strcmp(pszSectionType, "footer-last"))
                              )
                        {
                              // TODO verify id match

                              m_bListening = true;
                        }
                        else
                        {
                              return false;
                        }
                  }
            }
            else
            {
                  // TODO fail?
                  return false;
            }
      }
      break;

      case PTX_SectionHdrFtr:
      {
            PT_AttrPropIndex indexAP = pcr->getIndexAP();
            const PP_AttrProp* pAP = NULL;
            // need to explode revision attribute
            m_pDoc->getAttrProp(indexAP, &pAP);
            if(pAP)
            {
                  UT_return_val_if_fail(m_pHFSL && m_pHFSL->getDocLayout(), false);
                  FV_View* pView = m_pHFSL->getDocLayout()->getView();
                  UT_return_val_if_fail(pView, false);

                  UT_uint32 iId  = pView->getRevisionLevel();
                  bool bShow     = pView->isShowRevisions();

                  PP_RevisionAttr * pRevisions = NULL; // must be NULL

                  
                  if(  pAP->getRevisedIndex() != 0xffffffff
                    && pAP->getRevisionState().isEqual(iId, bShow, m_pDoc->isMarkRevisions()))
                  {
                        // the revision has a valid index to an inflated AP, so we use it
                        PT_AttrPropIndex revAPI = pAP->getRevisedIndex();

                        m_pDoc->getAttrProp(revAPI, &pAP);
                  }
                  else
                  {
                        bool bHiddenRevision;
                        const PP_AttrProp * pNewAP = m_pDoc->explodeRevisions(pRevisions, pAP, bShow,
                                                                                                        iId, bHiddenRevision);

                        if(pNewAP)
                              pAP = pNewAP;
                  }
            }
            
            if (pAP)
            {
                  const XML_Char* pszSectionType = NULL;
                  pAP->getAttribute("type", pszSectionType);
                  if (
                        !pszSectionType
                        || (0 == UT_strcmp(pszSectionType, "doc"))
                        )
                  {
                        m_bListening = false;
                  }
                  else
                  {
                        if ( (0 == UT_strcmp(pszSectionType, "header"))
                              || (0 == UT_strcmp(pszSectionType, "footer"))
                               || (0 == UT_strcmp(pszSectionType, "header-first"))
                              || (0 == UT_strcmp(pszSectionType, "footer-first"))
                               || (0 == UT_strcmp(pszSectionType, "header-even"))
                              || (0 == UT_strcmp(pszSectionType, "footer-even"))
                               || (0 == UT_strcmp(pszSectionType, "header-last"))
                              || (0 == UT_strcmp(pszSectionType, "footer-last"))
                              )
                        {
                              // TODO verify id match

                              m_bListening = true;
                        }
                        else
                        {
                              return false;
                        }
                  }
            }
            else
            {
                  // TODO fail?
                  return false;
            }
      }
      break;

      case PTX_Block:
      {
            if (m_bListening)
            {
                  // append a new BlockLayout to that SectionLayout
                  fl_ContainerLayout*     pBL = NULL;
                  if(m_pCurrentCell == NULL)
                  {
                        pBL = m_pShadow->append(sdh, pcr->getIndexAP(),FL_CONTAINER_BLOCK);
                  }
                  else
                  {
                        pBL = m_pCurrentCell->append(sdh, pcr->getIndexAP(),FL_CONTAINER_BLOCK);
                  }
                  UT_DEBUGMSG(("New Shadow block %x created and set as current \n",pBL));
                  if (!pBL)
                  {
                        UT_DEBUGMSG(("no memory for BlockLayout"));
                        return false;
                  }
                  m_pCurrentBL = pBL;
                  *psfh = static_cast<PL_StruxFmtHandle>(pBL);
            }

      }
      break;


      case PTX_SectionTable:
      {
            if (m_bListening)
            {
                  // append a new BlockLayout to that SectionLayout
                  fl_ContainerLayout*     pTL = m_pShadow->append(sdh, pcr->getIndexAP(),FL_CONTAINER_TABLE);
                  UT_DEBUGMSG(("New Shadow Table %x created and set as current \n",pTL));
                  m_pCurrentTL = static_cast<fl_TableLayout *>(pTL);
                  *psfh = static_cast<PL_StruxFmtHandle>(pTL);
            }

      }
      break;


      case PTX_SectionCell:
      {
            if (m_bListening && m_pCurrentTL)
            {

                  // append a new BlockLayout to that SectionLayout
                  fl_ContainerLayout*     pCell = m_pCurrentTL->append(sdh, pcr->getIndexAP(),FL_CONTAINER_CELL);
                  UT_DEBUGMSG(("New Shadow Cell %x created and set as current \n",pCell));
                  m_pCurrentCell = static_cast<fl_CellLayout *>(pCell);
                  *psfh = static_cast<PL_StruxFmtHandle>(m_pCurrentCell);
            }

      }
      break;

      case PTX_EndTable:
      {
            if(m_pCurrentTL == NULL)
            {
                  m_pDoc->miniDump(sdh,6);
            }

            UT_return_val_if_fail(m_pCurrentTL,false);
            UT_DEBUGMSG(("!!!! Append End Table to Shadow \n"));
            if(m_pCurrentTL->getContainerType() != FL_CONTAINER_TABLE)
            {
                  UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
                  return false;
            }
            *psfh = (PL_StruxFmtHandle)m_pCurrentTL;
            UT_DEBUGMSG(("SEVIOR: End table in  shadow listener \n"));
            m_pCurrentTL->setDirty();
            m_pCurrentTL->setEndTableIn();
            m_pCurrentTL = NULL;
      }
      break;
      case PTX_EndCell:
      {
            UT_ASSERT(m_pCurrentCell);
            UT_DEBUGMSG(("!!!! Append End Cell in Shadow Listener\n"));
            *psfh = (PL_StruxFmtHandle) m_pCurrentCell;
            m_pCurrentCell = NULL;
      }
      break;

      default:
            UT_ASSERT(0);
            return false;
      }
      //
      // We're not printing
      //
      return true;
}

bool fl_ShadowListener::change(PL_StruxFmtHandle /*sfh*/,
                                             const PX_ChangeRecord * /*pcr*/)
{
      UT_ASSERT(UT_SHOULD_NOT_HAPPEN);

      return false;
}

bool fl_ShadowListener::insertStrux(PL_StruxFmtHandle /*sfh*/,
                                                      const PX_ChangeRecord * /*pcr*/,
                                                      PL_StruxDocHandle /*sdh*/,
                                                      PL_ListenerId /*lid*/,
                                                      void (* /*pfnBindHandles*/)(PL_StruxDocHandle sdhNew,
                                                                                                PL_ListenerId lid,
                                                                                                PL_StruxFmtHandle sfhNew))
{
      UT_ASSERT(UT_SHOULD_NOT_HAPPEN);

      return false;
}

bool fl_ShadowListener::signal(UT_uint32 /*iSignal*/)
{
      UT_ASSERT(UT_SHOULD_NOT_HAPPEN);

      return false;
}



Generated by  Doxygen 1.6.0   Back to index