1 /* AbiWord
2 * Copyright (C) 1998 AbiSource, Inc.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301 USA.
18 */
19
20
21 #include "ut_types.h"
22 #include "ut_misc.h"
23 #include "ut_assert.h"
24 #include "ut_debugmsg.h"
25 #include "ut_growbuf.h"
26 #include "pt_PieceTable.h"
27 #include "pf_Frag.h"
28 #include "pf_Frag_FmtMark.h"
29 #include "pf_Frag_Object.h"
30 #include "pf_Frag_Strux.h"
31 #include "pf_Frag_Strux_Block.h"
32 #include "pf_Frag_Strux_Section.h"
33 #include "pf_Frag_Text.h"
34 #include "pf_Fragments.h"
35 #include "px_ChangeRecord.h"
36 #include "px_CR_Object.h"
37 #include "px_CR_Span.h"
38 #include "px_CR_SpanChange.h"
39 #include "px_CR_Strux.h"
40
41
42 /*****************************************************************/
43 /*****************************************************************/
44
tellListener(PL_Listener * pListener)45 bool pt_PieceTable::tellListener(PL_Listener* pListener)
46 {
47 return _tellAndMaybeAddListener(pListener, 0, false);
48 }
49
addListener(PL_Listener * pListener,PL_ListenerId listenerId)50 bool pt_PieceTable::addListener(PL_Listener* pListener,
51 PL_ListenerId listenerId)
52 {
53 return _tellAndMaybeAddListener(pListener, listenerId, true);
54 }
55
_tellAndMaybeAddListener(PL_Listener * pListener,PL_ListenerId listenerId,bool bAdd)56 bool pt_PieceTable::_tellAndMaybeAddListener(PL_Listener * pListener,
57 PL_ListenerId listenerId,
58 bool bAdd)
59 {
60 // walk document and for each fragment, send a notification
61 // to each layout.
62
63 fl_ContainerLayout* sfh = 0;
64 PT_DocPosition sum = 0;
65 UT_uint32 blockOffset = 0;
66 pf_Frag_Strux * pfs2 = NULL;
67 bool bListensOnly = (pListener->getType() >= PTL_CollabExport);
68 for (pf_Frag * pf = m_fragments.getFirst(); (pf); pf=pf->getNext())
69 {
70 switch (pf->getType())
71 {
72 case pf_Frag::PFT_Text:
73 {
74 if(bListensOnly)
75 {
76 break;
77 }
78 pf_Frag_Text * pft = static_cast<pf_Frag_Text *> (pf);
79 PX_ChangeRecord * pcr = NULL;
80 bool bStatus1 = false;
81 bool bAddOffset = true;
82 if(sfh != NULL)
83 {
84 bStatus1 = pft->createSpecialChangeRecord(&pcr,sum,blockOffset);
85 UT_return_val_if_fail (bStatus1, false);
86 }
87 else
88 {
89 PT_DocPosition pos = pf->getPos();
90 getStruxOfTypeFromPosition(listenerId,pos,PTX_Block,&sfh);
91
92 getStruxOfTypeFromPosition(pos,PTX_Block,&pfs2);
93 blockOffset = pos - pfs2->getPos() -1;
94 bStatus1 = pft->createSpecialChangeRecord(&pcr,pos,blockOffset);
95 UT_return_val_if_fail (bStatus1,false);
96 // I do not understand at all why this was set to
97 // false; if the doc contains a footnote section
98 // followed by a text fragment and another
99 // fragment, the text fragment and the fragment
100 // after it are given identical block offsets !!!
101 // Tomas, May, 12, 2003
102 bAddOffset = true;
103 }
104 bool bStatus2 = pListener->populate(sfh,pcr);
105 if (pcr)
106 delete pcr;
107 if (!bStatus2)
108 return false;
109 if(bAddOffset)
110 {
111 blockOffset += pf->getLength();
112 }
113 }
114 break;
115
116 case pf_Frag::PFT_Strux:
117 {
118 pfs2 = static_cast<pf_Frag_Strux *> (pf);
119 sfh = 0;
120 if(bListensOnly)
121 {
122 pfs2->setFmtHandle(listenerId,sfh);
123 break;
124 }
125 PX_ChangeRecord * pcr = NULL;
126 bool bStatus1 = pfs2->createSpecialChangeRecord(&pcr,sum);
127 UT_return_val_if_fail (bStatus1, false);
128 bool bStatus2 = pListener->populateStrux(pfs2,pcr,&sfh);
129
130 // This can happen legally, for example when inserting a hdr/ftr strux
131 // which was marked deleted in revisions mode -- such strux has no
132 // corresponding layout element
133 // UT_ASSERT_HARMLESS( sfh || !bAdd );
134 if (bAdd && sfh)
135 {
136 pfs2->setFmtHandle(listenerId,sfh);
137 }
138
139 if (pcr)
140 delete pcr;
141 if (!bStatus2)
142 return false;
143 blockOffset = 0;
144 if(isEndFootnote(pfs2))
145 {
146 sfh = NULL;
147 }
148 }
149 break;
150
151 case pf_Frag::PFT_Object:
152 {
153 if(bListensOnly)
154 {
155 break;
156 }
157 pf_Frag_Object * pfo = static_cast<pf_Frag_Object *> (pf);
158 PX_ChangeRecord * pcr = NULL;
159 bool bStatus1 = false;
160 bool bAddOffset = true;
161 if(sfh != NULL)
162 {
163 bStatus1 = pfo->createSpecialChangeRecord(&pcr,sum,blockOffset);
164 UT_return_val_if_fail (bStatus1,false);
165 }
166 else
167 {
168 PT_DocPosition pos = pf->getPos();
169 getStruxOfTypeFromPosition(listenerId,pos,PTX_Block,&sfh);
170 pf_Frag_Strux* pfs = NULL;
171 getStruxOfTypeFromPosition(pos,PTX_Block,&pfs);
172 if(!pfs)
173 return false;
174 blockOffset = pos - pfs->getPos() -1;
175 bStatus1 = pfo->createSpecialChangeRecord(&pcr,pos,blockOffset);
176 UT_return_val_if_fail (bStatus1, false);
177 // I do not understand at all why this was set to
178 // false; if the doc contains a footnote section
179 // followed by a text fragment and another
180 // fragment, the text fragment and the fragment
181 // after it are given identical block offsets !!!
182 // Tomas, May, 12, 2003
183 bAddOffset = true;
184 }
185
186 UT_return_val_if_fail (bStatus1,false);
187 bool bStatus2 = pListener->populate(sfh,pcr);
188 if (pcr)
189 delete pcr;
190 if (!bStatus2)
191 return false;
192 if(bAddOffset)
193 {
194 blockOffset += pf->getLength();
195 }
196 }
197 break;
198
199 case pf_Frag::PFT_FmtMark:
200 {
201 if(bListensOnly)
202 {
203 break;
204 }
205 pf_Frag_FmtMark * pffm = static_cast<pf_Frag_FmtMark *> (pf);
206 PX_ChangeRecord * pcr = NULL;
207 bool bStatus1 = false;
208 bool bAddOffset = true;
209 if(sfh != NULL)
210 {
211 bStatus1 = pffm->createSpecialChangeRecord(&pcr,sum,blockOffset);
212 UT_return_val_if_fail (bStatus1,false);
213 }
214 else
215 {
216 PT_DocPosition pos = pf->getPos();
217 getStruxOfTypeFromPosition(listenerId,pos,PTX_Block,&sfh);
218 getStruxOfTypeFromPosition(pos,PTX_Block,&pfs2);
219 blockOffset = pos - pfs2->getPos() -1;
220 bStatus1 = pffm->createSpecialChangeRecord(&pcr,pos,blockOffset);
221 UT_return_val_if_fail (bStatus1, false);
222 bAddOffset = false;
223 }
224 bool bStatus2 = pListener->populate(sfh,pcr);
225 DELETEP(pcr);
226 if (!bStatus2)
227 return false;
228 if(bAddOffset)
229 {
230 blockOffset += pf->getLength();
231 }
232 }
233 break;
234
235 case pf_Frag::PFT_EndOfDoc:
236 // they don't get to know about this.
237 break;
238
239 default:
240 UT_ASSERT_HARMLESS(0);
241 return false;
242 }
243
244 sum += pf->getLength();
245 }
246
247 // TODO assert that sum == our cached value.
248
249 return true;
250 }
251
252 #include "pl_ListenerCoupleCloser.h"
253 #include <set>
254 #include <boost/bind.hpp>
255 #include <boost/function.hpp>
256 typedef boost::function< bool (PT_DocPosition, PT_DocPosition, PT_DocPosition, PL_Listener*)> f_WalkRangeFinished_t;
257
finishedFunctorEndOfRage(PT_DocPosition,PT_DocPosition rangeEndPos,PT_DocPosition curPos,PL_Listener *)258 static bool finishedFunctorEndOfRage( PT_DocPosition /*rangeStartPos*/,
259 PT_DocPosition rangeEndPos,
260 PT_DocPosition curPos,
261 PL_Listener* /*pListener*/ )
262 {
263 if( curPos >= rangeEndPos )
264 return true;
265 return false;
266 }
267
finishedFunctorFinishingListener(PT_DocPosition,PT_DocPosition,PT_DocPosition,PL_Listener *,PL_FinishingListener * fl)268 static bool finishedFunctorFinishingListener( PT_DocPosition /*rangeStartPos*/,
269 PT_DocPosition /*rangeEndPos*/,
270 PT_DocPosition /*curPos*/,
271 PL_Listener* /*pListener*/,
272 PL_FinishingListener* fl )
273 {
274 if( fl->isFinished() )
275 return true;
276 return false;
277 }
278
279
280 typedef std::set< pf_Frag::PFType > m_fragtypecol_t;
_getTellListenerSubsetWalkRangeVisitAllFragments()281 static m_fragtypecol_t& _getTellListenerSubsetWalkRangeVisitAllFragments()
282 {
283 static m_fragtypecol_t col;
284 if( col.empty() )
285 {
286 col.insert( pf_Frag::PFT_Text );
287 col.insert( pf_Frag::PFT_Object );
288 col.insert( pf_Frag::PFT_Strux );
289 col.insert( pf_Frag::PFT_EndOfDoc );
290 col.insert( pf_Frag::PFT_FmtMark );
291 }
292 return col;
293 }
294
295
296 /**
297 * This is a static function instead of a member so that
298 * boost::functors can be passed in to this function but boost headers
299 * are not needed in pt_PieceTable.h
300 *
301 */
_tellListenerSubsetWalkRange(pt_PieceTable * pt,PL_Listener * pListener,PD_DocumentRange *,PT_DocPosition rangeStartPos,PT_DocPosition rangeEndPos,f_WalkRangeFinished_t finishedFunctor=finishedFunctorEndOfRage,m_fragtypecol_t & fragmentTypesToVisit=_getTellListenerSubsetWalkRangeVisitAllFragments (),bool walkForwards=true)302 static PT_DocPosition _tellListenerSubsetWalkRange(
303 pt_PieceTable* pt,
304 PL_Listener* pListener,
305 PD_DocumentRange* /*pDocRange*/,
306 PT_DocPosition rangeStartPos,
307 PT_DocPosition rangeEndPos,
308 f_WalkRangeFinished_t finishedFunctor = finishedFunctorEndOfRage,
309 m_fragtypecol_t& fragmentTypesToVisit = _getTellListenerSubsetWalkRangeVisitAllFragments(),
310 bool walkForwards = true )
311 {
312 UT_DEBUGMSG(("_tellListenerSubsetWalkRange(top) listener %p startpos %d endpos %d\n",
313 pListener, rangeStartPos, rangeEndPos ));
314 fl_ContainerLayout* sfh = 0;
315 UT_uint32 blockOffset = 0;
316
317 pf_Frag * pf1 = NULL;
318 PT_BlockOffset fragOffset1 = 0;
319 PT_BlockOffset endOffset = 0;
320 PT_DocPosition pfPos = rangeStartPos;
321 if( !walkForwards )
322 pfPos = rangeEndPos;
323
324 if (!pt->getFragFromPosition( pfPos, &pf1, &fragOffset1 ))
325 {
326 UT_DEBUGMSG(("_tellListenerSubsetWalkRange(no frag!) listener %p startpos %d endpos %d\n",
327 pListener, rangeStartPos, rangeEndPos ));
328 return true;
329 }
330
331 PT_DocPosition sum = rangeStartPos - fragOffset1;
332
333 pf_Frag * pf = pf1;
334 for ( ; (pf); )
335 {
336 if( fragmentTypesToVisit.count(pf->getType()))
337 {
338 switch (pf->getType())
339 {
340 case pf_Frag::PFT_Text:
341 {
342 pf_Frag_Text * pft = static_cast<pf_Frag_Text *> (pf);
343 PX_ChangeRecord * pcr = NULL;
344 if( rangeEndPos < sum+pf->getLength() )
345 endOffset = (rangeEndPos - sum);
346 else
347 endOffset = pf->getLength();
348 bool bStatus1 = pft->createSpecialChangeRecord(&pcr,sum,blockOffset,fragOffset1,endOffset);
349 if(!bStatus1) {
350 UT_DEBUGMSG(("_tellListenerSubsetWalkRange(st1) a\n" ));
351 }
352 UT_return_val_if_fail (bStatus1,false);
353 bool bStatus2 = pListener->populate(sfh,pcr);
354 if (pcr)
355 delete pcr;
356 if (!bStatus2)
357 return false;
358 blockOffset += pf->getLength();
359 fragOffset1 = 0;
360 }
361 break;
362
363 case pf_Frag::PFT_Strux:
364 {
365 pf_Frag_Strux * pfs = static_cast<pf_Frag_Strux *> (pf);
366 pf_Frag_Strux* sdh = pfs;
367 sfh = 0;
368 PX_ChangeRecord * pcr = NULL;
369 bool bStatus1 = pfs->createSpecialChangeRecord(&pcr,sum);
370 if(!bStatus1) {
371 UT_DEBUGMSG(("_tellListenerSubsetWalkRange(st1) b\n" ));
372 }
373 UT_return_val_if_fail (bStatus1,false);
374 bool bStatus2 = pListener->populateStrux(sdh,pcr,&sfh);
375 if (pcr)
376 delete pcr;
377 if (!bStatus2)
378 return false;
379 blockOffset = 0;
380 }
381 break;
382
383 case pf_Frag::PFT_Object:
384 {
385 pf_Frag_Object * pfo = static_cast<pf_Frag_Object *> (pf);
386 PX_ChangeRecord * pcr = NULL;
387 bool bStatus1 = pfo->createSpecialChangeRecord(&pcr,sum,blockOffset);
388 if(!bStatus1) {
389 UT_DEBUGMSG(("_tellListenerSubsetWalkRange(st1) c\n" ));
390 }
391 UT_return_val_if_fail (bStatus1,false);
392 bool bStatus2 = pListener->populate(sfh,pcr);
393 if (pcr)
394 delete pcr;
395 if (!bStatus2)
396 return false;
397 blockOffset += pf->getLength();
398 }
399 break;
400
401 case pf_Frag::PFT_FmtMark:
402 {
403 pf_Frag_FmtMark * pffm = static_cast<pf_Frag_FmtMark *> (pf);
404 PX_ChangeRecord * pcr = NULL;
405 bool bStatus1 = pffm->createSpecialChangeRecord(&pcr,sum,blockOffset);
406 if(!bStatus1) {
407 UT_DEBUGMSG(("_tellListenerSubsetWalkRange(st1) d\n" ));
408 }
409 UT_return_val_if_fail (bStatus1,false);
410 bool bStatus2 = pListener->populate(sfh,pcr);
411 DELETEP(pcr);
412 if (!bStatus2)
413 return false;
414 blockOffset += pf->getLength();
415 }
416 break;
417
418 case pf_Frag::PFT_EndOfDoc:
419 // they don't get to know about this.
420 break;
421
422 default:
423 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
424 return false;
425 }
426 }
427
428 UT_DEBUGMSG(("_tellListenerSubsetWalkRange(loop) listener %p sum %d startpos %d endpos %d\n",
429 pListener, sum, rangeStartPos, rangeEndPos ));
430
431 sum += pf->getLength();
432 if( finishedFunctor( rangeStartPos, rangeEndPos, sum, pListener ) )
433 break;
434
435 if( walkForwards )
436 {
437 pf=pf->getNext();
438 }
439 else
440 {
441 pf=pf->getPrev();
442 }
443 }
444
445 UT_DEBUGMSG(("_tellListenerSubsetWalkRange(done) listener %p startpos %d endpos %d\n",
446 pListener, rangeStartPos, rangeEndPos ));
447 return sum;
448 }
449
450
451
tellListenerSubset(PL_Listener * pListener,PD_DocumentRange * pDocRange,PL_ListenerCoupleCloser * closer)452 bool pt_PieceTable::tellListenerSubset( PL_Listener * pListener,
453 PD_DocumentRange * pDocRange,
454 PL_ListenerCoupleCloser* closer )
455 {
456 // walk the subset of the document in the given range
457 // and send notifications.
458
459 if( closer )
460 {
461 closer->setDocument( getDocument() );
462 closer->setDelegate( pListener );
463 }
464 m_fragtypecol_t closerFragmentTypesToVisit;
465 closerFragmentTypesToVisit.insert( pf_Frag::PFT_Object );
466 closerFragmentTypesToVisit.insert( pf_Frag::PFT_Strux );
467
468
469 //bool rc = 0;
470
471 if( closer )
472 {
473 /*rc =*/ _tellListenerSubsetWalkRange( this,
474 closer,
475 pDocRange,
476 pDocRange->m_pos1,
477 pDocRange->m_pos2 );
478
479 /**
480 * Emit the start tag for things that are closed in the
481 * selected range but are not opened in that range.
482 *
483 * Note that we walk backwards from the start of the range in
484 * order to find the matching open tags as quickly as possible
485 * even if the selection is at the end of a really large
486 * document.
487 *
488 * A null delegate is used while we are walking backwards. If
489 * we allowed the closer to emit to the real delegate then the
490 * calls to populate() on the delegate would happen in reverse
491 * document order. So we walk backwards to find the real
492 * startPos that the closer needs and then refresh the closer
493 * by walking the range again (in case it uses stacks which
494 * were erased during the reverse walk), and then use the real
495 * delegate and walk forwards from the correct startPos that
496 * we just found. This is admittedly a bit tricky, but for a
497 * 1000 page document we really really don't want to walk all
498 * the way from the start, so walking the range twice is
499 * likely to be a small trade off in performance.
500 */
501 if( PL_FinishingListener* cl = closer->getBeforeContentListener() )
502 {
503 bool walkForwards = false;
504 f_WalkRangeFinished_t f = boost::bind( finishedFunctorFinishingListener, _1, _2, _3, _4, cl );
505
506 PL_FinishingListener* nullListener = closer->getNullContentListener();
507 closer->setDelegate( nullListener );
508 PT_DocPosition startPos = _tellListenerSubsetWalkRange( this, cl,
509 pDocRange, 0, pDocRange->m_pos1,
510 f, closerFragmentTypesToVisit, walkForwards );
511
512 closer->setDelegate( pListener );
513 closer->reset();
514 /*rc =*/ _tellListenerSubsetWalkRange( this,
515 closer,
516 pDocRange,
517 pDocRange->m_pos1,
518 pDocRange->m_pos2 );
519
520 /*rc =*/ _tellListenerSubsetWalkRange( this, cl,
521 pDocRange, startPos, pDocRange->m_pos1,
522 f, closerFragmentTypesToVisit, walkForwards );
523
524 }
525 }
526
527 /*rc =*/ _tellListenerSubsetWalkRange( this, pListener,
528 pDocRange, pDocRange->m_pos1, pDocRange->m_pos2 );
529
530 if( closer )
531 {
532 /**
533 * emit the close tag for things that were left open in the range.
534 */
535 if( PL_FinishingListener* cl = closer->getAfterContentListener() )
536 {
537 f_WalkRangeFinished_t f = boost::bind( finishedFunctorFinishingListener, _1, _2, _3, _4, cl );
538 /*rc =*/ _tellListenerSubsetWalkRange( this, cl,
539 pDocRange, pDocRange->m_pos2, 0,
540 f, closerFragmentTypesToVisit );
541 }
542 }
543
544
545 // MIQ:2011, old code...
546 // move to using the above walker to allow mulitpass processing....
547 #if 0
548
549 fl_ContainerLayout* sfh = 0;
550 UT_uint32 blockOffset = 0;
551
552 pf_Frag * pf1 = NULL;
553 PT_BlockOffset fragOffset1 = 0;
554 PT_BlockOffset endOffset = 0;
555
556 if (!getFragFromPosition(pDocRange->m_pos1, &pf1, &fragOffset1))
557 return true;
558
559 PT_DocPosition sum = pDocRange->m_pos1 - fragOffset1;
560
561 pf_Frag * pf = pf1;
562 for ( ; (pf); pf=pf->getNext())
563 {
564 switch (pf->getType())
565 {
566 case pf_Frag::PFT_Text:
567 {
568 pf_Frag_Text * pft = static_cast<pf_Frag_Text *> (pf);
569 PX_ChangeRecord * pcr = NULL;
570 if (pDocRange->m_pos2 < sum+pf->getLength())
571 endOffset = (pDocRange->m_pos2 - sum);
572 else
573 endOffset = pf->getLength();
574 bool bStatus1 = pft->createSpecialChangeRecord(&pcr,sum,blockOffset,fragOffset1,endOffset);
575 UT_return_val_if_fail (bStatus1,false);
576 bool bStatus2 = pListener->populate(sfh,pcr);
577 if (pcr)
578 delete pcr;
579 if (!bStatus2)
580 return false;
581 blockOffset += pf->getLength();
582 fragOffset1 = 0;
583 }
584 break;
585
586 case pf_Frag::PFT_Strux:
587 {
588 pf_Frag_Strux * pfs = static_cast<pf_Frag_Strux *> (pf);
589 pf_Frag_Strux* sdh = pf;
590 sfh = 0;
591 PX_ChangeRecord * pcr = NULL;
592 bool bStatus1 = pfs->createSpecialChangeRecord(&pcr,sum);
593 UT_return_val_if_fail (bStatus1,false);
594 bool bStatus2 = pListener->populateStrux(sdh,pcr,&sfh);
595 if( closer )
596 closer->populateStrux(sdh,pcr,&sfh);
597 if (pcr)
598 delete pcr;
599 if (!bStatus2)
600 return false;
601 blockOffset = 0;
602 }
603 break;
604
605 case pf_Frag::PFT_Object:
606 {
607 pf_Frag_Object * pfo = static_cast<pf_Frag_Object *> (pf);
608 PX_ChangeRecord * pcr = NULL;
609 bool bStatus1 = pfo->createSpecialChangeRecord(&pcr,sum,blockOffset);
610 UT_return_val_if_fail (bStatus1,false);
611 bool bStatus2 = pListener->populate(sfh,pcr);
612 if( closer )
613 closer->populate(sfh,pcr);
614 if (pcr)
615 delete pcr;
616 if (!bStatus2)
617 return false;
618 blockOffset += pf->getLength();
619 }
620 break;
621
622 case pf_Frag::PFT_FmtMark:
623 {
624 pf_Frag_FmtMark * pffm = static_cast<pf_Frag_FmtMark *> (pf);
625 PX_ChangeRecord * pcr = NULL;
626 bool bStatus1 = pffm->createSpecialChangeRecord(&pcr,sum,blockOffset);
627 UT_return_val_if_fail (bStatus1,false);
628 bool bStatus2 = pListener->populate(sfh,pcr);
629 DELETEP(pcr);
630 if (!bStatus2)
631 return false;
632 blockOffset += pf->getLength();
633 }
634 break;
635
636 case pf_Frag::PFT_EndOfDoc:
637 // they don't get to know about this.
638 break;
639
640 default:
641 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
642 return false;
643 }
644
645 sum += pf->getLength();
646 if (sum >= pDocRange->m_pos2)
647 break;
648 }
649
650 // MIQ:2011
651 // The closer might want to inspect elements after the selected
652 // range to find end tags to emit as well. This allows things with
653 // a separate start and end element to have the end sent to the
654 // pListener although that end might not itself be in the range.
655 // Without this, we might have a bookmark-start but no matching
656 // bookmark-end, which will make a generated document invalid.
657 //
658 if( closer )
659 {
660 closer->setDelegate( pListener );
661 for ( ; (pf); pf=pf->getNext())
662 {
663 switch (pf->getType())
664 {
665 case pf_Frag::PFT_Strux:
666 {
667 pf_Frag_Strux * pfs = static_cast<pf_Frag_Strux *> (pf);
668 pf_Frag_Strux* sdh = pf;
669 sfh = 0;
670 PX_ChangeRecord * pcr = NULL;
671 bool bStatus1 = pfs->createSpecialChangeRecord(&pcr,sum);
672 UT_return_val_if_fail (bStatus1,false);
673 closer->populateStruxClose(sdh,pcr,&sfh);
674 if (pcr)
675 delete pcr;
676 blockOffset = 0;
677 }
678 break;
679
680 case pf_Frag::PFT_Object:
681 {
682 pf_Frag_Object * pfo = static_cast<pf_Frag_Object *> (pf);
683 PX_ChangeRecord * pcr = NULL;
684 bool bStatus1 = pfo->createSpecialChangeRecord(&pcr,sum,blockOffset);
685 UT_return_val_if_fail (bStatus1,false);
686 closer->populateClose(sfh,pcr);
687 if (pcr)
688 delete pcr;
689 blockOffset += pf->getLength();
690 }
691 break;
692 }
693
694 if( closer->isFinished() )
695 break;
696 }
697 }
698 #endif
699
700 return true;
701 }
702