1 /* -*- mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: t -*- */
2 /* AbiWord
3 * Copyright (C) 1998 AbiSource, Inc.
4 * Copyright (C) 2002 Martin Sevior
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301 USA.
20 */
21
22 #include <string.h>
23 #include <stdlib.h>
24
25 #include "ut_types.h"
26 #include "ut_string.h"
27
28 #include "ap_Prefs.h"
29 #include "fl_ContainerLayout.h"
30 #include "fl_FootnoteLayout.h"
31 #include "fl_SectionLayout.h"
32 #include "fl_Layout.h"
33 #include "fl_DocLayout.h"
34 #include "fl_BlockLayout.h"
35 #include "fl_TOCLayout.h"
36 #include "fl_TableLayout.h"
37 #include "fp_TableContainer.h"
38 #include "fp_Page.h"
39 #include "fp_Line.h"
40 #include "fp_Column.h"
41 #include "pd_Document.h"
42 #include "pp_AttrProp.h"
43 #include "pt_Types.h"
44 #include "gr_Graphics.h"
45 #include "fv_View.h"
46 #include "fp_Run.h"
47 #include "ut_debugmsg.h"
48 #include "ut_assert.h"
49 #include "ut_units.h"
50 #include "fl_FrameLayout.h"
51 #include "fp_FrameContainer.h"
52 #include "fl_AutoNum.h"
53
54
fl_ContainerLayout(fl_ContainerLayout * pMyLayout,pf_Frag_Strux * sdh,PT_AttrPropIndex indexAP,PTStruxType iStrux,fl_ContainerType iType)55 fl_ContainerLayout::fl_ContainerLayout(fl_ContainerLayout* pMyLayout, pf_Frag_Strux* sdh, PT_AttrPropIndex indexAP, PTStruxType iStrux, fl_ContainerType iType)
56 : fl_Layout(iStrux, sdh),
57 m_iConType(iType),
58 m_pMyLayout(pMyLayout),
59 m_pPrev(NULL),
60 m_pNext(NULL),
61 m_pFirstL(NULL),
62 m_pLastL(NULL),
63 m_pFirstContainer(NULL),
64 m_pLastContainer(NULL),
65 m_eHidden(FP_VISIBLE),
66 m_iFoldedLevel(0)
67 {
68 // UT_ASSERT(pMyLayout != NULL);
69 setAttrPropIndex(indexAP);
70 if(pMyLayout)
71 {
72 m_pDoc = pMyLayout->getDocument();
73 }
74 }
75
~fl_ContainerLayout()76 fl_ContainerLayout::~fl_ContainerLayout()
77 {
78 #if 1
79 m_pMyLayout = NULL;
80 m_pFirstL = NULL;
81 m_pLastL = NULL;
82 m_pPrev = NULL;
83 m_pNext = NULL;
84 m_pFirstContainer = NULL;
85 m_pLastContainer = NULL;
86 #endif
87 }
88
_getPropertiesAP(const PP_AttrProp * & pAP)89 bool fl_ContainerLayout::_getPropertiesAP(const PP_AttrProp*& pAP)
90 {
91 pAP = NULL;
92 FPVisibility eVisibility = getAP(pAP);
93 UT_return_val_if_fail(pAP, false);
94
95 setVisibility(eVisibility);
96
97 // Find the folded Level of the strux
98 lookupFoldedLevel();
99 if((isHidden() == FP_VISIBLE) && (getFoldedLevel() > 0) && (getLevelInList() > getFoldedLevel()) )
100 {
101 xxx_UT_DEBUGMSG(("Table set to hidden folded \n"));
102 setVisibility(FP_HIDDEN_FOLDED);
103 }
104 // evaluate "display" property
105 // display property
106 const char* pszDisplay = NULL;
107 pAP->getProperty("display", (const gchar *&)pszDisplay);
108 if(isHidden() == FP_VISIBLE && pszDisplay && !strcmp(pszDisplay, "none"))
109 {
110 setVisibility(FP_HIDDEN_TEXT);
111 }
112
113 return true;
114 }
115
lookupProperties(void)116 void fl_ContainerLayout::lookupProperties(void)
117 {
118 // first of all, call getAP() which will set default visibility
119 // for us (either visible, or hidden revision)
120
121 // other common properties should come here
122
123 // this should only implement class-specific properties ...
124 const PP_AttrProp* pAP;
125
126 // assert not needed, since _getPropertiesAP() asserts on failure
127 if(!_getPropertiesAP(pAP))
128 return;
129
130 _lookupProperties(pAP);
131 }
132
133 /*!
134 This function looks up only a limited set of properties such as margins.
135 It's purpose is to allow to reformat the document when the view mode changes (in
136 normal view we cannot allow negative margins; the derrived _lookupMarginProperties()
137 needs to handled that in a meaningful way.
138 */
lookupMarginProperties(void)139 void fl_ContainerLayout::lookupMarginProperties(void)
140 {
141 // first of all, call getAP() which will set default visibility
142 // for us (either visible, or hidden revision)
143
144 // other common properties should come here
145
146 // this should only implement class-specific properties ...
147 const PP_AttrProp* pAP;
148
149 // assert not needed, since _getPropertiesAP() asserts on failure
150 if(!_getPropertiesAP(pAP))
151 return;
152
153 _lookupMarginProperties(pAP);
154 }
155
156
157 /*!
158 retrieves AP associated with this layout, corretly processing any
159 revision information;
160
161 /return return value indicates whether the layout is hidden due to
162 current revision settings or not
163 */
getAP(const PP_AttrProp * & pAP) const164 FPVisibility fl_ContainerLayout::getAP(const PP_AttrProp *& pAP)const
165 {
166 FL_DocLayout* pDL = getDocLayout();
167 UT_return_val_if_fail(pDL,FP_VISIBLE);
168
169 FV_View* pView = pDL->getView();
170 UT_return_val_if_fail(pView,FP_VISIBLE);
171
172 UT_uint32 iId = pView->getRevisionLevel();
173 bool bShow = pView->isShowRevisions();
174 bool bHiddenRevision = false;
175
176 getAttrProp(&pAP,NULL,bShow,iId,bHiddenRevision);
177
178 if(bHiddenRevision)
179 {
180 return FP_HIDDEN_REVISION;
181 }
182 else
183 {
184 return FP_VISIBLE;
185 }
186 }
187
getSpanAP(UT_uint32 blockPos,bool bLeft,const PP_AttrProp * & pSpanAP) const188 void fl_ContainerLayout::getSpanAP(UT_uint32 blockPos, bool bLeft, const PP_AttrProp * &pSpanAP) const
189 {
190 //first we need to ascertain if this revision is visible
191 FL_DocLayout* pDL = getDocLayout();
192 UT_return_if_fail(pDL);
193
194 FV_View* pView = pDL->getView();
195 UT_return_if_fail(pView);
196
197 UT_uint32 iId = pView->getRevisionLevel();
198 bool bShow = pView->isShowRevisions();
199 bool bHiddenRevision = false;
200
201 getSpanAttrProp(blockPos, bLeft, &pSpanAP,NULL,bShow,iId,bHiddenRevision);
202 }
203
204
getContainerString(void)205 const char * fl_ContainerLayout::getContainerString(void)
206 {
207 switch(getContainerType())
208 {
209 case FL_CONTAINER_BLOCK:
210 return "FL_CONTAINER_BLOCK";
211 case FL_CONTAINER_DOCSECTION:
212 return "FL_CONTAINER_DOCSECTION";
213 case FL_CONTAINER_HDRFTR:
214 return "FL_CONTAINER_HDRFTR";
215 case FL_CONTAINER_SHADOW:
216 return "FL_CONTAINER_SHADOW";
217 case FL_CONTAINER_FOOTNOTE:
218 return "FL_CONTAINER_FOOTNOTE";
219 case FL_CONTAINER_ENDNOTE:
220 return "FL_CONTAINER_ENDNOTE";
221 case FL_CONTAINER_MARGINNOTE:
222 return "FL_CONTAINER_MARGINNOTE";
223 case FL_CONTAINER_TABLE:
224 return "FL_CONTAINER_TABLE";
225 case FL_CONTAINER_CELL:
226 return "FL_CONTAINER_CELL";
227 case FL_CONTAINER_FRAME:
228 return "FL_CONTAINER_FRAME";
229 case FL_CONTAINER_TOC:
230 return "FL_CONTAINER_TOC";
231 case FL_CONTAINER_ANNOTATION:
232 return "FL_CONTAINER_ANNOTATION";
233 case FL_CONTAINER_RDFANCHOR:
234 return "FL_CONTAINER_RDFANCHOR";
235 default:
236 return "NOT_IMPLEMENTED";
237 }
238 return "NOT IMPLEMENTED";
239 }
240
241
242
243 /*!
244 * Return the value of the attribute keyed by pszName
245 */
getAttribute(const char * pszName) const246 const char* fl_ContainerLayout::getAttribute(const char * pszName) const
247 {
248 const PP_AttrProp * pAP = NULL;
249 getAP(pAP);
250 UT_return_val_if_fail(pAP, NULL);
251
252 const gchar* pszAtt = NULL;
253 pAP->getAttribute(static_cast<const gchar*>(pszName), pszAtt);
254
255 return pszAtt;
256 }
257
258 /*!
259 * Return the nested List level of this structure.
260 */
getLevelInList(void)261 UT_sint32 fl_ContainerLayout::getLevelInList(void)
262 {
263 fl_BlockLayout * pBList = NULL;
264 if(getContainerType() == FL_CONTAINER_BLOCK)
265 {
266 pBList = static_cast<fl_BlockLayout * >(this);
267 }
268 else
269 {
270 pBList = getPrevBlockInDocument();
271 }
272 UT_sint32 iLevel = 0;
273 bool bLoop = true;
274 while(pBList && bLoop)
275 {
276 while(pBList && !pBList->isListItem())
277 {
278 pBList = pBList->getPrevBlockInDocument();
279 }
280 if(pBList == NULL)
281 {
282 bLoop = false;
283 break;
284 }
285 const PP_AttrProp * pAP = NULL;
286 pBList->getAP(pAP);
287 const gchar * szLid=NULL;
288 UT_uint32 id=0;
289
290 if (!pAP || !pAP->getAttribute(PT_LISTID_ATTRIBUTE_NAME, szLid))
291 szLid = NULL;
292 if (szLid)
293 {
294 id = atoi(szLid);
295
296 }
297 else
298 {
299 id = 0;
300 }
301 if(id == 0)
302 {
303 bLoop = false;
304 break;
305 }
306 PD_Document * pDoc = getDocLayout()->getDocument();
307 fl_AutoNum * pAuto = pDoc->getListByID( id);
308 if(pAuto->getLastItem() == pBList->getStruxDocHandle())
309 {
310 if(pAuto->getLastItem() == getStruxDocHandle())
311 {
312 iLevel = pAuto->getLevel();
313 bLoop = false;
314 break;
315 }
316 iLevel = pAuto->getLevel() -1;
317 if(iLevel < 0)
318 {
319 iLevel = 0;
320 }
321 }
322 else
323 {
324 if(pBList == this)
325 {
326 iLevel = pAuto->getLevel();
327 }
328 else
329 {
330 iLevel = pAuto->getLevel() + 1;
331 }
332 }
333 bLoop = false;
334 break;
335 }
336 return iLevel;
337 }
338 /*!
339 * This method returns the folded level of the text.
340 */
getFoldedLevel(void)341 UT_sint32 fl_ContainerLayout::getFoldedLevel(void)
342 {
343 return m_iFoldedLevel;
344 }
345
346
347 /*!
348 * This method returns the ID of the list that is folded.
349 */
getFoldedID(void)350 UT_uint32 fl_ContainerLayout::getFoldedID(void)
351 {
352 return m_iFoldedID;
353 }
354
355 /*!
356 * This Method looks up the folded level of the strux.
357 */
lookupFoldedLevel(void)358 void fl_ContainerLayout::lookupFoldedLevel(void)
359 {
360 const PP_AttrProp* pSectionAP = NULL;
361
362 getAP(pSectionAP);
363
364 const gchar *pszTEXTFOLDED = NULL;
365 if(!pSectionAP || !pSectionAP->getProperty("text-folded",pszTEXTFOLDED))
366 {
367 m_iFoldedLevel = 0;
368 }
369 else
370 {
371 m_iFoldedLevel = atoi(pszTEXTFOLDED);
372 }
373 xxx_UT_DEBUGMSG(("FOlded Level is %d \n",m_iFoldedLevel));
374 pszTEXTFOLDED = NULL;
375 if(!pSectionAP || !pSectionAP->getProperty("text-folded-id",pszTEXTFOLDED))
376 {
377 m_iFoldedID = 0;
378 }
379 else
380 {
381 m_iFoldedID = atoi(pszTEXTFOLDED);
382 }
383 }
384
385 /*!
386 * This method appends all the text in the current layout to the supplied
387 * GrowBuf.
388 */
appendTextToBuf(UT_GrowBuf & buf) const389 void fl_ContainerLayout::appendTextToBuf(UT_GrowBuf & buf) const
390 {
391 if(getContainerType() == FL_CONTAINER_BLOCK)
392 {
393 const fl_BlockLayout * pBL = static_cast<const fl_BlockLayout *>(this);
394 pBL->appendTextToBuf(buf);
395 return;
396 }
397 const fl_ContainerLayout * pCL = getFirstLayout();
398 while(pCL)
399 {
400 pCL->appendTextToBuf(buf);
401 pCL = pCL->getNext();
402 }
403 }
404
405 /*!
406 * Set the pointer to the next containerLayout given by pL
407 */
setNext(fl_ContainerLayout * pL)408 void fl_ContainerLayout::setNext(fl_ContainerLayout* pL)
409 {
410 m_pNext = pL;
411 }
412
413 /*!
414 * Set the pointer to the previous containerLayout in the linked list
415 * given by pL
416 */
setPrev(fl_ContainerLayout * pL)417 void fl_ContainerLayout::setPrev(fl_ContainerLayout* pL)
418 {
419 m_pPrev = pL;
420 }
421
422 /*!
423 * Return the next fl_ContainerLayout in the linked list.
424 */
getNext(void) const425 fl_ContainerLayout * fl_ContainerLayout::getNext(void) const
426 {
427 return m_pNext;
428 }
429
430 /*!
431 * Return the previous fl_ContainerLayout in the linked list
432 */
getPrev(void) const433 fl_ContainerLayout * fl_ContainerLayout::getPrev(void) const
434 {
435 return m_pPrev;
436 }
437
getDocSectionLayout(void) const438 fl_DocSectionLayout * fl_ContainerLayout::getDocSectionLayout(void) const
439 {
440 fl_ContainerLayout * pCL = myContainingLayout();
441 while(pCL!= NULL && ((pCL->getContainerType() != FL_CONTAINER_DOCSECTION) && (pCL->getContainerType() != FL_CONTAINER_HDRFTR)))
442 {
443 pCL = pCL->myContainingLayout();
444 }
445 if(pCL== NULL)
446 {
447 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
448 return NULL;
449 }
450 fl_DocSectionLayout * pDSL = NULL;
451 if(pCL->getContainerType() == FL_CONTAINER_HDRFTR)
452 {
453 pDSL = static_cast<fl_HdrFtrSectionLayout *>(pCL)->getDocSectionLayout();
454 }
455 else
456 {
457 pDSL = static_cast<fl_DocSectionLayout *>(pCL);
458 }
459 return pDSL;
460 }
461
462 /*!
463 * Return the fl_ContainerLayout that "owns" this. Set to NULL for
464 * fl_DocSectionLayout
465 */
myContainingLayout(void) const466 fl_ContainerLayout * fl_ContainerLayout::myContainingLayout(void) const
467 {
468 return m_pMyLayout;
469 }
470
471 /*!
472 * If this container is contained by a HdrFtrSectionLayout return it.
473 * Otherwise return
474 * NULL.
475 */
getHdrFtrLayout(void)476 fl_HdrFtrSectionLayout * fl_ContainerLayout::getHdrFtrLayout(void)
477 {
478 fl_ContainerLayout * pCL = this;
479 while(pCL && (pCL->getContainerType() != FL_CONTAINER_HDRFTR) &&
480 (pCL->getContainerType() != FL_CONTAINER_DOCSECTION))
481 {
482 pCL = pCL->myContainingLayout();
483 }
484 if(pCL && (pCL->getContainerType() == FL_CONTAINER_HDRFTR))
485 {
486 return static_cast<fl_HdrFtrSectionLayout *>(pCL);
487 }
488 return NULL;
489 }
490
getDocLayout(void) const491 FL_DocLayout* fl_ContainerLayout::getDocLayout(void) const
492 {
493 const fl_ContainerLayout * pMyContainer = static_cast<const fl_ContainerLayout *>(this);
494 while(pMyContainer->getContainerType() != FL_CONTAINER_DOCSECTION && pMyContainer->myContainingLayout())
495 {
496 pMyContainer = pMyContainer->myContainingLayout();
497 }
498 return static_cast<const fl_DocSectionLayout *>(pMyContainer)->getDocLayout();
499 }
500
setContainingLayout(fl_ContainerLayout * pL)501 void fl_ContainerLayout::setContainingLayout(fl_ContainerLayout * pL)
502 {
503 // UT_ASSERT(pL != NULL); // useful for debugging
504 m_pMyLayout = pL;
505 }
506
append(pf_Frag_Strux * sdh,PT_AttrPropIndex indexAP,fl_ContainerType iType)507 fl_ContainerLayout * fl_ContainerLayout::append(pf_Frag_Strux* sdh, PT_AttrPropIndex indexAP,fl_ContainerType iType)
508 {
509 return insert(sdh, m_pLastL, indexAP,iType);
510 }
511
add(fl_ContainerLayout * pL)512 void fl_ContainerLayout::add(fl_ContainerLayout* pL)
513 {
514 if (m_pLastL)
515 {
516 UT_ASSERT(m_pLastL->getNext() == NULL);
517
518 pL->setNext(NULL);
519 pL->setPrev(m_pLastL);
520 m_pLastL->setNext(pL);
521 m_pLastL = pL;
522 }
523 else
524 {
525 UT_ASSERT(!m_pFirstL);
526 UT_DEBUGMSG(("add: doing First = Last = NULL \n"));
527 pL->setNext(NULL);
528 pL->setPrev(NULL);
529 m_pFirstL = pL;
530 m_pLastL = m_pFirstL;
531 }
532 pL->setContainingLayout(this);
533 if(pL->getContainerType() == FL_CONTAINER_BLOCK)
534 {
535 UT_ASSERT(getContainerType() != FL_CONTAINER_BLOCK);
536 static_cast<fl_BlockLayout *>(pL)->setSectionLayout(static_cast<fl_SectionLayout *>(this));
537 }
538 }
539
540
getNextBlockInDocument(void) const541 fl_BlockLayout* fl_ContainerLayout::getNextBlockInDocument(void) const
542 {
543 fl_ContainerLayout * pNext = getNext();
544 if(getContainerType() != FL_CONTAINER_BLOCK)
545 {
546 pNext = getFirstLayout();
547 }
548 fl_ContainerLayout * pOld = NULL;
549 UT_uint32 depth = 0;
550 next_is_null :
551 if(pNext == NULL)
552 {
553 while((pNext == NULL) && ((pOld != NULL) || (depth == 0)))
554 {
555 fl_ContainerLayout * pPrevOld = pOld;
556 if(depth > 0)
557 {
558 pOld = pOld->myContainingLayout();
559 }
560 else
561 {
562 pOld = myContainingLayout();
563 }
564 depth++;
565 if(pOld != NULL) // HdrFtr's have myContainingLayout == NULL
566 {
567 pNext = pOld->getNext();
568 }
569 if(pPrevOld == pOld)
570 {
571 pOld = NULL;
572 }
573 }
574 }
575 while(pNext)
576 {
577 pOld = pNext;
578 if(pNext->getContainerType() == FL_CONTAINER_BLOCK)
579 {
580 return static_cast<fl_BlockLayout *>(pNext);
581 }
582 else if(pNext->getContainerType() == FL_CONTAINER_DOCSECTION)
583 {
584 pNext = pNext->getFirstLayout();
585 }
586 else if(pNext->getContainerType() == FL_CONTAINER_TABLE)
587 {
588 pNext = pNext->getFirstLayout();
589 }
590 else if(pNext->getContainerType() == FL_CONTAINER_FRAME)
591 {
592 if(pNext->getFirstLayout() == NULL)
593 {
594 pNext = pNext->getNext();
595 }
596 else
597 {
598 pNext = pNext->getFirstLayout();
599 }
600 }
601 else if(pNext->getContainerType() == FL_CONTAINER_CELL)
602 {
603 pNext = pNext->getFirstLayout();
604 }
605 else if(pNext->getContainerType() == FL_CONTAINER_TOC)
606 {
607 pNext = pNext->getNext();
608 if(pNext == NULL)
609 {
610 goto next_is_null;
611 }
612 }
613 else if(pNext->getContainerType() == FL_CONTAINER_FOOTNOTE)
614 {
615 pNext = pNext->getNext();
616 if(pNext == NULL)
617 {
618 goto next_is_null;
619 }
620 }
621 else if(pNext->getContainerType() == FL_CONTAINER_ANNOTATION)
622 {
623 pNext = pNext->getNext();
624 if(pNext == NULL)
625 {
626 goto next_is_null;
627 }
628 }
629 else if(pNext->getContainerType() == FL_CONTAINER_RDFANCHOR)
630 {
631 pNext = pNext->getNext();
632 if(pNext == NULL)
633 {
634 goto next_is_null;
635 }
636 }
637 else if(pNext->getContainerType() == FL_CONTAINER_ENDNOTE)
638 {
639 pNext = pNext->getNext();
640 if(pNext == NULL)
641 {
642 goto next_is_null;
643 }
644 }
645 else
646 {
647 pNext = NULL;
648 break;
649 }
650 if(pNext == NULL)
651 {
652 goto next_is_null;
653 }
654 }
655 return NULL;
656 }
657
getPrevBlockInDocument(void) const658 fl_BlockLayout* fl_ContainerLayout::getPrevBlockInDocument(void) const
659 {
660 fl_ContainerLayout * pPrev = getPrev();
661 fl_ContainerLayout * pOld = NULL;
662 UT_uint32 depth = 0;
663 if(pPrev == NULL)
664 {
665 while((pPrev == NULL) && ((pOld != NULL) || (depth == 0)))
666 {
667 fl_ContainerLayout * pPrevOld = pOld;
668 if(depth > 0)
669 {
670 pOld = pOld->myContainingLayout();
671 }
672 else
673 {
674 pOld = myContainingLayout();
675 }
676 depth++;
677 if(pOld != NULL) // HdrFtr's can have NULL myContainingLayout's
678 {
679 pPrev = pOld->getPrev();
680 }
681 if(pPrevOld == pOld )
682 {
683 pOld = NULL;
684 }
685 }
686 }
687 while(pPrev)
688 {
689 pOld = pPrev;
690 if(pPrev->getContainerType() == FL_CONTAINER_BLOCK)
691 {
692 return static_cast<fl_BlockLayout *>(pPrev);
693 }
694 else if(pPrev->getContainerType() == FL_CONTAINER_DOCSECTION)
695 {
696 pPrev = pPrev->getLastLayout();
697 }
698 else if(pPrev->getContainerType() == FL_CONTAINER_FRAME)
699 {
700 if(pPrev->getLastLayout() == NULL)
701 {
702 pPrev = pPrev->getPrev();
703 }
704 else
705 {
706 pPrev = pPrev->getLastLayout();
707 }
708 }
709 else if(pPrev->getContainerType() == FL_CONTAINER_TABLE)
710 {
711 pPrev = pPrev->getLastLayout();
712 }
713 else if(pPrev->getContainerType() == FL_CONTAINER_CELL)
714 {
715 pPrev = pPrev->getLastLayout();
716 }
717 else if(pPrev->getContainerType() == FL_CONTAINER_FOOTNOTE)
718 {
719 pPrev = pPrev->getLastLayout();
720 }
721 else if(pPrev->getContainerType() == FL_CONTAINER_ANNOTATION)
722 {
723 pPrev = pPrev->getLastLayout();
724 }
725 else if(pPrev->getContainerType() == FL_CONTAINER_RDFANCHOR)
726 {
727 pPrev = pPrev->getLastLayout();
728 }
729 else if(pPrev->getContainerType() == FL_CONTAINER_TOC)
730 {
731 pPrev = pPrev->getLastLayout();
732 }
733 else if(pPrev->getContainerType() == FL_CONTAINER_ENDNOTE)
734 {
735 pPrev = pPrev->getLastLayout();
736 }
737 else
738 {
739 pPrev = NULL;
740 break;
741 }
742 if(pPrev == NULL)
743 {
744 if(pOld && pOld->myContainingLayout())
745 {
746 pPrev = pOld->myContainingLayout()->getPrev();
747 }
748 }
749 }
750 return NULL;
751 }
752
753 /*!
754 * Set the pointer to the first Layout in the linked list.
755 */
setFirstLayout(fl_ContainerLayout * pL)756 void fl_ContainerLayout::setFirstLayout(fl_ContainerLayout * pL)
757 {
758 m_pFirstL = pL;
759 }
760
761 /*!
762 * Set the pointer to the last Layout in the linked list.
763 */
setLastLayout(fl_ContainerLayout * pL)764 void fl_ContainerLayout::setLastLayout(fl_ContainerLayout * pL)
765 {
766 m_pLastL = pL;
767 }
768
769 /*!
770 * Return the pointer to the first layout in the structure.
771 */
getFirstLayout(void) const772 fl_ContainerLayout * fl_ContainerLayout::getFirstLayout(void) const
773 {
774 return m_pFirstL;
775 }
776
777 /*!
778 * Return the pointer to the last layout in the structure.
779 */
getLastLayout(void) const780 fl_ContainerLayout * fl_ContainerLayout::getLastLayout(void) const
781 {
782 return m_pLastL;
783 }
784
785
786 /*!
787 * Create a new containerLayout and insert it into the linked list of
788 * layouts held by this class.
789 * Returns a pointer to the generated ContainerLayout class.
790 */
insert(pf_Frag_Strux * sdh,fl_ContainerLayout * pPrev,PT_AttrPropIndex indexAP,fl_ContainerType iType)791 fl_ContainerLayout * fl_ContainerLayout::insert(pf_Frag_Strux* sdh, fl_ContainerLayout * pPrev, PT_AttrPropIndex indexAP,fl_ContainerType iType)
792 {
793 fl_ContainerLayout* pL=NULL;
794 switch (iType)
795 {
796 case FL_CONTAINER_BLOCK:
797 // we have a problem here -- the block needs to be in the list before the consturction is completed
798 if(getContainerType() == FL_CONTAINER_HDRFTR)
799 {
800 pL = static_cast<fl_ContainerLayout *>(new fl_BlockLayout(sdh, pPrev, static_cast<fl_SectionLayout *>(this), indexAP,true));
801 }
802 else if ((pPrev!= NULL) && (pPrev->getContainerType() == FL_CONTAINER_TABLE))
803 {
804 pL = static_cast<fl_ContainerLayout *>(new fl_BlockLayout(sdh,pPrev, static_cast<fl_SectionLayout *>(pPrev->myContainingLayout()), indexAP));
805 }
806 else if ((pPrev!= NULL) && (pPrev->getContainerType() == FL_CONTAINER_ANNOTATION))
807 {
808 pL = static_cast<fl_ContainerLayout *>(new fl_BlockLayout(sdh,pPrev, static_cast<fl_SectionLayout *>(this), indexAP));
809 fp_Container * pFirstC = pL->getFirstContainer();
810 //
811 // This sets indent for a annotation label.
812 //
813 if(pFirstC)
814 pFirstC->recalcMaxWidth(true);
815 }
816 else if ((pPrev!= NULL) && (pPrev->getContainerType() == FL_CONTAINER_RDFANCHOR))
817 {
818 pL = static_cast<fl_ContainerLayout *>(new fl_BlockLayout(sdh,pPrev, static_cast<fl_SectionLayout *>(this), indexAP));
819 }
820 else
821 {
822 pL = static_cast<fl_ContainerLayout *>(new fl_BlockLayout(sdh, static_cast<fl_BlockLayout *>(pPrev), static_cast<fl_SectionLayout *>(this), indexAP));
823 }
824 break;
825 case FL_CONTAINER_TABLE:
826 pL = static_cast<fl_ContainerLayout *>(new fl_TableLayout(getDocLayout(),sdh, indexAP, this));
827 if(pPrev && (pPrev == this))
828 {
829 fl_ContainerLayout * pOldFirst = pPrev->getFirstLayout();
830 pPrev->setFirstLayout(pL);
831 pL->setNext(pOldFirst);
832 if(pOldFirst)
833 {
834 pOldFirst->setPrev(pL);
835 }
836 if(pPrev->getLastLayout() == NULL)
837 {
838 pPrev->setLastLayout(pL);
839 }
840 }
841 else if (pPrev)
842 {
843 pPrev->_insertIntoList(pL);
844 }
845 //
846 // Now put the Physical Container into the vertical container that contains it.
847 //
848 {
849 fp_TableContainer * pTab = static_cast<fp_TableContainer *>(static_cast<fl_TableLayout *>(pL)->getLastContainer());
850 static_cast<fl_TableLayout *>(pL)->insertTableContainer(static_cast<fp_TableContainer *>(pTab));
851 }
852 if(getContainerType() == FL_CONTAINER_CELL)
853 {
854 fl_CellLayout * pCell = static_cast<fl_CellLayout *>(this);
855 pCell->incNumNestedTables();
856 fl_TableLayout * pTab = static_cast<fl_TableLayout *>(pCell->myContainingLayout());
857 pTab->incNumNestedTables();
858 }
859 break;
860 case FL_CONTAINER_CELL:
861 pL = static_cast<fl_ContainerLayout *>(new fl_CellLayout(getDocLayout(),sdh, indexAP, this));
862 if (pPrev)
863 {
864 pPrev->_insertIntoList(pL);
865 }
866 else
867 {
868 _insertFirst(pL);
869 }
870 break;
871 case FL_CONTAINER_FRAME:
872 {
873 pL = static_cast<fl_ContainerLayout *>
874 (new fl_FrameLayout(getDocLayout(),
875 sdh, indexAP, this));
876 if (pPrev)
877 {
878 while(pPrev && pPrev->getContainerType() != FL_CONTAINER_BLOCK)
879 {
880 pPrev = pPrev->getPrev();
881 }
882 //
883 // Add the frame to the list in te previous block.
884 //
885 if(pPrev)
886 {
887 pPrev->_insertIntoList(pL);
888 pPrev->addFrame(static_cast<fl_FrameLayout *>(pL));
889 }
890 }
891 break;
892 }
893 case FL_CONTAINER_FOOTNOTE:
894 {
895 fl_DocSectionLayout * pDSL = getDocSectionLayout();
896 pL = static_cast<fl_ContainerLayout *>(new fl_FootnoteLayout(getDocLayout(),
897 pDSL,
898 sdh, indexAP, this));
899 if (pPrev)
900 pPrev->_insertIntoList(pL);
901 break;
902 }
903 case FL_CONTAINER_ANNOTATION:
904 {
905 fl_DocSectionLayout * pDSL = getDocSectionLayout();
906 pL = static_cast<fl_ContainerLayout *>(new fl_AnnotationLayout(getDocLayout(),
907 pDSL,
908 sdh, indexAP, this));
909 if (pPrev)
910 pPrev->_insertIntoList(pL);
911 break;
912 }
913 case FL_CONTAINER_TOC:
914 {
915 fl_DocSectionLayout * pDSL = getDocSectionLayout();
916 pL = static_cast<fl_ContainerLayout *>(new fl_TOCLayout(getDocLayout(),
917 pDSL,
918 sdh, indexAP, this));
919 if (pPrev)
920 pPrev->_insertIntoList(pL);
921 static_cast<fl_TOCLayout *>(pL)->getNewContainer(NULL);
922 break;
923 }
924 case FL_CONTAINER_ENDNOTE:
925 {
926 fl_DocSectionLayout * pDSL = getDocSectionLayout();
927 pL = static_cast<fl_ContainerLayout *>(new fl_EndnoteLayout(getDocLayout(),
928 pDSL,
929 sdh, indexAP, this));
930 if (pPrev)
931 pPrev->_insertIntoList(pL);
932 break;
933 }
934 default:
935 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
936 break;
937 }
938
939 if (pL == NULL)
940 {
941 return pL;
942 }
943
944 if (!m_pLastL)
945 {
946 UT_ASSERT(!m_pFirstL);
947 m_pFirstL = pL;
948 m_pLastL = pL;
949 }
950 else if (m_pLastL == pPrev)
951 {
952 m_pLastL = pL;
953 }
954 else if (!pPrev)
955 {
956 m_pFirstL = pL;
957 }
958 if(getContainerType() == FL_CONTAINER_CELL)
959 {
960 static_cast<fl_TableLayout *>(myContainingLayout())->setDirty();
961 }
962 return pL;
963 }
964
965 /*!
966 Inserts pL into the containment hierarchy after 'this'.
967 This is actually a general linked list insertion routine.
968 */
_insertIntoList(fl_ContainerLayout * pL)969 void fl_ContainerLayout::_insertIntoList(fl_ContainerLayout * pL)
970 {
971 fl_ContainerLayout * pNext = getNext();
972 setNext(pL);
973
974 pL->setPrev(this);
975 pL->setNext(pNext);
976
977 if(pNext)
978 pNext->setPrev(pL);
979 }
980
981
982 /*!
983 Inserts pL into the containment hierarchy at First Location;
984 */
_insertFirst(fl_ContainerLayout * pL)985 void fl_ContainerLayout::_insertFirst(fl_ContainerLayout * pL)
986 {
987 if(m_pFirstL == NULL)
988 {
989 m_pFirstL = pL;
990 pL->setPrev(NULL);
991 pL->setNext(NULL);
992 m_pLastL = pL;
993 return;
994 }
995 fl_ContainerLayout * pOldFirst = m_pFirstL;
996 m_pFirstL = pL;
997 pL->setNext(pOldFirst);
998 pL->setPrev(NULL);
999 pOldFirst->setPrev(pL);
1000 }
1001
1002 /*!
1003 * Remove a containerLayout class from the linked list held here.
1004 */
remove(fl_ContainerLayout * pL)1005 void fl_ContainerLayout::remove(fl_ContainerLayout * pL)
1006 {
1007 UT_ASSERT(pL);
1008 UT_ASSERT(m_pFirstL);
1009 fl_ContainerLayout* prev = pL->getPrev(); // can be NULL
1010
1011 if (prev)
1012 {
1013 prev->setNext(pL->getNext());
1014 }
1015
1016 if (pL->getNext())
1017 {
1018 pL->getNext()->setPrev(prev);
1019 if(pL->getContainerType() == FL_CONTAINER_BLOCK)
1020 {
1021 UT_ASSERT(getContainerType() != FL_CONTAINER_BLOCK);
1022 static_cast<fl_BlockLayout *>(pL)->transferListFlags();
1023 }
1024 if (pL->getNext()->getContainerType() == FL_CONTAINER_BLOCK)
1025 {
1026 fl_BlockLayout* pBNext = static_cast<fl_BlockLayout *>(pL->getNext());
1027 if (pBNext->hasBorders())
1028 {
1029 pBNext->setLineHeightBlockWithBorders(1);
1030 }
1031 }
1032 if (prev && prev->getContainerType() == FL_CONTAINER_BLOCK)
1033 {
1034 fl_BlockLayout* pBPrev = static_cast<fl_BlockLayout *>(prev);
1035 if (pBPrev->hasBorders())
1036 {
1037 pBPrev->setLineHeightBlockWithBorders(-1);
1038 }
1039 }
1040 }
1041
1042 if (pL == m_pFirstL)
1043 {
1044 m_pFirstL = m_pFirstL->getNext();
1045 if (!m_pFirstL)
1046 {
1047 m_pLastL = NULL;
1048 }
1049 }
1050
1051 if (pL == m_pLastL)
1052 {
1053 m_pLastL = m_pLastL->getPrev();
1054 if (!m_pLastL)
1055 {
1056 m_pFirstL = NULL;
1057 }
1058 }
1059 if(getContainerType() != FL_CONTAINER_BLOCK)
1060 {
1061 fl_SectionLayout * pSL = static_cast<fl_SectionLayout *>(this);
1062 pSL->removeFromUpdate(pL);
1063 }
1064 pL->setNext(NULL);
1065 pL->setPrev(NULL);
1066 pL->setContainingLayout(NULL);
1067 if(pL->getContainerType() == FL_CONTAINER_BLOCK)
1068 {
1069 UT_ASSERT(getContainerType() != FL_CONTAINER_BLOCK);
1070 static_cast<fl_BlockLayout *>(pL)->setSectionLayout(NULL);
1071 }
1072 }
1073
getFirstContainer() const1074 fp_Container* fl_ContainerLayout::getFirstContainer() const
1075 {
1076 return m_pFirstContainer;
1077 }
1078
getLastContainer() const1079 fp_Container* fl_ContainerLayout::getLastContainer() const
1080 {
1081 return m_pLastContainer;
1082 }
1083
setFirstContainer(fp_Container * pCon)1084 void fl_ContainerLayout::setFirstContainer(fp_Container * pCon)
1085 {
1086 if(pCon && getContainerType() == FL_CONTAINER_BLOCK)
1087 {
1088 UT_ASSERT(pCon->getContainerType() == FP_CONTAINER_LINE);
1089 }
1090 xxx_UT_DEBUGMSG(("Set FirstContainer of %x to %x \n",this,pCon));
1091 m_pFirstContainer = pCon;
1092 }
1093
setLastContainer(fp_Container * pCon)1094 void fl_ContainerLayout::setLastContainer(fp_Container * pCon)
1095 {
1096 xxx_UT_DEBUGMSG(("Set LastContainer of %x to %x \n",this,pCon));
1097 m_pLastContainer = pCon;
1098 }
1099
getFirstRun(void) const1100 fp_Run * fl_ContainerLayout::getFirstRun(void) const
1101 {
1102 if(getContainerType() == FL_CONTAINER_BLOCK)
1103 {
1104 const fl_BlockLayout * pBL = static_cast<const fl_BlockLayout *>(this);
1105 return pBL->getFirstRun();
1106 }
1107 else if(getFirstLayout() == NULL)
1108 {
1109 return NULL;
1110 }
1111 return getFirstLayout()->getFirstRun();
1112 }
1113
1114 /*!
1115 Get Container's position in document
1116 \param bActualContainerPos When true return block's position. When false
1117 return position of first run in block
1118 \return Position of Container (or first run in block)
1119 \fixme Split in two functions if called most often with FALSE
1120 */
getPosition(bool bActualBlockPos) const1121 UT_uint32 fl_ContainerLayout::getPosition(bool bActualBlockPos) const
1122 {
1123 const fl_ContainerLayout * pL = this;
1124 if(!bActualBlockPos && (getContainerType() != FL_CONTAINER_TOC))
1125 {
1126 pL = static_cast<fl_ContainerLayout *>(getNextBlockInDocument());
1127 if(pL == NULL)
1128 {
1129 PT_DocPosition pos = getDocLayout()->getDocument()->getStruxPosition(getStruxDocHandle());
1130 return pos;
1131 }
1132 if(pL->getContainerType() == FL_CONTAINER_BLOCK)
1133 {
1134 const fl_BlockLayout * pBL = static_cast<const fl_BlockLayout *>(pL);
1135 return pBL->getPosition(bActualBlockPos);
1136 }
1137 return 0;
1138 }
1139 PT_DocPosition pos = getDocLayout()->getDocument()->getStruxPosition(getStruxDocHandle());
1140 return pos;
1141 }
1142
getHdrFtrSectionLayout(void) const1143 fl_HdrFtrSectionLayout* fl_ContainerLayout::getHdrFtrSectionLayout(void) const
1144 {
1145 if(getContainerType() != FL_CONTAINER_SHADOW)
1146 {
1147 return NULL;
1148 }
1149 const fl_HdrFtrShadow * pHFS = static_cast<const fl_HdrFtrShadow * >(this);
1150 return pHFS->getHdrFtrSectionLayout();
1151 }
1152
canContainPoint() const1153 bool fl_ContainerLayout::canContainPoint() const
1154 {
1155 if(isCollapsed())
1156 return false;
1157
1158 FV_View* pView = getDocLayout()->getView();
1159 bool bShowHidden = pView->getShowPara();
1160
1161 bool bHidden = ((m_eHidden == FP_HIDDEN_TEXT && !bShowHidden)
1162 || m_eHidden == FP_HIDDEN_REVISION
1163 || m_eHidden == FP_HIDDEN_REVISION_AND_TEXT);
1164
1165 if(bHidden)
1166 return false;
1167
1168 if(!_canContainPoint())
1169 return false;
1170
1171 // see if we are not inside a containing layout that cannot contain point
1172 fl_ContainerLayout * pMyLayout = myContainingLayout();
1173
1174 if(!pMyLayout || pMyLayout->getContainerType() == FL_CONTAINER_DOCSECTION)
1175 return true;
1176
1177 return pMyLayout->canContainPoint();
1178 }
1179
isOnScreen() const1180 bool fl_ContainerLayout::isOnScreen() const
1181 {
1182 // we check if any of our containers is on screen
1183 // however, we will not call fp_Container::isOnScreen() to avoid
1184 // unnecessary overhead
1185
1186 if(isCollapsed())
1187 return false;
1188
1189 UT_return_val_if_fail(getDocLayout(),false);
1190
1191 FV_View *pView = getDocLayout()->getView();
1192
1193 bool bShowHidden = pView && pView->getShowPara();
1194
1195 bool bHidden = ((m_eHidden == FP_HIDDEN_TEXT && !bShowHidden)
1196 || m_eHidden == FP_HIDDEN_REVISION
1197 || m_eHidden == FP_HIDDEN_REVISION_AND_TEXT);
1198
1199
1200 if(bHidden)
1201 return false;
1202
1203 UT_GenericVector<UT_Rect*> vRect;
1204 UT_GenericVector<fp_Page*> vPages;
1205
1206 pView->getVisibleDocumentPagesAndRectangles(vRect, vPages);
1207
1208 UT_uint32 iCount = vPages.getItemCount();
1209
1210 if(!iCount)
1211 return false;
1212
1213 bool bRet = false;
1214 fp_Container * pC = getFirstContainer();
1215
1216 if(!pC)
1217 return false;
1218
1219 fp_Container *pCEnd = getLastContainer();
1220
1221 while(pC)
1222 {
1223 fp_Page * pMyPage = pC->getPage();
1224
1225 if(pMyPage)
1226 {
1227 for(UT_uint32 i = 0; i < iCount; i++)
1228 {
1229 fp_Page * pPage = vPages.getNthItem(i);
1230
1231 if(pPage == pMyPage)
1232 {
1233 UT_Rect r;
1234 UT_Rect *pR = vRect.getNthItem(i);
1235
1236 if(!pC->getPageRelativeOffsets(r))
1237 break;
1238
1239 bRet = r.intersectsRect(pR);
1240 break;
1241 }
1242
1243 }
1244 }
1245
1246 if(bRet || pC == pCEnd)
1247 break;
1248
1249 pC = static_cast<fp_Container*>(pC->getNext());
1250 }
1251
1252 UT_VECTOR_PURGEALL(UT_Rect*,vRect);
1253 return bRet;
1254 }
1255
1256 // Frames stuff
1257
addFrame(fl_FrameLayout * pFrame)1258 void fl_ContainerLayout::addFrame(fl_FrameLayout * pFrame)
1259 {
1260 UT_DEBUGMSG(("Adding frame %p to list in container %p \n",pFrame,this));
1261 UT_sint32 i = m_vecFrames.findItem(pFrame);
1262 if(i>= 0)
1263 {
1264 UT_DEBUGMSG(("Adding already existing frame \n"));
1265 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
1266 return;
1267 }
1268 m_vecFrames.addItem(pFrame);
1269 if (!pFrame->getParentContainer())
1270 {
1271 pFrame->setParentContainer(this);
1272 }
1273 else
1274 {
1275 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
1276 }
1277 }
1278
getNumFrames(void) const1279 UT_sint32 fl_ContainerLayout::getNumFrames(void) const
1280 {
1281 return m_vecFrames.getItemCount();
1282 }
1283
getNthFrameLayout(UT_sint32 i) const1284 fl_FrameLayout * fl_ContainerLayout::getNthFrameLayout(UT_sint32 i) const
1285 {
1286 if(i> getNumFrames())
1287 {
1288 return NULL;
1289 }
1290 return m_vecFrames.getNthItem(i);
1291 }
1292
1293
getNthFrameContainer(UT_sint32 i) const1294 fp_FrameContainer * fl_ContainerLayout::getNthFrameContainer(UT_sint32 i) const
1295 {
1296 if(i> getNumFrames())
1297 {
1298 return NULL;
1299 }
1300 fl_FrameLayout * pFrame= m_vecFrames.getNthItem(i);
1301 fp_FrameContainer * pFC = static_cast<fp_FrameContainer *>(pFrame->getFirstContainer());
1302 return pFC;
1303 }
1304
removeFrame(fl_FrameLayout * pFrame)1305 bool fl_ContainerLayout::removeFrame(fl_FrameLayout * pFrame)
1306 {
1307 UT_DEBUGMSG(("Remove Frame %p from this container %p \n",pFrame,this));
1308 UT_sint32 i = m_vecFrames.findItem(pFrame);
1309 if(i >= 0)
1310 {
1311 m_vecFrames.deleteNthItem(i);
1312 if (pFrame->getParentContainer() == this)
1313 {
1314 pFrame->setParentContainer(NULL);
1315 }
1316 return true;
1317 }
1318 else
1319 {
1320 UT_DEBUGMSG((" Requested Frame not found \n"));
1321 return false;
1322 }
1323 }
1324
1325
1326 /* This function returns true if the layout contains a footnote layout and false otherwise.
1327 The function returns false if the layout is contained inside a footnote layout.
1328 TODO TODO TODO: Move embedded layouts out of the main fl_Container lists
1329 */
1330
containsFootnoteLayouts(void) const1331 bool fl_ContainerLayout::containsFootnoteLayouts(void) const
1332 {
1333 if (getEndStruxDocHandle())
1334 {
1335 PT_DocPosition posStart = getDocument()->getStruxPosition(getStruxDocHandle());
1336 PT_DocPosition posEnd = getDocument()->getStruxPosition(getEndStruxDocHandle());
1337 return getDocument()->hasEmbedStruxOfTypeInRange(posStart,posEnd,PTX_SectionFootnote);
1338 }
1339 // This function has not yet been implemented for layouts that do not have a end strux (blocks, sections)
1340 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
1341 return false;
1342 }
1343
1344
1345 /* This function returns true if the layout contains a footnote layout and false otherwise.
1346 The function returns false if the layout is contained inside a footnote layout.
1347 TODO TODO TODO: Move embedded layouts out of the main fl_Container lists
1348 */
1349
containsAnnotationLayouts(void) const1350 bool fl_ContainerLayout::containsAnnotationLayouts(void) const
1351 {
1352 if (getEndStruxDocHandle())
1353 {
1354 PT_DocPosition posStart = getDocument()->getStruxPosition(getStruxDocHandle());
1355 PT_DocPosition posEnd = getDocument()->getStruxPosition(getEndStruxDocHandle());
1356 return getDocument()->hasEmbedStruxOfTypeInRange(posStart,posEnd,PTX_SectionAnnotation);
1357 }
1358 // This function has not yet been implemented for layouts that do not have a end strux (blocks, sections)
1359 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
1360 return false;
1361 }
1362
1363