1 /************************************************************************/
2 /*									*/
3 /*  Evaluate TOC fields.						*/
4 /*									*/
5 /************************************************************************/
6 
7 #   include	"docEditConfig.h"
8 
9 #   include	<stdlib.h>
10 
11 #   include	<docBuf.h>
12 #   include	<docTreeNode.h>
13 #   include	<docNodeTree.h>
14 #   include	"docCalculateToc.h"
15 #   include	"docTocBookmarks.h"
16 #   include	"docIntermediaryDocument.h"
17 #   include	<docTocField.h>
18 #   include	<docTreeType.h>
19 #   include	<docSeqField.h>
20 #   include	<docBookmarkField.h>
21 #   include	<docTextParticule.h>
22 
23 #   include	<appDebugon.h>
24 
25 /************************************************************************/
26 
docInitTocEntry(TocEntry * te)27 static void docInitTocEntry(	TocEntry *	te )
28     {
29     te->teLevel= PPoutlineBODYTEXT;
30     te->teField= (const DocumentField *)0;
31     docInitDocumentSelection( &(te->teDsInside) );
32     docInitDocumentSelection( &(te->teDsAround) );
33     te->tePart0= 0;
34     te->tePart1= 0;
35     te->teMarkName= (const MemoryBuffer *)0;
36     te->teNumbered= 1;
37     }
38 
39 /************************************************************************/
40 
docInitCalculateToc(CalculateToc * ct)41 void docInitCalculateToc(	CalculateToc *	ct )
42     {
43     int		i;
44 
45     ct->ctBdToc= (BufferDocument *)0;
46     ct->ctBdDoc= (BufferDocument *)0;
47     ct->ctSectNode= (BufferItem *)0;
48     ct->ctDfTocTo= (DocumentField *)0;
49 
50     docInitTocField( &(ct->ctTocField) );
51     docLayoutInitBlockFrame( &(ct->ctBlockFrame) );
52     docInitParagraphProperties( &(ct->ctRefPP) );
53     utilInitTextAttribute( &(ct->ctTextAttribute) );
54     ct->ctDefaultTextAttributeNumber= -1;
55     for ( i= 0; i < PPoutline_COUNT; i++ )
56 	{
57 	ct->ctLevelStyles[i]= (const DocumentStyle *)0;
58 	ct->ctLevelAttributeNumbers[i]= -1;
59 	}
60     utilInitIndexSet( &(ct->ctStyleNumbers) );
61 
62     ct->ctEntries= (TocEntry *)0;
63     ct->ctEntryCount= 0;
64     ct->ctDepth= 0;
65 
66     ct->ctStyleLevels= (unsigned char *)0;
67     ct->ctStyleLevelCount= 0;
68     return;
69     }
70 
docCleanCalculateToc(CalculateToc * ct)71 void docCleanCalculateToc(	CalculateToc *	ct )
72     {
73     if  ( ct->ctBdToc )
74 	{ docFreeIntermediaryDocument( ct->ctBdToc );	}
75 
76     docCleanTocField( &(ct->ctTocField) );
77     docLayoutCleanBlockFrame( &(ct->ctBlockFrame) );
78     docCleanParagraphProperties( &(ct->ctRefPP) );
79 
80     utilInitIndexSet( &(ct->ctStyleNumbers) );
81 
82     if  ( ct->ctEntries )
83 	{ free( ct->ctEntries );	}
84 
85     if  ( ct->ctStyleLevels )
86 	{ free( ct->ctStyleLevels );	}
87 
88     return;
89     }
90 
91 /************************************************************************/
92 /*									*/
93 /*  Sort Toc entries. Sort by increasing paragraph number,		*/
94 /*  decreasing size and increasing position.				*/
95 /*									*/
96 /************************************************************************/
97 
docCompareTocEntries(const void * voidte1,const void * voidte2)98 static int docCompareTocEntries(	const void *	voidte1,
99 					const void *	voidte2	)
100     {
101     const TocEntry *	te1= (const TocEntry *)voidte1;
102     const TocEntry *	te2= (const TocEntry *)voidte2;
103     int			parts1;
104     int			parts2;
105 
106     if  ( te1->teField->dfHeadPosition.epParaNr >
107 	  te2->teField->dfHeadPosition.epParaNr )
108 	{ return  1;	}
109 
110     if  ( te1->teField->dfHeadPosition.epParaNr <
111 	  te2->teField->dfHeadPosition.epParaNr )
112 	{ return -1;	}
113 
114     parts1= te1->tePart1- te1->tePart0;
115     parts2= te2->tePart1- te2->tePart0;
116     if  ( parts1 < parts2 )
117 	{ return  1;	}
118     if  ( parts1 > parts2 )
119 	{ return -1;	}
120 
121     if  ( te1->tePart0 > te2->tePart0 )
122 	{ return  1;	}
123     if  ( te1->tePart0 < te2->tePart0 )
124 	{ return -1;	}
125 
126     return 0;
127     }
128 
129 /************************************************************************/
130 /*									*/
131 /*  Does a field go to the TOC?						*/
132 /*									*/
133 /************************************************************************/
134 
docGetTocEntry(TocEntry * te,const CalculateToc * ct)135 static int docGetTocEntry(	TocEntry *		te,
136 				const CalculateToc *	ct )
137     {
138     char			flag[2];
139     const TocField *		tf= &(ct->ctTocField);
140 
141     if  ( te->teField->dfKind == DOCfkBOOKMARK )
142 	{
143 	BufferItem *	paraNode;
144 
145 	if  ( tf->tfType != TOCtypeTOC )
146 	    { return 1;	}
147 
148 	if  ( ! tf->tfUseStyleNames		&&
149 	      ! tf->tfUseStyleLevels		&&
150 	      ! tf->tfUseOutlineLevels	)
151 	    { return 1;	}
152 
153 	if  ( docDelimitFieldInDoc( &(te->teDsInside), &(te->teDsAround),
154 					    &(te->tePart0), &(te->tePart1),
155 					    ct->ctBdDoc, te->teField ) )
156 	    { LDEB(te->teField->dfFieldNumber); return 1; }
157 
158 	if  ( docIsIBarSelection( &(te->teDsInside) ) )
159 	    { return 1;	}
160 
161 	paraNode= te->teDsInside.dsHead.dpNode;
162 	if  ( te->teDsInside.dsTail.dpNode != paraNode )
163 	    { return 1;	}
164 
165 	/*  Holds any text? */
166 	{
167 	int			part;
168 	const TextParticule *	tp;
169 
170 	tp= te->teDsInside.dsHead.dpNode->biParaParticules+ te->tePart0+ 1;
171 	for ( part= te->tePart0+ 1; part < te->tePart1; tp++, part++ )
172 	    {
173 	    if  ( tp->tpKind == DOCkindSPAN && tp->tpStrlen > 0 )
174 		{ break;	}
175 	    }
176 
177 	if  ( part >= te->tePart1 )
178 	    { return 1;	}
179 	}
180 
181 	if  ( docFieldGetBookmark( &(te->teMarkName), te->teField ) )
182 	    { LDEB(te->teField->dfFieldNumber); return -1;	}
183 
184 	if  ( tf->tfType == TOCtypeTOC				&&
185 	      tf->tfUseStyleLevels				&&
186 	      paraNode->biParaStyle > 0				&&
187 	      paraNode->biParaStyle < ct->ctStyleLevelCount	)
188 	    {
189 	    te->teLevel= ct->ctStyleLevels[paraNode->biParaStyle];
190 
191 	    if  ( te->teLevel <= tf->tfStyleLevel1	&&
192 		  te->teLevel >= tf->tfStyleLevel0	)
193 		{
194 		te->teNumbered= te->teLevel < tf->tfNLevel0	||
195 				te->teLevel > tf->tfNLevel1	;
196 		return 0;
197 		}
198 	    }
199 
200 	if  ( tf->tfType == TOCtypeTOC				&&
201 	      tf->tfUseStyleNames				&&
202 	      utilIndexSetContains( &(ct->ctStyleNumbers),
203 				      paraNode->biParaStyle )	)
204 	    {
205 	    te->teNumbered= 1;
206 	    return 0;
207 	    }
208 
209 	if  ( tf->tfType == TOCtypeTOC				&&
210 	      tf->tfUseOutlineLevels				&&
211 	      paraNode->biParaOutlineLevel < PPoutlineBODYTEXT	)
212 	    {
213 	    te->teLevel= paraNode->biParaOutlineLevel;
214 
215 	    te->teNumbered= te->teLevel < tf->tfNLevel0	||
216 			    te->teLevel > tf->tfNLevel1	;
217 	    return 0;
218 	    }
219 
220 	return 1;
221 	}
222 
223     if  ( tf->tfType == TOCtypeTOC		&&
224 	  ( te->teField->dfKind == DOCfkTC	||
225 	    te->teField->dfKind == DOCfkTCN	)	)
226 	{
227 	DocumentField *	dfBookmark;
228 
229 	if  ( ! tf->tfUseTcEntries			||
230 	      te->teLevel > tf->tfEntryLevel1	||
231 	      te->teLevel < tf->tfEntryLevel0	)
232 	    { return 1;	}
233 
234 	flag[1]= '\0';
235 	if  ( docFieldGetTc( te->teField, flag,
236 				    &(te->teLevel), &(te->teNumbered) ) )
237 	    { LDEB(te->teField->dfFieldNumber); return -1;	}
238 
239 	dfBookmark= docFindTypedChildField( &(ct->ctBdDoc->bdBody.dtRootFields),
240 			    &(te->teField->dfHeadPosition), DOCfkBOOKMARK );
241 	if  ( ! dfBookmark )
242 	    { /*XDEB(dfBookmark);*/ return 1;	}
243 
244 	if  ( docDelimitFieldInDoc( &(te->teDsInside), &(te->teDsAround),
245 					&(te->tePart0), &(te->tePart1),
246 					ct->ctBdDoc, dfBookmark ) )
247 	    { LDEB(dfBookmark->dfFieldNumber); return 1; }
248 
249 	if  ( docIsIBarSelection( &(te->teDsInside) ) )
250 	    { return 1;	}
251 
252 	if  ( docFieldGetBookmark( &(te->teMarkName), dfBookmark ) )
253 	    { LDEB(te->teField->dfFieldNumber); return -1;	}
254 
255 	te->teNumbered= te->teLevel < tf->tfNLevel0	||
256 			te->teLevel > tf->tfNLevel1	;
257 
258 	return 0;
259 	}
260 
261     if  ( te->teField->dfKind == DOCfkSEQ )
262 	{
263 	SeqField		sf;
264 	BufferItem *		paraNode;
265 	const DocumentField *	dfBookmark;
266 
267 	if  ( tf->tfType != TOCtypeSEQ )
268 	    { return 1;	}
269 
270 	if  ( docGetSeqField( &sf, te->teField ) )
271 	    { LDEB(1); return 1;	}
272 
273 	if  ( utilMemoryBufferIsEmpty( &(tf->tfIdentifierName) )	||
274 	      ! utilEqualMemoryBuffer( &(tf->tfIdentifierName),
275 						  &(sf.sfIdentifier) )	)
276 	    { return 1;	}
277 
278 	paraNode= docGetParagraphByNumber( &(ct->ctBdDoc->bdBody),
279 					te->teField->dfHeadPosition.epParaNr );
280 	if  ( ! paraNode )
281 	    { XDEB(paraNode); return -1; }
282 
283 	dfBookmark= docGetParaTocBookmark( ct->ctBdDoc,
284 					    &(ct->ctBdDoc->bdBody), paraNode );
285 	if  ( ! dfBookmark )
286 	    { XDEB(dfBookmark); return -1;	}
287 
288 	if  ( docFieldGetBookmark( &(te->teMarkName), dfBookmark ) )
289 	    { LDEB(dfBookmark->dfFieldNumber); return -1;	}
290 
291 	te->teField= dfBookmark;
292 	return 0;
293 	}
294 
295     return 1;
296     }
297 
298 /************************************************************************/
299 /*									*/
300 /*  Collect TOC entries. Relies on the bookmarks that should already	*/
301 /*  have been made.							*/
302 /*									*/
303 /*  Sorting takes care of selecting the most appropriate ones.		*/
304 /*									*/
305 /************************************************************************/
306 
docCollectTocEntries(CalculateToc * ct)307 static int docCollectTocEntries(	CalculateToc *			ct )
308     {
309     const DocumentFieldList *	dflDoc= &(ct->ctBdDoc->bdFieldList);
310     const int			fieldCount= dflDoc->dflPagedList.plItemCount;
311     int				fieldNr;
312 
313     int				entryNr= -1;
314     int				entryParaNr;
315 
316     TocEntry *			te;
317     int				to= 0;
318 
319     for ( fieldNr= 0; fieldNr < fieldCount; fieldNr++ )
320 	{
321 	int			res;
322 	const DocumentField *	df= docGetFieldByNumber( dflDoc, fieldNr );
323 
324 	if  ( ! df )
325 	    { continue;	}
326 	if  ( df->dfSelectionScope.ssTreeType != DOCinBODY )
327 	    { continue;	}
328 
329 	if  ( df->dfKind != DOCfkBOOKMARK	&&
330 	      df->dfKind != DOCfkSEQ		&&
331 	      df->dfKind != DOCfkTC		&&
332 	      df->dfKind != DOCfkTCN		)
333 	    { continue;	}
334 
335 	te=  ct->ctEntries+ ct->ctEntryCount;
336 	te->teField= df;
337 
338 	res= docGetTocEntry( te, ct );
339 	if  ( res < 0 )
340 	    { LLDEB(fieldNr,res); return -1;	}
341 	if  ( res > 0 )
342 	    { continue;	}
343 
344 	if  ( ct->ctDepth < te->teLevel+ 1 )
345 	    { ct->ctDepth=  te->teLevel+ 1;	}
346 
347 	ct->ctEntryCount++;
348 	}
349 
350     qsort( ct->ctEntries, ct->ctEntryCount,
351 				    sizeof(TocEntry), docCompareTocEntries );
352 
353     entryParaNr= -1;
354     to= 0;
355     te= ct->ctEntries;
356     for ( entryNr= 0; entryNr < ct->ctEntryCount; te++, entryNr++ )
357 	{
358 	if  ( te->teField->dfHeadPosition.epParaNr == entryParaNr )
359 	    { continue;	}
360 	entryParaNr= te->teField->dfHeadPosition.epParaNr;
361 
362 	ct->ctEntries[to++]= *te;
363 	}
364 
365     ct->ctEntryCount= to;
366 
367     return 0;
368     }
369 
370 /************************************************************************/
371 
docTocCollectTocStyles(CalculateToc * ct)372 static int docTocCollectTocStyles(	CalculateToc *		ct )
373     {
374     const TocField *		tf= &(ct->ctTocField);
375     const BufferDocument *	bd= ct->ctBdDoc;
376     int				i;
377 
378     ct->ctStyleLevels= (unsigned char *)malloc(
379 					bd->bdStyleSheet.dssStyleCount );
380     if  ( ! ct->ctStyleLevels )
381 	{
382 	LXDEB(bd->bdStyleSheet.dssStyleCount,ct->ctStyleLevels);
383 	return -1;
384 	}
385 
386     for ( i= 0; i < bd->bdStyleSheet.dssStyleCount; i++ )
387 	{
388 	const DocumentStyle *	ds= bd->bdStyleSheet.dssStyles[i];
389 
390 	ct->ctStyleLevels[i]= PPoutlineBODYTEXT;
391 
392 	if  ( ds && tf->tfUseStyleLevels )
393 	    {
394 	    if  ( ds->dsOutlineLevel <= tf->tfStyleLevel1	&&
395 		  ds->dsOutlineLevel >= tf->tfStyleLevel0	)
396 		{ ct->ctStyleLevels[i]= ds->dsOutlineLevel; }
397 	    }
398 	}
399 
400     if  ( tf->tfUseStyleNames )
401 	{
402 	int			j;
403 	const StyleNameLevel *	snl;
404 
405 	snl= tf->tfStyleNameLevels;
406 	for ( j= 0; j < tf->tfStyleNameLevelCount; snl++, j++ )
407 	    {
408 	    DocumentStyle *	ds;
409 
410 	    ds= docGetStyleByName( &(bd->bdStyleSheet), snl->snlStyleName );
411 	    if  ( ds )
412 		{
413 		ct->ctStyleLevels[ds->dsStyleNumber]= snl->snlLevel;
414 		}
415 
416 	    if  ( utilIndexSetAdd( &(ct->ctStyleNumbers), ds->dsStyleNumber ) )
417 		{ LDEB(ds->dsStyleNumber); return -1;	}
418 	    }
419 	}
420 
421     ct->ctStyleLevelCount= bd->bdStyleSheet.dssStyleCount;
422 
423     return 0;
424     }
425 
426 /************************************************************************/
427 /*									*/
428 /*  Set a TOC bookmark for all paragraphs that are included in the	*/
429 /*  table of contents because of their style.				*/
430 /*									*/
431 /************************************************************************/
432 
docTocSetStyleBookmarks(CalculateToc * ct)433 static int docTocSetStyleBookmarks(	CalculateToc *		ct )
434     {
435     const TocField *		tf= &(ct->ctTocField);
436     BufferDocument *		bd= ct->ctBdDoc;
437     DocumentPosition		dp;
438 
439     if  ( docHeadPosition( &dp, bd->bdBody.dtRoot ) )
440 	{ LDEB(1); return 0;	}
441     while( dp.dpNode )
442 	{
443 	if  ( dp.dpNode->biParaStyle > 0			&&
444 	      dp.dpNode->biParaStyle < ct->ctStyleLevelCount	)
445 	    {
446 	    int	level= ct->ctStyleLevels[dp.dpNode->biParaStyle];
447 
448 	    if  ( level <= tf->tfStyleLevel1	&&
449 		  level >= tf->tfStyleLevel0	)
450 		{
451 		/*  Do not check return value:			*/
452 		/*  No bookmark is set in an empty paragraph	*/
453 
454 		docGetParaTocBookmark( bd, &(bd->bdBody), dp.dpNode );
455 		}
456 	    }
457 
458 	dp.dpNode= docNextParagraph( dp.dpNode );
459 	}
460 
461     return 0;
462     }
463 
464 /************************************************************************/
465 /*									*/
466 /*  Collect the entries for a TOC field, or for the spine of an EPUB	*/
467 /*  document.								*/
468 /*									*/
469 /************************************************************************/
470 
docCollectTocInput(CalculateToc * ct)471 int docCollectTocInput(	CalculateToc *			ct )
472     {
473     const TocField *		tf= &(ct->ctTocField);
474     int				fieldNr;
475     const DocumentFieldList *	dflDoc;
476     int				fieldCount;
477 
478     dflDoc= &(ct->ctBdDoc->bdFieldList);
479     fieldCount= dflDoc->dflPagedList.plItemCount;
480 
481     if  ( tf->tfType == TOCtypeTOC				&&
482 	  ( tf->tfUseStyleNames	|| tf->tfUseStyleLevels	)	)
483 	{
484 	if  ( docTocCollectTocStyles( ct ) )
485 	    { LDEB(1); return -1;	}
486 
487 	if  ( docTocSetStyleBookmarks( ct ) )
488 	    { LDEB(1); return -1;	}
489 	}
490 
491     if  ( tf->tfType == TOCtypeTOC	&&
492 	  tf->tfUseOutlineLevels	)
493 	{
494 	if  ( docTocSetOutlineBookmarks( ct->ctBdDoc ) )
495 	    { LDEB(1); return -1;	}
496 	}
497 
498     ct->ctEntries= (TocEntry *)malloc( fieldCount* sizeof(TocEntry) );
499     if  ( ! ct->ctEntries )
500 	{ LXDEB(fieldCount,ct->ctEntries); return -1;	}
501     for ( fieldNr= 0; fieldNr < fieldCount; fieldNr++ )
502 	{ docInitTocEntry( ct->ctEntries+ fieldNr ); }
503 
504     if  ( docCollectTocEntries( ct ) )
505 	{ LDEB(1); return -1;	}
506 
507     return 0;
508     }
509 
510