1 /* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */
2 /* AbiWord
3  * Copyright (C) 1998 AbiSource, Inc.
4  * Copyright (C) 2004 Martin Sevior <msevior@physics.unimelb.edu.au>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  * 02110-1301 USA.
20  */
21 
22 #include <stdlib.h>
23 #include <math.h>
24 #include <string.h>
25 
26 #include "fp_TOCContainer.h"
27 #include "fp_Column.h"
28 #include "fp_Page.h"
29 #include "fp_Line.h"
30 #include "fp_Run.h"
31 #include "fp_TableContainer.h"
32 #include "fl_DocLayout.h"
33 #include "fl_SectionLayout.h"
34 #include "gr_DrawArgs.h"
35 #include "ut_vector.h"
36 #include "ut_types.h"
37 #include "ut_debugmsg.h"
38 #include "ut_assert.h"
39 #include "fl_TOCLayout.h"
40 #include "fv_View.h"
41 #include "gr_Painter.h"
42 
43 /*!
44   Create Table Of Contents container
45   \param iType Container type
46   \param pSectionLayout Section layout type used for this container
47  */
fp_TOCContainer(fl_SectionLayout * pSectionLayout)48 fp_TOCContainer::fp_TOCContainer(fl_SectionLayout* pSectionLayout)
49 	: fp_VerticalContainer(FP_CONTAINER_TOC, pSectionLayout),
50 	  m_pFirstBrokenTOC(NULL),
51 	  m_pLastBrokenTOC(NULL),
52 	  m_bIsBroken(false),
53 	  m_pMasterTOC(NULL),
54 	  m_iYBreakHere(0),
55 	  m_iYBottom(0),
56 	  m_iBrokenTop(0),
57 	  m_iBrokenBottom(0),
58 	  m_iLastWantedVBreak(0)
59 {
60 }
61 
fp_TOCContainer(fl_SectionLayout * pSectionLayout,fp_TOCContainer * pMaster)62 fp_TOCContainer::fp_TOCContainer(fl_SectionLayout* pSectionLayout, fp_TOCContainer * pMaster)
63 	: fp_VerticalContainer(FP_CONTAINER_TOC, pSectionLayout),
64 	  m_pFirstBrokenTOC(NULL),
65 	  m_pLastBrokenTOC(NULL),
66 	  m_bIsBroken(true),
67 	  m_pMasterTOC(pMaster),
68 	  m_iYBreakHere(0),
69 	  m_iYBottom(0),
70 	  m_iBrokenTop(0),
71 	  m_iBrokenBottom(0),
72 	  m_iLastWantedVBreak(0)
73 {
74 	setY(0);
75 }
76 
77 /*!
78   Destruct container
79   \note The Containers in vector of the container are not
80         destructed. They are owned by the logical hierarchy (i.e.,
81 		the fl_Container classes like fl_BlockLayout), not the physical
82         hierarchy.
83  */
~fp_TOCContainer()84 fp_TOCContainer::~fp_TOCContainer()
85 {
86 	clearCons();
87 	deleteBrokenTOCs(false);
88 	UT_DEBUGMSG(("SEVIOR: deleting TOC %p \n",this));
89 //
90 // For debugging...
91 //
92 	setContainer(NULL);
93 	setPrev(NULL);
94 	setNext(NULL);
95 	m_pMasterTOC = NULL;
96 
97 }
98 
99 /*!
100   Find document position from X and Y coordinates.  Note that the TOC
101   only has one document position, so that mapXYToPosition is rather
102   unhelpful for scrolling purposes.
103  \param  x X coordinate
104  \param  y Y coordinate
105  \retval pos Document position
106  \retval bBOL True if position is at begining of line, otherwise false
107  \retval bEOL True if position is at end of line, otherwise false
108  */
mapXYToPosition(UT_sint32 x,UT_sint32 y,PT_DocPosition & pos,bool & bBOL,bool & bEOL,bool & isTOC)109 void fp_TOCContainer::mapXYToPosition(UT_sint32 x, UT_sint32 y,
110 									  PT_DocPosition& pos,
111 									  bool& bBOL, bool& bEOL, bool &isTOC)
112 {
113 	isTOC = true;
114 	fp_VerticalContainer::mapXYToPosition(x, y, pos, bBOL, bEOL, isTOC);
115 }
116 
117 /*!
118  * This method returns the value of the TOC reference (or anchor)
119  */
getValue(void)120 UT_sint32 fp_TOCContainer::getValue(void)
121 {
122 	fl_TOCLayout * pTL = static_cast<fl_TOCLayout *>(getSectionLayout());
123 	return pTL->getTOCPID();
124 }
125 
clearScreen(void)126 void fp_TOCContainer::clearScreen(void)
127 {
128 	if(getPage() == NULL)
129 	{
130 		return;
131 	}
132 	if(isThisBroken() && getContainer())
133 	{
134 		xxx_UT_DEBUGMSG(("Doing Clear Screen on Broken TOC %x \n",this));
135 		UT_sint32 iHeight = getHeight();
136 		UT_sint32 iWidth = getContainer()->getWidth();
137 		UT_sint32 srcX  = getX();
138 		UT_sint32 srcY = getY();
139 		if(getFirstBrokenTOC() == this)
140 		{
141 			srcY = getMasterTOC()->getY();
142 		}
143 		fp_Column * pCol = static_cast<fp_Column *>(getColumn());
144 		UT_sint32 x,y;
145 		getPage()->getScreenOffsets(pCol,x,y);
146 		x += srcX;
147 		y += srcY;
148 		getFillType().setWidthHeight(getGraphics(),iWidth,iHeight);
149 		getFillType().Fill(getGraphics(),srcX,srcY,x,y,iWidth,iHeight);
150 		xxx_UT_DEBUGMSG(("x %d y %d width %d height %d \n",x,y,iWidth,iHeight));
151 		return;
152 	}
153 	fp_Container * pCon = NULL;
154 	UT_sint32 i = 0;
155 	for(i=0; i< countCons(); i++)
156 	{
157 		pCon = static_cast<fp_Container *>(getNthCon(i));
158 		pCon->clearScreen();
159 	}
160 }
161 
162 
forceClearScreen(void)163 void fp_TOCContainer::forceClearScreen(void)
164 {
165 	if(getPage() == NULL)
166 	{
167 		return;
168 	}
169 	fp_Container * pCon = NULL;
170 	UT_sint32 i = 0;
171 	for(i=0; i< countCons(); i++)
172 	{
173 		pCon = static_cast<fp_Container *>(getNthCon(i));
174 		if(pCon->getContainerType() == FP_CONTAINER_LINE)
175 		{
176 			static_cast<fp_Line *>(pCon)->setScreenCleared(false);
177 		}
178 		pCon->clearScreen();
179 	}
180 }
181 
getDocSectionLayout(void)182 fl_DocSectionLayout * fp_TOCContainer::getDocSectionLayout(void)
183 {
184 	fl_TOCLayout * pTL = static_cast<fl_TOCLayout *>(getSectionLayout());
185 	fl_DocSectionLayout * pDSL = static_cast<fl_DocSectionLayout *>(pTL->myContainingLayout());
186 	UT_ASSERT(pDSL && (pDSL->getContainerType() == FL_CONTAINER_DOCSECTION));
187 	return pDSL;
188 }
189 
190 
191 /*!
192  Draw container content
193  \param pDA Draw arguments
194  */
draw(GR_Graphics *)195 void fp_TOCContainer::draw(GR_Graphics * /*pG*/)
196 {
197 }
198 /*!
199  Draw container content
200  \param pDA Draw arguments
201  */
draw(dg_DrawArgs * pDA)202 void fp_TOCContainer::draw(dg_DrawArgs* pDA)
203 {
204 	if(getPage() == NULL)
205 	{
206 		return;
207 	}
208 	if(!isThisBroken() && getFirstBrokenTOC())
209 	{
210 		getFirstBrokenTOC()->draw(pDA);
211 		return;
212 	}
213 	fp_TOCContainer * pMaster = this;
214 	if(getMasterTOC())
215 	{
216 		pMaster = getMasterTOC();
217 	}
218 	xxx_UT_DEBUGMSG(("TOC: Drawing broken TOC %x x %d, y %d width %d height %d \n",this,pDA->xoff,pDA->yoff,getWidth(),getHeight()));
219 
220 //
221 // Only draw the lines in the clipping region.
222 //
223 	dg_DrawArgs da = *pDA;
224 
225 	UT_uint32 count = pMaster->countCons();
226 	UT_sint32 iYStart = getYBreak();
227 	UT_sint32 iYBottom = getYBottom();
228 	xxx_UT_DEBUGMSG(("Drawing TOC, yBreak %d ybottom %d \n",iYStart,iYBottom));
229 	for (UT_uint32 i = 0; i<count; i++)
230 	{
231 		fp_ContainerObject* pContainer = static_cast<fp_ContainerObject*>(pMaster->getNthCon(i));
232 		if(pContainer->getY() < iYStart)
233 		{
234 			continue;
235 		}
236 		if(pContainer->getY() > iYBottom)
237 		{
238 			break;
239 		}
240 		da.xoff = pDA->xoff + pContainer->getX();
241 		da.yoff = pDA->yoff + pContainer->getY() - iYStart;
242 		pContainer->draw(&da);
243 	}
244     _drawBoundaries(pDA);
245 }
246 
getNextContainerInSection() const247 fp_Container * fp_TOCContainer::getNextContainerInSection() const
248 {
249 	if(getNext())
250 	{
251 		return static_cast<fp_Container *>(getNext());
252 	}
253 	fl_ContainerLayout * pCL = static_cast<fl_ContainerLayout *>(getSectionLayout());
254 	fl_ContainerLayout * pNext = pCL->getNext();
255 	while(pNext && pNext->getContainerType() == FL_CONTAINER_ENDNOTE)
256 	{
257 		pNext = pNext->getNext();
258 	}
259 	if(pNext)
260 	{
261 		return pNext->getFirstContainer();
262 	}
263 	return NULL;
264 }
265 
266 
getBrokenColumn(void)267 fp_Column * fp_TOCContainer::getBrokenColumn(void)
268 {
269 	if(!isThisBroken())
270 	{
271 		return static_cast<fp_Column *>(fp_VerticalContainer::getColumn());
272 	}
273 	fp_TOCContainer * pBroke = this;
274 	bool bStop = false;
275 	fp_Column * pCol = NULL;
276 	while(pBroke && pBroke->isThisBroken() && !bStop)
277 	{
278 		fp_Container * pCon = pBroke->getContainer();
279 		if(pCon->isColumnType())
280 		{
281 			if(pCon->getContainerType() == FP_CONTAINER_COLUMN)
282 			{
283 				pCol = static_cast<fp_Column *>(pCon);
284 			}
285 			else
286 			{
287 				pCol = static_cast<fp_Column *>(pCon->getColumn());
288 			}
289 			bStop = true;
290 		}
291 		else
292 		{
293 			UT_ASSERT(0);
294 		}
295 	}
296 	if(pBroke && !bStop)
297 	{
298 		pCol = static_cast<fp_Column *>(pBroke->getContainer());
299 	}
300 	return pCol;
301 }
302 
getPrevContainerInSection() const303 fp_Container * fp_TOCContainer::getPrevContainerInSection() const
304 {
305 	if(getPrev())
306 	{
307 		return static_cast<fp_Container *>(getPrev());
308 	}
309 
310 	fl_ContainerLayout * pCL = static_cast<fl_ContainerLayout *>(getSectionLayout());
311 	fl_ContainerLayout * pPrev = pCL->getPrev();
312 	while(pPrev && pPrev->getContainerType() == FL_CONTAINER_ENDNOTE)
313 	{
314 		pPrev = pPrev->getPrev();
315 	}
316 	if(pPrev)
317 	{
318 		return pPrev->getLastContainer();
319 	}
320 	return NULL;
321 }
322 
isVBreakable(void)323 bool fp_TOCContainer::isVBreakable(void)
324 {
325 	return true;
326 }
327 
isInBrokenTOC(fp_Container * pCon)328 bool fp_TOCContainer::isInBrokenTOC(fp_Container * pCon)
329 {
330 //
331 // OK A container is allowed in this broken TOC if it's
332 // Y location plus height lie between getYBreak() and getYBottom.
333 //
334 	//
335 	// Short circuit things if the BrokenContainer pointer is set.
336     //
337  	if(pCon->getMyBrokenContainer() == static_cast<fp_Container *>(this))
338  	{
339  		return true;
340  	}
341  	if(pCon->getMyBrokenContainer() != NULL)
342  	{
343  		return false;
344  	}
345 	UT_sint32 iTop = 0;
346 	iTop = pCon->getY();
347 	UT_sint32 iHeight = pCon->getHeight();
348 
349 	UT_sint32 iBot = iTop + iHeight;
350 
351 	UT_sint32 iBreak = getYBreak();
352 	UT_sint32 iBottom = getYBottom();
353 	xxx_UT_DEBUGMSG(("Column %x iTop = %d ybreak %d iBot= %d ybottom= %d \n",getBrokenColumn(),iTop,iBreak,iBot,iBottom));
354 	if(iBot >= iBreak)
355 	{
356 		if(iBot < iBottom)
357 		{
358 			//			pCon->setMyBrokenContainer(this);
359 			return true;
360 		}
361 
362 	}
363 	return false;
364 
365 }
366 
getLastBrokenTOC(void) const367 fp_TOCContainer * fp_TOCContainer::getLastBrokenTOC(void) const
368 {
369 	if(isThisBroken())
370 	{
371 		return getMasterTOC()->getLastBrokenTOC();
372 	}
373 	return m_pLastBrokenTOC;
374 }
375 
getBrokenNumber(void)376 UT_sint32 fp_TOCContainer::getBrokenNumber(void)
377 {
378 	if(!isThisBroken())
379 	{
380 		return 0;
381 	}
382 	fp_TOCContainer * pTOC = getMasterTOC()->getFirstBrokenTOC();
383 	UT_sint32 i = 1;
384 	while(pTOC && pTOC != this)
385 	{
386 		pTOC = static_cast<fp_TOCContainer *>(pTOC->getNext());
387 		i++;
388 	}
389 	if(!pTOC)
390 	{
391 		return -1;
392 	}
393 	return i;
394 }
395 
396 
setFirstBrokenTOC(fp_TOCContainer * pBroke)397 void fp_TOCContainer::setFirstBrokenTOC(fp_TOCContainer * pBroke)
398 {
399 	if(isThisBroken())
400 	{
401 		getMasterTOC()->setFirstBrokenTOC(pBroke);
402 	}
403 	m_pFirstBrokenTOC = pBroke;
404 
405 }
406 
setLastBrokenTOC(fp_TOCContainer * pBroke)407 void fp_TOCContainer::setLastBrokenTOC(fp_TOCContainer * pBroke)
408 {
409 	if(isThisBroken())
410 	{
411 		getMasterTOC()->setLastBrokenTOC(pBroke);
412 	}
413 	m_pLastBrokenTOC = pBroke;
414 }
415 
416 /*!
417  * This method creates a new broken toccontainer, broken at the
418  * offset given.
419  * If the new TOCcontainer is broken from a pre-existing
420  * broken TOC it is inserted into the holding vertical container after
421  * the old broken TOC.
422  * It also inserted into the linked list of containers in the vertical
423  * container.
424  * vpos is relative to the either the start of the TOC if it's the first
425  * non-zero vpos or relative to the previous ybreak if it's further down.
426  */
VBreakAt(UT_sint32 vpos)427 fp_ContainerObject * fp_TOCContainer::VBreakAt(UT_sint32 vpos)
428 {
429 //
430 // Do the case of creating the first broken TOC from the master TOC.
431 //
432 	fp_TOCContainer * pBroke = NULL;
433 	if(!isThisBroken() && getLastBrokenTOC() == NULL)
434 	{
435 		if(getFirstBrokenTOC() != NULL)
436 		{
437 			UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
438 			return NULL;
439 		}
440 		pBroke = new fp_TOCContainer(getSectionLayout(),this);
441 		UT_DEBUGMSG(("SEVIOR:!!!!!!! First broken TOC %p \n",pBroke));
442 		pBroke->setYBreakHere(vpos);
443 		pBroke->setYBottom(fp_VerticalContainer::getHeight());
444 		// leave this in!		UT_ASSERT(pBroke->getHeight());
445 		setFirstBrokenTOC(pBroke);
446 		setLastBrokenTOC(pBroke);
447 		pBroke->setContainer(getContainer());
448 		static_cast<fp_VerticalContainer *>(pBroke)->setHeight(pBroke->getHeight());
449 		static_cast<fp_VerticalContainer *>(pBroke)->setY(getY());
450 		return pBroke;
451 	}
452 //
453 // Now do the case of breaking a Master TOC.
454 //
455 	if(getMasterTOC() == NULL)
456 	{
457 		return getLastBrokenTOC()->VBreakAt(vpos);
458 	}
459 	UT_sint32 iTotalHeight = getTotalTOCHeight();
460 	if (vpos >= iTotalHeight)
461 	{
462 		UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
463 		return NULL;
464 	}
465 
466 	pBroke = new fp_TOCContainer(getSectionLayout(),getMasterTOC());
467 	getMasterTOC()->setLastBrokenTOC(pBroke);
468 
469 	xxx_UT_DEBUGMSG(("SEVIOR!!!!!!!!!!!  New broken TOC %x \n",getLastBrokenTOC()));
470 
471 //
472 // vpos is relative to the container that contains this height but we need
473 // to add in the height above it.
474 //
475 	setYBottom(getYBreak() + vpos -1);
476 	UT_ASSERT(getHeight() >0);
477 	pBroke->setYBreakHere(getYBreak()+vpos);
478 	pBroke->setYBottom(iTotalHeight);
479 	UT_ASSERT(pBroke->getHeight() > 0);
480 	UT_sint32 i = -1;
481 //
482 // The structure of TOC linked list is as follows.
483 // NULL <= Master <==> Next <==> Next => NULL
484 //          first
485 // ie terminated by NULL's in the getNext getPrev list. The second
486 // broken TOC points and is pointed to by the Master TOC
487 //
488 	pBroke->setPrev(this);
489 	fp_Container * pUpCon = NULL;
490 	if(getMasterTOC()->getFirstBrokenTOC() == this)
491 	{
492 		pUpCon = getMasterTOC()->getContainer();
493 		pBroke->setPrev(getMasterTOC());
494 		pBroke->setNext(NULL);
495 		getMasterTOC()->setNext(pBroke);
496 		setNext(pBroke);
497 		if (pUpCon)
498 		{
499 			i = pUpCon->findCon(getMasterTOC());
500 		}
501 	}
502 	else
503 	{
504 		pBroke->setNext(NULL);
505 		setNext(pBroke);
506 		if(getYBreak() == 0 )
507 		{
508 			UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
509 			pUpCon = getMasterTOC()->getContainer();
510 			if(pUpCon)
511 			{
512 				i = pUpCon->findCon(getMasterTOC());
513 			}
514 		}
515 		else
516 		{
517 			pUpCon = getContainer();
518 			if (pUpCon)
519 			{
520 				i = pUpCon->findCon(this);
521 			}
522 		}
523 	}
524 	if((i >= 0) && (i < pUpCon->countCons() -1))
525 	{
526 		pUpCon->insertConAt(pBroke,i+1);
527 	}
528 	else if((i >= 0) && (i == pUpCon->countCons() -1))
529 	{
530 		pUpCon->addCon(pBroke);
531 	}
532 	else
533 	{
534 		UT_DEBUGMSG(("Breaking a TOC that is not yet inserted\n"));
535 	}
536 	pBroke->setContainer(pUpCon);
537 	//
538 	// Now deal with issues from a container overlapping the top of the
539 	// of the new broken TOC.
540 	//
541 	// Skip this for now. Look at fp_TableContainer to see if it's needed later
542 	//
543 	static_cast<fp_VerticalContainer *>(pBroke)->setHeight(pBroke->getHeight());
544 	return pBroke;
545 }
546 
547 
548 /*!
549  * Overload the setY method
550  */
setY(UT_sint32 i)551 void fp_TOCContainer::setY(UT_sint32 i)
552 {
553 	bool bIsFirstBroken = false;
554 	UT_sint32 iOldY = getY();
555 	xxx_UT_DEBUGMSG(("fp_TOCContainer: setY set to %d \n",i));
556 	if(isThisBroken())
557 	{
558 		xxx_UT_DEBUGMSG(("setY: getMasterTOC %x FirstBrokenTOC %x this %x \n",getMasterTOC(),getMasterTOC()->getFirstBrokenTOC(),this));
559 		//	if(getMasterTOC()->getFirstBrokenTOC() != this)
560 		{
561 			xxx_UT_DEBUGMSG(("setY: Later broken TOC set to %d \n",i));
562 			fp_VerticalContainer::setY(i);
563 			return;
564 		}
565 		bIsFirstBroken = true;
566 	}
567 //
568 // Create an initial broken TOC if none exists
569 //
570 	if(!bIsFirstBroken && (getFirstBrokenTOC() == NULL))
571 	{
572 		VBreakAt(0);
573 	}
574 	iOldY = getY();
575 	if(i == iOldY)
576 	{
577 		return;
578 	}
579 	clearScreen();
580 //
581 // FIXME: Do I need to force another breakSection or will happen
582 // automatically?
583 //
584 	xxx_UT_DEBUGMSG(("Set Reformat 1 now from TOC %x in TOCLayout %x \n",this,getSectionLayout()));
585 	getSectionLayout()->setNeedsReformat(getSectionLayout());
586 	fp_VerticalContainer::setY(i);
587 	adjustBrokenTOCs();
588 }
589 
590 
setYBreakHere(UT_sint32 i)591 void fp_TOCContainer::setYBreakHere(UT_sint32 i)
592 {
593 	xxx_UT_DEBUGMSG(("SEVIOR: Ybreak set to %d \n",i));
594 	m_iYBreakHere = i;
595 	if(i > 0)
596 	{
597 		//	UT_ASSERT(getHeight() > 0);
598 	}
599 }
600 
setYBottom(UT_sint32 i)601 void fp_TOCContainer::setYBottom(UT_sint32 i)
602 {
603 	m_iYBottom = i;
604 	//	UT_ASSERT(getHeight() > 0);
605 }
606 
607 /*!
608  * The caller to this method requests a break at the vertical height
609  * given. It returns the actual break height, which will always be
610  * less than or equal to the requested height. The function returns -1
611  * if the table does not need to be broken.
612  */
wantVBreakAt(UT_sint32 vpos)613 UT_sint32 fp_TOCContainer::wantVBreakAt(UT_sint32 vpos)
614 {
615 	if(isThisBroken())
616 	{
617 		return getMasterTOC()->wantVBreakAt(vpos);
618 	}
619 	UT_sint32 count = countCons();
620 	UT_sint32 i =0;
621 	UT_sint32 iYBreak = vpos;
622 	UT_sint32 iTotHeight = getTotalTOCHeight();
623 	if (iYBreak > iTotHeight)
624 	{
625 		return -1;
626 	}
627 	else if (iYBreak > iTotHeight - FP_TABLE_MIN_BROKEN_HEIGHT)
628 	{
629 		iYBreak = iTotHeight - FP_TABLE_MIN_BROKEN_HEIGHT;
630 	}
631 
632 	fp_Line * pLine;
633 	for(i=0; i< count; i++)
634 	{
635 		pLine = static_cast<fp_Line *>(getNthCon(i));
636 		if((pLine->getY() <= vpos) && (pLine->getY() + pLine->getHeight() +pLine->getMarginAfter() > vpos))
637 		{
638 			//
639 			// Line overlaps break point. Find break here
640 			//
641 			iYBreak = pLine->getY();
642 		}
643 	}
644 	return iYBreak;
645 }
646 
647 
648 /*!
649  * Return the height of this Table taking into account the possibility
650  * of it being broken.
651  */
getHeight(void) const652 UT_sint32 fp_TOCContainer::getHeight(void) const
653 {
654 	UT_sint32 iFullHeight =  fp_VerticalContainer::getHeight();
655 	if(!isThisBroken())
656 	{
657 //
658 // If this is a master table but it contains broken tables, we actually
659 // want the height of the first broken table. The Master table is the
660 // one that actually has a relevant Y value in the vertical container.
661 // All other Y offsets from the broken tables are calculated relative to
662 // it.
663 //
664 		if(getFirstBrokenTOC() != NULL)
665 		{
666 			return getFirstBrokenTOC()->getHeight();
667 		}
668 		return iFullHeight;
669 	}
670 	UT_sint32 iMyHeight = getYBottom() - getYBreak();
671 	return iMyHeight;
672 }
673 
674 
675 
676 /*
677   Return the height of the complete TOC as if it was not broken
678 */
679 
getTotalTOCHeight(void) const680 UT_sint32 fp_TOCContainer::getTotalTOCHeight(void) const
681 {
682 	if (getMasterTOC())
683 	{
684 		return getMasterTOC()->getTotalTOCHeight();
685 	}
686 
687 	return fp_VerticalContainer::getHeight();
688 }
689 
690 /*!
691  * This method adjusts the m_iYBreak and m_iYBottom variables after a
692  * setY method changes the start position of the top of the table.
693  */
adjustBrokenTOCs(void)694 void fp_TOCContainer::adjustBrokenTOCs(void)
695 {
696 	if(isThisBroken())
697 	{
698 		//		UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
699 		return;
700 	}
701 	if(getFirstBrokenTOC() == NULL)
702 	{
703 		return;
704 	}
705 	if(getFirstBrokenTOC() == getLastBrokenTOC())
706 	{
707 		return;
708 	}
709 	//
710 	// FIXME. Both this code and the code in fp_TableContainer, somehow leads to bugs. I've clearly found
711 	// workarounds to what this is trying to achive. In pricinple this code should make laying out TOC's
712 	// faster. In parctice I suspect it leads to bugs in fb_ColumnBreaker. I'll leave these returns in place
713 	// for now, pending removal of the methods.
714 	//
715 	return;
716 	fp_TOCContainer * pBroke = getFirstBrokenTOC();
717 	fp_VerticalContainer * pVC = static_cast<fp_VerticalContainer *>(getContainer());
718 	UT_sint32 iNewHeight = pVC->getMaxHeight() - getY();
719 	UT_sint32 ishift = iNewHeight - pBroke->getYBottom();
720 	UT_sint32 iNewBot = pBroke->getYBottom() + ishift;
721 	UT_sint32 iTOCHeight = fp_VerticalContainer::getHeight();
722 	UT_DEBUGMSG(("SEVIOR: ishift = %d iNewHeight %d  pBroke->getYBottom() %d \n",ishift,iNewHeight,pBroke->getYBottom()));
723 	if(ishift == 0)
724 	{
725 		return;
726 	}
727 	if(iNewBot > iTOCHeight)
728 	{
729 		iNewBot = iTOCHeight;
730 	}
731 	pBroke->setYBottom(iNewBot);
732 	UT_ASSERT(pBroke->getHeight());
733 
734 	pBroke = static_cast<fp_TOCContainer *>(pBroke->getNext());
735 	while(pBroke)
736 	{
737 		UT_sint32 iNewTop = pBroke->getYBreak();
738 		iNewBot = pBroke->getYBottom();
739 		pBroke->setYBreakHere(iNewTop + ishift);
740 		if(pBroke->getNext())
741 		{
742 			pBroke->setYBottom(iNewBot+ishift);
743 			UT_ASSERT(pBroke->getHeight());
744 		}
745 		else
746 		{
747 			pBroke->setYBottom(iTOCHeight);
748 			UT_ASSERT(pBroke->getHeight());
749 		}
750 		xxx_UT_DEBUGMSG(("SEVIOR: Broken TOC %x YBreak adjusted to %d Shift is %d height is %d \n",pBroke,iNewTop+ishift,ishift,pBroke->getHeight()));
751 		fp_TOCContainer * pPrev = static_cast<fp_TOCContainer *>(pBroke->getPrev());
752 //
753 // If the height of the previous plus the height of pBroke offset from
754 // the previous position is less that the column height we can delete
755 // this broken TOC.
756 //
757 		UT_sint32 iMaxHeight = 0;
758 		bool bDeleteOK = false;
759 		if(pPrev)
760 		{
761 			iMaxHeight = static_cast<fp_VerticalContainer *>(pPrev->getContainer())->getMaxHeight();
762 			xxx_UT_DEBUGMSG(("SEVIOR: sum %d maxheight %d \n",(pPrev->getY() + pPrev->getHeight() + pBroke->getHeight()), iMaxHeight));
763 		}
764 		if(bDeleteOK && pPrev && (pPrev->getY() + pPrev->getHeight() + pBroke->getHeight() < iMaxHeight))
765 		{
766 //
767 // FIXME: This if should be unnested....
768 //
769 			if(pPrev == this)
770 			{
771 				pPrev = getFirstBrokenTOC();
772 			}
773 			xxx_UT_DEBUGMSG(("SEVIOR; In adjust - Deleting TOC. Max height %d prev Y %d prev Height %d cur Height %d \n",iMaxHeight, pPrev->getY(),pPrev->getHeight(),pBroke->getHeight()));
774 //
775 // Don't need this TOC any more. Delete it and all following TOCs.
776 // after adjusting the previous TOC.
777 //
778 			pPrev->setYBottom(iTOCHeight);
779 			UT_ASSERT(pPrev->getHeight());
780 			pPrev->setNext( NULL);
781 			if(pPrev == getFirstBrokenTOC())
782 			{
783 				setNext(NULL);
784 				getFirstBrokenTOC()->setYBreakHere(0);
785 				UT_ASSERT(getFirstBrokenTOC()->getHeight());
786 			}
787 			setLastBrokenTOC(pPrev);
788 			xxx_UT_DEBUGMSG(("SEVIOR!!!!!!!!!!! 2 last broken TOC %x deleting %x Master TOC %x  \n",getLastBrokenTOC(),pBroke,this));
789 			xxx_UT_DEBUGMSG(("SEVIOR!!!!!!!!!!! 2 get first %x get last broken TOC %x \n",getFirstBrokenTOC(),getLastBrokenTOC()));
790 			fp_TOCContainer * pT = getFirstBrokenTOC();
791 			UT_sint32 j = 0;
792 			while(pT)
793 			{
794 				xxx_UT_DEBUGMSG(("SEVIOR: TOC %d is %x \n",j,pT));
795 				j++;
796 				pT = static_cast<fp_TOCContainer *>(pT->getNext());
797 			}
798 			while(pBroke)
799 			{
800 				fp_TOCContainer * pNext = static_cast<fp_TOCContainer *>(pBroke->getNext());
801 				UT_sint32 i = pBroke->getContainer()->findCon(pBroke);
802 				if(i >=0)
803 				{
804 					pBroke->getContainer()->deleteNthCon(i);
805 				}
806 				else
807 				{
808 					UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
809 				}
810 				xxx_UT_DEBUGMSG(("SEVIOR: Adjust  - Delete TOC %x \n",pBroke));
811 				delete pBroke;
812 				pBroke = pNext;
813 			}
814 		}
815 		else
816 		{
817 			pBroke = static_cast<fp_TOCContainer *>(pBroke->getNext());
818 		}
819 	}
820 }
821 
822 /*!
823  * This deletes all the broken TOCs from this master TOC.
824  * This routine assumes that a clear screen has been set already.
825  */
deleteBrokenTOCs(bool bClearFirst)826 void fp_TOCContainer::deleteBrokenTOCs(bool bClearFirst)
827 {
828 	if(isThisBroken())
829 	{
830 		return;
831 	}
832 	if(bClearFirst)
833 	{
834 		clearScreen();
835 		//
836 		// Remove broken TOC pointers
837 		//
838 		clearBrokenContainers();
839 	}
840 	if(getFirstBrokenTOC() == NULL)
841 	{
842 		return;
843 	}
844 	fp_TOCContainer * pBroke = NULL;
845 	fp_TOCContainer * pNext = NULL;
846 	pBroke = getFirstBrokenTOC();
847 	bool bFirst = true;
848 	while(pBroke )
849 	{
850 		pNext = static_cast<fp_TOCContainer *>(pBroke->getNext());
851 		if(!bFirst)
852 		{
853 		        fp_Container * pConBroke =  pBroke->getContainer();
854 			if(pConBroke)
855 			{
856 			    UT_sint32 i = pBroke->getContainer()->findCon(pBroke);
857 //
858 // First broken TOC is not in the container.
859 //
860 			    if(i >=0)
861 			    {
862 			        fp_Container * pCon = pBroke->getContainer();
863 				pBroke->setContainer(NULL);
864 				pCon->deleteNthCon(i);
865 			    }
866 			}
867 		}
868 		bFirst = false;
869 		xxx_UT_DEBUGMSG(("SEVIOR: Deleting broken TOC %x \n",pBroke));
870 		delete pBroke;
871 		if(pBroke == getLastBrokenTOC())
872 		{
873 			pBroke = NULL;
874 		}
875 		else
876 		{
877 			pBroke = pNext;
878 		}
879 	}
880 	setFirstBrokenTOC(NULL);
881 	setLastBrokenTOC(NULL);
882 	setNext(NULL);
883 	setPrev(NULL);
884 //	if(bClearFirst)
885 	{
886 		fl_TOCLayout * pTL = static_cast<fl_TOCLayout *>(getSectionLayout());
887 		fl_DocSectionLayout * pDSL = pTL->getDocSectionLayout();
888 		pDSL->deleteBrokenTablesFromHere(pTL);
889 	}
890 }
891 
892 
893 /*
894   Delete all broken TOCs that follows this TOC. The first broken TOC
895   is kept if the function is called by the master TOC.
896 */
897 
deleteBrokenAfter(bool bClearFirst)898 void fp_TOCContainer::deleteBrokenAfter(bool bClearFirst)
899 {
900 	if (!isThisBroken())
901 	{
902 		if (getFirstBrokenTOC())
903 		{
904 			return getFirstBrokenTOC()->deleteBrokenAfter(bClearFirst);
905 		}
906 		return;
907 	}
908 
909 	if (bClearFirst)
910 	{
911 		clearScreen();
912 		getMasterTOC()->clearBrokenContainers();
913 	}
914 
915 	fp_TOCContainer * pBroke = static_cast<fp_TOCContainer *>(getNext());
916 	fp_TOCContainer * pNext = NULL;
917 	while(pBroke)
918 	{
919 		pNext = static_cast<fp_TOCContainer *> (pBroke->getNext());
920 		if (pBroke->getContainer())
921 		{
922 			UT_sint32 i = pBroke->getContainer()->findCon(pBroke);
923 			if (i >= 0)
924 			{
925 				pBroke->getContainer()->deleteNthCon(i);
926 				pBroke->setContainer(NULL);
927 			}
928 		}
929 		delete pBroke;
930 		pBroke = pNext;
931 	}
932 
933 	setNext(NULL);
934 	if (!getPrev())
935 	{
936 		getMasterTOC()->setNext(NULL);
937 	}
938 	getMasterTOC()->setLastBrokenTOC(this);
939 	setYBottom(getTotalTOCHeight());
940 }
941 
942 
getFirstBrokenTOC(void) const943 fp_TOCContainer * fp_TOCContainer::getFirstBrokenTOC(void) const
944 {
945 	if(isThisBroken())
946 	{
947 		return getMasterTOC()->getFirstBrokenTOC();
948 	}
949 	return m_pFirstBrokenTOC;
950 }
951 
952 
getFirstBrokenContainer() const953 fp_Container * fp_TOCContainer::getFirstBrokenContainer() const
954 {
955 	return getFirstBrokenTOC();
956 }
957 
958 
setContainer(fp_Container * pContainer)959 void fp_TOCContainer::setContainer(fp_Container * pContainer)
960 {
961 	xxx_UT_DEBUGMSG(("!!!!!-----!!!!TOC Container set to %x \n",pContainer));
962 	if(isThisBroken())
963 	{
964 		fp_Container::setContainer(pContainer);
965 		return;
966 	}
967 	if (pContainer == getContainer())
968 	{
969 		return;
970 	}
971 	if (getContainer() && (pContainer != NULL))
972 	{
973 		clearScreen();
974 	}
975 	fp_Container::setContainer(pContainer);
976 	fp_TOCContainer * pBroke = getFirstBrokenTOC();
977 	if(pBroke)
978 	{
979 		pBroke->setContainer(pContainer);
980 	}
981 	if(pContainer == NULL)
982 	{
983 		xxx_UT_DEBUGMSG(("Set master TOC %x container to NULL \n",this));
984 		return;
985 	}
986 	setWidth(pContainer->getWidth());
987 }
988 
layout(void)989 void fp_TOCContainer::layout(void)
990 {
991 	_setMaxContainerHeight(0);
992 	UT_sint32 iY = 0, iPrevY = 0;
993 	iY= 0;
994 	UT_uint32 iCountContainers = countCons();
995 	fp_Container *pContainer, *pPrevContainer = NULL;
996 	for (UT_uint32 i=0; i < iCountContainers; i++)
997 	{
998 		pContainer = static_cast<fp_Container*>(getNthCon(i));
999 //
1000 // This is to speedup redraws.
1001 //
1002 		if(pContainer->getHeight() > _getMaxContainerHeight())
1003 			_setMaxContainerHeight(pContainer->getHeight());
1004 
1005 		if(pContainer->getY() != iY)
1006 		{
1007 			pContainer->clearScreen();
1008 		}
1009 
1010 		pContainer->setY(iY);
1011 
1012 		UT_sint32 iContainerHeight = pContainer->getHeight();
1013 		UT_sint32 iContainerMarginAfter = pContainer->getMarginAfter();
1014 
1015 		iY += iContainerHeight;
1016 		iY += iContainerMarginAfter;
1017 		//iY +=  0.5;
1018 		if (pPrevContainer)
1019 		{
1020 			pPrevContainer->setAssignedScreenHeight(iY - iPrevY);
1021 		}
1022 		pPrevContainer = pContainer;
1023 		iPrevY = iY;
1024 	}
1025 
1026 	// Correct height position of the last line
1027 	if (pPrevContainer)
1028 	{
1029 		pPrevContainer->setAssignedScreenHeight(iY - iPrevY + 1);
1030 	}
1031 
1032 	if (fp_VerticalContainer::getHeight() == iY)
1033 	{
1034 		return;
1035 	}
1036 	UT_DEBUGMSG(("Height in TOCContainer set to %d Old Height %d \n",iY,getHeight()));
1037 	setHeight(iY);
1038 	deleteBrokenTOCs(true);
1039 }
1040 
1041