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 #include "xap_App.h"
27 #include "ap_Strings.h"
28 #include "ap_Prefs.h"
29 #include "fl_SectionLayout.h"
30 #include "fl_TableLayout.h"
31 #include "fp_TableContainer.h"
32 #include "fl_TOCLayout.h"
33 #include "fl_Layout.h"
34 #include "fl_DocLayout.h"
35 #include "fl_BlockLayout.h"
36 #include "fb_LineBreaker.h"
37 #include "fp_Page.h"
38 #include "fp_Line.h"
39 #include "fp_Column.h"
40 #include "fp_TOCContainer.h"
41 #include "fp_ContainerObject.h"
42 #include "pd_Document.h"
43 #include "pp_AttrProp.h"
44 #include "gr_Graphics.h"
45 #include "pp_Property.h"
46 #include "px_ChangeRecord.h"
47 #include "px_CR_Object.h"
48 #include "px_CR_ObjectChange.h"
49 #include "px_CR_Span.h"
50 #include "px_CR_SpanChange.h"
51 #include "px_CR_Strux.h"
52 #include "px_CR_StruxChange.h"
53 #include "px_CR_Glob.h"
54 #include "fp_Run.h"
55 #include "ut_debugmsg.h"
56 #include "ut_assert.h"
57 #include "ut_units.h"
58 #include "fv_View.h"
59 #include "pd_Style.h"
60 
TOCEntry(fl_BlockLayout * pBlock,UT_sint32 iLevel,UT_UTF8String & sDispStyle,bool bHaveLabel,FootnoteType iFType,UT_UTF8String & sBefore,UT_UTF8String sAfter,bool bInherit,UT_sint32 iStartAt)61 TOCEntry::TOCEntry(fl_BlockLayout * pBlock,
62 				   UT_sint32 iLevel,
63 				   UT_UTF8String & sDispStyle,
64 				   bool bHaveLabel,
65 				   FootnoteType iFType,
66 				   UT_UTF8String & sBefore,
67 				   UT_UTF8String sAfter,
68 				   bool bInherit,
69 				   UT_sint32 iStartAt):
70 	m_pBlock(pBlock),
71 	m_iLevel(iLevel),
72 	m_sDispStyle(sDispStyle),
73 	m_bHasLabel(bHaveLabel),
74 	m_iFType(iFType),
75 	m_sBefore(sBefore),
76 	m_sAfter(sAfter),
77 	m_bInherit(bInherit),
78 	m_iStartAt(iStartAt)
79 {
80 }
81 
~TOCEntry(void)82 TOCEntry::~TOCEntry(void)
83 {
84 	m_iLevel = -1;
85 	UT_DEBUGMSG(("Deleteing entry %p \n",this));
86 }
87 
getPositionInDoc(void)88 PT_DocPosition TOCEntry::getPositionInDoc(void)
89 {
90 	PT_DocPosition pos = m_pBlock->getPosition();
91 	return pos;
92 }
93 
setPosInList(UT_sint32 posInList)94 void TOCEntry::setPosInList(UT_sint32 posInList)
95 {
96 	m_iPosInList = posInList;
97 }
98 
calculateLabel(TOCEntry * pPrevLevel)99 void TOCEntry::calculateLabel(TOCEntry * pPrevLevel)
100 {
101 	UT_String sVal;
102 	sVal.clear();
103 	m_pBlock->getView()->getLayout()->getStringFromFootnoteVal(sVal,m_iPosInList,m_iFType);
104 	if((pPrevLevel == NULL) || !m_bInherit)
105 	{
106 		m_sLabel = sVal.c_str();
107 		return;
108 	}
109 	m_sLabel = pPrevLevel->getNumLabel();
110 	m_sLabel += ".";
111 	m_sLabel += sVal.c_str();
112 }
113 
getFullLabel(void)114 UT_UTF8String  TOCEntry::getFullLabel(void)
115 {
116 	static UT_UTF8String sFull;
117 	sFull.clear();
118 	sFull = m_sBefore;
119 	sFull += m_sLabel;
120 	sFull += m_sAfter;
121 	return sFull;
122 }
123 
fl_TOCLayout(FL_DocLayout * pLayout,fl_DocSectionLayout * pDocSL,pf_Frag_Strux * sdh,PT_AttrPropIndex indexAP,fl_ContainerLayout * pMyContainerLayout)124 fl_TOCLayout::fl_TOCLayout(FL_DocLayout* pLayout, fl_DocSectionLayout* pDocSL, pf_Frag_Strux* sdh, PT_AttrPropIndex indexAP, fl_ContainerLayout * pMyContainerLayout)
125  	: fl_SectionLayout(pLayout, sdh, indexAP, FL_SECTION_TOC,FL_CONTAINER_TOC,PTX_SectionTOC,pMyContainerLayout),
126 	  m_bNeedsRebuild(false),
127 	  m_bNeedsFormat(true),
128 	  m_bIsOnPage(false),
129 	  m_pDocSL(pDocSL),
130 	  m_bHasEndTOC(false),
131 	  m_bDoingPurge(false),
132 	  m_bIsSelected(false),
133 	  m_iNumType1(FOOTNOTE_TYPE_NUMERIC),
134 	  m_iNumType2(FOOTNOTE_TYPE_NUMERIC),
135 	  m_iNumType3(FOOTNOTE_TYPE_NUMERIC),
136 	  m_iNumType4(FOOTNOTE_TYPE_NUMERIC),
137 	  m_iTabLeader1(FL_LEADER_DOT),
138 	  m_iTabLeader2(FL_LEADER_DOT),
139 	  m_iTabLeader3(FL_LEADER_DOT),
140 	  m_iTabLeader4(FL_LEADER_DOT),
141 	  m_iCurrentLevel(0),
142 	  m_bMissingBookmark(false),
143 	  m_bFalseBookmarkEstimate(false)
144 {
145 	UT_ASSERT(m_pDocSL->getContainerType() == FL_CONTAINER_DOCSECTION);
146 //	_createTOCContainer();
147 //	_insertTOCContainer(static_cast<fp_TOCContainer *>(getLastContainer()));
148 	m_pLayout->addTOC(this);
149 }
150 
~fl_TOCLayout()151 fl_TOCLayout::~fl_TOCLayout()
152 {
153 	// NB: be careful about the order of these
154 	UT_DEBUGMSG(("Deleting TOClayout %p \n",this));
155 	_purgeLayout();
156 	fp_TOCContainer * pTC = static_cast<fp_TOCContainer *>(getFirstContainer());
157 	while(pTC)
158 	{
159 		fp_TOCContainer * pNext = static_cast<fp_TOCContainer *>(pTC->getNext());
160 		if(pTC == static_cast<fp_TOCContainer *>(getLastContainer()))
161 		{
162 			pNext = NULL;
163 		}
164 		delete pTC;
165 		pTC = pNext;
166 	}
167 
168 	setFirstContainer(NULL);
169 	setLastContainer(NULL);
170 	m_pLayout->removeTOC(this);
171 }
172 
173 /*!
174  * Returns the position in the document of the PTX_SectionTOC strux
175  * This is very useful for determining the value of the footnote reference
176  * and anchor.
177 */
getDocPosition(void)178 PT_DocPosition fl_TOCLayout::getDocPosition(void)
179 {
180 	pf_Frag_Strux* sdh = getStruxDocHandle();
181     return 	m_pLayout->getDocument()->getStruxPosition(sdh);
182 }
183 
setSelected(bool bIsSelected)184 void fl_TOCLayout::setSelected(bool bIsSelected)
185 {
186 	if(!bIsSelected  && m_bIsSelected)
187 	{
188 		m_bIsSelected = false;
189 		fp_TOCContainer * pTOCCon = static_cast<fp_TOCContainer *>(getFirstContainer());
190 		pTOCCon->forceClearScreen();
191 		markAllRunsDirty();
192 		m_pLayout->getView()->updateScreen();
193 //		pTOCCon->draw(m_pLayout->getGraphics());
194 	}
195 	m_bIsSelected = bIsSelected;
196 	if(m_bIsSelected)
197 	{
198 		fp_TOCContainer * pTOCCon = static_cast<fp_TOCContainer *>(getFirstContainer());
199 		pTOCCon->forceClearScreen();
200 		markAllRunsDirty();
201 		m_pLayout->getView()->updateScreen();
202 //		pTOCCon->draw(m_pLayout->getGraphics());
203 	}
204 }
205 
206 /*!
207  * This method returns the length of the footnote. This is such that
208  * getDocPosition() + getLength() is one value beyond the the EndFootnote
209  * strux
210  */
getLength(void)211 UT_uint32 fl_TOCLayout::getLength(void)
212 {
213 	PT_DocPosition startPos = getDocPosition();
214 	pf_Frag_Strux* sdhEnd = NULL;
215 	pf_Frag_Strux* sdhStart = getStruxDocHandle();
216 	UT_DebugOnly<bool> bres;
217 	bres = m_pLayout->getDocument()->getNextStruxOfType(sdhStart,PTX_EndTOC,&sdhEnd);
218 	UT_ASSERT(bres && sdhEnd);
219 	PT_DocPosition endPos = m_pLayout->getDocument()->getStruxPosition(sdhEnd);
220 	UT_uint32 length = static_cast<UT_uint32>(endPos - startPos + 1);
221 	return length;
222 }
223 
224 
bl_doclistener_insertEndTOC(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))225 bool fl_TOCLayout::bl_doclistener_insertEndTOC(fl_ContainerLayout*,
226 											  const PX_ChangeRecord_Strux * pcrx,
227 											  pf_Frag_Strux* sdh,
228 											  PL_ListenerId lid,
229 											  void (* pfnBindHandles)(pf_Frag_Strux* sdhNew,
230 																	  PL_ListenerId lid,
231 																	  fl_ContainerLayout* sfhNew))
232 {
233 	// The endFootnote strux actually needs a format handle to to this Footnote layout.
234 	// so we bind to this layout. We also set a pointer to keep track of the endTOC strux.
235 
236 
237 	fl_ContainerLayout* sfhNew = this;
238 	pfnBindHandles(sdh,lid,sfhNew);
239 	setEndStruxDocHandle(sdh);
240 
241 //
242 // increment the insertion point in the view.
243 //
244 	FV_View* pView = m_pLayout->getView();
245 	if (pView && (pView->isActive() || pView->isPreview()))
246 	{
247 		pView->setPoint(pcrx->getPosition() +  fl_BLOCK_STRUX_OFFSET);
248 	}
249 	else if(pView && pView->getPoint() > pcrx->getPosition())
250 	{
251 		pView->setPoint(pView->getPoint() +  fl_BLOCK_STRUX_OFFSET);
252 	}
253 	m_bHasEndTOC = true;
254 
255 	fillTOC();
256 
257 	return true;
258 }
259 
260 /*!
261  * Set boolean to tell that TOCend has been inserted. Also makes sure the
262  * layout is fully filled.
263  */
setTOCEndIn(void)264 void fl_TOCLayout::setTOCEndIn(void)
265 {
266 	m_bHasEndTOC = true;
267 }
268 
269 /*!
270  * This signals an incomplete footnote section.
271  */
doclistener_deleteEndTOC(const PX_ChangeRecord_Strux *)272 bool fl_TOCLayout::doclistener_deleteEndTOC( const PX_ChangeRecord_Strux * /*pcrx*/)
273 {
274 	m_bHasEndTOC = false;
275 	return true;
276 }
277 
278 
getSectionLayout(void) const279 fl_SectionLayout * fl_TOCLayout::getSectionLayout(void) const
280 {
281 	fl_ContainerLayout * pDSL = myContainingLayout();
282 	while(pDSL)
283 	{
284 		if(pDSL->getContainerType() == FL_CONTAINER_DOCSECTION)
285 		{
286 			return static_cast<fl_SectionLayout *>(pDSL);
287 		}
288 		pDSL = pDSL->myContainingLayout();
289 	}
290 	return NULL;
291 }
292 
getNumType(UT_sint32 iLevel)293 FootnoteType fl_TOCLayout::getNumType(UT_sint32 iLevel)
294 {
295 	if(iLevel == 1)
296 	{
297 		return m_iNumType1;
298 	}
299 	else if(iLevel == 2)
300 	{
301 		return m_iNumType2;
302 	}
303 	else if(iLevel == 3)
304 	{
305 		return m_iNumType3;
306 	}
307 	else if(iLevel == 4)
308 	{
309 		return m_iNumType4;
310 	}
311 	UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
312 	return static_cast<FootnoteType>(0);
313 }
314 
315 
getTabLeader(UT_sint32 iLevel)316 eTabLeader fl_TOCLayout::getTabLeader(UT_sint32 iLevel)
317 {
318 	if(iLevel == 1)
319 	{
320 		return m_iTabLeader1;
321 	}
322 	else if(iLevel == 2)
323 	{
324 		return m_iTabLeader2;
325 	}
326 	else if(iLevel == 3)
327 	{
328 		return m_iTabLeader3;
329 	}
330 	else if(iLevel == 4)
331 	{
332 		return m_iTabLeader4;
333 	}
334 	UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
335 	return static_cast<eTabLeader>(0);
336 }
337 
getTabPosition(UT_sint32 iLevel,const fl_BlockLayout * pBlock)338 UT_sint32 fl_TOCLayout::getTabPosition(UT_sint32 iLevel, const fl_BlockLayout * pBlock)
339 {
340 	fp_TOCContainer * pTOCC = static_cast<fp_TOCContainer *>(getFirstContainer());
341 	if(pTOCC == NULL)
342 	{
343 		UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
344 		return 0;
345 	}
346 	UT_sint32 iWidth = pTOCC->getWidth() -pBlock->getLeftMargin();
347 	UT_UTF8String sStr("");
348 	if(iLevel == 1)
349 	{
350 		sStr = m_sNumOff1;
351 	}
352 	else if(iLevel == 2)
353 	{
354 		sStr = m_sNumOff2;
355 	}
356 	else if(iLevel == 3)
357 	{
358 		sStr = m_sNumOff3;
359 	}
360 	else if(iLevel == 4)
361 	{
362 		sStr = m_sNumOff4;
363 	}
364 	iWidth -= UT_convertToLogicalUnits(sStr.utf8_str());
365 	return iWidth;
366 }
367 
368 /*
369    During the filling of the doc layout when the TOC layout is restricted by a bookmark, we have
370    made the assumption that if the bookmark was not in the doc when we are asked to add a particular
371    block, it was to come later in the filling process; in addition we assumed that the bookmark will
372    not immediately follow the block strux. We now need to verify these assumption and if either is
373    false, redo the TOC.
374 */
verifyBookmarkAssumptions()375 bool fl_TOCLayout::verifyBookmarkAssumptions()
376 {
377 	UT_return_val_if_fail(!m_pLayout->isLayoutFilling(), false);
378 
379 	if((!m_bMissingBookmark && !m_bFalseBookmarkEstimate) || !m_sRangeBookmark.size())
380 		return false;
381 
382 	PD_Document * pDoc = m_pLayout->getDocument();
383 	UT_return_val_if_fail(pDoc, false);
384 
385 	if(m_bFalseBookmarkEstimate || (m_bMissingBookmark && m_pDoc->isBookmarkUnique(m_sRangeBookmark.utf8_str())))
386 	{
387 		// this bookmark either does not exist, or it was positioned earlier than we assumed
388 		fillTOC();
389 	}
390 
391 	return true;
392 }
393 
394 
395 /*
396     bVerifyRange indicates whether the function should verify that pBlock is inside the range indicated
397     by associated bookmark. This parameter has default value true, but the caller can specify false
398     if the block is known to be inside the TOC range (the range checking is involved, so if this
399     function is called from a loop, it is desirable that most of the range verification is taken
400     outside the loop -- see for example fillTOC())
401 */
addBlock(fl_BlockLayout * pBlock,bool bVerifyRange)402 bool fl_TOCLayout::addBlock(fl_BlockLayout * pBlock, bool bVerifyRange)
403 {
404 	UT_return_val_if_fail( pBlock, false );
405 	UT_UTF8String sStyle;
406 	pBlock->getStyle(sStyle);
407 
408 	if(bVerifyRange && m_sRangeBookmark.size() /*&& !m_pLayout->isLayoutFilling()*/)
409 	{
410 		// we need to ascertain whether the block is in our range
411 		PD_Document * pDoc = m_pLayout->getDocument();
412 		UT_return_val_if_fail( pDoc, false );
413 
414 		const gchar * pBookmark = m_sRangeBookmark.utf8_str();
415 
416 		if(!m_pDoc->isBookmarkUnique(pBookmark))
417 		{
418 			UT_uint32 i = 0;
419 			fp_Run * pRun;
420 			fl_BlockLayout * pBL;
421 			fp_BookmarkRun * pB[2] = {NULL,NULL};
422 			fl_ContainerLayout * pDSL = m_pLayout->getFirstSection();
423 			fl_ContainerLayout * pCL = static_cast<fl_ContainerLayout *>(pDSL);
424 			bool bFound = false;
425 
426 			while(pCL && pCL->getContainerType() != FL_CONTAINER_BLOCK)
427 			{
428 				pCL = pCL->getFirstLayout();
429 			}
430 			if(pCL == NULL)
431 			{
432 				return false;
433 			}
434 			if(pCL->getContainerType() != FL_CONTAINER_BLOCK)
435 			{
436 				return false;
437 			}
438 
439 			pBL = static_cast<fl_BlockLayout *>(pCL);
440 			PT_DocPosition pos1 = 0, pos2 = 0xffffffff;
441 
442 			// during the fill process we will take advantage of the fact that the doc positions do
443 			// not change, and will store the positions of our bookmarks; if the document is not
444 			// filling, we will do this the hard way
445 
446 			if(!m_pLayout->isLayoutFilling())
447 				m_vecBookmarkPositions.clear();
448 
449 			if(m_vecBookmarkPositions.getItemCount() < 2)
450 			{
451 				if(m_vecBookmarkPositions.getItemCount() == 1)
452 				{
453 					pos1  = m_vecBookmarkPositions.getNthItem(0);
454 
455 					if(m_bMissingBookmark)
456 					{
457 						// the stored position is only an estimate == strux offset + 1
458 						// we have to substract the one
459 						UT_ASSERT_HARMLESS( pos1 );
460 						--pos1;
461 
462 						// we are still looking for the starting bookmark
463 						i = 0;
464 					}
465 					else
466 					{
467 						// the stored position is the real position, so we only need to look for the
468 						// end bookmark
469 						i = 1;
470 					}
471 
472 					// now jump to the block in question
473 					while(pBL->getNextBlockInDocument() && pBL->getNextBlockInDocument()->getPosition(true) < pos1)
474 						pBL = pBL->getNextBlockInDocument();
475 				}
476 
477 				while(pBL)
478 				{
479 					pRun = pBL->getFirstRun();
480 
481 					while(pRun)
482 					{
483 						if(pRun->getType()== FPRUN_BOOKMARK)
484 						{
485 							fp_BookmarkRun * pBR = static_cast<fp_BookmarkRun*>(pRun);
486 							bool bIsRight = (i == 0 && pBR->isStartOfBookmark()) || (i != 0 && !pBR->isStartOfBookmark());
487 
488 							if(bIsRight && !strcmp(pBR->getName(),pBookmark))
489 							{
490 								pB[i] = pBR;
491 								i++;
492 								if(i>1)
493 								{
494 									bFound = true;
495 									break;
496 								}
497 							}
498 						}
499 
500 						pRun = pRun->getNextRun();
501 					}
502 
503 					if(bFound)
504 						break;
505 
506 					pBL = pBL->getNextBlockInDocument();
507 				}
508 
509 				if(!pB[0] && !m_vecBookmarkPositions.getItemCount() && m_pLayout->isLayoutFilling())
510 				{
511 					// we will assume that the bookmark is still to come and that it is immediately
512 					// after the strux, but we need to make note that we made that assumption ...
513 					m_bMissingBookmark = true;
514 					pos1 = pBlock->getPosition(false); // position immediately after the strux
515 					m_vecBookmarkPositions.addItem(pos1);
516 				}
517 				else if(!pB[0] && m_vecBookmarkPositions.getItemCount())
518 				{
519 					// this is the case where we already knew the position and set it earlier
520 					// do nothing
521 					UT_ASSERT_HARMLESS( m_pLayout->isLayoutFilling() && m_vecBookmarkPositions.getItemCount() == 1 );
522 				}
523 				else if(!pB[0] && !m_pLayout->isLayoutFilling())
524 				{
525 					// the document does not contain this bookmark
526 					// we build the toc from the whole document
527 					pos1 = 0;
528 				}
529 				else if(pB[0])
530 				{
531 					pos1 = pB[0]->getBookmarkedDocPosition(false);
532 					PT_DocPosition posOld = 0;
533 
534 					if(m_vecBookmarkPositions.getItemCount())
535 					{
536 						// this is the case where we guessed the pos1
537 						posOld = m_vecBookmarkPositions.getNthItem(0);
538 						m_vecBookmarkPositions.clear();
539 					}
540 
541 					if(m_pLayout->isLayoutFilling())
542 						m_vecBookmarkPositions.addItem(pos1);
543 
544 					m_bMissingBookmark = false; // this is the real thing
545 
546 					if(pos1 < posOld)
547 					{
548 						// we assumed that the actual postion of the bookmark was after the strux
549 						// which we were processing when we previously set pos1. This assumption was
550 						// incorrect, so we will have to redo the layout later
551 						m_bFalseBookmarkEstimate = true;
552 					}
553 				}
554 
555 				if(!pB[1] && pos1 != 0)
556 				{
557 					// end bookmark not loaded yet
558 					UT_ASSERT_HARMLESS( m_pLayout->isLayoutFilling() );
559 					pos2 = 0xffffffff;
560 				}
561 				if(!pB[1] && pos1 == 0)
562 				{
563 					// this bookmark is not in the document, we will build the toc from the entire doc
564 					pos2 = 0xffffffff;
565 				}
566 				else if(pB[1])
567 				{
568 					pos2 = pB[1]->getBookmarkedDocPosition(true);
569 
570 					if(m_pLayout->isLayoutFilling())
571 					{
572 						if(m_vecBookmarkPositions.getItemCount() != 1)
573 						{
574 							UT_ASSERT_HARMLESS( UT_SHOULD_NOT_HAPPEN );
575 							m_vecBookmarkPositions.clear();
576 							m_vecBookmarkPositions.addItem(0);
577 						}
578 
579 						m_vecBookmarkPositions.addItem(pos2);
580 					}
581 				}
582 			}
583 			else
584 			{
585 				UT_ASSERT_HARMLESS(m_vecBookmarkPositions.getItemCount() == 2 && m_pLayout->isLayoutFilling());
586 				pos1 = m_vecBookmarkPositions.getNthItem(0);
587 				pos2 = m_vecBookmarkPositions.getNthItem(1);
588 			}
589 
590 
591 			if(pBlock->getPosition(true) < pos1 || pBlock->getPosition(true) >= pos2)
592 				return false;
593 		}
594 	}
595 
596 
597 	if(_isStyleInTOC(sStyle,m_sSourceStyle1))
598 	{
599 		m_iCurrentLevel = 1;
600 		_addBlockInVec(pBlock,m_sDestStyle1);
601 		return true;
602 	}
603 	if(_isStyleInTOC(sStyle,m_sSourceStyle2))
604 	{
605 		m_iCurrentLevel = 2;
606 		_addBlockInVec(pBlock,m_sDestStyle2);
607 		return true;
608 	}
609 	if(_isStyleInTOC(sStyle,m_sSourceStyle3))
610 	{
611 		m_iCurrentLevel = 3;
612 		_addBlockInVec(pBlock,m_sDestStyle3);
613 		return true;
614 	}
615 	if(_isStyleInTOC(sStyle,m_sSourceStyle4))
616 	{
617 		m_iCurrentLevel = 4;
618 		_addBlockInVec(pBlock,m_sDestStyle4);
619 		return true;
620 	}
621 	return false;
622 }
623 
624 /*
625     This function creates a TOC entry from the given document positions, with all the frills added
626     (this code used to be inside _addBlockInVec())
627 */
_createAndFillTOCEntry(PT_DocPosition posStart,PT_DocPosition posEnd,fl_BlockLayout * pPrevBL,const char * pszStyle,UT_sint32 iAllBlocks)628 void fl_TOCLayout::_createAndFillTOCEntry(PT_DocPosition posStart, PT_DocPosition posEnd,
629 										  fl_BlockLayout * pPrevBL, const char * pszStyle,
630 										  UT_sint32 iAllBlocks)
631 {
632 	UT_return_if_fail(pszStyle);
633 
634 	PD_Style * pStyle = NULL;
635 	m_pDoc->getStyle(pszStyle,&pStyle);
636 	if(pStyle == NULL)
637 	{
638 		m_pDoc->getStyle("Normal",&pStyle);
639 	}
640 	fl_TOCListener * pListen = new fl_TOCListener(this,pPrevBL,pStyle);
641 	PD_DocumentRange * docRange = new PD_DocumentRange(m_pDoc,posStart,posEnd);
642 
643 	m_pDoc->tellListenerSubset(pListen, docRange);
644 
645 	delete docRange;
646 	delete pListen;
647 
648 	fl_BlockLayout * pNewBlock;
649 	if(pPrevBL)
650 	{
651 		pNewBlock = static_cast<fl_BlockLayout *>(pPrevBL->getNext());
652 	}
653 	else
654 	{
655 		pNewBlock = static_cast<fl_BlockLayout *>(getFirstLayout());
656 		if(pNewBlock && (pNewBlock->getNext() != NULL))
657 		{
658 			pNewBlock = static_cast<fl_BlockLayout *>(pNewBlock->getNext());
659 		}
660 	}
661 
662 	// OK Now add the block to our vector.
663 	TOCEntry *pNewEntry = createNewEntry(pNewBlock);
664 	if(iAllBlocks == 0)
665 	{
666 		m_vecEntries.insertItemAt(pNewEntry,0);
667 	}
668 	else if (iAllBlocks < m_vecEntries.getItemCount())
669 	{
670 		m_vecEntries.insertItemAt(pNewEntry,iAllBlocks);
671 	}
672 	else
673 	{
674 		m_vecEntries.addItem(pNewEntry);
675 	}
676 
677 	_calculateLabels();
678 
679 	// Now append the tab and Field's to end of the new Block.
680 	PT_DocPosition iLen = posEnd - posStart - 1; // subtract 1 for the inital strux
681 	pNewBlock->_doInsertTOCTabRun(iLen);
682 
683 	iLen++;
684 	pNewBlock->_doInsertFieldTOCRun(iLen);
685 
686 	// Now Insert the TAB and TOCListLabel runs if requested.
687 	if(pNewEntry->hasLabel())
688 	{
689 		pNewBlock->_doInsertTOCListTabRun(0);
690 		pNewBlock->_doInsertTOCListLabelRun(0);
691 	}
692 
693 	fp_Container * pTOCC = getFirstContainer();
694 	fl_DocSectionLayout * pDSL = getDocSectionLayout();
695 	if(pTOCC && pTOCC->getPage())
696 	{
697 		fp_Page * pPage = pTOCC->getPage();
698 		pDSL->setNeedsSectionBreak(true,pPage );
699 	}
700 
701 	markAllRunsDirty();
702 	setNeedsReformat(0);
703 	setNeedsRedraw();
704 }
705 
_addBlockInVec(fl_BlockLayout * pBlock,UT_UTF8String & sStyle)706 void fl_TOCLayout::_addBlockInVec(fl_BlockLayout * pBlock, UT_UTF8String & sStyle)
707 {
708 	// First find where to put the block.
709 	PT_DocPosition posNew = pBlock->getPosition();
710 	TOCEntry * pEntry = NULL;
711 	fl_BlockLayout * pPrevBL = NULL;
712 	UT_sint32 i = 0;
713 	bool bFound = false;
714 
715 	for(i=0; i< m_vecEntries.getItemCount(); i++)
716 	{
717 		pEntry = m_vecEntries.getNthItem(i);
718 		pPrevBL = pEntry->getBlock();
719 
720 		if(pPrevBL->getPosition() > posNew)
721 		{
722 			bFound = true;
723 			break;
724 		}
725 	}
726 
727 	UT_sint32 iAllBlocks = 0;
728 	if(bFound)
729 	{
730 		if(i > 0)
731 		{
732 			pEntry =  m_vecEntries.getNthItem(i-1);
733 			pPrevBL =  pEntry->getBlock();
734 		}
735 		else
736 		{
737 			pEntry = NULL;
738 			pPrevBL = NULL;
739 		}
740 	}
741 
742 	iAllBlocks = i;
743 
744 	if(pPrevBL == NULL)
745 	{
746 		pPrevBL = static_cast<fl_BlockLayout *>(getFirstLayout());
747 	}
748 #if 0
749 	else if(!m_pLayout->isLayoutFilling())
750 	{
751 		// we have to redo the previous TOC block, if we have stolen some of its contents (i.e., if
752 		// the new block was inserted into a heading block) -- we need to see if the new block comes
753 		// immediately after the old block represented by pPrevBL
754 		PT_DocPosition posStart2 = pPrevBL->getPosition(true);
755 		PT_DocPosition posEnd2   = posStart2 + static_cast<PT_DocPosition>(pPrevBL->getLength());
756 		PT_DocPosition posStart  = pBlock->getPosition(true);
757 		UT_DEBUGMSG(("Prev. affected block is %d long \n",pPrevBL->getLength()));
758 
759 		if(posEnd2 == posStart)
760 		{
761 			fl_BlockLayout * pPrevBL2 = NULL;
762 			UT_return_if_fail( pEntry && iAllBlocks > 0 );
763 			UT_UTF8String sDispStyle = pEntry->getDispStyle();
764 			UT_sint32 iNewLevel = pEntry->getLevel();
765 			if(i > 1)
766 			{
767 				pEntry =  m_vecEntries.getNthItem(i-2);
768 				pPrevBL2 =  pEntry->getBlock();
769 			}
770 
771 			// now get rid of the old TOC block (this locates the shaddow to be removed by shd, so
772 			// it works whether passed the shaddow block or the main doc block)
773 
774 			_removeBlockInVec(pPrevBL, true);
775 			pPrevBL = NULL;
776 
777 			UT_sint32 iOldLevel = m_iCurrentLevel;
778 			m_iCurrentLevel = iNewLevel;
779 			_createAndFillTOCEntry(posStart2, posEnd2, pPrevBL2, sDispStyle.utf8_str(), iAllBlocks - 1);
780 			m_iCurrentLevel = iOldLevel;
781 
782 			// we do not have to notify the orignal block that it is shaddowed, it knows already,
783 			// but we need to obtain the new pPrevBL for further processing
784 
785 			if(pPrevBL2)
786 			{
787 				pPrevBL = static_cast<fl_BlockLayout *>(pPrevBL2->getNext());
788 			}
789 			else
790 			{
791 				pPrevBL = static_cast<fl_BlockLayout *>(getFirstLayout());
792 				if(pPrevBL && pPrevBL->getNext())
793 				{
794 					pPrevBL = static_cast<fl_BlockLayout *>(pPrevBL->getNext());
795 				}
796 			}
797 		}
798 	}
799 #endif
800 	PT_DocPosition posStart = pBlock->getPosition(true);
801 	PT_DocPosition posEnd = posStart + static_cast<PT_DocPosition>(pBlock->getLength());
802 
803 	_createAndFillTOCEntry(posStart, posEnd, pPrevBL, sStyle.utf8_str(), iAllBlocks);
804 
805 	// Tell the block it's shadowed in a TOC
806 	pBlock->setStyleInTOC(true);
807 }
808 
isInVector(fl_BlockLayout * pBlock,UT_GenericVector<TOCEntry * > * pVecEntries)809 UT_sint32 fl_TOCLayout::isInVector(fl_BlockLayout * pBlock,
810 								   UT_GenericVector<TOCEntry *>* pVecEntries)
811 {
812 	TOCEntry * pThisEntry = NULL;
813 	fl_BlockLayout * pThisBL = NULL;
814 	UT_sint32 i = 0;
815 	for(i=0; i< pVecEntries->getItemCount(); i++)
816 	{
817 
818 		pThisEntry = pVecEntries->getNthItem(i);
819 		pThisBL = pThisEntry->getBlock();
820 		if(pThisBL->getStruxDocHandle() == pBlock->getStruxDocHandle())
821 		{
822 			return i;
823 		}
824 	}
825 	return -1;
826 }
827 
828 
removeBlock(fl_BlockLayout * pBlock)829 bool fl_TOCLayout::removeBlock(fl_BlockLayout * pBlock)
830 {
831 	if(m_bDoingPurge)
832 	{
833 		return true;
834 	}
835 	if(m_pLayout && m_pLayout->isLayoutDeleting())
836 	{
837 		return false;
838 	}
839 	if(isInVector(pBlock,&m_vecEntries) >= 0)
840 	{
841 		fp_TOCContainer * pTOC = static_cast<fp_TOCContainer *>(getFirstContainer());
842 		if(pTOC)
843 		{
844 			pTOC->clearScreen();
845 		}
846 		_removeBlockInVec(pBlock);
847 		_calculateLabels();
848 		return true;
849 	}
850 	return false;
851 }
852 
853 
findMatchingBlock(fl_BlockLayout * pBlock)854 fl_BlockLayout * fl_TOCLayout::findMatchingBlock(fl_BlockLayout * pBlock)
855 {
856 	TOCEntry * pThisEntry = NULL;
857 	fl_BlockLayout * pThisBL = NULL;
858 	UT_sint32 i = 0;
859 	bool bFound = false;
860 	for(i=0; i< m_vecEntries.getItemCount(); i++)
861 	{
862 		pThisEntry = m_vecEntries.getNthItem(i);
863 		pThisBL = pThisEntry->getBlock();
864 		if(pThisBL->getStruxDocHandle() == pBlock->getStruxDocHandle())
865 		{
866 			bFound = true;
867 			break;
868 		}
869 	}
870 	if(bFound)
871 	{
872 		return pThisBL;
873 	}
874 	return NULL;
875 }
876 
877 /*
878     When a block is deleted from the TOC, it is sometimes necessary to redo the toc entry that
879     preceded it. We do this be removing and recreating this previous entry, which requires a
880     recursive call to ourselves. bDontRecurse indicates that the recursive processing should not be
881     done; it has a default value false.
882 */
_removeBlockInVec(fl_BlockLayout * pBlock,bool)883 void fl_TOCLayout::_removeBlockInVec(fl_BlockLayout * pBlock, bool /*bDontRecurse*/)
884 {
885 	TOCEntry * pThisEntry = NULL;
886 	fl_BlockLayout * pThisBL = NULL;
887 	UT_sint32 i = 0;
888 	bool bFound = false;
889 	for(i=0; i< m_vecEntries.getItemCount(); i++)
890 	{
891 		pThisEntry = m_vecEntries.getNthItem(i);
892 		pThisBL = pThisEntry->getBlock();
893 		if(pThisBL->getStruxDocHandle() == pBlock->getStruxDocHandle())
894 		{
895 			bFound = true;
896 			break;
897 		}
898 	}
899 	if(!bFound)
900 	{
901 		return;
902 	}
903 	//
904 	// Clear it!
905 	//
906 	UT_DEBUGMSG(("Removing block %p Entry %p \n",pThisBL,pThisEntry));
907 	if(!pBlock->isContainedByTOC())
908 	{
909 		// we only clear if the block passed to us is not one of our TOC blocks (i.e., if we are not
910 		// called recursively by this funciton, or by _addBlockInVec())
911 		pBlock->clearScreen(m_pLayout->getGraphics());
912 	}
913 	//
914 	// unlink it from the TOCLayout
915 	//
916 
917 	if(static_cast<fl_BlockLayout *>(getFirstLayout()) == pThisBL)
918 	{
919 		setFirstLayout(pThisBL->getNext());
920 	}
921 	if(static_cast<fl_BlockLayout *>(getLastLayout()) == pThisBL)
922 	{
923 		setLastLayout(pThisBL->getPrev());
924 	}
925 	if(pThisBL->getPrev())
926 	{
927 		pThisBL->getPrev()->setNext(pThisBL->getNext());
928 	}
929 	if(pThisBL->getNext())
930 	{
931 		pThisBL->getNext()->setPrev(pThisBL->getPrev());
932 	}
933 //
934 // Remove entry
935 //
936 	UT_sint32 k = m_vecEntries.findItem(pThisEntry);
937 	i = k-1;
938 	UT_ASSERT(k >= 0);
939 	while(k >= 0)
940 	{
941 		m_vecEntries.deleteNthItem(k);
942 		k = m_vecEntries.findItem(pThisEntry);
943 		UT_ASSERT(k== -1);
944 	}
945 
946 	delete pThisBL;
947 	delete pThisEntry;
948 //
949 // Used to have code to remove the previous block if it touched this
950 // block. Remove it and rely on fl_blocklayout to handle the case of
951 // text from a previous block coming into this block
952 //
953 	markAllRunsDirty();
954 	setNeedsReformat(0);
955 	setNeedsRedraw();
956 
957 }
958 
_getStartValue(TOCEntry * pEntry)959 UT_sint32 fl_TOCLayout::_getStartValue(TOCEntry * pEntry)
960 {
961 	if(pEntry->getLevel() == 1)
962 	{
963 		return m_iStartAt1;
964 	}
965 	else if(pEntry->getLevel() == 2)
966 	{
967 		return m_iStartAt2;
968 	}
969 	else if(pEntry->getLevel() == 3)
970 	{
971 		return m_iStartAt3;
972 	}
973 	else
974 	{
975 		return m_iStartAt4;
976 	}
977 }
978 
_calculateLabels(void)979 void fl_TOCLayout::_calculateLabels(void)
980 {
981 	UT_sint32 i = 0;
982 	TOCEntry * pThisEntry = NULL;
983 	TOCEntry * pPrevEntry = NULL;
984 	UT_Stack stEntry;
985 	stEntry.push(NULL);
986 	UT_sint32 iCount = m_vecEntries.getItemCount();
987 	if(iCount == 0)
988 	{
989 		return;
990 	}
991 	pThisEntry = m_vecEntries.getNthItem(0);
992 	stEntry.push(pThisEntry);
993 	for(i=0; i<	iCount; i++)
994 	{
995 		if(pPrevEntry == NULL)
996 		{
997 			pThisEntry->setPosInList(_getStartValue(pThisEntry));
998 			pThisEntry->calculateLabel(pPrevEntry);
999 			pPrevEntry = pThisEntry;
1000 			continue;
1001 		}
1002 		pThisEntry = m_vecEntries.getNthItem(i);
1003 		UT_ASSERT(pThisEntry->getLevel() >= 0);
1004 		if(pThisEntry->getLevel() == pPrevEntry->getLevel())
1005 		{
1006 			pThisEntry->setPosInList(pPrevEntry->getPosInList()+1);
1007 			void * pTmp = NULL;
1008 			UT_ASSERT(stEntry.getDepth() > 0);
1009 			stEntry.viewTop(&pTmp);
1010 			TOCEntry * pPrevLevel = static_cast<TOCEntry*>(pTmp);
1011 			if(pPrevLevel && pPrevLevel->getLevel() < pThisEntry->getLevel())
1012 			{
1013 				UT_ASSERT(pPrevLevel->getLevel() >= 0);
1014 				pThisEntry->calculateLabel(pPrevLevel);
1015 			}
1016 			else
1017 			{
1018 				pThisEntry->calculateLabel(NULL);
1019 			}
1020 			pPrevEntry = pThisEntry;
1021 		}
1022 		else if(pThisEntry->getLevel() > pPrevEntry->getLevel())
1023 		{
1024 			stEntry.push(pPrevEntry);
1025 			pThisEntry->setPosInList(_getStartValue(pThisEntry));
1026 			pThisEntry->calculateLabel(pPrevEntry);
1027 			pPrevEntry = pThisEntry;
1028 		}
1029 		else
1030 		{
1031 			bool bStop = false;
1032 			while((stEntry.getDepth()>1) && !bStop)
1033 			{
1034 				void * pTmp;
1035 				UT_ASSERT(stEntry.getDepth() > 0);
1036 				stEntry.pop(&pTmp);
1037 				pPrevEntry = static_cast<TOCEntry*>(pTmp);
1038 				if(pPrevEntry->getLevel() == pThisEntry->getLevel())
1039 				{
1040 					bStop = true;
1041 				}
1042 			}
1043 			if(bStop)
1044 			{
1045 				pThisEntry->setPosInList(pPrevEntry->getPosInList()+1);
1046 				void * pTmp;
1047 				UT_ASSERT(stEntry.getDepth() > 0);
1048 				stEntry.viewTop(&pTmp);
1049 				TOCEntry * pPrevLevel = static_cast<TOCEntry*>(pTmp);
1050 				if(pPrevLevel && pPrevLevel->getLevel() < pThisEntry->getLevel())
1051 				{
1052 					pThisEntry->calculateLabel(pPrevLevel);
1053 				}
1054 				else
1055 				{
1056 					pThisEntry->calculateLabel(NULL);
1057 				}
1058 				pPrevEntry = pThisEntry;
1059 			}
1060 			else
1061 			{
1062 				pThisEntry->setPosInList(_getStartValue(pThisEntry));
1063 				pPrevEntry = pThisEntry;
1064 				pThisEntry->calculateLabel(NULL);
1065 			}
1066 		}
1067 	}
1068 }
1069 
isStyleInTOC(UT_UTF8String & sStyle)1070 bool fl_TOCLayout::isStyleInTOC(UT_UTF8String & sStyle)
1071 {
1072 	if(_isStyleInTOC(sStyle,m_sSourceStyle1))
1073 	{
1074 		return true;
1075 	}
1076 	if(_isStyleInTOC(sStyle,m_sSourceStyle2))
1077 	{
1078 		return true;
1079 	}
1080 	if(_isStyleInTOC(sStyle,m_sSourceStyle3))
1081 	{
1082 		return true;
1083 	}
1084 	if(_isStyleInTOC(sStyle,m_sSourceStyle4))
1085 	{
1086 		return true;
1087 	}
1088 	return false;
1089 }
1090 
1091 /*!
1092  * Does a case insensitive search of the basedon heirachy for a match.
1093  */
_isStyleInTOC(UT_UTF8String & sStyle,UT_UTF8String & sTOCStyle)1094 bool fl_TOCLayout::_isStyleInTOC(UT_UTF8String & sStyle, UT_UTF8String & sTOCStyle)
1095 {
1096 	UT_UTF8String sTmpStyle = sStyle;
1097 	const char * sLStyle = sTOCStyle.utf8_str();
1098 	xxx_UT_DEBUGMSG(("Looking at TOC Style %s \n",sLStyle));
1099 	xxx_UT_DEBUGMSG(("Base input style is %s \n",sTmpStyle.utf8_str()));
1100 	if(g_ascii_strcasecmp(sLStyle,sTmpStyle.utf8_str()) == 0)
1101 	{
1102 		xxx_UT_DEBUGMSG(("Found initial match \n"));
1103 		return true;
1104 	}
1105 	PD_Style * pStyle = NULL;
1106 	m_pDoc->getStyle(sTmpStyle.utf8_str(), &pStyle);
1107 	if(pStyle != NULL)
1108 	{
1109 		UT_sint32 iLoop = 0;
1110 		while((pStyle->getBasedOn()) != NULL && (iLoop < 10))
1111 		{
1112 			pStyle = pStyle->getBasedOn();
1113 			iLoop++;
1114 			sTmpStyle = pStyle->getName();
1115 			xxx_UT_DEBUGMSG(("Level %d style is %s \n",iLoop,sTmpStyle.utf8_str()));
1116 			if(g_ascii_strcasecmp(sLStyle,sTmpStyle.utf8_str()) == 0)
1117 			{
1118 				return true;
1119 			}
1120 		}
1121 	}
1122 	xxx_UT_DEBUGMSG(("No match Found \n"));
1123 	return false;
1124 }
1125 
1126 
isBlockInTOC(fl_BlockLayout * pBlock)1127 bool fl_TOCLayout::isBlockInTOC(fl_BlockLayout * pBlock)
1128 {
1129 	TOCEntry * pEntry = NULL;
1130 	pf_Frag_Strux* sdh = pBlock->getStruxDocHandle();
1131 	UT_sint32 i = 0;
1132 	for(i=0; i< m_vecEntries.getItemCount(); i++)
1133 	{
1134 
1135 		pEntry = m_vecEntries.getNthItem(i);
1136 		fl_BlockLayout *pBL = pEntry->getBlock();
1137 		if(pBL->getStruxDocHandle() == sdh)
1138 		{
1139 			return true;
1140 		}
1141 	}
1142 	return false;
1143 }
1144 
1145 
getTOCListLabel(fl_BlockLayout * pBlock)1146 UT_UTF8String & fl_TOCLayout::getTOCListLabel(fl_BlockLayout * pBlock)
1147 {
1148 	static UT_UTF8String str;
1149 	str.clear();
1150 	TOCEntry * pEntry = NULL;
1151 	pf_Frag_Strux* sdh = pBlock->getStruxDocHandle();
1152 	UT_sint32 i = 0;
1153 	bool bFound = false;
1154 	for(i=0; i< m_vecEntries.getItemCount(); i++)
1155 	{
1156 
1157 		pEntry = m_vecEntries.getNthItem(i);
1158 		fl_BlockLayout *pBL = pEntry->getBlock();
1159 		if(pBL->getStruxDocHandle() == sdh)
1160 		{
1161 			bFound = true;
1162 			break;
1163 		}
1164 	}
1165 	if(!bFound)
1166 	{
1167 		return str;
1168 	}
1169 	str = pEntry->getFullLabel();
1170 	return str;
1171 }
1172 
getMatchingBlock(fl_BlockLayout * pBlock)1173 fl_BlockLayout * fl_TOCLayout::getMatchingBlock(fl_BlockLayout * pBlock)
1174 {
1175 	return findMatchingBlock(pBlock);
1176 }
1177 
doclistener_changeStrux(const PX_ChangeRecord_StruxChange * pcrxc)1178 bool fl_TOCLayout::doclistener_changeStrux(const PX_ChangeRecord_StruxChange * pcrxc)
1179 {
1180 	UT_ASSERT(pcrxc->getType()==PX_ChangeRecord::PXT_ChangeStrux);
1181 
1182 
1183 	setAttrPropIndex(pcrxc->getIndexAP());
1184 	fp_Page * pPage = getFirstContainer()->getPage();
1185 	collapse();
1186 	lookupProperties();
1187 	_createTOCContainer();
1188 	_insertTOCContainer(static_cast<fp_TOCContainer *>(getLastContainer()));
1189 	fl_DocSectionLayout * pDSL = getDocSectionLayout();
1190 	pDSL->setNeedsSectionBreak(true,pPage);
1191 	return true;
1192 }
1193 
1194 
recalculateFields(UT_uint32 iUpdateCount)1195 bool fl_TOCLayout::recalculateFields(UT_uint32 iUpdateCount)
1196 {
1197 
1198 	bool bResult = false;
1199 	fl_ContainerLayout*	pBL = getFirstLayout();
1200 	while (pBL)
1201 	{
1202 		bResult = pBL->recalculateFields(iUpdateCount) || bResult;
1203 		pBL = pBL->getNext();
1204 	}
1205 	return bResult;
1206 }
1207 
1208 
markAllRunsDirty(void)1209 void fl_TOCLayout::markAllRunsDirty(void)
1210 {
1211 	fl_ContainerLayout*	pCL = getFirstLayout();
1212 	while (pCL)
1213 	{
1214 		pCL->markAllRunsDirty();
1215 		pCL = pCL->getNext();
1216 	}
1217 }
1218 
updateLayout(bool)1219 void fl_TOCLayout::updateLayout(bool /*bDoAll*/)
1220 {
1221 	if(needsReformat())
1222 	{
1223 		format();
1224 	}
1225 	m_vecFormatLayout.clear();
1226 	fl_ContainerLayout*	pBL = getFirstLayout();
1227 	while (pBL)
1228 	{
1229 		if (pBL->needsReformat())
1230 		{
1231 			pBL->format();
1232 		}
1233 
1234 		pBL = pBL->getNext();
1235 	}
1236 }
1237 
redrawUpdate(void)1238 void fl_TOCLayout::redrawUpdate(void)
1239 {
1240 	fl_ContainerLayout*	pBL = getFirstLayout();
1241 	while (pBL)
1242 	{
1243 		if (pBL->needsRedraw())
1244 		{
1245 			pBL->redrawUpdate();
1246 		}
1247 
1248 		pBL = pBL->getNext();
1249 	}
1250 }
1251 
1252 
doclistener_deleteStrux(const PX_ChangeRecord_Strux * pcrx)1253 bool fl_TOCLayout::doclistener_deleteStrux(const PX_ChangeRecord_Strux * pcrx)
1254 {
1255 	UT_UNUSED(pcrx);
1256 	UT_ASSERT(pcrx->getType()==PX_ChangeRecord::PXT_DeleteStrux);
1257 //
1258 // Remove all remaining structures
1259 //
1260 	fp_Page * pPage = getFirstContainer()->getPage();
1261 	collapse();
1262 //	UT_ASSERT(pcrx->getStruxType()== PTX_SectionTOC);
1263 //
1264 	fl_DocSectionLayout * pDSL = getDocSectionLayout();
1265 	myContainingLayout()->remove(this);
1266 	UT_sint32 iPage = getDocLayout()->findPage(pPage);
1267 	if(iPage >= 0)
1268 	{
1269 		pDSL->setNeedsSectionBreak(true,pPage);
1270 	}
1271 	else
1272 	{
1273 		pDSL->setNeedsSectionBreak(true,NULL);
1274 	}
1275 	delete this;			// TODO whoa!  this construct is VERY dangerous.
1276 
1277 	return true;
1278 }
1279 
createNewEntry(fl_BlockLayout * pNewBL)1280 TOCEntry * fl_TOCLayout::createNewEntry(fl_BlockLayout * pNewBL)
1281 {
1282 	UT_UTF8String sDispStyle("");
1283 	bool bHaveLabel = true;
1284 	FootnoteType iFType = FOOTNOTE_TYPE_NUMERIC;
1285 	UT_UTF8String sBefore;
1286 	UT_UTF8String sAfter;
1287 	bool bInherit = false;
1288 	UT_sint32 iStartAt = 0;
1289 	if(m_iCurrentLevel == 1)
1290 	{
1291 		sDispStyle = m_sDestStyle1;
1292 		bHaveLabel = m_bHasLabel1;
1293 		iFType = m_iLabType1;
1294 		sBefore = m_sLabBefore1;
1295 		sAfter = m_sLabAfter1;
1296 		bInherit = m_bInherit1;
1297 		iStartAt = m_iStartAt1;
1298 	}
1299 	else if( m_iCurrentLevel == 2)
1300 	{
1301 		sDispStyle = m_sDestStyle2;
1302 		bHaveLabel = m_bHasLabel2;
1303 		iFType = m_iLabType2;
1304 		sBefore = m_sLabBefore2;
1305 		sAfter = m_sLabAfter2;
1306 		bInherit = m_bInherit2;
1307 		iStartAt = m_iStartAt2;
1308 	}
1309 	else if( m_iCurrentLevel == 3)
1310 	{
1311 		sDispStyle = m_sDestStyle3;
1312 		bHaveLabel = m_bHasLabel3;
1313 		iFType = m_iLabType3;
1314 		sBefore = m_sLabBefore3;
1315 		sAfter = m_sLabAfter3;
1316 		bInherit = m_bInherit3;
1317 		iStartAt = m_iStartAt3;
1318 	}
1319 	else if( m_iCurrentLevel == 4)
1320 	{
1321 		sDispStyle = m_sDestStyle4;
1322 		bHaveLabel = m_bHasLabel4;
1323 		iFType = m_iLabType4;
1324 		sBefore = m_sLabBefore4;
1325 		sAfter = m_sLabAfter4;
1326 		bInherit = m_bInherit4;
1327 		iStartAt = m_iStartAt4;
1328 	}
1329 	else {
1330 		UT_ASSERT_NOT_REACHED();
1331 	}
1332 	TOCEntry * pNew = new TOCEntry(pNewBL,m_iCurrentLevel,
1333 								   sDispStyle,
1334 								   bHaveLabel,
1335 								   iFType,
1336 								   sBefore,
1337 								   sAfter,
1338 								   bInherit,
1339 								   iStartAt);
1340 	return pNew;
1341 }
1342 
1343 /*!
1344  * This method removes all layout structures contained by this layout
1345  * structure.
1346  */
_purgeLayout(void)1347 void fl_TOCLayout::_purgeLayout(void)
1348 {
1349 	UT_DEBUGMSG(("TOCLayout: purge \n"));
1350 	fl_ContainerLayout * pCL = getFirstLayout();
1351 	m_bDoingPurge = true;
1352 	while(pCL)
1353 	{
1354 		fl_ContainerLayout * pNext = pCL->getNext();
1355 		delete pCL;
1356 		pCL = pNext;
1357 	}
1358 	UT_VECTOR_PURGEALL(TOCEntry *, m_vecEntries);
1359 	m_vecEntries.clear();
1360 	m_bDoingPurge = false;
1361 	setFirstLayout(NULL);
1362 	setLastLayout(NULL);
1363 }
1364 
1365 
1366 /*!
1367  * This method creates a new TOC.
1368  */
_createTOCContainer(void)1369 void fl_TOCLayout::_createTOCContainer(void)
1370 {
1371 	lookupProperties();
1372 	UT_ASSERT(getFirstLayout() == NULL);
1373 	fp_TOCContainer * pTOCContainer = new fp_TOCContainer(static_cast<fl_SectionLayout *>(this));
1374 	setFirstContainer(pTOCContainer);
1375 	setLastContainer(pTOCContainer);
1376 	fl_ContainerLayout * pCL = myContainingLayout();
1377 	while(pCL!= NULL && pCL->getContainerType() != FL_CONTAINER_DOCSECTION)
1378 	{
1379 		pCL = pCL->myContainingLayout();
1380 	}
1381 	UT_ASSERT(pCL);
1382 
1383 	fp_Container * pCon = pCL->getLastContainer();
1384 	UT_ASSERT(pCon);
1385 	UT_sint32 iWidth = pCon->getWidth();
1386 	pTOCContainer->setWidth(iWidth);
1387 	if(m_bHasEndTOC)
1388 	{
1389 	    fillTOC();
1390 	}
1391 }
1392 
1393 /*!
1394   Create a new TOC container.
1395   \return The newly created TOC container
1396 */
getNewContainer(fp_Container *)1397 fp_Container* fl_TOCLayout::getNewContainer(fp_Container *)
1398 {
1399 	UT_DEBUGMSG(("creating new TOC Physical container\n"));
1400 	_createTOCContainer();
1401 	_insertTOCContainer(static_cast<fp_TOCContainer *>(getLastContainer()));
1402 	return static_cast<fp_Container *>(getLastContainer());
1403 }
1404 
1405 
1406 /*!
1407  * This method inserts the given TOCContainer into its correct place in the
1408  * Vertical container.
1409  */
_insertTOCContainer(fp_TOCContainer * pNewTOC)1410 void fl_TOCLayout::_insertTOCContainer( fp_TOCContainer * pNewTOC)
1411 {
1412 	fl_ContainerLayout * pUPCL = myContainingLayout();
1413 	fl_ContainerLayout * pPrevL = static_cast<fl_ContainerLayout *>(getPrev());
1414 	fp_Container * pPrevCon = NULL;
1415 	fp_Container * pUpCon = NULL;
1416 	if(pPrevL != NULL)
1417 	{
1418 		while(pPrevL && ((pPrevL->getContainerType() == FL_CONTAINER_FOOTNOTE) || pPrevL->getContainerType() == FL_CONTAINER_ENDNOTE))
1419 		{
1420 			pPrevL = pPrevL->getPrev();
1421 		}
1422 		if(pPrevL)
1423 		{
1424 			if(pPrevL->getContainerType() == FL_CONTAINER_TABLE)
1425 			{
1426 //
1427 // Handle if prev container is table that is broken across a page
1428 //
1429 				fl_TableLayout * pTL = static_cast<fl_TableLayout *>(pPrevL);
1430 				fp_TableContainer * pTC = static_cast<fp_TableContainer *>(pTL->getFirstContainer());
1431 				fp_TableContainer * pFirst = pTC->getFirstBrokenTable();
1432 				fp_TableContainer * pLast = pTC->getLastBrokenTable();
1433 				if((pLast != NULL) && pLast != pFirst)
1434 				{
1435 					pPrevCon = static_cast<fp_Container *>(pLast);
1436 					pUpCon = pLast->getContainer();
1437 				}
1438 				else
1439 				{
1440 					pPrevCon = pPrevL->getLastContainer();
1441 					pUpCon = pPrevCon->getContainer();
1442 				}
1443 			}
1444 			else
1445 			{
1446 				pPrevCon = pPrevL->getLastContainer();
1447 				if(pPrevCon)
1448 				{
1449 					pUpCon = pPrevCon->getContainer();
1450 				}
1451 				else if(pPrevL->getPrev() == NULL)
1452 				{
1453 					pUpCon = myContainingLayout()->getFirstContainer();
1454 				}
1455 				else
1456 				{
1457 					pUpCon = myContainingLayout()->getFirstContainer();
1458 				}
1459 			}
1460 		}
1461 		else
1462 		{
1463 			pUpCon = pUPCL->getLastContainer();
1464 		}
1465 		UT_return_if_fail(pUpCon);
1466 	}
1467 	else
1468 	{
1469 		pUpCon = pUPCL->getLastContainer();
1470 		UT_return_if_fail(pUpCon);
1471 	}
1472 	if(pPrevL == NULL)
1473 	{
1474 		xxx_UT_DEBUGMSG(("SEVIOR!!!!!!!!!! New TOC %x added into %x \n",pNewTOC,pUpCon));
1475 		pUpCon->addCon(pNewTOC);
1476 		pNewTOC->setContainer(pUpCon);
1477 ;
1478 	}
1479 	else
1480 	{
1481 		UT_sint32 i = pUpCon->findCon(pPrevCon);
1482 		xxx_UT_DEBUGMSG(("SEVIOR!!!!!!!!!! New TOC %x inserted into %x \n",pNewTOC,pUpCon));
1483 		if(i >= 0 && (i+1) < pUpCon->countCons())
1484 		{
1485 			pUpCon->insertConAt(pNewTOC,i+1);
1486 			pNewTOC->setContainer(pUpCon);
1487 		}
1488 		else if( i >=0 &&  (i+ 1) == pUpCon->countCons())
1489 		{
1490 			pUpCon->addCon(pNewTOC);
1491 			pNewTOC->setContainer(pUpCon);
1492 		}
1493 		else
1494 		{
1495 			UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
1496 		}
1497 	}
1498 }
1499 
1500 
format(void)1501 void fl_TOCLayout::format(void)
1502 {
1503 	xxx_UT_DEBUGMSG(("SEVIOR: Formatting TOC container is %x \n",getFirstContainer()));
1504 	if(getFirstContainer() == NULL)
1505 	{
1506 		getNewContainer();
1507 	}
1508 	fl_ContainerLayout*	pBL = getFirstLayout();
1509 
1510 	while (pBL)
1511 	{
1512 		pBL->format();
1513 		UT_sint32 count = 0;
1514 		while(pBL->getLastContainer() == NULL || pBL->getFirstContainer()==NULL)
1515 		{
1516 			UT_DEBUGMSG(("Error formatting a block try again \n"));
1517 			count = count + 1;
1518 			pBL->format();
1519 			if(count > 3)
1520 			{
1521 				UT_DEBUGMSG(("Give up trying to format. Hope for the best :-( \n"));
1522 				break;
1523 			}
1524 		}
1525 		pBL = pBL->getNext();
1526 	}
1527 	static_cast<fp_TOCContainer *>(getFirstContainer())->layout();
1528 	m_bNeedsFormat = false;
1529 	m_bNeedsReformat = false;
1530 }
1531 
getDefaultHeading()1532 std::string fl_TOCLayout::getDefaultHeading()
1533 {
1534 	const XAP_StringSet * pSS = XAP_App::getApp()->getStringSet();
1535 	std::string sDefaultHeading;
1536 	pSS->getValueUTF8(AP_STRING_ID_TOC_TocHeading, sDefaultHeading);
1537 	return sDefaultHeading;
1538 }
1539 
getDefaultSourceStyle(UT_uint32 iLevel)1540 UT_UTF8String fl_TOCLayout::getDefaultSourceStyle(UT_uint32 iLevel)
1541 {
1542 	// fetch the default TOC destination style from the buildin defaults
1543 	UT_UTF8String sStyle = UT_UTF8String_sprintf("toc-source-style%d", iLevel);
1544 	const PP_Property* pProp = PP_lookupProperty(sStyle.utf8_str());
1545 	if (pProp)
1546 		return pProp->getInitial();
1547 	UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
1548 
1549 	// we're desperate, just use something, anything...
1550 	return UT_UTF8String_sprintf("Heading %d", iLevel);
1551 }
1552 
getDefaultDestStyle(UT_uint32 iLevel)1553 UT_UTF8String fl_TOCLayout::getDefaultDestStyle(UT_uint32 iLevel)
1554 {
1555 	// fetch the default TOC destination style from the buildin defaults
1556 	UT_UTF8String sStyle = UT_UTF8String_sprintf("toc-dest-style%d", iLevel);
1557 	const PP_Property* pProp = PP_lookupProperty(sStyle.utf8_str());
1558 	if (pProp)
1559 		return pProp->getInitial();
1560 	UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
1561 
1562 	// we're desperate, just use something, anything...
1563 	return UT_UTF8String_sprintf("Contents %d", iLevel);
1564 }
1565 
1566 /*!
1567     this function is only to be called by fl_ContainerLayout::lookupProperties()
1568     all other code must call lookupProperties() instead
1569 */
_lookupProperties(const PP_AttrProp * pSectionAP)1570 void fl_TOCLayout::_lookupProperties(const PP_AttrProp* pSectionAP)
1571 {
1572 	UT_return_if_fail(pSectionAP);
1573 
1574 	// I can't think of any properties we need for now.
1575 	// If we need any later, we'll add them. -PL
1576 	const gchar *pszTOCPID = NULL;
1577 	if(!pSectionAP || !pSectionAP->getProperty("toc-id",pszTOCPID))
1578 	{
1579 		m_iTOCPID = 0;
1580 	}
1581 	else
1582 	{
1583 		m_iTOCPID = atoi(pszTOCPID);
1584 	}
1585 
1586 	m_sNumOff1 = "0.5in";
1587 	m_sNumOff2 = "0.5in";
1588 	m_sNumOff3 = "0.5in";
1589 	m_sNumOff4 = "0.5in";
1590 
1591 
1592 	const gchar *pszINDENT = NULL;
1593 	if(!pSectionAP || !pSectionAP->getProperty("toc-indent1",pszINDENT))
1594 	{
1595 		m_sNumOff1 = "0.5in";
1596 	}
1597 	else
1598 	{
1599 		m_sNumOff1 = pszINDENT;
1600 	}
1601 	pszINDENT = NULL;
1602 	if(!pSectionAP || !pSectionAP->getProperty("toc-indent2",pszINDENT))
1603 	{
1604 		m_sNumOff2 = "0.5in";
1605 	}
1606 	else
1607 	{
1608 		m_sNumOff2 = pszINDENT;
1609 	}
1610 
1611 	pszINDENT = NULL;
1612 	if(!pSectionAP || !pSectionAP->getProperty("toc-indent3",pszINDENT))
1613 	{
1614 		m_sNumOff3 = "0.5in";
1615 	}
1616 	else
1617 	{
1618 		m_sNumOff3 = pszINDENT;
1619 	}
1620 
1621 	pszINDENT = NULL;
1622 	if(!pSectionAP || !pSectionAP->getProperty("toc-indent4",pszINDENT))
1623 	{
1624 		m_sNumOff4 = "0.5in";
1625 	}
1626 	else
1627 	{
1628 		m_sNumOff4 = pszINDENT;
1629 	}
1630 
1631 	const gchar *pszTOCSRC = NULL;
1632 	if(!pSectionAP || !pSectionAP->getProperty("toc-source-style1",pszTOCSRC))
1633 	{
1634 		m_sSourceStyle1 = getDefaultSourceStyle(1);
1635 	}
1636 	else
1637 	{
1638 		m_sSourceStyle1 = pszTOCSRC;
1639 	}
1640 	pszTOCSRC = NULL;
1641 	if(!pSectionAP || !pSectionAP->getProperty("toc-source-style2",pszTOCSRC))
1642 	{
1643 		m_sSourceStyle2 = getDefaultSourceStyle(2);
1644 	}
1645 	else
1646 	{
1647 		m_sSourceStyle2 = pszTOCSRC;
1648 	}
1649 	pszTOCSRC = NULL;
1650 	if(!pSectionAP || !pSectionAP->getProperty("toc-source-style3",pszTOCSRC))
1651 	{
1652 		m_sSourceStyle3 = getDefaultSourceStyle(3);
1653 	}
1654 	else
1655 	{
1656 		m_sSourceStyle3 = pszTOCSRC;
1657 	}
1658 	pszTOCSRC = NULL;
1659 	if(!pSectionAP || !pSectionAP->getProperty("toc-source-style4",pszTOCSRC))
1660 	{
1661 		m_sSourceStyle4 = getDefaultSourceStyle(4);
1662 	}
1663 	else
1664 	{
1665 		m_sSourceStyle4 = pszTOCSRC;
1666 	}
1667 	const gchar * pszTOCDEST = NULL;
1668 	if(!pSectionAP || !pSectionAP->getProperty("toc-dest-style1",pszTOCDEST))
1669 	{
1670 		m_sDestStyle1 = getDefaultDestStyle(1);
1671 	}
1672 	else
1673 	{
1674 		m_sDestStyle1 = pszTOCDEST;
1675 	}
1676 	pszTOCDEST = NULL;
1677 	if(!pSectionAP || !pSectionAP->getProperty("toc-dest-style2",pszTOCDEST))
1678 	{
1679 		m_sDestStyle2 = getDefaultDestStyle(2);
1680 	}
1681 	else
1682 	{
1683 		m_sDestStyle2 = pszTOCDEST;
1684 	}
1685 	pszTOCDEST = NULL;
1686 	if(!pSectionAP || !pSectionAP->getProperty("toc-dest-style3",pszTOCDEST))
1687 	{
1688 		m_sDestStyle3 = getDefaultDestStyle(3);
1689 	}
1690 	else
1691 	{
1692 		m_sDestStyle3 = pszTOCDEST;
1693 	}
1694 	pszTOCDEST = NULL;
1695 	if(!pSectionAP || !pSectionAP->getProperty("toc-dest-style4",pszTOCDEST))
1696 	{
1697 		m_sDestStyle4 = getDefaultDestStyle(4);
1698 	}
1699 	else
1700 	{
1701 		m_sDestStyle4 = pszTOCDEST;
1702 	}
1703 
1704 	const gchar * pszTOCHEADING = NULL;
1705 	if(!pSectionAP || !pSectionAP->getProperty("toc-heading",pszTOCHEADING))
1706 	{
1707 		m_sTOCHeading = getDefaultHeading();
1708 	}
1709 	else
1710 	{
1711 		m_sTOCHeading = pszTOCHEADING;
1712 	}
1713 
1714 	const gchar * pszTOCHEADINGStyle = NULL;
1715 	if(!pSectionAP || !pSectionAP->getProperty("toc-heading-style",pszTOCHEADINGStyle))
1716 	{
1717 		m_sTOCHeadingStyle = "Contents Header";
1718 	}
1719 	else
1720 	{
1721 		m_sTOCHeadingStyle = pszTOCHEADINGStyle;
1722 	}
1723 
1724 
1725 	const gchar * pszTOCHASHEADING = NULL;
1726 	if(!pSectionAP || !pSectionAP->getProperty("toc-has-heading",pszTOCHASHEADING))
1727 	{
1728 		m_bTOCHeading = true;
1729 	}
1730 	else
1731 	{
1732 		if(g_ascii_strcasecmp(pszTOCHASHEADING,"1") == 0)
1733 		{
1734 			m_bTOCHeading = true;
1735 		}
1736 		else
1737 		{
1738 			m_bTOCHeading = false;
1739 		}
1740 	}
1741 //
1742 // TOC Label
1743 //
1744 	const gchar * pszTOCLABEL = NULL;
1745 	if(!pSectionAP || !pSectionAP->getProperty("toc-has-label1",pszTOCLABEL))
1746 	{
1747 		m_bHasLabel1 = true;
1748 	}
1749 	else
1750 	{
1751 		if(g_ascii_strcasecmp(pszTOCLABEL,"1") == 0)
1752 		{
1753 			m_bHasLabel1 = true;
1754 		}
1755 		else
1756 		{
1757 			m_bHasLabel1 = false;
1758 		}
1759 	}
1760 	pszTOCLABEL = NULL;
1761 	if(!pSectionAP || !pSectionAP->getProperty("toc-has-label2",pszTOCLABEL))
1762 	{
1763 		m_bHasLabel2 = true;
1764 	}
1765 	else
1766 	{
1767 		if(g_ascii_strcasecmp(pszTOCLABEL,"1") == 0)
1768 		{
1769 			m_bHasLabel2 = true;
1770 		}
1771 		else
1772 		{
1773 			m_bHasLabel2 = false;
1774 		}
1775 	}
1776 	pszTOCLABEL = NULL;
1777 	if(!pSectionAP || !pSectionAP->getProperty("toc-has-label3",pszTOCLABEL))
1778 	{
1779 		m_bHasLabel3 = true;
1780 	}
1781 	else
1782 	{
1783 		if(g_ascii_strcasecmp(pszTOCLABEL,"1") == 0)
1784 		{
1785 			m_bHasLabel3 = true;
1786 		}
1787 		else
1788 		{
1789 			m_bHasLabel3 = false;
1790 		}
1791 	}
1792 	pszTOCLABEL = NULL;
1793 	if(!pSectionAP || !pSectionAP->getProperty("toc-has-label4",pszTOCLABEL))
1794 	{
1795 		m_bHasLabel4 = true;
1796 	}
1797 	else
1798 	{
1799 		if(g_ascii_strcasecmp(pszTOCLABEL,"1") == 0)
1800 		{
1801 			m_bHasLabel4 = true;
1802 		}
1803 		else
1804 		{
1805 			m_bHasLabel4 = false;
1806 		}
1807 	}
1808 //
1809 // TOC Label Inherits
1810 //
1811 	const gchar * pszTOCLABELINHERITS = NULL;
1812 	if(!pSectionAP || !pSectionAP->getProperty("toc-label-inherits1",pszTOCLABELINHERITS))
1813 	{
1814 		m_bInherit1 = true;
1815 	}
1816 	else
1817 	{
1818 		if(g_ascii_strcasecmp(pszTOCLABELINHERITS,"1") == 0)
1819 		{
1820 			m_bInherit1 = true;
1821 		}
1822 		else
1823 		{
1824 			m_bInherit1 = false;
1825 		}
1826 	}
1827 	pszTOCLABELINHERITS = NULL;
1828 	if(!pSectionAP || !pSectionAP->getProperty("toc-label-inherits2",pszTOCLABELINHERITS))
1829 	{
1830 		m_bInherit2 = true;
1831 	}
1832 	else
1833 	{
1834 		if(g_ascii_strcasecmp(pszTOCLABELINHERITS,"1") == 0)
1835 		{
1836 			m_bInherit2 = true;
1837 		}
1838 		else
1839 		{
1840 			m_bInherit2 = false;
1841 		}
1842 	}
1843 	pszTOCLABELINHERITS = NULL;
1844 	if(!pSectionAP || !pSectionAP->getProperty("toc-label-inherits3",pszTOCLABELINHERITS))
1845 	{
1846 		m_bInherit3 = true;
1847 	}
1848 	else
1849 	{
1850 		if(g_ascii_strcasecmp(pszTOCLABELINHERITS,"1") == 0)
1851 		{
1852 			m_bInherit3 = true;
1853 		}
1854 		else
1855 		{
1856 			m_bInherit3 = false;
1857 		}
1858 	}
1859 	pszTOCLABELINHERITS = NULL;
1860 	if(!pSectionAP || !pSectionAP->getProperty("toc-label-inherits4",pszTOCLABELINHERITS))
1861 	{
1862 		m_bInherit4 = true;
1863 	}
1864 	else
1865 	{
1866 		if(g_ascii_strcasecmp(pszTOCLABELINHERITS,"1") == 0)
1867 		{
1868 			m_bInherit4 = true;
1869 		}
1870 		else
1871 		{
1872 			m_bInherit4 = false;
1873 		}
1874 	}
1875 //
1876 // TOC Label Type
1877 //
1878 	const gchar * pszTOCLABELTYPE = NULL;
1879 	if(!pSectionAP || !pSectionAP->getProperty("toc-label-type1",pszTOCLABELTYPE))
1880 	{
1881 		m_iLabType1 = FOOTNOTE_TYPE_NUMERIC;
1882 	}
1883 	else
1884 	{
1885 		m_iLabType1 = m_pLayout->FootnoteTypeFromString(pszTOCLABELTYPE);
1886 	}
1887 	pszTOCLABELTYPE = NULL;
1888 	if(!pSectionAP || !pSectionAP->getProperty("toc-label-type2",pszTOCLABELTYPE))
1889 	{
1890 		m_iLabType2 = FOOTNOTE_TYPE_NUMERIC;
1891 	}
1892 	else
1893 	{
1894 		m_iLabType2 = m_pLayout->FootnoteTypeFromString(pszTOCLABELTYPE);
1895 	}
1896 	pszTOCLABELTYPE = NULL;
1897 	if(!pSectionAP || !pSectionAP->getProperty("toc-label-type3",pszTOCLABELTYPE))
1898 	{
1899 		m_iLabType3 = FOOTNOTE_TYPE_NUMERIC;
1900 	}
1901 	else
1902 	{
1903 		m_iLabType3 = m_pLayout->FootnoteTypeFromString(pszTOCLABELTYPE);
1904 	}
1905 	pszTOCLABELTYPE = NULL;
1906 	if(!pSectionAP || !pSectionAP->getProperty("toc-label-type4",pszTOCLABELTYPE))
1907 	{
1908 		m_iLabType4 = FOOTNOTE_TYPE_NUMERIC;
1909 	}
1910 	else
1911 	{
1912 		m_iLabType4 = m_pLayout->FootnoteTypeFromString(pszTOCLABELTYPE);
1913 	}
1914 //
1915 // TOC Label Before Text
1916 //
1917 	const gchar * pszTOCSTRBEFORE = NULL;
1918 	if(!pSectionAP || !pSectionAP->getProperty("toc-label-before1",pszTOCSTRBEFORE))
1919 	{
1920 		m_sLabBefore1 = "";
1921 	}
1922 	else
1923 	{
1924 		m_sLabBefore1 = pszTOCSTRBEFORE;
1925 	}
1926 	pszTOCSTRBEFORE = NULL;
1927 	if(!pSectionAP || !pSectionAP->getProperty("toc-label-before2",pszTOCSTRBEFORE))
1928 	{
1929 		m_sLabBefore2 = "";
1930 	}
1931 	else
1932 	{
1933 		m_sLabBefore2 = pszTOCSTRBEFORE;
1934 	}
1935 	pszTOCSTRBEFORE = NULL;
1936 	if(!pSectionAP || !pSectionAP->getProperty("toc-label-before3",pszTOCSTRBEFORE))
1937 	{
1938 		m_sLabBefore3 = "";
1939 	}
1940 	else
1941 	{
1942 		m_sLabBefore3 = pszTOCSTRBEFORE;
1943 	}
1944 	pszTOCSTRBEFORE = NULL;
1945 	if(!pSectionAP || !pSectionAP->getProperty("toc-label-before4",pszTOCSTRBEFORE))
1946 	{
1947 		m_sLabBefore4 = "";
1948 	}
1949 	else
1950 	{
1951 		m_sLabBefore4 = pszTOCSTRBEFORE;
1952 	}
1953 //
1954 // TOC Label After Text
1955 //
1956 	const gchar * pszTOCSTRAFTER = NULL;
1957 	if(!pSectionAP || !pSectionAP->getProperty("toc-label-after1",pszTOCSTRAFTER))
1958 	{
1959 		m_sLabAfter1 = "";
1960 	}
1961 	else
1962 	{
1963 		m_sLabAfter1 = pszTOCSTRAFTER;
1964 	}
1965 	pszTOCSTRAFTER = NULL;
1966 	if(!pSectionAP || !pSectionAP->getProperty("toc-label-after2",pszTOCSTRAFTER))
1967 	{
1968 		m_sLabAfter2 = "";
1969 	}
1970 	else
1971 	{
1972 		m_sLabAfter2 = pszTOCSTRAFTER;
1973 	}
1974 	pszTOCSTRAFTER = NULL;
1975 	if(!pSectionAP || !pSectionAP->getProperty("toc-label-after2",pszTOCSTRAFTER))
1976 	{
1977 		m_sLabAfter2 = "";
1978 	}
1979 	else
1980 	{
1981 		m_sLabAfter3 = pszTOCSTRAFTER;
1982 	}
1983 	pszTOCSTRAFTER = NULL;
1984 	if(!pSectionAP || !pSectionAP->getProperty("toc-label-after4",pszTOCSTRAFTER))
1985 	{
1986 		m_sLabAfter4 = "";
1987 	}
1988 	else
1989 	{
1990 		m_sLabAfter4 = pszTOCSTRAFTER;
1991 	}
1992 //
1993 // TOC Label Initial Value
1994 //
1995 	const gchar * pszTOCLABELSTART = NULL;
1996 	if(!pSectionAP || !pSectionAP->getProperty("toc-label-start1",pszTOCLABELSTART))
1997 	{
1998 		m_iStartAt1 = 1;
1999 	}
2000 	else
2001 	{
2002 		m_iStartAt1 = atoi(pszTOCLABELSTART);
2003 	}
2004 	pszTOCLABELSTART = NULL;
2005 	if(!pSectionAP || !pSectionAP->getProperty("toc-label-start2",pszTOCLABELSTART))
2006 	{
2007 		m_iStartAt2 = 1;
2008 	}
2009 	else
2010 	{
2011 		m_iStartAt2 = atoi(pszTOCLABELSTART);
2012 	}
2013 	pszTOCLABELSTART = NULL;
2014 	if(!pSectionAP || !pSectionAP->getProperty("toc-label-start3",pszTOCLABELSTART))
2015 	{
2016 		m_iStartAt3 = 1;
2017 	}
2018 	else
2019 	{
2020 		m_iStartAt3 = atoi(pszTOCLABELSTART);
2021 	}
2022 	pszTOCLABELSTART = NULL;
2023 	if(!pSectionAP || !pSectionAP->getProperty("toc-label-start4",pszTOCLABELSTART))
2024 	{
2025 		m_iStartAt4 = 1;
2026 	}
2027 	else
2028 	{
2029 		m_iStartAt4 = atoi(pszTOCLABELSTART);
2030 	}
2031 //
2032 // TOC Page Number Type
2033 //
2034 	const gchar * pszTOCPAGETYPE = NULL;
2035 	if(!pSectionAP || !pSectionAP->getProperty("toc-page-type1",pszTOCPAGETYPE))
2036 	{
2037 		m_iNumType1 = FOOTNOTE_TYPE_NUMERIC;
2038 	}
2039 	else
2040 	{
2041 		m_iNumType1 = m_pLayout->FootnoteTypeFromString(pszTOCPAGETYPE);
2042 	}
2043 	pszTOCPAGETYPE = NULL;
2044 	if(!pSectionAP || !pSectionAP->getProperty("toc-page-type2",pszTOCPAGETYPE))
2045 	{
2046 		m_iNumType2 = FOOTNOTE_TYPE_NUMERIC;
2047 	}
2048 	else
2049 	{
2050 		m_iNumType2 = m_pLayout->FootnoteTypeFromString(pszTOCPAGETYPE);
2051 	}
2052 	pszTOCPAGETYPE = NULL;
2053 	if(!pSectionAP || !pSectionAP->getProperty("toc-page-type3",pszTOCPAGETYPE))
2054 	{
2055 		m_iNumType3 = FOOTNOTE_TYPE_NUMERIC;
2056 	}
2057 	else
2058 	{
2059 		m_iNumType3 = m_pLayout->FootnoteTypeFromString(pszTOCPAGETYPE);
2060 	}
2061 	pszTOCPAGETYPE = NULL;
2062 	if(!pSectionAP || !pSectionAP->getProperty("toc-page-type4",pszTOCPAGETYPE))
2063 	{
2064 		m_iNumType4 = FOOTNOTE_TYPE_NUMERIC;
2065 	}
2066 	else
2067 	{
2068 		m_iNumType4 = m_pLayout->FootnoteTypeFromString(pszTOCPAGETYPE);
2069 	}
2070 //
2071 // TOC TAB leader
2072 //
2073 	const gchar * pszTOCTABTYPE = NULL;
2074 	if(!pSectionAP || !pSectionAP->getProperty("toc-tab-leader1",pszTOCTABTYPE))
2075 	{
2076 		m_iTabLeader1 = FL_LEADER_DOT;
2077 	}
2078 	else
2079 	{
2080 		if(g_ascii_strcasecmp(pszTOCTABTYPE,"none") == 0)
2081 		{
2082 			m_iTabLeader1 = FL_LEADER_NONE;
2083 		}
2084 		else if(g_ascii_strcasecmp(pszTOCTABTYPE,"dot") == 0)
2085 		{
2086 			m_iTabLeader1 = FL_LEADER_DOT;
2087 		}
2088 		else if(g_ascii_strcasecmp(pszTOCTABTYPE,"hyphen") == 0)
2089 		{
2090 			m_iTabLeader1 = FL_LEADER_HYPHEN;
2091 		}
2092 		else if(g_ascii_strcasecmp(pszTOCTABTYPE,"underline") == 0)
2093 		{
2094 			m_iTabLeader1 = FL_LEADER_UNDERLINE;
2095 		}
2096 		else
2097 		{
2098 			m_iTabLeader1 = FL_LEADER_DOT;
2099 		}
2100 	}
2101 	pszTOCTABTYPE = NULL;
2102 	if(!pSectionAP || !pSectionAP->getProperty("toc-tab-leader2",pszTOCTABTYPE))
2103 	{
2104 		m_iTabLeader2 = FL_LEADER_DOT;
2105 	}
2106 	else
2107 	{
2108 		if(g_ascii_strcasecmp(pszTOCTABTYPE,"none") == 0)
2109 		{
2110 			m_iTabLeader2 = FL_LEADER_NONE;
2111 		}
2112 		else if(g_ascii_strcasecmp(pszTOCTABTYPE,"dot") == 0)
2113 		{
2114 			m_iTabLeader2 = FL_LEADER_DOT;
2115 		}
2116 		else if(g_ascii_strcasecmp(pszTOCTABTYPE,"hyphen") == 0)
2117 		{
2118 			m_iTabLeader2 = FL_LEADER_HYPHEN;
2119 		}
2120 		else if(g_ascii_strcasecmp(pszTOCTABTYPE,"underline") == 0)
2121 		{
2122 			m_iTabLeader2 = FL_LEADER_UNDERLINE;
2123 		}
2124 		else
2125 		{
2126 			m_iTabLeader2 = FL_LEADER_DOT;
2127 		}
2128 	}
2129 	pszTOCTABTYPE = NULL;
2130 	if(!pSectionAP || !pSectionAP->getProperty("toc-tab-leader3",pszTOCTABTYPE))
2131 	{
2132 		m_iTabLeader3 = FL_LEADER_DOT;
2133 	}
2134 	else
2135 	{
2136 		if(g_ascii_strcasecmp(pszTOCTABTYPE,"none") == 0)
2137 		{
2138 			m_iTabLeader3 = FL_LEADER_NONE;
2139 		}
2140 		else if(g_ascii_strcasecmp(pszTOCTABTYPE,"dot") == 0)
2141 		{
2142 			m_iTabLeader3 = FL_LEADER_DOT;
2143 		}
2144 		else if(g_ascii_strcasecmp(pszTOCTABTYPE,"hyphen") == 0)
2145 		{
2146 			m_iTabLeader3 = FL_LEADER_HYPHEN;
2147 		}
2148 		else if(g_ascii_strcasecmp(pszTOCTABTYPE,"underline") == 0)
2149 		{
2150 			m_iTabLeader3 = FL_LEADER_UNDERLINE;
2151 		}
2152 		else
2153 		{
2154 			m_iTabLeader3 = FL_LEADER_DOT;
2155 		}
2156 	}
2157 	pszTOCTABTYPE = NULL;
2158 	if(!pSectionAP || !pSectionAP->getProperty("toc-tab-leader4",pszTOCTABTYPE))
2159 	{
2160 		m_iTabLeader4 = FL_LEADER_DOT;
2161 	}
2162 	else
2163 	{
2164 		if(g_ascii_strcasecmp(pszTOCTABTYPE,"none") == 0)
2165 		{
2166 			m_iTabLeader4 = FL_LEADER_NONE;
2167 		}
2168 		else if(g_ascii_strcasecmp(pszTOCTABTYPE,"dot") == 0)
2169 		{
2170 			m_iTabLeader4 = FL_LEADER_DOT;
2171 		}
2172 		else if(g_ascii_strcasecmp(pszTOCTABTYPE,"hyphen") == 0)
2173 		{
2174 			m_iTabLeader4 = FL_LEADER_HYPHEN;
2175 		}
2176 		else if(g_ascii_strcasecmp(pszTOCTABTYPE,"underline") == 0)
2177 		{
2178 			m_iTabLeader4 = FL_LEADER_UNDERLINE;
2179 		}
2180 		else
2181 		{
2182 			m_iTabLeader4 = FL_LEADER_DOT;
2183 		}
2184 	}
2185 
2186 	pszTOCTABTYPE = NULL;
2187 	if(pSectionAP && pSectionAP->getProperty("toc-range-bookmark",pszTOCTABTYPE))
2188 	{
2189 		m_sRangeBookmark = pszTOCTABTYPE;
2190 	}
2191 	else
2192 	{
2193 		m_sRangeBookmark.clear();
2194 	}
2195 }
2196 
_localCollapse(void)2197 void fl_TOCLayout::_localCollapse(void)
2198 {
2199 	// ClearScreen on our Cell. One Cell per layout.
2200 	fp_TOCContainer *pTC = static_cast<fp_TOCContainer *>(getFirstContainer());
2201 	if (pTC)
2202 	{
2203 		pTC->clearScreen();
2204 	}
2205 
2206 	// get rid of all the layout information for every containerLayout
2207 	fl_ContainerLayout*	pCL = getFirstLayout();
2208 	while (pCL)
2209 	{
2210 		pCL->collapse();
2211 		pCL = pCL->getNext();
2212 	}
2213 	m_bNeedsReformat = true;
2214 }
2215 
collapse(void)2216 void fl_TOCLayout::collapse(void)
2217 {
2218 	fp_TOCContainer *pTC = static_cast<fp_TOCContainer *>(getFirstContainer());
2219 	if(pTC)
2220 	{
2221 		fp_TOCContainer * pBroke = pTC->getFirstBrokenTOC();
2222 		while(pBroke)
2223 		{
2224 			xxx_UT_DEBUGMSG(("DOing clearscreen on broken toc in collapse \n"));
2225 			pBroke->clearScreen();
2226 			pBroke = static_cast<fp_TOCContainer *>(pBroke->getNext());
2227 		}
2228 		pTC->deleteBrokenTOCs(true);
2229 		pTC->clearScreen();
2230 	}
2231 	_localCollapse();
2232 	if (pTC)
2233 	{
2234 //
2235 // remove it from the linked list.
2236 //
2237 		fp_Container * pPrev = static_cast<fp_Container *>(pTC->getPrev());
2238 		if(pPrev)
2239 		{
2240 			pPrev->setNext(pTC->getNext());
2241 		}
2242 		if(pTC->getNext())
2243 		{
2244 			pTC->getNext()->setPrev(pPrev);
2245 		}
2246 //
2247 // Remove it from the vertical container that contains it.
2248 //
2249 		static_cast<fp_VerticalContainer *>(pTC->getContainer())->removeContainer(pTC);
2250 		pTC->setContainer(NULL);
2251 		delete pTC;
2252 	}
2253 	setFirstContainer(NULL);
2254 	setLastContainer(NULL);
2255 	_purgeLayout();
2256 	setNeedsReformat(0);
2257 }
2258 
2259 
2260 //////////////////////////////////////////////////////////////////
2261 //////////////////////////////////////////////////////////////////
2262 
fl_TOCListener(fl_TOCLayout * pTOCL,fl_BlockLayout * pPrevBL,PD_Style * pStyle)2263 fl_TOCListener::fl_TOCListener(fl_TOCLayout* pTOCL, fl_BlockLayout* pPrevBL, PD_Style * pStyle)
2264 {
2265 	UT_ASSERT(pTOCL);
2266 
2267 	m_pDoc = pTOCL->getDocLayout()->getDocument();
2268 	m_pTOCL = pTOCL;
2269 	m_pPrevBL = pPrevBL;
2270 	m_bListening = false;
2271 	m_pCurrentBL = NULL;
2272 	m_pStyle = pStyle;
2273 	// Mark this style as used, so it will be available in the list of used styles when
2274 	// exporters need to export this TOC
2275 	m_pStyle->used(1);
2276 }
2277 
~fl_TOCListener()2278 fl_TOCListener::~fl_TOCListener()
2279 {
2280 }
2281 
populate(fl_ContainerLayout * sfh,const PX_ChangeRecord * pcr)2282 bool fl_TOCListener::populate(fl_ContainerLayout* sfh,
2283 								 const PX_ChangeRecord * pcr)
2284 {
2285 	if (!m_bListening)
2286 	{
2287 		return true;
2288 	}
2289 
2290 	UT_ASSERT(m_pTOCL);
2291 
2292 	bool bResult = false;
2293 	//FV_View* pView = m_pTOCL->getDocLayout()->getView();
2294 	switch (pcr->getType())
2295 	{
2296 	case PX_ChangeRecord::PXT_InsertSpan:
2297 	{
2298 		const PX_ChangeRecord_Span * pcrs = static_cast<const PX_ChangeRecord_Span *> (pcr);
2299 
2300 		{
2301 			UT_UNUSED(sfh);
2302 			UT_ASSERT(static_cast<const fl_Layout *>(sfh)->getType() == PTX_Block);
2303 			UT_ASSERT(m_pCurrentBL == (static_cast<const fl_ContainerLayout *>(sfh)));
2304 		}
2305 		PT_BlockOffset blockOffset = pcrs->getBlockOffset();
2306 		UT_uint32 len = pcrs->getLength();
2307 
2308 
2309 		bResult = static_cast<fl_BlockLayout *>(m_pCurrentBL)->doclistener_populateSpan(pcrs, blockOffset, len);
2310 		goto finish_up;
2311 	}
2312 
2313 	case PX_ChangeRecord::PXT_InsertObject:
2314 	{
2315 		const PX_ChangeRecord_Object * pcro = static_cast<const PX_ChangeRecord_Object *>(pcr);
2316 
2317 		{
2318 			UT_ASSERT(static_cast<const fl_Layout *>(sfh)->getType() == PTX_Block);
2319 			UT_ASSERT(m_pCurrentBL == (static_cast<const fl_ContainerLayout *>(sfh)));
2320 		}
2321 		PT_BlockOffset blockOffset = pcro->getBlockOffset();
2322 
2323 // sterwill -- is this call to getSectionLayout() needed?  pBLSL is not used.
2324 
2325 //			fl_SectionLayout* pBLSL = m_pCurrentBL->getSectionLayout();
2326 		bResult = static_cast<fl_BlockLayout *>(m_pCurrentBL)->doclistener_populateObject(blockOffset,pcro);
2327 		goto finish_up;
2328 	}
2329 	default:
2330 		UT_DEBUGMSG(("Unknown Change record = %d \n",pcr->getType()));
2331 		return true;
2332 	}
2333 
2334  finish_up:
2335 	return bResult;
2336 }
2337 
populateStrux(pf_Frag_Strux * sdh,const PX_ChangeRecord * pcr,fl_ContainerLayout ** psfh)2338 bool fl_TOCListener::populateStrux(pf_Frag_Strux* sdh,
2339 									  const PX_ChangeRecord * pcr,
2340 									  fl_ContainerLayout* * psfh)
2341 {
2342 	UT_ASSERT(m_pTOCL);
2343 
2344 	UT_ASSERT(pcr->getType() == PX_ChangeRecord::PXT_InsertStrux);
2345 	PT_AttrPropIndex iTOC = m_pStyle->getIndexAP();
2346 	const PX_ChangeRecord_Strux * pcrx = static_cast<const PX_ChangeRecord_Strux *> (pcr);
2347 	m_bListening = true;
2348 	fl_BlockLayout * pMyBL = m_pPrevBL;
2349 	if(pMyBL == NULL)
2350 	{
2351 		pMyBL = static_cast<fl_BlockLayout *>(m_pTOCL->getFirstLayout());
2352 	}
2353 	switch (pcrx->getStruxType())
2354 	{
2355 	case PTX_Block:
2356 	{
2357 		if (m_bListening)
2358 		{
2359 			// append a new BlockLayout to that SectionLayout
2360 			fl_ContainerLayout*	pBL = m_pTOCL->insert(sdh,pMyBL, iTOC,FL_CONTAINER_BLOCK);
2361 			if (!pBL)
2362 			{
2363 				UT_DEBUGMSG(("no memory for BlockLayout"));
2364 				return false;
2365 			}
2366 			m_pCurrentBL = pBL;
2367 			*psfh = pBL;
2368 		}
2369 
2370 	}
2371 	break;
2372 
2373 	default:
2374 		UT_ASSERT(0);
2375 		return false;
2376 	}
2377 	//
2378 	// We're not printing
2379 	//
2380 	return true;
2381 }
2382 
change(fl_ContainerLayout *,const PX_ChangeRecord *)2383 bool fl_TOCListener::change(fl_ContainerLayout* /*sfh*/,
2384 							   const PX_ChangeRecord * /*pcr*/)
2385 {
2386 	UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
2387 
2388 	return false;
2389 }
2390 
insertStrux(fl_ContainerLayout *,const PX_ChangeRecord *,pf_Frag_Strux *,PL_ListenerId,void (*)(pf_Frag_Strux * sdhNew,PL_ListenerId lid,fl_ContainerLayout * sfhNew))2391 bool fl_TOCListener::insertStrux(fl_ContainerLayout* /*sfh*/,
2392 									const PX_ChangeRecord * /*pcr*/,
2393 									pf_Frag_Strux* /*sdh*/,
2394 									PL_ListenerId /*lid*/,
2395 									void (* /*pfnBindHandles*/)(pf_Frag_Strux* sdhNew,
2396 																PL_ListenerId lid,
2397 																fl_ContainerLayout* sfhNew))
2398 {
2399 	UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
2400 
2401 	return false;
2402 }
2403 
signal(UT_uint32)2404 bool fl_TOCListener::signal(UT_uint32 /*iSignal*/)
2405 {
2406 	UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
2407 
2408 	return false;
2409 }
2410 
2411 
fillTOC(void)2412 bool fl_TOCLayout::fillTOC(void)
2413 {
2414     fl_DocSectionLayout * pDSL = getDocLayout()->getFirstSection();
2415     fl_BlockLayout * pBlock = NULL;
2416     fl_ContainerLayout * pCL = static_cast<fl_ContainerLayout *>(pDSL);
2417     while(pCL && pCL->getContainerType() != FL_CONTAINER_BLOCK)
2418     {
2419 	pCL = pCL->getFirstLayout();
2420     }
2421     if(pCL == NULL)
2422     {
2423 	return false;
2424     }
2425     if(pCL->getContainerType() != FL_CONTAINER_BLOCK)
2426     {
2427 	return false;
2428     }
2429     UT_UTF8String sStyle;
2430     pBlock = static_cast<fl_BlockLayout *>(pCL);
2431     bool filled = false;
2432 
2433     const gchar * pBookmark = getRangeBookmarkName().size() ? getRangeBookmarkName().utf8_str() : NULL;
2434 
2435     if(pBookmark)
2436     {
2437 	if(m_pDoc->isBookmarkUnique(pBookmark))
2438 	{
2439 	    // bookmark does not exist
2440 	    pBookmark = NULL;
2441 	}
2442     }
2443 
2444     fl_BlockLayout * pBlockLast = NULL;
2445 
2446     if(pBookmark)
2447     {
2448 	UT_uint32 i = 0;
2449 	fp_BookmarkRun * pB[2] = {NULL,NULL};
2450 	fp_Run * pRun;
2451 	fl_BlockLayout * pBlockStart = pBlock;
2452 	bool bFound = false;
2453 
2454 	while(pBlock)
2455 	{
2456 	    pRun = pBlock->getFirstRun();
2457 	    while(pRun)
2458 	    {
2459 		if(pRun->getType()== FPRUN_BOOKMARK)
2460 		{
2461 		    fp_BookmarkRun * pBR = static_cast<fp_BookmarkRun*>(pRun);
2462 		    if(!strcmp(pBR->getName(),pBookmark))
2463 		    {
2464 			pB[i] = pBR;
2465 			i++;
2466 			if(i>1)
2467 			{
2468 			    bFound = true;
2469 			    break;
2470 			}
2471 		    }
2472 		}
2473 
2474 		pRun = pRun->getNextRun();
2475 	    }
2476 
2477 	    if(bFound)
2478 	    {
2479 		break;
2480 	    }
2481 	    pBlock = pBlock->getNextBlockInDocument();
2482 	}
2483 
2484 	if(pB[0] && pB[1])
2485 	{
2486 	    pBlockLast = pB[1]->getBlock();
2487 
2488 	    pBlock = pB[0]->getBlock();
2489 	    PT_DocPosition pos1 = pB[0]->getBookmarkedDocPosition(false);
2490 
2491 	    if(pBlock->getPosition(true) < pos1)
2492 	    {
2493 		pBlock = pBlock->getNextBlockInDocument();
2494 	    }
2495 	}
2496 	else
2497 	{
2498 	    UT_ASSERT_HARMLESS( UT_SHOULD_NOT_HAPPEN );
2499 	    pBlock = pBlockStart;
2500 	}
2501     }
2502 
2503     // clear any existing contents
2504     _purgeLayout();
2505 
2506     while(pBlock)
2507     {
2508 	pBlock->getStyle(sStyle);
2509 	if(isStyleInTOC(sStyle))
2510 	{
2511 	    filled = true;
2512 	    addBlock(pBlock, false);
2513 	}
2514 	if(pBlockLast && pBlockLast == pBlock)
2515 	{
2516 	    break;
2517 	}
2518 	pBlock = pBlock->getNextBlockInDocument();
2519     }
2520     if(m_bTOCHeading)
2521     {
2522 	PD_Style * pStyle = NULL;
2523 	m_pDoc->getStyle(m_sTOCHeadingStyle.utf8_str(), &pStyle);
2524 	if(pStyle == NULL)
2525 	{
2526 	    m_pDoc->getStyle("Heading 1", &pStyle);
2527 	}
2528 	PT_AttrPropIndex indexAP = pStyle->getIndexAP();
2529 
2530 	fl_BlockLayout * pNewBlock = static_cast<fl_BlockLayout *>(insert(getStruxDocHandle(),NULL,
2531 									  indexAP,FL_CONTAINER_BLOCK));
2532 	pNewBlock->_doInsertTOCHeadingRun(0);
2533     }
2534 
2535 
2536     return filled;
2537 }
2538