1 /* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */
2 /* AbiWord
3  * Copyright (C) 1998 AbiSource, Inc.
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 
22 // deleteStrux-related functions for class pt_PieceTable.
23 
24 #include "ut_types.h"
25 #include "ut_misc.h"
26 #include "ut_assert.h"
27 #include "ut_debugmsg.h"
28 #include "ut_growbuf.h"
29 #include "pt_PieceTable.h"
30 #include "pf_Frag.h"
31 #include "pf_Frag_Strux.h"
32 #include "pf_Frag_Strux_Block.h"
33 #include "pf_Frag_Strux_Section.h"
34 #include "pf_Frag_Text.h"
35 #include "pf_Fragments.h"
36 #include "px_ChangeRecord.h"
37 #include "px_CR_Span.h"
38 #include "px_CR_SpanChange.h"
39 #include "px_CR_Strux.h"
40 
41 /****************************************************************/
42 /****************************************************************/
_unlinkStrux(pf_Frag_Strux * pfs,pf_Frag ** ppfEnd,UT_uint32 * pfragOffsetEnd)43 bool pt_PieceTable::_unlinkStrux(pf_Frag_Strux * pfs,
44 									pf_Frag ** ppfEnd, UT_uint32 * pfragOffsetEnd)
45 {
46 #if DEBUG
47 	if(pfs->getStruxType() == PTX_SectionTable)
48 	{
49 		UT_DEBUGMSG(("_unlink Strux Table %p \n",pfs));
50 	}
51 	else if(pfs->getStruxType() == PTX_SectionCell)
52 	{
53 		UT_DEBUGMSG(("_unlink Strux Cell %p \n",pfs));
54 	}
55 	else if(pfs->getStruxType() == PTX_EndTable)
56 	{
57 		UT_DEBUGMSG(("_unlink Strux End Table %p \n",pfs));
58 	}
59 	else if(pfs->getStruxType() == PTX_EndCell)
60 	{
61 		UT_DEBUGMSG(("_unlink Strux EndCell %p \n",pfs));
62 	}
63 	else if(pfs->getStruxType() == PTX_SectionFrame)
64 	{
65 		UT_DEBUGMSG(("_unlink Strux SectionFrame %p \n",pfs));
66 	}
67 	else if(pfs->getStruxType() == PTX_EndFrame)
68 	{
69 		UT_DEBUGMSG(("_unlink Strux EndFrame %p \n",pfs));
70 	}
71 	else if(pfs->getStruxType() == PTX_Block)
72 	{
73 		UT_DEBUGMSG(("_unlink Strux Block %p \n",pfs));
74 	}
75 	else if(pfs->getStruxType() == PTX_Section)
76 	{
77 		UT_DEBUGMSG(("_unlink Strux Section %p \n",pfs));
78 	}
79 	else if(pfs->getStruxType() == PTX_SectionHdrFtr)
80 	{
81 		UT_DEBUGMSG(("_unlink HdrFtr Strux Section %p \n",pfs));
82 	}
83 	else if(pfs->getStruxType() == PTX_SectionFootnote)
84 	{
85 		UT_DEBUGMSG(("_unlink Strux SectionFootnote %p \n",pfs));
86 	}
87 	else if(pfs->getStruxType() == PTX_EndFootnote)
88 	{
89 		UT_DEBUGMSG(("_unlink Strux EndFootnote %p \n",pfs));
90 	}
91 	else if(pfs->getStruxType() == PTX_SectionEndnote)
92 	{
93 		UT_DEBUGMSG(("_unlink Strux SectionEndnote %p \n",pfs));
94 	}
95 	else if(pfs->getStruxType() == PTX_EndEndnote)
96 	{
97 		UT_DEBUGMSG(("_unlink Strux EndEndnote %p \n",pfs));
98 	}
99 	else if(pfs->getStruxType() == PTX_SectionTOC)
100 	{
101 		UT_DEBUGMSG(("_unlink Strux SectionTOC %p \n",pfs));
102 	}
103 	else if(pfs->getStruxType() == PTX_EndTOC)
104 	{
105 		UT_DEBUGMSG(("_unlink Strux EndTOC %p \n",pfs));
106 	}
107 //	m_pDocument->miniDump(pfs, 2);
108 #endif
109 	switch (pfs->getStruxType())
110 	{
111 	case PTX_Section:
112 	case PTX_SectionHdrFtr:
113 	case PTX_SectionEndnote:
114 	case PTX_SectionTable:
115 	case PTX_SectionFrame:
116 	case PTX_SectionCell:
117 	case PTX_SectionFootnote:
118 	case PTX_SectionAnnotation:
119 	case PTX_SectionTOC:
120 	case PTX_EndCell:
121 	case PTX_EndTable:
122 	case PTX_EndFootnote:
123 	case PTX_EndEndnote:
124 	case PTX_EndAnnotation:
125 	case PTX_EndFrame:
126 	case PTX_EndTOC:
127 		return _unlinkStrux_Section(pfs,ppfEnd,pfragOffsetEnd);
128 
129 	case PTX_Block:
130 		return _unlinkStrux_Block(pfs,ppfEnd,pfragOffsetEnd);
131 
132 	default:
133 		UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
134 		return false;
135 	}
136 }
137 
_unlinkStrux_Block(pf_Frag_Strux * pfs,pf_Frag ** ppfEnd,UT_uint32 * pfragOffsetEnd)138 bool pt_PieceTable::_unlinkStrux_Block(pf_Frag_Strux * pfs,
139 										  pf_Frag ** ppfEnd, UT_uint32 * pfragOffsetEnd)
140 {
141 	UT_return_val_if_fail (pfs->getStruxType()==PTX_Block,false);
142 
143 	// unlink this Block strux from the document.
144 	// the caller is responsible for deleting pfs.
145 
146 	if (ppfEnd)
147 		*ppfEnd = pfs->getNext();
148 	if (pfragOffsetEnd)
149 		*pfragOffsetEnd = 0;
150 
151 	// find the previous strux (either a paragraph or something else).
152 
153 	pf_Frag_Strux * pfsPrev = NULL;
154 	_getStruxFromPosition(pfs->getPos(),&pfsPrev, true); // should that really skip footnotes?
155 	UT_return_val_if_fail (pfsPrev, false);			// we have a block that's not in a section ??
156 	//
157 	// Code to prevent a crash. But this should not happen and if it does not everything will
158     // be deleted - Sevior.
159 	//
160 	if(pfsPrev == NULL)
161 	{
162 		_unlinkFrag(pfs,ppfEnd,pfragOffsetEnd);
163 		UT_DEBUGMSG(("shoudln't happen."));
164 		UT_ASSERT(0);
165 		return false;
166 	}
167 
168 	switch (pfsPrev->getStruxType())
169 	{
170 
171 	case PTX_Block:
172 		// if there is a paragraph before us, we can delete this
173 		// paragraph knowing that our content will be assimilated
174 		// in to the previous one.
175 
176 		_unlinkFrag(pfs,ppfEnd,pfragOffsetEnd);
177 		return true;
178 
179 	case PTX_Section:
180 		// we are the first paragraph in this section.  if we have
181 		// content, we cannot be deleted, since there is no one to
182 		// inherit our content.
183 	  UT_DEBUGMSG(("Prev frag is section in delete strux block \n"));
184 		if (!_struxIsEmpty(pfs))
185 		{
186 			// TODO decide if this should assert or just fail...
187 			UT_DEBUGMSG(("Cannot delete first paragraph with content.\n"));
188 			UT_ASSERT_HARMLESS(0);
189 			return false;
190 		}
191 		//
192 		// Check to see if this is the first section of the document.
193 		//
194 		if(pfsPrev->getPrev() == NULL)
195 		{
196 		  pf_Frag * pfNext = pfs->getNext();
197 		  if(pfNext == NULL)
198 		  {
199 		    //
200 		    // Cannot delete this because then there will be no page
201 		    //
202 			UT_DEBUGMSG(("Cannot delete only paragraph.\n"));
203 			UT_ASSERT_HARMLESS(0);
204 			return false;
205 		  }
206 		  if(pfNext->getType() == pf_Frag::PFT_Strux)
207 		  {
208 		      pf_Frag_Strux * pfsNext = static_cast<pf_Frag_Strux *>(pfNext);
209 		      if(pfsNext->getStruxType() == PTX_SectionHdrFtr)
210 		      {
211 		    //
212 		    // Cannot delete this because then there will be no page
213 		    //
214 			  UT_DEBUGMSG(("Cannot delete only paragraph.\n"));
215 			  UT_ASSERT_HARMLESS(0);
216 			  return false;
217 		      }
218 		      if(pfsNext->getStruxType() == PTX_SectionFrame)
219 		      {
220 		    //
221 		    // Cannot delete this because then there will be nowhere
222 		    // for the frame
223 		    //
224 			  UT_DEBUGMSG(("Cannot delete becase we need the frame.\n"));
225 			  UT_ASSERT_HARMLESS(0);
226 			  return false;
227 		      }
228 		  }
229 		}
230 
231 	case PTX_SectionHdrFtr:
232 		// we are the first paragraph in this section.  if we have
233 		// content, we cannot be deleted, since there is no one to
234 		// inherit our content.
235 
236 		if (!_struxIsEmpty(pfs))
237 		{
238 			// TODO decide if this should assert or just fail...
239 			UT_DEBUGMSG(("Cannot delete first paragraph with content.\n"));
240 			UT_ASSERT_HARMLESS(0);
241 			return false;
242 		}
243 
244 		// no content in this paragraph.
245 
246 		_unlinkFrag(pfs,ppfEnd,pfragOffsetEnd);
247 		return true;
248 
249 	case PTX_SectionFrame:
250     case PTX_EndFrame:
251 	case PTX_SectionTable:
252 	case PTX_SectionCell:
253 	case PTX_EndCell:
254 	case PTX_EndTable:
255 //
256 // deleting tables and cells is a mutlti-step process and we can make no assumptions
257 // along the way.
258 //
259 		_unlinkFrag(pfs,ppfEnd,pfragOffsetEnd);
260 		return true;
261 
262 
263 	default:
264 		UT_ASSERT_HARMLESS(0);
265 		return false;
266 	}
267 }
268 
_unlinkStrux_Section(pf_Frag_Strux * pfs,pf_Frag ** ppfEnd,UT_uint32 * pfragOffsetEnd)269 bool pt_PieceTable::_unlinkStrux_Section(pf_Frag_Strux * pfs,
270 											pf_Frag ** ppfEnd, UT_uint32 * pfragOffsetEnd)
271 {
272 	UT_return_val_if_fail (pfs->getStruxType()==PTX_Section
273 			  || pfs->getStruxType()==PTX_SectionHdrFtr
274 			  || pfs->getStruxType()==PTX_SectionEndnote
275 			  || pfs->getStruxType()==PTX_SectionTable
276 			  || pfs->getStruxType()==PTX_SectionFrame
277 			  || pfs->getStruxType()==PTX_SectionCell
278 			  || pfs->getStruxType()==PTX_EndCell
279 			  || pfs->getStruxType()==PTX_EndTable
280 			  || pfs->getStruxType()==PTX_EndFrame
281 			  || pfs->getStruxType()==PTX_SectionFootnote
282 			  || pfs->getStruxType()==PTX_EndFootnote
283 			  || pfs->getStruxType()==PTX_SectionAnnotation
284 			  || pfs->getStruxType()==PTX_EndAnnotation
285 			  || pfs->getStruxType()==PTX_SectionEndnote
286 			  || pfs->getStruxType()==PTX_EndEndnote
287 			  || pfs->getStruxType()==PTX_SectionTOC
288 			  || pfs->getStruxType()==PTX_EndTOC, false );
289 
290 	// unlink this Section strux from the document.
291 	// the caller is responsible for deleting pfs.
292 
293 	if (ppfEnd)
294 		*ppfEnd = pfs->getNext();
295 	if (pfragOffsetEnd)
296 		*pfragOffsetEnd = 0;
297 
298 	// find the previous strux (either a paragraph or something else).
299 
300 	pf_Frag_Strux * pfsPrev = NULL;
301 	pf_Frag * pf = pfs->getPrev();
302 	while (pf && (!pfsPrev || isFootnote(pf) || isEndFootnote(pf)))
303 	{
304 		if (pf->getType() == pf_Frag::PFT_Strux)
305 			pfsPrev = static_cast<pf_Frag_Strux *> (pf);
306 		pf = pf->getPrev();
307 	}
308 
309 	if (!pfsPrev)
310 	{
311 		// first section in the document cannot be deleted.
312 		// TODO decide if this should assesrt or just file...
313 		UT_DEBUGMSG(("Cannot delete first section in document.\n"));
314 		UT_ASSERT_HARMLESS(0);
315 		return false;
316 	}
317 
318 	// delete frag from the embedded_strux list if needed
319 	if ((pfs->getStruxType() == PTX_SectionFootnote) ||
320 		(pfs->getStruxType() == PTX_SectionEndnote) ||
321 		(pfs->getStruxType() == PTX_SectionAnnotation))
322 	{
323 		bool bNoteRemoved = false;
324 		if (!m_embeddedStrux.empty())
325 		{
326 			std::list<embeddedStrux>::iterator it;
327 			for (it = m_embeddedStrux.begin(); it != m_embeddedStrux.end(); ++it)
328 			{
329 				if ((*it).beginNote == pfs)
330 				{
331 					m_embeddedStrux.erase(it);
332 					bNoteRemoved = true;
333 					break;
334 				}
335 			}
336 		}
337 		if (!bNoteRemoved)
338 		{
339 			UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
340 		}
341 	}
342 
343 	switch (pfsPrev->getStruxType())
344 	{
345 	case PTX_Block:
346 		// if there is a paragraph before us, we can delete this
347 		// section knowing that our paragraphs will be assimilated
348 		// in to the previous section (that is, the container of
349 		// this block).
350 
351 		_unlinkFrag(pfs,ppfEnd,pfragOffsetEnd);
352 		return true;
353 	case PTX_SectionTable:
354         //
355         // deleting tables is a multi-step process that can't make assumptions
356         // on a single step
357 		_unlinkFrag(pfs,ppfEnd,pfragOffsetEnd);
358 		return true;
359 	case PTX_SectionFrame:
360         //
361         // deleting Frames is a multi-step process that can't make assumptions
362         // on a single step
363 		_unlinkFrag(pfs,ppfEnd,pfragOffsetEnd);
364 		return true;
365 	case PTX_EndFrame:
366         //
367         // deleting Frames is a multi-step process that can't make assumptions
368         // on a single step
369 		_unlinkFrag(pfs,ppfEnd,pfragOffsetEnd);
370 		return true;
371 
372 	case PTX_SectionCell:
373         //
374         // deleting tables is a multi-step process that can't make assumptions
375         // on a single step
376 		_unlinkFrag(pfs,ppfEnd,pfragOffsetEnd);
377 		return true;
378 
379 	case PTX_EndCell:
380         //
381         // deleting tables is a multi-step process that can't make assumptions
382         // on a single step
383 		_unlinkFrag(pfs,ppfEnd,pfragOffsetEnd);
384 		return true;
385 
386 	case PTX_EndTable:
387         //
388         // deleting tables is a multi-step process that can't make assumptions
389         // on a single step
390 		_unlinkFrag(pfs,ppfEnd,pfragOffsetEnd);
391 		return true;
392 
393 	case PTX_SectionEndnote:
394         //
395         // deleting Endnotes is a multi-step process that can't make
396         // assumptions
397         // on a single step
398 		_unlinkFrag(pfs,ppfEnd,pfragOffsetEnd);
399 		return true;
400 
401 	case PTX_EndEndnote:
402         //
403         // deleting Endnotes is a multi-step process that can't make
404         // assumptions
405         // on a single step
406 		_unlinkFrag(pfs,ppfEnd,pfragOffsetEnd);
407 		return true;
408 
409 
410 	case PTX_SectionTOC:
411         //
412         // deleting TOC is a multi-step process that can't make
413         // assumptions
414         // on a single step
415 		_unlinkFrag(pfs,ppfEnd,pfragOffsetEnd);
416 		return true;
417 
418 	case PTX_EndTOC:
419         //
420         // deleting TOC is a multi-step process that can't make
421         // assumptions
422         // on a single step
423 		_unlinkFrag(pfs,ppfEnd,pfragOffsetEnd);
424 		return true;
425 
426 
427 	case PTX_SectionFootnote:
428         //
429         // deleting Footnotes is a multi-step process that can't make
430         // assumptions
431         // on a single step
432 		_unlinkFrag(pfs,ppfEnd,pfragOffsetEnd);
433 		return true;
434 
435 	case PTX_EndFootnote:
436         //
437         // deleting Footnotes is a multi-step process that can't make
438         // assumptions
439         // on a single step
440 		_unlinkFrag(pfs,ppfEnd,pfragOffsetEnd);
441 		return true;
442 
443 
444 
445 	case PTX_SectionAnnotation:
446         //
447         // deleting Annotations is a multi-step process that can't make
448         // assumptions
449         // on a single step
450 		_unlinkFrag(pfs,ppfEnd,pfragOffsetEnd);
451 		return true;
452 
453 	case PTX_EndAnnotation:
454         //
455         // deleting Annotations is a multi-step process that can't make
456         // assumptions
457         // on a single step
458 		_unlinkFrag(pfs,ppfEnd,pfragOffsetEnd);
459 		return true;
460 
461 
462 	case PTX_Section:
463 	  //
464 	  // We can delete Tables provided there is a block to take it's place later
465 	  //
466 	        if((pfs->getStruxType() == PTX_SectionTable) || (pfs->getStruxType() == PTX_EndTable))
467 		{
468 		    _unlinkFrag(pfs,ppfEnd,pfragOffsetEnd);
469 		    return true;
470 		}
471 		// there are no blocks (paragraphs) between this section
472 		// and the previous section.  this is not possible.
473 		// TODO decide if this should assert or just fail...
474 		UT_DEBUGMSG(("No blocks between sections ??\n"));
475 		UT_ASSERT_HARMLESS(0);
476 		return false;
477 
478 
479 	case PTX_SectionHdrFtr:
480 	        if((pfs->getStruxType() == PTX_SectionTable) || (pfs->getStruxType() == PTX_EndTable))
481 		{
482 		    _unlinkFrag(pfs,ppfEnd,pfragOffsetEnd);
483 		    return true;
484 		}
485 		// there are no blocks (paragraphs) between this section
486 		// and the previous section.  this is not possible.
487 		// TODO decide if this should assert or just fail...
488         //
489         // Actually this is OK if it's a hdrFtr that has not been
490 		// "realized" yet. Like an even hdrftr that has been defined
491         // but no even pages exist yet.
492 		UT_DEBUGMSG(("No blocks between sections ??\n"));
493 //		_unlinkFrag(pfs,ppfEnd,pfragOffsetEnd);
494 		UT_ASSERT_HARMLESS(0);
495 		return false;
496 
497 	default:
498 		UT_ASSERT_HARMLESS(0);
499 		return false;
500 	}
501 }
502 
_deleteStruxWithNotify(PT_DocPosition dpos,pf_Frag_Strux * pfs,pf_Frag ** ppfEnd,UT_uint32 * pfragOffsetEnd,bool bWithRec)503 bool pt_PieceTable::_deleteStruxWithNotify(PT_DocPosition dpos,
504 										   pf_Frag_Strux * pfs,
505 										   pf_Frag ** ppfEnd,
506 										   UT_uint32 * pfragOffsetEnd,
507 										   bool bWithRec)
508 {
509 	UT_return_val_if_fail(pfs, false);
510 	PX_ChangeRecord_Strux * pcrs
511 		= new PX_ChangeRecord_Strux(PX_ChangeRecord::PXT_DeleteStrux,
512 									dpos, pfs->getIndexAP(), pfs->getXID(), pfs->getStruxType());
513 	UT_return_val_if_fail (pcrs, false);
514 
515 	if (!_unlinkStrux(pfs,ppfEnd,pfragOffsetEnd))
516 		return false;
517 
518 	// add record to history.  we do not attempt to coalesce these.
519 	if (bWithRec)
520 		m_history.addChangeRecord(pcrs);
521 	m_pDocument->notifyListeners(pfs,pcrs);
522 
523 	delete pfs;
524 
525 	return true;
526 }
527 
528 /*!
529  * This method scans the piecetAble from the section Frag_strux given looking
530  * for any Header/Footers that belong to the strux. If it finds them, they
531  * are deleted with notifications.
532 \param pf_Frag_Strux_Section pfStruxSec the Section strux that might have headers
533  *                                        or footers belonging to it.
534  * These must be deleted with notification otherwise they won't be recreated on
535  * an undo
536  */
_deleteHdrFtrsFromSectionStruxIfPresent(pf_Frag_Strux_Section * pfStruxSec)537 bool pt_PieceTable::_deleteHdrFtrsFromSectionStruxIfPresent(pf_Frag_Strux_Section * pfStruxSec)
538 {
539 	//
540 	// Get the index to the Attributes/properties of the section strux to see if
541 	// if there is a header defined for this strux.
542 	//
543 	// FIXME: Handle all the new header/footer types.
544 	PT_AttrPropIndex indexAP = pfStruxSec->getIndexAP();
545 	const PP_AttrProp * pAP = NULL;
546 	getAttrProp(indexAP, &pAP);
547 	UT_Vector vecHdrFtr;
548 	UT_String HeaderV,HeaderEvenV,HeaderLastV,HeaderFirstV;
549 	UT_String FooterV,FooterEvenV,FooterLastV,FooterFirstV;
550 	vecHdrFtr.clear();
551 	const gchar * szHeaderV = NULL;
552 	bool bres = pAP->getAttribute("header",szHeaderV);
553 	if(szHeaderV && *szHeaderV && (strcmp(szHeaderV,"0") != 0))
554 	{
555 		HeaderV = szHeaderV;
556 		vecHdrFtr.addItem((void *) HeaderV.c_str());
557 	}
558 	szHeaderV =  NULL;
559 	bres = pAP->getAttribute("header-even",szHeaderV);
560 	if(szHeaderV && *szHeaderV && (strcmp(szHeaderV,"0") != 0))
561 	{
562 		HeaderEvenV = szHeaderV;
563 		vecHdrFtr.addItem((void *) HeaderEvenV.c_str());
564 	}
565 	szHeaderV =  NULL;
566 	bres = pAP->getAttribute("header-last",szHeaderV);
567 	if(szHeaderV && *szHeaderV && (strcmp(szHeaderV,"0") != 0))
568 	{
569 		HeaderLastV = szHeaderV;
570 		vecHdrFtr.addItem((void *) HeaderLastV.c_str());
571 	}
572 	szHeaderV =  NULL;
573 	bres = pAP->getAttribute("header-first",szHeaderV);
574 	if(szHeaderV && *szHeaderV && (strcmp(szHeaderV,"0") != 0))
575 	{
576 		HeaderFirstV = szHeaderV;
577 		vecHdrFtr.addItem((void *) HeaderFirstV.c_str());
578 	}
579 	szHeaderV =  NULL;
580 	bres = pAP->getAttribute("footer",szHeaderV);
581 	if(szHeaderV && *szHeaderV && (strcmp(szHeaderV,"0") != 0))
582 	{
583 		FooterV = szHeaderV;
584 		vecHdrFtr.addItem((void *) FooterV.c_str());
585 	}
586 	szHeaderV =  NULL;
587 	bres = pAP->getAttribute("footer-even",szHeaderV);
588 	if(szHeaderV && *szHeaderV && (strcmp(szHeaderV,"0") != 0))
589 	{
590 		FooterEvenV = szHeaderV;
591 		vecHdrFtr.addItem((void *) FooterEvenV.c_str());
592 	}
593 	szHeaderV =  NULL;
594 	bres = pAP->getAttribute("footer-last",szHeaderV);
595 	if(szHeaderV && *szHeaderV && (strcmp(szHeaderV,"0") != 0))
596 	{
597 		FooterLastV = szHeaderV;
598 		vecHdrFtr.addItem((void *) FooterLastV.c_str());
599 	}
600 	szHeaderV =  NULL;
601 	bres = pAP->getAttribute("footer-first",szHeaderV);
602 	if(szHeaderV && *szHeaderV && (strcmp(szHeaderV,"0") != 0))
603 	{
604 		FooterFirstV = szHeaderV;
605 		vecHdrFtr.addItem((void *) FooterFirstV.c_str());
606 	}
607 	UT_sint32 countHdrFtr = vecHdrFtr.getItemCount();
608 	UT_DEBUGMSG(("SEVIOR: Deleting HdrFtrs from Document, num Header/Footers %d\n",countHdrFtr));
609 	if(0 == countHdrFtr)
610 	{
611 		return true;
612 	}
613 //
614 // This section has a header or footer attribute. Scan the piecetable to see
615 // if there is a header strux somewhere with an ID that matches our section.
616 //
617 	pf_Frag * curFrag = NULL;
618 //
619 // Do this loop for all and headers and footers.
620 //
621 	UT_sint32 i = 0;
622 	for(i=0; i< countHdrFtr; i++)
623 	{
624 		curFrag = static_cast<pf_Frag *>(pfStruxSec);
625 		bool bFoundIt = false;
626 		pf_Frag_Strux * curStrux = NULL;
627 		while(curFrag != getFragments().getLast() && !bFoundIt)
628 		{
629 			if(curFrag->getType() == pf_Frag::PFT_Strux)
630 			{
631 				curStrux = static_cast<pf_Frag_Strux *>(curFrag);
632 				if(curStrux->getStruxType() == PTX_SectionHdrFtr)
633 				{
634 //
635 // OK we've got a candidate
636 //
637 					PT_AttrPropIndex indexAPHdr = curStrux->getIndexAP();
638 					const PP_AttrProp * pAPHdr = NULL;
639 					getAttrProp(indexAPHdr, &pAPHdr);
640 					const gchar * szID = NULL;
641 					bres = pAPHdr->getAttribute("id",szID);
642 					UT_DEBUGMSG(("SEVIOR: Found candidate id = %s \n",szID));
643 					if(bres && (szID != NULL))
644 					{
645 					//
646 					// Look for a match.
647 					//
648 						szHeaderV = (const char *) vecHdrFtr.getNthItem(i);
649 						if(szHeaderV != NULL && strcmp(szHeaderV,szID) == 0)
650 						{
651 							bFoundIt = true;
652 						}
653 					}
654 				}
655 			}
656 			curFrag = curFrag->getNext();
657 		}
658 		if(bFoundIt)
659 		{
660 		//
661 		// This Header belongs to our section. It must be deleted.
662 		//
663 			_deleteHdrFtrStruxWithNotify(curStrux);
664 		}
665 	}
666 	return true;
667 }
668 
669 /*!
670  * This method deletes the Header/Footer from the pieceTable in the order that
671  * will allow an undo to recreate it.
672  */
_deleteHdrFtrStruxWithNotify(pf_Frag_Strux * pfFragStruxHdrFtr)673 void pt_PieceTable::_deleteHdrFtrStruxWithNotify( pf_Frag_Strux * pfFragStruxHdrFtr)
674 {
675 //
676 // First we need the document position of the header/footer strux.
677 //
678 	UT_DEBUGMSG(("SEVIOR: Deleting hdrftr \n"));
679 	const pf_Frag * pfFrag = NULL;
680 	pfFrag = static_cast<pf_Frag *>(pfFragStruxHdrFtr);
681 	// TODO HdrFtrPos is unused
682 	UT_DebugOnly<PT_DocPosition> HdrFtrPos = getFragPosition(pfFrag);
683 	UT_Vector vecFragStrux;
684 	UT_DEBUGMSG(("SEVIOR: Deleting hdrftr Strux Pos = %d \n",(PT_DocPosition)HdrFtrPos));
685 //
686 // Now find the first Non-strux frag within this hdrftr
687 //
688 	bool bStop = false;
689 	bool bIsTable = false;
690 	PT_DocPosition posLastStrux = 0;
691 	while((pfFrag->getType() == pf_Frag::PFT_Strux) && (pfFrag != getFragments().getLast()) && !bStop)
692 	{
693 		const pf_Frag_Strux * pfs = static_cast<const pf_Frag_Strux *>(pfFrag);
694 		if(pfs != pfFragStruxHdrFtr && (pfs->getStruxType() != PTX_Block))
695 		{
696 			bStop = true;
697 			if(pfs->getStruxType() == PTX_SectionTable)
698 			{
699 			       bIsTable = true;
700 			}
701 		}
702 		else
703 		{
704 			UT_DEBUGMSG(("Adding strux %p of type %d at Pos %d to strux vector for delete \n",pfs,pfs->getStruxType(),pfs->getPos()));
705 			posLastStrux = pfs->getPos();
706 			vecFragStrux.addItem((void *) pfFrag);
707 			pfFrag = pfFrag->getNext();
708 		}
709 	}
710 	PT_DocPosition TextStartPos = getFragPosition(pfFrag);
711 	if(TextStartPos == posLastStrux && !bIsTable)
712 	{
713 		TextStartPos++;
714 	}
715 	UT_DEBUGMSG(("SEVIOR: Deleting hdrftr Text Start Pos = %d \n",TextStartPos));
716 //
717 // Now find the end of the text in the header/footer
718 //
719 	bool foundEnd = false;
720 	while(!foundEnd)
721 	{
722 		foundEnd = pfFrag == getFragments().getLast();
723 		if(!foundEnd && pfFrag->getType() == pf_Frag::PFT_Strux)
724 		{
725 			const pf_Frag_Strux * pfFragStrux = static_cast<const pf_Frag_Strux *>(pfFrag);
726 			foundEnd = ((pfFragStrux->getStruxType() != PTX_Block) &&
727 						(pfFragStrux->getStruxType() != PTX_SectionTable) &&
728 						(pfFragStrux->getStruxType() != PTX_SectionCell) &&
729 						(pfFragStrux->getStruxType() != PTX_EndTable) &&
730 						(pfFragStrux->getStruxType() != PTX_EndCell));
731 		}
732 		if(!foundEnd)
733 		{
734 			pfFrag = pfFrag->getNext();
735 		}
736 	}
737 	PT_DocPosition TextEndPos = 0;
738 	TextEndPos = getFragPosition(pfFrag);
739 	if(pfFrag == getFragments().getLast())
740 	{
741 		TextEndPos = getFragPosition(pfFrag->getPrev()) + pfFrag->getPrev()->getLength();
742 	}
743 	UT_DEBUGMSG(("SEVIOR: Deleting hdrftr Text End Pos = %d \n",TextEndPos));
744 //
745 // OK delete the text
746 //
747 	if(TextEndPos > TextStartPos)
748 	{
749 		UT_uint32 iRealDeleteCount;
750 		deleteSpan(TextStartPos,TextEndPos,NULL,iRealDeleteCount,true);
751 		// TODO -- is this right with revisions ???
752 	}
753 //
754 // Now delete the struxes at the start.
755 //
756 //
757 	UT_uint32 count = vecFragStrux.getItemCount();
758 	UT_return_if_fail (count > 0);
759 	UT_uint32 i=0;
760 	bool bres = false;
761 //
762 // First delete the HdrFtr strux, then delete the blocks, this will enable the
763 // the HdrFtr to be properly recreated on undo (Since it needs blocks to be
764 // present before it can be created.)
765 //
766 	bres = _deleteStruxWithNotify(pfFragStruxHdrFtr->getPos(),pfFragStruxHdrFtr,NULL,NULL);
767 	for(i=1; i<count; i++)
768 	{
769 		pf_Frag_Strux * pfs = (pf_Frag_Strux *) vecFragStrux.getNthItem(i);
770 		if(static_cast<pf_Frag *>(pfs) ==  getFragments().getLast())
771 		{
772 			UT_DEBUGMSG(("Delete Last Strux type %d \n",pfs->getStruxType()));
773 			UT_ASSERT_HARMLESS(0);
774 		}
775 		UT_DEBUGMSG(("Delete Strux at %d strux type is %d \n",pfs->getPos(),pfs->getStruxType()));
776 		if(pfs->getStruxType() != PTX_SectionHdrFtr)
777 		{
778 			bres = _deleteStruxWithNotify(pfs->getPos(),pfs,NULL,NULL);
779 		}
780 		UT_return_if_fail (bres);
781 	}
782 	UT_return_if_fail (bres);
783 //	deleteSpan(HdrFtrPos,TextStartPos,NULL,true);
784 }
785 
786 
787 
788 
789