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