1 /* AbiWord
2 * Copyright (C) 1998 AbiSource, Inc.
3 * Copyright (C) 2002 Martin Sevior (msevior@physics.unimelb.edu.au>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301 USA.
19 */
20
21 #include <string.h>
22 #include <stdlib.h>
23
24 #include "ut_types.h"
25 #include "ut_string.h"
26
27 #include "ap_Prefs.h"
28 #include "fl_SectionLayout.h"
29 #include "fl_FootnoteLayout.h"
30 #include "fl_Layout.h"
31 #include "fl_DocLayout.h"
32 #include "fl_BlockLayout.h"
33 #include "fb_LineBreaker.h"
34 #include "fp_Page.h"
35 #include "fp_Run.h"
36 #include "fp_Line.h"
37 #include "fp_Column.h"
38 #include "fp_FootnoteContainer.h"
39 #include "fp_ContainerObject.h"
40 #include "pd_Document.h"
41 #include "pp_AttrProp.h"
42 #include "gr_Graphics.h"
43 #include "pp_Property.h"
44 #include "px_ChangeRecord.h"
45 #include "px_CR_Object.h"
46 #include "px_CR_ObjectChange.h"
47 #include "px_CR_Span.h"
48 #include "px_CR_SpanChange.h"
49 #include "px_CR_Strux.h"
50 #include "px_CR_StruxChange.h"
51 #include "px_CR_Glob.h"
52 #include "fp_Run.h"
53 #include "ut_debugmsg.h"
54 #include "ut_assert.h"
55 #include "ut_units.h"
56 #include "fp_TableContainer.h"
57 #include "fv_View.h"
58
fl_EmbedLayout(FL_DocLayout * pLayout,fl_DocSectionLayout * pDocSL,pf_Frag_Strux * sdh,PT_AttrPropIndex indexAP,fl_ContainerLayout * pMyContainerLayout,SectionType iSecType,fl_ContainerType myType,PTStruxType myStruxType)59 fl_EmbedLayout::fl_EmbedLayout(FL_DocLayout* pLayout, fl_DocSectionLayout* pDocSL, pf_Frag_Strux* sdh, PT_AttrPropIndex indexAP, fl_ContainerLayout * pMyContainerLayout, SectionType iSecType,fl_ContainerType myType,PTStruxType myStruxType)
60 : fl_SectionLayout(pLayout, sdh, indexAP, iSecType,myType,myStruxType,pMyContainerLayout),
61 m_bNeedsRebuild(false),
62 m_bNeedsFormat(true),
63 m_bIsOnPage(false),
64 m_pDocSL(pDocSL),
65 m_bHasEndFootnote(false),
66 m_iOldSize(0)
67 {
68 UT_ASSERT(m_pDocSL->getContainerType() == FL_CONTAINER_DOCSECTION);
69 }
70
~fl_EmbedLayout()71 fl_EmbedLayout::~fl_EmbedLayout()
72 {
73 }
74
75 /*!
76 * Returns the position in the document of the PTX_SectionFootnote strux
77 * This is very useful for determining the value of the footnote reference
78 * and anchor.
79 */
getDocPosition(void)80 PT_DocPosition fl_EmbedLayout::getDocPosition(void)
81 {
82 pf_Frag_Strux* sdh = getStruxDocHandle();
83 UT_return_val_if_fail( m_pLayout, 0 );
84 return m_pLayout->getDocument()->getStruxPosition(sdh);
85 }
86
87 /*!
88 * Return the block that contains this Embedded layout
89 */
getContainingBlock(void)90 fl_BlockLayout * fl_EmbedLayout::getContainingBlock(void)
91 {
92 fl_ContainerLayout * pCL = getPrev();
93 while(pCL && pCL->getContainerType() != FL_CONTAINER_BLOCK)
94 {
95 pCL = pCL->getPrev();
96 }
97 if(pCL == NULL)
98 return NULL;
99 fl_BlockLayout * pBL = static_cast<fl_BlockLayout *>(pCL);
100 while(pBL && pBL->getPosition(true) > getDocPosition())
101 pBL = pBL->getPrevBlockInDocument();
102 return pBL;
103 }
104
105 /*!
106 * This method returns the length of the footnote. This is such that
107 * getDocPosition() + getLength() is one value beyond the the EndFootnote
108 * strux
109 */
getLength(void)110 UT_uint32 fl_EmbedLayout::getLength(void)
111 {
112 UT_return_val_if_fail( m_pLayout, 0 );
113 PT_DocPosition startPos = getDocPosition();
114 pf_Frag_Strux* sdhEnd = NULL;
115 pf_Frag_Strux* sdhStart = getStruxDocHandle();
116 UT_DebugOnly<bool> bres;
117 if(getContainerType() == FL_CONTAINER_FOOTNOTE)
118 {
119 bres = m_pLayout->getDocument()->getNextStruxOfType(sdhStart,PTX_EndFootnote,&sdhEnd);
120 UT_ASSERT(bres);
121 }
122 else if(getContainerType() == FL_CONTAINER_ENDNOTE)
123 {
124 bres = m_pLayout->getDocument()->getNextStruxOfType(sdhStart,PTX_EndEndnote,&sdhEnd);
125 UT_ASSERT(bres);
126 }
127 else if(getContainerType() == FL_CONTAINER_ANNOTATION)
128 {
129 bres = m_pLayout->getDocument()->getNextStruxOfType(sdhStart,PTX_EndAnnotation,&sdhEnd);
130 UT_ASSERT(bres);
131 }
132 else
133 {
134 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
135 return 0;
136 }
137 UT_ASSERT(bres && sdhEnd);
138 PT_DocPosition endPos = m_pLayout->getDocument()->getStruxPosition(sdhEnd);
139 UT_uint32 length = static_cast<UT_uint32>(endPos - startPos + 1);
140 return length;
141 }
142
143
bl_doclistener_insertEndEmbed(fl_ContainerLayout *,const PX_ChangeRecord_Strux * pcrx,pf_Frag_Strux * sdh,PL_ListenerId lid,void (* pfnBindHandles)(pf_Frag_Strux * sdhNew,PL_ListenerId lid,fl_ContainerLayout * sfhNew))144 bool fl_EmbedLayout::bl_doclistener_insertEndEmbed(fl_ContainerLayout*,
145 const PX_ChangeRecord_Strux * pcrx,
146 pf_Frag_Strux* sdh,
147 PL_ListenerId lid,
148 void (* pfnBindHandles)(pf_Frag_Strux* sdhNew,
149 PL_ListenerId lid,
150 fl_ContainerLayout* sfhNew))
151 {
152 // The endFootnote strux actually needs a format handle to to this Footnote layout.
153 // so we bind to this layout. We also set a pointer to keep track of the endEmbed strux.
154
155
156 fl_ContainerLayout* sfhNew = this;
157 pfnBindHandles(sdh,lid,sfhNew);
158 setEndStruxDocHandle(sdh);
159
160 //
161 // increment the insertion point in the view.
162 //
163 FV_View* pView = m_pLayout->getView();
164 if (pView && (pView->isActive() || pView->isPreview()))
165 {
166 pView->setPoint(pcrx->getPosition() + fl_BLOCK_STRUX_OFFSET);
167 }
168 else if(pView && pView->getPoint() > pcrx->getPosition())
169 {
170 pView->setPoint(pView->getPoint() + fl_BLOCK_STRUX_OFFSET);
171 }
172 m_bHasEndFootnote = true;
173 fl_BlockLayout * pBL = static_cast<fl_BlockLayout *>(getFirstLayout());
174 pBL->updateEnclosingBlockIfNeeded();
175 return true;
176 }
177
178
179 /*!
180 * This signals an incomplete footnote section.
181 */
doclistener_deleteEndEmbed(const PX_ChangeRecord_Strux *)182 bool fl_EmbedLayout::doclistener_deleteEndEmbed( const PX_ChangeRecord_Strux * /*pcrx*/)
183 {
184 m_bHasEndFootnote = false;
185 return true;
186 }
187
188
getSectionLayout(void) const189 fl_SectionLayout * fl_EmbedLayout::getSectionLayout(void) const
190 {
191 fl_ContainerLayout * pDSL = myContainingLayout();
192 while(pDSL)
193 {
194 if(pDSL->getContainerType() == FL_CONTAINER_DOCSECTION)
195 {
196 return static_cast<fl_SectionLayout *>(pDSL);
197 }
198 pDSL = pDSL->myContainingLayout();
199 }
200 return NULL;
201 }
202
203
doclistener_changeStrux(const PX_ChangeRecord_StruxChange * pcrxc)204 bool fl_EmbedLayout::doclistener_changeStrux(const PX_ChangeRecord_StruxChange * pcrxc)
205 {
206 UT_ASSERT(pcrxc->getType()==PX_ChangeRecord::PXT_ChangeStrux);
207
208
209 setAttrPropIndex(pcrxc->getIndexAP());
210 collapse();
211 return true;
212 }
213
214
recalculateFields(UT_uint32 iUpdateCount)215 bool fl_EmbedLayout::recalculateFields(UT_uint32 iUpdateCount)
216 {
217
218 bool bResult = false;
219 fl_ContainerLayout* pBL = getFirstLayout();
220 while (pBL)
221 {
222 bResult = pBL->recalculateFields(iUpdateCount) || bResult;
223 pBL = pBL->getNext();
224 }
225 return bResult;
226 }
227
228
markAllRunsDirty(void)229 void fl_EmbedLayout::markAllRunsDirty(void)
230 {
231 fl_ContainerLayout* pCL = getFirstLayout();
232 while (pCL)
233 {
234 pCL->markAllRunsDirty();
235 pCL = pCL->getNext();
236 }
237 }
238
updateLayout(void)239 void fl_EmbedLayout::updateLayout(void)
240 {
241 if(needsReformat())
242 {
243 format();
244 }
245 m_vecFormatLayout.clear();
246 fl_ContainerLayout* pBL = getFirstLayout();
247 while (pBL)
248 {
249 if (pBL->needsReformat())
250 {
251 pBL->format();
252 }
253
254 pBL = pBL->getNext();
255 }
256 }
257
redrawUpdate(void)258 void fl_EmbedLayout::redrawUpdate(void)
259 {
260 fl_ContainerLayout* pBL = getFirstLayout();
261 while (pBL)
262 {
263 if (pBL->needsRedraw())
264 {
265 pBL->redrawUpdate();
266 }
267
268 pBL = pBL->getNext();
269 }
270 }
271
setNeedsReformat(fl_ContainerLayout *,UT_uint32)272 void fl_EmbedLayout::setNeedsReformat(fl_ContainerLayout * /*pCL*/, UT_uint32 /*offset*/)
273 {
274 m_bNeedsReformat = true;
275 if(getSectionLayout())
276 getSectionLayout()->setNeedsReformat(this);
277 }
278
updateLayout(bool)279 void fl_EmbedLayout::updateLayout(bool /*bDoAll*/)
280 {
281 fl_ContainerLayout * pBL = getFirstLayout();
282 while(pBL)
283 {
284 pBL->format();
285 pBL = pBL->getNext();
286 }
287 }
288
doclistener_deleteStrux(const PX_ChangeRecord_Strux * pcrx)289 bool fl_EmbedLayout::doclistener_deleteStrux(const PX_ChangeRecord_Strux * pcrx)
290 {
291 UT_ASSERT(pcrx->getType()==PX_ChangeRecord::PXT_DeleteStrux);
292 // Move cursor to its new position
293 m_pLayout->getView()->setPoint(pcrx->getPosition());
294 //
295 // Remove all remaining structures
296 //
297 if(getPrev())
298 {
299 getPrev()->setNeedsReformat(getPrev());
300 }
301 collapse();
302 // UT_ASSERT(pcrx->getStruxType()== PTX_SectionFootnote);
303 //
304 // Find the block that contains this layout.
305 //
306 PT_DocPosition prevPos = pcrx->getPosition();
307 fl_BlockLayout * pEncBlock = m_pLayout->findBlockAtPosition(prevPos);
308 //
309 // Fix the offsets for the block
310 //
311 m_bHasEndFootnote = false;
312 pEncBlock->updateOffsets(prevPos,0,-getOldSize());
313 getSectionLayout()->remove(this);
314 delete this; // TODO whoa! this construct is VERY dangerous.
315
316 return true;
317 }
318
319
320 /*!
321 * This method removes all layout structures contained by this layout
322 * structure.
323 */
_purgeLayout(void)324 void fl_EmbedLayout::_purgeLayout(void)
325 {
326 xxx_UT_DEBUGMSG(("embedLayout: purge \n"));
327 fl_ContainerLayout * pCL = getFirstLayout();
328 while(pCL)
329 {
330 fl_ContainerLayout * pNext = pCL->getNext();
331 delete pCL;
332 pCL = pNext;
333 }
334 }
335
336 /************************************************************************/
337
fl_FootnoteLayout(FL_DocLayout * pLayout,fl_DocSectionLayout * pDocSL,pf_Frag_Strux * sdh,PT_AttrPropIndex indexAP,fl_ContainerLayout * pMyContainerLayout)338 fl_FootnoteLayout::fl_FootnoteLayout(FL_DocLayout* pLayout,
339 fl_DocSectionLayout* pDocSL,
340 pf_Frag_Strux* sdh,
341 PT_AttrPropIndex indexAP,
342 fl_ContainerLayout * pMyContainerLayout)
343 : fl_EmbedLayout(pLayout,
344 pDocSL,
345 sdh,
346 indexAP,
347 pMyContainerLayout,
348 FL_SECTION_FOOTNOTE,
349 FL_CONTAINER_FOOTNOTE,
350 PTX_SectionFootnote),
351 m_iFootnotePID(0)
352 {
353 m_pLayout->addFootnote(this);
354 _createFootnoteContainer();
355 }
356
~fl_FootnoteLayout()357 fl_FootnoteLayout::~fl_FootnoteLayout()
358 {
359 // NB: be careful about the order of these
360 xxx_UT_DEBUGMSG(("Deleting Footlayout %x \n",this));
361 _purgeLayout();
362 fp_FootnoteContainer * pFC = static_cast<fp_FootnoteContainer *>(getFirstContainer());
363 while(pFC)
364 {
365 fp_FootnoteContainer * pNext = static_cast<fp_FootnoteContainer *>(pFC->getNext());
366 if(pFC == static_cast<fp_FootnoteContainer *>(getLastContainer()))
367 {
368 pNext = NULL;
369 }
370 delete pFC;
371 pFC = pNext;
372 }
373
374 setFirstContainer(NULL);
375 setLastContainer(NULL);
376
377 UT_return_if_fail( m_pLayout );
378 m_pLayout->removeFootnote(this);
379 }
380
381 /*!
382 * This method creates a new footnote with its properties initially set
383 * from the Attributes/properties of this Layout
384 */
_createFootnoteContainer(void)385 void fl_FootnoteLayout::_createFootnoteContainer(void)
386 {
387 lookupProperties();
388 fp_FootnoteContainer * pFootnoteContainer = new fp_FootnoteContainer(static_cast<fl_SectionLayout *>(this));
389 setFirstContainer(pFootnoteContainer);
390 setLastContainer(pFootnoteContainer);
391 fl_ContainerLayout * pCL = myContainingLayout();
392 while(pCL!= NULL && pCL->getContainerType() != FL_CONTAINER_DOCSECTION)
393 {
394 pCL = pCL->myContainingLayout();
395 }
396 fl_DocSectionLayout * pDSL = static_cast<fl_DocSectionLayout *>(pCL);
397 UT_return_if_fail(pDSL != NULL);
398
399 fp_Container * pCon = pCL->getLastContainer();
400 UT_return_if_fail(pCon);
401 UT_sint32 iWidth = pCon->getPage()->getWidth();
402 iWidth = iWidth - pDSL->getLeftMargin() - pDSL->getRightMargin();
403 pFootnoteContainer->setWidth(iWidth);
404 }
405
406 /*!
407 Create a new Footnote container.
408 \param If pPrevFootnote is non-null place the new cell after this in the linked
409 list, otherwise just append it to the end.
410 \return The newly created Footnote container
411 */
getNewContainer(fp_Container *)412 fp_Container* fl_FootnoteLayout::getNewContainer(fp_Container *)
413 {
414 UT_DEBUGMSG(("PLAM: creating new footnote container\n"));
415 _createFootnoteContainer();
416 m_bIsOnPage = false;
417 return static_cast<fp_Container *>(getLastContainer());
418 }
419
_insertFootnoteContainer(fp_Container * pNewFC)420 void fl_FootnoteLayout::_insertFootnoteContainer(fp_Container * pNewFC)
421 {
422 UT_DEBUGMSG(("inserting footnote container into container list\n"));
423 fl_ContainerLayout * pUPCL = myContainingLayout();
424 fl_ContainerLayout * pPrevL = static_cast<fl_ContainerLayout *>(m_pLayout->findBlockAtPosition(getDocPosition()-1));
425 fp_Container * pPrevCon = NULL;
426 fp_Container * pUpCon = NULL;
427 fp_Page * pPage = NULL;
428
429 // get the owning container
430 if(pPrevL != NULL)
431 {
432 pPrevCon = pPrevL->getLastContainer();
433 if(pPrevL->getContainerType() == FL_CONTAINER_BLOCK)
434 {
435 //
436 // Code to find the Line that contains the footnote reference
437 //
438 PT_DocPosition posFL = getDocPosition() - 1;
439 UT_ASSERT(pPrevL->getContainerType() == FL_CONTAINER_BLOCK);
440 fl_BlockLayout * pBL = static_cast<fl_BlockLayout *>(pPrevL);
441 fp_Run * pRun = pBL->getFirstRun();
442 PT_DocPosition posBL = pBL->getPosition();
443 while(pRun && ((posBL + pRun->getBlockOffset() + pRun->getLength()) < posFL))
444 {
445 pRun = pRun->getNextRun();
446 }
447 if(pRun && pRun->getLine())
448 {
449 pPrevCon = static_cast<fp_Container *>(pRun->getLine());
450 }
451 }
452 if(pPrevCon == NULL)
453 {
454 pPrevCon = pPrevL->getLastContainer();
455 }
456 pUpCon = pPrevCon->getContainer();
457 }
458 else
459 {
460 pUpCon = pUPCL->getLastContainer();
461 }
462 if(pPrevCon)
463 {
464 pPage = pPrevCon->getPage();
465 }
466 else
467 {
468 pPage = pUpCon->getPage();
469 }
470 pNewFC->setContainer(NULL);
471
472 // need to put onto page as well, in the appropriate place.
473 // UT_ASSERT(pPage);
474 if(pPage)
475 {
476 pPage->insertFootnoteContainer(static_cast<fp_FootnoteContainer*>(pNewFC));
477 m_bIsOnPage = true;
478 }
479 }
480
481
format(void)482 void fl_FootnoteLayout::format(void)
483 {
484 xxx_UT_DEBUGMSG(("SEVIOR: Formatting first container is %x \n",getFirstContainer()));
485 if(getFirstContainer() == NULL)
486 {
487 getNewContainer();
488 }
489 if(!m_bIsOnPage)
490 {
491 _insertFootnoteContainer(getFirstContainer());
492 }
493 fl_ContainerLayout* pBL = getFirstLayout();
494
495 while (pBL)
496 {
497 pBL->format();
498 UT_sint32 count = 0;
499 while(pBL->getLastContainer() == NULL || pBL->getFirstContainer()==NULL)
500 {
501 UT_DEBUGMSG(("Error formatting a block try again \n"));
502 count = count + 1;
503 pBL->format();
504 if(count > 3)
505 {
506 UT_DEBUGMSG(("Give up trying to format. Hope for the best :-( \n"));
507 break;
508 }
509 }
510 pBL = pBL->getNext();
511 }
512 static_cast<fp_FootnoteContainer *>(getFirstContainer())->layout();
513 m_bNeedsFormat = false;
514 m_bNeedsReformat = false;
515 }
516
517
518 /*!
519 this function is only to be called by fl_ContainerLayout::lookupProperties()
520 all other code must call lookupProperties() instead
521 */
_lookupProperties(const PP_AttrProp * pSectionAP)522 void fl_FootnoteLayout::_lookupProperties(const PP_AttrProp* pSectionAP)
523 {
524 UT_return_if_fail(pSectionAP);
525 // I can't think of any properties we need for now.
526 // If we need any later, we'll add them. -PL
527 const gchar *pszFootnotePID = NULL;
528 if(!pSectionAP->getAttribute("footnote-id",pszFootnotePID))
529 {
530 m_iFootnotePID = 0;
531 }
532 else
533 {
534 m_iFootnotePID = atoi(pszFootnotePID);
535 }
536 }
537
_localCollapse(void)538 void fl_FootnoteLayout::_localCollapse(void)
539 {
540 // ClearScreen on our Cell. One Cell per layout.
541 fp_FootnoteContainer *pFC = static_cast<fp_FootnoteContainer *>(getFirstContainer());
542 if (pFC)
543 {
544 pFC->clearScreen();
545 }
546
547 // get rid of all the layout information for every containerLayout
548 fl_ContainerLayout* pCL = getFirstLayout();
549 while (pCL)
550 {
551 pCL->collapse();
552 pCL = pCL->getNext();
553 }
554 m_bNeedsReformat = true;
555 }
556
collapse(void)557 void fl_FootnoteLayout::collapse(void)
558 {
559 _localCollapse();
560 fp_FootnoteContainer *pFC = static_cast<fp_FootnoteContainer *>(getFirstContainer());
561 if (pFC)
562 {
563 //
564 // Remove it from the page.
565 //
566 if(pFC->getPage())
567 {
568 pFC->getPage()->removeFootnoteContainer(pFC);
569 pFC->setPage(NULL);
570 }
571 //
572 // remove it from the linked list.
573 //
574 fp_FootnoteContainer * pPrev = static_cast<fp_FootnoteContainer *>(pFC->getPrev());
575 if(pPrev)
576 {
577 pPrev->setNext(pFC->getNext());
578 }
579 if(pFC->getNext())
580 {
581 pFC->getNext()->setPrev(pPrev);
582 }
583 delete pFC;
584 }
585 setFirstContainer(NULL);
586 setLastContainer(NULL);
587 }
588
589 /************************************************************************/
590
fl_AnnotationLayout(FL_DocLayout * pLayout,fl_DocSectionLayout * pDocSL,pf_Frag_Strux * sdh,PT_AttrPropIndex indexAP,fl_ContainerLayout * pMyContainerLayout)591 fl_AnnotationLayout::fl_AnnotationLayout(FL_DocLayout* pLayout,
592 fl_DocSectionLayout* pDocSL,
593 pf_Frag_Strux* sdh,
594 PT_AttrPropIndex indexAP,
595 fl_ContainerLayout * pMyContainerLayout)
596 : fl_EmbedLayout(pLayout,
597 pDocSL,
598 sdh,
599 indexAP,
600 pMyContainerLayout,
601 FL_SECTION_ANNOTATION,
602 FL_CONTAINER_ANNOTATION,
603 PTX_SectionAnnotation),
604 m_iAnnotationPID(0)
605 {
606 m_pLayout->addAnnotation(this);
607 _createAnnotationContainer();
608 }
609
~fl_AnnotationLayout()610 fl_AnnotationLayout::~fl_AnnotationLayout()
611 {
612 // NB: be careful about the order of these
613 UT_DEBUGMSG(("Deleting Annotationlayout %p \n",this));
614 _purgeLayout();
615 fp_AnnotationContainer * pAC = static_cast<fp_AnnotationContainer *>(getFirstContainer());
616 while(pAC)
617 {
618 fp_AnnotationContainer * pNext = static_cast<fp_AnnotationContainer *>(pAC->getNext());
619 if(pAC == static_cast<fp_AnnotationContainer *>(getLastContainer()))
620 {
621 pNext = NULL;
622 }
623 delete pAC;
624 pAC = pNext;
625 }
626
627 setFirstContainer(NULL);
628 setLastContainer(NULL);
629
630 UT_return_if_fail( m_pLayout );
631 m_pLayout->removeAnnotation(this);
632 }
633
634 /*!
635 * This method creates a new footnote with its properties initially set
636 * from the Attributes/properties of this Layout
637 */
_createAnnotationContainer(void)638 void fl_AnnotationLayout::_createAnnotationContainer(void)
639 {
640 lookupProperties();
641 fp_AnnotationContainer * pAnnotationContainer = new fp_AnnotationContainer(static_cast<fl_SectionLayout *>(this));
642 setFirstContainer(pAnnotationContainer);
643 setLastContainer(pAnnotationContainer);
644 fl_ContainerLayout * pCL = myContainingLayout();
645 while(pCL!= NULL && pCL->getContainerType() != FL_CONTAINER_DOCSECTION)
646 {
647 pCL = pCL->myContainingLayout();
648 }
649 fl_DocSectionLayout * pDSL = static_cast<fl_DocSectionLayout *>(pCL);
650 UT_return_if_fail(pDSL != NULL);
651
652 fp_Container * pCon = pCL->getLastContainer();
653 UT_return_if_fail(pCon);
654 UT_sint32 iWidth = pCon->getPage()->getWidth();
655 iWidth = iWidth - pDSL->getLeftMargin() - pDSL->getRightMargin();
656 pAnnotationContainer->setWidth(iWidth);
657 }
658
659 /*!
660 Create a new Annotation container.
661 \param If pPrevAnnotation is non-null place the new cell after this in the linked
662 list, otherwise just append it to the end.
663 \return The newly created Annotation container
664 */
getNewContainer(fp_Container *)665 fp_Container* fl_AnnotationLayout::getNewContainer(fp_Container *)
666 {
667 UT_DEBUGMSG(("Creating new Annotation container\n"));
668 _createAnnotationContainer();
669 m_bIsOnPage = false;
670 return static_cast<fp_Container *>(getLastContainer());
671 }
672
_insertAnnotationContainer(fp_Container * pNewAC)673 void fl_AnnotationLayout::_insertAnnotationContainer(fp_Container * pNewAC)
674 {
675 UT_DEBUGMSG(("inserting annotation container into container list\n"));
676 fl_ContainerLayout * pUPCL = myContainingLayout();
677 fl_ContainerLayout * pPrevL = static_cast<fl_ContainerLayout *>(m_pLayout->findBlockAtPosition(getDocPosition()-1));
678 fp_Container * pPrevCon = NULL;
679 fp_Container * pUpCon = NULL;
680 fp_Page * pPage = NULL;
681
682 // get the owning container
683 if(pPrevL != NULL)
684 {
685 pPrevCon = pPrevL->getLastContainer();
686 if(pPrevL->getContainerType() == FL_CONTAINER_BLOCK)
687 {
688 //
689 // Code to find the Line that contains the Annotation reference
690 //
691 PT_DocPosition posFL = getDocPosition() - 1;
692 UT_ASSERT(pPrevL->getContainerType() == FL_CONTAINER_BLOCK);
693 fl_BlockLayout * pBL = static_cast<fl_BlockLayout *>(pPrevL);
694 fp_Run * pRun = pBL->getFirstRun();
695 PT_DocPosition posBL = pBL->getPosition();
696 while(pRun && ((posBL + pRun->getBlockOffset() + pRun->getLength()) < posFL))
697 {
698 pRun = pRun->getNextRun();
699 }
700 if(pRun && pRun->getLine())
701 {
702 pPrevCon = static_cast<fp_Container *>(pRun->getLine());
703 }
704 }
705 if(pPrevCon == NULL)
706 {
707 pPrevCon = pPrevL->getLastContainer();
708 }
709 pUpCon = pPrevCon->getContainer();
710 }
711 else
712 {
713 pUpCon = pUPCL->getLastContainer();
714 }
715 if(pPrevCon)
716 {
717 pPage = pPrevCon->getPage();
718 }
719 else
720 {
721 pPage = pUpCon->getPage();
722 }
723 pNewAC->setContainer(NULL);
724
725 // need to put onto page as well, in the appropriate place.
726 UT_ASSERT(pPage);
727
728 if(pPage)
729 {
730 pPage->insertAnnotationContainer(static_cast<fp_AnnotationContainer*>(pNewAC));
731 m_bIsOnPage = true;
732 }
733 }
734
735
format(void)736 void fl_AnnotationLayout::format(void)
737 {
738 UT_DEBUGMSG(("SEVIOR: Formatting Annotations first container is %p\n", getFirstContainer()));
739 if(getFirstContainer() == NULL)
740 {
741 getNewContainer();
742 }
743 if(!m_bIsOnPage)
744 {
745 _insertAnnotationContainer(getFirstContainer());
746 }
747 fl_ContainerLayout* pBL = getFirstLayout();
748
749 while (pBL)
750 {
751 pBL->format();
752 UT_sint32 count = 0;
753 while(pBL->getLastContainer() == NULL || pBL->getFirstContainer()==NULL)
754 {
755 UT_DEBUGMSG(("Error formatting a block try again \n"));
756 count = count + 1;
757 pBL->format();
758 if(count > 3)
759 {
760 UT_DEBUGMSG(("Give up trying to format. Hope for the best :-( \n"));
761 break;
762 }
763 }
764 pBL = pBL->getNext();
765 }
766 static_cast<fp_AnnotationContainer *>(getFirstContainer())->layout();
767 m_bNeedsFormat = false;
768 m_bNeedsReformat = false;
769 }
770
771
772 /*!
773 this function is only to be called by fl_ContainerLayout::lookupProperties()
774 all other code must call lookupProperties() instead
775 */
_lookupProperties(const PP_AttrProp * pSectionAP)776 void fl_AnnotationLayout::_lookupProperties(const PP_AttrProp* pSectionAP)
777 {
778 UT_return_if_fail(pSectionAP);
779 // I can't think of any properties we need for now.
780 // If we need any later, we'll add them. -PL
781 const gchar *pszAnnotationPID = NULL;
782 if(!pSectionAP->getAttribute("annotation-id",pszAnnotationPID))
783 {
784 m_iAnnotationPID = 0;
785 }
786 else
787 {
788 m_iAnnotationPID = atoi(pszAnnotationPID);
789 }
790 const char* pszAuthor;
791 const char* pszTitle;
792 const char *pszDate;
793 if(!pSectionAP->getProperty("annotation-author", (const char *&)pszAuthor))
794 {
795 pszAuthor = "";
796 }
797 m_sAuthor = pszAuthor;
798 if(!pSectionAP->getProperty("annotation-title", (const char *&)pszTitle))
799 {
800 pszTitle = "";
801 }
802 m_sTitle = pszTitle;
803 if(!pSectionAP->getProperty("annotation-date", (const char *&)pszDate))
804 {
805 pszDate = "";
806 }
807 m_sDate = pszDate;
808 UT_DEBUGMSG(("Annotation _lookupProps Author|%s| Title |%s| \n", m_sAuthor.utf8_str(),m_sTitle.utf8_str()));
809 }
810
_localCollapse(void)811 void fl_AnnotationLayout::_localCollapse(void)
812 {
813 // ClearScreen on our Cell. One Cell per layout.
814 fp_AnnotationContainer *pAC = static_cast<fp_AnnotationContainer *>(getFirstContainer());
815 if (pAC)
816 {
817 pAC->clearScreen();
818 }
819
820 // get rid of all the layout information for every containerLayout
821 fl_ContainerLayout* pCL = getFirstLayout();
822 while (pCL)
823 {
824 pCL->collapse();
825 pCL = pCL->getNext();
826 }
827 m_bNeedsReformat = true;
828 }
829
getAnnotationRun(void)830 fp_AnnotationRun * fl_AnnotationLayout::getAnnotationRun(void)
831 {
832 PT_DocPosition posFL = getDocPosition() - 1;
833 fl_ContainerLayout * pPrevL = static_cast<fl_ContainerLayout *>(m_pLayout->findBlockAtPosition(posFL));
834
835 // get the owning container
836 if(pPrevL != NULL)
837 {
838 if(pPrevL->getContainerType() == FL_CONTAINER_BLOCK)
839 {
840 //
841 // Code to find the Line that contains the Annotation reference
842 //
843 UT_ASSERT(pPrevL->getContainerType() == FL_CONTAINER_BLOCK);
844 fl_BlockLayout * pBL = static_cast<fl_BlockLayout *>(pPrevL);
845 fp_Run * pRun = pBL->getFirstRun();
846 PT_DocPosition posBL = pBL->getPosition();
847 while(pRun && ((posBL + pRun->getBlockOffset() + pRun->getLength()) <= posFL))
848 {
849 pRun = pRun->getNextRun();
850 }
851 if(pRun && (pRun->getType() == FPRUN_HYPERLINK))
852 {
853 fp_HyperlinkRun * pHRun = static_cast<fp_HyperlinkRun *>(pRun);
854 if(pHRun->getHyperlinkType() == HYPERLINK_ANNOTATION)
855 {
856 fp_AnnotationRun * pARun = static_cast<fp_AnnotationRun * >(pHRun);
857 if(pARun->getPID() == getAnnotationPID())
858 {
859 return pARun;
860 }
861 }
862 }
863 else
864 {
865 return NULL;
866 }
867 }
868 else
869 {
870 return NULL;
871 }
872 }
873 return NULL;
874 }
875
876
collapse(void)877 void fl_AnnotationLayout::collapse(void)
878 {
879 _localCollapse();
880 fp_AnnotationContainer *pAC = static_cast<fp_AnnotationContainer *>(getFirstContainer());
881 if (pAC)
882 {
883 //
884 // Remove it from the page.
885 //
886 if(pAC->getPage())
887 {
888 pAC->getPage()->removeAnnotationContainer(pAC);
889 pAC->setPage(NULL);
890 }
891 //
892 // remove it from the linked list.
893 //
894 fp_AnnotationContainer * pPrev = static_cast<fp_AnnotationContainer *>(pAC->getPrev());
895 if(pPrev)
896 {
897 pPrev->setNext(pAC->getNext());
898 }
899 if(pAC->getNext())
900 {
901 pAC->getNext()->setPrev(pPrev);
902 }
903 delete pAC;
904 }
905 setFirstContainer(NULL);
906 setLastContainer(NULL);
907 m_bIsOnPage = false;
908 }
909
910
911
912 /************************************************************************/
913
fl_EndnoteLayout(FL_DocLayout * pLayout,fl_DocSectionLayout * pDocSL,pf_Frag_Strux * sdh,PT_AttrPropIndex indexAP,fl_ContainerLayout * pMyContainerLayout)914 fl_EndnoteLayout::fl_EndnoteLayout(FL_DocLayout* pLayout,
915 fl_DocSectionLayout* pDocSL,
916 pf_Frag_Strux* sdh,
917 PT_AttrPropIndex indexAP,
918 fl_ContainerLayout * pMyContainerLayout)
919 : fl_EmbedLayout(pLayout,
920 pDocSL,
921 sdh,
922 indexAP,
923 pMyContainerLayout,
924 FL_SECTION_ENDNOTE,
925 FL_CONTAINER_ENDNOTE,
926 PTX_SectionEndnote),
927 m_iEndnotePID(0)
928 {
929 UT_DEBUGMSG(("Create Endnote section %p from pos %d \n",this,getPosition()));
930 m_pLayout->addEndnote(this);
931 UT_DEBUGMSG(("myContaining Layout %s \n",myContainingLayout()->getContainerString()));
932 _createEndnoteContainer();
933 }
934
~fl_EndnoteLayout()935 fl_EndnoteLayout::~fl_EndnoteLayout()
936 {
937 // NB: be careful about the order of these
938 xxx_UT_DEBUGMSG(("Deleting Endlayout %x \n",this));
939 _purgeLayout();
940 fp_EndnoteContainer * pEC = static_cast<fp_EndnoteContainer *>(getFirstContainer());
941 while(pEC)
942 {
943 fp_EndnoteContainer * pNext = static_cast<fp_EndnoteContainer *>(pEC->getNext());
944 if(pEC == static_cast<fp_EndnoteContainer *>(getLastContainer()))
945 {
946 pNext = NULL;
947 }
948 m_pLayout->removeEndnoteContainer(pEC);
949 delete pEC;
950 pEC = pNext;
951 }
952
953 setFirstContainer(NULL);
954 setLastContainer(NULL);
955 m_pLayout->removeEndnote(this);
956 }
957
958 /*!
959 * This method creates a new footnote with its properties initially set
960 * from the Attributes/properties of this Layout
961 */
_createEndnoteContainer(void)962 void fl_EndnoteLayout::_createEndnoteContainer(void)
963 {
964 lookupProperties();
965 fp_EndnoteContainer * pEndnoteContainer = new fp_EndnoteContainer(static_cast<fl_SectionLayout *>(this));
966 setFirstContainer(pEndnoteContainer);
967 setLastContainer(pEndnoteContainer);
968 fl_DocSectionLayout * pDSL = m_pLayout->getDocSecForEndnote(pEndnoteContainer);
969 UT_sint32 iWidth = m_pLayout->getLastPage()->getWidth();
970 iWidth = iWidth - pDSL->getLeftMargin() - pDSL->getRightMargin();
971 pEndnoteContainer->setWidth(iWidth);
972 m_bNeedsReformat = true;
973 m_bNeedsFormat = true;
974 }
975
976
_localCollapse(void)977 void fl_EndnoteLayout::_localCollapse(void)
978 {
979 // ClearScreen on our Cell. One Cell per layout.
980 fp_EndnoteContainer *pFC = static_cast<fp_EndnoteContainer *>(getFirstContainer());
981 UT_DEBUGMSG(("fl_endnote: _localCollapse First Container %p \n",pFC));
982 if (pFC)
983 {
984 pFC->clearScreen();
985 }
986
987 // get rid of all the layout information for every containerLayout
988 fl_ContainerLayout* pCL = getFirstLayout();
989 while (pCL)
990 {
991 pCL->collapse();
992 pCL = pCL->getNext();
993 }
994 m_bNeedsReformat = true;
995 }
996
collapse(void)997 void fl_EndnoteLayout::collapse(void)
998 {
999 UT_DEBUGMSG(("Collapsing Endnote %p \n",this));
1000 _localCollapse();
1001 fp_EndnoteContainer *pFC = static_cast<fp_EndnoteContainer *>(getFirstContainer());
1002 while(pFC)
1003 {
1004 fp_EndnoteContainer *pNext = static_cast<fp_EndnoteContainer *>(pFC->getLocalNext());
1005 m_pLayout->removeEndnoteContainer(pFC);
1006 fp_EndnoteContainer * pPrev = static_cast<fp_EndnoteContainer *>(pFC->getPrev());
1007 if(pPrev)
1008 {
1009 pPrev->setNext(pFC->getNext());
1010 }
1011 if(pFC->getNext())
1012 {
1013 pFC->getNext()->setPrev(pPrev);
1014 }
1015 delete pFC;
1016 pFC = pNext;
1017 }
1018 setFirstContainer(NULL);
1019 setLastContainer(NULL);
1020 m_bIsOnPage = false;
1021 }
1022
1023
format(void)1024 void fl_EndnoteLayout::format(void)
1025 {
1026 UT_DEBUGMSG(("SEVIOR: Formatting Endnote first container is %p \n",getFirstContainer()));
1027 if(getFirstContainer() == NULL)
1028 {
1029 getNewContainer();
1030 }
1031 if(!m_bIsOnPage)
1032 {
1033 _insertEndnoteContainer(getFirstContainer());
1034 }
1035 fl_ContainerLayout* pBL = getFirstLayout();
1036 while (pBL)
1037 {
1038 pBL->format();
1039 UT_sint32 count = 0;
1040 while(pBL->getLastContainer() == NULL || pBL->getFirstContainer()==NULL)
1041 {
1042 UT_DEBUGMSG(("Error formatting a block try again \n"));
1043 count = count + 1;
1044 pBL->format();
1045 if(count > 3)
1046 {
1047 UT_DEBUGMSG(("Give up trying to format. Hope for the best :-( \n"));
1048 break;
1049 }
1050 }
1051 pBL = pBL->getNext();
1052 }
1053 static_cast<fp_EndnoteContainer *>(getFirstContainer())->layout();
1054 m_bNeedsFormat = false;
1055 m_bNeedsReformat = false;
1056 bool bOnPage = (getFirstContainer()->getPage() != NULL);
1057 FV_View * pView = NULL;
1058 if(m_pLayout)
1059 pView = m_pLayout->getView();
1060 if(bOnPage && pView && !pView->isLayoutFilling())
1061 {
1062 getDocSectionLayout()->setNeedsSectionBreak(true,NULL);
1063 }
1064 UT_ASSERT(getFirstContainer()->getPage());
1065 }
1066
1067
1068 /*!
1069 this function is only to be called by fl_ContainerLayout::lookupProperties()
1070 all other code must call lookupProperties() instead
1071 */
_lookupProperties(const PP_AttrProp * pSectionAP)1072 void fl_EndnoteLayout::_lookupProperties(const PP_AttrProp* pSectionAP)
1073 {
1074 UT_return_if_fail(pSectionAP);
1075 // I can't think of any properties we need for now.
1076 // If we need any later, we'll add them. -PL
1077 const gchar *pszEndnotePID = NULL;
1078 if(!pSectionAP->getAttribute("endnote-id",pszEndnotePID))
1079 {
1080 m_iEndnotePID = 0;
1081 }
1082 else
1083 {
1084 m_iEndnotePID = atoi(pszEndnotePID);
1085 }
1086 }
1087
1088
1089 /*!
1090 Create a new Endote container.
1091 \param If pPrevFootnote is non-null place the new cell after this in the linked
1092 list, otherwise just append it to the end.
1093 \return The newly created Endnote container
1094 */
getNewContainer(fp_Container *)1095 fp_Container* fl_EndnoteLayout::getNewContainer(fp_Container *)
1096 {
1097 UT_DEBUGMSG(("fl_EndnoteLayoutx: creating new Endnote container\n"));
1098 _createEndnoteContainer();
1099 m_bIsOnPage = false;
1100 return static_cast<fp_Container *>(getLastContainer());
1101 }
1102
1103
_insertEndnoteContainer(fp_Container * pNewEC)1104 void fl_EndnoteLayout::_insertEndnoteContainer(fp_Container * pNewEC)
1105 {
1106 xxx_UT_DEBUGMSG(("inserting endnote container into DocLayout list\n"));
1107
1108 m_pLayout->insertEndnoteContainer(static_cast<fp_EndnoteContainer *>(pNewEC));
1109 m_bIsOnPage = true;
1110 }
1111