/* -*- 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/. */ #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(true), m_bDrawTop(false), m_bDrawBot(true), m_bDrawRight(false), m_bLinesDrawn(false), m_bBgDirty(true), m_bIsSelected(false), m_bDirty(true), m_bIsRepeated(false), m_bDefaultLines(true) { } /*! 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) { UT_DEBUGMSG(("cell: Height was %d new height %d \n",getCellHeight(),iHeight)); if ((iHeight == getCellHeight()) || (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",getCellHeight())); 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 complete cell * and the broken table. * If the height or width is negative, the cell is not in the broken table. */ void fp_CellContainer::_getBrokenRectCell(fp_TableContainer * pBroke, fp_Page * &pPage, UT_Rect &bRec, GR_Graphics * pG) { _getBrokenRect(pBroke, pPage, bRec,pG); UT_sint32 xdiff = getX() - getCellX(); UT_sint32 ydiff = getY() - getCellY(); UT_sint32 iLeft,iRight,iTop,iBot = 0; UT_sint32 col_y = 0; fp_Column * pCol = NULL; fp_ShadowContainer * pShadow = NULL; bool bDoClear = true; // // Set height from actual draw positions // bRec.height = -1; getScreenPositions(pBroke,pG,iLeft,iRight,iTop,iBot,col_y,pCol,pShadow,bDoClear ); if(pBroke != NULL) { if(m_iBotY < pBroke->getYBreak()) { // // Cell is above this page return with height == -1 // return; } if(m_iTopY > pBroke->getYBottom()) { // // Cell is below this page return with height == -1 // return; } iTop -= pBroke->getYBreak(); iBot -= pBroke->getYBreak(); //Check if the upper row is present in this broken table. UT_sint32 iPrevRow = UT_MAX(getTopAttach() - 1,0); fp_TableContainer * pTab = static_cast(getContainer()); UT_sint32 iPrevY = pTab->getYOfRow(iPrevRow); xxx_UT_DEBUGMSG(("ADITYA: iprevy=%d, ybreak=%d\n", iPrevY, pBroke->getYBreak())); if(iTop < col_y) { iTop = col_y; } UT_sint32 iColHeight = 0; if(pCol) { iColHeight = pCol->getHeight(); } else if(pShadow) { iColHeight = pShadow->getHeight(); } if(iBot > col_y + iColHeight) { iBot = col_y + iColHeight; } } UT_sint32 wdiff = getCellWidth() - getWidth(); UT_sint32 hdiff = getCellHeight() - getHeight(); bRec.left -= xdiff; bRec.top = iTop; bRec.width += wdiff; bRec.height += (iBot-iTop); } /*! * Return the screen rectangle that is the intersection of the drawable part 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(); UT_sint32 iycon = pCon->getY(); if(pCon->getContainerType() == FP_CONTAINER_CELL) { offx += static_cast(pCon)->getX(); iycon = static_cast(pCon)->getY(); iPrevCellY = iycon; } else { offx += pCon->getX(); } offy += iycon; // this is not quite finished for nested tables! 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(); 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) { UT_DEBUGMSG(("No lines drawn - leaving cell clearscreen \n")); 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((getCellY() >= pBroke->getYBreak() && getCellY() < pBroke->getYBottom()) || ( (getCellY()+getSpannedHeight()) >= pBroke->getYBreak() && (getCellY() < 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 = getCellY(); UT_sint32 iBot2 = iTop + getCellHeight(); 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()) - getCellY(); } else { fp_CellContainer * pCell = pTab->getCellAtRowColumn(pTab->getNumRows() -1,0); fp_CellContainer * pMaxH = pCell; if(pMaxH == NULL) { return 0; } while(pCell) { if(pCell->getCellHeight() > pMaxH->getCellHeight()) { pMaxH = pCell; } pCell = static_cast(pCell->getNext()); } height = pMaxH->getCellY() - getCellY() + pMaxH->getCellHeight(); } 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) { UT_DEBUGMSG((" No broken table. Aborting clearscreen \n")); return; } if(pBroke->getPage() && !pBroke->getPage()->isOnScreen()) { UT_DEBUGMSG((" cell not on screen. Aborting clearscreen \n")); 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; _getBrokenRectCell(pBroke, pPage, bRec,getGraphics()); if((bRec.top + bRec.height) < 0) { UT_DEBUGMSG(("--+top+height -ve abort clear = %d \n",bRec.top+bRec.height)); return; } if(bRec.height < 0) { UT_DEBUGMSG(("--height -ve abort clear = %d \n",bRec.height)); return; } markAsDirty(); if (pPage != NULL) { GR_Graphics * pG = getGraphics(); GR_Painter Paint(pG); UT_Rect cRec; UT_DEBUGMSG(("_clear: top %d bot %d cell left attach %d top attach %d \n",bRec.top,bRec.top+bRec.height,m_iLeftAttach,m_iTopAttach)); _getCoveringRect(lineLeft,bRec.left,bRec.top,bRec.left,bRec.top + bRec.height,pG,cRec); Paint.clearArea(cRec.left, cRec.top, cRec.width,cRec.height); _getCoveringRect(lineTop,bRec.left,bRec.top,bRec.left+bRec.width,bRec.top,pG,cRec); Paint.clearArea(cRec.left, cRec.top, cRec.width,cRec.height); _getCoveringRect(lineRight,bRec.left+bRec.width,bRec.top,bRec.left+bRec.width,bRec.top + bRec.height,pG,cRec); Paint.clearArea(cRec.left, cRec.top, cRec.width,cRec.height); xxx_UT_DEBUGMSG(("_Clear: pBroke %x \n",pBroke)); _getCoveringRect(lineBottom,bRec.left,bRec.top + bRec.height,bRec.left+bRec.width,bRec.top + bRec.height,pG,cRec); Paint.clearArea(cRec.left, cRec.top, cRec.width,cRec.height); 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); const fl_ContainerLayout * pLayout = const_cast(getSectionLayout()->myContainingLayout ()); UT_return_if_fail(pLayout->getContainerType () == FL_CONTAINER_TABLE); const fl_TableLayout * pTableLayout = static_cast(pLayout); UT_uint32 topThickness = getTopStyle (pTableLayout).m_thickness; UT_DEBUGMSG(("Cell Clear screen x %d y %d width %d height %d \n",bRec.left,bRec.top+topThickness,bRec.width,bRec.height-topThickness)); if(getFillType()->getParent()) { srcX += getCellX(); srcY += getCellY(); getFillType()->getParent()->Fill(getGraphics(),srcX,srcY,bRec.left,bRec.top+topThickness,bRec.width,bRec.height-topThickness); } else { getFillType()->Fill(getGraphics(),srcX,srcY,bRec.left,bRec.top+topThickness,bRec.width,bRec.height-topThickness); } 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 = getCellWidth(); if (iWidth == myWidth) { return; } if(iWidth < 2) { iWidth = 2; } clearScreen(); UT_DEBUGMSG(("cellWidth set from %d to %d \n",myWidth,iWidth)); 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); } /*! * Return the rectangle that covers the line given. We can use this to * clear the line, with a clearArea call. */ void fp_CellContainer::_getCoveringRect(const PP_PropertyMap::Line & style, UT_sint32 left, UT_sint32 top, UT_sint32 right, UT_sint32 bot, GR_Graphics * pG, UT_Rect & cRec) { UT_sint32 thck = style.m_thickness; cRec.left = left; cRec.top = top; bool bThinWidth = false; if(right == left) { cRec.width = thck; bThinWidth = true; } else { cRec.width = right - left; } if(top == bot) { cRec.height = thck; } else { cRec.height = bot - top; } // // OK now make sure we have a one pixel cover over cRec // in just the thin dimension // UT_sint32 onepix = pG->tlu(1)+1; if(bThinWidth) { cRec.left = cRec.left - onepix; cRec.width = cRec.width + 2*onepix; cRec.top = cRec.top; cRec.height = cRec.height; } else { cRec.left = cRec.left; cRec.width = cRec.width; cRec.top = cRec.top - onepix; cRec.height = cRec.height + 2*onepix; } } /* 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) { xxx_UT_DEBUGMSG(("Doing drawlines for cell %x \n",this)); UT_return_if_fail(getPage()); bool bDrawTop = m_bDrawTop; bool bDrawBot = m_bDrawBot; bool bDrawRight = m_bDrawRight; bool bDrawLeft = m_bDrawLeft; UT_Rect cRec; // draw top if this cell is on top row of table. fp_TableContainer * pTab2 = static_cast(getContainer()); if(m_bDefaultLines) { bDrawTop = (0 == getTopAttach()); bDrawBot = true; // draw right if this cell is the rightmost of the table bDrawRight = (pTab2->getNumCols() == getRightAttach()); bDrawLeft = true; } 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; } 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 bDoClear = true; getScreenPositions(pBroke,pG,iLeft,iRight,iTop,iBot,col_y,pCol,pShadow,bDoClear ); bDoClear = true; 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)); //Check if the upper row is present in this broken table. UT_sint32 iPrevRow = UT_MAX(getTopAttach() - 1,0); fp_TableContainer * pTab = static_cast(getContainer()); UT_sint32 iPrevY = pTab->getYOfRow(iPrevRow); xxx_UT_DEBUGMSG(("ADITYA: iprevy=%d, ybreak=%d\n", iPrevY, pBroke->getYBreak())); if( iPrevY < pBroke->getYBreak()) { if(m_bDefaultLines) { bDrawTop = true; } } 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; 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; if(m_bDefaultLines) { bDrawBot = true; } if(pBroke != NULL) { pBroke->setBrokenBot(1); } } // // 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); /* * Co-ordinates are adjusted below so that the line is drawn * within the cell, rather than outside it. It is based on the * assumption that the line will be drawn between two points * such that the thickness of the drawing is equally * distributed on either side of the line **/ xxx_UT_DEBUGMSG(("ADITYA: t: %d b: %d r: %d l: %d\n", bDrawTop, bDrawBot, bDrawRight, bDrawLeft)); /* * Lines including thinkness are drawn like this: * |=============| | | | | | | | | |=============| left starts from 0 in y and extends to height right starts from 0 and extends to height top starts from (0+left thickness) and extends to width-rightthickness. bot start from 0+left thickness and extends to (width - right thickness) We draw left and right first, followed by top and bottom Doing things this way ensures we have no gaps at the clears. If we don't draw left we extend top and bottom leftThickness left If we don't draw right we extend top and bottom rightThickness right */ UT_sint32 leftThickness = lineLeft.m_thickness; UT_sint32 rightThickness = lineRight.m_thickness; GR_Painter Paint(pG); if (bDrawLeft) { xxx_UT_DEBUGMSG(("ADITYA: drawing left! (%d,%d),(%d,%d) ", iLeft , iTop, iLeft, iBot)); if(bDoClear) { _getCoveringRect(lineLeft, iLeft, iTop, iLeft, iBot, pG,cRec); Paint.clearArea(cRec.left, cRec.top, cRec.width,cRec.height); } _drawLine(lineLeft, iLeft, iTop, iLeft, iBot, pG); } if(bDrawRight) { xxx_UT_DEBUGMSG(("drawing right! ")); if(bDoClear) { _getCoveringRect(lineRight, iRight, iTop, iRight, iBot, pG,cRec); Paint.clearArea(cRec.left, cRec.top, cRec.width,cRec.height); } _drawLine(lineRight, iRight, iTop, iRight, iBot,pG); } UT_sint32 myLeft = iLeft; UT_sint32 myRight = iRight; if(bDrawLeft || m_bDefaultLines) { myLeft += leftThickness; } if(bDrawRight || m_bDefaultLines) { myRight -= rightThickness; } if(bDrawTop) { xxx_UT_DEBUGMSG(("drawing top! (%d,%d),(%d,%d) ", myLeft, iTop, myRight, iTop)); if(bDoClear) { _getCoveringRect(lineTop,myLeft,iTop,myRight,iTop,pG,cRec); Paint.clearArea(cRec.left, cRec.top, cRec.width,cRec.height); } _drawLine(lineTop, myLeft, iTop,myRight, iTop, pG); } if(bDrawBot) { xxx_UT_DEBUGMSG(("drawing bot! (%d,%d),(%d,%d) \n", myLeft, iBot, myRight, iBot)); if(bDoClear) { _getCoveringRect(lineBottom,myLeft,iBot,myRight,iBot,pG,cRec); Paint.clearArea(cRec.left, cRec.top, cRec.width,cRec.height); } _drawLine(lineBottom, myLeft, iBot, myRight, iBot, pG); } } } /*! * Draw lines around neighbouring cells. Use to fix artifacts of editting. */ void fp_CellContainer::drawLinesAdjacent(fp_TableContainer * pBroke, GR_Graphics * pG) { if(!pG) return; if(!pG->queryProperties(GR_Graphics::DGP_SCREEN)) return; if(!pBroke) return; UT_sint32 row = getTopAttach(); UT_sint32 col_right = getRightAttach(); UT_sint32 col_left = getLeftAttach(); UT_sint32 row_above = getTopAttach()-1; UT_sint32 row_below = getBottomAttach(); 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; } bool bDoTop = false; if(row_above > 0) { bDoTop = true; } bool bDoBot = false; if(row_below < pTab->getNumRows()) { bDoBot = true; } drawLines(pBroke,getGraphics()); if(bDoRight) { fp_CellContainer * pCell = pTab->getCellAtRowColumn(row,col_right); if(pCell) { pCell->drawLines(pBroke,pG); } } if(bDoLeft) { fp_CellContainer * pCell = pTab->getCellAtRowColumn(row,col_left-1); if(pCell) { pCell->drawLines(pBroke,pG); } } if(bDoTop) { fp_CellContainer * pCell = pTab->getCellAtRowColumn(row_above-1,col_left); if(pCell) { pCell->drawLines(pBroke,pG); } } if(bDoBot) { fp_CellContainer * pCell = pTab->getCellAtRowColumn(row_below,col_left); if(pCell) { pCell->drawLines(pBroke,pG); } } } /*! 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 + getCellX(); UT_sint32 yoffBegin = pDA->yoff + getCellY(); UT_sint32 xoffEnd = pDA->xoff + getCellX() + getCellWidth() - getGraphics()->tlu(1); UT_sint32 yoffEnd = pDA->yoff + getCellY() + getCellHeight() - 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 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() <= getCellY()) && (getCellY() <= 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() >= getCellY()) && (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; fp_TableContainer * pTab2 = NULL; bool bIsNested = isInNestedTable(); if(pBroke && pBroke->isThisBroken()) { pTab2 = pBroke->getMasterTable(); } else { pTab2 = static_cast(getContainer()); } 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); if((bRec.height < 0) || (bRec.width < 0)) return; xxx_UT_DEBUGMSG(("ADITYA: t: %d b: %d r: %d l: %d\n", m_bDrawTop, m_bDrawBot, m_bDrawRight, m_bDrawLeft)); 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 %p 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); const fl_ContainerLayout * pCLayout = const_cast(getSectionLayout()->myContainingLayout ()); UT_return_if_fail(pCLayout->getContainerType () == FL_CONTAINER_TABLE); const fl_TableLayout * pTableLayout = static_cast(pCLayout); UT_uint32 topThickness = getTopStyle (pTableLayout).m_thickness; UT_uint32 leftThickness = getLeftStyle (pTableLayout).m_thickness; UT_uint32 rightThickness = getRightStyle (pTableLayout).m_thickness; 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-leftThickness,bRec.height-topThickness); getLeftTopOffsets(srcX,srcY); getFillType()->Fill(pG,srcX,srcY,bRec.left,bRec.top+topThickness,bRec.width-leftThickness,bRec.height-topThickness); 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+leftThickness,bRec.top+topThickness,bRec.width-leftThickness,bRec.height-topThickness); if(getPage()) { getPage()->expandDamageRect(bRec.left,bRec.top,bRec.width,bRec.height); } } fl_ContainerLayout * pLayout = getSectionLayout()->myContainingLayout (); UT_return_if_fail(pLayout->getContainerType () == FL_CONTAINER_TABLE); //form a new drawing region. UT_Rect clip; clip.left = pDA->xoff + getX(); clip.top = pDA->yoff + getY(); clip.width = getWidth()-rightThickness; clip.height = getHeight(); xxx_UT_DEBUGMSG(("\nCLIPRECT: pos topleft (%d, %d), pos botright (%d,%d) dim width = %d ht = %d\n", clip.left, clip.top, clip.left + clip.width, clip.top + clip.height, clip.width, clip.height)); pDA->pG->setClipRect(&clip); // // Only draw the lines in the clipping region. // UT_sint32 iLastDraw = 0; UT_DEBUGMSG(("Container count = %d\n", countCons())); 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) { ydiff = da.yoff + static_cast(pContainer)->getHeight(); } 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 da.yoff %d yBreak %d \n",da.yoff,pTab->getYBreak())); dg_DrawArgs daa = da; daa.yoff -= pTab->getYBreak(); pTab->draw(&daa); iLastDraw = i; } else { fp_TableContainer * pT= pTab->getFirstBrokenTable(); if(pT == NULL) { UT_sint32 iY = pTab->getY(); xxx_UT_DEBUGMSG(("No Broken Table!! \n")); pTab = static_cast(pTab->VBreakAt(0)); pTab->setY(iY); } else { pTab = pT; } if(pTab) { 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(); } //reset the clipping region before drawing the border lines. pDA->pG->setClipRect(pClipRect); drawLines(pBroke,pG); drawLinesAdjacent(pBroke,pG); 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(); xxx_UT_DEBUGMSG(("vBREAK cell at %d \n",vpos)); UT_sint32 i =0; fp_Container * pCon; bool bBreak = false; fp_ContainerObject * 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) { xxx_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) { xxx_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); xxx_UT_DEBUGMSG(("Break Nested table Con %x at 0 y %d height %d \n",pCon,pCon->getY(),pCon->getHeight())); xxx_UT_DEBUGMSG(("Break Nested table Table %x 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. // fp_TableContainer * pPrevTab = static_cast(pCon); fp_TableContainer * pMaster = pPrevTab->getMasterTable(); pBroke = pPrevTab->VBreakAt(vpos - pMaster->getY() - pPrevTab->getYBreak()); pBroke->setY(vpos); static_cast(pBroke)->setY(pBroke->getY()); xxx_UT_DEBUGMSG(("Made broken nested Table %x Y %d height %d \n",pBroke,pBroke->getY(),pBroke->getHeight())); bBreak = true; break; } } } iY += pCon->getHeight(); iY += pCon->getMarginAfter(); } if(bBreak) { //layout(); } return 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() + getCellY(); 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; } /*! * This includes the border thicknesses. This method is used by the * containers held by the cell */ UT_sint32 fp_CellContainer::getX(void) const { UT_sint32 x = fp_VerticalContainer::getX(); const fl_ContainerLayout * pLayout = const_cast(getSectionLayout()->myContainingLayout ()); UT_return_val_if_fail(pLayout->getContainerType () == FL_CONTAINER_TABLE,0); const fl_TableLayout * pTableLayout = static_cast(pLayout); UT_uint32 leftThickness = getLeftStyle (pTableLayout).m_thickness; x += leftThickness + m_iLeftPad; return x; } /*! * This includes the boder thickness.This method is used by the * containers held by the cell */ UT_sint32 fp_CellContainer::getY(void) const { const fl_ContainerLayout * pLayout = const_cast(getSectionLayout()->myContainingLayout ()); UT_return_val_if_fail(pLayout->getContainerType () == FL_CONTAINER_TABLE,0); const fl_TableLayout * pTableLayout = static_cast(pLayout); UT_uint32 topThickness = getTopStyle (pTableLayout).m_thickness; UT_sint32 y = fp_VerticalContainer::getY(); y += topThickness + m_iTopPad; return y; } /*! * This is the actual location of the cell. Use to position the cell */ UT_sint32 fp_CellContainer::getCellX(void) const { return fp_VerticalContainer::getX(); } /*! * This is the actual location of the cell. Use to position the cell */ UT_sint32 fp_CellContainer::getCellY(void) const { return fp_VerticalContainer::getY(); } /*! * This is the width of the cell without the border padding * This is the method used by the containers held by the cell */ UT_sint32 fp_CellContainer::getWidth(void) const { UT_sint32 w = fp_VerticalContainer::getWidth(); const fl_ContainerLayout * pLayout = const_cast(getSectionLayout()->myContainingLayout ()); UT_return_val_if_fail(pLayout->getContainerType () == FL_CONTAINER_TABLE,0); const fl_TableLayout * pTableLayout = static_cast(pLayout); UT_uint32 leftThickness = getLeftStyle (pTableLayout).m_thickness; UT_uint32 rightThickness = getRightStyle (pTableLayout).m_thickness; w = w - leftThickness - rightThickness - m_iLeftPad - m_iRightPad; return w; } /*! * This is the height of the cell without the border padding. * This is the method used by the containers held by the cell */ UT_sint32 fp_CellContainer::getHeight(void) const { UT_sint32 h = fp_VerticalContainer::getHeight(); const fl_ContainerLayout * pLayout = const_cast(getSectionLayout()->myContainingLayout ()); UT_return_val_if_fail(pLayout->getContainerType () == FL_CONTAINER_TABLE,0); const fl_TableLayout * pTableLayout = static_cast(pLayout); UT_sint32 topThickness = getTopStyle (pTableLayout).m_thickness; UT_sint32 bottomThickness = getBottomStyle (pTableLayout).m_thickness; fp_TableContainer * pTab = static_cast(getContainer()); return h; } /*! * This is the total width of the cell including the border */ UT_sint32 fp_CellContainer::getCellWidth(void) const { return fp_VerticalContainer::getWidth(); } /*! * This is the total height of the cell including the border */ UT_sint32 fp_CellContainer::getCellHeight(void) const { return fp_VerticalContainer::getHeight(); } 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 \n",i,pCon->getHeight())); 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; } } 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(); } /* * To make sure that cells include their borders as well, get the * thickness of each of the cell borders and add them * appropriately to the requisition. */ //Lookup table properties to find line thickness. fl_ContainerLayout * pLayout = getSectionLayout()->myContainingLayout (); UT_return_if_fail(pLayout->getContainerType () == FL_CONTAINER_TABLE); fl_TableLayout * pTableLayout = static_cast(pLayout); UT_uint32 bottomLineThickness = getBottomStyle (pTableLayout).m_thickness; UT_uint32 leftLineThickness = getLeftStyle (pTableLayout).m_thickness; UT_uint32 rightLineThickness = getRightStyle (pTableLayout).m_thickness; UT_uint32 topLineThickness = getTopStyle (pTableLayout).m_thickness; width = width + leftLineThickness + rightLineThickness + m_iLeftPad + m_iRightPad; height = height + bottomLineThickness + topLineThickness + m_iTopPad + m_iBotPad; 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; UT_DEBUGMSG(("SIZE REQUEST: Old size: (%d, %d), new size: (%d, %d)\n", width, height, m_MyRequest.width, m_MyRequest.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; UT_DEBUGMSG(("SIZE ALLOCATION: corner (%d, %d), dimensions (%d, %d)\n", m_MyAllocation.x, m_MyAllocation.y, m_MyAllocation.width, m_MyAllocation.height)); } 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; UT_sint32 iAdditional= 0; const fl_ContainerLayout * pLayout = const_cast(getSectionLayout()->myContainingLayout ()); UT_return_if_fail(pLayout->getContainerType () == FL_CONTAINER_TABLE); const fl_TableLayout * pTableLayout = static_cast(pLayout); iAdditional = getTopStyle (pTableLayout).m_thickness; iAdditional += getBottomStyle (pTableLayout).m_thickness; iAdditional +=(m_iTopPad + m_iBotPad); 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+iAdditional); } 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); const fl_ContainerLayout * pLayout = const_cast(getSectionLayout()->myContainingLayout ()); UT_return_if_fail(pLayout->getContainerType () == FL_CONTAINER_TABLE); const fl_TableLayout * pTableLayout = static_cast(pLayout); UT_uint32 topThickness = getTopStyle (pTableLayout).m_thickness; xoff = -static_cast(pTab->getNthCol(getLeftAttach())->spacing); yoff = m_iTopY - getCellY()+topThickness; } /*! * 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 = getCellX(); fp_CellContainer * pCell = pTab->getCellAtRowColumn(getTopAttach(),getRightAttach()); if(pCell) { m_iRight = pCell->getCellX(); } else { m_iRight = getCellX() + getCellWidth(); } m_iTopY = pTab->getYOfRow(getTopAttach()); xxx_UT_DEBUGMSG(("getBottomAttach %d \n",getBottomAttach())); if(getBottomAttach() <= pTab->getNumRows()) { m_iBotY = pTab->getYOfRow(getBottomAttach()); } 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); } 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), m_iAdditionalMarginAfter(0), m_bDefaultLines(true) { 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), m_bDefaultLines(true) { if(pMaster) { m_bDefaultLines = pMaster->m_bDefaultLines; } } /*! 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()); pBroke = static_cast(pBroke->getNext()); } } else { pCell->drawLines(NULL,getGraphics()); } 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 the top of row number row in the unbroken * table. * The idea is to use the Y co-ordinates cached during table * layout. */ UT_sint32 fp_TableContainer::getYOfRow(UT_sint32 row) { if (row < 0 || row > getNumRows()) { return 0; } else if (row == getNumRows()) { UT_sint32 lastRow = getNumRows() - 1; return getNthRow(lastRow)->y + getNthRow(lastRow)->spacing + getNthRow(lastRow)->allocation; } return getNthRow(row)->y; } /*! * 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 = 0; 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 = 0; 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 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; } 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->getCellY() >= vpos) { bStop = true; break; } if((pCell->getCellY() + pCell->getHeight()) > vpos) { pCell->VBreakAt(vpos - pCell->getCellY()); } 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 don't break. 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->getCellY() <= vpos && pCell->getCellY() + pCell->getCellHeight() > 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->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); UT_DEBUGMSG(("ADITYA: Req: width = %d, height = %d\n", requisition.width, requisition.height )); setX(m_iBorderWidth); alloc.x = getX(); alloc.y = getY() + pTL->getTopOffset(); alloc.width = getWidth(); alloc.height = requisition.height + pTL->getTopOffset() + pTL->getBottomOffset(); UT_DEBUGMSG(("ADITYA: Alloc: width = %d, height = %d\n", alloc.width, alloc.height)); sizeAllocate(&alloc); // // Clear out the dirty flag. We've done a complete layout now. // pTL->setDirty(false); 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 } /* * This function sets the width allocations for the columns and then * sets the widths of all the cells too. The heights of the cells may * thus change. */ void fp_TableContainer::_size_allocate_pass_1(void) { fl_TableLayout * pTL = static_cast(getSectionLayout()); const UT_GenericVector * pVecColProps = pTL->getVecColProps(); //First set all fixed width columns to their 'fixed' widths. for (UT_sint32 col = 0; col < pVecColProps->getItemCount(); col++) getNthCol(col)->allocation = pVecColProps->getNthItem(col)->m_iColWidth; if ( pVecColProps->getItemCount() >= getNumCols() ) //Nothing to do, since all columns are fixed width. return; UT_DEBUGMSG(("ADITYA: No. of Col Props: %d\n", pVecColProps->getItemCount())); //Adjust the remaining columns now. if ( m_MyAllocation.width >= m_MyRequest.width ) { /* * Since we may have extra space, we can expand (and allocate) * all non-fixed width columns to fill up the allocated width. * * We evenly distribute the available surplus over the * non-fixed width columns. */ UT_sint32 extra_width = m_MyAllocation.width - m_MyRequest.width; UT_sint32 expandable_cols = getNumCols() - pVecColProps->getItemCount(); UT_sint32 rem = 0, quo = 0; UT_DEBUGMSG(("ADITYA: expandable_cols: %d\n", expandable_cols)); if ( expandable_cols > 0 ) { rem = extra_width % expandable_cols; quo = extra_width / expandable_cols; for (UT_sint32 col = pVecColProps->getItemCount(); col < getNumCols(); col++) { getNthCol(col)->allocation = getNthCol(col)->requisition + quo + ((rem > 0) ? 1 : 0); rem--; } } } else { /* * Here we need to shrink the non-fixed width cols to make it * fit within the allocated width. */ UT_sint32 shrink_width = m_MyRequest.width - m_MyAllocation.width; UT_sint32 shrinkable_cols = getNumCols() - pVecColProps->getItemCount(); UT_sint32 rem = 0, quo = 0; if ( shrinkable_cols > 0 ) { rem = shrink_width % shrinkable_cols; quo = shrink_width / shrinkable_cols; //We will need a min. col. width to avoid getting negative //column widths. UT_sint32 allowed_min_col_width = 1; for (UT_sint32 col = pVecColProps->getItemCount(); col < getNumCols(); col++) { getNthCol(col)->allocation = UT_MAX( allowed_min_col_width, getNthCol(col)->requisition - (quo + ((rem > 0) ? 1 : 0)) ); rem--; } } } /* * Now set the widths of all cells. This will give them new heights. */ fp_CellContainer * child = static_cast(getNthCon(0)); for (; child; child = static_cast(child->getNext())) { UT_sint32 child_width = 0; //for child that spans a single col if ( child->getLeftAttach() == child->getRightAttach() - 1 ) { child_width = getNthCol(child->getLeftAttach())->allocation; } else //for child that spans multiple cols { for( UT_sint32 col = child->getLeftAttach(); col < child->getRightAttach(); col++ ) { child_width += getNthCol(col)->allocation; if ( col + 1 < child->getRightAttach() ) child_width += getNthCol(col)->spacing; } } child->setWidth(child_width); UT_DEBUGMSG(("ADITYA: child width: %d height %d\n", child_width, child->getSpannedHeight())); } } /* * This function sets the height allocation for rows. */ void fp_TableContainer::_size_allocate_pass_2(void) { fl_TableLayout * pTL = static_cast(getSectionLayout()); const UT_GenericVector * pVecRowProps = pTL->getVecRowProps(); //First set all fixed height rows to their 'fixed' heights. for (UT_sint32 row = 0; row < pVecRowProps->getItemCount(); row++) getNthRow(row)->allocation = pVecRowProps->getNthItem(row)->m_iRowHeight; if ( pVecRowProps->getItemCount() >= getNumRows() ) //Nothing to do, since all rows are fixed height. return; //Since table can extend over multiple pages, we always grant the //requested height for cells. The cells' heights need to be //recomputed now - i.e. m_MyRequest.height is potentially //incorrect now. //So first recompute the requested height of all rows again. //clear the old height requisitions. for ( UT_sint32 row = 0; row < getNumRows(); row++ ) getNthRow(row)->requisition = 0; fp_CellContainer * child = static_cast(getNthCon(0)); for (; child; child = static_cast(child->getNext())) { UT_sint32 child_height; //Now handle the heights. child_height = child->getCellHeight(); //If child spans only one row. if ( child->getTopAttach() == child->getBottomAttach() - 1 ) { //ignore cells in fixed height rows. if (child->getTopAttach() < pVecRowProps->getItemCount()) continue; getNthRow(child->getTopAttach())->requisition = UT_MAX(getNthRow(child->getTopAttach())->requisition, child_height); } else // child spans multiple rows { UT_sint32 available_height = 0; for (UT_sint32 row = child->getTopAttach(); row < child->getBottomAttach(); row++) { available_height += getNthRow(row)->requisition; if (row + 1 < child->getBottomAttach()) available_height += getNthRow(row)->spacing; } /* * If the available height is insufficient, divide up the * required space evenly among the rows spanned. If * the spanned rows include those that are of fixed * height, then divide up the space among the non-fixed * height rows only. */ if (available_height < child_height) { UT_sint32 required_extra_height = child_height - available_height; UT_sint32 rows_spanned = child->getBottomAttach() - child->getTopAttach(); UT_sint32 start_index = child->getTopAttach(); UT_sint32 rem = 0, quo = 0; if (child->getTopAttach() < pVecRowProps->getItemCount()) { rows_spanned = child->getBottomAttach() - pVecRowProps->getItemCount(); start_index = pVecRowProps->getItemCount(); } if ( rows_spanned > 0 ) { rem = required_extra_height % rows_spanned; quo = required_extra_height / rows_spanned; for (UT_sint32 row = start_index; row < child->getBottomAttach(); row++) { getNthRow(row)->requisition += quo + ((rem > 0) ? 1 : 0); rem--; } } } } } #ifdef DEBUG for (UT_sint32 row = 0; row < getNumRows(); row++) { xxx_UT_DEBUGMSG(("ADITYA: Row height request: %d\n", getNthRow(row)->requisition)); } #endif //Calc new height request. UT_sint32 new_height_request = 0; for (UT_sint32 row = 0; row < getNumRows(); row++) { if ( row < pVecRowProps->getItemCount() ) new_height_request += pVecRowProps->getNthItem(row)->m_iRowHeight; else new_height_request += getNthRow(row)->requisition; } //Height requisitions have been recomputed. m_MyAllocation.height = new_height_request + pTL->getTopOffset() + pTL->getBottomOffset(); //Allocate the row heights. for (UT_sint32 row = 0; row < getNumRows(); row++) { if ( row < pVecRowProps->getItemCount() ) getNthRow(row)->allocation = pVecRowProps->getNthItem(row)->m_iRowHeight; else getNthRow(row)->allocation = getNthRow(row)->requisition; } } /* * This pass sets the allocations of cells. */ void fp_TableContainer::_size_allocate_pass_3(void) { fl_TableLayout * pTL = static_cast(getSectionLayout()); //Cache the x-position of cols getNthCol(0)->x = m_MyAllocation.x + m_iBorderWidth; for ( UT_sint32 col = 1; col < getNumCols(); col++ ) { getNthCol(col)->x = getNthCol(col-1)->x + getNthCol(col-1)->spacing + getNthCol(col-1)->allocation; } //Cache the y-position of rows getNthRow(0)->y = m_MyAllocation.y ; for ( UT_sint32 row = 1; row < getNumRows(); row++ ) { getNthRow(row)->y = getNthRow(row-1)->y + getNthRow(row-1)->spacing + getNthRow(row-1)->allocation; } fp_CellContainer* child = static_cast(getNthCon(0)); const UT_GenericVector * pVecColProps = pTL->getVecColProps(); const UT_GenericVector * pVecRowProps = pTL->getVecRowProps(); for ( ; child; child = static_cast(child->getNext()) ) { UT_sint32 scol = child->getLeftAttach(), srow = child->getTopAttach(); fp_Allocation allocation; allocation.x = getNthCol(scol)->x, allocation.y = getNthRow(srow)->y; allocation.width = allocation.height = 0; if ( child->getLeftAttach() == child->getRightAttach() - 1 ) { if ( scol < pVecColProps->getItemCount() ) allocation.width = pVecColProps->getNthItem(scol)->m_iColWidth; else allocation.width = getNthCol(scol)->allocation; } else { for ( UT_sint32 col = scol; col < child->getRightAttach(); col++ ) { if ( col < pVecColProps->getItemCount() ) allocation.width += pVecColProps->getNthItem(col)->m_iColWidth; else allocation.width += getNthCol(col)->allocation; } } if ( child->getTopAttach() == child->getBottomAttach() - 1 ) { if ( srow < pVecRowProps->getItemCount() ) allocation.height = pVecRowProps->getNthItem(srow)->m_iRowHeight; else allocation.height = getNthRow(srow)->allocation; } else { for ( UT_sint32 row = srow; row < child->getBottomAttach(); row++ ) { if ( row < pVecRowProps->getItemCount() ) allocation.height += pVecRowProps->getNthItem(row)->m_iRowHeight; else allocation.height += getNthRow(row)->allocation; } } child->sizeAllocate(&allocation); //UT_DEBUGMSG(("ADITYA: col %d row %d, alloc.w = %d, alloc.h = %d, alloc.x = %d, alloc.y = %d\n", scol, srow, allocation.width, allocation.height, allocation.x, allocation.y)); } } 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; 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; 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; } UT_DEBUGMSG(("Doing clear screen on %p num rows %d \n",this,getNumRows())); 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. // if(pCon->getMyBrokenContainer() == static_cast(this)) { return true; } if(pCon->getMyBrokenContainer() != NULL) { return false; } UT_sint32 iTop = 0; iTop = pCell->getCellY() + pCon->getY(); UT_sint32 iHeight = pCon->getHeight(); 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 %x iTop = %d ybreak %d iBot= %d ybottom= %d \n",getBrokenColumn(),iTop,iBreak,iBot,iBottom)); if(iBot >= iBreak) { if(iBot < iBottom + pCell->getBotPad()) { // 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->getCellY(), 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->getCellY(), 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->getCellY() > getYBottom()) { xxx_UT_DEBUGMSG(("SEVIOR: _drawBroken skipping cell %x cellY %d cellHeight %d YBreak %d yBottom %d \n",pCell,pCell->getCellY(), 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) { width = child_requisition.width; 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) { height = child_requisition.height - 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)); while (child) { fp_Requisition child_requisition; child->sizeRequest(&child_requisition); x = m_MyAllocation.x; double dy = static_cast(m_MyAllocation.y); xxx_UT_DEBUGMSG(("SEVIOR: Vertical border %f \n", dBorder)); y = static_cast (dy); 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); 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 ); 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::sizeRequest(fp_Requisition * pRequisition) { _size_request_init(); /* * Find the requisition width and height. The height though is not * going to be useful, because after the width is allocated the * height will change. */ fl_TableLayout * pTL = static_cast(getSectionLayout()); fp_CellContainer * child = static_cast(getNthCon(0)); const UT_GenericVector * pVecColProps = pTL->getVecColProps(); const UT_GenericVector * pVecRowProps = pTL->getVecRowProps(); for (; child; child = static_cast(child->getNext())) { UT_sint32 child_width, child_height; fp_Requisition child_requisition; child->sizeRequest(&child_requisition); //First take care of width child_width = child_requisition.width; //if child spans a single col. if (child->getLeftAttach() == child->getRightAttach() - 1) { //ignore cells in fixed width columns. if (child->getLeftAttach() >= pVecColProps->getItemCount()) getNthCol(child->getLeftAttach())->requisition = UT_MAX(getNthCol(child->getLeftAttach())->requisition, child_width); } else // child spans multiple cols { UT_sint32 available_width = 0; for (UT_sint32 col = child->getLeftAttach(); col < child->getRightAttach(); col++) { available_width += getNthCol(col)->requisition; if (col + 1 < child->getRightAttach()) available_width += getNthCol(col)->spacing; } /* * If the available width is insufficient, divide up the * required space evenly among the columns spanned. If * the spanned colums include those that are of fixed * width, then divide up the space among the non-fixed * width columns only. */ if (available_width < child_width) { UT_sint32 required_extra_width = child_width - available_width; UT_sint32 cols_spanned = child->getRightAttach() - child->getLeftAttach(); UT_sint32 start_index = child->getLeftAttach(); UT_sint32 rem = 0; UT_sint32 quo = 0; if (child->getLeftAttach() < pVecColProps->getItemCount()) { cols_spanned = child->getRightAttach() - pVecColProps->getItemCount(); start_index = pVecColProps->getItemCount(); } if ( cols_spanned > 0 ) { rem = required_extra_width % cols_spanned; quo = required_extra_width / cols_spanned; for (UT_sint32 col = start_index; col < child->getRightAttach(); col++) { getNthCol(col)->requisition += quo + ((rem > 0) ? 1 : 0); rem--; } } } } //Now handle the heights. child_height = child_requisition.height; //If child spans only one row. if ( child->getTopAttach() == child->getBottomAttach() - 1 ) { //ignore cells in fixed height rows. if (child->getTopAttach() < pVecRowProps->getItemCount()) continue; getNthRow(child->getTopAttach())->requisition = UT_MAX(getNthRow(child->getTopAttach())->requisition, child_width); } else // child spans multiple rows { UT_sint32 available_height = 0; for (UT_sint32 row = child->getTopAttach(); row < child->getBottomAttach(); row++) { available_height += getNthRow(row)->requisition; if (row + 1 < child->getBottomAttach()) available_height += getNthRow(row)->spacing; } /* * If the available height is insufficient, divide up the * required space evenly among the rows spanned. If * the spanned rows include those that are of fixed * height, then divide up the space among the non-fixed * height rows only. */ if (available_height < child_height) { UT_sint32 required_extra_height = child_height - available_height; UT_sint32 rows_spanned = child->getBottomAttach() - child->getTopAttach(); UT_sint32 start_index = child->getTopAttach(); UT_sint32 rem = 0, quo = 0; if (child->getTopAttach() < pVecRowProps->getItemCount()) { rows_spanned = child->getBottomAttach() - pVecRowProps->getItemCount(); start_index = pVecRowProps->getItemCount(); } if ( rows_spanned > 0 ) { rem = required_extra_height % rows_spanned; quo = required_extra_height / rows_spanned; for (UT_sint32 row = start_index; row < child->getBottomAttach(); row++) { getNthRow(row)->requisition += quo + ((rem > 0) ? 1 : 0); rem--; } } } } } /* * Calculate requisition of the table */ pRequisition->height = pRequisition->width = 0; for (UT_sint32 col = 0; col < getNumCols(); col++) { if ( col < pVecColProps->getItemCount() ) pRequisition->width += pVecColProps->getNthItem(col)->m_iColWidth; else pRequisition->width += getNthCol(col)->requisition; } for (UT_sint32 row = 0; row < getNumRows(); row++) { if ( row < pVecRowProps->getItemCount() ) pRequisition->height += pVecRowProps->getNthItem(row)->m_iRowHeight; else pRequisition->height += getNthRow(row)->requisition; } //Set the requisition values in the object too. m_MyRequest = *pRequisition; } /* 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; } */ 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; UT_DEBUGMSG(("ADITYA: Initial allocation height is %d \n", pAllocation->height)); UT_DEBUGMSG(("ADITYA: Initial allocation width is %d \n", pAllocation->width)); _size_allocate_pass_1(); _size_allocate_pass_2(); _size_allocate_pass_3(); }