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