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