/* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */ /* AbiWord * Copyright (C) 1998 AbiSource, Inc. * Copyright (C) 2002 Martin Sevior * * 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. */ /* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /* * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS * file for a list of people on the GTK+ Team. See the ChangeLog * files for a list of changes. These files are distributed with * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ // // Uncomment to benchmark our table layout time with release builds //#define BENCHLAYOUT 1 #include #include #include #include "fp_TableContainer.h" #include "fp_Column.h" #include "fp_Page.h" #include "fp_Line.h" #include "fv_View.h" #include "fl_SectionLayout.h" #include "fl_TableLayout.h" #include "gr_DrawArgs.h" #include "ut_vector.h" #include "ut_types.h" #include "ut_debugmsg.h" #include "ut_assert.h" #include "fl_FootnoteLayout.h" #include "fp_FootnoteContainer.h" #include "fp_FrameContainer.h" #include "gr_Painter.h" #include "pd_Document.h" #if BENCHLAYOUT #include #endif fp_TableRowColumn::fp_TableRowColumn(void) : requisition(0), allocation(0), spacing(0), need_expand(false), need_shrink(true), expand(true), shrink(true), empty(true) { } fp_TableRowColumn::~fp_TableRowColumn(void) { } /*! Create Cell container \param iType Container type \param pSectionLayout Section layout type used for this container */ fp_CellContainer::fp_CellContainer(fl_SectionLayout* pSectionLayout) : fp_VerticalContainer(FP_CONTAINER_CELL, pSectionLayout), m_iLeftAttach(0), m_iRightAttach(0), m_iTopAttach(0), m_iBottomAttach(0), m_borderColorNone(127,127,127), m_iLeftPad(0), m_iRightPad(0), m_iTopPad(0), m_iBotPad(0), m_pNextInTable(NULL), m_pPrevInTable(NULL), m_bXexpand(true), m_bYexpand(false), m_bXshrink(false), m_bYshrink(true), m_bXfill(true), m_bYfill(false), m_iLeft(0), m_iRight(0), m_iTopY(0), m_iBotY(0), m_bDrawLeft(false), m_bDrawTop(false), m_bDrawBot(false), m_bDrawRight(false), m_bLinesDrawn(false), m_bBgDirty(true), m_bIsSelected(false), m_bDirty(true), m_bIsRepeated(false) { } /*! Destruct container \note The Containers in vector of the container are not destructed. They are owned by the logical hierarchy (i.e., the fl_Container classes like fl_BlockLayout), not the physical hierarchy. */ fp_CellContainer::~fp_CellContainer() { xxx_UT_DEBUGMSG(("Deleting Cell container %x \n",this)); setNext(NULL); setPrev(NULL); } bool fp_CellContainer::isRepeated(void) const { return m_bIsRepeated; } void fp_CellContainer::setHeight(UT_sint32 iHeight) { xxx_UT_DEBUGMSG(("cell: Height was %d \n",getHeight())); if ((iHeight == getHeight()) || (iHeight== 0)) { return; } clearScreen(); fp_TableContainer * pTab = static_cast(getContainer()); if(pTab && getBottomAttach() == pTab->getNumRows()) { fp_CellContainer * pCell = pTab->getCellAtRowColumn(pTab->getNumRows() -1,0); while(pCell) { pCell->clearScreen(); pCell->getSectionLayout()->setNeedsRedraw(); pCell->getSectionLayout()->markAllRunsDirty(); pCell = static_cast(pCell->getNext()); } } fp_VerticalContainer::setHeight(iHeight); xxx_UT_DEBUGMSG(("cell: Height set to %d \n",getHeight())); fl_SectionLayout * pSL = getSectionLayout(); pSL = static_cast(pSL->myContainingLayout()); UT_ASSERT(pSL->getContainerType() == FL_CONTAINER_TABLE); static_cast(pSL)->setDirty(); static_cast(pSL)->setHeightChanged(this); } /*! * Return the broken table that contains this cell and the given Container */ fp_TableContainer * fp_CellContainer::getBrokenTable(fp_Container * pCon) { fp_TableContainer * pMaster = static_cast(getContainer()); fp_CellContainer * pTopCell = this; bool bNest = false; if(pMaster == NULL) { return pMaster; } fp_TableContainer * pBroke = pMaster->getFirstBrokenTable(); while(pBroke != NULL) { if(pTopCell->doesOverlapBrokenTable(pBroke)) { if(pCon->getContainerType() == FP_CONTAINER_TABLE) { fp_TableContainer * pT = static_cast(pCon); if(!pT->isThisBroken()) { fp_TableContainer * pTT = pT->getFirstBrokenTable(); if(pTT == NULL) { UT_sint32 iY = pT->getY(); UT_DEBUGMSG(("No Broken Table!! \n")); pT = static_cast(pT->VBreakAt(0)); pT->setY(iY); } else { pT = pTT; } } xxx_UT_DEBUGMSG(("Y of broken table %x is %d yBreak is %d height %d \n",pT,pT->getY(),pT->getYBreak(),pT->getHeight())); bNest = true; } if(pBroke->isInBrokenTable(this,pCon)) { if(bNest) { xxx_UT_DEBUGMSG(("Y of Found broken table %x is %d yBreak is %d height %d \n",pBroke,pBroke->getY(),pBroke->getYBreak(),pBroke->getHeight())); } return pBroke; } } pBroke = static_cast(pBroke->getNext()); } return pMaster; } /*! * This Method returns the column or shadow that embeds the container given. */ fp_VerticalContainer * fp_CellContainer::getColumn(fp_Container * _pCon) { fp_TableContainer * pBroke = getBrokenTable(_pCon); if(pBroke == NULL) { pBroke = static_cast(getContainer()); } if(pBroke == NULL) { return NULL; } if(isInNestedTable()) { xxx_UT_DEBUGMSG(("getColumn in nested table \n")); } bool bStop = false; fp_CellContainer * pCell = NULL; fp_Column * pCol = NULL; // // Now FIXED for nested tables off first page // while(pBroke && pBroke->isThisBroken() && !bStop) { fp_Container * pCon = pBroke->getContainer(); if(pCon->isColumnType()) { if(pCon->getContainerType() == FP_CONTAINER_COLUMN) { pCol = static_cast(pCon); } else if(pCon->getContainerType() == FP_CONTAINER_COLUMN_SHADOW) { return static_cast(pCon); } else { pCol = static_cast(pCon->getColumn()); } bStop = true; } else { pCell = static_cast(pBroke->getContainer()); UT_ASSERT(pCell->getContainerType() == FP_CONTAINER_CELL); pBroke = pCell->getBrokenTable(static_cast(pBroke)); } } if(pCell && (pBroke == NULL)) { return static_cast(static_cast(pCell)->getColumn()); } else if(pBroke == NULL) { return NULL; } if(!bStop) { pCol = static_cast(pBroke->getContainer()); } // UT_ASSERT(pCol->getContainerType() != FP_CONTAINER_CELL); if(pCol->getContainerType() == FP_CONTAINER_CELL) { fp_Container * pCon = static_cast(pCol); while(pCon && !pCon->isColumnType()) { pCon = pCon->getContainer(); } if(pCon) { pCol = static_cast(pCon); } else { pCol = NULL; } } if(isInNestedTable()) { xxx_UT_DEBUGMSG(("getColumn in nested table got column %x \n",pCol)); } else { xxx_UT_DEBUGMSG(("getColumn in table got column %x \n",pCol)); } return static_cast(pCol); } bool fp_CellContainer::containsNestedTables(void) { fl_CellLayout * pCL = static_cast(getSectionLayout()); return (pCL->getNumNestedTables() > 0); } /*! * Return the screen rectangle that is the intersection of the cell and the * broken table. * If the height or width is negative, the cell is not in the broken table. */ void fp_CellContainer::_getBrokenRect(fp_TableContainer * pBroke, fp_Page * &pPage, UT_Rect &bRec, GR_Graphics * pG) { UT_ASSERT(static_cast(getSectionLayout()->myContainingLayout()) && static_cast(getSectionLayout()->myContainingLayout())->getContainerType() == FL_CONTAINER_TABLE); fp_Column * pCol = NULL; UT_sint32 col_y =0; UT_sint32 col_x =0; UT_sint32 iLeft = m_iLeft; UT_sint32 iRight = m_iRight; UT_sint32 iTop = m_iTopY; UT_sint32 iBot = m_iBotY; bool bIsNested = false; if(pBroke && (pBroke->getContainer()->getContainerType() == FP_CONTAINER_CELL)) { bIsNested = true; #if DEBUG if(pBroke->getYBreak() > 0) { // fp_TableContainer * pPrev = static_cast(pBroke->getPrev()); xxx_UT_DEBUGMSG(("Broken nested table y %d ybreak %d height %d prev Y %d height %d yBreak %d \n",pBroke->getY(),pBroke->getYBreak(),pBroke->getHeight(),pPrev->getY(),pPrev->getHeight(),pPrev->getYBreak())); } #endif } UT_sint32 offx = 0; UT_sint32 offy = 0; bool bFrame = false; if(pBroke) { pPage = pBroke->getPage(); if(pPage) { if(pBroke->getContainer()->getContainerType() == FP_CONTAINER_FRAME) { fp_FrameContainer * pFC = static_cast(pBroke->getContainer()) ; getView()->getPageScreenOffsets(pPage,col_x,col_y); // // Use col_x, col_y later. // offx = pFC->getX(); offy = pFC->getY(); bFrame = true; } else { pCol = static_cast(pBroke->getBrokenColumn()); pBroke->getPage()->getScreenOffsets(pCol,col_x,col_y); } if(pBroke->getMasterTable()) { if(pBroke->getMasterTable()->getFirstBrokenTable() == pBroke) { if(!bFrame) { offy = pBroke->getMasterTable()->getY(); } else { offy += pBroke->getMasterTable()->getY(); } if(iBot > pBroke->getYBottom()) { iBot = pBroke->getYBottom(); } } else if(bIsNested) { if(iTop < pBroke->getYBreak()) { iTop = 0; } else { iTop = iTop - pBroke->getYBreak(); } if(iBot > pBroke->getYBottom()) { iBot = pBroke->getYBottom() - pBroke->getYBreak(); } else { iBot = iBot - pBroke->getYBreak(); } } else { offy = 0; if(iTop < pBroke->getYBreak()) { iTop = 0; } else { iTop = iTop - pBroke->getYBreak(); } if(iBot > pBroke->getYBottom()) { iBot = pBroke->getYBottom() - pBroke->getYBreak(); } else { iBot = iBot - pBroke->getYBreak(); } xxx_UT_DEBUGMSG(("fp_Tablecontainer:: second broken table col_y %d iTop %d iBot %d m_iTop %d m_iBot %d YBreak %d yBottom %d \n",col_y,iTop,iBot,m_iTopY,m_iBotY,pBroke->getYBreak(),pBroke->getYBottom())); } } else { offy = pBroke->getY(); } if(pBroke->getMasterTable()) { offx += pBroke->getMasterTable()->getX(); } else { offx += pBroke->getX(); } fp_Container * pCon = pBroke; fp_TableContainer * pCurTab = pBroke; UT_sint32 iPrevCellY = 0; UT_sint32 iPrevTabY = pBroke->getY(); UT_sint32 iPrevYBreak = pBroke->getYBreak(); while(pCon->getContainer() && !pCon->getContainer()->isColumnType()) { pCon = pCon->getContainer(); offx += pCon->getX(); UT_sint32 iycon = pCon->getY(); offy += iycon; // this is not quite finished for nested tables! if(pCon->getContainerType() == FP_CONTAINER_CELL) { iPrevCellY = iycon; } if(pCon->getContainerType() == FP_CONTAINER_TABLE) { if(pCol) { pCurTab = pCol->getCorrectBrokenTable(static_cast(pCurTab)); } else { pCurTab = static_cast(pCon); } if(pCurTab->isThisBroken() && (pCurTab != pCurTab->getMasterTable()->getFirstBrokenTable())) { offy = offy -iycon; } if(iPrevCellY > 0 && (iPrevCellY < pCurTab->getYBreak())) { offy -= iPrevCellY; if((iPrevTabY > 0) && (iPrevYBreak == 0)) { offy -= pCurTab->getYBreak() - iPrevCellY; } } else { offy -= pCurTab->getYBreak(); } pCon = static_cast(pCurTab); iPrevYBreak = pCurTab->getYBreak(); iPrevTabY = pCurTab->getY(); } } col_x += offx; col_y += offy; iLeft += col_x; iRight += col_x; iTop += col_y; iBot += col_y; xxx_UT_DEBUGMSG(("fp_Tablecontainer:: Final iTop %d iBot %d \n",iTop,iBot)); } else { UT_ASSERT(UT_SHOULD_NOT_HAPPEN); } } else { pPage = getPage(); if(pPage) { pCol = static_cast(fp_Container::getColumn()); pPage->getScreenOffsets(pCol,col_x,col_y); fp_Container * pCon = static_cast(this); while(!pCon->isColumnType()) { col_x += pCon->getX(); col_y += pCon->getY(); pCon = pCon->getContainer(); } if(pCon->getContainerType() != FP_CONTAINER_FRAME) { iLeft += col_x; iRight += col_x; iTop += col_y; iBot += col_y; } else { UT_sint32 iTmpX,iTmpY; pPage->getScreenOffsets(pCol,iTmpX,iTmpY); iLeft -= iTmpX; iTop -= iTmpY; } } } // // Now correct for printing // if(pG->queryProperties(GR_Graphics::DGP_PAPER)) { UT_sint32 xdiff,ydiff; pPage->getDocLayout()->getView()->getPageScreenOffsets(pPage, xdiff, ydiff); pPage = getPage(); if(pPage) { if(pPage->getDocLayout()->getView()->getViewMode() != VIEW_PRINT) { ydiff -= static_cast(getSectionLayout()->getDocSectionLayout())->getTopMargin(); } } iLeft -= xdiff; iRight -= xdiff; iTop -= ydiff; iBot -= ydiff; } xxx_UT_DEBUGMSG(("_getBrokenRect Returned Top %d height = %d \n",iTop,iBot-iTop)); bRec = UT_Rect(iLeft,iTop,iRight-iLeft,iBot-iTop); } /*! * Returns true if the cell in a broken table overlaps the supplied clip Rect */ bool fp_CellContainer::doesIntersectClip(fp_TableContainer * pBroke, const UT_Rect * rClip) { fp_Page * pPage = NULL; UT_Rect CellRect; _getBrokenRect(pBroke, pPage, CellRect,getGraphics()); return CellRect.intersectsRect(rClip); } void fp_CellContainer::clearScreen(void) { clearScreen(false); } void fp_CellContainer::clearScreen(bool bNoRecursive) { fp_Container * pUpCon = getContainer(); if(pUpCon == NULL) { return; } if(pUpCon->getY() == INITIAL_OFFSET) { return; } if(getPage() == NULL) { return; } markAsDirty(); xxx_UT_DEBUGMSG(("Doing cell clearscreen \n")); // only clear the embeded containers if no background is set: the background clearing will also these containers // FIXME: should work, but doesn't?? // if (m_iBgStyle == FS_OFF) // { fp_Container * pCon = NULL; UT_sint32 i = 0; if(!bNoRecursive) { for(i=0; i< countCons(); i++) { pCon = static_cast(getNthCon(i)); pCon->clearScreen(); } } //} fp_TableContainer * pTab = static_cast(getContainer()); m_bDirty = true; if(pTab) { fp_TableContainer * pBroke = pTab->getFirstBrokenTable(); if(pBroke == NULL) { _clear(pBroke); return; } if(!m_bLinesDrawn) { return; } while(pBroke) { xxx_UT_DEBUGMSG(("cell:clearscreean looking at pBroke %x Ybreak %d spannedHeight %d getY %d \n",pBroke,pBroke->getYBreak(),getSpannedHeight(),getY())); if((getY() >= pBroke->getYBreak() && getY() < pBroke->getYBottom()) || ( (getY()+getSpannedHeight()) >= pBroke->getYBreak() && (getY() < pBroke->getYBreak()))) { _clear(pBroke); m_bLinesDrawn = true; } pBroke = static_cast(pBroke->getNext()); } m_bLinesDrawn = false; } } /*! * This method fills the broken table with containers from this cell contained * by the broken table and returns the offset to current Ybreak of the * supplied broken * table required to wholly contain the first container of this cell in the * broken table. */ UT_sint32 fp_CellContainer::tweakBrokenTable(fp_TableContainer * pBroke) { UT_sint32 iTop = getY(); UT_sint32 iBot2 = iTop + getHeight(); UT_sint32 iBreak2 = pBroke->getYBreak(); UT_sint32 iBottom2 = pBroke->getYBottom(); xxx_UT_DEBUGMSG(("Doing TweakTable on %x iTop %d iBot %d iBreak %d iBottom %d \n",pBroke,iTop,iBot2, iBreak2,iBottom2)); if(iBot2 < iBreak2) { return 0; } if(iTop > iBottom2) { return 0; } fp_Container * pCon = NULL; UT_sint32 i = 0; bool bFound = false; bool bStop = false; UT_sint32 iTweak =0; bool bIsMaster = (static_cast(pBroke->getPrev()) == pBroke->getMasterTable()); fp_TableContainer * pFirst = NULL; if(bIsMaster) { pFirst = pBroke->getMasterTable()->getFirstBrokenTable(); } for(i=0; !bStop && (i(getNthCon(i)); if(pCon->getContainerType() == FP_CONTAINER_TABLE) { continue; } iTop = getY() + pCon->getY(); UT_sint32 iBot = iTop + pCon->getHeight(); UT_sint32 iBreak = pBroke->getYBreak(); UT_sint32 iBottom = pBroke->getYBottom(); bool bInBroke = (iBot >= iBreak) && (iBot < iBottom); if(!bFound) { if(bInBroke) { bFound = true; iTweak = pBroke->getYBreak() - getY() - pCon->getY(); xxx_UT_DEBUGMSG(("Doing TweakTable on %x Tweak %d YBreak %d Cell Y %d Con Y %d \n",pBroke,iTweak,pBroke->getYBreak(),getY(), pCon->getY())); if((i> 0) && (iTweak>0)) { pCon = static_cast(getNthCon(i-1)); if(!bIsMaster && pBroke->getPrev()) { xxx_UT_DEBUGMSG(("SetMyBrokenContainer %x \n",pBroke->getPrev())); pCon->setMyBrokenContainer(static_cast(pBroke->getPrev())); } else if(bIsMaster) { xxx_UT_DEBUGMSG(("SetMyBrokenContainer %x \n",pFirst)); pCon->setMyBrokenContainer(static_cast(pFirst)); } } } } else { if(!bInBroke) { bStop = true; } } } if(iTweak > 0) { return iTweak; } return 0; } UT_sint32 fp_CellContainer::getSpannedHeight(void) { fp_TableContainer * pTab = static_cast(getContainer()); if(pTab == NULL) { return 0; } fp_CellContainer * pCell2 = pTab->getCellAtRowColumn(getBottomAttach(),getLeftAttach()); UT_sint32 height = 0; if(pCell2) { height = pTab->getYOfRow(getBottomAttach()) - getY(); } else { fp_CellContainer * pCell = pTab->getCellAtRowColumn(pTab->getNumRows() -1,0); fp_CellContainer * pMaxH = pCell; if(pMaxH == NULL) { return 0; } while(pCell) { if(pCell->getHeight() > pMaxH->getHeight()) { pMaxH = pCell; } pCell = static_cast(pCell->getNext()); } height = pMaxH->getY() - getY() + pMaxH->getHeight(); } return height; } void fp_CellContainer::_clear(fp_TableContainer * pBroke) { // Lookup table properties to get the line thickness, etc. fl_ContainerLayout * pLayout = getSectionLayout()->myContainingLayout (); UT_return_if_fail(pLayout); if(pBroke == NULL) { return; } if(pBroke->getPage() && !pBroke->getPage()->isOnScreen()) { return; } UT_ASSERT(pLayout->getContainerType () == FL_CONTAINER_TABLE); if (pLayout->getContainerType () != FL_CONTAINER_TABLE) return; fl_TableLayout * pTableLayout = static_cast(pLayout); PP_PropertyMap::Background background = getBackground (); PP_PropertyMap::Line lineBottom = getBottomStyle (pTableLayout); PP_PropertyMap::Line lineLeft = getLeftStyle (pTableLayout); PP_PropertyMap::Line lineRight = getRightStyle (pTableLayout); PP_PropertyMap::Line lineTop = getTopStyle (pTableLayout); fp_Container * pCon = getContainer(); if(pCon->getContainer() && !pCon->getContainer()->isColumnType()) { xxx_UT_DEBUGMSG(("SEVIOR: Clearing nested cell lines \n")); } UT_Rect bRec; fp_Page * pPage = NULL; _getBrokenRect(pBroke, pPage, bRec,getGraphics()); UT_sint32 onePix = getGraphics()->tlu(1)+1; // // This fix makes win32 look bad. FIXME fix this later // onePix = 0.0; if((bRec.top + bRec.height) < 0) { return; } lineTop.m_thickness += 3*onePix; lineLeft.m_thickness += 3*onePix; lineRight.m_thickness += 3*onePix; lineBottom.m_thickness += 3*onePix; UT_RGBColor pageCol(255,255,255); if(pPage) { pageCol = *pPage->getFillType()->getColor(); } markAsDirty(); if (pPage != NULL) { xxx_UT_DEBUGMSG(("_clear: top %d bot %d cell left %d top %d \n",bRec.top,bRec.top+bRec.height,m_iLeftAttach,m_iTopAttach)); lineLeft.m_t_linestyle = PP_PropertyMap::linestyle_solid; lineLeft.m_color = pageCol; _drawLine (lineLeft, bRec.left, bRec.top, bRec.left, bRec.top + bRec.height,getGraphics()); lineTop.m_t_linestyle = PP_PropertyMap::linestyle_solid; lineTop.m_color = pageCol; _drawLine (lineTop, bRec.left, bRec.top, bRec.left + bRec.width, bRec.top,getGraphics()); if(pBroke && pBroke->getPage() && pBroke->getBrokenTop() > 0) { UT_sint32 col_x,col_y; fp_Column * pCol = static_cast(pBroke->getBrokenColumn()); pBroke->getPage()->getScreenOffsets(pCol, col_x,col_y); _drawLine (lineTop, bRec.left, col_y, bRec.left + bRec.width, col_y,getGraphics()); } lineRight.m_t_linestyle = PP_PropertyMap::linestyle_solid; lineRight.m_color = pageCol; _drawLine (lineRight, bRec.left + bRec.width, bRec.top, bRec.left + bRec.width, bRec.top + bRec.height,getGraphics()); lineBottom.m_t_linestyle = PP_PropertyMap::linestyle_solid; lineBottom.m_color = pageCol; _drawLine (lineBottom, bRec.left, bRec.top + bRec.height, bRec.left + bRec.width , bRec.top + bRec.height,getGraphics()); xxx_UT_DEBUGMSG(("_Clear: pBroke %x \n",pBroke)); if(pBroke && pBroke->getPage() && pBroke->getBrokenBot() >= 0) { UT_sint32 col_x,col_y; fp_Column * pCol = static_cast(pBroke->getBrokenColumn()); pBroke->getPage()->getScreenOffsets(pCol, col_x,col_y); UT_sint32 bot = col_y + pCol->getHeight(); xxx_UT_DEBUGMSG(("_clear: Clear broken bottom %d \n",bot)); _drawLine (lineBottom, bRec.left, bot, bRec.left + bRec.width, bot,getGraphics()); } getGraphics()->setLineWidth(1 ); xxx_UT_DEBUGMSG(("_clear: BRec.top %d Brec.height %d \n",bRec.top,bRec.height)); // UT_ASSERT((bRec.left + bRec.width) < getPage()->getWidth()); UT_sint32 srcX = 0; UT_sint32 srcY = 0; getFillType()->setWidthHeight(getGraphics(),bRec.width,bRec.height); getLeftTopOffsets(srcX,srcY); if(getFillType()->getParent()) { srcX += getX(); srcY += getY(); getFillType()->getParent()->Fill(getGraphics(),srcX,srcY,bRec.left,bRec.top,bRec.width,bRec.height); } else { getFillType()->Fill(getGraphics(),srcX,srcY,bRec.left,bRec.top,bRec.width,bRec.height); } if(getPage()) { getPage()->expandDamageRect(bRec.left,bRec.top,bRec.width,bRec.height); } } m_bDirty = true; m_bBgDirty = true; m_bLinesDrawn = false; } /*! Set width \param iWidth Width of container \todo Should force re-line-break operations on all blocks in the container */ void fp_CellContainer::setWidth(UT_sint32 iWidth) { UT_sint32 myWidth = getWidth(); if (iWidth == myWidth) { return; } if(iWidth < 2) { iWidth = 2; } clearScreen(); fp_VerticalContainer::setWidth(iWidth); fl_SectionLayout * pSL = getSectionLayout(); pSL = static_cast(pSL->myContainingLayout()); UT_ASSERT(pSL->getContainerType() == FL_CONTAINER_TABLE); static_cast(pSL)->setDirty(); fl_CellLayout * pCellL = static_cast(getSectionLayout()); xxx_UT_DEBUGMSG(("Set Reformat 2 now from table %x in TableLayout %x \n",this,getSectionLayout())); pCellL->setNeedsReformat(pCellL); pCellL->_localCollapse(); pCellL->format(); UT_sint32 i = 0; for(i =0; i< countCons(); i++) { fp_Container * pCon = static_cast(getNthCon(i)); if(pCon->getContainerType() == FP_CONTAINER_LINE) { static_cast(pCon)->layout(); } else if(pCon->getContainerType() == FP_CONTAINER_TABLE) { static_cast(pCon)->layout(); } else { UT_ASSERT(UT_SHOULD_NOT_HAPPEN); } } } void fp_CellContainer::setContainer(fp_Container * pContainer) { if (pContainer == getContainer()) { return; } if (getContainer()) { clearScreen(); } fp_Container::setContainer(pContainer); if(pContainer == NULL) { return; } UT_ASSERT(pContainer->getContainerType() == FP_CONTAINER_TABLE); fp_TableContainer * pTable = static_cast(pContainer); UT_sint32 iWidth = pTable->getWidth(); fp_CellContainer::setWidth(iWidth); } /* just a little helper function */ void fp_CellContainer::_drawLine (const PP_PropertyMap::Line & style, UT_sint32 left, UT_sint32 top, UT_sint32 right, UT_sint32 bot,GR_Graphics * pGr) { if (style.m_t_linestyle == PP_PropertyMap::linestyle_none && !pGr->queryProperties(GR_Graphics::DGP_SCREEN)) return; // do not draw the dotted line when printing GR_Graphics::JoinStyle js = GR_Graphics::JOIN_MITER; GR_Graphics::CapStyle cs = GR_Graphics::CAP_PROJECTING; switch (style.m_t_linestyle) { case PP_PropertyMap::linestyle_none: pGr->setLineProperties (pGr->tlu(1), js, cs, GR_Graphics::LINE_DOTTED); break; case PP_PropertyMap::linestyle_dotted: pGr->setLineProperties (pGr->tlu(1), js, cs, GR_Graphics::LINE_DOTTED); break; case PP_PropertyMap::linestyle_dashed: pGr->setLineProperties (pGr->tlu(1), js, cs, GR_Graphics::LINE_ON_OFF_DASH); break; case PP_PropertyMap::linestyle_solid: pGr->setLineProperties (pGr->tlu(1), js, cs, GR_Graphics::LINE_SOLID); break; default: // do nothing; shouldn't happen break; } pGr->setLineWidth (static_cast(style.m_thickness)); if (style.m_t_linestyle == PP_PropertyMap::linestyle_none) { pGr->setColor (m_borderColorNone); } else { pGr->setColor (style.m_color); } xxx_UT_DEBUGMSG(("_drawLine: top %d bot %d \n",top,bot)); GR_Painter painter(pGr); painter.drawLine (left, top, right, bot); pGr->setLineProperties (pGr->tlu(1), js, cs, GR_Graphics::LINE_SOLID); } PP_PropertyMap::Background fp_CellContainer::getBackground () const { PP_PropertyMap::Background background(m_background); fl_ContainerLayout * pLayout = getSectionLayout()->myContainingLayout (); UT_return_val_if_fail(pLayout, background); UT_return_val_if_fail(pLayout->getContainerType () == FL_CONTAINER_TABLE, background); fl_TableLayout * table = static_cast(pLayout); const PP_PropertyMap::Background & table_background = table->getBackground (); /* (unclear how "inherit" differs from "transparent") */ if (background.m_t_background != PP_PropertyMap::background_solid) { background.m_t_background = table_background.m_t_background; if (background.m_t_background == PP_PropertyMap::background_solid) background.m_color = table_background.m_color; } if ((background.m_t_background == PP_PropertyMap::background_inherit) || (background.m_t_background == PP_PropertyMap::background__unset)) { background.m_t_background = PP_PropertyMap::background_none; } return background; } /* sort out inheritance and defaults of cell-border properties */ void s_cell_border_style (PP_PropertyMap::Line & line, const PP_PropertyMap::Line & table_line, const fl_TableLayout * table) { if (line.m_t_color == PP_PropertyMap::color_inherit) { line.m_t_color = table_line.m_t_color; if (line.m_t_color == PP_PropertyMap::color_color) line.m_color = table_line.m_color; } if ((line.m_t_color == PP_PropertyMap::color_inherit) || (line.m_t_color == PP_PropertyMap::color__unset)) { line.m_t_color = PP_PropertyMap::color_color; line.m_color = table->getDefaultColor (); } if (line.m_t_linestyle == PP_PropertyMap::linestyle_inherit) line.m_t_linestyle = table_line.m_t_linestyle; if ((line.m_t_linestyle == PP_PropertyMap::linestyle_inherit) || (line.m_t_linestyle == PP_PropertyMap::linestyle__unset)) line.m_t_linestyle = PP_PropertyMap::linestyle_solid; if (line.m_t_thickness == PP_PropertyMap::thickness_inherit) { line.m_t_thickness = table_line.m_t_thickness; if (line.m_t_thickness == PP_PropertyMap::thickness_length) line.m_thickness = table_line.m_thickness; } if ((line.m_t_thickness == PP_PropertyMap::thickness_inherit) || (line.m_t_thickness == PP_PropertyMap::thickness__unset)) { line.m_t_thickness = table_line.m_t_thickness; UT_sint32 defaultThickness = table->getLineThickness (); line.m_thickness = (defaultThickness > 0) ? static_cast(defaultThickness) : 0; } /* if the color is transparent or the thickness is 0, then set the line-style to none */ if ((line.m_thickness == 0) || (line.m_t_color == PP_PropertyMap::color_transparent)) { line.m_t_linestyle = PP_PropertyMap::linestyle_none; } } PP_PropertyMap::Line fp_CellContainer::getBottomStyle (const fl_TableLayout * table) const { PP_PropertyMap::Line line(m_lineBottom); if (table == 0) return line; const PP_PropertyMap::Line & table_line = table->getBottomStyle (); s_cell_border_style (line, table_line, table); return line; } PP_PropertyMap::Line fp_CellContainer::getLeftStyle (const fl_TableLayout * table) const { PP_PropertyMap::Line line(m_lineLeft); if (table == 0) return line; const PP_PropertyMap::Line & table_line = table->getLeftStyle (); s_cell_border_style (line, table_line, table); return line; } PP_PropertyMap::Line fp_CellContainer::getRightStyle (const fl_TableLayout * table) const { PP_PropertyMap::Line line(m_lineRight); if (table == 0) return line; const PP_PropertyMap::Line & table_line = table->getRightStyle (); s_cell_border_style (line, table_line, table); return line; } PP_PropertyMap::Line fp_CellContainer::getTopStyle (const fl_TableLayout * table) const { PP_PropertyMap::Line line(m_lineTop); if (table == 0) return line; const PP_PropertyMap::Line & table_line = table->getTopStyle (); s_cell_border_style (line, table_line, table); return line; } bool fp_CellContainer::isInNestedTable(void) { fp_TableContainer * pMaster = static_cast(getContainer()); fp_CellContainer * pTopCell = static_cast(this); UT_sint32 icount = 0; while(pMaster && pMaster->getContainer() && !pMaster->getContainer()->isColumnType()) { pTopCell = static_cast(pMaster->getContainer()); pMaster = static_cast(pTopCell->getContainer()); icount++; } if(icount < 1) { return false; } return true; } void fp_CellContainer::setBackground (const PP_PropertyMap::Background & style) { m_background = style; PP_PropertyMap::Background background = getBackground (); if(background.m_t_background == PP_PropertyMap::background_solid) { getFillType()->setColor(background.m_color); } } /*! * Given the broken table that contains this cell, calculate the positions * of the left,right,top and bottom edges of the cell. */ void fp_CellContainer::getScreenPositions(fp_TableContainer * pBroke,GR_Graphics * pG, UT_sint32 & iLeft, UT_sint32 & iRight,UT_sint32 & iTop,UT_sint32 & iBot, UT_sint32 & col_y, fp_Column *& pCol, fp_ShadowContainer *& pShadow, bool & bDoClear ) { UT_return_if_fail(getPage()); bool bNested = false; if(pBroke == NULL) { pBroke = static_cast(getContainer()); } if(isInNestedTable()) { bNested = true; } if(pBroke && pBroke->getPage()) { if(pG->queryProperties(GR_Graphics::DGP_SCREEN) && !pBroke->getPage()->isOnScreen()) { return; } } // // Now correct if iTop or iBot is off the page. // UT_sint32 col_x; UT_sint32 offy =0; UT_sint32 offx =0; fp_Page * pPage = pBroke->getPage(); if(pPage == NULL) { // // Can happen while loading. // return; } pPage = pBroke->getPage(); if(getContainer()->getContainerType() == FP_CONTAINER_FRAME) { fp_FrameContainer * pFC = static_cast(getContainer()); getView()->getPageScreenOffsets(pPage,col_x,col_y); col_x += pFC->getX(); col_y += pFC->getY(); pCol = static_cast(pFC->getColumn()); } else if(getContainer()->getContainerType() == FP_CONTAINER_COLUMN_SHADOW) { pShadow = static_cast(pBroke->getContainer()); if(pShadow) { pShadow->getPage()->getScreenOffsets(pShadow, col_x,col_y); } else { pPage->getScreenOffsets(pShadow, col_x,col_y); } } else if(pBroke && (pBroke->getBrokenColumn()->getContainerType() == FP_CONTAINER_COLUMN_SHADOW)) { pShadow = static_cast(pBroke->getContainer()); if(pShadow) { pShadow->getPage()->getScreenOffsets(pShadow, col_x,col_y); } else { pPage->getScreenOffsets(pShadow, col_x,col_y); } } else { pCol = static_cast(pBroke->getBrokenColumn()); if(pCol) { pCol->getPage()->getScreenOffsets(pCol, col_x,col_y); } else { pPage->getScreenOffsets(pCol, col_x,col_y); } } bDoClear = true; if(pPage->getDocLayout()->getView() && pG->queryProperties(GR_Graphics::DGP_PAPER)) { // // Now correct for printing // bDoClear = false; UT_sint32 xdiff,ydiff; pPage->getDocLayout()->getView()->getPageScreenOffsets(pPage, xdiff, ydiff); col_y = col_y - ydiff; col_x = col_x - xdiff; if(pPage->getDocLayout()->getView()->getViewMode() != VIEW_PRINT) { col_y += static_cast(getSectionLayout()->getDocSectionLayout())->getTopMargin(); } } if(pBroke->getMasterTable()) { offx = pBroke->getMasterTable()->getX(); if(pBroke->getMasterTable()->getFirstBrokenTable() == pBroke) { offy = pBroke->getMasterTable()->getY(); } else { offy = 0; } } if(bNested && pBroke) { fp_Container * pCon = static_cast(pBroke->getContainer()); fp_TableContainer * pCurTab = pBroke; while(!pCon->isColumnType()) { UT_sint32 iycon = pCon->getY(); offy += iycon; offx += pCon->getX(); if(pCon->getContainerType() == FP_CONTAINER_TABLE) { if(pCol) { pCurTab = pCol->getCorrectBrokenTable(static_cast(pCurTab)); } else { pCurTab = static_cast(pCon); } if(pCurTab->isThisBroken() && (pCurTab != pCurTab->getMasterTable()->getFirstBrokenTable())) { offy = offy + pCurTab->getY() - iycon; } if(offy < pCurTab->getYBreak()) { offy = 0; } else { offy -= pCurTab->getYBreak(); } } pCon = pCon->getContainer(); } } iLeft = col_x + m_iLeft + offx; iRight = col_x + m_iRight + offx; iTop = col_y + m_iTopY + offy; iBot = col_y + m_iBotY + offy; } /*! * Draw background and lines around a cell in a broken table. */ void fp_CellContainer::drawLines(fp_TableContainer * pBroke,GR_Graphics * pG, bool bDoClear) { xxx_UT_DEBUGMSG(("Doing drawlines for cell %x \n",this)); UT_return_if_fail(getPage()); bool bNested = false; if(pBroke == NULL) { pBroke = static_cast(getContainer()); } if(isInNestedTable()) { bNested = true; } if(pBroke && pBroke->getPage()) { if(pG->queryProperties(GR_Graphics::DGP_SCREEN) && !pBroke->getPage()->isOnScreen()) { return; } } // Lookup table properties to get the line thickness, etc. fl_ContainerLayout * pLayout = getSectionLayout()->myContainingLayout (); UT_return_if_fail(pLayout->getContainerType () == FL_CONTAINER_TABLE); fl_TableLayout * pTableLayout = static_cast(pLayout); PP_PropertyMap::Line lineBottom = getBottomStyle (pTableLayout); PP_PropertyMap::Line lineLeft = getLeftStyle (pTableLayout); PP_PropertyMap::Line lineRight = getRightStyle (pTableLayout); PP_PropertyMap::Line lineTop = getTopStyle (pTableLayout); fp_Page * pPage = pBroke->getPage(); if(pPage == NULL) { // // Can happen while loading. // return; } bool bDrawTop = true; bool bDrawBot = true; xxx_UT_DEBUGMSG(("m_iBotY %d \n",m_iBotY)); m_bLinesDrawn = true; UT_sint32 iLeft,iRight,iTop,iBot = 0; UT_sint32 col_y = 0; fp_Column * pCol = NULL; fp_ShadowContainer * pShadow = NULL; bool doClear2 =false; bool bTopScreen = false; bool bBotScreen = false; getScreenPositions(pBroke,pG,iLeft,iRight,iTop,iBot,col_y,pCol,pShadow,doClear2 ); if(pBroke != NULL) { if(m_iBotY < pBroke->getYBreak()) { // // Cell is above this page // xxx_UT_DEBUGMSG(("Don't drawlines because M-IBotY < pBroke->getYbreak \n",m_iBotY,pBroke->getYBreak())); return; } if(m_iTopY > pBroke->getYBottom()) { // // Cell is below this page // xxx_UT_DEBUGMSG(("Don't drawlines because m_iTopY > pBroke->getYBottom \n",m_iTopY, pBroke->getYBottom())); return; } iTop -= pBroke->getYBreak(); iBot -= pBroke->getYBreak(); xxx_UT_DEBUGMSG(("drawLines: ibot = %d col_y %d m_iBotY %d pCol->getHeight() %d left %d top %d \n",iBot,col_y,m_iBotY,pCol->getHeight(),m_iLeftAttach,m_iTopAttach)); if(iTop < col_y) { xxx_UT_DEBUGMSG(("iTop < col_y !! iTop %d col_y %d row is %d \n",iTop,col_y,getTopAttach())); iTop = col_y; bDrawTop = true; bTopScreen = true; if(pBroke != NULL) { pBroke->setBrokenTop(1); } } xxx_UT_DEBUGMSG(("drawlines: After iTop %d iBot = %d sum %d left %d top %d \n",iTop,iBot,col_y + pCol->getHeight(),m_iLeftAttach,m_iTopAttach)); UT_sint32 iColHeight = 0; if(pCol) { iColHeight = pCol->getHeight(); } else if(pShadow) { iColHeight = pShadow->getHeight(); } if(iBot > col_y + iColHeight) { iBot = col_y + iColHeight; bDrawBot = true; bBotScreen = true; if(pBroke != NULL) { pBroke->setBrokenBot(1); } } // // Now get a rectangle to calculate draw arguments // // This code might eventually replace a lot of the code above but // it needs more testing and tweaking - particularly for nested tables. // // UT_Rect bRec; // fp_Page * pLinePage; // _getBrokenRect(pBroke, pLinePage, bRec); // if(pLinePage != pPage) // { // UT_DEBUGMSG(("Pages don't match! \n")); // return; // } // iLeft = bRec.left; // iTop = bRec.top; // iBot = iTop + bRec.height; // iRight = iLeft + bRec.width; m_bDrawRight = true; UT_sint32 onePix = pG->tlu(1)+1; // // the was put in to fix cairo draws but it makes windows look bad. // Fixme for cairo a different way. // onePix = 0; // // Have to draw white first because drawing is additive // PP_PropertyMap::Line clineBottom = getBottomStyle (pTableLayout); PP_PropertyMap::Line clineLeft = getLeftStyle (pTableLayout); PP_PropertyMap::Line clineRight = getRightStyle (pTableLayout); PP_PropertyMap::Line clineTop = getTopStyle (pTableLayout); UT_RGBColor white(255,255,255); white = *pPage->getFillType()->getColor(); // // Might needs these later // UT_sint32 iextLeft=0; UT_sint32 iextRight=0; UT_sint32 iextTop=0; UT_sint32 iextBot= 0; if (m_bDrawLeft) { if(bDoClear) { clineLeft.m_color = white; clineLeft.m_thickness += 3*onePix; _drawLine (clineLeft, iLeft, iTop, iLeft, iBot,pG); } else { if(bTopScreen) iextTop = 0; if(bBotScreen) iextBot = 0; _drawLine(lineLeft, iLeft, iTop-iextTop, iLeft, iBot+iextBot,pG); } } if(m_bDrawTop || bDrawTop) { if(bDoClear) { clineTop.m_color = white; clineTop.m_thickness += 3*onePix; _drawLine(clineTop, iLeft, iTop, iRight, iTop,pG); } else { _drawLine(lineTop, iLeft-iextLeft, iTop, iRight+iextRight, iTop,pG); } } if(m_bDrawRight) { if(bDoClear) { clineRight.m_color = white; clineRight.m_thickness += 3*onePix; _drawLine(clineRight, iRight, iTop, iRight, iBot,pG); } else { if(bTopScreen) iextTop = 0; if(bBotScreen) iextBot = 0; _drawLine(lineRight, iRight, iTop-iextTop, iRight, iBot+iextBot,pG); } } if(m_bDrawBot || bDrawBot) { if(bDoClear) { clineBottom.m_color = white; clineBottom.m_thickness += 3*onePix; _drawLine(clineBottom, iLeft, iBot, iRight, iBot,pG); } else { _drawLine(lineBottom, iLeft-iextLeft, iBot, iRight+iextRight, iBot,pG); } } } } /*! * | * |_ * * Extend the cell line at the left top corner if needed */ #if 0 // // These methods not needed for 2.8 but might be for 2.10 // void fp_CellContainer::extendLeftTop(PP_PropertyMap::Line & line,GR_Graphics * pG,UT_sint32 & iextTop) { iextTop = 0; if(getTopAttach() == 0) { return; } fp_TableContainer * pTab = static_cast(getContainer()); if(pTab == NULL) { return; } fp_CellContainer * pCell = pTab->getCellAtRowColumn(getTopAttach()-1,getLeftAttach()); if(pCell->getLeftAttach() != getLeftAttach()) { return; } iextTop = line.m_thickness; UT_sint32 onePix = pG->tlu(1)+1; iextTop += 3*onePix; } /*! * _ * | * | * * Extend the cell line at the left bot corner if needed */ void fp_CellContainer::extendLeftBot(PP_PropertyMap::Line & line,GR_Graphics * pG,UT_sint32 & iextBot) { iextBot = 0; fp_TableContainer * pTab = static_cast(getContainer()); if(pTab == NULL) { return; } if(getBottomAttach() == pTab->getNumRows()) { return; } fp_CellContainer * pCell = pTab->getCellAtRowColumn(getTopAttach()+1,getLeftAttach()); if(!pCell) return; if(pCell->getLeftAttach() != getLeftAttach()) { return; } iextBot = line.m_thickness; UT_sint32 onePix = pG->tlu(1)+1; iextBot += 3*onePix; } /*! * | * _| * * Extend the cell line at the right top corner if needed */ void fp_CellContainer::extendRightTop(PP_PropertyMap::Line & line,GR_Graphics * pG,UT_sint32 & iextTop) { iextTop = 0; if(getTopAttach() == 0) { return; } fp_TableContainer * pTab = static_cast(getContainer()); if(pTab == NULL) { return; } fp_CellContainer * pCell = pTab->getCellAtRowColumn(getTopAttach()-1,getLeftAttach()); if(!pCell) return; if(pCell->getRightAttach() != getRightAttach()) { return; } iextTop = line.m_thickness; UT_sint32 onePix = pG->tlu(1)+1; iextTop += 3*onePix; } /*! * _ * | * | * * Extend the cell line at the right bot corner if needed */ void fp_CellContainer::extendRightBot(PP_PropertyMap::Line & line,GR_Graphics * pG,UT_sint32 & iextBot) { iextBot = 0; fp_TableContainer * pTab = static_cast(getContainer()); if(pTab == NULL) { return; } if(getBottomAttach() == pTab->getNumRows()) { return; } fp_CellContainer * pCell = pTab->getCellAtRowColumn(getTopAttach()+1,getLeftAttach()); if(!pCell) return; if(pCell->getRightAttach() != getRightAttach()) { return; } iextBot = line.m_thickness; UT_sint32 onePix = pG->tlu(1)+1; iextBot += 3*onePix; } /*! * _ _ * | * * * Extend the cell line at the left top corner if needed */ void fp_CellContainer::extendTopLeft(PP_PropertyMap::Line & line,GR_Graphics * pG,UT_sint32 & iextLeft) { iextLeft = 0; fp_TableContainer * pTab = static_cast(getContainer()); if(pTab == NULL) { return; } if(getLeftAttach() == 0) { return; } fp_CellContainer * pCell = pTab->getCellAtRowColumn(getTopAttach(),getLeftAttach()-1); if(!pCell) return; if(pCell->getTopAttach() != getTopAttach()) { return; } iextLeft = line.m_thickness; UT_sint32 onePix = pG->tlu(1)+1; iextLeft += 3*onePix; } /*! * * _ _ * | * * Extend the cell line at the right top corner if needed */ void fp_CellContainer::extendTopRight(PP_PropertyMap::Line & line,GR_Graphics * pG,UT_sint32 & iextRight) { iextRight = 0; fp_TableContainer * pTab = static_cast(getContainer()); if(pTab == NULL) { return; } if(getRightAttach() >= pTab->getNumCols()) { return; } fp_CellContainer * pCell = pTab->getCellAtRowColumn(getTopAttach(),getRightAttach()); if(!pCell) return; if(pCell->getTopAttach() != getTopAttach()) { return; } iextRight = line.m_thickness; UT_sint32 onePix = pG->tlu(1)+1; iextRight += 3*onePix; } /*! * _ _| * * * Extend the cell line at the left Bot corner if needed */ void fp_CellContainer::extendBotLeft(PP_PropertyMap::Line & line,GR_Graphics * pG,UT_sint32 & iextLeft) { iextLeft = 0; fp_TableContainer * pTab = static_cast(getContainer()); if(pTab == NULL) { return; } if(getLeftAttach() == 0) { return; } fp_CellContainer * pCell = pTab->getCellAtRowColumn(getTopAttach(),getLeftAttach()-1); if(!pCell) return; if(pCell->getBottomAttach() != getBottomAttach()) { return; } iextLeft = line.m_thickness; UT_sint32 onePix = pG->tlu(1)+1; iextLeft += 3*onePix; } /*! * * |_ _ * * Extend the cell line at the right bot corner if needed */ void fp_CellContainer::extendBotRight(PP_PropertyMap::Line & line,GR_Graphics * pG,UT_sint32 & iextRight) { iextRight = 0; fp_TableContainer * pTab = static_cast(getContainer()); if(pTab == NULL) { return; } if(getRightAttach() >= pTab->getNumCols()) { return; } fp_CellContainer * pCell = pTab->getCellAtRowColumn(getTopAttach(),getRightAttach()); if(!pCell) return; if(pCell->getBottomAttach() != getBottomAttach()) { return; } iextRight = line.m_thickness; UT_sint32 onePix = pG->tlu(1)+1; iextRight += 3*onePix; } #endif /*! * Draw lines around neighbouring cells. Use to fix artifacts of editting. */ void fp_CellContainer::drawLinesAdjacent(void) { UT_sint32 row = getTopAttach(); UT_sint32 col_right = getRightAttach(); UT_sint32 col_left = getLeftAttach(); fp_TableContainer * pTab = static_cast(getContainer()); if(pTab == NULL) { return; } bool bDoRight = false; if(col_right < pTab->getNumCols()) { bDoRight = true; } bool bDoLeft = false; if(col_left >= 0) { bDoLeft = true; } fp_TableContainer * pBroke = pTab->getFirstBrokenTable(); while(pBroke) { drawLines(pBroke,getGraphics(),true); if(bDoRight) { fp_CellContainer * pCell = pTab->getCellAtRowColumn(row,col_right); if(pCell) { pCell->drawLines(pBroke,getGraphics(),true); } } if(bDoLeft) { fp_CellContainer * pCell = pTab->getCellAtRowColumn(row,col_left); if(pCell) { pCell->drawLines(pBroke,getGraphics(),true); } } drawLines(pBroke,getGraphics(),false); if(bDoRight) { fp_CellContainer * pCell = pTab->getCellAtRowColumn(row,col_right); if(pCell) { pCell->drawLines(pBroke,getGraphics(),false); } } if(bDoLeft) { fp_CellContainer * pCell = pTab->getCellAtRowColumn(row,col_left); if(pCell) { pCell->drawLines(pBroke,getGraphics(),false); } } pBroke = static_cast(pBroke->getNext()); } } /*! Draw container outline \param pDA Draw arguments \param pBroke fp_TableContainer pointer to broken table */ void fp_CellContainer::_drawBoundaries(dg_DrawArgs* pDA, fp_TableContainer * pBroke) { UT_return_if_fail(getPage()); if(getPage()->getDocLayout()->getView() == NULL) { return; } if(pBroke && pBroke->getPage()) { if(pDA->pG->queryProperties(GR_Graphics::DGP_SCREEN) && !pBroke->getPage()->isOnScreen()) { return; } if(pBroke->getYBreak() > (getY() + getHeight())) { return; } } if(getPage()->getDocLayout()->getView()->getShowPara() && getGraphics()->queryProperties(GR_Graphics::DGP_SCREEN)){ UT_sint32 xoffBegin = pDA->xoff + getX(); UT_sint32 yoffBegin = pDA->yoff + getY(); UT_sint32 xoffEnd = pDA->xoff + getX() + getWidth() - getGraphics()->tlu(1); UT_sint32 yoffEnd = pDA->yoff + getY() + getHeight() - getGraphics()->tlu(1); UT_RGBColor clrShowPara(127,127,127); GR_Painter painter(getGraphics()); getGraphics()->setColor(clrShowPara); xxx_UT_DEBUGMSG(("SEVIOR: cell boundaries xleft %d xright %d ytop %d ybot %d \n",xoffBegin,xoffEnd,yoffBegin,yoffEnd)); painter.drawLine(xoffBegin, yoffBegin, xoffEnd, yoffBegin); painter.drawLine(xoffBegin, yoffEnd, xoffEnd, yoffEnd); painter.drawLine(xoffBegin, yoffBegin, xoffBegin, yoffEnd); painter.drawLine(xoffEnd, yoffBegin, xoffEnd, yoffEnd); } } /*! * Return the topmost table in this structure. The one embedded in the * column. */ fp_TableContainer * fp_CellContainer::getTopmostTable() const { fp_Container * pUp = getContainer(); fp_Container * pPrev = pUp; while(pUp->getContainerType() != FP_CONTAINER_COLUMN) { pPrev = pUp; pUp = pUp->getContainer(); } if(pPrev->getContainerType() == FP_CONTAINER_TABLE) { return static_cast(pPrev); } UT_ASSERT(UT_SHOULD_NOT_HAPPEN); return NULL; } /*! * Return true if the cell contains footnote references */ bool fp_CellContainer::containsFootnoteReference(void) { fp_Container * pCon = getFirstContainer(); bool bFound = false; while(pCon && !bFound) { if(pCon->getContainerType() == FP_CONTAINER_LINE) { fp_Line * pLine = static_cast(pCon); if(pLine->containsFootnoteReference()) { bFound = true; } } else if(pCon->getContainerType() == FP_CONTAINER_TABLE) { fp_TableContainer *pTab = static_cast(pCon); if(pTab->containsFootnoteReference()) { bFound = true; } } pCon = static_cast(pCon->getNext()); } return bFound; } /*! * This method returns a vector of all the footnote layouts in this cell */ bool fp_CellContainer::getFootnoteContainers(UT_GenericVector* pVecFoots) { fp_Container * pCon = getFirstContainer(); bool bFound = false; while(pCon) { if(pCon->getContainerType() == FP_CONTAINER_LINE) { fp_Line * pLine = static_cast(pCon); if(pLine->containsFootnoteReference()) { bFound = true; UT_GenericVector vecFC; pLine->getFootnoteContainers(&vecFC); UT_sint32 i =0; for(i=0; i< vecFC.getItemCount();i++) { pVecFoots->addItem(vecFC.getNthItem(i)); } } } else if(pCon->getContainerType() == FP_CONTAINER_TABLE) { fp_TableContainer *pTab = static_cast(pCon); if(pTab->containsFootnoteReference()) { bFound = true; UT_GenericVector vecFC; pTab->getFootnoteContainers(&vecFC); UT_sint32 i =0; for(i=0; i< vecFC.getItemCount();i++) { pVecFoots->addItem(vecFC.getNthItem(i)); } } } pCon = static_cast(pCon->getNext()); } return bFound; } /*! * Return true if the cell contains an annotation */ bool fp_CellContainer::containsAnnotations(void) { fp_Container * pCon = getFirstContainer(); bool bFound = false; while(pCon && !bFound) { if(pCon->getContainerType() == FP_CONTAINER_LINE) { fp_Line * pLine = static_cast(pCon); if(pLine->containsAnnotations()) { bFound = true; } } else if(pCon->getContainerType() == FP_CONTAINER_TABLE) { fp_TableContainer *pTab = static_cast(pCon); if(pTab->containsAnnotations()) { bFound = true; } } pCon = static_cast(pCon->getNext()); } return bFound; } /*! * This method returns a vector of all the footnote layouts in this cell */ bool fp_CellContainer::getAnnotationContainers(UT_GenericVector* pVecAnns) { fp_Container * pCon = getFirstContainer(); bool bFound = false; while(pCon) { if(pCon->getContainerType() == FP_CONTAINER_LINE) { fp_Line * pLine = static_cast(pCon); if(pLine->containsAnnotations()) { bFound = true; UT_GenericVector vecAC; pLine->getAnnotationContainers(&vecAC); UT_sint32 i =0; for(i=0; i< vecAC.getItemCount();i++) { pVecAnns->addItem(vecAC.getNthItem(i)); } } } else if(pCon->getContainerType() == FP_CONTAINER_TABLE) { fp_TableContainer *pTab = static_cast(pCon); if(pTab->containsAnnotations()) { bFound = true; UT_GenericVector vecAC; pTab->getAnnotationContainers(&vecAC); UT_sint32 i =0; for(i=0; i< vecAC.getItemCount();i++) { pVecAnns->addItem(vecAC.getNthItem(i)); } } } pCon = static_cast(pCon->getNext()); } return bFound; } /*! * Return the x coordinate offset of this cell. * We need to know the line for situations where the cell is broken over * different pages. */ UT_sint32 fp_CellContainer::getCellX(fp_Line * /*pLine*/) const { return 0; } /*! * Return the y coordinate offset of this cell. * We need to know the line for situations where the cell is broken over * different pages. */ UT_sint32 fp_CellContainer::getCellY(fp_Line * /*pLine*/) const { fp_TableContainer * pTab = getTopmostTable(); return pTab->getY(); } /*! Draw container content \param pDA Draw arguments */ void fp_CellContainer::draw(dg_DrawArgs* pDA) { m_bDrawTop = false; GR_Graphics * pG = pDA->pG; fp_TableContainer * pTab = static_cast(getContainer()); // draw bottom if this cell is the last of the table and fully contained on the page m_bDrawBot = (pTab->getNumRows() == getBottomAttach()); m_bDrawLeft = true; UT_sint32 count = countCons(); const UT_Rect * pClipRect = pDA->pG->getClipRect(); UT_sint32 ytop,ybot; UT_sint32 i; UT_sint32 imax = static_cast((static_cast(1<<31)) - 1); if(pClipRect) { ybot = UT_MAX(pClipRect->height,_getMaxContainerHeight()); ytop = pClipRect->top; ybot += ytop + 1; xxx_UT_DEBUGMSG(("SEVIOR: clip top %d clip bot %d \n",ytop,ybot)); } else { ytop = 0; ybot = imax; } bool bStop = false; bool bStart = false; xxx_UT_DEBUGMSG(("SEVIOR: Drawing unbroken cell %x x %d, y %d width %d height %d \n",this,getX(),getY(),getWidth(),getHeight())); // // Only draw the lines in the clipping region. // for ( i = 0; (i(getNthCon(i)); dg_DrawArgs da = *pDA; // // pDA has xoff set at the columns left edge, we need to offset this // by the cell x position. // pDA has yoffset at the last ypos in the column relative to the screen // The position Ypos is the absolute position on the screen we need // to offset this with the position of the container holding this // cell. da.xoff += pContainer->getX() + getX(); da.yoff += pContainer->getY() + getY(); UT_sint32 ydiff = da.yoff + pContainer->getHeight(); if((da.yoff >= ytop && da.yoff <= ybot) || (ydiff >= ytop && ydiff <= ybot)) { // // Always draw the top of the cell. // m_bDrawTop = true; bStart = true; pContainer->draw(&da); } else if(bStart) { bStop = true; } } if(i == count) { m_bDirty = false; } if(pG->queryProperties(GR_Graphics::DGP_SCREEN)) drawLines(NULL,pG,true); drawLines(NULL,pG,false); pTab->setRedrawLines(); _drawBoundaries(pDA,NULL); } /*! * Draw the whole cell with the selection colour background. \Param pLine pointer to the line contained within the cell the cell. */ void fp_CellContainer::draw(fp_Line * pLine) { UT_return_if_fail(getPage()); m_bDirty = false; FV_View * pView = getView(); fp_TableContainer * pTab = static_cast(getContainer()); if(pTab == NULL) { return; } UT_ASSERT(pTab->getContainerType() == FP_CONTAINER_TABLE); fp_TableContainer * pBroke = pTab->getFirstBrokenTable(); if(pBroke == NULL) { return; } bool bFound = false; while(pBroke && !bFound) { if(pBroke->isInBrokenTable(this,pLine)) { bFound = true; break; } pBroke = static_cast(pBroke->getNext()); } if(!bFound) { return; } fp_Container * pLast = static_cast(pLine); while(pLast->getNext() && pBroke->isInBrokenTable(this,pLast)) { pLast = static_cast(pLast->getNext()); } // // Now get a rectangle to calculate draw arguments // UT_Rect bRec; fp_Page * pLinePage; _getBrokenRect(pBroke, pLinePage, bRec,getGraphics()); dg_DrawArgs da; UT_sint32 xoff,yoff; fp_Container * pCon = static_cast(this); pView->getPageScreenOffsets(pLinePage,xoff,yoff); // // Just need to get the offsets of the container that contains // this table. // pCon = pCon->getContainer(); while(pCon && !pCon->isColumnType()) { xoff += pCon->getX(); yoff += pCon->getY(); pCon = pCon->getContainer(); } if(pCon) { xoff += pCon->getX(); yoff += pCon->getY(); } if(getY() < pBroke->getYBreak()) { // // Have to account for the bit of the cell on the previous page // da.yoff = yoff - pBroke->getYBreak(); } da.xoff = xoff; da.yoff = yoff; da.bDirtyRunsOnly = false; da.pG = pView->getGraphics(); drawBroken(&da,pBroke); return ; } /*! * Deletes any broken tables in this cell. */ void fp_CellContainer::deleteBrokenTables(bool bClearFirst) { if(!containsNestedTables()) { return; } fl_CellLayout * pCell = static_cast(getSectionLayout()); fl_ContainerLayout * pCL = pCell->getFirstLayout(); while(pCL) { xxx_UT_DEBUGMSG(("Looking at CL %x for delete \n",pCL)); if(pCL->getContainerType() == FL_CONTAINER_TABLE) { fl_TableLayout * pTL = static_cast(pCL); fp_TableContainer * pTab = static_cast(pTL->getFirstContainer()); xxx_UT_DEBUGMSG(("Doing delete broken tables on %x \n",pTab)); if(pTab) { pTab->deleteBrokenTables(bClearFirst,false); } } pCL = pCL->getNext(); } } /*! * Draw the whole cell with the selection colour background. * returns the last drawn cell in the container or NULL \Param pLine pointer to the line contained within the cell the cell. */ fp_Container * fp_CellContainer::drawSelectedCell(fp_Line * /*pLine*/) { UT_return_val_if_fail(getPage(), NULL); FV_View * pView = getPage()->getDocLayout()->getView(); fp_TableContainer * pTab = static_cast(getContainer()); if(pTab == NULL) { return NULL; } UT_ASSERT(pTab->getContainerType() == FP_CONTAINER_TABLE); fp_TableContainer * pBroke = pTab->getFirstBrokenTable(); if(pBroke == NULL) { return NULL; } bool bFound = false; bool bEnd = false; UT_sint32 iBroke = 0; while(pBroke && !bEnd) { if(doesOverlapBrokenTable(pBroke)) { bFound = true; // // Set a flag to indicate the cell is selected // m_bIsSelected = true; // // Now get a rectangle to calculate draw arguments // UT_Rect bRec; fp_Page * pLinePage; _getBrokenRect(pBroke, pLinePage, bRec,getGraphics()); dg_DrawArgs da; UT_sint32 xoff,yoff; fp_Container * pCon = static_cast(this); pView->getPageScreenOffsets(pLinePage,xoff,yoff); // // Just need to get the offsets of the container that contains // this table. // pCon = static_cast(pBroke); fp_TableContainer * pMaster = pBroke->getMasterTable(); if(pMaster->getFirstBrokenTable() == pBroke) { pCon = static_cast(pBroke->getMasterTable()); } while(pCon && !pCon->isColumnType()) { xoff += pCon->getX(); yoff += pCon->getY(); pCon = pCon->getContainer(); } if(pCon) { xoff += pCon->getX(); yoff += pCon->getY(); } yoff -= pBroke->getYBreak(); da.xoff = xoff; da.yoff = yoff; da.bDirtyRunsOnly = false; da.pG = pView->getGraphics(); drawBroken(&da,pBroke); m_bBgDirty = true; } else if(bFound) { bEnd = true; } iBroke++; pBroke = static_cast(pBroke->getNext()); } fp_Container * pLast = NULL; if(getNext()) { pLast = static_cast(static_cast(getNext())->getNthCon(0)); while(pLast && pLast->getContainerType() !=FP_CONTAINER_LINE) { pLast = static_cast(pLast->getNthCon(0)); } } else { fl_ContainerLayout * pCL = static_cast(getSectionLayout()); pCL = pCL->getNext(); if(pCL) { pLast = pCL->getFirstContainer(); while(pLast && pLast->getContainerType() !=FP_CONTAINER_LINE) { pLast = static_cast(pLast->getNthCon(0)); } } } return pLast; } /*! * This method returns true if the cell overlaps the supplied broken * table. */ bool fp_CellContainer::doesOverlapBrokenTable(fp_TableContainer * pBroke) { UT_sint32 nextRow = m_iBottomAttach; UT_sint32 yCellBot = 0; if(nextRow <= pBroke->getMasterTable()->getNumRows()) { yCellBot = pBroke->getMasterTable()->getYOfRow(nextRow); } else { yCellBot = pBroke->getMasterTable()->getY() + pBroke->getMasterTable()->getHeight(); } if((pBroke->getYBreak() <= getY()) && (getY() <= pBroke->getYBottom())) { return true; } if((pBroke->getYBreak() < yCellBot) && (yCellBot <= pBroke->getYBottom())) { return true; } // // The broken table is containtained within this cell. // ie The cell spans several pages. // if((pBroke->getYBreak() >= getY()) && (yCellBot >= pBroke->getYBottom())) { return true; } return false; } /*! Draw container content visible within the supplied broken table \param pDA Draw arguments \param pBroke broken table that cell is part of */ void fp_CellContainer::drawBroken(dg_DrawArgs* pDA, fp_TableContainer * pBroke) { GR_Graphics * pG = pDA->pG; m_bDrawLeft = false; m_bDrawTop = false; fp_TableContainer * pTab2 = NULL; bool bIsNested = isInNestedTable(); if(pBroke && pBroke->isThisBroken()) { pTab2 = pBroke->getMasterTable(); } else { pTab2 = static_cast(getContainer()); } // draw bottom if this cell is the last of the table and fully contained on the page m_bDrawBot = (pTab2->getCellAtRowColumn(getBottomAttach(),getLeftAttach()) == NULL); // draw right if this cell is the rightmost of the table m_bDrawRight = (pTab2->getCellAtRowColumn(getTopAttach(),getRightAttach()) == NULL); m_bDrawRight = true; m_bDrawLeft = true; const UT_Rect * pClipRect = pDA->pG->getClipRect(); UT_sint32 ytop,ybot; UT_sint32 i; UT_sint32 imax = static_cast((static_cast(1<<29)) - 1); UT_Rect bRec; fp_Page * pPage; _getBrokenRect(pBroke, pPage, bRec,pG); xxx_UT_DEBUGMSG(("Draw Broken Table %p ybreak %d On Page %d cell %p \n",pBroke,pBroke->getYBreak(),pPage->getPageNumber(),this)); if((bRec.height < 0) || (bRec.width < 0)) return; if(getFillType()->getFillType() == FG_FILL_IMAGE && (getContainer() != NULL)) { fl_DocSectionLayout * pDSL = getSectionLayout()->getDocSectionLayout(); if(pDSL && (bRec.height < pDSL->getActualColumnHeight()) && (bRec.height > pG->tlu(3))) { getSectionLayout()->setImageHeight(bRec.height); getSectionLayout()->setImageWidth(bRec.width); getFillType()->setWidthHeight(pG,bRec.width,bRec.height,true); } } if(pClipRect) { ybot = UT_MAX(pClipRect->height,_getMaxContainerHeight()); ytop = pClipRect->top; ybot = ybot + ytop + pG->tlu(1); } else { ytop = 0; ybot = imax; } xxx_UT_DEBUGMSG(("cliprect %x ytop %d ybot %d \n",pClipRect,ytop,ybot)); bool bStop = false; bool bStart = false; xxx_UT_DEBUGMSG(("drawBroken: Drawing broken cell %x x %d, y %d width %d height %d ncons %d \n",this,getX(),getY(),getWidth(),getHeight(),countCons())); // // Now draw the cell background. // GR_Painter painter(pG); if (((m_bIsSelected == false) || (!pG->queryProperties(GR_Graphics::DGP_SCREEN))) && (m_bBgDirty || !pDA->bDirtyRunsOnly)) { UT_sint32 srcX = 0; UT_sint32 srcY = 0; getFillType()->setWidthHeight(pG,bRec.width,bRec.height); getLeftTopOffsets(srcX,srcY); getFillType()->Fill(pG,srcX,srcY,bRec.left,bRec.top,bRec.width,bRec.height); if(getPage()) { getPage()->expandDamageRect(bRec.left,bRec.top,bRec.width,bRec.height); } m_bBgDirty = false; } // // This cell is selected, fill it with colour // else if(m_bIsSelected && pG->queryProperties(GR_Graphics::DGP_SCREEN)) { FV_View * pView = getPage()->getDocLayout()->getView(); xxx_UT_DEBUGMSG(("drawBroke: fill rect: Final top %d bot %d pBroke %x \n",bRec.top,bRec.top + bRec.height,pBroke)); UT_ASSERT((bRec.left + bRec.width) < static_cast(pView->getWidthPagesInRow(getPage())) ); ///////////////////////////////////// if(bIsNested) { xxx_UT_DEBUGMSG(("Drawing nested selected cell top %d height %d \n",bRec.top,bRec.height)); } painter.fillRect(pView->getColorSelBackground(),bRec.left,bRec.top,bRec.width,bRec.height); if(getPage()) { getPage()->expandDamageRect(bRec.left,bRec.top,bRec.width,bRec.height); } } // // Only draw the lines in the clipping region. // xxx_UT_DEBUGMSG(("number containers %d \n",countCons())); UT_sint32 iLastDraw = 0; for ( i = 0; (i< countCons() && !bStop); i++) { fp_Container* pContainer = static_cast(getNthCon(i)); if(pBroke->isInBrokenTable(this, pContainer)) { dg_DrawArgs da = *pDA; // // pDA has xoff set at the columns left edge, we need to offset this // by the cell x position. // pDA has yoffset at the last ypos in the column relative to the screen // The position Ypos is the absolute position on the screen we need // to offset this with the position of the container holding this // cell. da.xoff += pContainer->getX() + getX(); da.yoff += pContainer->getY() + getY(); UT_sint32 ydiff = da.yoff + pContainer->getHeight(); if(pContainer->getContainerType() == FP_CONTAINER_TABLE) { UT_sint32 TabHeight= 0; fp_TableContainer * pTCon = static_cast(pContainer); if(pTCon->isThisBroken()) { TabHeight = pTCon->getHeight(); } else if(pTCon->getFirstBrokenTable()) { pContainer = pTCon->getFirstBrokenTable(); TabHeight = static_cast(pContainer)->getHeight(); } else { TabHeight = static_cast(pContainer)->getHeight(); } ydiff = da.yoff + TabHeight; } xxx_UT_DEBUGMSG((" -1- da.yoff %d ydiff %d \n",da.yoff,ydiff)); // UT_ASSERT(da.yoff > 1000); if(containsNestedTables()) { xxx_UT_DEBUGMSG(("draw nested somewhere da.yoff %d ytop %d ybot %d ydiff %d \n",da.yoff,ytop,ybot,ydiff)); } if((da.yoff >= ytop && da.yoff <= ybot) || (ydiff >= ytop && ydiff <= ybot)) { // // Draw the top of the cell if the cell starts on this page. // xxx_UT_DEBUGMSG((" -2- da.yoff %d ydiff %d \n",da.yoff,ydiff)); if(i == 0) { m_bDrawTop = true; } bStart = true; if(containsNestedTables()) { xxx_UT_DEBUGMSG((" drawBroken drawing container %d da.yoff %d pContainer->getY() %d \n",i,da.yoff,pContainer->getY())); } if(pContainer->getContainerType() == FP_CONTAINER_TABLE) { fp_TableContainer * pTab = static_cast(pContainer); if(pTab->isThisBroken()) { xxx_UT_DEBUGMSG(("Draw nested broken table %p da.yoff %d yBreak %d \n",pTab,da.yoff,pTab->getYBreak())); dg_DrawArgs daa = da; daa.yoff -= pTab->getYBreak(); pTab->draw(&daa); iLastDraw = i; } else { xxx_UT_DEBUGMSG(("Draw nested unbroken table %p da.yoff %d yBreak %d \n",pTab,da.yoff,pTab->getYBreak())); fp_TableContainer * pT= pTab->getFirstBrokenTable(); if(pT == NULL) { UT_DEBUGMSG(("No Broken Table in draw !! \n")); UT_sint32 iY = pTab->getY(); pTab = static_cast(pTab->VBreakAt(0)); pTab->setY(iY); } else { pTab = pT; } if(pTab) { xxx_UT_DEBUGMSG(("Draw first nested broken table %p da.yoff %d yBreak %d height %d next %p \n",pTab,da.yoff,pTab->getYBreak(),pTab->getHeight(),pTab->getNext())); pTab->draw(&da); iLastDraw = i; } } } else { if((pContainer->getMyBrokenContainer() == NULL ) || (pContainer->getMyBrokenContainer() == pBroke) || (pContainer->getBreakTick() != getBreakTick())) { pContainer->setBreakTick(getBreakTick()); pContainer->setMyBrokenContainer(pBroke); xxx_UT_DEBUGMSG((" -3- da.yoff %d ydiff %d \n",da.yoff,ydiff)); pContainer->draw(&da); iLastDraw = i; } else { xxx_UT_DEBUGMSG(("pCon->BrokenContainer %x pBroke %x \n",pContainer->getMyBrokenContainer(),pBroke)); } } } else if(bStart) { xxx_UT_DEBUGMSG(("drawBroken: Skipping container: ypos %d height %d ytop %d ybot %d \n",da.yoff,pContainer->getY(),ytop,ybot)); bStop = true; } } else if(bStart) { xxx_UT_DEBUGMSG(("drawBroken: Skipping container: 1 container pos %d ytop %d ybot %d \n",pContainer->getY(),ytop,ybot)); bStop = true; } else { xxx_UT_DEBUGMSG(("drawBroken: Container line:2 container pos %d ytop %d ybot %d pBroke %x \n",pContainer->getY(),ytop,ybot,pBroke)); } } if((iLastDraw >= countCons()-1) && !bStop) { m_bDirty = false; if(bIsNested) { xxx_UT_DEBUGMSG(("Clearing nested cell redraw %x \n",this)); } else if(containsNestedTables()) { xxx_UT_DEBUGMSG(("Clearing cell contained nested table of redraw %x \n",this)); } getSectionLayout()->clearNeedsRedraw(); } drawLines(pBroke,pG,true); drawLines(pBroke,pG,false); pTab2->setRedrawLines(); _drawBoundaries(pDA,pBroke); } /*! * Returns true since cells can be broken vertically. */ bool fp_CellContainer::isVBreakable(void) { return true; } /*! * Break the cell at the specified location. This is mostly to handle * the case of tables embedded in the cell. * vpos is relative to the start of the cell. */ fp_ContainerObject * fp_CellContainer::VBreakAt(UT_sint32 vpos) { UT_sint32 iBreakTick = getBreakTick(); iBreakTick++; setBreakTick(iBreakTick); xxx_UT_DEBUGMSG(("iBreakTick is %d \n",getBreakTick())); if(!containsNestedTables()) { return NULL; } vpos -= 2; // make broken container wholly within the cell. UT_sint32 count = countCons(); UT_DEBUGMSG(("vBREAK cell at %d \n",vpos)); UT_sint32 i =0; fp_Container * pCon; bool bBreak = false; fp_TableContainer * pBroke = NULL; UT_sint32 iY = 0; for(i=0; i< count; i++) { pCon = static_cast(getNthCon(i)); xxx_UT_DEBUGMSG(("Looking Container iY %d height %d \n",iY,pCon->getHeight())); if(pCon->getContainerType() == FP_CONTAINER_TABLE) { UT_DEBUGMSG(("Looking at nested table to break at %d height %d \n",vpos,pCon->getHeight())); } if(iY <= vpos && iY + pCon->getHeight() > vpos) { // // Container overlaps break point. See if container is // is a table // container if possible. // if(pCon->isVBreakable()) { if(pCon->getContainerType() == FP_CONTAINER_TABLE) { UT_DEBUGMSG(("Want to break nested table at %d \n",vpos)); fp_TableContainer * pTab = static_cast(pCon); if(!pTab->isThisBroken()) { if(pTab->getY() < -999999) { pTab->setY(iY); } if(pTab->getFirstBrokenTable()) { pCon = static_cast(pTab->getFirstBrokenTable()); } else { pCon = static_cast(pTab->VBreakAt(0)); fp_TableContainer * pBTab = static_cast(pCon); pBTab->setY(iY); UT_DEBUGMSG(("Break Nested table Con %p at 0 y %d height %d \n",pCon,pCon->getY(),pCon->getHeight())); UT_DEBUGMSG(("Break Nested table Table %p at 0 y %d height %d \n",pBTab,pBTab->getY(),pBTab->getHeight())); } } } if(vpos > 0) { // // Tables are broken from the start of the table. // vpos is preseneted as the distance from start of the // cell so we have to subtract the y position of the // first table. // if there is previous non-zero ybreak table this is added // so we // subtract that off too. This is because the top-level // tables are broken over columns and heights are // calculated from within these columns. // if(iY > vpos) vpos = iY+1; fp_TableContainer * pPrevTab = static_cast(pCon); fp_TableContainer * pMaster = pPrevTab->getMasterTable(); pBroke = static_cast(pPrevTab->VBreakAt(vpos - pMaster->getY() - pPrevTab->getYBreak())); pBroke->setY(vpos); static_cast(pBroke)->setY(pBroke->getY()); UT_DEBUGMSG(("Made broken nested Table %p Y %d height %d \n",pBroke,pBroke->getY(),pBroke->getHeight())); UT_ASSERT(pBroke->getContainer() == this); bBreak = true; break; } } } iY += pCon->getHeight(); iY += pCon->getMarginAfter(); } if(bBreak) { //layout(); } return static_cast(pBroke); } /*! * This routine requests that the cell be broken at the specfied height. * the return value of the method is the actual height it can be broken * which is less than or equal to the requested height. */ UT_sint32 fp_CellContainer::wantVBreakAt(UT_sint32 vpos) { UT_sint32 count = countCons(); UT_sint32 i =0; UT_sint32 iYBreak = vpos; fp_Container * pCon; fp_Line * pLine = NULL; UT_sint32 footHeight = 0; for(i=0; i< count; i++) { pCon = static_cast(getNthCon(i)); UT_sint32 iY = pCon->getY() + getY(); UT_sint32 conHeight = pCon->getHeight(); if(pCon->getContainerType() == FP_CONTAINER_LINE) { pLine = static_cast(pCon); if(pLine->containsFootnoteReference()) { UT_GenericVector vecFC; if(pLine->getFootnoteContainers(&vecFC)) { UT_sint32 k = 0; for(k=0; k < vecFC.getItemCount(); k++) { fp_FootnoteContainer * pFC = vecFC.getNthItem(k); conHeight += pFC->getHeight(); if((pFC->getPage() == NULL) || (pFC->getPage() != pLine->getPage())) { footHeight += pFC->getHeight(); } } } } if(pLine->containsAnnotations() && getSectionLayout()->getDocLayout()->displayAnnotations() ) { UT_GenericVector vecAC; if(pLine->getAnnotationContainers(&vecAC)) { UT_sint32 k = 0; for(k=0; k < vecAC.getItemCount(); k++) { fp_AnnotationContainer * pAC = vecAC.getNthItem(k); conHeight += pAC->getHeight(); if((pAC->getPage() == NULL) || (pAC->getPage() != pLine->getPage())) { footHeight += pAC->getHeight(); } } } } } if(iY <= vpos && iY + conHeight > vpos) { // // Container overlaps break point. Find break point in the // container if possible. // UT_sint32 iCur =0; if(pCon->isVBreakable()) { iCur = pCon->wantVBreakAt(vpos - iY); iCur = iCur + iY; } else { iCur = iY; } if(iCur < iYBreak) { iYBreak = iCur; } break; } } if((iYBreak == vpos) && (footHeight > 0)) { iYBreak = iYBreak - footHeight; } return iYBreak; } fp_Container * fp_CellContainer::getNextContainerInSection() const { fl_ContainerLayout * pCL = static_cast(getSectionLayout()); fl_ContainerLayout * pNext = pCL->getNext(); while(pNext && ((pNext->getContainerType() == FL_CONTAINER_ENDNOTE) || (pNext->getContainerType() == FL_CONTAINER_FRAME) || (pNext->isHidden() == FP_HIDDEN_FOLDED))) { pNext = pNext->getNext(); } if(pNext) { return pNext->getFirstContainer(); } return NULL; } fp_Container * fp_CellContainer::getPrevContainerInSection() const { fl_ContainerLayout * pCL = static_cast(getSectionLayout()); fl_ContainerLayout * pPrev = pCL->getPrev(); while(pPrev && ((pPrev->getContainerType() == FL_CONTAINER_ENDNOTE) || (pPrev->getContainerType() == FL_CONTAINER_FRAME) || (pPrev->isHidden() == FP_HIDDEN_FOLDED))) { pPrev = pPrev->getPrev(); } if(pPrev) { return pPrev->getLastContainer(); } return NULL; } void fp_CellContainer::sizeRequest(fp_Requisition * pRequest) { xxx_UT_DEBUGMSG(("Doing size request on %x \n",pRequest)); UT_sint32 count = countCons(); UT_sint32 i =0; UT_sint32 height = 0; UT_sint32 width = 0; for(i=0 ; i < count; i++) { fp_Container * pCon = static_cast(getNthCon(i)); if(pCon->getContainerType() == FP_CONTAINER_LINE) { static_cast(pCon)->recalcHeight(); if(width < pCon->getWidth()) { width = pCon->getWidth(); } xxx_UT_DEBUGMSG(("sizeRequest: Height of Line %d %d tot %d \n",i,pCon->getHeight(),height)); height = height + pCon->getHeight(); height = height + pCon->getMarginAfter(); } else { fp_Requisition pReq; if(pCon->getContainerType() == FP_CONTAINER_TABLE) { static_cast(pCon)->sizeRequest(&pReq); } else if(pCon->getContainerType() == FP_CONTAINER_CELL) { UT_ASSERT(UT_SHOULD_NOT_HAPPEN); } else { UT_ASSERT(UT_SHOULD_NOT_HAPPEN); } if(width < pReq.width) { width = pReq.width; } height = height + pReq.height; } xxx_UT_DEBUGMSG(("Total height %d \n",height)); } UT_sint32 maxwidth = 0; fl_CellLayout * pCellL = static_cast(getSectionLayout()); fl_ContainerLayout * pCL = pCellL->getFirstLayout(); while(pCL) { if(pCL->getContainerType() == FL_CONTAINER_BLOCK) { fl_BlockLayout * pBL = static_cast(pCL); UT_sint32 iw = pBL->getMaxNonBreakableRun(); if(maxwidth < iw) { maxwidth = iw; } } pCL = pCL->getNext(); } if(maxwidth > width) { width = maxwidth; } if(pRequest) { pRequest->width = width; pRequest->height = height; } fp_Column * pCol = static_cast(fp_Container::getColumn()); if(pCol && (width == 0)) { width = pCol->getWidth(); } m_MyRequest.width = width; m_MyRequest.height = height; xxx_UT_DEBUGMSG(("Size Request: Cell Total height %d width %d \n",height,width)); } void fp_CellContainer::sizeAllocate(fp_Allocation * pAllocate) { m_MyAllocation.width = pAllocate->width; m_MyAllocation.height = pAllocate->height; m_MyAllocation.x = pAllocate->x; m_MyAllocation.y = pAllocate->y; } void fp_CellContainer::layout(void) { _setMaxContainerHeight(0); UT_sint32 iY = 0, iPrevY = 0; fp_Container *pContainer, *pPrevContainer = NULL; xxx_UT_DEBUGMSG(("Doing Cell layout %x \n",this)); fp_TableContainer * pMyBrokenTable = NULL; if(countCons() == 0) { return; } pMyBrokenTable = getBrokenTable(static_cast(getNthCon(0))); for (UT_sint32 i=0; i < countCons(); i++) { pContainer = static_cast(getNthCon(i)); // // This is to speedup redraws. // if(pContainer->getHeight() > _getMaxContainerHeight()) _setMaxContainerHeight(pContainer->getHeight()); fp_TableContainer * pTab = NULL; if(pContainer->getY() != iY) { pContainer->clearScreen(); if(pContainer->getContainerType() == FP_CONTAINER_TABLE) { pTab = static_cast(pContainer); if(!pTab->isThisBroken()) { // // The position of the master table has changed. // All broken tables need to be rebroken pTab->deleteBrokenTables(false,true); } } } pContainer->setY(iY); UT_sint32 iContainerHeight = pContainer->getHeight(); UT_sint32 iContainerMarginAfter = pContainer->getMarginAfter(); if(pContainer->getContainerType() == FP_CONTAINER_TABLE) { xxx_UT_DEBUGMSG(("Doing Nested table layout Y 1 is %d \n",pContainer->getY())); pTab = static_cast(pContainer); if(!pTab->isThisBroken()) { if(pTab->getFirstBrokenTable() == NULL) { static_cast(pTab->VBreakAt(0)); pTab = pTab->getFirstBrokenTable(); if(pContainer->getY() == iY) { static_cast(pTab)->setY(iY); } } pTab = pTab->getFirstBrokenTable(); } pTab->setY(iY); iContainerHeight = pTab->getHeight(); xxx_UT_DEBUGMSG(("Doing Nested table layout Y 2 is %d height is %d YBottom %d \n",pTab->getY(),pTab->getHeight(),pTab->getYBottom())); } iY += iContainerHeight; iY += iContainerMarginAfter; //iY += 0.5; // Update height of previous line now we know the gap between // it and the current line. if (pPrevContainer && pPrevContainer->getContainerType() != FP_CONTAINER_TABLE) { pPrevContainer->setAssignedScreenHeight(iY - iPrevY); } pPrevContainer = pContainer; iPrevY = iY; } // Correct height position of the last line if (pPrevContainer) { pPrevContainer->setAssignedScreenHeight(iY - iPrevY + 1); } if (getHeight() == iY) { return; } setHeight(iY); } void fp_CellContainer::setToAllocation(void) { m_bBgDirty = true; setWidth(static_cast(m_MyAllocation.width)); setHeight(m_MyAllocation.height); setX(static_cast(m_MyAllocation.x)); xxx_UT_DEBUGMSG(("SEVIOR: set to width %d, height %d,y %d,x %d \n", m_MyAllocation.width,m_MyAllocation.height,m_MyAllocation.y,m_MyAllocation.x)); setMaxHeight(m_MyAllocation.height); setY(m_MyAllocation.y); layout(); } void fp_CellContainer::getLeftTopOffsets(UT_sint32 & xoff, UT_sint32 & yoff) const { fp_TableContainer * pTab = static_cast(getContainer()); UT_return_if_fail(pTab); xoff = -static_cast(pTab->getNthCol(getLeftAttach())->spacing); yoff = m_iTopY - getY(); } /*! * This method sets the line markers between the rows and columns. It must be called after * the setToAllocation() for all cells. */ void fp_CellContainer::setLineMarkers(void) { // // Set the boundary markers for line draing. // fp_TableContainer * pTab = static_cast(getContainer()); UT_return_if_fail(pTab); fl_TableLayout * pTL = static_cast(pTab->getSectionLayout()); fp_TableRowColumn *pCol = pTab->getNthCol(getLeftAttach()); if(pCol) m_iLeft = getX() - static_cast(pCol->spacing); fp_CellContainer * pCell = pTab->getCellAtRowColumn(getTopAttach(),getRightAttach()); if(pCell) { m_iRight = pCell->getX(); m_iRight -= static_cast(pTab->getNthCol(getRightAttach())->spacing); } else { // m_iRight = getX() + getWidth() - getGraphics()->tlu(1); m_iRight = getX() + getWidth(); m_iRight += static_cast (0.5 * static_cast(pTab->getBorderWidth())); } m_iTopY = pTab->getYOfRow(getTopAttach()); if(getTopAttach() == 0) { m_iTopY -= static_cast(0.5 * static_cast(pTab->getBorderWidth())); } else { fp_TableRowColumn *pRow = pTab->getNthRow(getTopAttach()); if(pRow) m_iTopY -= pRow->spacing/2; } if(getTopAttach() > 0) { UT_sint32 cLeft = 0; for(cLeft = getLeftAttach(); cLeft < getRightAttach(); cLeft++) { fp_CellContainer * pCellAtRow = pTab->getCellAtRowColumn(getTopAttach() -1,cLeft); if(pCellAtRow) { pCellAtRow->m_iBotY = m_iTopY; } else { break; } } } xxx_UT_DEBUGMSG(("getBottomAttach %d \n",getBottomAttach())); if(getBottomAttach() <= pTab->getNumRows()) { m_iBotY = pTab->getYOfRow(getBottomAttach()); if(getBottomAttach() < pTab->getNumRows()) { fp_TableRowColumn *pRow = pTab->getNthRow(getBottomAttach()); if(pRow) m_iBotY += pRow->spacing/2; } } else { // // Have to cast the MasterTable to a vertical container to get the full height of a broken // table. Otherwise we just get height of the first broken table. // fp_VerticalContainer * pVert = static_cast(pTab); m_iBotY = pTab->getYOfRow(0) + pVert->getHeight() -pTL->getBottomOffset() - getGraphics()->tlu(1); m_iBotY -= static_cast(2.0 * static_cast(pTab->getBorderWidth())); m_iBotY += pTab->getNthRow(pTab->getNumRows()-1)->spacing/2; } xxx_UT_DEBUGMSG(("SEVIOR getX %d left %d right %d top %d bot %d \n",getX(),m_iLeft,m_iRight,m_iTopY,m_iBotY)); } //--------------------------------------------------------------------- /*! Create a Master Table container. This is broken across other vertical Containers. \param iType Container type \param pSectionLayout Section layout type used for this container */ fp_TableContainer::fp_TableContainer(fl_SectionLayout* pSectionLayout) : fp_VerticalContainer(FP_CONTAINER_TABLE, pSectionLayout), m_iRows(0), m_iCols(0), m_iBorderWidth(0), m_bIsHomogeneous(true), m_iRowSpacing(0), m_iColSpacing(0), m_pFirstBrokenTable(NULL), m_pLastBrokenTable(NULL), m_bIsBroken(false), m_pMasterTable(NULL), m_iYBreakHere(0), m_iYBottom(0), m_bRedrawLines(false), m_iRepeatedRowNumber(-1), m_iRepeatedRowHeight(0), m_iLeftOffset(0), m_iRightOffset(0), m_iTopOffset(0), m_iBottomOffset(0), m_iLineThickness(1), m_iRowHeightType(FL_ROW_HEIGHT_NOT_DEFINED), m_iRowHeight(0), m_iLastWantedVBreak(-1), m_pFirstBrokenCell(NULL), m_pLastBrokenCell(NULL), m_bRecursiveClear(false) { if(getSectionLayout()) { getSectionLayout()->setNeedsRedraw(); getSectionLayout()->markAllRunsDirty(); } } /*! Create a broken Table container. This is placed between the cells and drawing. A vertical offset is subtracted from the Cells Y location for all manipulations. \param iType Container type \param pSectionLayout Section layout type used for this container */ fp_TableContainer::fp_TableContainer(fl_SectionLayout* pSectionLayout, fp_TableContainer * pMaster) : fp_VerticalContainer(FP_CONTAINER_TABLE, pSectionLayout), m_iRows(0), m_iCols(0), m_iBorderWidth(0), m_bIsHomogeneous(true), m_iRowSpacing(0), m_iColSpacing(0), m_pFirstBrokenTable(NULL), m_pLastBrokenTable(NULL), m_bIsBroken(true), m_pMasterTable(pMaster), m_iYBreakHere(0), m_iYBottom(0), m_iBrokenTop(0), m_iBrokenBottom(0), m_bRedrawLines(false), m_iRepeatedRowNumber(-1), m_iRepeatedRowHeight(0), m_iLeftOffset(0), m_iRightOffset(0), m_iTopOffset(0), m_iBottomOffset(0), m_iLineThickness(1), m_iRowHeightType(FL_ROW_HEIGHT_NOT_DEFINED), m_iRowHeight(0), m_iLastWantedVBreak(-1), m_pFirstBrokenCell(NULL), m_pLastBrokenCell(NULL), m_bRecursiveClear(false), m_iAdditionalMarginAfter(0) { } /*! Destruct container \note The Containers in vector of the container are not destructed. They are owned by the logical hierarchy (i.e., the fl_Container classes like fl_BlockLayout), not the physical hierarchy. */ fp_TableContainer::~fp_TableContainer() { UT_VECTOR_PURGEALL(fp_TableRowColumn *, m_vecRows); UT_VECTOR_PURGEALL(fp_TableRowColumn *, m_vecColumns); clearCons(); deleteBrokenTables(false,false); xxx_UT_DEBUGMSG(("SEVIOR: deleting table %x \n",this)); // // For debugging... // setContainer(NULL); setPrev(NULL); setNext(NULL); m_pMasterTable = NULL; } fp_Column * fp_TableContainer::getBrokenColumn(void) { if(!isThisBroken()) { return static_cast(fp_VerticalContainer::getColumn()); } fp_TableContainer * pBroke = this; bool bStop = false; fp_Column * pCol = NULL; while(pBroke && pBroke->isThisBroken() && !bStop) { fp_Container * pCon = pBroke->getContainer(); if(pCon->isColumnType()) { if(pCon->getContainerType() == FP_CONTAINER_COLUMN) { pCol = static_cast(pCon); } else { pCol = static_cast(pCon->getColumn()); } bStop = true; } else { fp_CellContainer * pCell = static_cast(pBroke->getContainer()); UT_ASSERT(pCell->getContainerType() == FP_CONTAINER_CELL); pBroke = pCell->getBrokenTable(static_cast(pBroke)); } } if(pBroke && !bStop) { pCol = static_cast(pBroke->getContainer()); } // UT_ASSERT(pCol->getContainerType() != FP_CONTAINER_CELL); if(pCol && pCol->getContainerType() == FP_CONTAINER_CELL) { fp_Container * pCon = static_cast(pCol); while(pCon && !pCon->isColumnType()) { pCon = pCon->getContainer(); } if(pCon) { pCol = static_cast(pCon); } else { pCol = NULL; } } return pCol; } bool fp_TableContainer::containsNestedTables(void) { fl_TableLayout * pTL = static_cast(getSectionLayout()); return (pTL->getNumNestedTables() > 0); } fp_TableContainer * fp_TableContainer::getFirstBrokenTable(void) const { if(isThisBroken()) { return getMasterTable()->getFirstBrokenTable(); } return m_pFirstBrokenTable; } /* * Just draw the lines around a table */ void fp_TableContainer::drawLines(void) { if(isThisBroken()) { m_bRedrawLines = false; getMasterTable()->drawLines(); return; } fp_CellContainer * pCell = static_cast(getNthCon(0)); while(pCell) { fp_TableContainer * pBroke = getFirstBrokenTable(); if(pBroke) { while(pBroke) { pCell->drawLines(pBroke,getGraphics(),true); pCell->drawLines(pBroke,getGraphics(),false); pBroke = static_cast(pBroke->getNext()); } } else { pCell->drawLines(NULL,getGraphics(),true); pCell->drawLines(NULL,getGraphics(),false); } pCell = static_cast(pCell->getNext()); } m_bRedrawLines = false; } fp_TableContainer * fp_TableContainer::getLastBrokenTable(void) const { if(isThisBroken()) { return getMasterTable()->getLastBrokenTable(); } return m_pLastBrokenTable; } UT_sint32 fp_TableContainer::getBrokenNumber(void) { if(!isThisBroken()) { return 0; } fp_TableContainer * pTab = getMasterTable()->getFirstBrokenTable(); UT_sint32 i = 1; while(pTab && pTab != this) { pTab = static_cast(pTab->getNext()); i++; } if(!pTab) { return -1; } return i; } void fp_TableContainer::setFirstBrokenTable(fp_TableContainer * pBroke) { if(isThisBroken()) { UT_ASSERT(UT_SHOULD_NOT_HAPPEN); fp_TableContainer * pMaster = getMasterTable(); pMaster->setFirstBrokenTable(pBroke); fp_TableContainer * pNext = static_cast(pMaster); while(pNext) { pNext->setFirstBrokenTable( pBroke); pNext = static_cast(pNext->getNext()); } } m_pFirstBrokenTable = pBroke; } void fp_TableContainer::setLastBrokenTable(fp_TableContainer * pBroke) { if(isThisBroken()) { fp_TableContainer * pMaster = getMasterTable(); pMaster->setLastBrokenTable(pBroke); fp_TableContainer * pNext = static_cast(pMaster); while(pNext) { pNext->setLastBrokenTable( pBroke); pNext = static_cast(pNext->getNext()); } } m_pLastBrokenTable = pBroke; } /*! * Return the Y location of row number row */ UT_sint32 fp_TableContainer::getYOfRow(UT_sint32 row) { UT_sint32 i =0; UT_sint32 numCols = getNumCols(); if(row > getNumRows()) { return 0; } fp_CellContainer * pCell = getCellAtRowColumn(0,0); UT_sint32 iYRow = 0; if(pCell != NULL) { iYRow = pCell->getY(); } for(i=0; i< numCols; i++) { pCell = getCellAtRowColumn(0,i); if(pCell) { UT_sint32 Y = pCell->getY(); if(Y < iYRow) { iYRow = Y; } } } if(row == 0) { return iYRow; } xxx_UT_DEBUGMSG(("Looking for row %d numrows %d \n",row,getNumRows())); for(i=0; i < row; i++) { fp_TableRowColumn *pRow = getNthRow(i); if(pRow) { iYRow += pRow->allocation; iYRow += pRow->spacing; } xxx_UT_DEBUGMSG((" row %d Height here %d \n",i,iYRow)); } if((row < getNumRows()) && (i > 0)) { fp_TableRowColumn *pRow = getNthRow(i-1); if(pRow) { iYRow -= pRow->spacing; iYRow += pRow->spacing/2; } } return iYRow; } /*! * This method returns the Y Location of the line drawn across the top of * broken table. * It returns -1 if the table is not broken or it is the first broken table * of the chain. */ UT_sint32 fp_TableContainer::getBrokenTop(void) { if(getMasterTable() == NULL) { return -1; } else if(getYBreak() == 0) { return -1; } return m_iBrokenTop; } /*! * This method returns the Y Location of the line drawn across the Bottom of * broken table. * It returns -1 if the table is not broken. */ UT_sint32 fp_TableContainer::getBrokenBot(void) { if(getMasterTable() == NULL) { return -1; } return m_iBrokenBottom; } /*! * This static function is used to compare cells' position for the * UT_Vector::binarysearch \param vX1 pointer to a Point value. \param vX2 pointer to a fp_CellContainer object */ static UT_sint32 compareCellPosBinary(const void * vX1, const void * vX2) { const UT_Point *pt = static_cast(vX1); const fp_ContainerObject *pc = *(fp_ContainerObject **)(vX2); const fp_CellContainer *pCell = static_cast(pc); if((pCell->getTopAttach()) <= pt->y && (pCell->getBottomAttach() > pt->y) && (pCell->getLeftAttach() <= pt->x) && (pCell->getRightAttach() > pt->x)) { return 0; } // compare cell's top and bottom first if (pCell->getTopAttach() > pt->y) { return -1; } if (pCell->getBottomAttach() <= pt->y) { return 1; } // then compare cell's left position if (pCell->getLeftAttach() > pt->x) { return -1; } if (pCell->getRightAttach() <= pt->x) { return 1; } return 0; } /*! * Binary search failed. Do a simple Linear search instead */ fp_CellContainer * fp_TableContainer::getCellAtRowColumnLinear(UT_sint32 row, UT_sint32 col) { UT_sint32 i = 0; fp_CellContainer * pCell = NULL; bool bFound = false; for(i=0; (i(getNthCon(i)); if((pCell->getTopAttach()) <= row && (pCell->getBottomAttach() > row) && (pCell->getLeftAttach() <= col) && (pCell->getRightAttach() > col)) { return pCell; } } return NULL; } /*! * Return the cell container at the specified row and column */ fp_CellContainer * fp_TableContainer::getCellAtRowColumn(UT_sint32 row, UT_sint32 col) { UT_Point pt; pt.x = col; pt.y = row; if((row >= getNumRows()) || (row <0)) { return NULL; } if((col >= getNumCols()) || (col < 0)) { return NULL; } UT_sint32 u =-1; u = binarysearchCons(&pt, compareCellPosBinary); if (u != -1) { fp_CellContainer *pSmall = static_cast(getNthCon(u)); if((pSmall->getTopAttach() > row) || (pSmall->getBottomAttach() <= row) || (pSmall->getLeftAttach() > col) || (pSmall->getRightAttach() <= col)) { xxx_UT_DEBUGMSG(("No cell found 1 at %d %d \n",row,col)); xxx_UT_DEBUGMSG(("Returned cell left %d right %d top %d bot %d pt.y %d \n",pSmall->getLeftAttach(),pSmall->getRightAttach(),pSmall->getTopAttach(),pSmall->getBottomAttach(),pt.y)); return getCellAtRowColumnLinear(row,col); } return pSmall; } xxx_UT_DEBUGMSG(("No cell found -2 at %d %d \n",row,col)); return getCellAtRowColumnLinear(row,col); } /* * This method looks up the various propeties of the table and returns the * height of a given row. The input parameter iMeasHeight is the height * the row would have if it's height was automatically calculated from the * height of the rows. */ UT_sint32 fp_TableContainer::getRowHeight(UT_sint32 iRow, UT_sint32 iMeasHeight) { fl_TableLayout * pTL = static_cast(getSectionLayout()); UT_return_val_if_fail(pTL, 0); const UT_GenericVector* pVecRow = pTL->getVecRowProps(); if(pVecRow->getItemCount() < (iRow + 1)) { if(m_iRowHeight == 0) { return iMeasHeight; } if(m_iRowHeightType == FL_ROW_HEIGHT_EXACTLY) { return m_iRowHeight; } if(m_iRowHeightType == FL_ROW_HEIGHT_AT_LEAST) { if(iMeasHeight < m_iRowHeight) { return m_iRowHeight; } else { return iMeasHeight; } } return iMeasHeight; } fl_RowProps * pRowProps = pVecRow->getNthItem(iRow); UT_sint32 iRowHeight = pRowProps->m_iRowHeight; FL_RowHeightType rowType = pRowProps->m_iRowHeightType; if(rowType == FL_ROW_HEIGHT_EXACTLY ) { return iRowHeight; } if(rowType == FL_ROW_HEIGHT_AT_LEAST) { if(iMeasHeight < iRowHeight) { return iRowHeight; } else { return iMeasHeight; } } if(rowType == FL_ROW_HEIGHT_AUTO) { return iMeasHeight; } // // Here is the row type is undefined // if(m_iRowHeightType == FL_ROW_HEIGHT_EXACTLY) { if(m_iRowHeight == 0 ) { if(iRowHeight > 0) { return iRowHeight; } else { return iMeasHeight; } } else { return m_iRowHeight; } } if(m_iRowHeightType == FL_ROW_HEIGHT_AT_LEAST) { if(m_iRowHeight > 0) { if(iMeasHeight < m_iRowHeight) { return m_iRowHeight; } else { return iMeasHeight; } return iMeasHeight; } if(iMeasHeight > iRowHeight) { return iMeasHeight; } else { return iRowHeight; } } if(m_iRowHeightType == FL_ROW_HEIGHT_AUTO) { return iMeasHeight; } // // Undefined on undefined with a defined height - assume AT_LEAST // if(iMeasHeight > iRowHeight) { return iMeasHeight; } return iRowHeight; } /*! Find document position from X and Y coordinates \param x X coordinate \param y Y coordinate \retval pos Document position \retval bBOL True if position is at begining of line, otherwise false \retval bEOL True if position is at end of line, otherwise false */ void fp_TableContainer::mapXYToPosition(UT_sint32 x, UT_sint32 y, PT_DocPosition& pos, bool& bBOL, bool& bEOL, bool & isTOC) { if(isThisBroken()) { y = y + getYBreak(); getMasterTable()->mapXYToPosition(x,y, pos,bBOL,bEOL,isTOC); return; } UT_sint32 count = countCons(); if(count == 0) { pos = 2; bBOL = true; bEOL = true; return; } y = y + getYBreak(); xxx_UT_DEBUGMSG(("SEVIOR: Table %x Looking for location x %d y %d \n",this,x,y)); fp_VerticalContainer* pC = NULL; UT_sint32 i = 0; bool bFound = false; // First see if there is a container with the point inside it. for(i=0; (i< count) && !bFound; i++) { pC = static_cast(getNthCon(i)); if(x >= pC->getX() && x < pC->getX() + pC->getWidth() && y >= pC->getY() && y < pC->getY()+ pC->getMaxHeight()) { bFound = true; } } if(bFound) { pC->mapXYToPosition(x - pC->getX(), y - pC->getY(), pos, bBOL, bEOL,isTOC); return; } // // No cell directly overlaps. Look first for a column that overlaps and // then choose the cell that is closest within that. Otherwise choose // the closest cell. // fp_VerticalContainer * pCloseX = NULL; fp_VerticalContainer * pCloseTot = NULL; UT_sint32 dclosex = 231456789; UT_sint32 dclosetot = 231456789; UT_sint32 d = 0; for(i=0; (i< count) && !bFound; i++) { pC = static_cast(getNthCon(i)); if(pC->getContainerType() == FP_CONTAINER_TABLE) { fp_TableContainer * pTab = static_cast(pC); if(!pTab->isThisBroken()) { pC = static_cast(pTab->getFirstBrokenTable()); if(pC == NULL) { pC = static_cast(pC); } } } if(x >= pC->getX() && x < pC->getX() + pC->getWidth()) { d = y - pC->getY(); if(d < 0) d = - d; if(d < dclosex) { dclosex = d; pCloseX = pC; } } d = pC->distanceFromPoint(x,y); if(d < dclosetot) { pCloseTot = pC; dclosetot = d; } } if(pCloseX != NULL) { pC = pCloseX; } else { pC = pCloseTot; } UT_return_if_fail( pC != NULL); pC->mapXYToPosition(x - pC->getX(), y - pC->getY(), pos, bBOL, bEOL,isTOC); } void fp_TableContainer::resize(UT_sint32 n_rows, UT_sint32 n_cols) { if ((n_rows != m_iRows) || ( n_cols != m_iCols)) { fp_CellContainer * child = static_cast(getNthCon(0)); while(child) { n_rows = UT_MAX (n_rows, child->getBottomAttach()); n_cols = UT_MAX (n_cols, child->getRightAttach()); child = static_cast(child->getNext()); } if (n_rows != m_iRows) { UT_sint32 i; i = m_iRows; m_iRows = n_rows; UT_VECTOR_PURGEALL(fp_TableRowColumn *, m_vecRows); m_vecRows.clear(); for(i=0; i< m_iRows; i++) { m_vecRows.addItem(new fp_TableRowColumn()); fp_TableRowColumn * pRow = getNthRow(i); pRow->requisition = 0; pRow->allocation = 0; pRow->spacing = m_iRowSpacing; pRow->need_expand = 0; pRow->need_shrink = 0; pRow->expand = 0; pRow->shrink = 0; } } if (n_cols != m_iCols) { UT_sint32 i; i = m_iCols; m_iCols = n_cols; UT_VECTOR_PURGEALL(fp_TableRowColumn *, m_vecColumns); m_vecColumns.clear(); for(i=0; i< m_iCols; i++) { m_vecColumns.addItem(new fp_TableRowColumn()); fp_TableRowColumn *pCol= getNthCol(i); pCol->requisition = 0; pCol->allocation = 0; pCol->spacing = m_iColSpacing; pCol->need_expand = 0; pCol->need_shrink = 0; pCol->expand = 0; pCol->shrink = 0; } } } xxx_UT_DEBUGMSG(("SEVIOR: m_iRowSpacing = %d \n",m_iRowSpacing)); } /*! * Returns true if this is a broken table */ bool fp_TableContainer::isThisBroken(void) const { return m_bIsBroken; } /*! * Returns true since a table can be broken vertically. */ bool fp_TableContainer::isVBreakable(void) { // // Fixme remove this when nested tables break across pages. // #if 0 if(getContainer() && (getContainer()->getContainerType() == FP_CONTAINER_CELL)) { return false; } #endif return true; } /*! * This method adjusts the m_iYBreak and m_iYBottom variables after a * setY method changes the start position of the top of the table. */ void fp_TableContainer::adjustBrokenTables(void) { if(isThisBroken()) { // UT_ASSERT(UT_SHOULD_NOT_HAPPEN); return; } if(getFirstBrokenTable() == NULL) { return; } if(getFirstBrokenTable() == getLastBrokenTable()) { return; } // FIXME. Both this code and the code in fp_TOCContainer, somehow leads to bugs. I've clearly found // workarounds to what this is trying to achive. In pricinple this code should make laying out Table's // faster. In practice I suspect it leads to bugs in fb_ColumnBreaker. I'll leave these returns in place // for now, pending removal of the methods. // return; fp_TableContainer * pBroke = getFirstBrokenTable(); fp_VerticalContainer * pVC = static_cast(getContainer()); UT_sint32 iNewHeight = pVC->getMaxHeight() - getY(); UT_sint32 ishift = iNewHeight - pBroke->getYBottom(); UT_sint32 iNewBot = pBroke->getYBottom() + ishift; UT_sint32 iTableHeight = fp_VerticalContainer::getHeight(); xxx_UT_DEBUGMSG(("SEVIOR: ishift = %d iNewHeight %d pBroke->getYBottom() %d \n",ishift,iNewHeight,pBroke->getYBottom())); if(ishift == 0) { return; } if(iNewBot > iTableHeight) { iNewBot = iTableHeight; } pBroke->setYBottom(iNewBot); UT_ASSERT(pBroke->getHeight()); pBroke = static_cast(pBroke->getNext()); while(pBroke) { UT_sint32 iNewTop = pBroke->getYBreak(); iNewBot = pBroke->getYBottom(); pBroke->setYBreakHere(iNewTop + ishift); if(pBroke->getNext()) { pBroke->setYBottom(iNewBot+ishift); UT_ASSERT(pBroke->getHeight()); } else { pBroke->setYBottom(iTableHeight); UT_ASSERT(pBroke->getHeight()); } xxx_UT_DEBUGMSG(("SEVIOR: Broken table %x YBreak adjusted to %d Shift is %d height is %d \n",pBroke,iNewTop+ishift,ishift,pBroke->getHeight())); fp_TableContainer * pPrev = static_cast(pBroke->getPrev()); // // If the height of the previous plus the height of pBroke offset from // the previous position is less that the column height we can delete // this broken table. FIXE: This won't work for nested tables. // UT_sint32 iMaxHeight = 0; bool bDeleteOK = false; if(pPrev) { iMaxHeight = static_cast(pPrev->getContainer())->getMaxHeight(); xxx_UT_DEBUGMSG(("SEVIOR: sum %d maxheight %d \n",(pPrev->getY() + pPrev->getHeight() + pBroke->getHeight()), iMaxHeight)); } if(bDeleteOK && pPrev && (pPrev->getY() + pPrev->getHeight() + pBroke->getHeight() < iMaxHeight)) { // // FIXME: This if should be unnested.... // if(pPrev == this) { pPrev = getFirstBrokenTable(); } xxx_UT_DEBUGMSG(("SEVIOR; In adjust - Deleting table. Max height %d prev Y %d prev Height %d cur Height %d \n",iMaxHeight, pPrev->getY(),pPrev->getHeight(),pBroke->getHeight())); // // Don't need this table any more. Delete it and all following tables. // after adjusting the previous table. // pPrev->setYBottom(iTableHeight); UT_ASSERT(pPrev->getHeight()); pPrev->setNext( NULL); if(pPrev == getFirstBrokenTable()) { setNext(NULL); getFirstBrokenTable()->setYBreakHere(0); UT_ASSERT(getFirstBrokenTable()->getHeight()); } setLastBrokenTable(pPrev); xxx_UT_DEBUGMSG(("SEVIOR!!!!!!!!!!! 2 last broken table %x deleting %x Master Table %x \n",getLastBrokenTable(),pBroke,this)); xxx_UT_DEBUGMSG(("SEVIOR!!!!!!!!!!! 2 get first %x get last broken table %x \n",getFirstBrokenTable(),getLastBrokenTable())); fp_TableContainer * pT = getFirstBrokenTable(); UT_sint32 j = 0; while(pT) { xxx_UT_DEBUGMSG(("SEVIOR: Table %d is %x \n",j,pT)); j++; pT = static_cast(pT->getNext()); } while(pBroke) { fp_TableContainer * pNext = static_cast(pBroke->getNext()); UT_sint32 i = pBroke->getContainer()->findCon(pBroke); if(i >=0) { pBroke->getContainer()->deleteNthCon(i); } else { UT_ASSERT(UT_SHOULD_NOT_HAPPEN); } xxx_UT_DEBUGMSG(("SEVIOR: Adjust - Delete Table %x \n",pBroke)); delete pBroke; pBroke = pNext; } } else { pBroke = static_cast(pBroke->getNext()); } } } /*! * This deletes all the broken tables from this master table. * This routine assumes that a clear screen has been set already. */ void fp_TableContainer::deleteBrokenTables(bool bClearFirst, bool bRecurseUp) { if(isThisBroken()) { return; } if(bClearFirst) { clearScreen(); // // Remove broken Table pointers // clearBrokenContainers(); } if(getFirstBrokenTable() == NULL) { return; } fp_TableContainer * pUpTab = this; if(bRecurseUp) { while(pUpTab && pUpTab->getContainer() && pUpTab->getContainer()->getContainerType() == FP_CONTAINER_CELL) { fp_CellContainer * pUpCell = static_cast(pUpTab->getContainer()); pUpTab = static_cast(pUpCell->getContainer()); } if(pUpTab && (pUpTab != this)) { pUpTab->deleteBrokenTables(bClearFirst,false); return; } } if(containsNestedTables()) { xxx_UT_DEBUGMSG(("Deleting nested broken tables \n")); fp_CellContainer * pCell = static_cast(getFirstContainer()); while(pCell) { xxx_UT_DEBUGMSG(("Deleting broken tables in Cell Con %x \n",pCell)); pCell->deleteBrokenTables(bClearFirst); pCell = static_cast(pCell->getNext()); } } fp_TableContainer * pBroke = NULL; fp_TableContainer * pNext = NULL; fp_TableContainer * pLast = NULL; pBroke = getFirstBrokenTable(); bool bFirst = true; bool bDontRemove = false; fl_ContainerLayout * pMyConL = getSectionLayout()->myContainingLayout(); if(pMyConL && pMyConL->getContainerType() == FL_CONTAINER_CELL) { pMyConL = pMyConL->myContainingLayout(); fl_TableLayout * pTL = static_cast(pMyConL); if(pTL->isDoingDestructor()) { bDontRemove = true; } } while(pBroke ) { pNext = static_cast(pBroke->getNext()); // // Remove from list // if(pBroke->getPrev()) { pBroke->getPrev()->setNext(pBroke->getNext()); } if(pBroke->getNext()) { pBroke->getNext()->setPrev(pBroke->getPrev()); } pLast = pBroke; if(pBroke->getContainer() && !bDontRemove) { UT_sint32 i = pBroke->getContainer()->findCon(pBroke); // // First broken table is not in the container. // if(i >=0) { fp_Container * pCon = pBroke->getContainer(); pBroke->setContainer(NULL); pCon->deleteNthCon(i); xxx_UT_DEBUGMSG(("Delete %x from column %x \n",pBroke,pCon)); // // Search before and after. This should not happen! // FIXME put in some code to detect this in breakSection // fp_Container * pPrevCon = static_cast(pCon->getPrev()); while(pPrevCon && i >=0) { i = pPrevCon->findCon(pBroke); UT_sint32 j = i; while(j >= 0) { xxx_UT_DEBUGMSG(("Also remove table %x from column %x \n",pBroke,pPrevCon)); pPrevCon->deleteNthCon(j); j = pPrevCon->findCon(pBroke); } pPrevCon = static_cast(pPrevCon->getPrev()); } fp_Container * pNextCon = static_cast(pCon->getNext()); i = 0; while(pNextCon && (i>=0)) { i = pNextCon->findCon(pBroke); UT_sint32 j = i; while(j >= 0) { xxx_UT_DEBUGMSG(("Also remove table %x from column %x \n",pBroke,pNextCon)); pNextCon->deleteNthCon(j); j = pNextCon->findCon(pBroke); } pNextCon = static_cast(pNextCon->getNext()); } } } bFirst = false; xxx_UT_DEBUGMSG(("SEVIOR: table %x Deleting broken table %x \n",this,pBroke)); delete pBroke; if(pBroke == getLastBrokenTable()) { pBroke = NULL; } else { pBroke = pNext; } } setFirstBrokenTable(NULL); setLastBrokenTable(NULL); setNext(NULL); setPrev(NULL); // if(bClearFirst) { fl_TableLayout * pTL = static_cast(getSectionLayout()); if(pTL->myContainingLayout()->getContainerType() != FL_CONTAINER_CELL) { fl_DocSectionLayout * pDSL = pTL->getDocSectionLayout(); pDSL->deleteBrokenTablesFromHere(pTL); } } } void fp_TableContainer::setHeight(UT_sint32 iHeight) { if(!isThisBroken()) { xxx_UT_DEBUGMSG(("Unbroken Table Height set to %d from %d \n",iHeight,getHeight())); } fp_VerticalContainer::setHeight(iHeight); } UT_sint32 fp_TableContainer::getMarginBefore(void) const { if(isThisBroken()) { if(getPrev() && getPrev() == static_cast(getMasterTable())) { // getMargin of revious block fl_TableLayout * pTL = static_cast(getSectionLayout()); fl_ContainerLayout * pCL = pTL->getPrev(); if(pCL && pCL->getContainerType() == FL_CONTAINER_BLOCK) { return static_cast(pCL)->getBottomMargin(); } return 0; } else if( getPrev() == NULL) { // getMargin of revious block fl_TableLayout * pTL = static_cast(getSectionLayout()); fl_ContainerLayout * pCL = pTL->getPrev(); if(pCL && pCL->getContainerType() == FL_CONTAINER_BLOCK) { return static_cast(pCL)->getBottomMargin(); } return 0; } else { return 0; } } fl_TableLayout * pTL = static_cast(getSectionLayout()); fl_ContainerLayout * pCL = pTL->getPrev(); if(pCL && pCL->getContainerType() == FL_CONTAINER_BLOCK) { return static_cast(pCL)->getBottomMargin(); } return 0; } UT_sint32 fp_TableContainer::getMarginAfter(void) const { if(isThisBroken()) { if(getNext()) { return 0; // still in the table list } } fl_TableLayout * pTL = static_cast(getSectionLayout()); fl_ContainerLayout * pCL = pTL->getNext(); if(pCL && pCL->getContainerType() == FL_CONTAINER_BLOCK) { return static_cast(pCL)->getTopMargin()+ 0; } return 0; } /*! * vpos is the location from the top of the table that holds these * cells. */ void fp_TableContainer::breakCellsAt(UT_sint32 vpos) { if(!containsNestedTables()) { return; } fp_TableContainer * pMaster = NULL; if(isThisBroken()) { pMaster = getMasterTable(); } else { pMaster = this; } fp_CellContainer * pCell = static_cast(pMaster->getNthCon(0)); bool bStop = false; while(pCell && !bStop) { if(pCell->getY() >= vpos) { bStop = true; break; } if((pCell->getY() + pCell->getHeight()) > vpos) { pCell->VBreakAt(vpos - pCell->getY()); } pCell = static_cast(pCell->getNext()); } } /*! * This method creates a new broken tablecontainer, broken at the * offset given. * If the new tablecontainer is broken from a pre-existing * broken table it is inserted into the holding vertical container after * the old broken table. * It also inserted into the linked list of containers in the vertical * container. * vpos is relative to the either the start of the table if it's the first * non-zero vpos or relative to the previous ybreak if it's further down. */ fp_ContainerObject * fp_TableContainer::VBreakAt(UT_sint32 vpos) { /* If this table is nested in a cell we break it and leave it in the cell. cell->Master------>more lines \ Broke->Broke->Broke|more lines The offsets for each line will be calculated only with the top level broken table. */ fp_Container * pCon = getContainer(); UT_return_val_if_fail(pCon, NULL); bool bIsNested = false; if(pCon->getContainerType() == FP_CONTAINER_CELL) { bIsNested = true; xxx_UT_DEBUGMSG(("ypos of nested table being broken %d \n",getY())); } // // Do the case of creating the first broken table from the master table. // fp_TableContainer * pBroke = NULL; if(!isThisBroken() && getLastBrokenTable() == NULL) { if(getFirstBrokenTable() != NULL) { UT_ASSERT(UT_SHOULD_NOT_HAPPEN); return NULL; } pBroke = new fp_TableContainer(getSectionLayout(),this); xxx_UT_DEBUGMSG(("SEVIOR:!!!!!!! Frist broken table %x \n",pBroke)); pBroke->setYBreakHere(vpos); pBroke->setYBottom(fp_VerticalContainer::getHeight()); // leave this in! UT_ASSERT(pBroke->getHeight()); setFirstBrokenTable(pBroke); setLastBrokenTable(pBroke); pBroke->setContainer(getContainer()); /*UT_sint32 iTweak =*/ tweakBrokenTable(pBroke); static_cast(pBroke)->setHeight(pBroke->getHeight()); static_cast(pBroke)->setY(getY()); pBroke->breakCellsAt(vpos); return pBroke; } // // Now do the case of breaking a Master table. // if(getMasterTable() == NULL) { return getLastBrokenTable()->VBreakAt(vpos); } pBroke = new fp_TableContainer(getSectionLayout(),getMasterTable()); getMasterTable()->setLastBrokenTable(pBroke); xxx_UT_DEBUGMSG(("SEVIOR!!!!!!!!!!! New broken table %x \n",getLastBrokenTable())); // // vpos is relative to the container that contains this height but we need // to add in the height above it. // pBroke->setYBreakHere(getYBreak()+vpos); setYBottom(getYBreak() + vpos -1); UT_ASSERT(getHeight() >0); fp_VerticalContainer * pVCon = static_cast(getMasterTable()); if(pVCon == NULL) { } pBroke->setYBottom(pVCon->getHeight()); xxx_UT_DEBUGMSG(("SEVIOR????????: YBreak %d YBottom %d Height of broken table %d \n",pBroke->getYBreak(),pBroke->getYBottom(),pBroke->getHeight())); xxx_UT_DEBUGMSG(("SEVIOR????????: Previous table YBreak %d YBottom %d Height of broken table %d \n",getYBreak(),getYBottom(),getHeight())); UT_ASSERT(pBroke->getHeight() > 0); UT_sint32 i = 0; // // The structure of table linked list is as follows. // NULL <= Master <==> Next <==> Next => NULL // first // ie terminated by NULL's in the getNext getPrev list. The second // broken table points and is pointed to by the Master table // pBroke->setPrev(this); fp_Container * pUpCon = NULL; if(getMasterTable()->getFirstBrokenTable() == this) { i = getContainer()->findCon(getMasterTable()); pUpCon = getMasterTable()->getContainer(); pBroke->setPrev(getMasterTable()); pBroke->setNext(NULL); getMasterTable()->setNext(pBroke); setNext(pBroke); } else { pBroke->setNext(NULL); setNext(pBroke); if(getYBreak() == 0 ) { UT_ASSERT(UT_SHOULD_NOT_HAPPEN); pUpCon = getMasterTable()->getContainer(); // // Fallback for loads... // if(pUpCon == NULL) { pUpCon = getContainer(); } } else { pUpCon = getContainer(); } if(getYBreak() == 0) { i = pUpCon->findCon(getMasterTable()); } else { i = pUpCon->findCon(this); } } if(i >=0 && i < pUpCon->countCons() -1) { pUpCon->insertConAt(pBroke,i+1); } else if( i == pUpCon->countCons() -1) { pUpCon->addCon(pBroke); } else { UT_ASSERT(UT_SHOULD_NOT_HAPPEN); return NULL; } pBroke->setContainer(pUpCon); // // Now deal with issues from a container overlapping the top of the // of the new broken table. // UT_sint32 iTweak = tweakBrokenTable(pBroke); xxx_UT_DEBUGMSG(("BrakeTable: Tweak Result is %d !!!!!!!!!!!\n",iTweak)); if(iTweak > 0) { xxx_UT_DEBUGMSG(("Ybreak of %x set to %d after tweak \n",pBroke,pBroke->getYBreak() - iTweak)); pBroke->setYBreakHere(pBroke->getYBreak() - iTweak); xxx_UT_DEBUGMSG(("YBottom set to %d after tweak \n",getYBottom() - iTweak -1)); } static_cast(pBroke)->setHeight(pBroke->getHeight()); // // The cells are broken relative to the top of the table // breakCellsAt(getYBottom() - iTweak); return pBroke; } UT_sint32 fp_TableContainer::tweakBrokenTable(fp_TableContainer * pBroke) { fp_TableContainer * pTab = getMasterTable(); if(!pTab) { return 0; } UT_sint32 iTweak = 0; fp_CellContainer * pCell = NULL; UT_sint32 i = 0; for(i =0; icountCons(); i++) { pCell = static_cast(pTab->getNthCon(i)); UT_sint32 iTwk = pCell->tweakBrokenTable(pBroke); if(iTwk > iTweak) { iTweak = iTwk; } } return iTweak; } /*! * Overload the setY method */ void fp_TableContainer::setY(UT_sint32 i) { bool bIsFirstBroken = false; xxx_UT_DEBUGMSG(("fp_TableContainer: setY set to %d \n",i)); if(isThisBroken()) { xxx_UT_DEBUGMSG(("setY: getMasterTable %x FirstBrokenTable %x this %x \n",getMasterTable(),getMasterTable()->getFirstBrokenTable(),this)); if(getMasterTable()->getFirstBrokenTable() != this) { xxx_UT_DEBUGMSG(("setY: Later broken table set to %d \n",i)); fp_VerticalContainer::setY(i); return; } bIsFirstBroken = true; } // // Create an initial broken table if none exists // if(!bIsFirstBroken && (getFirstBrokenTable() == NULL)) { VBreakAt(0); } UT_sint32 iOldY = getY(); if(i == iOldY) { return; } clearScreen(); // // FIXME: Do I need to force another breakSection or will happen // automatically? // xxx_UT_DEBUGMSG(("Set Reformat 1 now from table %x in TableLayout %x \n",this,getSectionLayout())); // getSectionLayout()->setNeedsReformat(); fp_VerticalContainer::setY(i); adjustBrokenTables(); } void fp_TableContainer::setYBreakHere(UT_sint32 i) { xxx_UT_DEBUGMSG(("SEVIOR: Ybreak set to %d \n",i)); m_iYBreakHere = i; if(i > 0) { // UT_ASSERT(getHeight() > 0); } } void fp_TableContainer::setYBottom(UT_sint32 i) { m_iYBottom = i; // UT_ASSERT(getHeight() > 0); } /*! * The caller to this method requests a break at the vertical height * given. It returns the actual break height, which will always be * less than or equal to the requested height. */ UT_sint32 fp_TableContainer::wantVBreakAt(UT_sint32 vpos) { if(isThisBroken()) { return getMasterTable()->wantVBreakAt(vpos); } UT_sint32 count = countCons(); UT_sint32 i =0; UT_sint32 iYBreak = vpos; fp_CellContainer * pCell; for(i=0; i< count; i++) { pCell = static_cast(getNthCon(i)); if(pCell->getY() <= vpos && pCell->getY() + pCell->getHeight() > vpos) { // // Cell overlaps break point. Find break point in the cell. // UT_sint32 iCur = pCell->wantVBreakAt(vpos); if(iCur < iYBreak) { iYBreak = iCur; } } } return iYBreak; } /*! * returns the first fp_Line of the table in this column by recursively * searching down the table structure. */ fp_Line * fp_TableContainer::getFirstLineInColumn(fp_Column * pCol) { fp_TableContainer * pTab = NULL; fp_TableContainer * pBroke = NULL; fp_CellContainer * pCell = NULL; if(!isThisBroken()) { pTab = this; } else { pBroke = this; pTab = getMasterTable(); } pCell = static_cast(pTab->getNthCon(0)); if(!pBroke) { while(pCell) { fp_Container * pFirst = static_cast(pCell->getNthCon(0)); while(pFirst && pCell->getColumn(pFirst) != static_cast(pCol)) { pFirst = static_cast(pFirst->getNext()); } if(pFirst) { if(pFirst->getContainerType() == FP_CONTAINER_LINE) { return static_cast(pFirst); } if(pFirst->getContainerType() == FP_CONTAINER_TABLE) { return static_cast(pFirst)->getFirstLineInColumn(pCol); } UT_ASSERT(UT_SHOULD_NOT_HAPPEN); return NULL; } pCell = static_cast(pCell->getNext()); } return NULL; } while(pCell) { if(pCell->doesOverlapBrokenTable(pBroke)) { fp_Container * pFirst = static_cast(pCell->getNthCon(0)); while(pFirst && pCell->getColumn(pFirst) != static_cast(pCol)) { pFirst = static_cast(pFirst->getNext()); } if(pFirst) { if(pFirst->getContainerType() == FP_CONTAINER_LINE) { return static_cast(pFirst); } if(pFirst->getContainerType() == FP_CONTAINER_TABLE) { return static_cast(pFirst)->getFirstLineInColumn(pCol); } UT_ASSERT(UT_SHOULD_NOT_HAPPEN); return NULL; } } pCell = static_cast(pCell->getNext()); } return NULL; } /*! * returns the Last fp_Line of the table in this column by recursively * searching down the table structure. */ fp_Line * fp_TableContainer::getLastLineInColumn(fp_Column * pCol) { fp_TableContainer * pTab = NULL; fp_TableContainer * pBroke = NULL; fp_CellContainer * pCell = NULL; if(!isThisBroken()) { pTab = this; } else { pBroke = this; pTab = getMasterTable(); } UT_return_val_if_fail(pTab,NULL); if(pTab->countCons() == 0) { return NULL; } pCell = static_cast(pTab->getNthCon(pTab->countCons()-1)); if(!pBroke) { while(pCell) { if(pCell->countCons() > 0) { fp_Container * pLast = static_cast(pCell->getNthCon(pCell->countCons()-1)); while(pLast && pCell->getColumn(pLast) != static_cast(pCol)) { pLast = static_cast(pLast->getPrev()); } if(!pLast) return NULL; if(pLast->getContainerType() == FP_CONTAINER_LINE) { return static_cast(pLast); } if(pLast->getContainerType() == FP_CONTAINER_TABLE) { return static_cast(pLast)->getLastLineInColumn(pCol); } UT_ASSERT(UT_SHOULD_NOT_HAPPEN); return NULL; } pCell = static_cast(pCell->getPrev()); } return NULL; } while(pCell) { if(pCell->doesOverlapBrokenTable(pBroke) && (pCell->countCons() > 0)) { fp_Container * pLast = static_cast(pCell->getNthCon(pCell->countCons()-1)); while(pLast && pCell->getColumn(pLast) != static_cast(pCol)) { pLast = static_cast(pLast->getNext()); } if(pLast) { if(pLast->getContainerType() == FP_CONTAINER_LINE) { return static_cast(pLast); } if(pLast->getContainerType() == FP_CONTAINER_TABLE) { return static_cast(pLast)->getLastLineInColumn(pCol); } UT_ASSERT(UT_SHOULD_NOT_HAPPEN); return NULL; } } pCell = static_cast(pCell->getPrev()); } return NULL; } fp_Page * fp_TableContainer::getPage(void) { if(getContainer() && getContainer()->getContainerType() == FP_CONTAINER_CELL) { if(!isThisBroken()) { return fp_Container::getPage(); } fp_Column * pCol = getBrokenColumn(); if(pCol) { fp_Page * pPage = pCol->getPage(); return pPage; } if(getMasterTable() && getMasterTable()->getFirstBrokenTable() == this) { return fp_Container::getPage(); } // // OK all the easy cases dealt with.Now we have to find the page // associated with this broken table. // fp_CellContainer * pCell = static_cast(getContainer()); return pCell->getColumn(this)->getPage(); } return fp_Container::getPage(); } fp_Container * fp_TableContainer::getNextContainerInSection() const { if(getNext()) { return static_cast(getNext()); } fl_ContainerLayout * pCL = static_cast(getSectionLayout()); fl_ContainerLayout * pNext = pCL->getNext(); while(pNext && ((pNext->getContainerType() == FL_CONTAINER_ENDNOTE) || (pNext->getContainerType() == FL_CONTAINER_FRAME) || (pNext->isHidden() == FP_HIDDEN_FOLDED))) { pNext = pNext->getNext(); } if(pNext) { return pNext->getFirstContainer(); } return NULL; } fp_Container * fp_TableContainer::getPrevContainerInSection() const { if(getPrev()) { return static_cast(getPrev()); } fl_ContainerLayout * pCL = static_cast(getSectionLayout()); fl_ContainerLayout * pPrev = pCL->getPrev(); while(pPrev && ((pPrev->getContainerType() == FL_CONTAINER_ENDNOTE) || (pPrev->getContainerType() == FL_CONTAINER_FRAME) || (pPrev->isHidden() == FP_HIDDEN_FOLDED))) { pPrev = pPrev->getPrev(); } if(pPrev) { fp_Container * pPrevCon = static_cast(pPrev->getLastContainer()); // // Have to handle broken tables in the previous layout.. // if(pPrevCon->getContainerType() == FP_CONTAINER_TABLE) { fp_TableContainer * pTab = static_cast(pPrevCon); fp_TableContainer * pLLast = pTab; fp_TableContainer * pNext = static_cast(pTab->getNext()); while(pNext) { pLLast = pNext; pNext = static_cast(pNext->getNext()); } pPrevCon = static_cast(pLLast); } return pPrevCon; } return NULL; } void fp_TableContainer::tableAttach (fp_CellContainer *child) { UT_sint32 count = countCons(); if(count > 0) { fp_Container * pLast = static_cast(getNthCon(count - 1)); pLast->setNext(child); child->setPrev(pLast); } if (child->getRightAttach() >= m_iCols) { resize (m_iRows, child->getRightAttach()); } if (child->getBottomAttach() >= m_iRows) { resize (child->getBottomAttach(), m_iCols); } xxx_UT_DEBUGMSG(("tableAttach: Attaching cell %x to table \n",child)); addContainer(child); child->setContainer(static_cast(this)); queueResize(); } void fp_TableContainer::setContainer(fp_Container * pContainer) { if(isThisBroken()) { fp_Container::setContainer(pContainer); return; } if (pContainer == getContainer()) { return; } if (getContainer() && (pContainer != NULL)) { clearScreen(); } fp_Container::setContainer(pContainer); fp_TableContainer * pBroke = getFirstBrokenTable(); if(pBroke) { pBroke->setContainer(pContainer); } if(pContainer == NULL) { xxx_UT_DEBUGMSG(("Set master table %x container to NULL \n",this)); return; } setWidth(pContainer->getWidth()); } void fp_TableContainer::setRowSpacing (UT_sint32 row, UT_sint32 spacing) { if (getNthRow(row)->spacing != spacing) { getNthRow(row)->spacing = spacing; queueResize(); } } void fp_TableContainer::setColSpacing(UT_sint32 column,UT_sint32 spacing) { if (getNthCol(column)->spacing != spacing) { getNthCol(column)->spacing = spacing; queueResize(); } } void fp_TableContainer::setRowSpacings ( UT_sint32 spacing) { UT_sint32 row; m_iRowSpacing = spacing; for (row = 0; row < m_iRows; row++) { getNthRow(row)->spacing = spacing; } queueResize(); } void fp_TableContainer::setColSpacings (UT_sint32 spacing) { UT_sint32 col; m_iColSpacing = spacing; for (col = 0; col < m_iCols; col++) { getNthCol(col)->spacing = spacing; } queueResize(); } void fp_TableContainer::setHomogeneous (bool bIsHomogeneous) { if (bIsHomogeneous != m_bIsHomogeneous) { m_bIsHomogeneous = bIsHomogeneous; queueResize(); } } void fp_TableContainer::setBorderWidth(UT_sint32 iBorder) { if(iBorder == m_iBorderWidth) { return; } m_iBorderWidth = iBorder; queueResize(); } void fp_TableContainer::queueResize(void) { static_cast(getSectionLayout())->setDirty(); if(getContainer() && getContainer()->getContainerType() == FP_CONTAINER_CELL) { fp_TableContainer * pTab = static_cast(getContainer()->getContainer()); if(pTab && pTab->getContainerType() == FP_CONTAINER_TABLE) { pTab->queueResize(); } } } void fp_TableContainer::layout(void) { if(isThisBroken()) { UT_ASSERT(UT_SHOULD_NOT_HAPPEN); return; } xxx_UT_DEBUGMSG(("Doing Table layout %x \n",this)); #if BENCHLAYOUT printf("Doing Table layout \n"); timespec t1; clock_gettime(CLOCK_REALTIME, &t1); #endif fl_TableLayout * pTL = static_cast(getSectionLayout()); static fp_Requisition requisition; static fp_Allocation alloc; sizeRequest(&requisition); setX(m_iBorderWidth); alloc.x = getX(); alloc.y = getY() + pTL->getTopOffset(); alloc.width = getWidth(); alloc.height = requisition.height + pTL->getTopOffset() + pTL->getBottomOffset(); sizeAllocate(&alloc); setToAllocation(); #if BENCHLAYOUT timespec t2; clock_gettime(CLOCK_REALTIME, &t2); double millidiff = (t2.tv_sec-t1.tv_sec)*1e3 + (t2.tv_nsec-t1.tv_nsec)/1e6; printf("Layout TIME: %lf milliseconds\n", millidiff); #endif } void fp_TableContainer::setToAllocation(void) { bool bDeleteBrokenTables = false; setWidth(m_MyAllocation.width); if(fp_VerticalContainer::getHeight() != m_MyAllocation.height) { xxx_UT_DEBUGMSG(("Old table Height %d New allocation %d \n",fp_VerticalContainer::getHeight(),m_MyAllocation.height)); bDeleteBrokenTables = true; } // // clear and delete broken tables before their height changes. // Doing this clear at this point makes a table flicker when changing // height but it does remove the last the pixel dirt with tables. // if(bDeleteBrokenTables) { deleteBrokenTables(true,true); } setHeight(m_MyAllocation.height); setMaxHeight(m_MyAllocation.height); xxx_UT_DEBUGMSG(("SEVIOR: Height is set to %d \n",m_MyAllocation.height)); fp_CellContainer * pCon = static_cast(getNthCon(0)); while(pCon) { pCon->setToAllocation(); pCon = static_cast(pCon->getNext()); } pCon = static_cast(getNthCon(0)); while(pCon) { pCon->setLineMarkers(); pCon = static_cast(pCon->getNext()); } setYBottom(m_MyAllocation.height); } void fp_TableContainer::_size_request_init(void) { UT_sint32 row, col; for (row = 0; row < m_iRows; row++) { getNthRow(row)->requisition = 0; } m_iCols = m_vecColumns.getItemCount(); for (col = 0; col < m_iCols; col++) { getNthCol(col)->requisition = 0; } fp_CellContainer * pCell = static_cast(getNthCon(0)); while (pCell) { UT_ASSERT(pCell->getContainerType() == FP_CONTAINER_CELL); pCell->sizeRequest(NULL); pCell = static_cast(pCell->getNext()); } } void fp_TableContainer::_drawBoundaries(dg_DrawArgs* pDA) { UT_ASSERT(getPage()); if(getPage() == NULL) { return; } if(getPage()->getDocLayout()->getView() == NULL) { return; } UT_sint32 iWidth =0; UT_sint32 iBorderWidth =0; if(isThisBroken()) { iWidth = getMasterTable()->getWidth(); iBorderWidth = getMasterTable()->m_iBorderWidth; } else { iWidth = getWidth(); iBorderWidth = m_iBorderWidth; } if(getPage()->getDocLayout()->getView()->getShowPara() && getGraphics()->queryProperties(GR_Graphics::DGP_SCREEN)){ UT_sint32 xoffBegin = pDA->xoff - 1; UT_sint32 yoffBegin = pDA->yoff - 1; UT_sint32 xoffEnd = pDA->xoff + iWidth + 2 - static_cast (iBorderWidth * 2.0); UT_sint32 yoffEnd = pDA->yoff + getHeight() + 2; UT_RGBColor clrShowPara(127,127,127); getGraphics()->setColor(clrShowPara); xxx_UT_DEBUGMSG(("SEVIOR: Table Top (getY()) = %d \n",getY())); xxx_UT_DEBUGMSG(("SEVIOR: Table boundaries xleft %d xright %d ytop %d ybot %d \n",xoffBegin,xoffEnd,yoffBegin,yoffEnd)); GR_Painter painter (getGraphics()); painter.drawLine(xoffBegin, yoffBegin, xoffEnd, yoffBegin); painter.drawLine(xoffBegin, yoffEnd, xoffEnd, yoffEnd); painter.drawLine(xoffBegin, yoffBegin, xoffBegin, yoffEnd); painter.drawLine(xoffEnd, yoffBegin, xoffEnd, yoffEnd); } } void fp_TableContainer::_size_request_pass1(void) { UT_sint32 width; UT_sint32 height; fp_CellContainer * child = static_cast(getNthCon(0)); while (child) { // // OK send down // fp_Requisition child_requisition; child->sizeRequest(&child_requisition); /* Child spans a single column. */ if (child->getLeftAttach() == (child->getRightAttach() - 1)) { width = child_requisition.width + child->getLeftPad() + child->getRightPad(); getNthCol(child->getLeftAttach())->requisition = UT_MAX (getNthCol(child->getLeftAttach())->requisition, width); } /* Child spans a single row. */ if (child->getTopAttach() == (child->getBottomAttach() - 1)) { height = child_requisition.height + child->getTopPad() + child->getBotPad(); getNthRow(child->getTopAttach())->requisition = UT_MAX (getNthRow(child->getTopAttach())->requisition, height); } child = static_cast(child->getNext()); } } void fp_TableContainer::clearScreen(void) { // // If table is nested, do a clear screen on the topmost cell that // contains it // This should be fixed later. if(getSectionLayout() && getSectionLayout()->getDocLayout()) { if(getSectionLayout()->getDocLayout()->isLayoutDeleting()) { return; } } fp_Container *pUp = getContainer(); bool bIsNested = (pUp && (pUp->getContainerType() == FP_CONTAINER_CELL)); if(isThisBroken() && !bIsNested) { return; } if(getPage() == NULL) { return; } if(getPage()->getDocLayout()->isLayoutFilling()) { return; } UT_sint32 yoff,xoff; getPage()->getScreenOffsets(static_cast(this),xoff,yoff); if(yoff > getPage()->getHeight()) { return; } xxx_UT_DEBUGMSG(("Doing clear screen on %x \n",this)); fp_CellContainer * pCell = static_cast(getNthCon(0)); while(pCell) { // if(pCell->containsNestedTables()) // { // pCell->clearScreen(true); // } // else { pCell->clearScreen(); } pCell = static_cast(pCell->getNext()); } if(getSectionLayout()) { getSectionLayout()->setNeedsRedraw(); getSectionLayout()->markAllRunsDirty(); } } void fp_TableContainer::draw(dg_DrawArgs* pDA) { // // Don't draw if the table is still being constructed. // xxx_UT_DEBUGMSG(("TablecONTAINER enter draw table yoff %ld \n",pDA->yoff)); if(getSectionLayout()->getDocument()->isDontImmediateLayout()) { xxx_UT_DEBUGMSG(("TablecONTAINER leave draw dont immediately layout \n")); return; } if(pDA->bDirtyRunsOnly) { if(getSectionLayout() && !getSectionLayout()->needsRedraw()) { xxx_UT_DEBUGMSG(("TablecONTAINER leave draw section does not want redraw \n")); // return; } } if(isThisBroken()) { _brokenDraw(pDA); return; } else if(getFirstBrokenTable() != NULL) { getFirstBrokenTable()->draw( pDA); return; } fp_Container * pCell = static_cast(getNthCon(0)); while(pCell) { xxx_UT_DEBUGMSG(("!!!!!!!!!!!!Draw unbroken table cell !!!!!!!!!!\n")); pCell->draw(pDA); pCell = static_cast(pCell->getNext()); } _drawBoundaries(pDA); } UT_sint32 fp_TableContainer::getNumRows(void) const { return m_vecRows.getItemCount(); } UT_sint32 fp_TableContainer::getNumCols(void) const { return m_vecColumns.getItemCount(); } /*! * Return the height of this Table taking into account the possibility * of it being broken. */ UT_sint32 fp_TableContainer::getHeight(void) { UT_sint32 iFullHeight = fp_VerticalContainer::getHeight(); if(!isThisBroken()) { // // If this is a master table but it contains broken tables, we actually // want the height of the first broken table. The Master table is the // one that actually has a relevant Y value in the vertical container. // All other Y offsets from the broken tables are calculated relative to // it. // if(getFirstBrokenTable() != NULL) { return getFirstBrokenTable()->getHeight(); } return iFullHeight; } UT_sint32 iMyHeight = getYBottom() - getYBreak(); return iMyHeight; } /*! * Return true if the table contains footnote references */ bool fp_TableContainer::containsFootnoteReference(void) { fp_Container * pCon = getFirstContainer(); if(isThisBroken()) { pCon = getMasterTable()->getFirstContainer(); } bool bFound = false; while(pCon && !bFound) { if(pCon->getContainerType() == FP_CONTAINER_CELL) { fp_CellContainer * pCell = static_cast(pCon); if(pCell->containsFootnoteReference()) { if(isThisBroken()) { // // If broken check to see if the container containing the footnote reference // is on screen. // fp_Container * pCellCon = pCell->getFirstContainer(); while(pCellCon && !bFound) { if(isInBrokenTable(pCell,pCellCon)) { if(pCellCon->getContainerType() == FP_CONTAINER_LINE) { fp_Line * pLine = static_cast(pCellCon); if(pLine->containsFootnoteReference()) { bFound = true; } } else if(pCellCon->getContainerType() == FP_CONTAINER_TABLE) { fp_TableContainer *pTab = static_cast(pCellCon); if(pTab->containsFootnoteReference()) { bFound = true; } } } pCellCon = static_cast(pCellCon->getNext()); } } else { bFound = true; } } } else if(pCon->getContainerType() == FP_CONTAINER_TABLE) { fp_TableContainer *pTab = static_cast(pCon); bFound = pTab->containsFootnoteReference(); } pCon = static_cast(pCon->getNext()); } return bFound; } /*! * This method returns a vector of call the footnote layouts in this table */ bool fp_TableContainer::getFootnoteContainers(UT_GenericVector* pVecFoots) { fp_Container * pCon = getFirstContainer(); if(isThisBroken()) { pCon = getMasterTable()->getFirstContainer(); } bool bFound = false; while(pCon) { if(pCon->getContainerType() == FP_CONTAINER_CELL) { fp_CellContainer * pCell = static_cast(pCon); if(pCell->containsFootnoteReference()) { if(isThisBroken()) { // // If broken check to see if the container containing the footnote reference // is on screen. // fp_Container * pCellCon = pCell->getFirstContainer(); while(pCellCon) { if(isInBrokenTable(pCell,pCellCon)) { if(pCellCon->getContainerType() == FP_CONTAINER_LINE) { fp_Line * pLine = static_cast(pCellCon); if(pLine->containsFootnoteReference()) { bFound = true; UT_GenericVector vecFC; pLine->getFootnoteContainers(&vecFC); UT_sint32 i =0; for(i=0; i< vecFC.getItemCount();i++) { pVecFoots->addItem(vecFC.getNthItem(i)); } } } else if(pCellCon->getContainerType() == FP_CONTAINER_TABLE) { fp_TableContainer *pTab = static_cast(pCellCon); if(pTab->containsFootnoteReference()) { bFound = true; UT_GenericVector vecFC; pTab->getFootnoteContainers(&vecFC); UT_sint32 i =0; for(i=0; i< vecFC.getItemCount();i++) { pVecFoots->addItem(vecFC.getNthItem(i)); } } } } pCellCon = static_cast(pCellCon->getNext()); } } else { UT_GenericVector vecFC; pCell->getFootnoteContainers(&vecFC); UT_sint32 i =0; for(i=0; i< vecFC.getItemCount();i++) { pVecFoots->addItem(vecFC.getNthItem(i)); } bFound = true; } } } else if(pCon->getContainerType() == FP_CONTAINER_TABLE) { fp_TableContainer *pTab = static_cast(pCon); bFound = pTab->containsFootnoteReference(); if(bFound) { UT_GenericVector vecFC; pTab->getFootnoteContainers(&vecFC); UT_sint32 i =0; for(i=0; i< vecFC.getItemCount();i++) { pVecFoots->addItem(vecFC.getNthItem(i)); } } } pCon = static_cast(pCon->getNext()); } return bFound; } /*! * Return true if the table contains Annotations */ bool fp_TableContainer::containsAnnotations(void) { fp_Container * pCon = getFirstContainer(); if(isThisBroken()) { pCon = getMasterTable()->getFirstContainer(); } bool bFound = false; while(pCon && !bFound) { if(pCon->getContainerType() == FP_CONTAINER_CELL) { fp_CellContainer * pCell = static_cast(pCon); if(pCell->containsAnnotations()) { if(isThisBroken()) { // // If broken check to see if the container containing the footnote reference // is on screen. // fp_Container * pCellCon = pCell->getFirstContainer(); while(pCellCon && !bFound) { if(isInBrokenTable(pCell,pCellCon)) { if(pCellCon->getContainerType() == FP_CONTAINER_LINE) { fp_Line * pLine = static_cast(pCellCon); if(pLine->containsFootnoteReference()) { bFound = true; } } else if(pCellCon->getContainerType() == FP_CONTAINER_TABLE) { fp_TableContainer *pTab = static_cast(pCellCon); if(pTab->containsFootnoteReference()) { bFound = true; } } } pCellCon = static_cast(pCellCon->getNext()); } } else { bFound = true; } } } else if(pCon->getContainerType() == FP_CONTAINER_TABLE) { fp_TableContainer *pTab = static_cast(pCon); bFound = pTab->containsAnnotations(); } pCon = static_cast(pCon->getNext()); } return bFound; } /*! * This method returns a vector of call the Annotation layouts in this table */ bool fp_TableContainer::getAnnotationContainers(UT_GenericVector* pVecAnns) { fp_Container * pCon = getFirstContainer(); if(isThisBroken()) { pCon = getMasterTable()->getFirstContainer(); } bool bFound = false; while(pCon) { if(pCon->getContainerType() == FP_CONTAINER_CELL) { fp_CellContainer * pCell = static_cast(pCon); if(pCell->containsAnnotations()) { if(isThisBroken()) { // // If broken check to see if the container containing the footnote reference // is on screen. // fp_Container * pCellCon = pCell->getFirstContainer(); while(pCellCon) { if(isInBrokenTable(pCell,pCellCon)) { if(pCellCon->getContainerType() == FP_CONTAINER_LINE) { fp_Line * pLine = static_cast(pCellCon); if(pLine->containsAnnotations()) { bFound = true; UT_GenericVector vecAC; pLine->getAnnotationContainers(&vecAC); UT_sint32 i =0; for(i=0; i< vecAC.getItemCount();i++) { pVecAnns->addItem(vecAC.getNthItem(i)); } } } else if(pCellCon->getContainerType() == FP_CONTAINER_TABLE) { fp_TableContainer *pTab = static_cast(pCellCon); if(pTab->containsAnnotations()) { bFound = true; UT_GenericVector vecAC; pTab->getAnnotationContainers(&vecAC); UT_sint32 i =0; for(i=0; i< vecAC.getItemCount();i++) { pVecAnns->addItem(vecAC.getNthItem(i)); } } } } pCellCon = static_cast(pCellCon->getNext()); } } else { UT_GenericVector vecAC; pCell->getAnnotationContainers(&vecAC); UT_sint32 i =0; for(i=0; i< vecAC.getItemCount();i++) { pVecAnns->addItem(vecAC.getNthItem(i)); } bFound = true; } } } else if(pCon->getContainerType() == FP_CONTAINER_TABLE) { fp_TableContainer *pTab = static_cast(pCon); bFound = pTab->containsAnnotations(); if(bFound) { UT_GenericVector vecAC; pTab->getAnnotationContainers(&vecAC); UT_sint32 i =0; for(i=0; i< vecAC.getItemCount();i++) { pVecAnns->addItem(vecAC.getNthItem(i)); } } } pCon = static_cast(pCon->getNext()); } return bFound; } /*! * Return true if the supplied Cell and it's container are within this * broken container. */ bool fp_TableContainer::isInBrokenTable(fp_CellContainer * pCell, fp_Container * pCon) { // // OK A container in a cell is allowed in this broken table if it's // Y location plus height lie between getYBreak() and getYBottom. // // If the container starts within the table but it's height is not // contained in the table it is not allowed in here unless it is the only // container in the cell in the table. If this the case the rest of the // drawing code in AbiWord will have to clip it on the bottom. // // We don't assume that this is the top level table // // // Short circuit things if the BrokenContainer pointer is set. // xxx_UT_DEBUGMSG(("isInBrokenTable %p pcell %p line %p\n",this,pCell,pCon)); #if 1 if(pCon->getMyBrokenContainer() == static_cast(this)) { xxx_UT_DEBUGMSG(("Already set to this %p\n",this)); return true; } if(pCon->getMyBrokenContainer() != NULL) { xxx_UT_DEBUGMSG(("Already set to other %p\n",pCon->getMyBrokenContainer() )); return false; } #endif UT_sint32 iTop = 0; iTop = pCell->getY() + pCon->getY(); UT_sint32 iHeight = pCon->getHeight(); if(!getContainer()) { UT_DEBUGMSG(("This broken table has NO container ! %p \n",this)); } if(pCon->getContainerType() == FP_CONTAINER_TABLE) { fp_TableContainer * ppTab = static_cast(pCon); xxx_UT_DEBUGMSG(("Nested table Y %d height %d yBottom %d contained in broken table height %d \n",ppTab->getY(),ppTab->getHeight(),ppTab->getYBottom(),getHeight())); ppTab = static_cast(ppTab->getNext()); if(ppTab) { xxx_UT_DEBUGMSG(("Next table yBreak %d \n",ppTab->getYBreak())); } iHeight = static_cast(pCon)->getHeight(); } UT_sint32 iBot = iTop + iHeight; UT_sint32 iBreak = getYBreak(); UT_sint32 iBottom = getYBottom(); xxx_UT_DEBUGMSG(("Column %p iTop = %d ybreak %d iBot= %d ybottom= %d \n",getBrokenColumn(),iTop,iBreak,iBot,iBottom)); // // When breaking a nested table, it is possible that the pieces don't // quite fit into the containing broken table. This "Delta" allows // a degree of sloppiness to find the correct matching broken table // for a broken nested table. // UT_sint32 iDelta = 0; if(pCon->getContainerType() == FP_CONTAINER_TABLE) { iDelta = iBot * 0.03; } if((iBot >= (iBreak - iDelta)) && (iTop >= (iBreak - iDelta))) { if(iBot < (iBottom+iDelta) ) { // pCon->setMyBrokenContainer(this); return true; } } return false; } /*! * Draw that segment of the table that fits within the Y offsets of this * Broken table. */ void fp_TableContainer::_brokenDraw(dg_DrawArgs* pDA) { bool bIsNested = false; UT_sint32 iMyY = 0; fp_TableContainer *pMaster = getMasterTable(); UT_sint32 iCount = 0; fp_TableContainer * pPrev = this; while(pPrev != NULL) { iCount++; pPrev = static_cast(pPrev->getPrev()); } xxx_UT_DEBUGMSG(("Drawing %d table in broken chain yoff %ld \n",iCount,pDA->yoff)); if(iCount > 0) { xxx_UT_DEBUGMSG(("Draw the repeated Row here \n")); } if(getContainer()->getContainerType() == FP_CONTAINER_CELL) { xxx_UT_DEBUGMSG(("Draw broken nested Table - 0 %x yBreak %d \n",this,getYBreak())); bIsNested = true; if(getYBreak() > 0) { iMyY = getY(); } } fp_CellContainer * pCell = static_cast(getMasterTable()->getNthCon(0)); xxx_UT_DEBUGMSG(("SEVIOR: _brokenDraw table %x getYBreak %d getYBottom %d \n",this, getYBreak(),getYBottom())); xxx_UT_DEBUGMSG(("SEVIOR: _brokenDraw table Initial Y-offset %d \n",pDA->yoff)); UT_sint32 iCountCells = 0; const UT_Rect * pClipRect = pDA->pG->getClipRect(); fp_TableContainer * pBroke = const_cast(this); bool bDirtyOnly = pDA->bDirtyRunsOnly; if(m_pFirstBrokenCell) { pCell = m_pFirstBrokenCell; xxx_UT_DEBUGMSG(("Doing FirstBrokenCell Starting at cell %p \n",pCell)); while(pCell) { xxx_UT_DEBUGMSG(("Look at Cell %x isdirty %d \n",pCell,pCell->isDirty())); if(pCell->containsNestedTables()) { xxx_UT_DEBUGMSG(("SEVIOR: 2 Cell Contains nested tables cell %x cellY %d cellHeight %d YBreak %d yBottom %d \n",pCell,pCell->getY(), pCell->getHeight(), getYBreak(),getYBottom())); } dg_DrawArgs da = *pDA; if(!bIsNested) { da.yoff = da.yoff - getYBreak(); xxx_UT_DEBUGMSG((" -1- Not Nested yoff %ld \n",da.yoff)); } if(bDirtyOnly) { if(pCell->containsNestedTables()) { xxx_UT_DEBUGMSG(("da dirty only, pCell->isDirty %d needsredraw %d \n",pCell->isDirty(), pCell->getSectionLayout()->needsRedraw())); } if(pCell->isDirty() || pCell->getSectionLayout()->needsRedraw()) { pCell->drawBroken(&da, this); iCountCells++; } } else { if(pClipRect) { if(pCell->doesIntersectClip(pBroke,pClipRect)) { pCell->drawBroken(&da, this); iCountCells++; } } else { pCell->drawBroken(&da, this); iCountCells++; } } if(pCell != m_pLastBrokenCell) { pCell = static_cast(pCell->getNext()); } else { pCell = NULL; } } } else { UT_DEBUGMSG(("Not doing FirstBrokenCell \n")); while(pCell) { UT_sint32 botY = 0; if(pCell->containsNestedTables()) { xxx_UT_DEBUGMSG(("SEVIOR: 1 Cell Contains nested tables cell %x cellY %d cellHeight %d YBreak %d yBottom %d \n",pCell,pCell->getY(), pCell->getHeight(), getYBreak(),getYBottom())); } if(pCell->getBottomAttach() < pMaster->getNumRows()) { botY = pMaster->getYOfRow(pCell->getBottomAttach()); } else { fp_VerticalContainer * pVert = static_cast(pMaster); botY = pMaster->getYOfRow(0) + pVert->getHeight(); botY -= 2 * pMaster->getBorderWidth(); botY += pMaster->getNthRow(pMaster->getNumRows()-1)->spacing/2; } if(pCell->getY() > getYBottom()) { xxx_UT_DEBUGMSG(("SEVIOR: _drawBroken skipping cell %x cellY %d cellHeight %d YBreak %d yBottom %d \n",pCell,pCell->getY(), pCell->getHeight(), getYBreak(),getYBottom())); break; pCell = static_cast(pCell->getNext()); } else { dg_DrawArgs da = *pDA; if(pCell->containsNestedTables()) { xxx_UT_DEBUGMSG(("SEVIOR: drawing cell with nested tables yoff %d cellY %d cellHeight %d YBreak %d yBottom %d \n",da.yoff,pCell->getY(), pCell->getHeight(), getYBreak(),getYBottom())); // // Doing this fixes the overflow onto next page // for nest spanning 2 pages but not 3 page da.yoff = da.yoff + getYBreak(); } da.yoff = da.yoff - getYBreak(); iCountCells++; xxx_UT_DEBUGMSG((" -2- da.yoff set to %d \n",da.yoff)); pCell->drawBroken(&da, this); if(m_pFirstBrokenCell == NULL) { m_pFirstBrokenCell = pCell; } m_pLastBrokenCell = pCell; pCell = static_cast(pCell->getNext()); } } } xxx_UT_DEBUGMSG(("_brokenDraw: Draw %d cells \n",iCountCells)); _drawBrokenBoundaries(pDA); fl_TableLayout * pTL = static_cast(getSectionLayout()); pTL->clearNeedsRedraw(); } void fp_TableContainer::_drawBrokenBoundaries(dg_DrawArgs* pDA) { UT_ASSERT(getPage()); if(!pDA->pG->queryProperties(GR_Graphics::DGP_SCREEN)) { return; } if(getPage() == NULL) { return; } if(getPage()->getDocLayout()->getView() == NULL) { return; } if(getPage()->getDocLayout()->getView()->getShowPara() && getGraphics()->queryProperties(GR_Graphics::DGP_SCREEN)){ UT_sint32 xoffBegin = pDA->xoff + getX(); UT_sint32 yoffBegin = pDA->yoff; UT_sint32 xoffEnd = pDA->xoff + getX() + getWidth() - getGraphics()->tlu(1); UT_sint32 yoffEnd = pDA->yoff + getHeight() - getGraphics()->tlu(1); UT_RGBColor clrShowPara(127,127,127); getGraphics()->setColor(clrShowPara); xxx_UT_DEBUGMSG(("SEVIOR: Table Top (getY()) = %d \n",getY())); xxx_UT_DEBUGMSG(("SEVIOR: Table boundaries xleft %d xright %d ytop %d ybot %d \n",xoffBegin,xoffEnd,yoffBegin,yoffEnd)); GR_Painter painter (getGraphics()); painter.drawLine(xoffBegin, yoffBegin, xoffEnd, yoffBegin); painter.drawLine(xoffBegin, yoffEnd, xoffEnd, yoffEnd); painter.drawLine(xoffBegin, yoffBegin, xoffBegin, yoffEnd); painter.drawLine(xoffEnd, yoffBegin, xoffEnd, yoffEnd); } } void fp_TableContainer::_size_request_pass2(void) { UT_sint32 max_width; UT_sint32 col; if (m_bIsHomogeneous) { max_width = 0; m_iCols = m_vecColumns.getItemCount(); for (col = 0; col < m_iCols; col++) { max_width = UT_MAX (max_width, getNthCol(col)->requisition); } for (col = 0; col < m_iCols; col++) { getNthCol(col)->requisition = max_width; } // // Don't want homogeneous in height // #if 0 UT_sint32 max_height = 0; UT_sint32 row = 0; for (row = 0; row < m_iRows; row++) { max_height = UT_MAX (max_height, getNthRow(row)->requisition); } for (row = 0; row < m_iRows; row++) { getNthRow(row)->requisition = max_height; } #endif } } void fp_TableContainer::_size_request_pass3(void) { fp_CellContainer *child; UT_sint32 width, height; UT_sint32 row, col; UT_sint32 extra; child = static_cast(getNthCon(0)); while (child) { /* Child spans multiple columns. */ if (child->getLeftAttach() != (child->getRightAttach() - 1)) { fp_Requisition child_requisition; child->sizeRequest(&child_requisition); /* Check and see if there is already enough space * for the child. */ width = 0; for (col = child->getLeftAttach(); col < child->getRightAttach(); col++) { width += getNthCol(col)->requisition; if ((col + 1) < child->getRightAttach()) { width += getNthCol(col)->spacing; } } /* If we need to request more space for this child to fill * its requisition, then divide up the needed space evenly * amongst the columns it spans. */ if (width < child_requisition.width + child->getLeftPad() + child->getRightPad()) { width = child_requisition.width + child->getLeftPad() + child->getRightPad(); for (col = child->getLeftAttach(); col < child->getRightAttach(); col++) { extra = width / (child->getRightAttach() - col); getNthCol(col)->requisition += extra; width -= extra; } } } /* Child spans multiple rows. */ if (child->getTopAttach() != (child->getBottomAttach() - 1)) { fp_Requisition child_requisition; child->sizeRequest(&child_requisition); /* Check and see if there is already enough space * for the child. */ height = 0; for (row = child->getTopAttach(); row < child->getBottomAttach(); row++) { height += getNthRow(row)->requisition; if ((row + 1) < child->getBottomAttach()) height += getNthRow(row)->spacing; } /* If we need to request more space for this child to fill * its requisition, then divide up the needed space evenly * amongst the columns it spans. */ if (height < child_requisition.height + child->getTopPad() + child->getBotPad()) { height = child_requisition.height + child->getTopPad() + child->getBotPad() - height; for (row = child->getTopAttach(); row < child->getBottomAttach(); row++) { extra = height / (child->getBottomAttach() - row); getNthRow(row)->requisition += extra; height -= extra; } } } child = static_cast(child->getNext()); } } void fp_TableContainer::_size_allocate_init(void) { fp_CellContainer * child; UT_sint32 row, col; UT_sint32 has_expand; UT_sint32 has_shrink; /* Initialize the rows and cols. * By default, rows and cols do not expand and do shrink. * Those values are modified by the children that occupy * the rows and cols. */ m_iCols = m_vecColumns.getItemCount(); for (col = 0; col < m_iCols; col++) { fp_TableRowColumn *pCol= getNthCol(col); pCol->allocation = pCol->requisition; pCol->need_expand = false; pCol->need_shrink = true; pCol->expand = false; pCol->shrink = true; pCol->empty = true; } for (row = 0; row < m_iRows; row++) { fp_TableRowColumn * pRow = getNthRow(row); pRow->allocation = pRow->requisition; pRow->need_expand = false; pRow->need_shrink = true; pRow->expand = false; pRow->shrink = true; pRow->empty = true; } /* Loop over all the children and adjust the row and col values * based on whether the children want to be allowed to expand * or shrink. This loop handles children that occupy a single * row or column. */ child = static_cast(getNthCon(0)); while (child) { if (child->getLeftAttach() == (child->getRightAttach() - 1)) { if (child->getXexpand()) { getNthCol(child->getLeftAttach())->expand = true; } if (!child->getXshrink()) { getNthCol(child->getLeftAttach())->shrink = false; } getNthCol(child->getLeftAttach())->empty = false; } if (child->getTopAttach() == (child->getBottomAttach() - 1)) { if (child->getYshrink()) { getNthRow(child->getTopAttach())->expand = true; } if (!child->getYshrink()) { getNthRow(child->getTopAttach())->shrink = false; } getNthRow(child->getTopAttach())->empty = false; } child = static_cast(child->getNext()); } /* Loop over all the children again and this time handle children * which span multiple rows or columns. */ child = static_cast(getNthCon(0)); while (child) { if (child->getLeftAttach() != (child->getRightAttach() - 1)) { for (col = child->getLeftAttach(); col < child->getRightAttach(); col++) { getNthCol(col)->empty = false; } if (child->getXexpand()) { has_expand = false; for (col = child->getLeftAttach(); col < child->getRightAttach(); col++) { if (getNthCol(col)->expand) { has_expand = true; break; } } if (!has_expand) { for (col = child->getLeftAttach(); col < child->getRightAttach(); col++) { getNthCol(col)->need_expand = true; } } } if (!child->getXshrink()) { has_shrink = true; for (col = child->getLeftAttach(); col < child->getRightAttach(); col++) { if (!getNthCol(col)->shrink) { has_shrink = false; break; } } if (has_shrink) { for (col = child->getLeftAttach(); col < child->getRightAttach(); col++) { getNthCol(col)->need_shrink = false; } } } if (child->getTopAttach() != (child->getBottomAttach() - 1)) { for (row = child->getTopAttach(); row < child->getBottomAttach(); row++) { getNthRow(row)->empty = false; } if (child->getYexpand()) { has_expand = false; for (row = child->getTopAttach(); row < child->getBottomAttach(); row++) { if (getNthRow(row)->expand) { has_expand = true; break; } } if (!has_expand) { for (row = child->getTopAttach(); row < child->getBottomAttach(); row++) { getNthRow(row)->need_expand = true; } } } if (!child->getYshrink()) { has_shrink = true; for (row = child->getTopAttach(); row < child->getBottomAttach(); row++) { if (!getNthRow(row)->shrink) { has_shrink = false; break; } } if (has_shrink) { for (row = child->getTopAttach(); row < child->getBottomAttach(); row++) { getNthRow(row)->need_shrink = false; } } } } } child = static_cast(child->getNext()); } /* Loop over the columns and set the expand and shrink values * if the column can be expanded or shrunk. */ m_iCols = m_vecColumns.getItemCount(); for (col = 0; col < m_iCols; col++) { fp_TableRowColumn *pCol= getNthCol(col); if (pCol->empty) { pCol->expand = false; pCol->shrink = false; } else { if (pCol->need_expand) { pCol->expand = true; } if (!pCol->need_shrink) { pCol->shrink = false; } } } /* Loop over the rows and set the expand and shrink values * if the row can be expanded or shrunk. */ for (row = 0; row < m_iRows; row++) { fp_TableRowColumn * pRow = getNthRow(row); if (pRow->empty) { pRow->expand = false; pRow->shrink = false; } else { if (pRow->need_expand) { pRow->expand = true; } if (!pRow->need_shrink) { pRow->shrink = false; } } } } void fp_TableContainer::_size_allocate_pass1(void) { UT_sint32 real_width; UT_sint32 real_height; UT_sint32 width, height; UT_sint32 row, col; UT_sint32 nexpand; UT_sint32 nshrink; UT_sint32 extra; /* If we were allocated more space than we requested * then we have to expand any expandable rows and columns * to fill in the extra space. */ real_width = m_MyAllocation.width - m_iBorderWidth * 2; double dHeight = static_cast(m_MyAllocation.height); double dBorder = static_cast(m_iBorderWidth); real_height = static_cast (dHeight - dBorder * 2.0); // real_height = m_MyAllocation.height; if (m_bIsHomogeneous) { nexpand = 0; m_iCols = m_vecColumns.getItemCount(); for (col = 0; col < m_iCols; col++) { if (getNthCol(col)->expand) { nexpand += 1; break; } } if (nexpand > 0) { width = real_width; for (col = 0; col + 1 < m_iCols; col++) { width -= getNthCol(col)->spacing; } for (col = 0; col < m_iCols; col++) { extra = width / (m_iCols - col); getNthCol(col)->allocation = UT_MAX (1, extra); width -= extra; } } } else { width = 0; nexpand = 0; nshrink = 0; m_iCols = m_vecColumns.getItemCount(); for (col = 0; col < m_iCols; col++) { width += getNthCol(col)->requisition; if (getNthCol(col)->expand) { nexpand += 1; } if (getNthCol(col)->shrink) { nshrink += 1; } } for (col = 0; col + 1 < m_iCols; col++) { width += getNthCol(col)->spacing; } /* Check to see if we were allocated more width than we requested. */ if ((width < real_width) && (nexpand >= 1)) { width = real_width - width; for (col = 0; col < m_iCols; col++) { if (getNthCol(col)->expand) { extra = width / nexpand; getNthCol(col)->allocation += extra; width -= extra; nexpand -= 1; } } } /* Check to see if we were allocated less width than we requested, * then shrink until we fit the size give. */ if (width > real_width) { UT_sint32 total_nshrink = nshrink; extra = width - real_width; while (total_nshrink > 0 && extra > 0) { nshrink = total_nshrink; m_iCols = m_vecColumns.getItemCount(); for (col = 0; col < m_iCols; col++) { fp_TableRowColumn *pCol= getNthCol(col); if (pCol->shrink) { UT_sint32 allocation = pCol->allocation; pCol->allocation = UT_MAX (1, static_cast(pCol->allocation) - extra / nshrink); extra -= allocation - pCol->allocation; nshrink -= 1; if (pCol->allocation < 2) { total_nshrink -= 1; pCol->shrink = false; } } } } } } // // Don't want homogenous in height // if (m_bIsHomogeneous && false) { nexpand = 0; for (row = 0; row < m_iRows; row++) { if (getNthRow(row)->expand) { nexpand += 1; break; } } if (nexpand > 0) { height = real_height; for (row = 0; row + 1 < m_iRows; row++) { height -= getNthRow(row)->spacing; } for (row = 0; row < m_iRows; row++) { extra = height / (m_iRows - row); getNthRow(row)->allocation = UT_MAX (1, extra); height -= extra; } } } else { height = 0; nexpand = 0; nshrink = 0; for (row = 0; row < m_iRows; row++) { height += getNthRow(row)->requisition; if (getNthRow(row)->expand) { nexpand += 1; } if (getNthRow(row)->shrink) { nshrink += 1; } } for (row = 0; row + 1 < m_iRows; row++) { height += getNthRow(row)->spacing; } /* Check to see if we were allocated more height than we requested. */ if ((height < real_height) && (nexpand >= 1)) { height = real_height - height; for (row = 0; row < m_iRows; row++) { if (getNthRow(row)->expand) { extra = height / nexpand; getNthRow(row)->allocation += extra; height -= extra; nexpand -= 1; } } } /* Check to see if we were allocated less height than we requested. * then shrink until we fit the size give. */ if (height > real_height) { UT_sint32 total_nshrink = nshrink; extra = height - real_height; while (total_nshrink > 0 && extra > 0) { nshrink = total_nshrink; for (row = 0; row < m_iRows; row++) { fp_TableRowColumn * pRow = getNthRow(row); if (pRow->shrink) { UT_sint32 allocation = pRow->allocation; pRow->allocation = UT_MAX (1, static_cast(pRow->allocation) - extra / nshrink); extra -= allocation - pRow->allocation; nshrink -= 1; if (pRow->allocation < 2) { total_nshrink -= 1; pRow->shrink = false; } } } } } } } void fp_TableContainer::_size_allocate_pass2(void) { fp_CellContainer *child; UT_sint32 max_width; UT_sint32 max_height; UT_sint32 x, y; UT_sint32 row, col; fp_Allocation allocation; fl_TableLayout * pTL = static_cast(getSectionLayout()); const UT_GenericVector * pVecColProps = pTL->getVecColProps(); if(pVecColProps->getItemCount() > 0) { for (col = 0; (col < pVecColProps->getItemCount()) && (col getNthItem(col); getNthCol(col)->allocation = pColProp->m_iColWidth - getNthCol(col)->spacing; if(col == (getNumCols() - 1) ) { getNthCol(col)->allocation += 2 * getNthCol(col)->spacing; } xxx_UT_DEBUGMSG(("Sevior: table %x column %d set to width %d spacing %d pColProp width %d \n",this,col,getNthCol(col)->allocation,getNthCol(col)->spacing,pColProp->m_iColWidth)); } } m_MyAllocation.x = pTL->getLeftColPos() - m_iBorderWidth; child = static_cast(getNthCon(0)); double dBorder = static_cast(m_iBorderWidth); while (child) { fp_Requisition child_requisition; child->sizeRequest(&child_requisition); x = m_MyAllocation.x + m_iBorderWidth; double dy = static_cast(m_MyAllocation.y); xxx_UT_DEBUGMSG(("SEVIOR: Vertical border %f \n", dBorder)); y = static_cast (dy + dBorder); xxx_UT_DEBUGMSG(("SEVIOR: 1 initial y %d for top-attach %d \n",y,child->getTopAttach())); max_width = 0; max_height = 0; for (col = 0; col < child->getLeftAttach(); col++) { x += getNthCol(col)->allocation; x += getNthCol(col)->spacing; } for (col = child->getLeftAttach(); col < child->getRightAttach(); col++) { max_width += getNthCol(col)->allocation; if ((col + 1) < child->getRightAttach()) { max_width += getNthCol(col)->spacing; } } for (row = 0; row < child->getTopAttach(); row++) { fp_TableRowColumn * pRow = getNthRow(row); UT_continue_if_fail(pRow); UT_sint32 iOldAlloc = pRow->allocation; UT_sint32 iNewAlloc = getRowHeight(row,iOldAlloc); if(iNewAlloc > iOldAlloc) { iNewAlloc -= pRow->spacing; } pRow->allocation = iNewAlloc; y += pRow->allocation; y += pRow->spacing; xxx_UT_DEBUGMSG(("SEVIOR: Adding Height %d spacing is %d \n", getNthRow(row)->allocation,getNthRow(row)->spacing)); } xxx_UT_DEBUGMSG(("SEVIOR: 2 next y %d for top-attach %d \n",y,child->getTopAttach())); for (row = child->getTopAttach(); row < child->getBottomAttach(); row++) { max_height += getNthRow(row)->allocation; if ((row + 1) < child->getBottomAttach()) { max_height += getNthRow(row)->spacing; } } if (child->getXfill()) { allocation.width = UT_MAX (1, max_width - static_cast(child->getLeftPad()) - child->getRightPad()); allocation.x = x + (max_width - allocation.width) / 2; } else { allocation.width = child_requisition.width; allocation.x = x + (max_width - allocation.width) / 2; } // fixme sevior look here!!! if (child->getYfill()) { allocation.height = UT_MAX (1, max_height - static_cast(child->getTopPad()) - child->getBotPad()); allocation.y = y; } else { allocation.height = child_requisition.height; allocation.y = y; xxx_UT_DEBUGMSG(("SEVIOR: top attach %d height %d y %d \n",child->getTopAttach(),allocation.height,allocation.y)); } xxx_UT_DEBUGMSG(("SEVIOR!!!!!!: max_height = %d width =%d \n",max_height,allocation.width)); child->sizeAllocate( &allocation); child = static_cast(child->getNext()); } } fp_TableRowColumn * fp_TableContainer::getNthCol(UT_sint32 i) { UT_ASSERT(i < m_vecColumns.getItemCount()); return m_vecColumns.getNthItem(i); } fp_TableRowColumn * fp_TableContainer::getNthRow(UT_sint32 i) { UT_ASSERT(i < m_vecRows.getItemCount()); return m_vecRows.getNthItem(i); } void fp_TableContainer::sizeRequest(fp_Requisition * pRequisition) { UT_sint32 row, col; pRequisition->width = 0; pRequisition->height = 0; bool bDefinedColWidth = false; fl_TableLayout * pTL = static_cast(getSectionLayout()); const UT_GenericVector * pVecColProps = pTL->getVecColProps(); if(pVecColProps->getItemCount() > 0) { bDefinedColWidth = true; } _size_request_init (); _size_request_pass1 (); _size_request_pass2 (); _size_request_pass3 (); _size_request_pass2 (); m_iCols = m_vecColumns.getItemCount(); for (col = 0; col < m_iCols; col++) { if(bDefinedColWidth && (col < pVecColProps->getItemCount()) ) { fl_ColProps * pColProp = pVecColProps->getNthItem(col); getNthCol(col)->requisition = pColProp->m_iColWidth; } pRequisition->width += getNthCol(col)->requisition; } for (col = 0; col + 1 < m_iCols; col++) { pRequisition->width += getNthCol(col)->spacing; } // for (row = 0; row + 1 < m_iRows; row++) for (row = 0; row < m_iRows; row++) { fp_TableRowColumn * pRow = getNthRow(row); UT_sint32 iOldReq = pRow->requisition; UT_sint32 iNewReq = getRowHeight(row,iOldReq); if(iNewReq > iOldReq) { iNewReq -= pRow->spacing; } pRow->requisition = iNewReq; pRequisition->height += pRow->spacing; xxx_UT_DEBUGMSG(("SEVIOR: requisition spacing 2 is %d \n", getNthRow(row)->spacing)); xxx_UT_DEBUGMSG(("SEVIOR: requisition height 2 is %d \n", pRequisition->height)); } for (row = 0; row < m_iRows; row++) { pRequisition->height += getNthRow(row)->requisition; xxx_UT_DEBUGMSG(("SEVIOR: requisition height %d \n", pRequisition->height)); } pRequisition->height += 2 * m_iBorderWidth; } void fp_TableContainer::sizeAllocate(fp_Allocation * pAllocation) { m_MyAllocation.width = pAllocation->width; m_MyAllocation.height = pAllocation->height; m_MyAllocation.x = pAllocation->x; m_MyAllocation.y = pAllocation->y; m_MyAllocation.y = 0; xxx_UT_DEBUGMSG(("SEVIOR: Initial allocation height is %d \n", pAllocation->height)); _size_allocate_init (); xxx_UT_DEBUGMSG(("SEVIOR: Initial allocation height 1 is %d \n", m_MyAllocation.height)); _size_allocate_pass1 (); xxx_UT_DEBUGMSG(("SEVIOR: Initial allocation height 2 is %d \n", m_MyAllocation.height)); _size_allocate_pass2 (); xxx_UT_DEBUGMSG(("SEVIOR: Initial allocation height 3 is %d \n", m_MyAllocation.height)); // fp_Requisition pReq; // sizeRequest(&pReq); // m_MyAllocation.height = pReq.height; }