1 /* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */
2 
3 /* AbiWord
4  * Copyright (C) 1998 AbiSource, Inc.
5  * Copyright (C) 2002 Martin Sevior <msevior@physics.unimelb.edu.au>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20  * 02110-1301 USA.
21  */
22 /* GTK - The GIMP Toolkit
23  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
24  *
25  * This library is free software; you can redistribute it and/or
26  * modify it under the terms of the GNU Library General Public
27  * License as published by the Free Software Foundation; either
28  * version 2 of the License, or (at your option) any later version.
29  *
30  * This library is distributed in the hope that it will be useful,
31  * but WITHOUT ANY WARRANTY; without even the implied warranty of
32  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
33  * Library General Public License for more details.
34  *
35  * You should have received a copy of the GNU Library General Public
36  * License along with this library; if not, write to the
37  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
38  * Boston, MA 02110-1301 USA.
39  */
40 
41 /*
42  * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
43  * file for a list of people on the GTK+ Team.  See the ChangeLog
44  * files for a list of changes.  These files are distributed with
45  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
46  */
47 
48 //
49 // Uncomment to benchmark our table layout time with release builds
50 //#define BENCHLAYOUT 1
51 #include <stdlib.h>
52 #include <math.h>
53 #include <string.h>
54 
55 #include "fp_TableContainer.h"
56 #include "fp_Column.h"
57 #include "fp_Page.h"
58 #include "fp_Line.h"
59 #include "fv_View.h"
60 #include "fl_SectionLayout.h"
61 #include "fl_TableLayout.h"
62 #include "gr_DrawArgs.h"
63 #include "ut_vector.h"
64 #include "ut_types.h"
65 #include "ut_debugmsg.h"
66 #include "ut_assert.h"
67 #include "fl_FootnoteLayout.h"
68 #include "fp_FootnoteContainer.h"
69 #include "fp_FrameContainer.h"
70 #include "gr_Painter.h"
71 #include "pd_Document.h"
72 #if BENCHLAYOUT
73 #include <time.h>
74 #endif
75 
fp_TableRowColumn(UT_sint32 defaultSpacing)76 fp_TableRowColumn::fp_TableRowColumn(UT_sint32 defaultSpacing) :
77 		requisition(0),
78 		allocation(0),
79 		spacing(defaultSpacing),
80 		position(0),
81 		need_expand(false),
82 		need_shrink(false),
83 		expand(false),
84 		shrink(false),
85 		empty(true)
86 {
87 }
88 
~fp_TableRowColumn(void)89 fp_TableRowColumn::~fp_TableRowColumn(void)
90 {
91 }
92 
93 
94 /*!
95   Create Cell container
96   \param iType Container type
97   \param pSectionLayout Section layout type used for this container
98  */
fp_CellContainer(fl_SectionLayout * pSectionLayout)99 fp_CellContainer::fp_CellContainer(fl_SectionLayout* pSectionLayout)
100 	: fp_VerticalContainer(FP_CONTAINER_CELL, pSectionLayout),
101 	  m_iLeftAttach(0),
102 	  m_iRightAttach(0),
103 	  m_iTopAttach(0),
104 	  m_iBottomAttach(0),
105 	  m_borderColorNone(127,127,127),
106 	  m_iLeftPad(0),
107 	  m_iRightPad(0),
108 	  m_iTopPad(0),
109 	  m_iBotPad(0),
110 	  m_pNextInTable(NULL),
111 	  m_pPrevInTable(NULL),
112 	  m_bXexpand(true),
113 	  m_bYexpand(false),
114 	  m_bXshrink(false),
115 	  m_bYshrink(true),
116 	  m_bXfill(true),
117 	  m_bYfill(false),
118 	  m_iLeft(0),
119 	  m_iRight(0),
120 	  m_iTopY(0),
121 	  m_iBotY(0),
122 	  m_bDrawLeft(false),
123 	  m_bDrawTop(false),
124 	  m_bDrawBot(false),
125 	  m_bDrawRight(false),
126 	  m_bLinesDrawn(false),
127 	  m_bBgDirty(true),
128 	  m_bIsSelected(false),
129 	  m_bDirty(true),
130 	  m_bIsRepeated(false),
131 	  m_iVertAlign(0)
132 {
133 }
134 
135 /*!
136   Destruct container
137   \note The Containers in vector of the container are not
138         destructed. They are owned by the logical hierarchy (i.e.,
139 		the fl_Container classes like fl_BlockLayout), not the physical
140         hierarchy.
141  */
~fp_CellContainer()142 fp_CellContainer::~fp_CellContainer()
143 {
144 	xxx_UT_DEBUGMSG(("Deleting Cell container %x \n",this));
145 	setNext(NULL);
146 	setPrev(NULL);
147 }
148 
isRepeated(void) const149 bool fp_CellContainer::isRepeated(void) const
150 {
151 	return m_bIsRepeated;
152 }
153 
setHeight(UT_sint32 iHeight)154 void fp_CellContainer::setHeight(UT_sint32 iHeight)
155 {
156 	xxx_UT_DEBUGMSG(("cell: Height was %d \n",getHeight()));
157 	if ((iHeight == getHeight()) || (iHeight== 0))
158 	{
159 		return;
160 	}
161 	clearScreen();
162 	fp_TableContainer * pTab = static_cast<fp_TableContainer *>(getContainer());
163 	if(pTab && getBottomAttach() == pTab->getNumRows())
164 	{
165 		fp_CellContainer * pCell = pTab->getCellAtRowColumn(pTab->getNumRows() -1,0);
166 		while(pCell)
167 		{
168 			pCell->clearScreen();
169 			pCell->getSectionLayout()->setNeedsRedraw();
170 			pCell->getSectionLayout()->markAllRunsDirty();
171 			pCell = static_cast<fp_CellContainer *>(pCell->getNext());
172 		}
173 	}
174 	fp_VerticalContainer::setHeight(iHeight);
175 	xxx_UT_DEBUGMSG(("cell: Height set to %d \n",getHeight()));
176 	fl_SectionLayout * pSL = getSectionLayout();
177 	pSL = static_cast<fl_SectionLayout *>(pSL->myContainingLayout());
178 	UT_ASSERT(pSL->getContainerType() == FL_CONTAINER_TABLE);
179 	static_cast<fl_TableLayout *>(pSL)->setDirty();
180 	static_cast<fl_TableLayout *>(pSL)->setHeightChanged(this);
181 }
182 
183 /*!
184  * Return the broken table that contains this cell and the given Container
185  */
getBrokenTable(fp_Container * pCon) const186 fp_TableContainer * fp_CellContainer::getBrokenTable(fp_Container * pCon) const
187 {
188 	fp_TableContainer * pMaster = static_cast<fp_TableContainer *>(getContainer());
189 	if(!pMaster)
190 	{
191 		return NULL;
192 	}
193 	fp_TableContainer * pBroke = pMaster->getFirstBrokenTable();
194 	if (!pBroke)
195 	{
196 		return pMaster;
197 	}
198 
199 	UT_sint32 yPos = getY() + pCon->getY() + 1;
200 	while(pBroke && (pBroke->getYBottom() < yPos))
201     {
202 		pBroke = static_cast<fp_TableContainer *>(pBroke->getNext());
203 	}
204 
205 	return ((pBroke) ? pBroke : pMaster);
206 }
207 
208 /*!
209  * This Method returns the column or shadow that embeds the container given.
210  */
getColumn(fp_Container * _pCon)211 fp_VerticalContainer * fp_CellContainer::getColumn(fp_Container * _pCon)
212 {
213 	fp_TableContainer * pBroke = getBrokenTable(_pCon);
214 	if(pBroke == NULL)
215 	{
216 		return NULL;
217 	}
218 
219 	bool bStop = false;
220 	fp_CellContainer * pCell = NULL;
221 	fp_Column * pCol = NULL;
222 	//
223 	// Now FIXED for nested tables off first page
224 	//
225 	while(pBroke && pBroke->isThisBroken() && !bStop)
226 	{
227 		fp_Container * pCon = pBroke->getContainer();
228 		if(pCon == NULL)
229 		{
230 			return NULL;
231 		}
232 		if(pCon->isColumnType())
233 		{
234 			if(pCon->getContainerType() == FP_CONTAINER_COLUMN)
235 			{
236 				pCol = static_cast<fp_Column *>(pCon);
237 			}
238 			else if(pCon->getContainerType() == FP_CONTAINER_COLUMN_SHADOW)
239 			{
240 				return static_cast<fp_VerticalContainer *>(pCon);
241 			}
242 			else
243 			{
244 				pCol = static_cast<fp_Column *>(pCon->getColumn());
245 			}
246 			bStop = true;
247 		}
248 		else
249 		{
250 			pCell = static_cast<fp_CellContainer *>(pCon);
251 			UT_ASSERT(pCell->getContainerType() == FP_CONTAINER_CELL);
252 			pBroke = pCell->getBrokenTable(static_cast<fp_Container *>(pBroke));
253 		}
254 	}
255 	if(pCell && (pBroke == NULL))
256 	{
257 		return static_cast<fp_Column *>(static_cast<fp_Container *>(pCell)->getColumn());
258 	}
259 	else if(pBroke == NULL)
260 	{
261 		return NULL;
262 	}
263 	if(!bStop)
264 	{
265 		pCol = static_cast<fp_Column *>(pBroke->getContainer());
266 		if (!pCol)
267 		{
268 			return NULL;
269 		}
270 	}
271 	//	UT_ASSERT(pCol->getContainerType() != FP_CONTAINER_CELL);
272 	if(pCol && pCol->getContainerType() == FP_CONTAINER_CELL)
273 	{
274 		fp_Container * pCon = static_cast<fp_Container *>(pCol);
275 		while(pCon && !pCon->isColumnType())
276 		{
277 			pCon = pCon->getContainer();
278 		}
279 		if(pCon)
280 		{
281 			pCol = static_cast<fp_Column *>(pCon);
282 		}
283 		else
284 		{
285 			pCol = NULL;
286 		}
287 	}
288 
289 	return static_cast<fp_VerticalContainer *>(pCol);
290 }
291 
containsNestedTables(void)292 bool fp_CellContainer::containsNestedTables(void)
293 {
294 	fl_CellLayout * pCL = static_cast<fl_CellLayout *>(getSectionLayout());
295 	return (pCL->getNumNestedTables() > 0);
296 }
297 
298 /*!
299  * Return the screen rectangle that is the intersection of the cell and the
300  * broken table.
301  * If the height or width is negative, the cell is not in the broken table.
302  */
_getBrokenRect(fp_TableContainer * pBroke,fp_Page * & pPage,UT_Rect & bRec,GR_Graphics * pG)303 void fp_CellContainer::_getBrokenRect(fp_TableContainer * pBroke, fp_Page * &pPage, UT_Rect &bRec, GR_Graphics * pG)
304 {
305 	UT_ASSERT(static_cast<fl_TableLayout *>(getSectionLayout()->myContainingLayout()) &&
306 	static_cast<fl_TableLayout *>(getSectionLayout()->myContainingLayout())->getContainerType() == FL_CONTAINER_TABLE);
307 
308 	fp_Column * pCol = NULL;
309 	UT_sint32 col_y =0;
310 	UT_sint32 col_x =0;
311 	UT_sint32 iLeft = m_iLeft;
312 	UT_sint32 iRight = m_iRight;
313 	UT_sint32 iTop = m_iTopY;
314 	UT_sint32 iBot = m_iBotY;
315 	bool bIsNested = false;
316 	if(pBroke && (pBroke->getContainer()->getContainerType() == FP_CONTAINER_CELL))
317 	{
318 		bIsNested = true;
319 	}
320 	UT_sint32 offx = 0;
321 	UT_sint32 offy = 0;
322 	bool bFrame = false;
323 	if(pBroke)
324 	{
325 		pPage = pBroke->getPage();
326 		if(pPage)
327 		{
328 			if(pBroke->getContainer()->getContainerType() == FP_CONTAINER_FRAME)
329 		    {
330 				fp_FrameContainer * pFC = static_cast<fp_FrameContainer *>(pBroke->getContainer());
331 				getView()->getPageScreenOffsets(pPage,col_x,col_y);
332 				//
333 				// Use col_x, col_y later.
334 				//
335 				offx = pFC->getX();
336 				offy = pFC->getY();
337 				bFrame = true;
338 			}
339 			else
340 			{
341 				pCol = static_cast<fp_Column *>(pBroke->getBrokenColumn());
342 				pBroke->getPage()->getScreenOffsets(pCol,col_x,col_y);
343 			}
344 			if(pBroke->getMasterTable())
345 			{
346 				if(pBroke->getMasterTable()->getFirstBrokenTable() == pBroke)
347 				{
348 					if(!bFrame)
349 					{
350 						offy = pBroke->getMasterTable()->getY();
351 					}
352 					else
353 					{
354 						offy += pBroke->getMasterTable()->getY();
355 					}
356 					if(iBot > pBroke->getYBottom())
357 					{
358 						iBot = pBroke->getYBottom();
359 					}
360 				}
361 				else if(bIsNested)
362 				{
363 					if(iTop < pBroke->getYBreak())
364 					{
365 						iTop = 0;
366 					}
367 					else
368 					{
369 						iTop = iTop - pBroke->getYBreak();
370 					}
371 					if(iBot > pBroke->getYBottom())
372 					{
373 						iBot = pBroke->getYBottom() - pBroke->getYBreak();
374 					}
375 					else
376 					{
377 						iBot = iBot - pBroke->getYBreak();
378 					}
379 				}
380 				else
381 				{
382 					offy = 0;
383 					if(iTop < pBroke->getYBreak())
384 					{
385 						iTop = 0;
386 					}
387 					else
388 					{
389 						iTop = iTop - pBroke->getYBreak();
390 					}
391 					if(iBot > pBroke->getYBottom())
392 					{
393 						iBot = pBroke->getYBottom() - pBroke->getYBreak();
394 					}
395 					else
396 					{
397 						iBot = iBot - pBroke->getYBreak();
398 					}
399 					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()));
400 				}
401 			}
402 			else
403 			{
404 				offy = pBroke->getY();
405 			}
406 			if(pBroke->getMasterTable())
407 			{
408 				offx += pBroke->getMasterTable()->getX();
409 			}
410 			else
411 			{
412 				offx += pBroke->getX();
413 			}
414 			fp_Container * pCon = pBroke;
415 			fp_TableContainer * pCurTab = pBroke;
416 			UT_sint32 iPrevCellY = 0;
417 			UT_sint32 iPrevTabY = pBroke->getY();
418 			UT_sint32 iPrevYBreak = pBroke->getYBreak();
419 			while(pCon->getContainer() && !pCon->getContainer()->isColumnType())
420 			{
421 				pCon = pCon->getContainer();
422 				offx += pCon->getX();
423 				UT_sint32 iycon = pCon->getY();
424 				offy += iycon; // this is not quite finished for nested tables!
425 				if(pCon->getContainerType() == FP_CONTAINER_CELL)
426 				{
427 					iPrevCellY = iycon;
428 				}
429 				if(pCon->getContainerType() == FP_CONTAINER_TABLE)
430 				{
431 					if(pCol)
432 					{
433 						pCurTab = pCol->getCorrectBrokenTable(static_cast<fp_Container *>(pCurTab));
434 					}
435 					else
436 					{
437 						pCurTab = static_cast<fp_TableContainer *>(pCon);
438 					}
439 					if(pCurTab->isThisBroken() && (pCurTab != pCurTab->getMasterTable()->getFirstBrokenTable()))
440 					{
441 
442 						offy = offy -iycon;
443 					}
444 					if(iPrevCellY > 0 && (iPrevCellY < pCurTab->getYBreak()))
445 					{
446 						offy -= iPrevCellY;
447 						if((iPrevTabY > 0) && (iPrevYBreak == 0))
448 						{
449 							offy -= pCurTab->getYBreak() - iPrevCellY;
450 						}
451 					}
452 					else
453 					{
454 						offy -= pCurTab->getYBreak();
455 					}
456 					pCon = static_cast<fp_Container *>(pCurTab);
457 					iPrevYBreak = pCurTab->getYBreak();
458 					iPrevTabY = pCurTab->getY();
459 				}
460 			}
461 			col_x += offx;
462 			col_y += offy;
463 			iLeft += col_x;
464 			iRight += col_x;
465 			iTop += col_y;
466 			iBot += col_y;
467 			xxx_UT_DEBUGMSG(("fp_Tablecontainer:: Final iTop %d iBot %d \n",iTop,iBot));
468 		}
469 		else
470 		{
471 			UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
472 		}
473 	}
474 	else
475 	{
476 		pPage = getPage();
477 		if(pPage)
478 		{
479 			pCol = static_cast<fp_Column *>(fp_Container::getColumn());
480 			pPage->getScreenOffsets(pCol,col_x,col_y);
481 			fp_Container * pCon = static_cast<fp_Container *>(this);
482 			while(!pCon->isColumnType())
483 			{
484 				col_x += pCon->getX();
485 				col_y += pCon->getY();
486 				pCon = pCon->getContainer();
487 			}
488 			if(pCon->getContainerType() != FP_CONTAINER_FRAME)
489 			{
490 				iLeft += col_x;
491 				iRight += col_x;
492 				iTop += col_y;
493 				iBot += col_y;
494 			}
495 			else
496 			{
497 				UT_sint32 iTmpX,iTmpY;
498 				pPage->getScreenOffsets(pCol,iTmpX,iTmpY);
499 				iLeft -= iTmpX;
500 				iTop -= iTmpY;
501 			}
502 		}
503 	}
504 
505 //
506 // Now correct for printing
507 //
508 	if(pG->queryProperties(GR_Graphics::DGP_PAPER))
509 	{
510 		UT_sint32 xdiff,ydiff;
511 		pPage->getDocLayout()->getView()->getPageScreenOffsets(pPage, xdiff, ydiff);
512 		pPage = getPage();
513 		if(pPage)
514 		{
515 			if(pPage->getDocLayout()->getView()->getViewMode() != VIEW_PRINT)
516 			{
517 				ydiff -= static_cast<fl_DocSectionLayout *>(getSectionLayout()->getDocSectionLayout())->getTopMargin();
518 			}
519 		}
520 		iLeft -= xdiff;
521 		iRight -= xdiff;
522 		iTop -= ydiff;
523 		iBot -= ydiff;
524 	}
525 	xxx_UT_DEBUGMSG(("_getBrokenRect Returned Top %d height = %d \n",iTop,iBot-iTop));
526 	bRec = UT_Rect(iLeft,iTop,iRight-iLeft,iBot-iTop);
527 }
528 
529 
530 /*!
531  * Returns true if the cell in a broken table overlaps the supplied clip Rect
532  */
doesIntersectClip(fp_TableContainer * pBroke,const UT_Rect * rClip)533 bool fp_CellContainer::doesIntersectClip(fp_TableContainer * pBroke, const UT_Rect * rClip)
534 {
535 	fp_Page * pPage = NULL;
536 	UT_Rect CellRect;
537 	_getBrokenRect(pBroke, pPage, CellRect,getGraphics());
538 	return CellRect.intersectsRect(rClip);
539 }
540 
541 
clearScreen(void)542 void fp_CellContainer::clearScreen(void)
543 {
544 	clearScreen(false);
545 }
546 
clearScreen(bool bNoRecursive)547 void fp_CellContainer::clearScreen(bool bNoRecursive)
548 {
549 	fp_Container * pUpCon = getContainer();
550 	if(pUpCon == NULL)
551 	{
552 		return;
553 	}
554 	if(pUpCon->getY() == INITIAL_OFFSET)
555 	{
556 		return;
557 	}
558 	if(getPage() == NULL)
559 	{
560 		return;
561 	}
562 	markAsDirty();
563 	xxx_UT_DEBUGMSG(("Doing cell clearscreen \n"));
564 // only clear the embeded containers if no background is set: the background clearing will also these containers
565 // FIXME: should work, but doesn't??
566 //	if (m_iBgStyle == FS_OFF)
567 //	{
568 		fp_Container * pCon = NULL;
569 		UT_sint32 i = 0;
570 		if(!bNoRecursive)
571 		{
572 			for(i=0; i< countCons(); i++)
573 			{
574 				pCon = static_cast<fp_Container *>(getNthCon(i));
575 				pCon->clearScreen();
576 			}
577 		}
578 	//}
579 		fp_TableContainer * pTab = static_cast<fp_TableContainer *>(getContainer());
580 		m_bDirty = true;
581 	if(pTab)
582 	{
583 		fp_TableContainer * pBroke = pTab->getFirstBrokenTable();
584 		if(pBroke == NULL)
585 		{
586 			_clear(pBroke);
587 			return;
588 		}
589 		if(!m_bLinesDrawn)
590 		{
591 			return;
592 		}
593 		while(pBroke)
594 		{
595 			xxx_UT_DEBUGMSG(("cell:clearscreean looking at pBroke %x Ybreak %d spannedHeight %d getY %d \n",pBroke,pBroke->getYBreak(),getSpannedHeight(),getY()));
596 			if((getY() >= pBroke->getYBreak() && getY() < pBroke->getYBottom())
597 				|| ( (getY()+getSpannedHeight()) >= pBroke->getYBreak() &&
598 					 (getY()  < pBroke->getYBreak())))
599 			{
600 				_clear(pBroke);
601 				m_bLinesDrawn = true;
602 			}
603 			pBroke = static_cast<fp_TableContainer *>(pBroke->getNext());
604 		}
605 		m_bLinesDrawn = false;
606 	}
607 }
608 
609 
getSpannedHeight(void)610 UT_sint32 fp_CellContainer::getSpannedHeight(void)
611 {
612 	fp_TableContainer * pTab = static_cast<fp_TableContainer *>(getContainer());
613 	if(pTab == NULL)
614 	{
615 		return 0;
616 	}
617 	fp_CellContainer * pCell2 = pTab->getCellAtRowColumn(getBottomAttach(),getLeftAttach());
618 	UT_sint32 height = 0;
619 	if(pCell2)
620 	{
621 		height = pTab->getYOfRow(getBottomAttach()) - getY();
622 	}
623 	else
624 	{
625 		fp_CellContainer * pCell = pTab->getCellAtRowColumn(pTab->getNumRows() -1,0);
626 		fp_CellContainer * pMaxH = pCell;
627 		if(pMaxH == NULL)
628 		{
629 			return 0;
630 		}
631 		while(pCell)
632 		{
633 			if(pCell->getHeight() > pMaxH->getHeight())
634 			{
635 				pMaxH = pCell;
636 			}
637 			pCell = static_cast<fp_CellContainer *>(pCell->getNext());
638 		}
639 		height = pMaxH->getY() - getY() + pMaxH->getHeight();
640 	}
641 	return height;
642 }
643 
_clear(fp_TableContainer * pBroke)644 void fp_CellContainer::_clear(fp_TableContainer * pBroke)
645 {
646 // Lookup table properties to get the line thickness, etc.
647 
648 	fl_ContainerLayout * pLayout = getSectionLayout()->myContainingLayout ();
649 	UT_return_if_fail(pLayout);
650 
651 	if(pBroke == NULL)
652 	{
653 		return;
654 	}
655 	if(pBroke->getPage() && !pBroke->getPage()->isOnScreen())
656 	{
657 		return;
658 	}
659 
660 	UT_ASSERT(pLayout->getContainerType () == FL_CONTAINER_TABLE);
661 	if (pLayout->getContainerType () != FL_CONTAINER_TABLE) return;
662 
663 	fl_TableLayout * pTableLayout = static_cast<fl_TableLayout *>(pLayout);
664 
665 	PP_PropertyMap::Background background = getBackground ();
666 
667 	PP_PropertyMap::Line lineBottom = getBottomStyle (pTableLayout);
668 	PP_PropertyMap::Line lineLeft   = getLeftStyle   (pTableLayout);
669 	PP_PropertyMap::Line lineRight  = getRightStyle  (pTableLayout);
670 	PP_PropertyMap::Line lineTop    = getTopStyle    (pTableLayout);
671 
672 	fp_Container * pCon = getContainer();
673 	if(pCon->getContainer() && !pCon->getContainer()->isColumnType())
674 	{
675 		xxx_UT_DEBUGMSG(("SEVIOR: Clearing nested cell lines \n"));
676 	}
677 	UT_Rect bRec;
678 	fp_Page * pPage = NULL;
679 	_getBrokenRect(pBroke, pPage, bRec,getGraphics());
680 	UT_sint32 onePix = getGraphics()->tlu(1)+1;
681 
682 	//
683 	// This fix makes win32 look bad. FIXME fix this later
684 	//
685 	onePix = 0.0;
686 	if((bRec.top + bRec.height) < 0)
687 	{
688 		return;
689 	}
690 	lineTop.m_thickness += 3*onePix;
691 	lineLeft.m_thickness += 3*onePix;
692 	lineRight.m_thickness += 3*onePix;
693 	lineBottom.m_thickness += 3*onePix;
694 	UT_RGBColor pageCol(255,255,255);
695 	if(pPage)
696 	{
697 		pageCol = *pPage->getFillType().getColor();
698 	}
699 	markAsDirty();
700 	if (pPage != NULL)
701 	{
702 		xxx_UT_DEBUGMSG(("_clear: top %d bot %d cell left %d top %d \n",bRec.top,bRec.top+bRec.height,m_iLeftAttach,m_iTopAttach));
703 
704 		lineLeft.m_t_linestyle = PP_PropertyMap::linestyle_solid;
705 		lineLeft.m_color = pageCol;
706 		drawLine (lineLeft, bRec.left, bRec.top, bRec.left,  bRec.top + bRec.height,getGraphics());
707 
708 		lineTop.m_t_linestyle = PP_PropertyMap::linestyle_solid;
709 		lineTop.m_color =  pageCol;
710 		drawLine (lineTop, bRec.left, bRec.top, bRec.left + bRec.width,  bRec.top,getGraphics());
711 		if(pBroke && pBroke->getPage() && pBroke->getBrokenTop())
712 		{
713 			UT_sint32 col_x,col_y;
714 			fp_Column * pCol = static_cast<fp_Column *>(pBroke->getBrokenColumn());
715 			pBroke->getPage()->getScreenOffsets(pCol, col_x,col_y);
716 			drawLine (lineTop, bRec.left, col_y, bRec.left + bRec.width,  col_y,getGraphics());
717 		}
718 		lineRight.m_t_linestyle = PP_PropertyMap::linestyle_solid;
719 		lineRight.m_color =  pageCol;
720 		drawLine (lineRight, bRec.left + bRec.width, bRec.top, bRec.left + bRec.width, bRec.top + bRec.height,getGraphics());
721 
722 		lineBottom.m_t_linestyle = PP_PropertyMap::linestyle_solid;
723 		lineBottom.m_color = pageCol;
724 		drawLine (lineBottom, bRec.left, bRec.top + bRec.height, bRec.left + bRec.width , bRec.top + bRec.height,getGraphics());
725 		xxx_UT_DEBUGMSG(("_Clear: pBroke %x \n",pBroke));
726 		if(pBroke && pBroke->getPage() && pBroke->getBrokenBottom())
727 		{
728 			UT_sint32 col_x,col_y;
729 			fp_Column * pCol = static_cast<fp_Column *>(pBroke->getBrokenColumn());
730 			pBroke->getPage()->getScreenOffsets(pCol, col_x,col_y);
731 			UT_sint32 bot = col_y + pCol->getHeight();
732 			xxx_UT_DEBUGMSG(("_clear: Clear broken bottom %d \n",bot));
733 			drawLine (lineBottom, bRec.left, bot, bRec.left + bRec.width,  bot,getGraphics());
734 		}
735 		getGraphics()->setLineWidth(1 );
736 		xxx_UT_DEBUGMSG(("_clear: BRec.top %d  Brec.height %d \n",bRec.top,bRec.height));
737 		//			UT_ASSERT((bRec.left + bRec.width) < getPage()->getWidth());
738 		UT_sint32 srcX = 0;
739 		UT_sint32 srcY = 0;
740 		getFillType().setWidthHeight(getGraphics(),bRec.width,bRec.height);
741 		getLeftTopOffsets(srcX,srcY);
742 		if(getFillType().getParent())
743 		{
744 			srcX += getX();
745 			srcY += getY();
746 			getFillType().getParent()->Fill(getGraphics(),srcX,srcY,bRec.left,bRec.top,bRec.width,bRec.height);
747 		}
748 		else
749 		{
750 			getFillType().Fill(getGraphics(),srcX,srcY,bRec.left,bRec.top,bRec.width,bRec.height);
751 		}
752 		if(getPage())
753 		{
754 			getPage()->expandDamageRect(bRec.left,bRec.top,bRec.width,bRec.height);
755 		}
756 	}
757 	m_bDirty = true;
758 	m_bBgDirty = true;
759 	m_bLinesDrawn = false;
760 }
761 
762 /*!
763   Set width
764   \param iWidth Width of container
765   \todo Should force re-line-break operations on all blocks in the
766         container
767  */
setWidth(UT_sint32 iWidth)768 void fp_CellContainer::setWidth(UT_sint32 iWidth)
769 {
770 	UT_sint32 myWidth = getWidth();
771 	if (iWidth == myWidth)
772 	{
773 		return;
774 	}
775 	if(iWidth < 2)
776 	{
777 		iWidth = 2;
778 	}
779 	clearScreen();
780 	fp_VerticalContainer::setWidth(iWidth);
781 	fl_SectionLayout * pSL = getSectionLayout();
782 	pSL = static_cast<fl_SectionLayout *>(pSL->myContainingLayout());
783 	UT_ASSERT(pSL->getContainerType() == FL_CONTAINER_TABLE);
784 	static_cast<fl_TableLayout *>(pSL)->setDirty();
785 	fl_CellLayout * pCellL = static_cast<fl_CellLayout *>(getSectionLayout());
786 	xxx_UT_DEBUGMSG(("Set Reformat 2 now from table %x in TableLayout %x \n",this,getSectionLayout()));
787 	pCellL->setNeedsReformat(pCellL);
788 	pCellL->_localCollapse();
789 	pCellL->format();
790 	UT_sint32 i = 0;
791 	for(i =0; i< countCons(); i++)
792 	{
793 		fp_Container * pCon = static_cast<fp_Container *>(getNthCon(i));
794 		if(pCon->getContainerType() == FP_CONTAINER_LINE)
795 		{
796 			static_cast<fp_Line *>(pCon)->layout();
797 		}
798 		else if(pCon->getContainerType() == FP_CONTAINER_TABLE)
799 		{
800 			static_cast<fp_TableContainer *>(pCon)->layout();
801 		}
802 		else
803 		{
804 			UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
805 		}
806 	}
807 }
808 
setContainer(fp_Container * pContainer)809 void fp_CellContainer::setContainer(fp_Container * pContainer)
810 {
811 	if (pContainer == getContainer())
812 	{
813 		return;
814 	}
815 
816 	if (getContainer())
817 	{
818 		clearScreen();
819 	}
820 	fp_Container::setContainer(pContainer);
821 	if(pContainer == NULL)
822 	{
823 		return;
824 	}
825 	UT_ASSERT(pContainer->getContainerType() == FP_CONTAINER_TABLE);
826 	fp_TableContainer * pTable = static_cast<fp_TableContainer *>(pContainer);
827 	UT_sint32 iWidth = pTable->getWidth();
828 
829 	fp_CellContainer::setWidth(iWidth);
830 }
831 
getBackground() const832 PP_PropertyMap::Background fp_CellContainer::getBackground () const
833 {
834 	PP_PropertyMap::Background background(m_background);
835 
836 	fl_ContainerLayout * pLayout = getSectionLayout()->myContainingLayout ();
837 	UT_return_val_if_fail(pLayout, background);
838 	UT_return_val_if_fail(pLayout->getContainerType () == FL_CONTAINER_TABLE, background);
839 
840 	fl_TableLayout * table = static_cast<fl_TableLayout *>(pLayout);
841 
842 	const PP_PropertyMap::Background & table_background = table->getBackground ();
843 
844 	/* (unclear how "inherit" differs from "transparent")
845 	 */
846 	if (background.m_t_background != PP_PropertyMap::background_solid)
847 		{
848 			background.m_t_background = table_background.m_t_background;
849 			if (background.m_t_background == PP_PropertyMap::background_solid)
850 				background.m_color = table_background.m_color;
851 		}
852 	if ((background.m_t_background == PP_PropertyMap::background_inherit) ||
853 		(background.m_t_background == PP_PropertyMap::background__unset))
854 		{
855 			background.m_t_background = PP_PropertyMap::background_none;
856 		}
857 
858 	return background;
859 }
860 
861 /* sort out inheritance and defaults of cell-border properties
862  */
s_cell_border_style(PP_PropertyMap::Line & line,const PP_PropertyMap::Line & table_line,const fl_TableLayout * table)863 void s_cell_border_style (PP_PropertyMap::Line & line, const PP_PropertyMap::Line & table_line,
864 						  const fl_TableLayout * table)
865 {
866 	if (line.m_t_color == PP_PropertyMap::color_inherit)
867 		{
868 			line.m_t_color = table_line.m_t_color;
869 			if (line.m_t_color == PP_PropertyMap::color_color)
870 				line.m_color = table_line.m_color;
871 		}
872 	if ((line.m_t_color == PP_PropertyMap::color_inherit) ||
873 		(line.m_t_color == PP_PropertyMap::color__unset))
874 		{
875 			line.m_t_color = PP_PropertyMap::color_color;
876 			line.m_color = table->getDefaultColor ();
877 		}
878 
879 	if (line.m_t_linestyle == PP_PropertyMap::linestyle_inherit)
880 		line.m_t_linestyle = table_line.m_t_linestyle;
881 	if ((line.m_t_linestyle == PP_PropertyMap::linestyle_inherit) ||
882 		(line.m_t_linestyle == PP_PropertyMap::linestyle__unset))
883 		line.m_t_linestyle = PP_PropertyMap::linestyle_solid;
884 
885 	if (line.m_t_thickness == PP_PropertyMap::thickness_inherit)
886 		{
887 			line.m_t_thickness = table_line.m_t_thickness;
888 			if (line.m_t_thickness == PP_PropertyMap::thickness_length)
889 				line.m_thickness = table_line.m_thickness;
890 		}
891 	if ((line.m_t_thickness == PP_PropertyMap::thickness_inherit) ||
892 		(line.m_t_thickness == PP_PropertyMap::thickness__unset))
893 		{
894 			line.m_t_thickness = table_line.m_t_thickness;
895 			UT_sint32 defaultThickness = table->getLineThickness ();
896 			line.m_thickness = (defaultThickness > 0) ? static_cast<UT_uint32>(defaultThickness) : 0;
897 		}
898 
899 	/* if the color is transparent or the thickness is 0, then set the line-style to none
900 	 */
901 	if ((line.m_thickness == 0) || (line.m_t_color == PP_PropertyMap::color_transparent))
902 		{
903 			line.m_t_linestyle = PP_PropertyMap::linestyle_none;
904 		}
905 }
906 
getBottomStyle(const fl_TableLayout * table) const907 PP_PropertyMap::Line fp_CellContainer::getBottomStyle (const fl_TableLayout * table) const
908 {
909 	PP_PropertyMap::Line line(m_lineBottom);
910 	if (table == 0) return line;
911 	const PP_PropertyMap::Line & table_line = table->getBottomStyle ();
912 	s_cell_border_style (line, table_line, table);
913 	return line;
914 }
915 
getLeftStyle(const fl_TableLayout * table) const916 PP_PropertyMap::Line fp_CellContainer::getLeftStyle (const fl_TableLayout * table) const
917 {
918 	PP_PropertyMap::Line line(m_lineLeft);
919 	if (table == 0) return line;
920 	const PP_PropertyMap::Line & table_line = table->getLeftStyle ();
921 	s_cell_border_style (line, table_line, table);
922 	return line;
923 }
924 
getRightStyle(const fl_TableLayout * table) const925 PP_PropertyMap::Line fp_CellContainer::getRightStyle (const fl_TableLayout * table) const
926 {
927 	PP_PropertyMap::Line line(m_lineRight);
928 	if (table == 0) return line;
929 	const PP_PropertyMap::Line & table_line = table->getRightStyle ();
930 	s_cell_border_style (line, table_line, table);
931 	return line;
932 }
933 
getTopStyle(const fl_TableLayout * table) const934 PP_PropertyMap::Line fp_CellContainer::getTopStyle (const fl_TableLayout * table) const
935 {
936 	PP_PropertyMap::Line line(m_lineTop);
937 	if (table == 0) return line;
938 	const PP_PropertyMap::Line & table_line = table->getTopStyle ();
939 	s_cell_border_style (line, table_line, table);
940 	return line;
941 }
942 
isInNestedTable(void) const943 bool fp_CellContainer::isInNestedTable(void) const
944 {
945 	fp_TableContainer * pMaster = static_cast<fp_TableContainer *>(getContainer());
946 	if(pMaster && pMaster->getContainer() && !pMaster->getContainer()->isColumnType())
947 	{
948 		return true;
949 	}
950 	return false;
951 }
952 
setBackground(const PP_PropertyMap::Background & style)953 void fp_CellContainer::setBackground (const PP_PropertyMap::Background & style)
954 {
955 	m_background = style;
956 	PP_PropertyMap::Background background = getBackground ();
957 	if(background.m_t_background == PP_PropertyMap::background_solid)
958 	{
959 		getFillType().setColor(background.m_color);
960 	}
961 }
962 
963 /*!
964  * Given the broken table that contains this cell, calculate the positions
965  * of the left,right,top and bottom edges of the cell.
966  */
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)967 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 )
968 {
969 	UT_return_if_fail(getPage());
970 
971 	bool bNested = false;
972 	if(pBroke == NULL)
973 	{
974 		pBroke = static_cast<fp_TableContainer *>(getContainer());
975 	}
976 	if(isInNestedTable())
977 	{
978 		bNested = true;
979 	}
980 	if(pBroke && pBroke->getPage())
981 	{
982 		if(pG->queryProperties(GR_Graphics::DGP_SCREEN) && !pBroke->getPage()->isOnScreen())
983 		{
984 			return;
985 		}
986 	}
987 //
988 // Now correct if iTop or iBot is off the page.
989 //
990 	UT_sint32 col_x;
991 	UT_sint32 offy =0;
992 	UT_sint32 offx =0;
993 	fp_Page * pPage = pBroke->getPage();
994 	if(pPage == NULL)
995 	{
996 //
997 // Can happen while loading.
998 //
999 		return;
1000 	}
1001 
1002 	pPage = pBroke->getPage();
1003 	if(getContainer()->getContainerType() == FP_CONTAINER_FRAME)
1004 	{
1005 		fp_FrameContainer * pFC = static_cast<fp_FrameContainer *>(getContainer());
1006 		getView()->getPageScreenOffsets(pPage,col_x,col_y);
1007 		col_x += pFC->getX();
1008 		col_y += pFC->getY();
1009 		pCol = static_cast<fp_Column *>(pFC->getColumn());
1010 	}
1011 	else if(getContainer()->getContainerType() == FP_CONTAINER_COLUMN_SHADOW)
1012 	{
1013 		pShadow =  static_cast<fp_ShadowContainer *>(pBroke->getContainer());
1014 		if(pShadow)
1015 		{
1016 			pShadow->getPage()->getScreenOffsets(pShadow, col_x,col_y);
1017 		}
1018 		else
1019 		{
1020 			pPage->getScreenOffsets(pShadow, col_x,col_y);
1021 		}
1022 
1023 	}
1024 	else if(pBroke && (pBroke->getBrokenColumn()->getContainerType()  == FP_CONTAINER_COLUMN_SHADOW))
1025 	{
1026 		pShadow =  static_cast<fp_ShadowContainer *>(pBroke->getContainer());
1027 		if(pShadow)
1028 		{
1029 			pShadow->getPage()->getScreenOffsets(pShadow, col_x,col_y);
1030 		}
1031 		else
1032 		{
1033 			pPage->getScreenOffsets(pShadow, col_x,col_y);
1034 		}
1035 
1036 	}
1037 	else
1038 	{
1039 		pCol = static_cast<fp_Column *>(pBroke->getBrokenColumn());
1040 		if(pCol)
1041 		{
1042 			pCol->getPage()->getScreenOffsets(pCol, col_x,col_y);
1043 		}
1044 		else
1045 		{
1046 			pPage->getScreenOffsets(pCol, col_x,col_y);
1047 		}
1048 	}
1049 	bDoClear = true;
1050 	if(pPage->getDocLayout()->getView() && pG->queryProperties(GR_Graphics::DGP_PAPER))
1051 	{
1052 //
1053 // Now correct for printing
1054 //
1055 		bDoClear = false;
1056 		UT_sint32 xdiff,ydiff;
1057 		pPage->getDocLayout()->getView()->getPageScreenOffsets(pPage, xdiff, ydiff);
1058 		col_y = col_y - ydiff;
1059 		col_x = col_x - xdiff;
1060 		if(pPage->getDocLayout()->getView()->getViewMode() != VIEW_PRINT)
1061 		{
1062 			col_y += static_cast<fl_DocSectionLayout *>(getSectionLayout()->getDocSectionLayout())->getTopMargin();
1063 		}
1064 	}
1065 	if(pBroke->getMasterTable())
1066 	{
1067 		offx = pBroke->getMasterTable()->getX();
1068 		if(pBroke->getMasterTable()->getFirstBrokenTable() == pBroke)
1069 		{
1070 			offy = pBroke->getMasterTable()->getY();
1071 		}
1072 		else
1073 		{
1074 			offy = 0;
1075 		}
1076 	}
1077 	if(bNested && pBroke)
1078 	{
1079 		fp_Container * pCon = static_cast<fp_Container *>(pBroke->getContainer());
1080 		fp_TableContainer * pCurTab = pBroke;
1081 		while(!pCon->isColumnType())
1082 		{
1083 			UT_sint32 iycon = pCon->getY();
1084 			offy += iycon;
1085 			offx += pCon->getX();
1086 			if(pCon->getContainerType() == FP_CONTAINER_TABLE)
1087 			{
1088 				if(pCol)
1089 				{
1090 					pCurTab = pCol->getCorrectBrokenTable(static_cast<fp_Container *>(pCurTab));
1091 				}
1092 				else
1093 				{
1094 					pCurTab = static_cast<fp_TableContainer *>(pCon);
1095 			    }
1096 				if(pCurTab->isThisBroken() && (pCurTab != pCurTab->getMasterTable()->getFirstBrokenTable()))
1097 				{
1098 
1099 					offy = offy + pCurTab->getY() - iycon;
1100 				}
1101 				if(offy < pCurTab->getYBreak())
1102 				{
1103 					offy = 0;
1104 				}
1105 				else
1106 				{
1107 					offy -= pCurTab->getYBreak();
1108 				}
1109 			}
1110 			pCon = pCon->getContainer();
1111 		}
1112 	}
1113 	iLeft = col_x + m_iLeft + offx;
1114 	iRight = col_x + m_iRight + offx;
1115 	iTop = col_y + m_iTopY + offy;
1116 	iBot = col_y + m_iBotY + offy;
1117 }
1118 /*!
1119  * Draw background and lines around a cell in a broken table.
1120  */
drawLines(fp_TableContainer * pBroke,GR_Graphics * pG,bool bDoClear)1121 void fp_CellContainer::drawLines(fp_TableContainer * pBroke,GR_Graphics * pG, bool bDoClear)
1122 {
1123 	xxx_UT_DEBUGMSG(("Doing drawlines for cell %x \n",this));
1124 	UT_return_if_fail(getPage());
1125 
1126 	if(pBroke == NULL)
1127 	{
1128 		pBroke = static_cast<fp_TableContainer *>(getContainer());
1129 	}
1130 	if(pBroke && pBroke->getPage())
1131 	{
1132 		if(pG->queryProperties(GR_Graphics::DGP_SCREEN) && !pBroke->getPage()->isOnScreen())
1133 		{
1134 			return;
1135 		}
1136 	}
1137 // Lookup table properties to get the line thickness, etc.
1138 
1139 	fl_ContainerLayout * pLayout = getSectionLayout()->myContainingLayout ();
1140 	UT_return_if_fail(pLayout->getContainerType () == FL_CONTAINER_TABLE);
1141 
1142 	fl_TableLayout * pTableLayout = static_cast<fl_TableLayout *>(pLayout);
1143 
1144 	PP_PropertyMap::Line lineBottom = getBottomStyle (pTableLayout);
1145 	PP_PropertyMap::Line lineLeft   = getLeftStyle   (pTableLayout);
1146 	PP_PropertyMap::Line lineRight  = getRightStyle  (pTableLayout);
1147 	PP_PropertyMap::Line lineTop    = getTopStyle    (pTableLayout);
1148 	fp_Page * pPage = pBroke->getPage();
1149 
1150 	if(pPage == NULL)
1151 	{
1152 //
1153 // Can happen while loading.
1154 //
1155 		return;
1156 	}
1157 	bool bDrawTop = true;
1158 	bool bDrawBot = true;
1159 	xxx_UT_DEBUGMSG(("m_iBotY %d \n",m_iBotY));
1160 	m_bLinesDrawn = true;
1161 	UT_sint32 iLeft,iRight,iTop,iBot = 0;
1162 	UT_sint32 col_y = 0;
1163 	fp_Column * pCol = NULL;
1164 	fp_ShadowContainer * pShadow = NULL;
1165 	bool doClear2 =false;
1166 	bool bTopScreen = false;
1167 	bool bBotScreen = false;
1168 	getScreenPositions(pBroke,pG,iLeft,iRight,iTop,iBot,col_y,pCol,pShadow,doClear2 );
1169 	if(pBroke != NULL)
1170 	{
1171 		if(m_iBotY < pBroke->getYBreak())
1172 		{
1173 //
1174 // Cell is above this page
1175 //
1176 			xxx_UT_DEBUGMSG(("Don't drawlines because M-IBotY < pBroke->getYbreak \n",m_iBotY,pBroke->getYBreak()));
1177 			return;
1178 		}
1179 		if(m_iTopY > pBroke->getYBottom())
1180 		{
1181 //
1182 // Cell is below this page
1183 //
1184 			xxx_UT_DEBUGMSG(("Don't drawlines because m_iTopY > pBroke->getYBottom \n",m_iTopY, pBroke->getYBottom()));
1185 			return;
1186 		}
1187 		iTop -= pBroke->getYBreak();
1188 		iBot -= pBroke->getYBreak();
1189 		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));
1190 		if(iTop < col_y)
1191 		{
1192 			xxx_UT_DEBUGMSG(("iTop < col_y !! iTop %d col_y %d row is %d \n",iTop,col_y,getTopAttach()));
1193 			iTop = col_y;
1194 			bDrawTop = true;
1195 			bTopScreen = true;
1196 			if(pBroke != NULL)
1197 			{
1198 				pBroke->setBrokenTop(true);
1199 			}
1200 		}
1201 		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));
1202 		UT_sint32 iColHeight = 0;
1203 		if(pCol)
1204 		{
1205 			iColHeight = pCol->getHeight();
1206 		}
1207 		else if(pShadow)
1208 		{
1209 			iColHeight = pShadow->getHeight();
1210 		}
1211 
1212 		if(iBot > col_y + iColHeight && (!pBroke || pBroke->getNext()))
1213 		{
1214 			if (pBroke)
1215 			{
1216 				iBot += pBroke->getYBottom() + 1 - pBroke->getYOfRow(getBottomAttach());
1217 				iBot +=	pBroke->getAdditionalBottomSpace();
1218 				pBroke->setBrokenBottom(true);
1219 			}
1220 			else
1221 			{
1222 				iBot =  col_y + iColHeight;
1223 			}
1224 			bDrawBot = true;
1225 			bBotScreen = true;
1226 		}
1227 		//
1228 		// Now get a rectangle to calculate draw arguments
1229 		//
1230 		// This code might eventually replace a lot of the code above but
1231 		// it needs more testing and tweaking - particularly for nested tables.
1232 		//
1233 // 		UT_Rect bRec;
1234 // 		fp_Page * pLinePage;
1235 // 		_getBrokenRect(pBroke, pLinePage, bRec);
1236 // 		if(pLinePage != pPage)
1237 // 		{
1238 // 			UT_DEBUGMSG(("Pages don't match! \n"));
1239 // 			return;
1240 // 		}
1241 // 		iLeft = bRec.left;
1242 // 		iTop = bRec.top;
1243 // 		iBot = iTop + bRec.height;
1244 // 		iRight = iLeft + bRec.width;
1245 		m_bDrawRight = true;
1246 		UT_sint32 onePix = pG->tlu(1)+1;
1247 		//
1248 		// the was put in to fix cairo draws but it makes windows look bad.
1249 		// Fixme for cairo a different way.
1250 		//
1251 		onePix = 0;
1252 		//
1253 		// Have to draw white first because drawing is additive
1254 		//
1255 		PP_PropertyMap::Line clineBottom = getBottomStyle (pTableLayout);
1256 		PP_PropertyMap::Line clineLeft   = getLeftStyle   (pTableLayout);
1257 		PP_PropertyMap::Line clineRight  = getRightStyle  (pTableLayout);
1258 		PP_PropertyMap::Line clineTop    = getTopStyle    (pTableLayout);
1259 
1260 		UT_RGBColor white(255,255,255);
1261 		white = *pPage->getFillType().getColor();
1262 
1263 		//
1264 		// Might needs these later
1265 		//
1266 		UT_sint32 iextLeft=0;
1267 		UT_sint32 iextRight=0;
1268 		UT_sint32 iextTop=0;
1269 		UT_sint32 iextBot= 0;
1270 
1271 		if (m_bDrawLeft)
1272 		{
1273 			if(bDoClear)
1274 			{
1275 				clineLeft.m_color = white;
1276 				clineLeft.m_thickness  += 3*onePix;
1277 				drawLine (clineLeft, iLeft, iTop, iLeft,  iBot,pG);
1278 			}
1279 			else
1280 		    {
1281 				if(bTopScreen)
1282 					iextTop = 0;
1283 				if(bBotScreen)
1284 					iextBot = 0;
1285 				drawLine(lineLeft, iLeft, iTop-iextTop, iLeft, iBot+iextBot,pG);
1286 			}
1287 		}
1288 		if(m_bDrawTop || bDrawTop)
1289 		{
1290 			if(bDoClear)
1291 			{
1292 				clineTop.m_color = white;
1293 				clineTop.m_thickness  += 3*onePix;
1294 				drawLine(clineTop, iLeft, iTop, iRight, iTop,pG);
1295 			}
1296 			else
1297 			{
1298 				drawLine(lineTop, iLeft-iextLeft, iTop, iRight+iextRight, iTop,pG);
1299 			}
1300 		}
1301 		if(m_bDrawRight)
1302 		{
1303 			if(bDoClear)
1304 			{
1305 				clineRight.m_color = white;
1306 				clineRight.m_thickness  += 3*onePix;
1307 				drawLine(clineRight, iRight, iTop, iRight, iBot,pG);
1308 			}
1309 			else
1310 			{
1311 				if(bTopScreen)
1312 					iextTop = 0;
1313 				if(bBotScreen)
1314 					iextBot = 0;
1315 				drawLine(lineRight, iRight, iTop-iextTop, iRight, iBot+iextBot,pG);
1316 			}
1317 		}
1318 		if(m_bDrawBot || bDrawBot)
1319 		{
1320 			if(bDoClear)
1321 			{
1322 				clineBottom.m_color = white;
1323 				clineBottom.m_thickness  += 3*onePix;
1324 				drawLine(clineBottom, iLeft, iBot, iRight, iBot,pG);
1325 			}
1326 			else
1327 			{
1328 				drawLine(lineBottom, iLeft-iextLeft, iBot, iRight+iextRight, iBot,pG);
1329 			}
1330 		}
1331 	}
1332 }
1333 
1334 /*!
1335  *   |
1336  *   |_
1337  *
1338  * Extend the cell line at the left top corner if needed
1339  */
1340 #if 0
1341 //
1342 // These methods not needed for 2.8 but might be for 2.10
1343 //
1344 void  fp_CellContainer::extendLeftTop(PP_PropertyMap::Line & line,GR_Graphics * pG,UT_sint32 & iextTop)
1345 {
1346 	iextTop = 0;
1347 	if(getTopAttach() == 0)
1348 	{
1349 		return;
1350 	}
1351 	fp_TableContainer * pTab = static_cast<fp_TableContainer *>(getContainer());
1352 	if(pTab == NULL)
1353 	{
1354 		return;
1355 	}
1356 	fp_CellContainer * pCell = pTab->getCellAtRowColumn(getTopAttach()-1,getLeftAttach());
1357 	if(pCell->getLeftAttach() != getLeftAttach())
1358 	{
1359 		return;
1360 	}
1361 	iextTop = line.m_thickness;
1362 	UT_sint32 onePix = pG->tlu(1)+1;
1363 	iextTop += 3*onePix;
1364 }
1365 
1366 
1367 /*!
1368  *    _
1369  *   |
1370  *   |
1371  *
1372  * Extend the cell line at the left bot corner if needed
1373  */
1374 void  fp_CellContainer::extendLeftBot(PP_PropertyMap::Line & line,GR_Graphics * pG,UT_sint32 & iextBot)
1375 {
1376 	iextBot = 0;
1377 	fp_TableContainer * pTab = static_cast<fp_TableContainer *>(getContainer());
1378 	if(pTab == NULL)
1379 	{
1380 		return;
1381 	}
1382 	if(getBottomAttach() == pTab->getNumRows())
1383 	{
1384 		return;
1385 	}
1386 	fp_CellContainer * pCell = pTab->getCellAtRowColumn(getTopAttach()+1,getLeftAttach());
1387 	if(!pCell)
1388 		return;
1389 	if(pCell->getLeftAttach() != getLeftAttach())
1390 	{
1391 		return;
1392 	}
1393 	iextBot = line.m_thickness;
1394 	UT_sint32 onePix = pG->tlu(1)+1;
1395 	iextBot += 3*onePix;
1396 }
1397 
1398 /*!
1399  *    |
1400  *   _|
1401  *
1402  * Extend the cell line at the right top corner if needed
1403  */
1404 void  fp_CellContainer::extendRightTop(PP_PropertyMap::Line & line,GR_Graphics * pG,UT_sint32 & iextTop)
1405 {
1406 	iextTop = 0;
1407 	if(getTopAttach() == 0)
1408 	{
1409 		return;
1410 	}
1411 	fp_TableContainer * pTab = static_cast<fp_TableContainer *>(getContainer());
1412 	if(pTab == NULL)
1413 	{
1414 		return;
1415 	}
1416 	fp_CellContainer * pCell = pTab->getCellAtRowColumn(getTopAttach()-1,getLeftAttach());
1417 	if(!pCell)
1418 		return;
1419 	if(pCell->getRightAttach() != getRightAttach())
1420 	{
1421 		return;
1422 	}
1423 	iextTop = line.m_thickness;
1424 	UT_sint32 onePix = pG->tlu(1)+1;
1425 	iextTop += 3*onePix;
1426 }
1427 
1428 
1429 /*!
1430  *   _
1431  *    |
1432  *    |
1433  *
1434  * Extend the cell line at the right bot corner if needed
1435  */
1436 void  fp_CellContainer::extendRightBot(PP_PropertyMap::Line & line,GR_Graphics * pG,UT_sint32 & iextBot)
1437 {
1438 	iextBot = 0;
1439 	fp_TableContainer * pTab = static_cast<fp_TableContainer *>(getContainer());
1440 	if(pTab == NULL)
1441 	{
1442 		return;
1443 	}
1444 	if(getBottomAttach() == pTab->getNumRows())
1445 	{
1446 		return;
1447 	}
1448 	fp_CellContainer * pCell = pTab->getCellAtRowColumn(getTopAttach()+1,getLeftAttach());
1449 	if(!pCell)
1450 		return;
1451 	if(pCell->getRightAttach() != getRightAttach())
1452 	{
1453 		return;
1454 	}
1455 	iextBot = line.m_thickness;
1456 	UT_sint32 onePix = pG->tlu(1)+1;
1457 	iextBot += 3*onePix;
1458 }
1459 
1460 /*!
1461  *  _ _
1462  *     |
1463  *
1464  *
1465  * Extend the cell line at the left top corner if needed
1466  */
1467 void  fp_CellContainer::extendTopLeft(PP_PropertyMap::Line & line,GR_Graphics * pG,UT_sint32 & iextLeft)
1468 {
1469 	iextLeft = 0;
1470 	fp_TableContainer * pTab = static_cast<fp_TableContainer *>(getContainer());
1471 	if(pTab == NULL)
1472 	{
1473 		return;
1474 	}
1475 	if(getLeftAttach() == 0)
1476 	{
1477 		return;
1478 	}
1479 	fp_CellContainer * pCell = pTab->getCellAtRowColumn(getTopAttach(),getLeftAttach()-1);
1480 	if(!pCell)
1481 		return;
1482 	if(pCell->getTopAttach() != getTopAttach())
1483 	{
1484 		return;
1485 	}
1486 	iextLeft = line.m_thickness;
1487 	UT_sint32 onePix = pG->tlu(1)+1;
1488 	iextLeft += 3*onePix;
1489 }
1490 
1491 
1492 /*!
1493  *
1494  *   _ _
1495  *  |
1496  *
1497  * Extend the cell line at the right top corner if needed
1498  */
1499 void  fp_CellContainer::extendTopRight(PP_PropertyMap::Line & line,GR_Graphics * pG,UT_sint32 & iextRight)
1500 {
1501 	iextRight = 0;
1502 	fp_TableContainer * pTab = static_cast<fp_TableContainer *>(getContainer());
1503 	if(pTab == NULL)
1504 	{
1505 		return;
1506 	}
1507 	if(getRightAttach() >=  pTab->getNumCols())
1508 	{
1509 		return;
1510 	}
1511 	fp_CellContainer * pCell = pTab->getCellAtRowColumn(getTopAttach(),getRightAttach());
1512 	if(!pCell)
1513 		return;
1514 	if(pCell->getTopAttach() != getTopAttach())
1515 	{
1516 		return;
1517 	}
1518 	iextRight = line.m_thickness;
1519 	UT_sint32 onePix = pG->tlu(1)+1;
1520 	iextRight += 3*onePix;
1521 }
1522 
1523 
1524 /*!
1525  *  _ _|
1526  *
1527  *
1528  * Extend the cell line at the left Bot corner if needed
1529  */
1530 void  fp_CellContainer::extendBotLeft(PP_PropertyMap::Line & line,GR_Graphics * pG,UT_sint32 & iextLeft)
1531 {
1532 	iextLeft = 0;
1533 	fp_TableContainer * pTab = static_cast<fp_TableContainer *>(getContainer());
1534 	if(pTab == NULL)
1535 	{
1536 		return;
1537 	}
1538 	if(getLeftAttach() == 0)
1539 	{
1540 		return;
1541 	}
1542 	fp_CellContainer * pCell = pTab->getCellAtRowColumn(getTopAttach(),getLeftAttach()-1);
1543 	if(!pCell)
1544 		return;
1545 	if(pCell->getBottomAttach() != getBottomAttach())
1546 	{
1547 		return;
1548 	}
1549 	iextLeft = line.m_thickness;
1550 	UT_sint32 onePix = pG->tlu(1)+1;
1551 	iextLeft += 3*onePix;
1552 }
1553 
1554 
1555 /*!
1556  *
1557  *  |_ _
1558  *
1559  * Extend the cell line at the right bot corner if needed
1560  */
1561 void  fp_CellContainer::extendBotRight(PP_PropertyMap::Line & line,GR_Graphics * pG,UT_sint32 & iextRight)
1562 {
1563 	iextRight = 0;
1564 	fp_TableContainer * pTab = static_cast<fp_TableContainer *>(getContainer());
1565 	if(pTab == NULL)
1566 	{
1567 		return;
1568 	}
1569 	if(getRightAttach() >=  pTab->getNumCols())
1570 	{
1571 		return;
1572 	}
1573 	fp_CellContainer * pCell = pTab->getCellAtRowColumn(getTopAttach(),getRightAttach());
1574 	if(!pCell)
1575 		return;
1576 	if(pCell->getBottomAttach() != getBottomAttach())
1577 	{
1578 		return;
1579 	}
1580 	iextRight = line.m_thickness;
1581 	UT_sint32 onePix = pG->tlu(1)+1;
1582 	iextRight += 3*onePix;
1583 }
1584 #endif
1585 
1586 /*!
1587  * Draw lines around neighbouring cells. Use to fix artifacts of editting.
1588  */
drawLinesAdjacent(void)1589 void fp_CellContainer::drawLinesAdjacent(void)
1590 {
1591 	UT_sint32 row = getTopAttach();
1592 	UT_sint32 col_right = getRightAttach();
1593 	UT_sint32 col_left = getLeftAttach();
1594 	fp_TableContainer * pTab = static_cast<fp_TableContainer *>(getContainer());
1595 	if(pTab == NULL)
1596 	{
1597 		return;
1598 	}
1599 	bool bDoRight = false;
1600 	if(col_right < pTab->getNumCols())
1601 	{
1602 		bDoRight = true;
1603 	}
1604 	bool bDoLeft = false;
1605 	if(col_left >= 0)
1606 	{
1607 		bDoLeft = true;
1608 	}
1609 	fp_TableContainer * pBroke = pTab->getFirstBrokenTable();
1610 	while(pBroke)
1611 	{
1612 		drawLines(pBroke,getGraphics(),true);
1613 		if(bDoRight)
1614 		{
1615 			fp_CellContainer * pCell = pTab->getCellAtRowColumn(row,col_right);
1616 			if(pCell)
1617 			{
1618 				pCell->drawLines(pBroke,getGraphics(),true);
1619 			}
1620 		}
1621 		if(bDoLeft)
1622 		{
1623 			fp_CellContainer * pCell = pTab->getCellAtRowColumn(row,col_left);
1624 			if(pCell)
1625 			{
1626 				pCell->drawLines(pBroke,getGraphics(),true);
1627 			}
1628 		}
1629 		drawLines(pBroke,getGraphics(),false);
1630 		if(bDoRight)
1631 		{
1632 			fp_CellContainer * pCell = pTab->getCellAtRowColumn(row,col_right);
1633 			if(pCell)
1634 			{
1635 				pCell->drawLines(pBroke,getGraphics(),false);
1636 			}
1637 		}
1638 		if(bDoLeft)
1639 		{
1640 			fp_CellContainer * pCell = pTab->getCellAtRowColumn(row,col_left);
1641 			if(pCell)
1642 			{
1643 				pCell->drawLines(pBroke,getGraphics(),false);
1644 			}
1645 		}
1646 		pBroke = static_cast<fp_TableContainer *>(pBroke->getNext());
1647 	}
1648 }
1649 
1650 
1651 /*!
1652  Draw container outline
1653  \param pDA Draw arguments
1654  \param pBroke fp_TableContainer pointer to broken table
1655  */
_drawBoundaries(dg_DrawArgs * pDA,fp_TableContainer * pBroke)1656 void fp_CellContainer::_drawBoundaries(dg_DrawArgs* pDA, fp_TableContainer * pBroke)
1657 {
1658 	UT_return_if_fail(getPage());
1659 
1660 	if(getPage()->getDocLayout()->getView() == NULL)
1661 	{
1662 		return;
1663 	}
1664 	if(pBroke && pBroke->getPage())
1665 	{
1666 		if(pDA->pG->queryProperties(GR_Graphics::DGP_SCREEN) && !pBroke->getPage()->isOnScreen())
1667 		{
1668 			return;
1669 		}
1670 		if(pBroke->getYBreak() > (getY() + getHeight()))
1671 		{
1672 			return;
1673 		}
1674 	}
1675     if(getPage()->getDocLayout()->getView()->getShowPara() && getGraphics()->queryProperties(GR_Graphics::DGP_SCREEN)){
1676         UT_sint32 xoffBegin = pDA->xoff + getX();
1677         UT_sint32 yoffBegin = pDA->yoff + getY();
1678         UT_sint32 xoffEnd = pDA->xoff + getX() + getWidth() - getGraphics()->tlu(1);
1679         UT_sint32 yoffEnd = pDA->yoff + getY() + getHeight() - getGraphics()->tlu(1);
1680 
1681 		UT_RGBColor clrShowPara(127,127,127);
1682 
1683 		GR_Painter painter(getGraphics());
1684 
1685 		getGraphics()->setColor(clrShowPara);
1686 		xxx_UT_DEBUGMSG(("SEVIOR: cell boundaries xleft %d xright %d ytop %d ybot %d \n",xoffBegin,xoffEnd,yoffBegin,yoffEnd));
1687         painter.drawLine(xoffBegin, yoffBegin, xoffEnd, yoffBegin);
1688         painter.drawLine(xoffBegin, yoffEnd, xoffEnd, yoffEnd);
1689         painter.drawLine(xoffBegin, yoffBegin, xoffBegin, yoffEnd);
1690         painter.drawLine(xoffEnd, yoffBegin, xoffEnd, yoffEnd);
1691     }
1692 }
1693 
1694 /*!
1695  * Return the topmost table in this structure. The one embedded in the
1696  * column.
1697  */
getTopmostTable() const1698 fp_TableContainer * fp_CellContainer::getTopmostTable() const
1699 {
1700 	fp_Container * pUp = getContainer();
1701 	fp_Container * pPrev = pUp;
1702 	while(pUp->getContainerType() != FP_CONTAINER_COLUMN)
1703 	{
1704 		pPrev = pUp;
1705 		pUp = pUp->getContainer();
1706 	}
1707 	if(pPrev->getContainerType() == FP_CONTAINER_TABLE)
1708 	{
1709 		return static_cast<fp_TableContainer *>(pPrev);
1710 	}
1711 	UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
1712 	return NULL;
1713 }
1714 /*!
1715  * Return true if the segment of the cell within a broken table pBroke contains a footnote references
1716  */
containsFootnoteReference(fp_TableContainer * pBroke) const1717 bool fp_CellContainer::containsFootnoteReference(fp_TableContainer * pBroke) const
1718 {
1719 	// First check if there are footnotes in the whole cell
1720 	fl_CellLayout * pCL = static_cast<fl_CellLayout *>(getSectionLayout());
1721 	if (!pCL->containsFootnoteLayouts())
1722 	{
1723 		return false;
1724 	}
1725 	else if (!pBroke || ((getY() >= pBroke->getYBreak()) &&
1726 						 (getY() + getHeight() <= pBroke->getYBottom())))
1727 	{
1728 		// the complete cell is within the broken table
1729 		return true;
1730 	}
1731 
1732 	// Check if there are footnotes in the segment of the cell within the broken table
1733 
1734 	fp_Container * pCon = getFirstContainer();
1735 	bool bFound = false;
1736 	bool bFirst = false;
1737 	while(pCon && !bFound)
1738 	{
1739 		if (pBroke->isInBrokenTable(this,pCon))
1740 		{
1741 			if(pCon->getContainerType() == FP_CONTAINER_LINE)
1742 			{
1743 				fp_Line * pLine = static_cast<fp_Line *>(pCon);
1744 				if(pLine->containsFootnoteReference())
1745 				{
1746 					bFound = true;
1747 				}
1748 			}
1749 			else if(pCon->getContainerType() == FP_CONTAINER_TABLE)
1750 			{
1751 				fp_TableContainer *pTab = static_cast<fp_TableContainer *>(pCon);
1752 				if(pTab->containsFootnoteReference())
1753 				{
1754 					bFound = true;
1755 				}
1756 			}
1757 			bFirst = true;
1758 		}
1759 		else if (bFirst)
1760 		{
1761 			// this container is in the following broken table
1762 			break;
1763 		}
1764 		pCon = static_cast<fp_Container*>(pCon->getNext());
1765 	}
1766 	return bFound;
1767 }
1768 
1769 /*!
1770  * This method returns a vector of all the footnote layouts in the segment of the cell
1771  within a broke table pBroke
1772  */
getFootnoteContainers(UT_GenericVector<fp_FootnoteContainer * > * pVecFoots,fp_TableContainer * pBroke)1773 bool fp_CellContainer::getFootnoteContainers(UT_GenericVector<fp_FootnoteContainer*>* pVecFoots,
1774 											 fp_TableContainer * pBroke)
1775 {
1776 	bool bWholeCell = (!pBroke || ((getY() >= pBroke->getYBreak()) &&
1777 								   (getY() + getHeight() <= pBroke->getYBottom())));
1778 	fp_Container * pCon = getFirstContainer();
1779 	bool bFound = false;
1780 	bool bFirst = false;
1781 	while(pCon)
1782 	{
1783 		if (bWholeCell || pBroke->isInBrokenTable(this,pCon))
1784 		{
1785 			if(pCon->getContainerType() == FP_CONTAINER_LINE)
1786 			{
1787 				fp_Line * pLine = static_cast<fp_Line *>(pCon);
1788 				UT_GenericVector<fp_FootnoteContainer*> vecFC;
1789 				pLine->getFootnoteContainers(&vecFC);
1790 				if (vecFC.getItemCount() > 0)
1791 				{
1792 					bFound = true;
1793 					UT_sint32 i = 0;
1794 					for(i = 0; i < vecFC.getItemCount();i++)
1795 					{
1796 						pVecFoots->addItem(vecFC.getNthItem(i));
1797 					}
1798 				}
1799 			}
1800 			else if(pCon->getContainerType() == FP_CONTAINER_TABLE)
1801 			{
1802 				fp_TableContainer *pTab = static_cast<fp_TableContainer *>(pCon);
1803 				if(pTab->containsFootnoteReference())
1804 				{
1805 					bFound = true;
1806 					UT_GenericVector<fp_FootnoteContainer*> vecFC;
1807 					pTab->getFootnoteContainers(&vecFC);
1808 					UT_sint32 i = 0;
1809 					for(i = 0; i < vecFC.getItemCount();i++)
1810 					{
1811 						pVecFoots->addItem(vecFC.getNthItem(i));
1812 					}
1813 				}
1814 			}
1815 			bFirst = true;
1816 		}
1817 		else if (bFirst)
1818 		{
1819 			break;
1820 		}
1821 		pCon = static_cast<fp_Container*>(pCon->getNext());
1822 	}
1823 	return bFound;
1824 }
1825 
1826 
1827 /*!
1828  * Return true if the segment of the cell within a broken table pBroke contains an annotation
1829  */
containsAnnotations(fp_TableContainer * pBroke) const1830 bool fp_CellContainer::containsAnnotations(fp_TableContainer * pBroke) const
1831 {
1832 	// First check if there are annotations in the whole cell
1833 	fl_CellLayout * pCL = static_cast<fl_CellLayout *>(getSectionLayout());
1834 	if (!pCL->containsAnnotationLayouts())
1835 	{
1836 		return false;
1837 	}
1838 	else if (!pBroke || ((getY() >= pBroke->getYBreak()) &&
1839 						 (getY() + getHeight() <= pBroke->getYBottom())))
1840 	{
1841 		// the complete cell is within the broken table
1842 		return true;
1843 	}
1844 
1845 	// Check if there are annotations in the segment of the cell within the broken table
1846 
1847 	fp_Container * pCon = getFirstContainer();
1848 	bool bFound = false;
1849 	bool bFirst = false;
1850 	while(pCon && !bFound)
1851 	{
1852 		if (pBroke->isInBrokenTable(this,pCon))
1853 		{
1854 			if(pCon->getContainerType() == FP_CONTAINER_LINE)
1855 			{
1856 				fp_Line * pLine = static_cast<fp_Line *>(pCon);
1857 				if(pLine->containsAnnotations())
1858 				{
1859 					bFound = true;
1860 				}
1861 			}
1862 			else if(pCon->getContainerType() == FP_CONTAINER_TABLE)
1863 			{
1864 				fp_TableContainer *pTab = static_cast<fp_TableContainer *>(pCon);
1865 				if(pTab->containsAnnotations())
1866 				{
1867 					bFound = true;
1868 				}
1869 			}
1870 			bFirst = true;
1871 		}
1872 		else if (bFirst)
1873 		{
1874 			// this container is in the following broken table
1875 			break;
1876 		}
1877 		pCon = static_cast<fp_Container*>(pCon->getNext());
1878 	}
1879 	return bFound;
1880 }
1881 
1882 /*!
1883  * This method returns a vector of all the annotation layouts in the segment of the cell
1884  within a broke table pBroke
1885  */
getAnnotationContainers(UT_GenericVector<fp_AnnotationContainer * > * pVecAnns,fp_TableContainer * pBroke)1886 bool fp_CellContainer::getAnnotationContainers(UT_GenericVector<fp_AnnotationContainer*>* pVecAnns,
1887 											 fp_TableContainer * pBroke)
1888 {
1889 	bool bWholeCell = (!pBroke || ((getY() >= pBroke->getYBreak()) &&
1890 								   (getY() + getHeight() <= pBroke->getYBottom())));
1891 	fp_Container * pCon = getFirstContainer();
1892 	bool bFound = false;
1893 	bool bFirst = false;
1894 	while(pCon)
1895 	{
1896 		if (bWholeCell || pBroke->isInBrokenTable(this,pCon))
1897 		{
1898 			if(pCon->getContainerType() == FP_CONTAINER_LINE)
1899 			{
1900 				fp_Line * pLine = static_cast<fp_Line *>(pCon);
1901 				UT_GenericVector<fp_AnnotationContainer*> vecAC;
1902 				pLine->getAnnotationContainers(&vecAC);
1903 				if (vecAC.getItemCount() > 0)
1904 				{
1905 					bFound = true;
1906 					UT_sint32 i = 0;
1907 					for(i = 0; i < vecAC.getItemCount();i++)
1908 					{
1909 						pVecAnns->addItem(vecAC.getNthItem(i));
1910 					}
1911 				}
1912 			}
1913 			else if(pCon->getContainerType() == FP_CONTAINER_TABLE)
1914 			{
1915 				fp_TableContainer *pTab = static_cast<fp_TableContainer *>(pCon);
1916 				if(pTab->containsAnnotations())
1917 				{
1918 					bFound = true;
1919 					UT_GenericVector<fp_AnnotationContainer*> vecAC;
1920 					pTab->getAnnotationContainers(&vecAC);
1921 					UT_sint32 i = 0;
1922 					for(i = 0; i < vecAC.getItemCount();i++)
1923 					{
1924 						pVecAnns->addItem(vecAC.getNthItem(i));
1925 					}
1926 				}
1927 			}
1928 			bFirst = true;
1929 		}
1930 		else if (bFirst)
1931 		{
1932 			break;
1933 		}
1934 		pCon = static_cast<fp_Container*>(pCon->getNext());
1935 	}
1936 	return bFound;
1937 }
1938 
1939 /*!
1940  * Return the x coordinate offset of this cell.
1941  * We need to know the line for situations where the cell is broken over
1942  * different pages.
1943  */
getCellX(fp_Line *) const1944 UT_sint32 fp_CellContainer::getCellX(fp_Line * /*pLine*/) const
1945 {
1946 	return 0;
1947 }
1948 
1949 /*!
1950  * Return the y coordinate offset of this cell.
1951  * We need to know the line for situations where the cell is broken over
1952  * different pages.
1953  */
getCellY(fp_Line *) const1954 UT_sint32 fp_CellContainer::getCellY(fp_Line * /*pLine*/) const
1955 {
1956 	fp_TableContainer * pTab = getTopmostTable();
1957 	return pTab->getY();
1958 }
1959 
1960 /*!
1961  Draw container content
1962  \param pDA Draw arguments
1963  */
draw(dg_DrawArgs * pDA)1964 void fp_CellContainer::draw(dg_DrawArgs* pDA)
1965 {
1966 	m_bDrawTop = false;
1967 	GR_Graphics * pG = pDA->pG;
1968 	fp_TableContainer * pTab = static_cast<fp_TableContainer *>(getContainer());
1969 // draw bottom if this cell is the last of the table and fully contained on the page
1970 
1971 	m_bDrawBot = (pTab->getNumRows() == getBottomAttach());
1972 
1973 	m_bDrawLeft = true;
1974 
1975 	UT_sint32 count = countCons();
1976 	const UT_Rect * pClipRect = pDA->pG->getClipRect();
1977 	UT_sint32 ytop,ybot;
1978 	UT_sint32 i;
1979 	UT_sint32 imax = static_cast<UT_sint32>((static_cast<UT_uint32>(1<<31)) - 1);
1980 	if(pClipRect)
1981 	{
1982 		ybot = UT_MAX(pClipRect->height,_getMaxContainerHeight());
1983 		ytop = pClipRect->top;
1984         ybot += ytop + 1;
1985 		xxx_UT_DEBUGMSG(("SEVIOR: clip top %d clip bot %d \n",ytop,ybot));
1986 	}
1987 	else
1988 	{
1989 		ytop = 0;
1990 		ybot = imax;
1991 	}
1992 	bool bStop = false;
1993 	bool bStart = false;
1994 	xxx_UT_DEBUGMSG(("SEVIOR: Drawing unbroken cell %x x %d, y %d width %d height %d \n",this,getX(),getY(),getWidth(),getHeight()));
1995 
1996 //
1997 // Only draw the lines in the clipping region.
1998 //
1999 	for ( i = 0; (i<count && !bStop); i++)
2000 	{
2001 		fp_ContainerObject* pContainer = static_cast<fp_ContainerObject*>(getNthCon(i));
2002 		dg_DrawArgs da = *pDA;
2003 //
2004 // pDA has xoff set at the columns left edge, we need to offset this
2005 //     by the cell x position.
2006 // pDA has yoffset at the last ypos in the column relative to the screen
2007 //     The position Ypos is the absolute position on the screen we need
2008 //     to offset this with the position of the container holding this
2009 //     cell.
2010 
2011 		da.xoff += pContainer->getX() + getX();
2012 		da.yoff += pContainer->getY() + getY();
2013 		UT_sint32 ydiff = da.yoff + pContainer->getHeight();
2014 		if((da.yoff >= ytop && da.yoff <= ybot) || (ydiff >= ytop && ydiff <= ybot))
2015 		{
2016 //
2017 // Always draw the top of the cell.
2018 //
2019 			m_bDrawTop = true;
2020 			bStart = true;
2021 			pContainer->draw(&da);
2022 		}
2023 		else if(bStart)
2024 		{
2025 			bStop = true;
2026 		}
2027 	}
2028 	if(i == count)
2029 	{
2030 		m_bDirty = false;
2031 	}
2032 	if(pG->queryProperties(GR_Graphics::DGP_SCREEN))
2033 		drawLines(NULL,pG,true);
2034 	drawLines(NULL,pG,false);
2035 	pTab->setRedrawLines();
2036     _drawBoundaries(pDA,NULL);
2037 }
2038 
2039 
2040 /*!
2041  * Draw the whole cell with the selection colour background.
2042 \Param pLine pointer to the line contained within the cell the cell.
2043 */
draw(fp_Line * pLine)2044 void fp_CellContainer::draw(fp_Line * pLine)
2045 {
2046 	UT_return_if_fail(getPage());
2047 
2048 	m_bDirty = false;
2049 	FV_View * pView = getView();
2050 	fp_TableContainer * pTab = static_cast<fp_TableContainer *>(getContainer());
2051 	if(pTab == NULL)
2052 	{
2053 		return;
2054 	}
2055 	UT_ASSERT(pTab->getContainerType() == FP_CONTAINER_TABLE);
2056 	fp_TableContainer * pBroke = pTab->getFirstBrokenTable();
2057 	if(pBroke == NULL)
2058 	{
2059 		return;
2060 	}
2061 	bool bFound = false;
2062 
2063 	while(pBroke && !bFound)
2064 	{
2065 		if(pBroke->isInBrokenTable(this,pLine))
2066 		{
2067 			bFound = true;
2068 			break;
2069 		}
2070 		pBroke = static_cast<fp_TableContainer *>(pBroke->getNext());
2071 	}
2072 	if(!bFound)
2073 	{
2074 		return;
2075 	}
2076 	fp_Container * pLast = static_cast<fp_Container *>(pLine);
2077 	while(pLast->getNext() && pBroke->isInBrokenTable(this,pLast))
2078 	{
2079 		pLast = static_cast<fp_Container*>(pLast->getNext());
2080 	}
2081 	//
2082 	// Now get a rectangle to calculate draw arguments
2083 	//
2084 	UT_Rect bRec;
2085 	fp_Page * pLinePage;
2086 	_getBrokenRect(pBroke, pLinePage, bRec,getGraphics());
2087 	dg_DrawArgs da;
2088 	UT_sint32 xoff,yoff;
2089 	fp_Container * pCon = static_cast<fp_Container *>(this);
2090 	pView->getPageScreenOffsets(pLinePage,xoff,yoff);
2091 	//
2092 	// Just need to get the offsets of the container that contains
2093 	// this table.
2094 	//
2095 	pCon = pCon->getContainer();
2096 	while(pCon && !pCon->isColumnType())
2097 	{
2098 		xoff += pCon->getX();
2099 		yoff += pCon->getY();
2100 		pCon = pCon->getContainer();
2101 	}
2102 	if(pCon)
2103 	{
2104 		xoff += pCon->getX();
2105 		yoff += pCon->getY();
2106 	}
2107 	if(getY() < pBroke->getYBreak())
2108 	{
2109 		//
2110 		// Have to account for the bit of the cell on the previous page
2111 		//
2112 		da.yoff = yoff - pBroke->getYBreak();
2113 	}
2114 	da.xoff = xoff;
2115 	da.yoff = yoff;
2116 	da.bDirtyRunsOnly = false;
2117 	da.pG = pView->getGraphics();
2118 	drawBroken(&da,pBroke);
2119 	return ;
2120 }
2121 
2122 /*!
2123  * Deletes any broken tables in this cell.
2124  */
deleteBrokenTables(bool bClearFirst)2125 void fp_CellContainer::deleteBrokenTables(bool bClearFirst)
2126 {
2127 	if(!containsNestedTables())
2128 	{
2129 		return;
2130 	}
2131 	fl_CellLayout * pCell = static_cast<fl_CellLayout *>(getSectionLayout());
2132 	fl_ContainerLayout * pCL = pCell->getFirstLayout();
2133 	while(pCL)
2134 	{
2135 		xxx_UT_DEBUGMSG(("Looking at CL %x for delete \n",pCL));
2136 		if(pCL->getContainerType() == FL_CONTAINER_TABLE)
2137 		{
2138 			fl_TableLayout * pTL = static_cast<fl_TableLayout *>(pCL);
2139 			fp_TableContainer * pTab = static_cast<fp_TableContainer *>(pTL->getFirstContainer());
2140 			xxx_UT_DEBUGMSG(("Doing delete broken tables on %x \n",pTab));
2141 			if(pTab)
2142 			{
2143 				pTab->deleteBrokenTables(bClearFirst,false);
2144 			}
2145 		}
2146 		pCL = pCL->getNext();
2147 	}
2148 }
2149 
2150 
deleteBrokenAfter(bool bClearFirst,UT_sint32 iOldBottom)2151 void fp_CellContainer::deleteBrokenAfter(bool bClearFirst,UT_sint32 iOldBottom)
2152 {
2153 	if(!containsNestedTables())
2154 	{
2155 		return;
2156 	}
2157 
2158 	UT_sint32 i = 0;
2159 	fp_Container * pCon;
2160 	for(i=0; i< countCons(); i++)
2161 	{
2162 		pCon = static_cast<fp_Container *>(getNthCon(i));
2163 		if (pCon->getContainerType() == FP_CONTAINER_TABLE)
2164 		{
2165 			fp_TableContainer * pTab = static_cast<fp_TableContainer*>(pCon);
2166 			UT_sint32 iYTab = getY() + pTab->getY();
2167 			if (iYTab > iOldBottom)
2168 			{
2169 				UT_ASSERT(!pTab->getMasterTable());
2170 				pTab->deleteBrokenAfter(bClearFirst);
2171 			}
2172 			else if (iYTab + pTab->getTotalTableHeight() < iOldBottom)
2173 			{
2174 				continue;
2175 			}
2176 			else
2177 			{
2178 				while(pTab)
2179 				{
2180 					if (iYTab + pTab->getYBreak() >= iOldBottom)
2181 					{
2182 						break;
2183 					}
2184 					pTab = static_cast<fp_TableContainer*>(pTab->getNext());
2185 				}
2186 
2187 				if(pTab && pTab->getPrev())
2188 				{
2189 					pTab = static_cast<fp_TableContainer*>(pTab->getPrev());
2190 					pTab->deleteBrokenAfter(bClearFirst);
2191 				}
2192 			}
2193 		}
2194 	}
2195 }
2196 
2197 
2198 
2199 /*!
2200  * Draw the whole cell with the selection colour background.
2201  * returns the last drawn cell in the container or NULL
2202 \Param pLine pointer to the line contained within the cell the cell.
2203 */
drawSelectedCell(fp_Line *)2204 fp_Container * fp_CellContainer::drawSelectedCell(fp_Line * /*pLine*/)
2205 {
2206 	UT_return_val_if_fail(getPage(), NULL);
2207 
2208 	FV_View * pView = getPage()->getDocLayout()->getView();
2209 	fp_TableContainer * pTab = static_cast<fp_TableContainer *>(getContainer());
2210 	if(pTab == NULL)
2211 	{
2212 		return NULL;
2213 	}
2214 	UT_ASSERT(pTab->getContainerType() == FP_CONTAINER_TABLE);
2215 	fp_TableContainer * pBroke = pTab->getFirstBrokenTable();
2216 	if(pBroke == NULL)
2217 	{
2218 		return NULL;
2219 	}
2220 	bool bFound = false;
2221 	bool bEnd = false;
2222 	UT_sint32 iBroke = 0;
2223 	while(pBroke && !bEnd)
2224 	{
2225 		if(doesOverlapBrokenTable(pBroke))
2226 		{
2227 			bFound = true;
2228 			//
2229 			// Set a flag to indicate the cell is selected
2230 			//
2231 			m_bIsSelected = true;
2232 			//
2233 			// Now get a rectangle to calculate draw arguments
2234 			//
2235 			UT_Rect bRec;
2236 			fp_Page * pLinePage;
2237 			_getBrokenRect(pBroke, pLinePage, bRec,getGraphics());
2238 			dg_DrawArgs da;
2239 			UT_sint32 xoff,yoff;
2240 			fp_Container * pCon = static_cast<fp_Container *>(this);
2241 			pView->getPageScreenOffsets(pLinePage,xoff,yoff);
2242 			//
2243 			// Just need to get the offsets of the container that contains
2244 			// this table.
2245 			//
2246 			pCon = static_cast<fp_Container *>(pBroke);
2247 			fp_TableContainer * pMaster = pBroke->getMasterTable();
2248 			if(pMaster->getFirstBrokenTable() == pBroke)
2249 			{
2250 				pCon = static_cast<fp_Container *>(pBroke->getMasterTable());
2251 			}
2252 			while(pCon && !pCon->isColumnType())
2253 			{
2254 				xoff += pCon->getX();
2255 				yoff += pCon->getY();
2256 				pCon = pCon->getContainer();
2257 			}
2258 			if(pCon)
2259 			{
2260 				xoff += pCon->getX();
2261 				yoff += pCon->getY();
2262 			}
2263 			yoff -= pBroke->getYBreak();
2264 			da.xoff = xoff;
2265    			da.yoff = yoff;
2266 			da.bDirtyRunsOnly = false;
2267 			da.pG = pView->getGraphics();
2268 			drawBroken(&da,pBroke);
2269 			m_bBgDirty = true;
2270 		}
2271 		else if(bFound)
2272 		{
2273 			bEnd = true;
2274 		}
2275 		iBroke++;
2276 		pBroke = static_cast<fp_TableContainer *>(pBroke->getNext());
2277 	}
2278 	fp_Container * pLast = NULL;
2279 	if(getNext())
2280 	{
2281 		pLast = static_cast<fp_Container *>(static_cast<fp_Container *>(getNext())->getNthCon(0));
2282 		while(pLast && pLast->getContainerType() !=FP_CONTAINER_LINE)
2283 		{
2284 			pLast = static_cast<fp_Container *>(pLast->getNthCon(0));
2285 		}
2286 	}
2287 	else
2288 	{
2289 		fl_ContainerLayout * pCL = static_cast<fl_ContainerLayout *>(getSectionLayout());
2290 		pCL = pCL->getNext();
2291 		if(pCL)
2292 		{
2293 			pLast = pCL->getFirstContainer();
2294 			while(pLast && pLast->getContainerType() !=FP_CONTAINER_LINE)
2295 			{
2296 				pLast = static_cast<fp_Container *>(pLast->getNthCon(0));
2297 			}
2298 		}
2299 	}
2300 	return pLast;
2301 }
2302 
2303 /*!
2304  * This method returns true if the cell overlaps the supplied broken
2305  * table.
2306  */
doesOverlapBrokenTable(fp_TableContainer * pBroke) const2307 bool fp_CellContainer::doesOverlapBrokenTable(fp_TableContainer * pBroke) const
2308 {
2309 	UT_sint32 nextRow = m_iBottomAttach;
2310 	UT_sint32 yCellBot = 0;
2311 	if(nextRow <= pBroke->getMasterTable()->getNumRows())
2312 	{
2313 		yCellBot = pBroke->getMasterTable()->getYOfRow(nextRow);
2314 	}
2315 	else
2316 	{
2317 		yCellBot = pBroke->getMasterTable()->getY() + pBroke->getMasterTable()->getHeight();
2318 	}
2319 	if((pBroke->getYBreak() <= getY()) && (getY() <= pBroke->getYBottom()))
2320 	{
2321 		return true;
2322 	}
2323 	if((pBroke->getYBreak() < yCellBot) && (yCellBot <= pBroke->getYBottom()))
2324 	{
2325 		return true;
2326 	}
2327 	//
2328 	// The broken table is containtained within this cell.
2329 	// ie The cell spans several pages.
2330 	//
2331 	if((pBroke->getYBreak() >= getY()) && (yCellBot >= pBroke->getYBottom()))
2332 	{
2333 		return true;
2334 	}
2335 	return false;
2336 }
2337 
2338 /*!
2339  Draw container content visible within the supplied broken table
2340  \param pDA Draw arguments
2341  \param pBroke broken table that cell is part of
2342  */
drawBroken(dg_DrawArgs * pDA,fp_TableContainer * pBroke)2343 void fp_CellContainer::drawBroken(dg_DrawArgs* pDA,
2344 								  fp_TableContainer * pBroke)
2345 {
2346 	GR_Graphics * pG = pDA->pG;
2347 	m_bDrawLeft = false;
2348 	m_bDrawTop = false;
2349 	fp_TableContainer * pTab2 = NULL;
2350 	if(pBroke && pBroke->isThisBroken())
2351 	{
2352 		pTab2 = pBroke->getMasterTable();
2353 	}
2354 	else
2355 	{
2356 		pTab2 = static_cast<fp_TableContainer *>(getContainer());
2357 	}
2358 // draw bottom if this cell is the last of the table and fully contained on the page
2359 
2360 	m_bDrawBot = (pTab2->getCellAtRowColumn(getBottomAttach(),getLeftAttach()) == NULL);
2361 
2362 // draw right if this cell is the rightmost of the table
2363 
2364 	m_bDrawRight = (pTab2->getCellAtRowColumn(getTopAttach(),getRightAttach()) == NULL);
2365 	m_bDrawRight = true;
2366 	m_bDrawLeft = true;
2367 
2368 	const UT_Rect * pClipRect = pDA->pG->getClipRect();
2369 	UT_sint32 ytop,ybot;
2370 	UT_sint32 i;
2371 	UT_sint32 imax = static_cast<UT_sint32>((static_cast<UT_uint32>(1<<29)) - 1);
2372 	UT_Rect bRec;
2373 	fp_Page * pPage;
2374 	_getBrokenRect(pBroke, pPage, bRec,pG);
2375 	xxx_UT_DEBUGMSG(("Draw Broken Table %p ybreak %d On Page %d cell %p \n",pBroke,pBroke->getYBreak(),pPage->getPageNumber(),this));
2376 	if((bRec.height < 0) || (bRec.width < 0))
2377 	{
2378 		xxx_UT_DEBUGMSG(("brokenRect off page - bailing out \n"));
2379 		return;
2380 	}
2381 	if(getFillType().getFillType() == FG_FILL_IMAGE && (getContainer() != NULL))
2382 	{
2383 		fl_DocSectionLayout * pDSL = getSectionLayout()->getDocSectionLayout();
2384 		if(pDSL && (bRec.height < pDSL->getActualColumnHeight()) && (bRec.height > pG->tlu(3)))
2385 		{
2386 			getSectionLayout()->setImageHeight(bRec.height);
2387 			getSectionLayout()->setImageWidth(bRec.width);
2388 			getFillType().setWidthHeight(pG,bRec.width,bRec.height,true);
2389 		}
2390 	}
2391 
2392 	if(pClipRect)
2393 	{
2394 		ybot = UT_MAX(pClipRect->height,_getMaxContainerHeight());
2395 		ytop = pClipRect->top;
2396 		ybot = ybot + ytop + pG->tlu(1);
2397 	}
2398 	else
2399 	{
2400 		ytop = 0;
2401 		ybot = imax;
2402 	}
2403 	xxx_UT_DEBUGMSG(("cliprect %x ytop %d ybot %d \n",pClipRect,ytop,ybot));
2404 	bool bStop = false;
2405 	bool bStart = false;
2406 	xxx_UT_DEBUGMSG(("drawBroken: Drawing broken cell %x x %d, y %d width %d height %d ncons %d \n",this,getX(),getY(),getWidth(),getHeight(),countCons()));
2407 
2408 //
2409 // Now draw the cell background.
2410 //
2411 
2412 	GR_Painter painter(pG);
2413 
2414 	if (((m_bIsSelected == false) || (!pG->queryProperties(GR_Graphics::DGP_SCREEN))) && (m_bBgDirty || !pDA->bDirtyRunsOnly))
2415 	{
2416 		UT_sint32 srcX = 0;
2417 		UT_sint32 srcY = 0;
2418 		getFillType().setWidthHeight(pG,bRec.width,bRec.height);
2419 		getLeftTopOffsets(srcX,srcY);
2420 		getFillType().Fill(pG,srcX,srcY,bRec.left,bRec.top,bRec.width,bRec.height);
2421 		if(getPage())
2422 		{
2423 			getPage()->expandDamageRect(bRec.left,bRec.top,bRec.width,bRec.height);
2424 		}
2425 		m_bBgDirty = false;
2426 	}
2427 	//
2428 	// This cell is selected, fill it with colour
2429 	//
2430 	else if(m_bIsSelected && pG->queryProperties(GR_Graphics::DGP_SCREEN))
2431 	{
2432 		FV_View * pView = getPage()->getDocLayout()->getView();
2433 		xxx_UT_DEBUGMSG(("drawBroke: fill rect: Final top %d bot %d  pBroke %x \n",bRec.top,bRec.top + bRec.height,pBroke));
2434 		UT_ASSERT((bRec.left + bRec.width) < static_cast<UT_sint32>(pView->getWidthPagesInRow(getPage())) );
2435 		painter.fillRect(pView->getColorSelBackground(),bRec.left,bRec.top,bRec.width,bRec.height);
2436 		if(getPage())
2437 		{
2438 			getPage()->expandDamageRect(bRec.left,bRec.top,bRec.width,bRec.height);
2439 		}
2440 	}
2441 
2442 //
2443 // Only draw the lines in the clipping region.
2444 //
2445 
2446 	xxx_UT_DEBUGMSG(("number containers %d \n",countCons()));
2447 	UT_sint32 iLastDraw = 0;
2448 	for ( i = 0; (i< countCons() && !bStop); i++)
2449 	{
2450 		fp_Container* pContainer = static_cast<fp_Container*>(getNthCon(i));
2451 		if(pBroke->isInBrokenTable(this, pContainer))
2452 		{
2453 			dg_DrawArgs da = *pDA;
2454 //
2455 // pDA has xoff set at the columns left edge, we need to offset this
2456 //     by the cell x position.
2457 // pDA has yoffset at the last ypos in the column relative to the screen
2458 //     The position Ypos is the absolute position on the screen we need
2459 //     to offset this with the position of the container holding this
2460 //     cell.
2461 
2462 			da.xoff += pContainer->getX() + getX();
2463 			da.yoff += pContainer->getY() + getY();
2464 			UT_sint32 ydiff = da.yoff + pContainer->getHeight();
2465 			if(pContainer->getContainerType() == FP_CONTAINER_TABLE)
2466 			{
2467 				UT_sint32 TabHeight= 0;
2468 				fp_TableContainer * pTCon = static_cast<fp_TableContainer *>(pContainer);
2469 				if(pTCon->isThisBroken())
2470 				{
2471 					TabHeight = pTCon->getHeight();
2472 				}
2473 				else if(pTCon->getFirstBrokenTable())
2474 				{
2475 					pContainer = pTCon->getFirstBrokenTable();
2476 					TabHeight = static_cast<fp_TableContainer *>(pContainer)->getHeight();
2477 				}
2478 				else
2479 				{
2480 					TabHeight = static_cast<fp_TableContainer *>(pContainer)->getHeight();
2481 				}
2482 				ydiff = da.yoff + TabHeight;
2483 			}
2484 
2485 			if((da.yoff >= ytop && da.yoff <= ybot) || (ydiff >= ytop && ydiff <= ybot))
2486 			{
2487 				// Draw the top of the cell if the cell starts on this page.
2488 				if(i == 0)
2489 				{
2490 					m_bDrawTop = true;
2491 				}
2492 				bStart = true;
2493 
2494 				if(pContainer->getContainerType() == FP_CONTAINER_TABLE)
2495 				{
2496 					fp_TableContainer * pTab = static_cast<fp_TableContainer *>(pContainer);
2497 					if(pTab->isThisBroken())
2498 					{
2499 						xxx_UT_DEBUGMSG(("Draw nested broken table %p da.yoff %d yBreak %d \n",pTab,da.yoff,pTab->getYBreak()));
2500 						dg_DrawArgs daa = da;
2501 						pTab->draw(&daa);
2502 						iLastDraw = i;
2503 					}
2504 					else
2505 					{
2506 						fp_TableContainer * pT= pTab->getFirstBrokenTable();
2507 						if(pT == NULL)
2508 						{
2509 							UT_DEBUGMSG(("No Broken Table in draw !! \n"));
2510 							UT_sint32 iY = pTab->getY();
2511 							pTab = static_cast<fp_TableContainer *>(pTab->VBreakAt(0));
2512 							pTab->setY(iY);
2513 						}
2514 						else
2515 						{
2516 							pTab = pT;
2517 						}
2518 						if(pTab)
2519 						{
2520 							pTab->draw(&da);
2521 							iLastDraw = i;
2522 						}
2523 					}
2524 				}
2525 				else
2526 				{
2527 					pContainer->setBreakTick(getBreakTick());
2528 					pContainer->draw(&da);
2529 					iLastDraw = i;
2530 				}
2531 			}
2532 			else if(bStart)
2533 			{
2534 				bStop = true;
2535 			}
2536 		}
2537 		else if(bStart)
2538 		{
2539 			bStop = true;
2540 		}
2541 	}
2542 	if((iLastDraw >= countCons()-1) && !bStop)
2543 	{
2544 		m_bDirty = false;
2545 		getSectionLayout()->clearNeedsRedraw();
2546 	}
2547 	drawLines(pBroke,pG,true);
2548 	drawLines(pBroke,pG,false);
2549 	pTab2->setRedrawLines();
2550     _drawBoundaries(pDA,pBroke);
2551 }
2552 
2553 /*!
2554  * Returns true since cells can be broken vertically.
2555  */
isVBreakable(void)2556 bool fp_CellContainer::isVBreakable(void)
2557 {
2558 	return true;
2559 }
2560 
2561 /*!
2562  * Break the cell at the specified location. This is mostly to handle
2563  * the case of tables embedded in the cell.
2564  * vpos is relative to the start of the cell.
2565  */
VBreakAt(UT_sint32 vpos)2566 fp_ContainerObject * fp_CellContainer::VBreakAt(UT_sint32 vpos)
2567 {
2568 	UT_sint32 iBreakTick = getBreakTick();
2569 	iBreakTick++;
2570 	setBreakTick(iBreakTick);
2571 	xxx_UT_DEBUGMSG(("iBreakTick is %d \n",getBreakTick()));
2572 	if(!containsNestedTables())
2573 	{
2574 		return NULL;
2575 	}
2576 	UT_sint32 count = countCons();
2577 	UT_DEBUGMSG(("vBREAK cell at  %d \n",vpos));
2578 	UT_sint32 i = 0;
2579 	fp_Container * pCon;
2580 	fp_TableContainer * pBroke = NULL;
2581 	UT_sint32 iY = 0;
2582 	for(i=0; (i < count) || (iY <= vpos); i++)
2583 	{
2584 		pCon = static_cast<fp_Container *>(getNthCon(i));
2585 		xxx_UT_DEBUGMSG(("Looking Container iY  %d height %d \n",iY,pCon->getHeight()));
2586 		if(iY <= vpos && iY + pCon->getHeight() > vpos)
2587 		{
2588 			//
2589 			// Container overlaps break point. See if container is
2590 			// is a table
2591 			// container if possible.
2592 			//
2593 			if(pCon->isVBreakable())
2594 			{
2595 				if(pCon->getContainerType() == FP_CONTAINER_TABLE)
2596 				{
2597 					UT_DEBUGMSG(("Want to break nested table at %d \n",vpos));
2598 					fp_TableContainer * pTab = static_cast<fp_TableContainer *>(pCon);
2599 					if(!pTab->isThisBroken())
2600 					{
2601 						if(pTab->getY() < -999999)
2602 						{
2603 							pTab->setY(iY);
2604 						}
2605 						if(pTab->getFirstBrokenTable())
2606 						{
2607 							pCon = static_cast<fp_Container *>(pTab->getFirstBrokenTable());
2608 						}
2609 						else
2610 						{
2611 							pCon = static_cast<fp_Container *>(pTab->VBreakAt(0));
2612 							fp_TableContainer * pBTab = static_cast<fp_TableContainer *>(pCon);
2613 							pBTab->setY(iY);
2614 							UT_DEBUGMSG(("Break Nested table Con %p at 0 y %d height %d \n",pCon,pCon->getY(),pCon->getHeight()));
2615 							UT_DEBUGMSG(("Break Nested table Table %p at 0 y %d height %d \n",pBTab,pBTab->getY(),pBTab->getHeight()));
2616 						}
2617 					}
2618 				}
2619 				if(vpos > 0)
2620 				{
2621 					//
2622 					// Tables are broken from the start of the table.
2623 					// vpos is preseneted as the distance from start of the
2624 					// cell so we have to subtract the y position of the
2625 					// first table.
2626 					// if there is previous non-zero ybreak table this is added
2627 					// so we
2628 					// subtract that off too. This is because the top-level
2629 					// tables are broken over columns and heights are
2630 					// calculated from within these columns.
2631 					//
2632 					fp_TableContainer * pPrevTab = static_cast<fp_TableContainer *>(pCon);
2633 					fp_TableContainer * pMaster = pPrevTab->getMasterTable();
2634 					pBroke = static_cast<fp_TableContainer *>(pPrevTab->VBreakAt(vpos - pMaster->getY() - pPrevTab->getYBreak()));
2635 					if (pBroke)
2636 					{
2637 						pBroke->setY(vpos);
2638 						static_cast<fp_TableContainer *>(pBroke)->setY(pBroke->getY());
2639 						UT_DEBUGMSG(("Made broken nested Table %p Y %d height %d \n",pBroke,pBroke->getY(),pBroke->getHeight()));
2640 						UT_ASSERT(pBroke->getContainer() == this);
2641 					}
2642 					break;
2643 				}
2644 			}
2645 		}
2646 		iY += pCon->getHeight();
2647 		iY += pCon->getMarginAfter();
2648 	}
2649 	return static_cast<fp_ContainerObject *>(pBroke);
2650 }
2651 
2652 
2653 /*!
2654  * This routine requests that the cell be broken at the specfied height.
2655  * the return value of the method is the actual height it can be broken
2656  * which is less than or equal to the requested height.
2657  */
wantCellVBreakAt(UT_sint32 vpos,UT_sint32 yCellMin)2658 UT_sint32 fp_CellContainer::wantCellVBreakAt(UT_sint32 vpos, UT_sint32 yCellMin)
2659 {
2660 	UT_sint32 i =0;
2661 	UT_sint32 iYBreak = vpos;
2662 	fp_Container * pCon;
2663 	//fp_Line * pLine = NULL;
2664 	UT_sint32 footHeight = 0;
2665 	fp_TableContainer * pTab = static_cast<fp_TableContainer *>(getContainer());
2666 	UT_return_val_if_fail(pTab,0);
2667 	for(i=0; i < countCons(); i++)
2668 	{
2669 		pCon = static_cast<fp_Container *>(getNthCon(i));
2670 		if (yCellMin > pCon->getY() + 1)
2671 		{
2672 			// pCon is in a segment of the cell contained within a previous broken table
2673 			// This condition matches the condition in fp_TableContainer::isInBrokenTable
2674 			continue;
2675 		}
2676 		UT_sint32 iY = pCon->getY() + getY();
2677 		UT_sint32 conHeight = pCon->getHeight();
2678 		bool bConBroken = false;
2679 		if (pCon->isVBreakable() && pCon->getNext())
2680 		{
2681 			bConBroken = true;
2682 			if (pCon->getContainerType() == FP_CONTAINER_TABLE)
2683 			{
2684 				conHeight = static_cast<fp_TableContainer*>(pCon)->getTotalTableHeight();
2685 			}
2686 		}
2687 
2688 		if(iY <= vpos && iY + conHeight > vpos)
2689 		{
2690 			//
2691 			// Container overlaps break point. Find break point in the
2692 			// container if possible.
2693 			//
2694 			UT_sint32 iCur =0;
2695 			if(pCon->getContainerType() == FP_CONTAINER_TABLE)
2696 			{
2697 				iCur = pCon->wantVBreakAt(vpos - iY);
2698 				fp_TableContainer* pNestedTab = static_cast<fp_TableContainer*>(pCon);
2699 				if (!pNestedTab->isThisBroken() && pNestedTab->getFirstBrokenTable())
2700 				{
2701 					pNestedTab = pNestedTab->getFirstBrokenTable();
2702 				}
2703 				if (pNestedTab->getYBottom() != iCur - 1)
2704 				{
2705 					pNestedTab->deleteBrokenAfter(true);
2706 				}
2707 				iCur = iCur + iY + 1;
2708 			}
2709 			else
2710 			{
2711 				iCur = iY + 1;
2712 			}
2713 			if(iCur < iYBreak)
2714 			{
2715 				iYBreak = iCur;
2716 			}
2717 			break;
2718 		}
2719 		else if (bConBroken)
2720 		{
2721 			// The whole container fits in the table. Delete broken segments
2722 			static_cast<fp_VerticalContainer*>(pCon)->deleteBrokenAfter(true);
2723 		}
2724 	}
2725 	if((iYBreak == vpos) && (footHeight > 0))
2726 	{
2727 		iYBreak = iYBreak - footHeight;
2728 	}
2729 	return iYBreak;
2730 }
2731 
2732 
getNextContainerInSection() const2733 fp_Container * fp_CellContainer::getNextContainerInSection() const
2734 {
2735 
2736 	fl_ContainerLayout * pCL = static_cast<fl_ContainerLayout *>(getSectionLayout());
2737 	fl_ContainerLayout * pNext = pCL->getNext();
2738 	while(pNext && ((pNext->getContainerType() == FL_CONTAINER_ENDNOTE) ||
2739 		  (pNext->getContainerType() == FL_CONTAINER_FRAME) ||
2740 		  (pNext->isHidden() == FP_HIDDEN_FOLDED)))
2741 	{
2742 		pNext = pNext->getNext();
2743 	}
2744 	if(pNext)
2745 	{
2746 		return pNext->getFirstContainer();
2747 	}
2748 	return NULL;
2749 }
2750 
2751 
getPrevContainerInSection() const2752 fp_Container * fp_CellContainer::getPrevContainerInSection() const
2753 {
2754 
2755 	fl_ContainerLayout * pCL = static_cast<fl_ContainerLayout *>(getSectionLayout());
2756 	fl_ContainerLayout * pPrev = pCL->getPrev();
2757 	while(pPrev && ((pPrev->getContainerType() == FL_CONTAINER_ENDNOTE) ||
2758 		  (pPrev->getContainerType() == FL_CONTAINER_FRAME) ||
2759 		  (pPrev->isHidden() == FP_HIDDEN_FOLDED)))
2760 
2761 	{
2762 		pPrev = pPrev->getPrev();
2763 	}
2764 	if(pPrev)
2765 	{
2766 		return pPrev->getLastContainer();
2767 	}
2768 	return NULL;
2769 }
2770 
2771 
2772 /*
2773   This function returns the first container inside a cell that is also inside
2774   a broken table. It returns NULL if no container is inside  the broken table
2775 */
2776 
getFirstContainerInBrokenTable(fp_TableContainer * pBroke) const2777 fp_Container * fp_CellContainer::getFirstContainerInBrokenTable(fp_TableContainer * pBroke) const
2778 {
2779 	if (!pBroke->isThisBroken())
2780 	{
2781 		return NULL;
2782 	}
2783 
2784 	UT_sint32 count = countCons();
2785 	UT_sint32 k = 0;
2786 	fp_Container * pCon = NULL;
2787 	for (k = 0; k < count; k++)
2788 	{
2789 		pCon = static_cast<fp_Container *>(getNthCon(k));
2790 		if (pBroke->isInBrokenTable(this, pCon))
2791 		{
2792 			return pCon;
2793 		}
2794 	}
2795 	return NULL;
2796 }
2797 
sizeRequest(fp_Requisition * pRequest)2798 void fp_CellContainer::sizeRequest(fp_Requisition * pRequest)
2799 {
2800 	xxx_UT_DEBUGMSG(("Doing size request on %x \n",pRequest));
2801 	UT_sint32 count = countCons();
2802 	UT_sint32 i =0;
2803 	UT_sint32 height = 0;
2804 	UT_sint32 width = 0;
2805 	for(i=0 ; i < count; i++)
2806 	{
2807 		fp_Container * pCon = static_cast<fp_Container *>(getNthCon(i));
2808 		if(pCon->getContainerType() == FP_CONTAINER_LINE)
2809 		{
2810 			static_cast<fp_Line *>(pCon)->recalcHeight();
2811 			if(width < pCon->getWidth())
2812 			{
2813 				width = pCon->getWidth();
2814 
2815 			}
2816 			xxx_UT_DEBUGMSG(("sizeRequest: Height of Line %d %d tot %d \n",i,pCon->getHeight(),height));
2817 			height = height + pCon->getHeight();
2818 			height = height + pCon->getMarginAfter();
2819 		}
2820 		else
2821 		{
2822 			if(pCon->getContainerType() == FP_CONTAINER_TABLE)
2823 			{
2824 				fp_TableContainer * pTab = static_cast<fp_TableContainer*>(pCon);
2825 				fl_TableLayout * pTL = static_cast<fl_TableLayout *>(pTab->getSectionLayout());
2826 				if (pTL->isInitialLayoutCompleted())
2827 				{
2828 					fp_Requisition pReq;
2829 					pTab->sizeRequest(&pReq);
2830 					if(width < pReq.width)
2831 					{
2832 						width = pReq.width;
2833 					}
2834 					height = height + pReq.height;
2835 				}
2836 			}
2837 			else
2838 			{
2839 				UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
2840 			}
2841 		}
2842 		xxx_UT_DEBUGMSG(("Total height %d \n",height));
2843 	}
2844 	UT_sint32 maxwidth = 0;
2845 	fl_CellLayout * pCellL = static_cast<fl_CellLayout *>(getSectionLayout());
2846 	fl_ContainerLayout * pCL = pCellL->getFirstLayout();
2847 	while(pCL)
2848 	{
2849 		if(pCL->getContainerType() == FL_CONTAINER_BLOCK)
2850 		{
2851 			fl_BlockLayout * pBL = static_cast<fl_BlockLayout *>(pCL);
2852 			UT_sint32 iw = pBL->getMaxNonBreakableRun();
2853 			if(maxwidth < iw)
2854 			{
2855 				maxwidth = iw;
2856 			}
2857 		}
2858 		pCL = pCL->getNext();
2859 	}
2860 
2861 	if(maxwidth > width)
2862 	{
2863 		width = maxwidth;
2864 	}
2865 	if(pRequest)
2866 	{
2867 		pRequest->width = width;
2868 		pRequest->height = height;
2869 	}
2870 
2871 	fp_Column * pCol = static_cast<fp_Column *>(fp_Container::getColumn());
2872 	if(pCol && (width == 0))
2873 	{
2874 		width = pCol->getWidth();
2875 	}
2876 
2877 	m_MyRequest.width = width;
2878 	m_MyRequest.height = height;
2879 	xxx_UT_DEBUGMSG(("Size Request: Cell Total height  %d width %d \n",height,width));
2880 }
2881 
sizeAllocate(fp_Allocation * pAllocate)2882 void fp_CellContainer::sizeAllocate(fp_Allocation * pAllocate)
2883 {
2884 	m_MyAllocation.width = pAllocate->width;
2885 	m_MyAllocation.height = pAllocate->height;
2886 	m_MyAllocation.x = pAllocate->x;
2887 	m_MyAllocation.y = pAllocate->y;
2888 }
2889 
layout(void)2890 void fp_CellContainer::layout(void)
2891 {
2892 	_setMaxContainerHeight(0);
2893 	UT_sint32 iY = 0, iPrevY = 0;
2894 	fp_Container *pContainer, *pPrevContainer = NULL;
2895 	xxx_UT_DEBUGMSG(("Doing Cell layout %x \n",this));
2896 	if(countCons() == 0)
2897 	{
2898 		return;
2899 	}
2900 	for (UT_sint32 i=0; i < countCons(); i++)
2901 	{
2902 		pContainer = static_cast<fp_Container*>(getNthCon(i));
2903 //
2904 // This is to speedup redraws.
2905 //
2906 		if(pContainer->getHeight() > _getMaxContainerHeight())
2907 			_setMaxContainerHeight(pContainer->getHeight());
2908 
2909 		fp_TableContainer * pTab = NULL;
2910 		if(pContainer->getY() != iY)
2911 		{
2912 			pContainer->clearScreen();
2913 			if(pContainer->getContainerType() == FP_CONTAINER_TABLE)
2914 			{
2915 				pTab = static_cast<fp_TableContainer *>(pContainer);
2916 				if(!pTab->isThisBroken())
2917 				{
2918 					//
2919 					// The position of the master table has changed.
2920 					// All broken tables need to be rebroken
2921 					pTab->deleteBrokenTables(false,true);
2922 				}
2923 			}
2924 		}
2925 
2926 		pContainer->setY(iY);
2927 
2928 		UT_sint32 iContainerHeight = pContainer->getHeight();
2929 		UT_sint32 iContainerMarginAfter = pContainer->getMarginAfter();
2930 
2931 		if(pContainer->getContainerType() == FP_CONTAINER_TABLE)
2932 		{
2933 			xxx_UT_DEBUGMSG(("Doing Nested table layout Y 1 is %d \n",pContainer->getY()));
2934 			pTab = static_cast<fp_TableContainer *>(pContainer);
2935 			if(!pTab->isThisBroken())
2936 			{
2937 				if(pTab->getFirstBrokenTable() == NULL)
2938 				{
2939 					static_cast<fp_TableContainer *>(pTab->VBreakAt(0));
2940 					pTab = pTab->getFirstBrokenTable();
2941 					if(pContainer->getY() == iY)
2942 					{
2943 						static_cast<fp_VerticalContainer *>(pTab)->setY(iY);
2944 					}
2945 				}
2946 				pTab = pTab->getFirstBrokenTable();
2947 			}
2948 			pTab->setY(iY);
2949 			iContainerHeight = pTab->getHeight();
2950 			xxx_UT_DEBUGMSG(("Doing Nested table layout Y 2 is %d height is %d YBottom %d \n",pTab->getY(),pTab->getHeight(),pTab->getYBottom()));
2951 		}
2952 
2953 		iY += iContainerHeight;
2954 		iY += iContainerMarginAfter;
2955 		//iY +=  0.5;
2956 
2957 		// Update height of previous line now we know the gap between
2958 		// it and the current line.
2959 		if (pPrevContainer && pPrevContainer->getContainerType() != FP_CONTAINER_TABLE)
2960 		{
2961 			pPrevContainer->setAssignedScreenHeight(iY - iPrevY);
2962 		}
2963 		pPrevContainer = pContainer;
2964 		iPrevY = iY;
2965 	}
2966 
2967 	// Correct height position of the last line
2968 	if (pPrevContainer)
2969 	{
2970 		pPrevContainer->setAssignedScreenHeight(iY - iPrevY + 1);
2971 	}
2972 
2973 	if (getHeight() == iY)
2974 	{
2975 		return;
2976 	}
2977 	setHeight(iY);
2978 }
2979 
setToAllocation(void)2980 void fp_CellContainer::setToAllocation(void)
2981 {
2982 	m_bBgDirty = true;
2983 	setWidth(static_cast<UT_sint32>(m_MyAllocation.width));
2984 	setHeight(m_MyAllocation.height);
2985 	setX(static_cast<UT_sint32>(m_MyAllocation.x));
2986 	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));
2987 	setMaxHeight(m_MyAllocation.height);
2988 	layout();
2989 }
2990 
2991 
getLeftTopOffsets(UT_sint32 & xoff,UT_sint32 & yoff) const2992 void fp_CellContainer::getLeftTopOffsets(UT_sint32 & xoff, UT_sint32 & yoff) const
2993 {
2994 	fp_TableContainer * pTab = static_cast<fp_TableContainer *>(getContainer());
2995 	UT_return_if_fail(pTab);
2996 	xoff = -static_cast<UT_sint32>(pTab->getNthCol(getLeftAttach())->spacing);
2997 	yoff = m_iTopY - getY();
2998 }
2999 
3000 /*!
3001  * This method sets the line markers between the rows and columns. It must be called after
3002  * the setToAllocation() for all cells.
3003  */
setLineMarkers(void)3004 void fp_CellContainer::setLineMarkers(void)
3005 {
3006 //
3007 // Set the boundary markers for line drawing.
3008 //
3009 	fp_TableContainer * pTab = static_cast<fp_TableContainer *>(getContainer());
3010 	UT_return_if_fail(pTab);
3011 
3012 	fl_TableLayout * pTL = static_cast<fl_TableLayout *>(pTab->getSectionLayout());
3013 	fp_TableRowColumn *pCol = pTab->getNthCol(getLeftAttach());
3014 	if(pCol)
3015 		m_iLeft = getX() - static_cast<UT_sint32>(pCol->spacing);
3016 
3017 	if (pTab->getNumCols() == getRightAttach())
3018 	{
3019 		m_iRight = getX() + getWidth();
3020 		m_iRight += static_cast<UT_sint32> (0.5 * static_cast<double>(pTab->getBorderWidth()));
3021 	}
3022 	else
3023 	{
3024 		fp_CellContainer * pCell = static_cast<fp_CellContainer*>(getNext());
3025 		if (!pCell || (pCell->getTopAttach() != getTopAttach()) || (pCell->getLeftAttach() != getRightAttach()))
3026 		{
3027 			pCell = pTab->getCellAtRowColumn(getTopAttach(),getRightAttach());
3028 		}
3029 
3030 		if(pCell)
3031 		{
3032 			m_iRight = pCell->getX();
3033 			m_iRight -= static_cast<UT_sint32>(pTab->getNthCol(getRightAttach())->spacing);
3034 		}
3035 		else
3036 		{
3037 			UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
3038 			m_iRight = getX() + getWidth();
3039 			m_iRight += static_cast<UT_sint32> (0.5 * static_cast<double>(pTab->getBorderWidth()));
3040 		}
3041 	}
3042 
3043 	m_iTopY = pTab->getYOfRow(getTopAttach());
3044 	if(getTopAttach() == 0)
3045 	{
3046 		m_iTopY -= static_cast<UT_sint32>(0.5 * static_cast<double>(pTab->getBorderWidth()));
3047 	}
3048 	else
3049 	{
3050 		fp_TableRowColumn *pRow = pTab->getNthRow(getTopAttach());
3051 		if(pRow)
3052 		{
3053 			m_iTopY -= pRow->spacing/2;
3054 		}
3055 
3056 		UT_sint32 cLeft = 0;
3057 		for(cLeft = getLeftAttach(); cLeft < getRightAttach(); cLeft++)
3058 		{
3059 			fp_CellContainer * pCellAtRow = pTab->getCellAtRowColumn(getTopAttach() -1,cLeft);
3060 			if(pCellAtRow)
3061 			{
3062 				pCellAtRow->m_iBotY = m_iTopY;
3063 			}
3064 			else
3065 			{
3066 				break;
3067 			}
3068 		}
3069 	}
3070 	xxx_UT_DEBUGMSG(("getBottomAttach %d \n",getBottomAttach()));
3071 	if(getBottomAttach() <= pTab->getNumRows())
3072 	{
3073 		m_iBotY = pTab->getYOfRow(getBottomAttach());
3074 		if(getBottomAttach() < pTab->getNumRows())
3075 		{
3076 			fp_TableRowColumn *pRow = pTab->getNthRow(getBottomAttach());
3077 			if(pRow)
3078 				m_iBotY += pRow->spacing/2;
3079 		}
3080 	}
3081 	else
3082 	{
3083 //
3084 // Have to cast the MasterTable to a vertical container to get the full height of a broken
3085 // table. Otherwise we just get height of the first broken table.
3086 //
3087 		fp_VerticalContainer * pVert = static_cast<fp_VerticalContainer *>(pTab);
3088 		m_iBotY = pTab->getYOfRow(0) + pVert->getHeight() -pTL->getBottomOffset() - getGraphics()->tlu(1);
3089 		m_iBotY -= static_cast<UT_sint32>(2.0 * static_cast<double>(pTab->getBorderWidth()));
3090 		m_iBotY +=  pTab->getNthRow(pTab->getNumRows()-1)->spacing/2;
3091 	}
3092 
3093 	xxx_UT_DEBUGMSG(("SEVIOR getX %d left %d right %d top %d bot %d \n",getX(),m_iLeft,m_iRight,m_iTopY,m_iBotY));
3094 }
3095 
doVertAlign(void)3096 void fp_CellContainer::doVertAlign(void)
3097 {
3098 	// Vertical alignment - EA
3099 	// Note, must be called right after the cell's boundary lines have been determined with setLineMarkers.
3100 	// Currently, doVertAlign is called fp_TableContainer::setToAllocation() although the most direct method
3101 	// would be to call it at the end of fp_CellContainer::setLineMarkers() because I don't want the call to
3102 	// be too deeply buried in code.
3103 
3104 	setY( m_MyAllocation.y - (getHeight() * (m_iVertAlign/100.0)) + ((m_iBotY - m_iTopY) * (m_iVertAlign/100.0)) );
3105 	if( (getY() + getHeight()) > m_MyAllocation.y + (m_iBotY - m_iTopY) - getBotPad() ) // Make sure not to exceed cell's bottom padding
3106 		setY( m_MyAllocation.y + (m_iBotY - m_iTopY) - getBotPad() - getHeight() );
3107 	if( getY() < m_MyAllocation.y + getTopPad() ) // Make sure not to exceed cell's top padding
3108 		setY( m_MyAllocation.y + getTopPad() );
3109 }
3110 
3111 //---------------------------------------------------------------------
3112 
3113 /*!
3114   Create a Master Table container. This is broken across other vertical
3115   Containers.
3116   \param iType Container type
3117   \param pSectionLayout Section layout type used for this container
3118  */
fp_TableContainer(fl_SectionLayout * pSectionLayout)3119 fp_TableContainer::fp_TableContainer(fl_SectionLayout* pSectionLayout)
3120 	: fp_VerticalContainer(FP_CONTAINER_TABLE, pSectionLayout),
3121 	  m_iRows(0),
3122 	  m_iCols(0),
3123 	  m_iBorderWidth(0),
3124 	  m_bIsHomogeneous(true),
3125 	  m_iRowSpacing(0),
3126 	  m_iColSpacing(0),
3127 	  m_pFirstBrokenTable(NULL),
3128 	  m_pLastBrokenTable(NULL),
3129 	  m_bIsBroken(false),
3130 	  m_pMasterTable(NULL),
3131 	  m_iYBreakHere(0),
3132 	  m_iYBottom(0),
3133 	  m_iAdditionalBottomSpace(0),
3134 	  m_bBrokenTop(false),
3135 	  m_bBrokenBottom(false),
3136 	  m_bRedrawLines(false),
3137 	  m_iLineThickness(1),
3138 	  m_iRowHeightType(FL_ROW_HEIGHT_NOT_DEFINED),
3139 	  m_iRowHeight(0),
3140 	  m_iLastWantedVBreak(-1),
3141 	  m_iNextWantedVBreak(-1),
3142 	  m_pFirstBrokenCell(NULL),
3143 	  m_iAdditionalMarginAfter(0)
3144 {
3145 	if(getSectionLayout())
3146 	{
3147 		getSectionLayout()->setNeedsRedraw();
3148 		getSectionLayout()->markAllRunsDirty();
3149 	}
3150 }
3151 
3152 
3153 /*!
3154   Create a broken Table container. This is placed between the cells and
3155   drawing. A vertical offset is subtracted from the Cells Y location for
3156   all manipulations.
3157   \param iType Container type
3158   \param pSectionLayout Section layout type used for this container
3159  */
fp_TableContainer(fl_SectionLayout * pSectionLayout,fp_TableContainer * pMaster)3160 fp_TableContainer::fp_TableContainer(fl_SectionLayout* pSectionLayout, fp_TableContainer * pMaster)
3161 	: fp_VerticalContainer(FP_CONTAINER_TABLE, pSectionLayout),
3162 	  m_iRows(0),
3163 	  m_iCols(0),
3164 	  m_iBorderWidth(0),
3165 	  m_bIsHomogeneous(true),
3166 	  m_iRowSpacing(0),
3167 	  m_iColSpacing(0),
3168 	  m_pFirstBrokenTable(NULL),
3169 	  m_pLastBrokenTable(NULL),
3170 	  m_bIsBroken(true),
3171 	  m_pMasterTable(pMaster),
3172 	  m_iYBreakHere(0),
3173 	  m_iYBottom(0),
3174 	  m_iAdditionalBottomSpace(0),
3175 	  m_bBrokenTop(false),
3176 	  m_bBrokenBottom(false),
3177 	  m_bRedrawLines(false),
3178 	  m_iLineThickness(1),
3179 	  m_iRowHeightType(FL_ROW_HEIGHT_NOT_DEFINED),
3180 	  m_iRowHeight(0),
3181 	  m_iLastWantedVBreak(-1),
3182 	  m_iNextWantedVBreak(-1),
3183 	  m_pFirstBrokenCell(NULL),
3184 	  m_iAdditionalMarginAfter(0)
3185 {
3186 }
3187 
3188 /*!
3189   Destruct container
3190   \note The Containers in vector of the container are not
3191         destructed. They are owned by the logical hierarchy (i.e.,
3192 		the fl_Container classes like fl_BlockLayout), not the physical
3193         hierarchy.
3194  */
~fp_TableContainer()3195 fp_TableContainer::~fp_TableContainer()
3196 {
3197 	UT_VECTOR_PURGEALL(fp_TableRowColumn *, m_vecRows);
3198 	UT_VECTOR_PURGEALL(fp_TableRowColumn *, m_vecColumns);
3199 	clearCons();
3200 	deleteBrokenTables(false,false);
3201 	xxx_UT_DEBUGMSG(("SEVIOR: deleting table %x \n",this));
3202 //
3203 // For debugging...
3204 //
3205 	setContainer(NULL);
3206 	setPrev(NULL);
3207 	setNext(NULL);
3208 	m_pMasterTable = NULL;
3209 }
3210 
getBrokenColumn(void)3211 fp_Column * fp_TableContainer::getBrokenColumn(void)
3212 {
3213 	if(!isThisBroken())
3214 	{
3215 		return static_cast<fp_Column *>(fp_VerticalContainer::getColumn());
3216 	}
3217 	fp_TableContainer * pBroke = this;
3218 	bool bStop = false;
3219 	fp_Column * pCol = NULL;
3220 	while(pBroke && pBroke->isThisBroken() && !bStop)
3221 	{
3222 		fp_Container * pCon = pBroke->getContainer();
3223 		if (!pCon)
3224 		{
3225 			return NULL;
3226 		}
3227 		if(pCon->isColumnType())
3228 		{
3229 			if(pCon->getContainerType() == FP_CONTAINER_COLUMN)
3230 			{
3231 				pCol = static_cast<fp_Column *>(pCon);
3232 			}
3233 			else
3234 			{
3235 				pCol = static_cast<fp_Column *>(pCon->getColumn());
3236 			}
3237 			bStop = true;
3238 		}
3239 		else
3240 		{
3241 			fp_CellContainer * pCell = static_cast<fp_CellContainer *>(pBroke->getContainer());
3242 			UT_ASSERT(pCell->getContainerType() == FP_CONTAINER_CELL);
3243 			pBroke = pCell->getBrokenTable(static_cast<fp_Container *>(pBroke));
3244 		}
3245 	}
3246 	if(pBroke && !bStop)
3247 	{
3248 		pCol = static_cast<fp_Column *>(pBroke->getContainer());
3249 	}
3250 	//	UT_ASSERT(pCol->getContainerType() != FP_CONTAINER_CELL);
3251 	if(pCol && pCol->getContainerType() == FP_CONTAINER_CELL)
3252 	{
3253 		fp_Container * pCon = static_cast<fp_Container *>(pCol);
3254 		while(pCon && !pCon->isColumnType())
3255 		{
3256 			pCon = pCon->getContainer();
3257 		}
3258 		if(pCon)
3259 		{
3260 			pCol = static_cast<fp_Column *>(pCon);
3261 		}
3262 		else
3263 		{
3264 			pCol = NULL;
3265 		}
3266 	}
3267 	return pCol;
3268 }
3269 
containsNestedTables(void)3270 bool fp_TableContainer::containsNestedTables(void)
3271 {
3272 	fl_TableLayout * pTL = static_cast<fl_TableLayout *>(getSectionLayout());
3273 	return (pTL->getNumNestedTables() > 0);
3274 }
3275 
getFirstBrokenTable(void) const3276 fp_TableContainer * fp_TableContainer::getFirstBrokenTable(void) const
3277 {
3278 	if(isThisBroken())
3279 	{
3280 		return getMasterTable()->getFirstBrokenTable();
3281 	}
3282 	return m_pFirstBrokenTable;
3283 }
3284 
3285 /*
3286  * Just draw the lines around a table
3287  */
drawLines(void)3288 void fp_TableContainer::drawLines(void)
3289 {
3290 	if(isThisBroken())
3291 	{
3292 		m_bRedrawLines = false;
3293 		getMasterTable()->drawLines();
3294 		return;
3295 	}
3296 	fp_CellContainer * pCell = static_cast<fp_CellContainer *>(getNthCon(0));
3297 	while(pCell)
3298 	{
3299 		fp_TableContainer * pBroke = getFirstBrokenTable();
3300 		if(pBroke)
3301 		{
3302 			while(pBroke)
3303 			{
3304 				pCell->drawLines(pBroke,getGraphics(),true);
3305 				pCell->drawLines(pBroke,getGraphics(),false);
3306 				pBroke = static_cast<fp_TableContainer *>(pBroke->getNext());
3307 			}
3308 		}
3309 		else
3310 		{
3311 			pCell->drawLines(NULL,getGraphics(),true);
3312 			pCell->drawLines(NULL,getGraphics(),false);
3313 		}
3314 		pCell = static_cast<fp_CellContainer *>(pCell->getNext());
3315 	}
3316 	m_bRedrawLines = false;
3317 }
3318 
getLastBrokenTable(void) const3319 fp_TableContainer * fp_TableContainer::getLastBrokenTable(void) const
3320 {
3321 	if(isThisBroken())
3322 	{
3323 		return getMasterTable()->getLastBrokenTable();
3324 	}
3325 	return m_pLastBrokenTable;
3326 }
3327 
getBrokenNumber(void) const3328 UT_sint32 fp_TableContainer::getBrokenNumber(void) const
3329 {
3330 	if(!isThisBroken())
3331 	{
3332 		return 0;
3333 	}
3334 	fp_TableContainer * pTab = getMasterTable()->getFirstBrokenTable();
3335 	UT_sint32 i = 1;
3336 	while(pTab && pTab != this)
3337 	{
3338 		pTab = static_cast<fp_TableContainer *>(pTab->getNext());
3339 		i++;
3340 	}
3341 	if(!pTab)
3342 	{
3343 		return -1;
3344 	}
3345 	return i;
3346 }
3347 
3348 
setFirstBrokenTable(fp_TableContainer * pBroke)3349 void fp_TableContainer::setFirstBrokenTable(fp_TableContainer * pBroke)
3350 {
3351 	if(isThisBroken())
3352 	{
3353 		getMasterTable()->setFirstBrokenTable(pBroke);
3354 	}
3355 	m_pFirstBrokenTable = pBroke;
3356 
3357 }
3358 
setLastBrokenTable(fp_TableContainer * pBroke)3359 void fp_TableContainer::setLastBrokenTable(fp_TableContainer * pBroke)
3360 {
3361 	if(isThisBroken())
3362 	{
3363 		getMasterTable()->setLastBrokenTable(pBroke);
3364 	}
3365 	m_pLastBrokenTable = pBroke;
3366 }
3367 
3368 /* Return the first cell of a broken table.
3369 */
3370 
getFirstBrokenCell(bool bCacheResultOnly) const3371 fp_CellContainer *  fp_TableContainer::getFirstBrokenCell(bool bCacheResultOnly) const
3372 {
3373 	if (bCacheResultOnly || m_pFirstBrokenCell)
3374 	{
3375 		return m_pFirstBrokenCell;
3376 	}
3377 
3378 	if (getPrev())
3379 	{
3380 		fp_TableContainer * pPrevTable = static_cast<fp_TableContainer*>(getPrev());
3381 		if (pPrevTable->getFirstBrokenCell(true))
3382 		{
3383 			return pPrevTable->getFirstBrokenCell(true);
3384 		}
3385 	}
3386 
3387 	if (!isThisBroken())
3388 	{
3389 		return static_cast<fp_CellContainer *>(getNthCon(0));
3390 	}
3391 
3392 	return static_cast<fp_CellContainer *>(getMasterTable()->getNthCon(0));
3393 }
3394 
3395 
3396 
getYOfRowOrColumn(UT_sint32 row,bool bRow) const3397 UT_sint32 fp_TableContainer::getYOfRowOrColumn(UT_sint32 row, bool bRow) const
3398 {
3399 	return ((bRow) ? getYOfRow(row) : getXOfColumn(row));
3400 }
3401 
3402 /*!
3403  * Return the Y location of row number row
3404  */
getYOfRow(UT_sint32 row) const3405 UT_sint32 fp_TableContainer::getYOfRow(UT_sint32 row) const
3406 {
3407 	if (getMasterTable())
3408 	{
3409 		return getMasterTable()->getYOfRow(row);
3410 	}
3411 	UT_sint32 numRows = getNumRows();
3412 	if((row > numRows) || (numRows == 0))
3413 	{
3414 		return 0;
3415 	}
3416 
3417 	UT_sint32 iYRow = 0;
3418 	fp_TableRowColumn *pRow = NULL;
3419 	if (row == 0)
3420 	{
3421 		pRow = getNthRow(0);
3422 		iYRow = pRow->position;
3423 	}
3424 	else if ((row < numRows) && (row > 0))
3425 	{
3426 		pRow = getNthRow(row);
3427 		iYRow = pRow->position - pRow->spacing/2;
3428 	}
3429 	else
3430 	{
3431 		pRow = getNthRow(numRows - 1);
3432 		iYRow = pRow->position + pRow->allocation;
3433 		iYRow += m_iBorderWidth;
3434 	}
3435 
3436 	return iYRow;
3437  }
3438 
3439 
3440 /*!
3441  * Return the X location of column number col
3442  */
getXOfColumn(UT_sint32 col) const3443 UT_sint32 fp_TableContainer::getXOfColumn(UT_sint32 col) const
3444 {
3445 	if (getMasterTable())
3446 	{
3447 		return getMasterTable()->getXOfColumn(col);
3448 	}
3449 	UT_sint32 numCols = getNumCols();
3450 	if((col > numCols) || (numCols == 0))
3451 	{
3452 		return 0;
3453 	}
3454 
3455 	UT_sint32 iXCol = 0;
3456 	fp_TableRowColumn *pCol = NULL;
3457 	if (col == 0)
3458 	{
3459 		pCol = getNthCol(0);
3460 		iXCol = pCol->position;
3461 	}
3462 	else if ((col < numCols) && (col > 0))
3463 	{
3464 		pCol = getNthCol(col);
3465 		iXCol = pCol->position - pCol->spacing/2;
3466 	}
3467 	else
3468 	{
3469 		pCol = getNthCol(numCols - 1);
3470 		iXCol = pCol->position + pCol->allocation;
3471 	}
3472 
3473 	return iXCol;
3474  }
3475 
3476 
3477 /*!
3478  * This static function is used to compare cells' position for the
3479  * UT_Vector::binarysearch
3480 \param vX1 pointer to a Point value.
3481 \param vX2 pointer to a fp_CellContainer object
3482 */
compareCellPosBinary(const void * vX1,const void * vX2)3483 static UT_sint32 compareCellPosBinary(const void * vX1, const void * vX2)
3484 {
3485 	const UT_Point *pt = static_cast<const UT_Point *>(vX1);
3486 	const fp_ContainerObject *pc = *(fp_ContainerObject **)(vX2);
3487 	const fp_CellContainer *pCell = static_cast<const fp_CellContainer *>(pc);
3488 
3489 	if((pCell->getTopAttach()) <= pt->y && (pCell->getBottomAttach() > pt->y)
3490 	   && (pCell->getLeftAttach() <= pt->x) && (pCell->getRightAttach() > pt->x))
3491 	{
3492 		return 0;
3493 	}
3494 	// compare cell's top and bottom first
3495 	if (pCell->getTopAttach() > pt->y)
3496 	{
3497 		return -1;
3498 	}
3499 	if (pCell->getBottomAttach() <= pt->y)
3500 	{
3501 		return 1;
3502 	}
3503 	// then compare cell's left position
3504 	if (pCell->getLeftAttach() > pt->x)
3505 	{
3506 		return -1;
3507 	}
3508 	if (pCell->getRightAttach() <= pt->x)
3509 	{
3510 		return 1;
3511 	}
3512 
3513 	return 0;
3514 }
3515 
3516 /*!
3517  * Binary search failed. Do a simple Linear search instead
3518  */
getCellAtRowColumnLinear(UT_sint32 row,UT_sint32 col) const3519 fp_CellContainer * fp_TableContainer::getCellAtRowColumnLinear(UT_sint32 row, UT_sint32 col) const
3520 {
3521 	UT_sint32 i = 0;
3522 	fp_CellContainer * pCell = NULL;
3523 	bool bFound = false;
3524 	for(i=0; (i<countCons()) && !bFound; i++)
3525 	{
3526 		pCell = static_cast<fp_CellContainer *>(getNthCon(i));
3527 		if((pCell->getTopAttach()) <= row && (pCell->getBottomAttach() > row)
3528 		   && (pCell->getLeftAttach() <= col) && (pCell->getRightAttach() > col))
3529 		{
3530 			return pCell;
3531 		}
3532 	}
3533 	return NULL;
3534 }
3535 /*!
3536  * Return the cell container at the specified row and column
3537  */
getCellAtRowColumn(UT_sint32 row,UT_sint32 col) const3538 fp_CellContainer * fp_TableContainer::getCellAtRowColumn(UT_sint32 row, UT_sint32 col) const
3539 {
3540 	UT_Point pt;
3541 	pt.x = col;
3542 	pt.y = row;
3543 	if((row >= getNumRows()) || (row <0))
3544 	{
3545 		return NULL;
3546 	}
3547 	if((col >= getNumCols()) || (col < 0))
3548 	{
3549 		return NULL;
3550 	}
3551 	UT_sint32 u =-1;
3552 	u = binarysearchCons(&pt, compareCellPosBinary);
3553 	if (u != -1)
3554 	{
3555 		fp_CellContainer *pSmall = static_cast<fp_CellContainer *>(getNthCon(u));
3556 		if((pSmall->getTopAttach() > row) || (pSmall->getBottomAttach() <= row)
3557 		   || (pSmall->getLeftAttach() > col) || (pSmall->getRightAttach() <= col))
3558 			{
3559 				xxx_UT_DEBUGMSG(("No cell found 1 at %d %d \n",row,col));
3560 				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));
3561 				return getCellAtRowColumnLinear(row,col);
3562 			}
3563 		return pSmall;
3564 	}
3565 	xxx_UT_DEBUGMSG(("No cell found -2 at %d %d \n",row,col));
3566 	return getCellAtRowColumnLinear(row,col);
3567 }
3568 
3569 /*
3570  * This method looks up the various propeties of the table and returns the
3571  * height of a given row. The input parameter iMeasHeight is the height
3572  * the row would have if it's height was automatically calculated from the
3573  * height of the rows.
3574  */
getRowHeight(UT_sint32 iRow,UT_sint32 iMeasHeight)3575 UT_sint32 fp_TableContainer::getRowHeight(UT_sint32 iRow, UT_sint32 iMeasHeight)
3576 {
3577 	fl_TableLayout * pTL = static_cast<fl_TableLayout *>(getSectionLayout());
3578 	UT_return_val_if_fail(pTL, 0);
3579 	const  UT_GenericVector<fl_RowProps*>* pVecRow = pTL->getVecRowProps();
3580 	if(pVecRow->getItemCount() < (iRow + 1))
3581 	{
3582 		if(m_iRowHeight == 0)
3583 		{
3584 			return iMeasHeight;
3585 		}
3586 		if(m_iRowHeightType == FL_ROW_HEIGHT_EXACTLY)
3587 		{
3588 			return m_iRowHeight;
3589 		}
3590 		if(m_iRowHeightType == FL_ROW_HEIGHT_AT_LEAST)
3591 		{
3592 			if(iMeasHeight < m_iRowHeight)
3593 			{
3594 				return m_iRowHeight;
3595 			}
3596 			else
3597 			{
3598 				return iMeasHeight;
3599 			}
3600 		}
3601 		return iMeasHeight;
3602 	}
3603 	fl_RowProps * pRowProps = pVecRow->getNthItem(iRow);
3604 	UT_sint32 iRowHeight = pRowProps->m_iRowHeight;
3605 	FL_RowHeightType rowType = pRowProps->m_iRowHeightType;
3606 	if(rowType == FL_ROW_HEIGHT_EXACTLY )
3607 	{
3608 		return iRowHeight;
3609 	}
3610 	if(rowType == FL_ROW_HEIGHT_AT_LEAST)
3611 	{
3612 		if(iMeasHeight < iRowHeight)
3613 		{
3614 			return iRowHeight;
3615 		}
3616 		else
3617 		{
3618 			return iMeasHeight;
3619 		}
3620 	}
3621 	if(rowType == FL_ROW_HEIGHT_AUTO)
3622 	{
3623 		return iMeasHeight;
3624 	}
3625 //
3626 // Here is the row type is undefined
3627 //
3628 	if(m_iRowHeightType == FL_ROW_HEIGHT_EXACTLY)
3629 	{
3630 		if(m_iRowHeight == 0 )
3631 		{
3632 			if(iRowHeight > 0)
3633 			{
3634 				return iRowHeight;
3635 			}
3636 			else
3637 			{
3638 				return iMeasHeight;
3639 			}
3640 		}
3641 		else
3642 		{
3643 			return m_iRowHeight;
3644 		}
3645 	}
3646 	if(m_iRowHeightType == FL_ROW_HEIGHT_AT_LEAST)
3647 	{
3648 		if(m_iRowHeight > 0)
3649 		{
3650 			if(iMeasHeight < m_iRowHeight)
3651 			{
3652 				return m_iRowHeight;
3653 			}
3654 			else
3655 			{
3656 				return iMeasHeight;
3657 			}
3658 			return iMeasHeight;
3659 		}
3660 		if(iMeasHeight > iRowHeight)
3661 		{
3662 			return iMeasHeight;
3663 		}
3664 		else
3665 		{
3666 			return iRowHeight;
3667 		}
3668 	}
3669 	if(m_iRowHeightType == FL_ROW_HEIGHT_AUTO)
3670 	{
3671 		return iMeasHeight;
3672 	}
3673 //
3674 // Undefined on undefined with a defined height - assume AT_LEAST
3675 //
3676 	if(iMeasHeight > iRowHeight)
3677 	{
3678 		return iMeasHeight;
3679 	}
3680 	return iRowHeight;
3681 }
3682 
3683 
3684 /*!
3685   Find document position from X and Y coordinates
3686  \param  x X coordinate
3687  \param  y Y coordinate
3688  \retval pos Document position
3689  \retval bBOL True if position is at begining of line, otherwise false
3690  \retval bEOL True if position is at end of line, otherwise false
3691  */
mapXYToPosition(UT_sint32 x,UT_sint32 y,PT_DocPosition & pos,bool & bBOL,bool & bEOL,bool & isTOC)3692 void fp_TableContainer::mapXYToPosition(UT_sint32 x, UT_sint32 y, PT_DocPosition& pos,
3693 										bool& bBOL, bool& bEOL, bool & isTOC)
3694 {
3695 	bool bAboveTable = false;
3696 	if (y <= 0)
3697 	{
3698 		y = 1;
3699 		bAboveTable = true;
3700 	}
3701 
3702 	fp_TableContainer * pMaster = NULL;
3703 	if(isThisBroken())
3704 	{
3705 		pMaster = getMasterTable();
3706 		y = y + getYBreak();
3707 		if (y >= getYBottom())
3708 		{
3709 			y = getYBottom() - 1;
3710 		}
3711 	}
3712 	else
3713 	{
3714 		pMaster = this;
3715 		if (getFirstBrokenTable() && y >= getFirstBrokenTable()->getYBottom())
3716 		{
3717 			y = getFirstBrokenTable()->getYBottom() - 1;
3718 		}
3719 	}
3720 
3721 	if(!pMaster->countCons())
3722 	{
3723 		UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
3724 		pos = 2;
3725 		bBOL = true;
3726 		bEOL = true;
3727 		return;
3728 	}
3729 
3730 	xxx_UT_DEBUGMSG(("SEVIOR: Table %x Looking for location x %d y %d \n",this,x,y));
3731 	UT_sint32 row = pMaster->getRowOrColumnAtPosition(y,true);
3732 	UT_sint32 col = pMaster->getRowOrColumnAtPosition(x,false);
3733 	fp_CellContainer * pCell = pMaster->getCellAtRowColumn(row,col);
3734 	if (!pCell)
3735 	{
3736 		col--;
3737 		while (!pCell && col >= 0)
3738 		{
3739 			pCell = pMaster->getCellAtRowColumn(row,col);
3740 			col--;
3741 		}
3742 		if (!pCell)
3743 		{
3744 			pCell = static_cast<fp_CellContainer*>(pMaster->getFirstContainer());
3745 		}
3746 	}
3747 	UT_sint32 xCell = x - pCell->getX();
3748 	UT_sint32 yCell = y - pCell->getY();
3749 	if (bAboveTable)
3750 	{
3751 		// If the cell is broken between two pages, we need tomake sure that the y
3752 		// value points to a line within the good page.
3753 		// TODO create a fp_CellContainer version of mapXYToPosition instead of
3754 		//      using fp_VerticalContainer::mapXYToPosition
3755 		fp_Container * pCon = pCell->getFirstContainerInBrokenTable(this);
3756 		if (pCon && (pCon->getY() + 1 > yCell))
3757 		{
3758 			yCell = pCon->getY() + 1;
3759 		}
3760 	}
3761 	pCell->mapXYToPosition(xCell, yCell, pos, bBOL, bEOL,isTOC);
3762 	return;
3763 }
3764 
3765 
getRowOrColumnAtPosition(UT_sint32 y,bool bRow) const3766 UT_sint32 fp_TableContainer::getRowOrColumnAtPosition(UT_sint32 y, bool bRow) const
3767 {
3768 	if (isThisBroken())
3769 	{
3770 		return getMasterTable()->getRowOrColumnAtPosition(y,bRow);
3771 	}
3772 	UT_sint32 count = (bRow) ? getNumRows() : getNumCols();
3773 	UT_sint32 k = 0;
3774 	for (k = 0; k < count; k++)
3775 	{
3776 		if (y < getYOfRowOrColumn(k + 1,bRow))
3777 		{
3778 			break;
3779 		}
3780 	}
3781 	return (k < count) ? k : (count - 1);
3782 }
3783 
3784 
resize(UT_sint32 n_rows,UT_sint32 n_cols)3785 void fp_TableContainer::resize(UT_sint32 n_rows, UT_sint32 n_cols)
3786 {
3787 	fl_TableLayout * pTL = static_cast<fl_TableLayout *>(getSectionLayout());
3788 	if (!pTL->isInitialLayoutCompleted() || (n_rows != m_iRows) ||
3789 		( n_cols != m_iCols))
3790 	{
3791 		if (!pTL->isInitialLayoutCompleted() || (n_rows != m_iRows))
3792 		{
3793 			UT_sint32 i;
3794 			m_iRows = n_rows;
3795 			UT_VECTOR_PURGEALL(fp_TableRowColumn *, m_vecRows);
3796 			m_vecRows.clear();
3797 			for(i=0; i< m_iRows; i++)
3798 			{
3799 				m_vecRows.addItem(new fp_TableRowColumn(m_iRowSpacing));
3800 			}
3801 		}
3802 
3803 		if (!pTL->isInitialLayoutCompleted() || (n_cols != m_iCols))
3804 		{
3805 			UT_sint32 i;
3806 			m_iCols = n_cols;
3807 			UT_VECTOR_PURGEALL(fp_TableRowColumn *, m_vecColumns);
3808 			m_vecColumns.clear();
3809 			for(i=0; i< m_iCols; i++)
3810 			{
3811 				m_vecColumns.addItem(new fp_TableRowColumn(m_iColSpacing));
3812 			}
3813 		}
3814 	}
3815 }
3816 
3817 /*!
3818  * Returns true if this is a broken table
3819  */
isThisBroken(void) const3820 bool fp_TableContainer::isThisBroken(void) const
3821 {
3822 	return m_bIsBroken;
3823 }
3824 /*!
3825  * Returns true since a table can be broken vertically.
3826  */
isVBreakable(void)3827 bool fp_TableContainer::isVBreakable(void)
3828 {
3829 	return true;
3830 }
3831 
3832 
3833 /*!
3834  * This deletes all the broken tables from this master table.
3835  * This routine assumes that a clear screen has been set already.
3836  */
deleteBrokenTables(bool bClearFirst,bool bRecurseUp)3837 void fp_TableContainer::deleteBrokenTables(bool bClearFirst, bool bRecurseUp)
3838 {
3839 	if(isThisBroken())
3840 	{
3841 		return;
3842 	}
3843 	if(bClearFirst)
3844 	{
3845 		clearScreen();
3846 		//
3847 		// Remove broken Table pointers
3848 		//
3849 		clearBrokenContainers();
3850 	}
3851 	if(getFirstBrokenTable() == NULL)
3852 	{
3853 		return;
3854 	}
3855 	fp_TableContainer * pUpTab = this;
3856 	if(bRecurseUp)
3857 	{
3858 		while(pUpTab && pUpTab->getContainer() && pUpTab->getContainer()->getContainerType() == FP_CONTAINER_CELL)
3859 		{
3860 			fp_CellContainer * pUpCell = static_cast<fp_CellContainer *>(pUpTab->getContainer());
3861 			pUpTab = static_cast<fp_TableContainer *>(pUpCell->getContainer());
3862 		}
3863 		if(pUpTab && (pUpTab != this))
3864 		{
3865 			pUpTab->deleteBrokenTables(bClearFirst,false);
3866 			return;
3867 		}
3868 	}
3869 	if(containsNestedTables())
3870 	{
3871 		xxx_UT_DEBUGMSG(("Deleting nested broken tables \n"));
3872 		fp_CellContainer * pCell = static_cast<fp_CellContainer *>(getFirstContainer());
3873 		while(pCell)
3874 		{
3875 			xxx_UT_DEBUGMSG(("Deleting broken tables in Cell Con %x \n",pCell));
3876 			pCell->deleteBrokenTables(bClearFirst);
3877 			pCell = static_cast<fp_CellContainer *>(pCell->getNext());
3878 		}
3879 	}
3880 
3881 	fp_TableContainer * pBroke = NULL;
3882 	fp_TableContainer * pNext = NULL;
3883 	pBroke = getFirstBrokenTable();
3884 	bool bDontRemove = false;
3885 	fl_ContainerLayout * pMyConL = getSectionLayout()->myContainingLayout();
3886 	if(pMyConL && pMyConL->getContainerType() == FL_CONTAINER_CELL)
3887 	{
3888 		pMyConL = pMyConL->myContainingLayout();
3889 		fl_TableLayout * pTL = static_cast<fl_TableLayout *>(pMyConL);
3890 		if(pTL->isDoingDestructor())
3891 		{
3892 				bDontRemove = true;
3893 		}
3894 	}
3895 	while(pBroke )
3896 	{
3897 		pNext = static_cast<fp_TableContainer *>(pBroke->getNext());
3898 		//
3899 		// Remove from list
3900 		//
3901 		if(pBroke->getPrev())
3902 		{
3903 			pBroke->getPrev()->setNext(pBroke->getNext());
3904 		}
3905 		if(pBroke->getNext())
3906 		{
3907 			pBroke->getNext()->setPrev(pBroke->getPrev());
3908 		}
3909 		if(pBroke->getContainer() && !bDontRemove)
3910 		{
3911 			UT_sint32 i = pBroke->getContainer()->findCon(pBroke);
3912 //
3913 // First broken table is not in the container.
3914 //
3915 			if(i >=0)
3916 			{
3917 				fp_Container * pCon = pBroke->getContainer();
3918 				pBroke->setContainer(NULL);
3919 				pCon->deleteNthCon(i);
3920 				xxx_UT_DEBUGMSG(("Delete %x from column %x \n",pBroke,pCon));
3921 				//
3922 				// Search before and after. This should not happen!
3923 				// FIXME put in some code to detect this in breakSection
3924 				//
3925 				fp_Container * pPrevCon = static_cast<fp_Container *>(pCon->getPrev());
3926 				while(pPrevCon && i >=0)
3927 				{
3928 					i = pPrevCon->findCon(pBroke);
3929 					UT_sint32 j = i;
3930 					while(j >= 0)
3931 					{
3932 						xxx_UT_DEBUGMSG(("Also remove table %x from column %x \n",pBroke,pPrevCon));
3933 						pPrevCon->deleteNthCon(j);
3934 						j = pPrevCon->findCon(pBroke);
3935 					}
3936 					pPrevCon = static_cast<fp_Container *>(pPrevCon->getPrev());
3937 				}
3938 				fp_Container * pNextCon = static_cast<fp_Container *>(pCon->getNext());
3939 				i = 0;
3940 				while(pNextCon && (i>=0))
3941 				{
3942 					i = pNextCon->findCon(pBroke);
3943 					UT_sint32 j = i;
3944 					while(j >= 0)
3945 					{
3946 						xxx_UT_DEBUGMSG(("Also remove table %x from column %x \n",pBroke,pNextCon));
3947 						pNextCon->deleteNthCon(j);
3948 						j = pNextCon->findCon(pBroke);
3949 					}
3950 					pNextCon = static_cast<fp_Container *>(pNextCon->getNext());
3951 				}
3952 			}
3953 		}
3954 		xxx_UT_DEBUGMSG(("SEVIOR: table %x  Deleting broken table %x \n",this,pBroke));
3955 		delete pBroke;
3956 		if(pBroke == getLastBrokenTable())
3957 		{
3958 			pBroke = NULL;
3959 		}
3960 		else
3961 		{
3962 			pBroke = pNext;
3963 		}
3964 	}
3965 	setFirstBrokenTable(NULL);
3966 	setLastBrokenTable(NULL);
3967 	setNext(NULL);
3968 	setPrev(NULL);
3969 //	if(bClearFirst)
3970 	{
3971 		fl_TableLayout * pTL = static_cast<fl_TableLayout *>(getSectionLayout());
3972 		if(pTL->myContainingLayout()->getContainerType() != FL_CONTAINER_CELL)
3973 		{
3974 			fl_DocSectionLayout * pDSL = pTL->getDocSectionLayout();
3975 			pDSL->deleteBrokenTablesFromHere(pTL);
3976 		}
3977 	}
3978 }
3979 
3980 
3981 /*
3982   Delete all broken tables that follows this table. The first broken table
3983   is kept if the function is called by the master table.
3984 */
3985 
deleteBrokenAfter(bool bClearFirst)3986 void fp_TableContainer::deleteBrokenAfter(bool bClearFirst)
3987 {
3988 	if (!isThisBroken())
3989 	{
3990 		if (getFirstBrokenTable())
3991 		{
3992 			return getFirstBrokenTable()->deleteBrokenAfter(bClearFirst);
3993 		}
3994 		return;
3995 	}
3996 
3997 	if (bClearFirst)
3998 	{
3999 		clearScreen();
4000 		getMasterTable()->clearBrokenContainers();
4001 	}
4002 
4003 	fp_TableContainer * pBroke = static_cast<fp_TableContainer *>(getNext());
4004 	fp_TableContainer * pNext = NULL;
4005 	while(pBroke)
4006 	{
4007 		pNext = static_cast<fp_TableContainer *> (pBroke->getNext());
4008 		if (pBroke->getContainer())
4009 		{
4010 			UT_sint32 i = pBroke->getContainer()->findCon(pBroke);
4011 			if (i >= 0)
4012 			{
4013 				pBroke->getContainer()->deleteNthCon(i);
4014 				pBroke->setContainer(NULL);
4015 			}
4016 		}
4017 		delete pBroke;
4018 		pBroke = pNext;
4019 	}
4020 
4021 	setNext(NULL);
4022 	if (!getPrev())
4023 	{
4024 		getMasterTable()->setNext(NULL);
4025 	}
4026 	getMasterTable()->setLastBrokenTable(this);
4027 	UT_sint32 iOldYBottom = getYBottom();
4028 	setYBottom(getTotalTableHeight());
4029 
4030 	if (containsNestedTables())
4031 	{
4032 		// delete nested broken tables
4033 		fp_CellContainer * pCell = m_pFirstBrokenCell;
4034 		if (!pCell)
4035 		{
4036 			pCell = static_cast<fp_CellContainer*>(getMasterTable()->getFirstContainer());
4037 		}
4038 		while (pCell)
4039 		{
4040 			if (pCell->getY() + pCell->getHeight() > iOldYBottom)
4041 			{
4042 				pCell->deleteBrokenAfter(bClearFirst,iOldYBottom);
4043 			}
4044 			pCell = static_cast<fp_CellContainer*>(pCell->getNext());
4045 		}
4046 	}
4047 }
4048 
setHeight(UT_sint32 iHeight)4049 void fp_TableContainer::setHeight(UT_sint32 iHeight)
4050 {
4051 	if(!isThisBroken())
4052 	{
4053 		xxx_UT_DEBUGMSG(("Unbroken Table Height set to %d from %d \n",iHeight,getHeight()));
4054 	}
4055 
4056 	fp_VerticalContainer::setHeight(iHeight);
4057 }
4058 
4059 /*
4060  * Return the margin before the table. Note that TopOffset (set by the property table-margin-top)
4061  * is not considered a margin, but as a gap at the top of the table (it is included in the height of
4062  * the fp_TableContainer object). This allows to move down a table that is placed at the top of a page.
4063  */
4064 
getMarginBefore(void) const4065 UT_sint32 fp_TableContainer::getMarginBefore(void) const
4066 {
4067 
4068 	if(!isThisBroken() || !getPrev())
4069 	{
4070 		// getMargin of previous block
4071 		fl_TableLayout * pTL = static_cast<fl_TableLayout *>(getSectionLayout());
4072 		fl_ContainerLayout * pCL = pTL->getPrev();
4073 		if(pCL && pCL->getContainerType() == FL_CONTAINER_BLOCK)
4074 		{
4075 			return static_cast<fl_BlockLayout *>(pCL)->getBottomMargin();
4076 		}
4077 		return 0;
4078 	}
4079 	return 0;
4080 }
4081 
4082 /*
4083  * Return the margin after the table. Note that BottomOffset (set by the property table-margin-bottom)
4084  * is considered a margin and the function returns the maximum of BottomOffset and the margin before of
4085  * the following block.
4086  */
4087 
4088 
getMarginAfter(void) const4089 UT_sint32 fp_TableContainer::getMarginAfter(void) const
4090 {
4091 	if(!isThisBroken() || !getNext())
4092 	{
4093 		fl_TableLayout * pTL = static_cast<fl_TableLayout *>(getSectionLayout());
4094 		fl_ContainerLayout * pCL = pTL->getNext();
4095 		if(pCL && pCL->getContainerType() == FL_CONTAINER_BLOCK)
4096 		{
4097 			return UT_MAX(static_cast<fl_BlockLayout *>(pCL)->getTopMargin(),pTL->getBottomOffset());
4098 		}
4099 		return pTL->getBottomOffset();
4100 	}
4101 	return 0;
4102 }
4103 
4104 /*!
4105  * vpos is the location from the top of the table that holds these
4106  * cells.
4107  */
breakCellsAt(UT_sint32 vpos)4108 void fp_TableContainer::breakCellsAt(UT_sint32 vpos)
4109 {
4110 	if(!containsNestedTables())
4111 	{
4112 		return;
4113 	}
4114 	fp_TableContainer * pMaster = NULL;
4115 	if(isThisBroken())
4116 	{
4117 		pMaster = getMasterTable();
4118 	}
4119 	else
4120 	{
4121 		pMaster = this;
4122 	}
4123 	fp_CellContainer * pCell = static_cast<fp_CellContainer *>(pMaster->getNthCon(0));
4124 	while(pCell)
4125 	{
4126 		if(pCell->getY() >= vpos)
4127 		{
4128 			break;
4129 		}
4130 		if((pCell->getY() + pCell->getHeight()) > vpos)
4131 		{
4132 			pCell->VBreakAt(vpos - pCell->getY());
4133 		}
4134 		pCell = static_cast<fp_CellContainer *>(pCell->getNext());
4135 	}
4136 }
4137 
4138 /*!
4139  * This method creates a new broken tablecontainer, broken at the
4140  * offset given.
4141  * If the new tablecontainer is broken from a pre-existing
4142  * broken table it is inserted into the holding vertical container after
4143  * the old broken table.
4144  * It also inserted into the linked list of containers in the vertical
4145  * container.
4146  * vpos is relative to the either the start of the table if it's the first
4147  * non-zero vpos or relative to the previous ybreak if it's further down.
4148  */
VBreakAt(UT_sint32 vpos)4149 fp_ContainerObject * fp_TableContainer::VBreakAt(UT_sint32 vpos)
4150 {
4151 /*
4152  If this table is nested in a cell we break it and leave it in the cell.
4153 
4154  cell->Master------>more lines
4155        \
4156         Broke->Broke->Broke|more lines
4157  The offsets for each line
4158  will be calculated only with the top level broken table.
4159 */
4160 
4161 //
4162 // Do the case of creating the first broken table from the master table.
4163 //
4164 	fp_TableContainer * pBroke = NULL;
4165 	if(!isThisBroken() && getLastBrokenTable() == NULL)
4166 	{
4167 		if(getFirstBrokenTable() != NULL)
4168 		{
4169 			UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
4170 			return NULL;
4171 		}
4172 		pBroke = new fp_TableContainer(getSectionLayout(),this);
4173 		xxx_UT_DEBUGMSG(("SEVIOR:!!!!!!! Frist broken table %x \n",pBroke));
4174 		pBroke->setYBreakHere(vpos);
4175 		pBroke->setYBottom(getTotalTableHeight());
4176 		setFirstBrokenTable(pBroke);
4177 		setLastBrokenTable(pBroke);
4178 		pBroke->setContainer(getContainer());
4179 		static_cast<fp_VerticalContainer *>(pBroke)->setHeight(pBroke->getHeight());
4180 		static_cast<fp_VerticalContainer *>(pBroke)->setY(getY());
4181 		pBroke->breakCellsAt(vpos);
4182 		return pBroke;
4183 	}
4184 //
4185 // Now do the case of breaking a Master table.
4186 //
4187 	if(getMasterTable() == NULL)
4188 	{
4189 		return getLastBrokenTable()->VBreakAt(vpos);
4190 	}
4191 	pBroke = new fp_TableContainer(getSectionLayout(),getMasterTable());
4192 	getMasterTable()->setLastBrokenTable(pBroke);
4193 
4194 	UT_sint32 iTotalHeight = getTotalTableHeight();
4195 	UT_sint32 iNewYBreak = vpos + getYBreak();
4196 	if(getContainer() && getContainer()->getContainerType() == FP_CONTAINER_CELL)
4197 	{
4198 		if (m_iNextWantedVBreak <= 0)
4199 		{
4200 			return NULL;
4201 		}
4202 		iNewYBreak = m_iNextWantedVBreak + getYBreak();
4203 		UT_ASSERT(iNewYBreak > 0);
4204 	}
4205 	if (iNewYBreak >= iTotalHeight)
4206 	{
4207 		UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
4208 		return NULL;
4209 	}
4210 
4211 //
4212 // vpos is relative to the container that contains this height but we need
4213 // to add in the height above it.
4214 //
4215 	pBroke->setYBreakHere(iNewYBreak);
4216 	setYBottom(iNewYBreak -1);
4217 	pBroke->setYBottom(iTotalHeight);
4218 	UT_ASSERT(getHeight() > 0);
4219 	UT_ASSERT(pBroke->getHeight() > 0);
4220 
4221 //
4222 // The structure of table linked list is as follows.
4223 // NULL <= Master <==> Next <==> Next => NULL
4224 //          first
4225 // ie terminated by NULL's in the getNext getPrev list. The second
4226 // broken table points and is pointed to by the Master table
4227 //
4228 	pBroke->setPrev(this);
4229 	fp_Container * pUpCon = NULL;
4230 	UT_sint32 i = -1;
4231 	if(getMasterTable()->getFirstBrokenTable() == this)
4232 	{
4233 		pUpCon = getMasterTable()->getContainer();
4234   		pBroke->setPrev(getMasterTable());
4235   		pBroke->setNext(NULL);
4236   		getMasterTable()->setNext(pBroke);
4237 		setNext(pBroke);
4238 		if (pUpCon)
4239 		{
4240 			i = pUpCon->findCon(getMasterTable());
4241 		}
4242 	}
4243 	else
4244 	{
4245 		pBroke->setNext(NULL);
4246   		setNext(pBroke);
4247 		if(getYBreak() == 0 )
4248 		{
4249 			UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
4250 			pUpCon = getMasterTable()->getContainer();
4251 			if (pUpCon)
4252 			{
4253 				i = pUpCon->findCon(getMasterTable());
4254 			}
4255 		}
4256 		else
4257 		{
4258 			pUpCon = getContainer();
4259 			if (pUpCon)
4260 			{
4261 				i = pUpCon->findCon(this);
4262 			}
4263 		}
4264 	}
4265 
4266 	if((i >=0) && (i < pUpCon->countCons() - 1))
4267 	{
4268 		pUpCon->insertConAt(pBroke,i+1);
4269 	}
4270 	else if((i >= 0) && (i == pUpCon->countCons() -1))
4271 	{
4272 		pUpCon->addCon(pBroke);
4273 	}
4274 	else
4275 	{
4276 		UT_DEBUGMSG(("Breaking a table that is not yet inserted\n"));
4277 	}
4278 	pBroke->setContainer(pUpCon);
4279 	static_cast<fp_VerticalContainer *>(pBroke)->setHeight(pBroke->getHeight());
4280 	//
4281 	// The cells are broken relative to the top of the table
4282 	//
4283 	breakCellsAt(getYBottom());
4284 	return pBroke;
4285 }
4286 
4287 
4288 /*!
4289  * Overload the setY method
4290  */
setY(UT_sint32 i)4291 void fp_TableContainer::setY(UT_sint32 i)
4292 {
4293 	bool bIsFirstBroken = false;
4294 	xxx_UT_DEBUGMSG(("fp_TableContainer: setY set to %d \n",i));
4295 	if(isThisBroken())
4296 	{
4297 		xxx_UT_DEBUGMSG(("setY: getMasterTable %x FirstBrokenTable %x this %x \n",getMasterTable(),getMasterTable()->getFirstBrokenTable(),this));
4298 		if(getMasterTable()->getFirstBrokenTable() != this)
4299 		{
4300 			xxx_UT_DEBUGMSG(("setY: Later broken table set to %d \n",i));
4301 			fp_VerticalContainer::setY(i);
4302 			return;
4303 		}
4304 		bIsFirstBroken = true;
4305 	}
4306 //
4307 // Create an initial broken table if none exists
4308 //
4309 	if(!bIsFirstBroken && (getFirstBrokenTable() == NULL))
4310 	{
4311 		VBreakAt(0);
4312 	}
4313 	UT_sint32 iOldY = getY();
4314 	if(i == iOldY)
4315 	{
4316 		return;
4317 	}
4318 	clearScreen();
4319 
4320 	xxx_UT_DEBUGMSG(("Set Reformat 1 now from table %x in TableLayout %x \n",this,getSectionLayout()));
4321 	fp_VerticalContainer::setY(i);
4322 }
4323 
4324 
setYBreakHere(UT_sint32 i)4325 void fp_TableContainer::setYBreakHere(UT_sint32 i)
4326 {
4327 	xxx_UT_DEBUGMSG(("SEVIOR: Ybreak set to %d \n",i));
4328 	m_iYBreakHere = i;
4329 }
4330 
setYBottom(UT_sint32 i)4331 void fp_TableContainer::setYBottom(UT_sint32 i)
4332 {
4333 	m_iYBottom = i;
4334 	//	UT_ASSERT(getHeight() > 0);
4335 }
4336 
4337 /*!
4338  * The caller to this method requests a break at the vertical height
4339  * given. It returns the actual break height, which will always be
4340  * less than or equal to the requested height. The function returns -1
4341  * if the table does not need to be broken.
4342  */
wantVBreakAt(UT_sint32 vpos)4343 UT_sint32 fp_TableContainer::wantVBreakAt(UT_sint32 vpos)
4344 {
4345 	if (!isThisBroken())
4346 	{
4347 		if (!getFirstBrokenTable())
4348 		{
4349 			VBreakAt(0);
4350 			UT_ASSERT(getFirstBrokenTable());
4351 		}
4352 		return getFirstBrokenTable()->wantVBreakAt(vpos);
4353 	}
4354 
4355 	// Check if the table has footnotes and call the appropriate function
4356 	fl_TableLayout * pTL = static_cast<fl_TableLayout *>(getSectionLayout());
4357 	if (pTL->containsFootnoteLayouts() ||
4358 		(pTL->getDocLayout()->displayAnnotations() && pTL->containsAnnotationLayouts()))
4359 	{
4360 		return wantVBreakAtWithFootnotes(vpos);
4361 	}
4362 	else
4363 	{
4364 		return wantVBreakAtNoFootnotes(vpos);
4365 	}
4366 }
4367 
wantVBreakAtNoFootnotes(UT_sint32 vpos)4368 UT_sint32 fp_TableContainer::wantVBreakAtNoFootnotes(UT_sint32 vpos)
4369 {
4370 	UT_sint32 iYBreakMax = vpos + getYBreak();
4371 	UT_sint32 iTotHeight = getTotalTableHeight();
4372 	if (iYBreakMax > iTotHeight)
4373 	{
4374 		// The table fits in the column. No need to break it
4375 		return -1;
4376 	}
4377 	else if (iYBreakMax > iTotHeight - FP_TABLE_MIN_BROKEN_HEIGHT)
4378 	{
4379 		iYBreakMax = iTotHeight - FP_TABLE_MIN_BROKEN_HEIGHT;
4380 	}
4381 
4382 	fp_CellContainer * pCell = getFirstBrokenCell(false);
4383 
4384 	// To avoid breaking small cells, we first check if the table can be broken
4385 	// along a cell boundary. We test if the height of the gap left at the bottom
4386 	// of the page is smaller than a fraction of a full column height (colHeight).
4387 
4388 	UT_sint32 row = getRowOrColumnAtPosition(iYBreakMax,true);
4389 	fl_TableLayout * pTL = static_cast<fl_TableLayout *>(getSectionLayout());
4390 	UT_sint32 colHeight = pTL->getDocSectionLayout()->getActualColumnHeight();
4391 	if ((row > 0) && (colHeight*pTL->getMaxExtraMargin() > iYBreakMax - getYOfRow(row)))
4392 	{
4393 		// Check that the row is cell boundary for all columns
4394 		while (pCell)
4395 		{
4396 			if (!m_pFirstBrokenCell && (getYOfRow(pCell->getBottomAttach()) >= getYBreak()))
4397 			{
4398 				m_pFirstBrokenCell = pCell;
4399 			}
4400 			if (pCell->getBottomAttach() <= row)
4401 			{
4402 				pCell = static_cast<fp_CellContainer*>(pCell->getNext());
4403 			}
4404 			else if (pCell->getTopAttach() == row)
4405 			{
4406 				setAdditionalBottomSpace(0);
4407 				m_iNextWantedVBreak = getYOfRow(row) - getYBreak();
4408 				return (m_iNextWantedVBreak);
4409 			}
4410 			else
4411 			{
4412 				break;
4413 			}
4414 		}
4415 	}
4416 
4417 	// The table could not be broken along a cell boundary. Break table within cells
4418 
4419 	UT_sint32 iYBreak = iYBreakMax;
4420 	UT_sint32 iYBreakLine = 0;
4421 	while (pCell)
4422 	{
4423 		if (!m_pFirstBrokenCell && (getYOfRow(pCell->getBottomAttach()) >= getYBreak()))
4424 		{
4425 			m_pFirstBrokenCell = pCell;
4426 		}
4427 		if (getYOfRow(pCell->getTopAttach()) >= iYBreakMax)
4428 		{
4429 			break;
4430 		}
4431 		if(pCell->getY() <= iYBreakMax && pCell->getY() + pCell->getHeight() > iYBreakMax)
4432 		{
4433 			//
4434 			// Cell overlaps break point. Find break point in the cell.
4435 			//
4436 			UT_sint32 yCellMin = UT_MAX(getYBreak() - pCell->getY(),0);
4437 			UT_ASSERT(iYBreakMax > yCellMin);
4438 			UT_sint32 iCur = pCell->wantCellVBreakAt(iYBreakMax,yCellMin);
4439 			if(iCur < iYBreak)
4440 			{
4441 				iYBreak = iCur;
4442 			}
4443 			if (iCur > iYBreakLine)
4444 			{
4445 				iYBreakLine = iCur;
4446 			}
4447 		}
4448 		pCell = static_cast<fp_CellContainer*>(pCell->getNext());
4449 	}
4450 
4451 	// We need to do a second pass to find if there are some cells that could have fitted completely with the
4452 	// original break point that will be affected by the new break point. If that is the case, we adjust the
4453 	// bottom line position.
4454 	pCell = getFirstBrokenCell(false);
4455 	while (pCell)
4456 	{
4457 		if (getYOfRow(pCell->getTopAttach()) >= iYBreakMax)
4458 		{
4459 			break;
4460 		}
4461 		UT_sint32 iCellBottom = pCell->getY() + pCell->getHeight();
4462 		if((iCellBottom < iYBreakMax) && (iCellBottom > iYBreak) &&
4463 		   (pCell->getY() <= iYBreak) && (iCellBottom > iYBreakLine))
4464 		{
4465 			iYBreakLine = iCellBottom;
4466 		}
4467 		pCell = static_cast<fp_CellContainer*>(pCell->getNext());
4468 	}
4469 	setAdditionalBottomSpace(iYBreakLine - iYBreak);
4470 	m_iNextWantedVBreak = iYBreak;
4471 	return (iYBreak - getYBreak());
4472 }
4473 
4474 
wantVBreakAtWithFootnotes(UT_sint32 vpos)4475 UT_sint32 fp_TableContainer::wantVBreakAtWithFootnotes(UT_sint32 vpos)
4476 {
4477 	// This function is not optimized at all as it may require building several times
4478 	// nearly identical footnote vectors.
4479 	UT_sint32 iYBreakMax = vpos + getYBreak();
4480 	UT_sint32 iTotHeight = getTotalTableHeight();
4481 	if (iYBreakMax > iTotHeight)
4482 	{
4483 		// check if there is enough space to fit the table and the footnotes on the page
4484 		if (iYBreakMax > iTotHeight + sumFootnoteHeight())
4485 		{
4486 			return -1;
4487 		}
4488 	}
4489 
4490 	UT_sint32 iOrigBottom = getYBottom();
4491 	UT_sint32 vposHigh = vpos;
4492 	UT_sint32 vposLow = 0;
4493 	UT_sint32 iSumHigh = 0;
4494 	UT_sint32 iSumLow = vpos;
4495 	UT_sint32 k = 0;
4496 	for (k = 0; k < 10; k++)
4497 	{
4498 		setYBottom(getYBreak() + vposHigh);
4499 		iSumHigh = sumFootnoteHeight();
4500 		if (vpos - iSumHigh != vposLow)
4501 		{
4502 			vposLow = vpos - iSumHigh;
4503 		}
4504 		else
4505 		{
4506 			break;
4507 		}
4508 		setYBottom(getYBreak() + vposLow);
4509 		iSumLow = sumFootnoteHeight();
4510 		if (vpos - iSumLow != vposHigh)
4511 		{
4512 			vposHigh = vpos - iSumLow;
4513 		}
4514 		else
4515 		{
4516 			break;
4517 		}
4518 		if (vposHigh == vposLow)
4519 		{
4520 			break;
4521 		}
4522 	}
4523 
4524 	setYBottom(iOrigBottom);
4525 	return wantVBreakAtNoFootnotes(vposLow);
4526 }
4527 
4528 
4529 /*
4530    This function calculates the total height of all the footnotes in the broken table.
4531 */
4532 
sumFootnoteHeight(void)4533 UT_sint32 fp_TableContainer::sumFootnoteHeight(void)
4534 {
4535 	UT_sint32 iSum = 0;
4536 	fl_TableLayout * pTL = static_cast<fl_TableLayout *>(getSectionLayout());
4537 	if (pTL->containsFootnoteLayouts())
4538 	{
4539 		UT_GenericVector<fp_FootnoteContainer*> vecFootnotes;
4540 		getFootnoteContainers(&vecFootnotes);
4541 		UT_sint32 i = 0;
4542 		for(i = 0; i < vecFootnotes.getItemCount(); i++)
4543 		{
4544 			fp_FootnoteContainer * pFC = vecFootnotes.getNthItem(i);
4545 			iSum += pFC->getHeight();
4546 		}
4547 		vecFootnotes.clear();
4548 	}
4549 
4550 	if (pTL->getDocLayout()->displayAnnotations() && pTL->containsAnnotationLayouts())
4551 	{
4552 		UT_GenericVector<fp_AnnotationContainer*> vecAnnotations;
4553 		getAnnotationContainers(&vecAnnotations);
4554 		UT_sint32 i = 0;
4555 		for(i = 0; i < vecAnnotations.getItemCount(); i++)
4556 		{
4557 			fp_AnnotationContainer * pAC = vecAnnotations.getNthItem(i);
4558 			iSum += pAC->getHeight();
4559 		}
4560 		vecAnnotations.clear();
4561 	}
4562 
4563 	return iSum;
4564 }
4565 
4566 
getFirstBrokenContainer() const4567 fp_Container * fp_TableContainer::getFirstBrokenContainer() const
4568 {
4569 	return getFirstBrokenTable();
4570 }
4571 
4572 
4573 /*
4574   Return the height of the complete table as if it was not broken
4575 */
4576 
getTotalTableHeight(void) const4577 UT_sint32 fp_TableContainer::getTotalTableHeight(void) const
4578 {
4579 	if (getMasterTable())
4580 	{
4581 		return getMasterTable()->getTotalTableHeight();
4582 	}
4583 
4584 	return getYOfRow(getNumRows());
4585 }
4586 
4587 
4588 
4589 
4590 
4591 /*!
4592  * returns the first fp_Line of the table in this column by recursively
4593  * searching down the table structure.
4594  */
getFirstLineInColumn(fp_Column * pCol)4595 fp_Line * fp_TableContainer::getFirstLineInColumn(fp_Column * pCol)
4596 {
4597 	fp_TableContainer * pTab = NULL;
4598 	fp_TableContainer * pBroke = NULL;
4599 	fp_CellContainer * pCell = NULL;
4600 	if(!isThisBroken())
4601 	{
4602 		pTab = this;
4603 	}
4604 	else
4605 	{
4606 		pBroke = this;
4607 		pTab = getMasterTable();
4608 	}
4609 	pCell = static_cast<fp_CellContainer *>(pTab->getNthCon(0));
4610 	if(!pBroke)
4611 	{
4612 		while(pCell)
4613 		{
4614 			fp_Container * pFirst = static_cast<fp_Container *>(pCell->getNthCon(0));
4615 			while(pFirst && pCell->getColumn(pFirst) != static_cast<fp_VerticalContainer *>(pCol))
4616 			{
4617 				pFirst = static_cast<fp_Container *>(pFirst->getNext());
4618 			}
4619 			if(pFirst)
4620 			{
4621 				if(pFirst->getContainerType() == FP_CONTAINER_LINE)
4622 				{
4623 					return static_cast<fp_Line *>(pFirst);
4624 				}
4625 				if(pFirst->getContainerType() == FP_CONTAINER_TABLE)
4626 				{
4627 					return static_cast<fp_TableContainer *>(pFirst)->getFirstLineInColumn(pCol);
4628 				}
4629 				UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
4630 				return NULL;
4631 			}
4632 			pCell = static_cast<fp_CellContainer *>(pCell->getNext());
4633 		}
4634 		return NULL;
4635 	}
4636 	while(pCell)
4637 	{
4638 		if(pCell->doesOverlapBrokenTable(pBroke))
4639 		{
4640 			fp_Container * pFirst = static_cast<fp_Container *>(pCell->getNthCon(0));
4641 			while(pFirst && pCell->getColumn(pFirst) != static_cast<fp_VerticalContainer *>(pCol))
4642 			{
4643 				pFirst =  static_cast<fp_Container *>(pFirst->getNext());
4644 			}
4645 			if(pFirst)
4646 			{
4647 				if(pFirst->getContainerType() == FP_CONTAINER_LINE)
4648 				{
4649 					return static_cast<fp_Line *>(pFirst);
4650 				}
4651 				if(pFirst->getContainerType() == FP_CONTAINER_TABLE)
4652 				{
4653 					return static_cast<fp_TableContainer *>(pFirst)->getFirstLineInColumn(pCol);
4654 				}
4655 				UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
4656 				return NULL;
4657 			}
4658 		}
4659 		pCell =  static_cast<fp_CellContainer *>(pCell->getNext());
4660 	}
4661 	return NULL;
4662 }
4663 
4664 
4665 /*!
4666  * returns the Last fp_Line of the table in this column by recursively
4667  * searching down the table structure.
4668  */
getLastLineInColumn(fp_Column * pCol)4669 fp_Line * fp_TableContainer::getLastLineInColumn(fp_Column * pCol)
4670 {
4671 	fp_TableContainer * pTab = NULL;
4672 	fp_TableContainer * pBroke = NULL;
4673 	fp_CellContainer * pCell = NULL;
4674 	if(!isThisBroken())
4675 	{
4676 		pTab = this;
4677 	}
4678 	else
4679 	{
4680 		pBroke = this;
4681 		pTab = getMasterTable();
4682 	}
4683 	UT_return_val_if_fail(pTab,NULL);
4684 	if(pTab->countCons() == 0)
4685 	{
4686 		return NULL;
4687 	}
4688 	pCell = static_cast<fp_CellContainer *>(pTab->getNthCon(pTab->countCons()-1));
4689 	if(!pBroke)
4690 	{
4691 		while(pCell)
4692 		{
4693 			if(pCell->countCons() > 0)
4694 			{
4695 				fp_Container * pLast = static_cast<fp_Container *>(pCell->getNthCon(pCell->countCons()-1));
4696 				while(pLast && pCell->getColumn(pLast) != static_cast<fp_VerticalContainer *>(pCol))
4697 				{
4698 					pLast = static_cast<fp_Container *>(pLast->getPrev());
4699 				}
4700 				if(!pLast)
4701 					return NULL;
4702 				if(pLast->getContainerType() == FP_CONTAINER_LINE)
4703 				{
4704 					return static_cast<fp_Line *>(pLast);
4705 				}
4706 				if(pLast->getContainerType() == FP_CONTAINER_TABLE)
4707 				{
4708 					return static_cast<fp_TableContainer *>(pLast)->getLastLineInColumn(pCol);
4709 				}
4710 				UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
4711 				return NULL;
4712 			}
4713 			pCell = static_cast<fp_CellContainer *>(pCell->getPrev());
4714 		}
4715 		return NULL;
4716 	}
4717 	while(pCell)
4718 	{
4719 		if(pCell->doesOverlapBrokenTable(pBroke) && (pCell->countCons() > 0))
4720 		{
4721 			fp_Container * pLast = static_cast<fp_Container *>(pCell->getNthCon(pCell->countCons()-1));
4722 			while(pLast && pCell->getColumn(pLast) != static_cast<fp_VerticalContainer *>(pCol))
4723 			{
4724 				pLast =  static_cast<fp_Container *>(pLast->getNext());
4725 			}
4726 			if(pLast)
4727 			{
4728 				if(pLast->getContainerType() == FP_CONTAINER_LINE)
4729 				{
4730 					return static_cast<fp_Line *>(pLast);
4731 				}
4732 				if(pLast->getContainerType() == FP_CONTAINER_TABLE)
4733 				{
4734 					return static_cast<fp_TableContainer *>(pLast)->getLastLineInColumn(pCol);
4735 				}
4736 				UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
4737 				return NULL;
4738 			}
4739 		}
4740 		pCell =  static_cast<fp_CellContainer *>(pCell->getPrev());
4741 	}
4742 	return NULL;
4743 }
4744 
4745 
getPage(void)4746 fp_Page * fp_TableContainer::getPage(void)
4747 {
4748 	if(getContainer() && getContainer()->getContainerType() == FP_CONTAINER_CELL)
4749 	{
4750 		if(!isThisBroken())
4751 		{
4752 			return fp_Container::getPage();
4753 		}
4754 		fp_Column * pCol = getBrokenColumn();
4755 		if(pCol)
4756 		{
4757 			fp_Page * pPage = pCol->getPage();
4758 			return pPage;
4759 		}
4760 		if(getMasterTable() && getMasterTable()->getFirstBrokenTable() == this)
4761 		{
4762 			return fp_Container::getPage();
4763 		}
4764 		//
4765 		// OK all the easy cases dealt with.Now we have to find the page
4766 		// associated with this broken table.
4767 		//
4768 		fp_CellContainer * pCell = static_cast<fp_CellContainer *>(getContainer());
4769 		return pCell->getColumn(this)->getPage();
4770 	}
4771 	return fp_Container::getPage();
4772 }
4773 
getNextContainerInSection() const4774 fp_Container * fp_TableContainer::getNextContainerInSection() const
4775 {
4776 	if(getNext())
4777 	{
4778 		return static_cast<fp_Container *>(getNext());
4779 	}
4780 	fl_ContainerLayout * pCL = static_cast<fl_ContainerLayout *>(getSectionLayout());
4781 	fl_ContainerLayout * pNext = pCL->getNext();
4782 	while(pNext && ((pNext->getContainerType() == FL_CONTAINER_ENDNOTE) ||
4783 		  (pNext->getContainerType() == FL_CONTAINER_FRAME) ||
4784 		  (pNext->isHidden() == FP_HIDDEN_FOLDED)))
4785 	{
4786 		pNext = pNext->getNext();
4787 	}
4788 	if(pNext)
4789 	{
4790 		return pNext->getFirstContainer();
4791 	}
4792 	return NULL;
4793 }
4794 
4795 
getPrevContainerInSection() const4796 fp_Container * fp_TableContainer::getPrevContainerInSection() const
4797 {
4798 	if(getPrev())
4799 	{
4800 		return static_cast<fp_Container *>(getPrev());
4801 	}
4802 
4803 	fl_ContainerLayout * pCL = static_cast<fl_ContainerLayout *>(getSectionLayout());
4804 	fl_ContainerLayout * pPrev = pCL->getPrev();
4805 	while(pPrev && ((pPrev->getContainerType() == FL_CONTAINER_ENDNOTE) ||
4806 		  (pPrev->getContainerType() == FL_CONTAINER_FRAME) ||
4807 		  (pPrev->isHidden() == FP_HIDDEN_FOLDED)))
4808 	{
4809 		pPrev = pPrev->getPrev();
4810 	}
4811 	if(pPrev)
4812 	{
4813 		fp_Container * pPrevCon = static_cast<fp_Container *>(pPrev->getLastContainer());
4814 //
4815 // Have to handle broken tables in the previous layout..
4816 //
4817 		if(pPrevCon->getContainerType() == FP_CONTAINER_TABLE)
4818 		{
4819 			fp_TableContainer * pTab = static_cast<fp_TableContainer *>(pPrevCon);
4820 			fp_TableContainer * pLLast = pTab;
4821 			fp_TableContainer * pNext = static_cast<fp_TableContainer *>(pTab->getNext());
4822 			while(pNext)
4823 			{
4824 				pLLast = pNext;
4825 				pNext = static_cast<fp_TableContainer *>(pNext->getNext());
4826 			}
4827 			pPrevCon = static_cast<fp_Container *>(pLLast);
4828 		}
4829 		return pPrevCon;
4830 	}
4831 	return NULL;
4832 }
4833 
4834 
tableAttach(fp_CellContainer * child)4835 void fp_TableContainer::tableAttach (fp_CellContainer *child)
4836 {
4837 	UT_sint32 count = countCons();
4838 	if(count > 0)
4839 	{
4840 		fp_Container * pLast = static_cast<fp_Container *>(getNthCon(count - 1));
4841 		pLast->setNext(child);
4842 		child->setPrev(pLast);
4843 	}
4844 
4845 	fl_TableLayout * pTL = static_cast<fl_TableLayout *>(getSectionLayout());
4846 	if (!pTL->isInitialLayoutCompleted())
4847 	{
4848 		m_iCols = UT_MAX(m_iCols, child->getRightAttach());
4849 		m_iRows = UT_MAX(m_iRows, child->getBottomAttach());
4850 	}
4851 	else
4852 	{
4853 		if (child->getRightAttach() >= m_iCols)
4854 		{
4855 			resize (m_iRows, child->getRightAttach());
4856 		}
4857 
4858 		if (child->getBottomAttach() >=  m_iRows)
4859 		{
4860 			resize (child->getBottomAttach(), m_iCols);
4861 		}
4862 	}
4863 	xxx_UT_DEBUGMSG(("tableAttach: Attaching cell %x to table \n",child));
4864 	addContainer(child);
4865 	child->setContainer(static_cast<fp_Container *>(this));
4866 	queueResize();
4867 }
4868 
setContainer(fp_Container * pContainer)4869 void fp_TableContainer::setContainer(fp_Container * pContainer)
4870 {
4871 	if(isThisBroken())
4872 	{
4873 		fp_Container::setContainer(pContainer);
4874 		return;
4875 	}
4876 	if (pContainer == getContainer())
4877 	{
4878 		return;
4879 	}
4880 
4881 	if (getContainer() && (pContainer != NULL))
4882 	{
4883 		clearScreen();
4884 	}
4885 	fp_Container::setContainer(pContainer);
4886 	fp_TableContainer * pBroke = getFirstBrokenTable();
4887 	if(pBroke)
4888 	{
4889 		pBroke->setContainer(pContainer);
4890 	}
4891 	if(pContainer == NULL)
4892 	{
4893 		xxx_UT_DEBUGMSG(("Set master table %x container to NULL \n",this));
4894 		return;
4895 	}
4896 	setWidth(pContainer->getWidth());
4897 }
4898 
4899 
setRowSpacing(UT_sint32 row,UT_sint32 spacing)4900 void fp_TableContainer::setRowSpacing (UT_sint32 row, UT_sint32  spacing)
4901 {
4902   if (getNthRow(row)->spacing != spacing)
4903   {
4904       getNthRow(row)->spacing = spacing;
4905 	  queueResize();
4906   }
4907 }
4908 
setColSpacing(UT_sint32 column,UT_sint32 spacing)4909 void fp_TableContainer::setColSpacing(UT_sint32 column,UT_sint32 spacing)
4910 {
4911   if (getNthCol(column)->spacing != spacing)
4912   {
4913       getNthCol(column)->spacing = spacing;
4914 	  queueResize();
4915   }
4916 }
4917 
setRowSpacings(UT_sint32 spacing)4918 void fp_TableContainer::setRowSpacings ( UT_sint32 spacing)
4919 {
4920     UT_sint32 row;
4921 	m_iRowSpacing = spacing;
4922 	for (row = 0; row < getNumRows(); row++)
4923 	{
4924 		getNthRow(row)->spacing = spacing;
4925 	}
4926 	queueResize();
4927 }
4928 
setColSpacings(UT_sint32 spacing)4929 void fp_TableContainer::setColSpacings (UT_sint32  spacing)
4930 {
4931   UT_sint32 col;
4932   m_iColSpacing = spacing;
4933   for (col = 0; col < m_iCols; col++)
4934   {
4935 	  getNthCol(col)->spacing = spacing;
4936   }
4937   queueResize();
4938 }
4939 
setHomogeneous(bool bIsHomogeneous)4940 void fp_TableContainer::setHomogeneous (bool bIsHomogeneous)
4941 {
4942   if (bIsHomogeneous != m_bIsHomogeneous)
4943   {
4944       m_bIsHomogeneous = bIsHomogeneous;
4945 	  queueResize();
4946   }
4947 }
4948 
setBorderWidth(UT_sint32 iBorder)4949 void fp_TableContainer::setBorderWidth(UT_sint32 iBorder)
4950 {
4951 	if(iBorder == m_iBorderWidth)
4952 	{
4953 		return;
4954 	}
4955 	m_iBorderWidth = iBorder;
4956 	queueResize();
4957 }
4958 
queueResize(void)4959 void fp_TableContainer::queueResize(void)
4960 {
4961 	static_cast<fl_TableLayout *>(getSectionLayout())->setDirty();
4962 	if(getContainer() && getContainer()->getContainerType() == FP_CONTAINER_CELL)
4963 	{
4964 		fp_TableContainer * pTab = static_cast<fp_TableContainer *>(getContainer()->getContainer());
4965 		if(pTab && pTab->getContainerType() == FP_CONTAINER_TABLE)
4966 		{
4967 			pTab->queueResize();
4968 		}
4969 	}
4970 }
4971 
4972 
layout(void)4973 void fp_TableContainer::layout(void)
4974 {
4975 	if(isThisBroken())
4976 	{
4977 		UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
4978 		return;
4979 	}
4980 	xxx_UT_DEBUGMSG(("Doing Table layout %x \n",this));
4981 
4982 #if BENCHLAYOUT
4983 	printf("Doing Table layout \n");
4984 	timespec t1;
4985 	clock_gettime(CLOCK_REALTIME, &t1);
4986 #endif
4987 
4988 	fl_TableLayout * pTL = static_cast<fl_TableLayout *>(getSectionLayout());
4989 	if (!pTL->isInitialLayoutCompleted())
4990 	{
4991 		resize(m_iRows,m_iCols);
4992 	}
4993 	static fp_Requisition requisition;
4994 	static fp_Allocation alloc;
4995 	sizeRequest(&requisition);
4996 	setX(m_iBorderWidth);
4997 	alloc.x = getX();
4998 	alloc.y = getY();
4999 	alloc.width = getWidth();
5000 	alloc.height = requisition.height;
5001 	sizeAllocate(&alloc);
5002 	setToAllocation();
5003 #if BENCHLAYOUT
5004 	timespec t2;
5005 	clock_gettime(CLOCK_REALTIME, &t2);
5006 	double millidiff = (t2.tv_sec-t1.tv_sec)*1e3 + (t2.tv_nsec-t1.tv_nsec)/1e6;
5007 	printf("Layout TIME: %lf milliseconds\n", millidiff);
5008 #endif
5009 }
5010 
setToAllocation(void)5011 void fp_TableContainer::setToAllocation(void)
5012 {
5013 	setWidth(m_MyAllocation.width);
5014 	if(fp_VerticalContainer::getHeight() != m_MyAllocation.height)
5015 	{
5016 		//
5017 		// clear and delete broken tables before their height changes.
5018 		// Doing this clear at this point makes a table flicker when changing
5019 		// height but it does remove the last the pixel dirt with tables.
5020 		//
5021 		deleteBrokenTables(true,true);
5022 	}
5023 	setHeight(getTotalTableHeight());
5024 	setMaxHeight(getTotalTableHeight());
5025 	xxx_UT_DEBUGMSG(("SEVIOR: Height is set to %d \n",m_MyAllocation.height));
5026 
5027 	fp_CellContainer * pCon = static_cast<fp_CellContainer *>(getNthCon(0));
5028 	while(pCon)
5029 	{
5030 		pCon->setToAllocation();
5031 		pCon = static_cast<fp_CellContainer *>(pCon->getNext());
5032 	}
5033 	pCon = static_cast<fp_CellContainer *>(getNthCon(0));
5034 	while(pCon)
5035 	{
5036 		pCon->setLineMarkers();
5037 		pCon->doVertAlign();
5038 		pCon = static_cast<fp_CellContainer *>(pCon->getNext());
5039 	}
5040 	setYBottom(getTotalTableHeight());
5041 }
5042 
_size_request_init(void)5043 void  fp_TableContainer::_size_request_init(void)
5044 {
5045   UT_sint32 row, col;
5046 
5047   for (row = 0; row < m_iRows; row++)
5048   {
5049 	  getNthRow(row)->requisition = 0;
5050   }
5051   m_iCols =  m_vecColumns.getItemCount();
5052   for (col = 0; col < m_iCols; col++)
5053   {
5054 	  getNthCol(col)->requisition = 0;
5055   }
5056 
5057   fp_CellContainer * pCell = static_cast<fp_CellContainer *>(getNthCon(0));
5058   while (pCell)
5059   {
5060 	  UT_ASSERT(pCell->getContainerType() == FP_CONTAINER_CELL);
5061 	  pCell->sizeRequest(NULL);
5062 	  pCell = static_cast<fp_CellContainer *>(pCell->getNext());
5063   }
5064 }
5065 
_drawBoundaries(dg_DrawArgs * pDA)5066 void  fp_TableContainer::_drawBoundaries(dg_DrawArgs* pDA)
5067 {
5068 	UT_ASSERT(getPage());
5069 	if(getPage() == NULL)
5070 	{
5071 		return;
5072 	}
5073 	if(getPage()->getDocLayout()->getView() == NULL)
5074 	{
5075 		return;
5076 	}
5077 	UT_sint32 iWidth =0;
5078 	UT_sint32 iBorderWidth =0;
5079 	if(isThisBroken())
5080 	{
5081 		iWidth = getMasterTable()->getWidth();
5082 		iBorderWidth = getMasterTable()->m_iBorderWidth;
5083 	}
5084 	else
5085 	{
5086 		iWidth = getWidth();
5087 		iBorderWidth = m_iBorderWidth;
5088 	}
5089     if(getPage()->getDocLayout()->getView()->getShowPara() && getGraphics()->queryProperties(GR_Graphics::DGP_SCREEN)){
5090         UT_sint32 xoffBegin = pDA->xoff - 1;
5091         UT_sint32 yoffBegin = pDA->yoff - 1;
5092         UT_sint32 xoffEnd = pDA->xoff +  iWidth + 2 - static_cast<UT_sint32> (iBorderWidth * 2.0);
5093         UT_sint32 yoffEnd = pDA->yoff + getHeight() + 2;
5094 
5095 		UT_RGBColor clrShowPara(127,127,127);
5096 		getGraphics()->setColor(clrShowPara);
5097 		xxx_UT_DEBUGMSG(("SEVIOR: Table Top (getY()) = %d \n",getY()));
5098 		xxx_UT_DEBUGMSG(("SEVIOR: Table boundaries xleft %d xright %d ytop %d ybot %d \n",xoffBegin,xoffEnd,yoffBegin,yoffEnd));
5099 
5100 		GR_Painter painter (getGraphics());
5101 
5102         painter.drawLine(xoffBegin, yoffBegin, xoffEnd, yoffBegin);
5103         painter.drawLine(xoffBegin, yoffEnd, xoffEnd, yoffEnd);
5104         painter.drawLine(xoffBegin, yoffBegin, xoffBegin, yoffEnd);
5105         painter.drawLine(xoffEnd, yoffBegin, xoffEnd, yoffEnd);
5106     }
5107 
5108 }
5109 
5110 
_size_request_pass1(void)5111 void  fp_TableContainer::_size_request_pass1(void)
5112 {
5113   UT_sint32 width;
5114   UT_sint32 height;
5115 
5116   fp_CellContainer * child = static_cast<fp_CellContainer *>(getNthCon(0));
5117   while (child)
5118   {
5119 //
5120 // OK send down
5121 //
5122 	  fp_Requisition child_requisition;
5123 	  child->sizeRequest(&child_requisition);
5124 
5125 	  /* Child spans a single column.
5126 	   */
5127 	  if (child->getLeftAttach() == (child->getRightAttach() - 1))
5128 	  {
5129 	      width = child_requisition.width + child->getLeftPad() + child->getRightPad();
5130 	      getNthCol(child->getLeftAttach())->requisition = UT_MAX (getNthCol(child->getLeftAttach())->requisition, width);
5131 	  }
5132 
5133 	  /* Child spans a single row.
5134 	   */
5135 	  if (child->getTopAttach() == (child->getBottomAttach() - 1))
5136 	  {
5137 	      height = child_requisition.height + child->getTopPad() + child->getBotPad();
5138 	      getNthRow(child->getTopAttach())->requisition = UT_MAX (getNthRow(child->getTopAttach())->requisition, height);
5139 	  }
5140 	  child = static_cast<fp_CellContainer *>(child->getNext());
5141   }
5142 }
5143 
clearScreen(void)5144 void  fp_TableContainer::clearScreen(void)
5145 {
5146 	//
5147 	// If table is nested, do a clear screen on the topmost cell that
5148 	// contains it
5149 	// This should be fixed later.
5150 	if(getSectionLayout() && getSectionLayout()->getDocLayout())
5151 	{
5152 		if(getSectionLayout()->getDocLayout()->isLayoutDeleting())
5153 		{
5154 			return;
5155 		}
5156 	}
5157 	fp_Container *pUp = getContainer();
5158 	bool bIsNested = (pUp && (pUp->getContainerType() == FP_CONTAINER_CELL));
5159 	if(isThisBroken()  && !bIsNested)
5160 	{
5161 		return;
5162 	}
5163 	if(getPage() == NULL)
5164 	{
5165 		return;
5166 	}
5167 	if(getPage()->getDocLayout()->isLayoutFilling())
5168 	{
5169 		return;
5170 	}
5171 	UT_sint32 yoff,xoff;
5172 	getPage()->getScreenOffsets(static_cast<fp_Container *>(this),xoff,yoff);
5173 	if(yoff > getPage()->getHeight())
5174 	{
5175 		return;
5176 	}
5177 	xxx_UT_DEBUGMSG(("Doing clear screen on %x \n",this));
5178 	fp_CellContainer * pCell = static_cast<fp_CellContainer *>(getNthCon(0));
5179 	while(pCell)
5180 	{
5181 		//		if(pCell->containsNestedTables())
5182 		//	{
5183 		// 	pCell->clearScreen(true);
5184 		//  }
5185 		//  else
5186 		{
5187 			pCell->clearScreen();
5188 		}
5189 		pCell = static_cast<fp_CellContainer *>(pCell->getNext());
5190 	}
5191 	if(getSectionLayout())
5192 	{
5193 		getSectionLayout()->setNeedsRedraw();
5194 		getSectionLayout()->markAllRunsDirty();
5195 	}
5196 }
5197 
draw(dg_DrawArgs * pDA)5198 void fp_TableContainer::draw(dg_DrawArgs* pDA)
5199 {
5200 //
5201 // Don't draw if the table is still being constructed.
5202 //
5203 	xxx_UT_DEBUGMSG(("TablecONTAINER enter draw table yoff %ld \n",pDA->yoff));
5204 	if(getSectionLayout()->getDocument()->isDontImmediateLayout())
5205 	{
5206 		xxx_UT_DEBUGMSG(("TablecONTAINER leave draw dont immediately layout \n"));
5207 		return;
5208 	}
5209 	if(pDA->bDirtyRunsOnly)
5210 	{
5211 		if(getSectionLayout() && !getSectionLayout()->needsRedraw())
5212 		{
5213 			xxx_UT_DEBUGMSG(("TablecONTAINER leave draw section does not want redraw \n"));
5214 //			return;
5215 		}
5216 	}
5217 	if(isThisBroken())
5218 	{
5219 		_brokenDraw(pDA);
5220 		return;
5221 	}
5222 	else if(getFirstBrokenTable() != NULL)
5223 	{
5224 		getFirstBrokenTable()->draw( pDA);
5225 		return;
5226 	}
5227 	fp_Container * pCell = static_cast<fp_Container *>(getNthCon(0));
5228 	while(pCell)
5229 	{
5230 		xxx_UT_DEBUGMSG(("!!!!!!!!!!!!Draw unbroken table cell !!!!!!!!!!\n"));
5231 		pCell->draw(pDA);
5232 		pCell = static_cast<fp_Container *>(pCell->getNext());
5233 	}
5234     _drawBoundaries(pDA);
5235 
5236 }
5237 
getNumRows(void) const5238 UT_sint32 fp_TableContainer::getNumRows(void) const
5239 {
5240 	return m_vecRows.getItemCount();
5241 }
5242 
5243 
getNumCols(void) const5244 UT_sint32 fp_TableContainer::getNumCols(void) const
5245 {
5246 	return m_vecColumns.getItemCount();
5247 }
5248 
5249 /*!
5250  * Return the height of this Table taking into account the possibility
5251  * of it being broken.
5252  */
getHeight(void) const5253 UT_sint32 fp_TableContainer::getHeight(void) const
5254 {
5255 	UT_sint32 iFullHeight =  fp_VerticalContainer::getHeight();
5256 	if(!isThisBroken())
5257 	{
5258 //
5259 // If this is a master table but it contains broken tables, we actually
5260 // want the height of the first broken table. The Master table is the
5261 // one that actually has a relevant Y value in the vertical container.
5262 // All other Y offsets from the broken tables are calculated relative to
5263 // it.
5264 //
5265 		if(getFirstBrokenTable() != NULL)
5266 		{
5267 			return getFirstBrokenTable()->getHeight();
5268 		}
5269 		return iFullHeight;
5270 	}
5271 	UT_sint32 iMyHeight = getYBottom() - getYBreak();
5272 	return iMyHeight;
5273 }
5274 /*!
5275  * Return true if the table contains footnote references
5276  */
containsFootnoteReference(void)5277 bool fp_TableContainer::containsFootnoteReference(void)
5278 {
5279 	// First check if there are footnotes in the whole table
5280 	// This operation is quite fast
5281 	fl_TableLayout * pTL = static_cast<fl_TableLayout *>(getSectionLayout());
5282 	if (!pTL->containsFootnoteLayouts())
5283 	{
5284 		return false;
5285 	}
5286 
5287 	// Check if there are footnotes in the broken table
5288 	fp_CellContainer * pCell = getFirstBrokenCell(false);
5289 
5290 	bool bFound = false;
5291 	while(pCell && !bFound)
5292 	{
5293 		if (getYOfRow(pCell->getTopAttach()) >= getYBottom())
5294 		{
5295 			break;
5296 		}
5297 		if ((pCell->getY() < getYBottom()) && (pCell->getY() + pCell->getHeight() >= getYBreak()))
5298 		{
5299 			bFound = pCell->containsFootnoteReference(this);
5300 		}
5301 		pCell = static_cast<fp_CellContainer*>(pCell->getNext());
5302 	}
5303 	return bFound;
5304 }
5305 
5306 /*!
5307  * This method returns a vector of all the footnote object in the broken table
5308  */
getFootnoteContainers(UT_GenericVector<fp_FootnoteContainer * > * pVecFoots)5309 bool fp_TableContainer::getFootnoteContainers(UT_GenericVector<fp_FootnoteContainer*>* pVecFoots)
5310 {
5311 	fp_CellContainer * pCell = getFirstBrokenCell(false);
5312 	bool bFound = false;
5313 	while(pCell)
5314 	{
5315 		if (getYOfRow(pCell->getTopAttach()) >= getYBottom())
5316 		{
5317 			break;
5318 		}
5319 		if ((pCell->getY() < getYBottom()) && (pCell->getY() + pCell->getHeight() >= getYBreak()) &&
5320 			pCell->containsFootnoteReference(this))
5321 		{
5322 			bFound |= pCell->getFootnoteContainers(pVecFoots,this);
5323 		}
5324 		pCell = static_cast<fp_CellContainer *>(pCell->getNext());
5325 	}
5326 	return bFound;
5327 }
5328 
5329 
5330 /*!
5331  * Return true if the table contains annotation references
5332  */
containsAnnotations(void)5333 bool fp_TableContainer::containsAnnotations(void)
5334 {
5335 	// First check if there are annotations in the whole table
5336 	// This operation is quite fast
5337 	fl_TableLayout * pTL = static_cast<fl_TableLayout *>(getSectionLayout());
5338 	if (!pTL->containsAnnotationLayouts())
5339 	{
5340 		return false;
5341 	}
5342 
5343 	// Check if there are annotations in the broken table
5344 	fp_CellContainer * pCell = getFirstBrokenCell(false);
5345 
5346 	bool bFound = false;
5347 	while(pCell && !bFound)
5348 	{
5349 		if (getYOfRow(pCell->getTopAttach()) >= getYBottom())
5350 		{
5351 			break;
5352 		}
5353 		if ((pCell->getY() < getYBottom()) && (pCell->getY() + pCell->getHeight() >= getYBreak()))
5354 		{
5355 			bFound = pCell->containsAnnotations(this);
5356 		}
5357 		pCell = static_cast<fp_CellContainer*>(pCell->getNext());
5358 	}
5359 	return bFound;
5360 }
5361 
5362 /*!
5363  * This method returns a vector of all the annotation object in the broken table
5364  */
getAnnotationContainers(UT_GenericVector<fp_AnnotationContainer * > * pVecAnns)5365 bool fp_TableContainer::getAnnotationContainers(UT_GenericVector<fp_AnnotationContainer*>* pVecAnns)
5366 {
5367 	fp_CellContainer * pCell = getFirstBrokenCell(false);
5368 	bool bFound = false;
5369 	while(pCell)
5370 	{
5371 		if (getYOfRow(pCell->getTopAttach()) >= getYBottom())
5372 		{
5373 			break;
5374 		}
5375 		if ((pCell->getY() < getYBottom()) && (pCell->getY() + pCell->getHeight() >= getYBreak()) &&
5376 			pCell->containsAnnotations(this))
5377 		{
5378 			bFound |= pCell->getAnnotationContainers(pVecAnns,this);
5379 		}
5380 		pCell = static_cast<fp_CellContainer *>(pCell->getNext());
5381 	}
5382 	return bFound;
5383 }
5384 
5385 
5386 /*!
5387  * Return true if the supplied Cell and its container are within this
5388  * broken container.
5389  */
isInBrokenTable(const fp_CellContainer * pCell,fp_Container * pCon) const5390 bool fp_TableContainer::isInBrokenTable(const fp_CellContainer * pCell, fp_Container * pCon) const
5391 {
5392 	xxx_UT_DEBUGMSG(("isInBrokenTable %p pcell %p container %p\n",this,pCell,pCon));
5393 	UT_sint32 iTop = pCell->getY() + pCon->getY();
5394 
5395 	if ((iTop >= getYBreak() - 1) && (iTop < getYBottom()))
5396 	{
5397 		return true;
5398 	}
5399 
5400 	return false;
5401 }
5402 
5403 
5404 /*!
5405  * Draw that segment of the table that fits within the Y offsets of this
5406  * Broken table.
5407  */
_brokenDraw(dg_DrawArgs * pDA)5408 void fp_TableContainer::_brokenDraw(dg_DrawArgs* pDA)
5409 {
5410 	xxx_UT_DEBUGMSG(("Drawing %d table in broken chain yoff %ld \n",getBrokenDraw(),pDA->yoff));
5411 	xxx_UT_DEBUGMSG(("SEVIOR: _brokenDraw table %p getYBreak %d getYBottom %d \n",this, getYBreak(),getYBottom()));
5412 	UT_sint32 iCountCells = 0;
5413 	const UT_Rect * pClipRect = pDA->pG->getClipRect();
5414 
5415 	fp_CellContainer * pCell = getFirstBrokenCell(false);
5416 
5417 	xxx_UT_DEBUGMSG(("Drawing cells for table %p starting at cell %p \n",this,pCell));
5418 	while(pCell)
5419 	{
5420 		dg_DrawArgs da = *pDA;
5421 		da.yoff = da.yoff - getYBreak();
5422 
5423 		if(getYOfRow(pCell->getTopAttach()) > getYBottom())
5424 		{
5425 			break;
5426 		}
5427 		else if (getYOfRow(pCell->getBottomAttach()) > getYBreak())
5428 		{
5429 			if(!pClipRect || (pCell->doesIntersectClip(this,pClipRect)))
5430 			{
5431 				pCell->drawBroken(&da, this);
5432 				iCountCells++;
5433 			}
5434 			if(!m_pFirstBrokenCell)
5435 			{
5436 				m_pFirstBrokenCell = pCell;
5437 			}
5438 		}
5439 
5440 		pCell = static_cast<fp_CellContainer *>(pCell->getNext());
5441 	}
5442 
5443 	xxx_UT_DEBUGMSG(("_brokenDraw: Draw %d cells and check %d cells for table %p\n",iCountCells,this));
5444     _drawBrokenBoundaries(pDA);
5445 	fl_TableLayout * pTL = static_cast<fl_TableLayout *>(getSectionLayout());
5446 	pTL->clearNeedsRedraw();
5447 }
5448 
5449 
_drawBrokenBoundaries(dg_DrawArgs * pDA)5450 void fp_TableContainer::_drawBrokenBoundaries(dg_DrawArgs* pDA)
5451 {
5452 
5453 	UT_ASSERT(getPage());
5454 	if(!pDA->pG->queryProperties(GR_Graphics::DGP_SCREEN))
5455 	{
5456 		return;
5457 	}
5458 	if(!getPage() || (getPage()->getDocLayout()->getView() == NULL))
5459 	{
5460 		return;
5461 	}
5462 
5463     if(getPage()->getDocLayout()->getView()->getShowPara() && getGraphics()->queryProperties(GR_Graphics::DGP_SCREEN)){
5464         UT_sint32 xoffBegin = pDA->xoff + getX();
5465         UT_sint32 yoffBegin = pDA->yoff;
5466         UT_sint32 xoffEnd = pDA->xoff + getX() + getWidth() - getGraphics()->tlu(1);
5467         UT_sint32 yoffEnd = pDA->yoff + getHeight() - getGraphics()->tlu(1);
5468 
5469 		UT_RGBColor clrShowPara(127,127,127);
5470 		getGraphics()->setColor(clrShowPara);
5471 		xxx_UT_DEBUGMSG(("SEVIOR: Table Top (getY()) = %d \n",getY()));
5472 		xxx_UT_DEBUGMSG(("SEVIOR: Table boundaries xleft %d xright %d ytop %d ybot %d \n",xoffBegin,xoffEnd,yoffBegin,yoffEnd));
5473 
5474 		GR_Painter painter (getGraphics());
5475 
5476         painter.drawLine(xoffBegin, yoffBegin, xoffEnd, yoffBegin);
5477         painter.drawLine(xoffBegin, yoffEnd, xoffEnd, yoffEnd);
5478         painter.drawLine(xoffBegin, yoffBegin, xoffBegin, yoffEnd);
5479         painter.drawLine(xoffEnd, yoffBegin, xoffEnd, yoffEnd);
5480     }
5481 
5482 }
5483 
_size_request_pass2(void)5484 void  fp_TableContainer::_size_request_pass2(void)
5485 {
5486   UT_sint32 max_width;
5487    UT_sint32 col;
5488 
5489   if (m_bIsHomogeneous)
5490   {
5491       max_width = 0;
5492       m_iCols = m_vecColumns.getItemCount();
5493       for (col = 0; col < m_iCols; col++)
5494 	  {
5495 		  max_width = UT_MAX (max_width, getNthCol(col)->requisition);
5496 	  }
5497       for (col = 0; col < m_iCols; col++)
5498 	  {
5499 		  getNthCol(col)->requisition = max_width;
5500 	  }
5501 //
5502 // Don't want homogeneous in height
5503 //
5504 #if 0
5505       UT_sint32 max_height = 0;
5506 	  UT_sint32 row = 0;
5507 	  for (row = 0; row < m_iRows; row++)
5508 	  {
5509 		  max_height = UT_MAX (max_height, getNthRow(row)->requisition);
5510       }
5511       for (row = 0; row < m_iRows; row++)
5512 	  {
5513 		  getNthRow(row)->requisition = max_height;
5514 	  }
5515 #endif
5516   }
5517 }
5518 
_size_request_pass3(void)5519 void  fp_TableContainer::_size_request_pass3(void)
5520 {
5521   fp_CellContainer  *child;
5522   UT_sint32 width, height;
5523   UT_sint32 row, col;
5524   UT_sint32 extra;
5525 
5526   child = static_cast<fp_CellContainer *>(getNthCon(0));
5527   while (child)
5528   {
5529 	  /* Child spans multiple columns.
5530 	   */
5531 	  if (child->getLeftAttach() != (child->getRightAttach() - 1))
5532 	  {
5533 	      fp_Requisition child_requisition;
5534 
5535 	      child->sizeRequest(&child_requisition);
5536 
5537 	      /* Check and see if there is already enough space
5538 	       *  for the child.
5539 	       */
5540 	      width = 0;
5541 	      for (col = child->getLeftAttach(); col < child->getRightAttach(); col++)
5542 		  {
5543 			  width += getNthCol(col)->requisition;
5544 			  if ((col + 1) < child->getRightAttach())
5545 			  {
5546 				  width += getNthCol(col)->spacing;
5547 			  }
5548 		  }
5549 
5550 	      /* If we need to request more space for this child to fill
5551 	       *  its requisition, then divide up the needed space evenly
5552 	       *  amongst the columns it spans.
5553 	       */
5554 	      if (width < child_requisition.width + child->getLeftPad() + child->getRightPad())
5555 		  {
5556 			  width = child_requisition.width + child->getLeftPad() + child->getRightPad();
5557 
5558 			  for (col = child->getLeftAttach(); col < child->getRightAttach(); col++)
5559 			  {
5560 				  extra = width / (child->getRightAttach() - col);
5561 				  getNthCol(col)->requisition += extra;
5562 				  width -= extra;
5563 			  }
5564 		  }
5565 	  }
5566 
5567 	  /* Child spans multiple rows.
5568 	   */
5569 	  if (child->getTopAttach() != (child->getBottomAttach() - 1))
5570 	  {
5571 	      fp_Requisition child_requisition;
5572 
5573 	      child->sizeRequest(&child_requisition);
5574 
5575 	      /* Check and see if there is already enough space
5576 	       *  for the child.
5577 	       */
5578 	      height = 0;
5579 	      for (row = child->getTopAttach(); row < child->getBottomAttach(); row++)
5580 		  {
5581 			  height += getNthRow(row)->requisition;
5582 			  if ((row + 1) < child->getBottomAttach())
5583 				  height +=  getNthRow(row)->spacing;
5584 		  }
5585 
5586 	      /* If we need to request more space for this child to fill
5587 	       *  its requisition, then divide up the needed space evenly
5588 	       *  amongst the columns it spans.
5589 	       */
5590 	      if (height < child_requisition.height + child->getTopPad() + child->getBotPad())
5591 		  {
5592 			  height = child_requisition.height + child->getTopPad() + child->getBotPad() - height;
5593 
5594 			  for (row = child->getTopAttach(); row < child->getBottomAttach(); row++)
5595 			  {
5596 				  extra = height / (child->getBottomAttach() - row);
5597 				  getNthRow(row)->requisition += extra;
5598 				  height -= extra;
5599 			  }
5600 		  }
5601 	  }
5602 	  child = static_cast<fp_CellContainer *>(child->getNext());
5603     }
5604 }
5605 
_size_allocate_init(void)5606 void  fp_TableContainer::_size_allocate_init(void)
5607 {
5608   fp_CellContainer * child;
5609   UT_sint32 row, col;
5610   UT_sint32 has_expand;
5611   UT_sint32 has_shrink;
5612 
5613   /* Initialize the rows and cols.
5614    *  By default, rows and cols do not expand and do shrink.
5615    *  Those values are modified by the children that occupy
5616    *  the rows and cols.
5617    */
5618   m_iCols = m_vecColumns.getItemCount();
5619   for (col = 0; col < m_iCols; col++)
5620   {
5621 	  fp_TableRowColumn *pCol= getNthCol(col);
5622 
5623       pCol->allocation = pCol->requisition;
5624       pCol->need_expand = false;
5625       pCol->need_shrink = true;
5626       pCol->expand = false;
5627       pCol->shrink = true;
5628       pCol->empty = true;
5629   }
5630   for (row = 0; row < m_iRows; row++)
5631   {
5632 	  fp_TableRowColumn * pRow = getNthRow(row);
5633       pRow->allocation = pRow->requisition;
5634       pRow->need_expand = false;
5635       pRow->need_shrink = true;
5636       pRow->expand = false;
5637       pRow->shrink = true;
5638       pRow->empty = true;
5639   }
5640 
5641   /* Loop over all the children and adjust the row and col values
5642    *  based on whether the children want to be allowed to expand
5643    *  or shrink. This loop handles children that occupy a single
5644    *  row or column.
5645    */
5646   child = static_cast<fp_CellContainer *>(getNthCon(0));
5647   while (child)
5648   {
5649 	  if (child->getLeftAttach() == (child->getRightAttach() - 1))
5650 	  {
5651 		  if (child->getXexpand())
5652 		  {
5653 			  getNthCol(child->getLeftAttach())->expand = true;
5654 		  }
5655 		  if (!child->getXshrink())
5656 		  {
5657 			  getNthCol(child->getLeftAttach())->shrink = false;
5658 		  }
5659 		  getNthCol(child->getLeftAttach())->empty = false;
5660 	  }
5661 
5662 	  if (child->getTopAttach() == (child->getBottomAttach() - 1))
5663 	  {
5664 		  if (child->getYshrink())
5665 		  {
5666 			  getNthRow(child->getTopAttach())->expand = true;
5667 		  }
5668 		  if (!child->getYshrink())
5669 		  {
5670 			  getNthRow(child->getTopAttach())->shrink = false;
5671 		  }
5672 		  getNthRow(child->getTopAttach())->empty = false;
5673 	  }
5674 	  child = static_cast<fp_CellContainer *>(child->getNext());
5675   }
5676 
5677   /* Loop over all the children again and this time handle children
5678    *  which span multiple rows or columns.
5679    */
5680   child = static_cast<fp_CellContainer *>(getNthCon(0));
5681   while (child)
5682   {
5683 	  if (child->getLeftAttach() != (child->getRightAttach() - 1))
5684 	  {
5685 		  for (col = child->getLeftAttach(); col < child->getRightAttach(); col++)
5686 		  {
5687 			  getNthCol(col)->empty = false;
5688 		  }
5689 		  if (child->getXexpand())
5690 		  {
5691 			  has_expand = false;
5692 			  for (col = child->getLeftAttach(); col < child->getRightAttach(); col++)
5693 			  {
5694 				  if (getNthCol(col)->expand)
5695 				  {
5696 					  has_expand = true;
5697 					  break;
5698 				  }
5699 			  }
5700 			  if (!has_expand)
5701 			  {
5702 				  for (col = child->getLeftAttach(); col < child->getRightAttach(); col++)
5703 				  {
5704 					  getNthCol(col)->need_expand = true;
5705 				  }
5706 			  }
5707 		  }
5708 
5709 		  if (!child->getXshrink())
5710 		  {
5711 			  has_shrink = true;
5712 			  for (col = child->getLeftAttach(); col < child->getRightAttach(); col++)
5713 			  {
5714 				  if (!getNthCol(col)->shrink)
5715 				  {
5716 					  has_shrink = false;
5717 					  break;
5718 				  }
5719 			  }
5720 			  if (has_shrink)
5721 			  {
5722 				  for (col = child->getLeftAttach(); col < child->getRightAttach(); col++)
5723 				  {
5724 						  getNthCol(col)->need_shrink = false;
5725 				  }
5726 			  }
5727 		  }
5728 
5729 		  if (child->getTopAttach() != (child->getBottomAttach() - 1))
5730 		  {
5731 			  for (row = child->getTopAttach(); row < child->getBottomAttach(); row++)
5732 			  {
5733 				  getNthRow(row)->empty = false;
5734 			  }
5735 			  if (child->getYexpand())
5736 			  {
5737 				  has_expand = false;
5738 				  for (row = child->getTopAttach(); row < child->getBottomAttach(); row++)
5739 				  {
5740 					  if (getNthRow(row)->expand)
5741 					  {
5742 						  has_expand = true;
5743 						  break;
5744 					  }
5745 				  }
5746 				  if (!has_expand)
5747 				  {
5748 					  for (row = child->getTopAttach(); row < child->getBottomAttach(); row++)
5749 						{
5750 							getNthRow(row)->need_expand = true;
5751 						}
5752 				  }
5753 			  }
5754 
5755 			  if (!child->getYshrink())
5756 			  {
5757 				  has_shrink = true;
5758 				  for (row = child->getTopAttach(); row < child->getBottomAttach(); row++)
5759 				  {
5760 					  if (!getNthRow(row)->shrink)
5761 					  {
5762 						  has_shrink = false;
5763 						  break;
5764 					  }
5765 				  }
5766 				  if (has_shrink)
5767 				  {
5768 					  for (row = child->getTopAttach(); row < child->getBottomAttach(); row++)
5769 					  {
5770 						  getNthRow(row)->need_shrink = false;
5771 					  }
5772 				  }
5773 			  }
5774 		  }
5775 	  }
5776 	  child = static_cast<fp_CellContainer *>(child->getNext());
5777   }
5778 
5779   /* Loop over the columns and set the expand and shrink values
5780    *  if the column can be expanded or shrunk.
5781    */
5782 
5783   m_iCols = m_vecColumns.getItemCount();
5784   for (col = 0; col < m_iCols; col++)
5785   {
5786 	  fp_TableRowColumn *pCol= getNthCol(col);
5787 
5788       if (pCol->empty)
5789 	  {
5790 		  pCol->expand = false;
5791 		  pCol->shrink = false;
5792 	  }
5793       else
5794 	  {
5795 		  if (pCol->need_expand)
5796 		  {
5797 			  pCol->expand = true;
5798 		  }
5799 		  if (!pCol->need_shrink)
5800 		  {
5801 			  pCol->shrink = false;
5802 		  }
5803 	  }
5804   }
5805 
5806   /* Loop over the rows and set the expand and shrink values
5807    *  if the row can be expanded or shrunk.
5808    */
5809   for (row = 0; row < m_iRows; row++)
5810   {
5811 	  fp_TableRowColumn * pRow = getNthRow(row);
5812       if (pRow->empty)
5813 	  {
5814 		  pRow->expand = false;
5815 		  pRow->shrink = false;
5816 	  }
5817       else
5818 	  {
5819 		  if (pRow->need_expand)
5820 		  {
5821 			  pRow->expand = true;
5822 		  }
5823 		  if (!pRow->need_shrink)
5824 		  {
5825 			  pRow->shrink = false;
5826 		  }
5827 	  }
5828   }
5829 }
5830 
_size_allocate_pass1(void)5831 void  fp_TableContainer::_size_allocate_pass1(void)
5832 {
5833 
5834   UT_sint32 real_width;
5835   UT_sint32 real_height;
5836   UT_sint32 width, height;
5837   UT_sint32 row, col;
5838   UT_sint32 nexpand;
5839   UT_sint32 nshrink;
5840   UT_sint32 extra;
5841 
5842   /* If we were allocated more space than we requested
5843    *  then we have to expand any expandable rows and columns
5844    *  to fill in the extra space.
5845    */
5846 
5847   real_width = m_MyAllocation.width - m_iBorderWidth * 2;
5848   double dHeight = static_cast<double>(m_MyAllocation.height);
5849   double dBorder = static_cast<double>(m_iBorderWidth);
5850   real_height = static_cast<UT_sint32> (dHeight - dBorder * 2.0);
5851   // real_height =  m_MyAllocation.height;
5852 
5853   if (m_bIsHomogeneous)
5854   {
5855       nexpand = 0;
5856 	  m_iCols = m_vecColumns.getItemCount();
5857       for (col = 0; col < m_iCols; col++)
5858 	  {
5859 		  if (getNthCol(col)->expand)
5860 		  {
5861 			  nexpand += 1;
5862 			  break;
5863 		  }
5864 	  }
5865 
5866       if (nexpand > 0)
5867 	  {
5868 		  width = real_width;
5869 
5870 		  for (col = 0; col + 1 < m_iCols; col++)
5871 		  {
5872 			  width -= getNthCol(col)->spacing;
5873 		  }
5874 
5875 		  for (col = 0; col < m_iCols; col++)
5876 		  {
5877 			  extra = width / (m_iCols - col);
5878 			  getNthCol(col)->allocation = UT_MAX (1, extra);
5879 			  width -= extra;
5880 		  }
5881 	  }
5882   }
5883   else
5884   {
5885       width = 0;
5886       nexpand = 0;
5887       nshrink = 0;
5888 
5889 	  m_iCols = m_vecColumns.getItemCount();
5890       for (col = 0; col < m_iCols; col++)
5891 	  {
5892 		  width += getNthCol(col)->requisition;
5893 		  if (getNthCol(col)->expand)
5894 		  {
5895 			  nexpand += 1;
5896 		  }
5897 		  if (getNthCol(col)->shrink)
5898 		  {
5899 			  nshrink += 1;
5900 		  }
5901 	  }
5902       for (col = 0; col + 1 < m_iCols; col++)
5903 	  {
5904 		  width += getNthCol(col)->spacing;
5905       }
5906       /* Check to see if we were allocated more width than we requested.
5907        */
5908       if ((width < real_width) && (nexpand >= 1))
5909 	  {
5910 		  width = real_width - width;
5911 
5912 		  for (col = 0; col < m_iCols; col++)
5913 		  {
5914 			  if (getNthCol(col)->expand)
5915 			  {
5916 				  extra = width / nexpand;
5917 				  getNthCol(col)->allocation += extra;
5918 				  width -= extra;
5919 				  nexpand -= 1;
5920 			  }
5921 		  }
5922 	  }
5923 
5924       /* Check to see if we were allocated less width than we requested,
5925        * then shrink until we fit the size give.
5926        */
5927       if (width > real_width)
5928 	  {
5929 		  UT_sint32 total_nshrink = nshrink;
5930 
5931 		  extra = width - real_width;
5932 		  while (total_nshrink > 0 && extra > 0)
5933 		  {
5934 			  nshrink = total_nshrink;
5935 			  m_iCols = m_vecColumns.getItemCount();
5936 			  for (col = 0; col < m_iCols; col++)
5937 			  {
5938 				  fp_TableRowColumn *pCol= getNthCol(col);
5939 
5940 				  if (pCol->shrink)
5941 				  {
5942 					  UT_sint32 allocation = pCol->allocation;
5943 					  pCol->allocation = UT_MAX (1, static_cast<UT_sint32>(pCol->allocation) - extra / nshrink);
5944 					  extra -= allocation - pCol->allocation;
5945 					  nshrink -= 1;
5946 					  if (pCol->allocation < 2)
5947 					  {
5948 						  total_nshrink -= 1;
5949 						  pCol->shrink = false;
5950 					  }
5951 				  }
5952 			  }
5953 		  }
5954 	  }
5955   }
5956 
5957 //
5958 // Don't want homogenous in height
5959 //
5960   {
5961 	  height = 0;
5962 	  nexpand = 0;
5963 	  nshrink = 0;
5964 	  for (row = 0; row < m_iRows; row++)
5965 	  {
5966 
5967 
5968 		  height += getNthRow(row)->requisition;
5969 		  if (getNthRow(row)->expand)
5970 		  {
5971 			  nexpand += 1;
5972 		  }
5973 		  if (getNthRow(row)->shrink)
5974 		  {
5975 			  nshrink += 1;
5976 		  }
5977 	  }
5978 	  for (row = 0; row + 1 < m_iRows; row++)
5979 	  {
5980 		  height += getNthRow(row)->spacing;
5981 	  }
5982       /* Check to see if we were allocated more height than we requested.
5983        */
5984       if ((height < real_height) && (nexpand >= 1))
5985 	  {
5986 		  height = real_height - height;
5987 		  for (row = 0; row < m_iRows; row++)
5988 		  {
5989 			  if (getNthRow(row)->expand)
5990 			  {
5991 				  extra = height / nexpand;
5992 				  getNthRow(row)->allocation += extra;
5993 				  height -= extra;
5994 				  nexpand -= 1;
5995 			  }
5996 		  }
5997 	  }
5998 
5999       /* Check to see if we were allocated less height than we requested.
6000        * then shrink until we fit the size give.
6001        */
6002       if (height > real_height)
6003 	  {
6004 		  UT_sint32 total_nshrink = nshrink;
6005 		  extra = height - real_height;
6006 		  while (total_nshrink > 0 && extra > 0)
6007 		  {
6008 			  nshrink = total_nshrink;
6009 			  for (row = 0; row < m_iRows; row++)
6010 			  {
6011 				  fp_TableRowColumn * pRow = getNthRow(row);
6012 				  if (pRow->shrink)
6013 				  {
6014 					  UT_sint32 allocation = pRow->allocation;
6015 
6016 					  pRow->allocation = UT_MAX (1, static_cast<UT_sint32>(pRow->allocation) - extra / nshrink);
6017 					  extra -= allocation - pRow->allocation;
6018 					  nshrink -= 1;
6019 					  if (pRow->allocation < 2)
6020 					  {
6021 						  total_nshrink -= 1;
6022 						  pRow->shrink = false;
6023 					  }
6024 				  }
6025 			  }
6026 		  }
6027 	  }
6028   }
6029 }
6030 
_size_allocate_pass2(void)6031 void  fp_TableContainer::_size_allocate_pass2(void)
6032 {
6033 	fp_CellContainer  *child;
6034 	UT_sint32 max_width;
6035 	UT_sint32 max_height;
6036 	UT_sint32 x, y;
6037 	UT_sint32 row, col;
6038 	fp_Allocation allocation;
6039 	fl_TableLayout * pTL = static_cast<fl_TableLayout *>(getSectionLayout());
6040 	const UT_GenericVector<fl_ColProps*> * pVecColProps = pTL->getVecColProps();
6041 	if(pVecColProps->getItemCount() > 0)
6042 	{
6043 		for (col = 0; (col < pVecColProps->getItemCount()) && (col <getNumCols()); col++)
6044 		{
6045 			fl_ColProps * pColProp = pVecColProps->getNthItem(col);
6046 			getNthCol(col)->allocation = pColProp->m_iColWidth - getNthCol(col)->spacing;
6047 			if(col == (getNumCols() - 1) )
6048 			{
6049 				getNthCol(col)->allocation += 2 * getNthCol(col)->spacing;
6050 			}
6051 		}
6052 	}
6053 	m_MyAllocation.x = pTL->getLeftColPos() - m_iBorderWidth;
6054 
6055 	x = m_MyAllocation.x + m_iBorderWidth;
6056 	y = m_MyAllocation.y + m_iBorderWidth + pTL->getTopOffset();
6057 
6058 	for (col = 0; col < m_iCols; col++)
6059 	{
6060 		getNthCol(col)->position = x;
6061 		x += getNthCol(col)->allocation + getNthCol(col)->spacing;
6062 	}
6063 	UT_sint32 totalWidth = x;
6064 
6065 	for (row = 0; row < m_iRows; row++)
6066 	{
6067 		getNthRow(row)->position = y;
6068 		y += getNthRow(row)->allocation + getNthRow(row)->spacing;
6069 	}
6070 	UT_sint32 totalHeight = y;
6071 
6072 	UT_sint32 iBottom,iRight;
6073 	child = static_cast<fp_CellContainer *>(getNthCon(0));
6074 	while (child)
6075 	{
6076 		fp_Requisition child_requisition;
6077 		child->sizeRequest(&child_requisition);
6078 
6079 		x = getNthCol(child->getLeftAttach())->position;
6080 		iRight = child->getRightAttach();
6081 		max_width = ((iRight < m_iCols) ? getNthCol(iRight)->position : totalWidth) - (x + getNthCol(iRight - 1)->spacing);
6082 		y = getNthRow(child->getTopAttach())->position;
6083 		iBottom = child->getBottomAttach();
6084 		max_height = ((iBottom < m_iRows) ? getNthRow(iBottom)->position : totalHeight)- (x + getNthRow(iBottom - 1)->spacing);
6085 
6086 		if (child->getXfill())
6087 		{
6088 			allocation.width = UT_MAX (1, max_width - static_cast<UT_sint32>(child->getLeftPad()) - child->getRightPad());
6089 			allocation.x = x + (max_width - allocation.width) / 2;
6090 		}
6091 		else
6092 		{
6093 			allocation.width = child_requisition.width;
6094 			allocation.x = x + (max_width - allocation.width) / 2;
6095 		}
6096 		// fixme sevior look here!!!
6097 		if (child->getYfill())
6098 		{
6099 			allocation.height = UT_MAX (1, max_height - static_cast<UT_sint32>(child->getTopPad()) - child->getBotPad());
6100 			allocation.y = y;
6101 		}
6102 		else
6103 		{
6104 			allocation.height = child_requisition.height;
6105 			allocation.y = y;
6106 		}
6107 		xxx_UT_DEBUGMSG(("SEVIOR!!!!!!: max_height = %d width =%d \n",max_height,allocation.width));
6108 		child->sizeAllocate( &allocation);
6109 		child = static_cast<fp_CellContainer *>(child->getNext());
6110 	}
6111 }
6112 
getNthCol(UT_sint32 i) const6113 fp_TableRowColumn * fp_TableContainer::getNthCol(UT_sint32 i) const
6114 {
6115 	UT_ASSERT(i < m_vecColumns.getItemCount());
6116 	return m_vecColumns.getNthItem(i);
6117 }
6118 
getNthRow(UT_sint32 i) const6119 fp_TableRowColumn * fp_TableContainer::getNthRow(UT_sint32 i) const
6120 {
6121 	UT_ASSERT(i < m_vecRows.getItemCount());
6122 	return m_vecRows.getNthItem(i);
6123 }
6124 
6125 
sizeRequest(fp_Requisition * pRequisition)6126 void fp_TableContainer::sizeRequest(fp_Requisition * pRequisition)
6127 {
6128   UT_sint32 row, col;
6129 
6130   pRequisition->width = 0;
6131   pRequisition->height = 0;
6132   bool bDefinedColWidth = false;
6133   fl_TableLayout * pTL = static_cast<fl_TableLayout *>(getSectionLayout());
6134   const UT_GenericVector<fl_ColProps *> * pVecColProps = pTL->getVecColProps();
6135   if(pVecColProps->getItemCount() > 0)
6136   {
6137 	  bDefinedColWidth = true;
6138   }
6139   _size_request_init ();
6140   _size_request_pass1 ();
6141   _size_request_pass2 ();
6142   _size_request_pass3 ();
6143   _size_request_pass2 ();
6144 
6145   m_iCols = m_vecColumns.getItemCount();
6146   for (col = 0; col < m_iCols; col++)
6147   {
6148 	  if(bDefinedColWidth && (col < pVecColProps->getItemCount()) )
6149 	  {
6150 		  fl_ColProps * pColProp = pVecColProps->getNthItem(col);
6151 		  getNthCol(col)->requisition = pColProp->m_iColWidth;
6152 	  }
6153 	  pRequisition->width += getNthCol(col)->requisition;
6154   }
6155   for (col = 0; col + 1 < m_iCols; col++)
6156   {
6157 	  pRequisition->width += getNthCol(col)->spacing;
6158   }
6159 
6160   for (row = 0; row < m_iRows; row++)
6161   {
6162 	  fp_TableRowColumn * pRow = getNthRow(row);
6163 	  UT_sint32 iOldReq = pRow->requisition;
6164 	  UT_sint32 iNewReq = getRowHeight(row,iOldReq);
6165 	  if(iNewReq > iOldReq)
6166 	  {
6167 		  iNewReq -= pRow->spacing;
6168 	  }
6169 	  pRow->requisition = iNewReq;
6170 	  pRequisition->height += getNthRow(row)->requisition;
6171 	  if (row < m_iRows - 1)
6172 	  {
6173 		  pRequisition->height += pRow->spacing;
6174 	  }
6175   }
6176   pRequisition->height += 2 * m_iBorderWidth;
6177   xxx_UT_DEBUGMSG(("SEVIOR: requisition height %d \n", pRequisition->height));
6178 }
6179 
sizeAllocate(fp_Allocation * pAllocation)6180 void fp_TableContainer::sizeAllocate(fp_Allocation * pAllocation)
6181 {
6182 	m_MyAllocation.width = pAllocation->width;
6183 	m_MyAllocation.height = pAllocation->height;
6184 	m_MyAllocation.x = pAllocation->x;
6185 	m_MyAllocation.y = pAllocation->y;
6186 	m_MyAllocation.y = 0;
6187 	xxx_UT_DEBUGMSG(("SEVIOR: Initial allocation height is %d \n", pAllocation->height));
6188 
6189 	_size_allocate_init ();
6190 	xxx_UT_DEBUGMSG(("SEVIOR: Initial allocation height 1 is %d \n", m_MyAllocation.height));
6191 	_size_allocate_pass1 ();
6192 	xxx_UT_DEBUGMSG(("SEVIOR: Initial allocation height 2 is %d \n", m_MyAllocation.height));
6193 	_size_allocate_pass2 ();
6194 	xxx_UT_DEBUGMSG(("SEVIOR: Initial allocation height 3 is %d \n", m_MyAllocation.height));
6195 }
6196