1 /************************************************************************/
2 /*									*/
3 /*  Management of bookmarks related to TOC fields.			*/
4 /*									*/
5 /************************************************************************/
6 
7 #   include	"docEditConfig.h"
8 
9 #   include	<stdio.h>
10 
11 #   include	<appDebugon.h>
12 
13 #   include	<docBuf.h>
14 #   include	<docField.h>
15 #   include	<docParaParticules.h>
16 #   include	<docTreeType.h>
17 #   include	<docBookmarkField.h>
18 #   include	"docEdit.h"
19 #   include	"docTocBookmarks.h"
20 
21 /************************************************************************/
22 /*									*/
23 /*  Recalculate TOC fields in a document.				*/
24 /*									*/
25 /************************************************************************/
26 
docSetTocBookmark(FieldInstructions * fiBookmark,BufferDocument * bd)27 static int docSetTocBookmark(	FieldInstructions *	fiBookmark,
28 				BufferDocument *	bd )
29     {
30     int			rval= 0;
31     DocumentFieldList *	dfl= &(bd->bdFieldList);
32     const int		fieldCount= dfl->dflPagedList.plItemCount;
33     int			fieldNr;
34 
35     char		markName[DOCmaxBOOKMARK+1];
36 
37     long		id0= 0;
38     long		id1= 0;
39 
40     MemoryBuffer	mbBookmark;
41 
42     utilInitMemoryBuffer( &mbBookmark );
43 
44     for ( fieldNr= 0; fieldNr < fieldCount; fieldNr++ )
45 	{
46 	DocumentField *		df= docGetFieldByNumber( dfl, fieldNr );
47 	long			id;
48 
49 	if  ( ! df )
50 	    { continue;	}
51 	if  ( df->dfKind != DOCfkBOOKMARK	||
52 	      ! docIsTocBookmark( &id, df )	)
53 	    { continue;	}
54 
55 	if  ( id0 <= 0 || id0 > id )
56 	    { id0= id;	}
57 	if  ( id1 <= 0 || id1 < id )
58 	    { id1= id;	}
59 	}
60 
61     if  ( id0 > 1 )
62 	{ sprintf( markName, "_Toc%ld", id0- 1 );	}
63     else{ sprintf( markName, "_Toc%ld", id1+ 1 );	}
64 
65     if  ( utilMemoryBufferSetString( &mbBookmark, markName ) )
66 	{ LDEB(1); rval= -1; goto ready;	}
67 
68     if  ( docSetBookmarkField( fiBookmark, &mbBookmark ) )
69 	{ SDEB(markName); rval= -1; goto ready;	}
70 
71   ready:
72 
73     utilCleanMemoryBuffer( &mbBookmark );
74 
75     return rval;
76     }
77 
docRemoveUnbalancedTocBookmarks(BufferDocument * bdDoc)78 void docRemoveUnbalancedTocBookmarks(	BufferDocument *	bdDoc )
79     {
80     DocumentFieldList *	dfl= &(bdDoc->bdFieldList);
81     const int		fieldCount= dfl->dflPagedList.plItemCount;
82     int			fieldNr;
83 
84     EditOperation	eo;
85 
86     docInitEditOperation( &eo );
87 
88     eo.eoTree= &(bdDoc->bdBody);
89     eo.eoDocument= bdDoc;
90 
91     for ( fieldNr= 0; fieldNr < fieldCount; fieldNr++ )
92 	{
93 	DocumentField *		df= docGetFieldByNumber( dfl, fieldNr );
94 
95 	if  ( ! df )
96 	    { continue;		}
97 	if  ( df->dfSelectionScope.ssTreeType != DOCinBODY	)
98 	    { continue;	}
99 
100 	if  ( df->dfKind == DOCfkBOOKMARK				&&
101 	      df->dfHeadPosition.epParaNr !=
102 				      df->dfTailPosition.epParaNr	&&
103 	      docIsTocBookmark( (long *)0, df )				)
104 	    {
105 	    DocumentSelection	dsInside;
106 	    DocumentSelection	dsAround;
107 	    int			headPart;
108 	    int			tailPart;
109 	    DocumentSelection	dsExInside;
110 
111 	    if  ( docDelimitFieldInDoc( &dsInside, &dsAround,
112 					    &headPart, &tailPart, bdDoc, df ) )
113 		{ LDEB(fieldNr); continue; }
114 
115 	    if  ( docDeleteField( &dsExInside, &eo,
116 			dsInside.dsHead.dpNode, dsInside.dsTail.dpNode,
117 			headPart, tailPart, df ) )
118 		{ LDEB(fieldNr);	}
119 	    }
120 	}
121 
122     docCleanEditOperation( &eo );
123 
124     }
125 
126 /************************************************************************/
127 /*									*/
128 /*  Find a bookmark field that could be used as a TOC bookmark.		*/
129 /*  If no field can be found.. fill a selection that can be used to set	*/
130 /*  a TOC bookmark.							*/
131 /*									*/
132 /************************************************************************/
133 
docFindParaTocBookmark(DocumentField ** pDfBookmark,DocumentSelection * dsBookmark,BufferDocument * bd,DocumentTree * dt,BufferItem * paraNode)134 static int docFindParaTocBookmark(	DocumentField **	pDfBookmark,
135 					DocumentSelection *	dsBookmark,
136 					BufferDocument *	bd,
137 					DocumentTree *		dt,
138 					BufferItem *		paraNode )
139     {
140     DocumentSelection	ds;
141     DocumentField *	dfBookmark;
142 
143     if  ( docHeadPosition( &(ds.dsHead), paraNode ) )
144 	{ LDEB(1); return -1;	}
145     docAvoidParaHeadField( &(ds.dsHead), (int *)0, bd );
146 
147     {
148     int				part;
149     const TextParticule *	tp;
150 
151     docFindParticuleOfPosition( &part, (int *)0, &(ds.dsHead), PARAfindLAST );
152 
153     tp= ds.dsHead.dpNode->biParaParticules+ part;
154     while( part < paraNode->biParaParticuleCount	&&
155 	   ( tp->tpKind == DOCkindPAGEBREAK	||
156 	     tp->tpKind == DOCkindLINEBREAK	)	)
157 	{
158 	ds.dsHead.dpStroff= tp->tpStrlen+ tp->tpStroff;
159 	tp++; part++;
160 	}
161     }
162 
163     if  ( docTailPosition( &(ds.dsTail), paraNode ) )
164 	{ LDEB(1); return -1;	}
165 
166     docSetRangeSelection( &ds, &(ds.dsHead), &(ds.dsTail), 1 );
167 
168     dfBookmark= docFindTypedFieldInSelection( bd, &ds, DOCfkBOOKMARK, 0 );
169     if  ( dfBookmark )
170 	{
171 	if  ( docSelectionForEditPositionsInTree( dsBookmark, dt,
172 					    &(dfBookmark->dfHeadPosition),
173 					    &(dfBookmark->dfTailPosition) ) )
174 	    { LDEB(1); return -1;	}
175 
176 	*pDfBookmark= dfBookmark;
177 	return 0;
178 	}
179     else{
180 	if  ( ds.dsTail.dpStroff < ds.dsHead.dpStroff )
181 	    {
182 	    XXDEB(ds.dsTail.dpNode,ds.dsHead.dpNode);
183 	    LLDEB(ds.dsTail.dpStroff,ds.dsHead.dpStroff);
184 	    return -1;
185 	    }
186 
187 	*dsBookmark= ds;
188 	*pDfBookmark= (DocumentField *)0;
189 	return 1;
190 	}
191     }
192 
193 /************************************************************************/
194 /*									*/
195 /*  Set a TOC bookmark that contains the whole paragraph.		*/
196 /*									*/
197 /************************************************************************/
198 
docGetParaTocBookmark(BufferDocument * bd,DocumentTree * dt,BufferItem * paraNode)199 const DocumentField * docGetParaTocBookmark(
200 					BufferDocument *	bd,
201 					DocumentTree *		dt,
202 					BufferItem *		paraNode )
203     {
204     int			res;
205     DocumentSelection	dsBookmark;
206     DocumentField *	dfBookmark= (DocumentField *)0;
207 
208     FieldInstructions	fiBookmark;
209 
210     docInitFieldInstructions( &fiBookmark );
211 
212     res= docFindParaTocBookmark( &dfBookmark, &dsBookmark, bd, dt, paraNode );
213     if  ( res < 0 )
214 	{ LDEB(res); goto ready;	}
215     if  ( res > 0 )
216 	{
217 	if  ( ! docIsIBarSelection( &dsBookmark ) )
218 	    {
219 	    if  ( docSetTocBookmark( &fiBookmark, bd ) )
220 		{ LDEB(1); goto ready;	}
221 
222 	    if  ( docSurroundTextSelectionByField( bd, dt, &dsBookmark,
223 			    &dfBookmark,
224 			    (DocumentSelection *)0, (DocumentSelection *)0,
225 			    (int *)0, (int *)0,
226 			    (PropertyMask *)0, (TextAttribute *)0,
227 			    DOCfkBOOKMARK, &fiBookmark ) )
228 		{ LDEB(1); goto ready;	}
229 	    }
230 	}
231 
232   ready:
233 
234     docCleanFieldInstructions( &fiBookmark );
235 
236     return dfBookmark;
237     }
238 
239 /************************************************************************/
240 /*									*/
241 /*  Make sure that all leaves in the outlinelevel tree have a bookmark	*/
242 /*  that can be used in the table of contents.				*/
243 /*									*/
244 /************************************************************************/
245 
246 typedef struct SetBookmarkThrough
247     {
248     int			sbtRval;
249     BufferDocument *	sbtDocument;
250     DocumentTree *	sbtTree;
251     } SetBookmarkThrough;
252 
docSetTocBookmarkForLevel(int ilvl,void * vsbt)253 static int docSetTocBookmarkForLevel(	int			ilvl,
254 					void *			vsbt )
255     {
256     BufferItem *		paraNode;
257     SetBookmarkThrough *	sbt= (SetBookmarkThrough *)vsbt;
258 
259     paraNode= docGetParagraphByNumber( sbt->sbtTree, ilvl );
260     if  ( ! paraNode )
261 	{ LXDEB(ilvl,paraNode); sbt->sbtRval= -1;	}
262     else{
263 	/*  Do not check return value:			*/
264 	/*  No bookmark is set in an empty paragraph	*/
265 
266 	docGetParaTocBookmark( sbt->sbtDocument, sbt->sbtTree, paraNode );
267 	}
268 
269     return 0;
270     }
271 
docTocSetOutlineBookmarks(BufferDocument * bd)272 int docTocSetOutlineBookmarks(	BufferDocument *	bd )
273     {
274     SetBookmarkThrough	sbt;
275 
276     sbt.sbtRval= 0;
277     sbt.sbtDocument= bd;
278     sbt.sbtTree= &(bd->bdBody);
279 
280     if  ( docListNumberTreeForAll( &(sbt.sbtTree->dtOutlineTree),
281 				docSetTocBookmarkForLevel, (void *)&sbt ) )
282 	{ LDEB(1); return -1;	}
283 
284     return sbt.sbtRval;
285     }
286 
docSetTocBookmarks(BufferDocument * bd)287 int docSetTocBookmarks(	BufferDocument *		bd )
288     {
289     int			rval= 0;
290     DocumentTree *	dt= &(bd->bdBody);
291 
292     DocumentFieldList *	dfl= &(bd->bdFieldList);
293     const int		fieldCount= dfl->dflPagedList.plItemCount;
294     int			fieldNr;
295 
296     FieldInstructions	fiBookmark;
297 
298     docInitFieldInstructions( &fiBookmark );
299 
300     if  ( docTocSetOutlineBookmarks( bd ) )
301 	{ LDEB(1); rval= -1; goto ready;	}
302 
303     for ( fieldNr= 0; fieldNr < fieldCount; fieldNr++ )
304 	{
305 	DocumentField *		dfTc= docGetFieldByNumber( dfl, fieldNr );
306 	DocumentField *		dfBookmark;
307 	DocumentSelection	dsInsideTc;
308 	DocumentSelection	dsAroundTc;
309 
310 	if  ( ! dfTc )
311 	    { continue;	}
312 	if  ( ( dfTc->dfKind != DOCfkTC && dfTc->dfKind != DOCfkTCN )	||
313 	      dfTc->dfSelectionScope.ssTreeType != DOCinBODY		)
314 	    { continue;	}
315 
316 	if  ( docDelimitFieldInDoc( &dsInsideTc, &dsAroundTc,
317 					    (int *)0, (int *)0, bd, dfTc ) )
318 	    { LDEB(1); rval= -1; goto ready;	}
319 
320 	dfBookmark= docFindTypedFieldForPosition( bd, &(dsInsideTc.dsHead),
321 							    DOCfkBOOKMARK, 0 );
322 	if  ( ! dfBookmark )
323 	    {
324 	    if  ( docSetTocBookmark( &fiBookmark, bd ) )
325 		{ LDEB(1); rval= -1; goto ready;	}
326 
327 	    if  ( docSurroundTextSelectionByField( bd, dt, &dsAroundTc,
328 			    &dfBookmark,
329 			    (DocumentSelection *)0, (DocumentSelection *)0,
330 			    (int *)0, (int *)0,
331 			    (PropertyMask *)0, (TextAttribute *)0,
332 			    DOCfkBOOKMARK, &fiBookmark ) )
333 		{ LDEB(1); rval= -1; goto ready;	}
334 	    }
335 	}
336 
337   ready:
338 
339     docCleanFieldInstructions( &fiBookmark );
340 
341     return rval;
342     }
343 
344