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