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