1 /* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */
2
3 /* AbiWord
4 * Copyright (C) 1998 AbiSource, Inc.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301 USA.
20 */
21
22 #include <list>
23 #include "ut_types.h"
24 #include "ut_misc.h"
25 #include "ut_assert.h"
26 #include "ut_debugmsg.h"
27 #include "ut_growbuf.h"
28 #include "ut_std_map.h"
29 #include "pt_PieceTable.h"
30 #include "pf_Frag.h"
31 #include "pf_Frag_FmtMark.h"
32 #include "pf_Frag_Strux.h"
33 #include "pf_Frag_Strux_Block.h"
34 #include "pf_Frag_Strux_Section.h"
35 #include "pf_Frag_Text.h"
36 #include "pf_Frag_Object.h"
37 #include "pf_Fragments.h"
38 #include "px_ChangeRecord.h"
39 #include "px_CR_Span.h"
40 #include "px_CR_SpanChange.h"
41 #include "px_CR_Strux.h"
42 #include "pd_Style.h"
43 #include "px_CR_Glob.h"
44
45 // TODO: calculate this from pf_FRAG_STRUX_*_LENGTH instead?
46 #define pt_BOD_POSITION 2
47
48 /*****************************************************************/
49 /*****************************************************************/
50
pt_PieceTable(PD_Document * pDocument)51 pt_PieceTable::pt_PieceTable(PD_Document * pDocument)
52 : m_pts(PTS_Create),
53 m_history(this),
54 m_pDocument(pDocument),
55 m_atomicGlobCount(0),
56 m_bDoingTheDo(false),
57 m_bDoNotTweakPosition(false),
58 m_iXID(0),
59 m_iCurCRNumber(0)
60 {
61
62 setPieceTableState(PTS_Create);
63 loading.m_indexCurrentInlineAP = 0;
64 }
65
~pt_PieceTable()66 pt_PieceTable::~pt_PieceTable()
67 {
68 m_fragments.purgeFrags();
69 UT_map_delete_all_second(m_hashStyles);
70 }
71
setPieceTableState(PTState pts)72 void pt_PieceTable::setPieceTableState(PTState pts)
73 {
74 UT_return_if_fail (pts >= m_pts);
75
76 if ((m_pts==PTS_Create) && (pts==PTS_Loading))
77 {
78 // transition from create to loading.
79 // populate the builtin styles
80 _loadBuiltinStyles();
81 }
82
83 if ((m_pts==PTS_Loading) && (pts==PTS_Editing))
84 {
85 // transition from loading to editing.
86 // tack on an EOD fragment to the fragment list.
87 // this allows us to safely go to the end of the document.
88 pf_Frag * pfEOD = new pf_Frag(this,pf_Frag::PFT_EndOfDoc,0);
89 m_fragments.appendFrag(pfEOD);
90 }
91
92 m_pts = pts;
93 m_varset.setPieceTableState(pts);
94 }
95
96 /*!
97 * Use this for deleting unneeded strux during doc import. Particularly useful for importing
98 * RTF.
99 */
deleteStruxNoUpdate(pf_Frag_Strux * sdh)100 bool pt_PieceTable::deleteStruxNoUpdate(pf_Frag_Strux* sdh)
101 {
102 const pf_Frag_Strux * pfs = sdh;
103 UT_DEBUGMSG(("SEVIOR: deleting strux no update %p \n",sdh));
104 pf_Frag * pf = pfs->getNext();
105 if(pf != NULL && pf->getType() == pf_Frag::PFT_FmtMark)
106 {
107 getFragments().unlinkFrag(pf);
108 delete pf;
109 }
110 getFragments().unlinkFrag(const_cast<pf_Frag_Strux*>(pfs));
111 delete pfs;
112 return true;
113 }
114
115
116 /*!
117 * Use this for deleting unused sections of the document during import.
118 * In Particular use this to remove unused headers/footers.
119 */
deleteFragNoUpdate(pf_Frag * pf)120 bool pt_PieceTable::deleteFragNoUpdate(pf_Frag * pf)
121 {
122 UT_DEBUGMSG(("SEVIOR: deleting frag no update %p \n",pf));
123 getFragments().unlinkFrag(pf);
124 delete pf;
125 return true;
126 }
127
128 /*!
129 * Itterate through the document to calculate the document size
130 * Don't call this in production code. This is used only for recovery and
131 * testing purposes
132 */
calcDocsize(void)133 UT_sint32 pt_PieceTable::calcDocsize(void)
134 {
135 UT_sint32 size = 0;
136 pf_Frag * pf = getFragments().getFirst();
137 while(pf && (pf->getType() != pf_Frag::PFT_EndOfDoc))
138 {
139 size += static_cast<UT_sint32>(pf->getLength());
140 pf = pf->getNext();
141 }
142 UT_ASSERT(pf->getType() == pf_Frag::PFT_EndOfDoc);
143 return size;
144 }
145
createAndSendDocPropCR(const gchar ** pAtts,const gchar ** pProps)146 bool pt_PieceTable::createAndSendDocPropCR( const gchar ** pAtts, const gchar ** pProps)
147 {
148 PT_AttrPropIndex indexAP = 0;
149 PP_AttrProp * pAP = new PP_AttrProp();
150 pAP->setAttributes(pAtts);
151 pAP->setProperties(pProps);
152 bool b = m_varset.addIfUniqueAP(pAP,&indexAP);
153 PX_ChangeRecord * pcr= new PX_ChangeRecord(PX_ChangeRecord::PXT_ChangeDocProp,0,indexAP,0);
154 const pf_Frag_Strux * pfStart = static_cast<pf_Frag_Strux *>(getFragments().getFirst());
155 m_pDocument->notifyListeners(pfStart, pcr);
156 delete pcr;
157 return b;
158 }
159
createAndSendCR(PT_DocPosition iPos,UT_sint32 iType,bool bSave,UT_Byte iGlob)160 bool pt_PieceTable::createAndSendCR(PT_DocPosition iPos, UT_sint32 iType,bool bSave,UT_Byte iGlob)
161 {
162 PX_ChangeRecord::PXType cType = static_cast< PX_ChangeRecord::PXType>(iType);
163 switch(cType)
164 {
165 case PX_ChangeRecord::PXT_InsertSpan:
166 case PX_ChangeRecord::PXT_DeleteSpan:
167 case PX_ChangeRecord::PXT_ChangeSpan:
168 case PX_ChangeRecord::PXT_InsertStrux:
169 case PX_ChangeRecord::PXT_DeleteStrux:
170 case PX_ChangeRecord::PXT_ChangeStrux:
171 case PX_ChangeRecord::PXT_InsertObject:
172 case PX_ChangeRecord::PXT_ChangeObject:
173 case PX_ChangeRecord::PXT_InsertFmtMark:
174 case PX_ChangeRecord::PXT_DeleteFmtMark:
175 case PX_ChangeRecord::PXT_ChangeFmtMark:
176 {
177 UT_DEBUGMSG(("CR already implemented \n"));
178 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
179 return false;
180 }
181 case PX_ChangeRecord::PXT_GlobMarker:
182 {
183 PX_ChangeRecord * pcr= static_cast<PX_ChangeRecord *>(new PX_ChangeRecord_Glob(cType,iGlob));
184 if(bSave)
185 {
186 m_history.addChangeRecord(pcr);
187 }
188 m_pDocument->notifyListeners(NULL, pcr);
189 if(!bSave)
190 delete pcr;
191 return true;
192
193 }
194 case PX_ChangeRecord::PXT_ChangePoint:
195 case PX_ChangeRecord::PXT_ListUpdate:
196 case PX_ChangeRecord::PXT_StopList:
197 case PX_ChangeRecord::PXT_UpdateField:
198 case PX_ChangeRecord::PXT_RemoveList:
199 case PX_ChangeRecord::PXT_UpdateLayout:
200 {
201 PX_ChangeRecord * pcr= new PX_ChangeRecord(cType,iPos, 0,0);
202 if(bSave)
203 {
204 m_history.addChangeRecord(pcr);
205 }
206 m_pDocument->notifyListeners(NULL, pcr);
207 if(!bSave)
208 delete pcr;
209 return true;
210 }
211 default:
212 return false;
213 }
214 }
215
216
217 /*!
218 * Delete the single strux given in sdh and create and record a change record.
219 */
deleteStruxWithNotify(pf_Frag_Strux * sdh)220 bool pt_PieceTable::deleteStruxWithNotify(pf_Frag_Strux* sdh)
221 {
222 pf_Frag_Strux * pfs = sdh;
223 PT_DocPosition dpos = pfs->getPos();
224 pf_Frag * pfEnd = NULL;
225 UT_uint32 pfragOffsetEnd = 0;
226 bool b = _deleteStruxWithNotify(dpos,pfs,&pfEnd,&pfragOffsetEnd,true);
227 return b;
228 }
229
230 /*!
231 * Delete The first FmtMark found at the position given.
232 */
deleteFmtMark(PT_DocPosition dpos)233 bool pt_PieceTable::deleteFmtMark(PT_DocPosition dpos)
234 {
235 pf_Frag * pf = NULL;
236 PT_BlockOffset pOffset= 0;
237 getFragFromPosition(dpos,&pf,&pOffset);
238 pf_Frag_FmtMark * pfm = NULL;
239 if(pf->getType() == pf_Frag::PFT_FmtMark)
240 {
241 pfm = static_cast<pf_Frag_FmtMark *>(pf);
242 }
243 if(pf->getPrev() && pf->getPrev()->getType() == pf_Frag::PFT_FmtMark)
244 {
245 pfm = static_cast<pf_Frag_FmtMark *>(pf->getPrev());
246 }
247 if(pf->getNext() && pf->getNext()->getType() == pf_Frag::PFT_FmtMark)
248 {
249 pfm = static_cast<pf_Frag_FmtMark *>(pf->getNext());
250 }
251 if(pfm == NULL)
252 {
253 return false;
254 }
255 pf_Frag_Strux * pfs = NULL;
256 if (!_getStruxFromFragSkip(pfm,&pfs))
257 return false;
258 pf_Frag * pfEnd = NULL;
259 UT_uint32 fragOff = 0;
260 bool b = _deleteFmtMarkWithNotify(dpos,pfm,pfs,&pfEnd,&fragOff);
261 return b;
262 }
263 /*!
264 * This method inserts a strux of type pts immediately before the sdh given.
265 * Attributes of the strux can be optionally passed. This method does not throw
266 * a change record and should only be used under exceptional circumstances to
267 * repair the piecetable during loading. It was necessary to import RTF tables.
268 */
insertStruxNoUpdateBefore(pf_Frag_Strux * sdh,PTStruxType pts,const gchar ** attributes)269 bool pt_PieceTable::insertStruxNoUpdateBefore(pf_Frag_Strux* sdh, PTStruxType pts,const gchar ** attributes )
270 {
271 const pf_Frag_Strux * pfs = sdh;
272 UT_DEBUGMSG(("SEVIOR: Inserting strux of type %d no update %p \n",pts,sdh));
273 //
274 // Create an indexAP
275 //
276 PT_AttrPropIndex indexAP = pfs->getIndexAP();
277 if(attributes)
278 {
279 PT_AttrPropIndex pAPIold = indexAP;
280 bool bMerged = m_varset.mergeAP(PTC_AddFmt,pAPIold,attributes,NULL,&indexAP,getDocument());
281 UT_UNUSED(bMerged);
282 UT_ASSERT_HARMLESS(bMerged);
283 }
284 //
285 // create a strux
286 //
287 pf_Frag_Strux * pNewStrux = NULL;
288 _createStrux(pts,indexAP,&pNewStrux);
289 //
290 // Insert it.
291 //
292 pf_Frag * pfPrev = pfs->getPrev();
293 UT_return_val_if_fail (pfPrev,false);
294
295 m_fragments.insertFrag(pfPrev,pNewStrux);
296 // insert frag in the embedded_strux list if needed
297 if ((pts == PTX_EndFootnote) || (pts == PTX_EndEndnote) || (pts == PTX_EndAnnotation))
298 {
299 _insertNoteInEmbeddedStruxList(pNewStrux);
300 }
301
302 #if 0
303 m_pDocument->miniDump(sdh,8);
304 #endif
305 return true;
306 }
307
_unlinkFrag(pf_Frag * pf,pf_Frag ** ppfEnd,UT_uint32 * pfragOffsetEnd)308 void pt_PieceTable::_unlinkFrag(pf_Frag * pf,
309 pf_Frag ** ppfEnd, UT_uint32 * pfragOffsetEnd)
310 {
311 // unlink the given fragment from the fragment list.
312 // also, see if the adjacent fragments can be coalesced.
313 // in (ppfEnd,pfragOffsetEnd) we return the position
314 // immediately past the frag we're deleting.
315 // the caller is responsible for deleting pf.
316
317 if (ppfEnd)
318 *ppfEnd = pf->getNext();
319 if (pfragOffsetEnd)
320 *pfragOffsetEnd = 0;
321
322 pf_Frag * pp = pf->getPrev();
323 xxx_UT_DEBUGMSG(("Unlink frag %x of type %d \n",pf,pf->getType()));
324 m_fragments.unlinkFrag(pf);
325
326 if ( pp
327 && pp->getType()==pf_Frag::PFT_Text
328 && pp->getNext()
329 && pp->getNext()->getType()==pf_Frag::PFT_Text)
330 {
331 pf_Frag_Text * ppt = static_cast<pf_Frag_Text *> (pp);
332 pf_Frag_Text * pnt = static_cast<pf_Frag_Text *> (pp->getNext());
333 UT_uint32 prevLength = ppt->getLength();
334 if ( ppt->getIndexAP() == pnt->getIndexAP()
335 && m_varset.isContiguous(ppt->getBufIndex(),prevLength,pnt->getBufIndex()))
336 {
337 if (ppfEnd)
338 *ppfEnd = pp;
339 if (pfragOffsetEnd)
340 *pfragOffsetEnd = prevLength;
341
342 ppt->changeLength(prevLength+pnt->getLength());
343 m_fragments.unlinkFrag(pnt);
344 delete pnt;
345 }
346 }
347 UT_ASSERT(pp && (pp->getNext() != pf));
348 }
349
_struxHasContent(pf_Frag_Strux * pfs) const350 bool pt_PieceTable::_struxHasContent(pf_Frag_Strux * pfs) const
351 {
352 // return true iff the paragraph has content (text).
353
354 return (pfs->getNext() && (pfs->getNext()->getType() == pf_Frag::PFT_Text));
355 }
356
_struxIsEmpty(pf_Frag_Strux * pfs) const357 bool pt_PieceTable::_struxIsEmpty(pf_Frag_Strux * pfs) const
358 {
359 if(pfs->getNext() == NULL)
360 {
361 return true;
362 }
363 pf_Frag * pf = pfs->getNext();
364 if(pf->getType() == pf_Frag::PFT_EndOfDoc)
365 {
366 return true;
367 }
368 if(pf->getType() != pf_Frag::PFT_Strux)
369 {
370 return false;
371 }
372 pf_Frag_Strux * pfsNext = static_cast<pf_Frag_Strux *>(pfs->getNext());
373 if(isFootnote(pfsNext))
374 {
375 return false;
376 }
377 return true;
378 }
379
getAttrProp(PT_AttrPropIndex indexAP,const PP_AttrProp ** ppAP) const380 bool pt_PieceTable::getAttrProp(PT_AttrPropIndex indexAP, const PP_AttrProp ** ppAP) const
381 {
382 UT_return_val_if_fail (ppAP,false);
383
384 const PP_AttrProp * pAP = m_varset.getAP(indexAP);
385 if (!pAP)
386 return false;
387
388 *ppAP = pAP;
389 return true;
390 }
391
_getSpanAttrPropHelper(pf_Frag * pf,const PP_AttrProp ** ppAP) const392 bool pt_PieceTable::_getSpanAttrPropHelper(pf_Frag * pf, const PP_AttrProp ** ppAP) const
393 {
394 switch (pf->getType())
395 {
396 case pf_Frag::PFT_FmtMark:
397 case pf_Frag::PFT_Text:
398 case pf_Frag::PFT_Object:
399 {
400 const PP_AttrProp * pAP = m_varset.getAP(pf->getIndexAP());
401 if (pAP)
402 {
403 *ppAP = pAP;
404 return true;
405 }
406 else
407 {
408 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
409 return false;
410 }
411 }
412
413 case pf_Frag::PFT_Strux:
414 case pf_Frag::PFT_EndOfDoc:
415 default:
416 {
417 *ppAP = NULL;
418 }
419 }
420 return false;
421 }
422
423
getSpanAttrProp(pf_Frag_Strux * sdh,UT_uint32 offset,bool bLeftSide,const PP_AttrProp ** ppAP) const424 bool pt_PieceTable::getSpanAttrProp(pf_Frag_Strux* sdh, UT_uint32 offset, bool bLeftSide,
425 const PP_AttrProp ** ppAP) const
426 {
427 // return the AP for the text at the given offset from the given strux.
428 // offset zero now refers to the first character in the block, so adding
429 // fl_BLOCK_STRUX_OFFSET to the offset in the call is no longer necessary.
430
431 UT_return_val_if_fail (sdh,false);
432 UT_return_val_if_fail (ppAP,false);
433
434 const pf_Frag * pf = sdh;
435 UT_return_val_if_fail (pf->getType() == pf_Frag::PFT_Strux,false);
436 const pf_Frag_Strux * pfsBlock = sdh;
437
438 // This assert is incorrect; blocks that are inserted inside a TOC use sdh of the TOC section
439 // UT_return_val_if_fail (pfsBlock->getStruxType() == PTX_Block,false);
440 UT_return_val_if_fail (pfsBlock->getStruxType() == PTX_Block || pfsBlock->getStruxType() == PTX_SectionTOC,false);
441
442 UT_uint32 cumOffset = 0;
443 UT_uint32 cumEndOffset = 0;
444 pf_Frag * pfTemp = NULL;
445 for (pfTemp=pfsBlock->getNext(); (pfTemp); cumOffset=cumEndOffset, pfTemp=pfTemp->getNext())
446 {
447 cumEndOffset = cumOffset+pfTemp->getLength();
448
449 if (offset > cumEndOffset) // the place we want is way past the end of pfTemp,
450 continue; // so keep searching.
451
452 if (offset == cumOffset) // there's a frag boundary exactly where we want. pfTemp is to our right.
453 {
454 // FmtMarks have length zero, so we have to see what side of the position the caller wants.
455 if ((pfTemp->getType()==pf_Frag::PFT_FmtMark) && (!bLeftSide))
456 continue; // go round again and get thing to the right
457
458 return _getSpanAttrPropHelper(pfTemp,ppAP);
459 }
460
461 UT_return_val_if_fail (offset > cumOffset,false);
462
463 if (offset == cumEndOffset) // there's a frag boundary exactly where we want. pfTemp is to our left.
464 {
465 // FmtMarks have length zero, so we advance to put it to our left and then decide what to do
466 if (!bLeftSide || (pfTemp->getNext() && (pfTemp->getNext()->getType()==pf_Frag::PFT_FmtMark)))
467 continue; // return the next one on the next iteration
468 // If we are just after a footnote or an endnote, we move to the right fragment
469 if (isEndFootnote(pfTemp) && pfTemp->getNext())
470 {
471 pfTemp = pfTemp->getNext();
472 }
473 return _getSpanAttrPropHelper(pfTemp,ppAP);
474 }
475
476 UT_return_val_if_fail (offset < cumEndOffset,false);
477
478 // the place we want is inside of a fragment, so just use it.
479 return _getSpanAttrPropHelper(pfTemp,ppAP);
480 }
481
482 *ppAP = NULL;
483 return false;
484 }
485
486 #if 0
487 // I will leave the code here for now to aid in debugging any problems
488 // with the new iterator (should there be any, that is) Tomas, Nov 15, 2003
489 bool pt_PieceTable::getSpanPtr(pf_Frag_Strux* sdh, UT_uint32 offset,
490 const UT_UCSChar ** ppSpan, UT_uint32 * pLength) const
491 {
492 // note: offset zero refers to the strux. the first character is at
493 // note: (0 + pfsBlock->getLength()).
494
495 *ppSpan = NULL;
496 *pLength = 0;
497
498 const pf_Frag * pf = sdh;
499 UT_return_val_if_fail (pf->getType() == pf_Frag::PFT_Strux,false);
500 const pf_Frag_Strux * pfsBlock = sdh;
501 UT_return_val_if_fail (pfsBlock->getStruxType() == PTX_Block,false);
502 xxx_UT_DEBUGMSG(("getSpanPtr: Requested offset %d \n",offset));
503
504 UT_uint32 cumOffset = pf->getLength();
505 for (pf_Frag * pfTemp=pfsBlock->getNext(); (pfTemp); pfTemp=pfTemp->getNext())
506 {
507 xxx_UT_DEBUGMSG(("getSpanPtr: offset %d cumOffset %d \n",offset,cumOffset));
508 if (offset == cumOffset)
509 {
510 if (pfTemp->getType() == pf_Frag::PFT_FmtMark)
511 continue;
512 if(isFootnote(pfTemp) || isEndFootnote(pfTemp))
513 {
514 cumOffset += pfTemp->getLength();
515 continue;
516 }
517 if (pfTemp->getType() != pf_Frag::PFT_Text)
518 {
519 xxx_UT_DEBUGMSG(("getSpanPtr: Error 1 offset %d cumOffset %d \n",offset,cumOffset));
520 // UT_ASSERT_HARMLESS(0);
521 return false;
522 }
523
524 pf_Frag_Text * pfText = static_cast<pf_Frag_Text *> (pfTemp);
525 *ppSpan = getPointer(pfText->getBufIndex());
526 *pLength = pfText->getLength();
527 return true;
528 }
529 if (offset < cumOffset+pfTemp->getLength())
530 {
531 if(isFootnote(pfTemp) || isEndFootnote(pfTemp))
532 {
533 cumOffset += pfTemp->getLength();
534 continue;
535 }
536 if (pfTemp->getType() != pf_Frag::PFT_Text)
537 {
538 xxx_UT_DEBUGMSG(("getSpanPtr: Error 2 offset %d cumOffset %d \n",offset,cumOffset));
539 return false;
540 }
541 pf_Frag_Text * pfText = static_cast<pf_Frag_Text *> (pfTemp);
542 const UT_UCSChar * p = getPointer(pfText->getBufIndex());
543 UT_uint32 delta = offset - cumOffset;
544 *ppSpan = p + delta;
545 *pLength = pfText->getLength() - delta;
546 return true;
547 }
548
549 cumOffset += pfTemp->getLength();
550 }
551 xxx_UT_DEBUGMSG(("getSpanPtr: Error 3 offset %d cumOffset %d \n",offset,cumOffset));
552 return false;
553 }
554 #endif
555
getDocument(void)556 PD_Document * pt_PieceTable::getDocument(void)
557 {
558 return m_pDocument;
559 }
560
561 /*!
562 Copy paragraph (block) into buffer
563 \param sdh Paragraph to copy
564 \retval pgb Buffer where text should be copied to
565 \return Always returns true
566
567 Copy the contents (unicode character data) of the paragraph (block)
568 into the growbuf given. We append the content onto the growbuf.
569 */
getBlockBuf(pf_Frag_Strux * sdh,UT_GrowBuf * pgb) const570 bool pt_PieceTable::getBlockBuf(pf_Frag_Strux* sdh,
571 UT_GrowBuf * pgb) const
572 {
573 UT_return_val_if_fail (pgb,false);
574
575 const pf_Frag * pf = sdh;
576 UT_return_val_if_fail(pf->getType() == pf_Frag::PFT_Strux, false);
577 const pf_Frag_Strux * pfsBlock = sdh;
578 UT_return_val_if_fail(pfsBlock->getStruxType() == PTX_Block, false);
579
580 UT_uint32 bufferOffset = pgb->getLength();
581
582 pf_Frag * pfTemp = pfsBlock->getNext();
583 UT_sint32 countFoots = 0;
584 while (pfTemp)
585 {
586 switch (pfTemp->getType())
587 {
588 default:
589 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
590 case pf_Frag::PFT_Strux:
591 //
592 // Have to deal with embedded section struxes like Footnotes. We do this by
593 // filling the block buffer with the content contained until we find an
594 // end of embedded container. By placing zero's and content as expected in
595 // the block buffer we match the situation in fl_BlockLayout.
596 //
597 {
598 UT_GrowBufElement valz = 0;
599 bool bAppended;
600 //
601 // Deal with TOC's. Since TOC's are always placed right before
602 // the end of the paragraph we terminate the fill here.
603 //
604 pf_Frag_Strux * pfs = static_cast<pf_Frag_Strux *>(pfTemp);
605 if(pfs->getStruxType() == PTX_SectionTOC)
606 {
607 pfTemp = NULL;
608 break;
609 }
610 if(isFootnote(pfTemp))
611 {
612 countFoots++;
613 bAppended = pgb->ins(bufferOffset,&valz,1);
614 UT_return_val_if_fail (bAppended,false);
615 bufferOffset++;
616 pfTemp = pfTemp->getNext();
617 break;
618 }
619 if(isEndFootnote(pfTemp))
620 {
621 countFoots--;
622 if(countFoots < 0)
623 {
624 pfTemp = NULL;
625 break;
626 }
627 bAppended = pgb->ins(bufferOffset,&valz,1);
628 UT_return_val_if_fail (bAppended,false);
629 bufferOffset++;
630 pfTemp = pfTemp->getNext();
631 break;
632 }
633 if(countFoots>0)
634 {
635 bAppended = pgb->ins(bufferOffset,&valz,1);
636 UT_return_val_if_fail (bAppended,false);
637 bufferOffset++;
638 pfTemp = pfTemp->getNext();
639 break;
640 }
641 pfTemp = NULL;
642 break;
643 }
644 case pf_Frag::PFT_EndOfDoc:
645 pfTemp = NULL;
646 break;
647
648 case pf_Frag::PFT_FmtMark:
649 pfTemp = pfTemp->getNext();
650 break;
651
652 case pf_Frag::PFT_Text:
653 {
654 pf_Frag_Text * pft = static_cast<pf_Frag_Text *>(pfTemp);
655 const UT_UCSChar * pSpan = getPointer(pft->getBufIndex());
656 UT_uint32 length = pft->getLength();
657
658 bool bAppended;
659 bAppended = pgb->ins(bufferOffset,reinterpret_cast<const UT_GrowBufElement*>(pSpan),length);
660 UT_return_val_if_fail (bAppended,false);
661
662 bufferOffset += length;
663 }
664 pfTemp = pfTemp->getNext();
665 break;
666
667 case pf_Frag::PFT_Object:
668 {
669 /*
670 TODO investigate this.... Now *here* is a seriously
671 questionable fragment of code. :-) We can't let
672 getBlockBuf halt on a block when it finds an inline
673 object. However, we can't very well sensibly store an
674 inline object in a UNICODE character. So, we dump
675 USC_BLOCK in its place, to preserve the integrity of the
676 buffer. Obviously, those codes aren't useful, but at
677 least the app doesn't crash, and the rest of the text in
678 the block is safely stored in the buffer in the proper
679 location.
680
681 The UCS_ABI_OBJECT used to be defined as a space, but
682 that caused selection code to fail for fields since the
683 code would look for the beginning of a word, ignoring
684 spaces. Now the UCS_ABI_OBJECT is instead defined as an
685 alpha character. Doesn't really matter since it'll never
686 be used for anything but limit checking anyway. See bug
687 #223 for details.
688 */
689
690 UT_uint32 length = pfTemp->getLength();
691
692 // TODO investigate appending the SPACES directly to
693 // TODO the pgb. **or** investigate the cost of this
694 // TODO g_try_malloc and what happens when it fails....
695
696 UT_UCSChar* pSpaces = new UT_UCSChar[length];
697 for (UT_uint32 i=0; i<length; i++)
698 {
699 pSpaces[i] = UCS_ABI_OBJECT;
700 }
701 bool bAppended;
702 bAppended = pgb->ins(bufferOffset, reinterpret_cast<UT_GrowBufElement*>(pSpaces), length);
703 delete[] pSpaces;
704 UT_return_val_if_fail (bAppended,false);
705
706 bufferOffset += length;
707 }
708 pfTemp = pfTemp->getNext();
709 break;
710 }
711 }
712
713 UT_return_val_if_fail (bufferOffset == pgb->getLength(),false);
714 return true;
715 }
716
getPosEnd()717 PT_DocPosition pt_PieceTable::getPosEnd()
718 {
719 PT_DocPosition ret = 0;
720 getBounds( true, ret );
721 return ret;
722 }
723
724
getBounds(bool bEnd,PT_DocPosition & docPos) const725 bool pt_PieceTable::getBounds(bool bEnd, PT_DocPosition & docPos) const
726 {
727 // be optimistic
728 bool res = true;
729
730 if (!bEnd)
731 {
732 docPos = pt_BOD_POSITION;
733 }
734 else
735 {
736 docPos = m_fragments.getLast()->getPos()+m_fragments.getLast()->getLength();
737 }
738 return res;
739 }
740
getStruxPosition(pf_Frag_Strux * sdh) const741 PT_DocPosition pt_PieceTable::getStruxPosition(pf_Frag_Strux* sdh) const
742 {
743 // return absolute document position of the given handle.
744
745 const pf_Frag * pfToFind = sdh;
746
747 return getFragPosition(pfToFind);
748 }
749
deleteHdrFtrStrux(pf_Frag_Strux * pfs)750 void pt_PieceTable::deleteHdrFtrStrux(pf_Frag_Strux * pfs)
751 {
752 UT_return_if_fail( pfs );
753
754 if(m_pDocument->isMarkRevisions())
755 {
756 const pf_Frag * pfFrag = pfs;
757 PT_DocPosition dpos1 = getFragPosition(pfFrag);
758
759 pfFrag = pfFrag->getNext();
760
761 while(pfFrag)
762 {
763 if((pfFrag->getType() == pf_Frag::PFT_EndOfDoc) ||
764 (pfFrag->getType() == pf_Frag::PFT_Strux &&
765 static_cast<const pf_Frag_Strux*>(pfFrag)->getStruxType() == PTX_SectionHdrFtr))
766 {
767 break;
768 }
769
770 pfFrag = pfFrag->getNext();
771 }
772
773 // there should always be at least EndOfDoc fragment !!!
774 UT_return_if_fail( pfFrag );
775
776 PT_DocPosition dpos2 = getFragPosition(pfFrag);
777
778 UT_uint32 iRealDelete = 0;
779 deleteSpan(dpos1, dpos2, NULL, iRealDelete, true /*delete table struxes*/, false /* don't glob */);
780 }
781 else
782 {
783 const PP_AttrProp * pAP = NULL;
784 UT_return_if_fail(pfs->getStruxType()==PTX_SectionHdrFtr);
785 pf_Frag_Strux_SectionHdrFtr * pfHdr = static_cast<pf_Frag_Strux_SectionHdrFtr *>(pfs);
786
787 if(!getAttrProp(pfHdr->getIndexAP(),&pAP) || !pAP)
788 return;
789
790 const gchar * pszHdrId;
791 if(!pAP->getAttribute("id", pszHdrId) || !pszHdrId)
792 return;
793
794 const gchar * pszHdrType;
795 if(!pAP->getAttribute("type", pszHdrType) || !pszHdrType)
796 return;
797
798 _realDeleteHdrFtrStrux(pfs);
799 _fixHdrFtrReferences(pszHdrType, pszHdrId);
800 }
801
802 }
803
_realDeleteHdrFtrStrux(pf_Frag_Strux * pfs)804 void pt_PieceTable::_realDeleteHdrFtrStrux(pf_Frag_Strux * pfs)
805 {
806 _deleteHdrFtrStruxWithNotify(pfs);
807 }
808
getFragPosition(const pf_Frag * pfToFind) const809 PT_DocPosition pt_PieceTable::getFragPosition(const pf_Frag * pfToFind) const
810 {
811 return pfToFind->getPos();
812 }
813
814
getFragFromPosition(PT_DocPosition docPos,pf_Frag ** ppf,PT_BlockOffset * pFragOffset) const815 bool pt_PieceTable::getFragFromPosition(PT_DocPosition docPos,
816 pf_Frag ** ppf,
817 PT_BlockOffset * pFragOffset) const
818 {
819 // return the frag at the given doc position.
820 //
821 // Sevior do a binary search here now
822 //
823 pf_Frag * pfLast = m_fragments.findFirstFragBeforePos(docPos);
824 if(pfLast)
825 {
826 xxx_UT_DEBUGMSG(("_findFrag: docPos %d pfLast->getPos %d pfLast->getLength %d \n",docPos,pfLast->getPos(),pfLast->getLength()));
827 while(pfLast->getNext() && docPos >= (pfLast->getPos() + pfLast->getLength()))
828 {
829 xxx_UT_DEBUGMSG(("_findFrag: docPos %d pfLast->getPos %d pfLast->getLength %d \n",docPos,pfLast->getPos(),pfLast->getLength()));
830 pfLast = pfLast->getNext();
831 }
832 xxx_UT_DEBUGMSG(("_findFrag: docPos %d pfLast->getPos %d pfLast->getLength %d offset %d Frag Type %d \n",docPos,pfLast->getPos(),pfLast->getLength(),docPos - pfLast->getPos(),pfLast->getType()));
833 if (pFragOffset)
834 *pFragOffset = docPos - pfLast->getPos();
835 *ppf = pfLast;
836 return true;
837 }
838
839 UT_return_val_if_fail (pfLast,false);
840 UT_return_val_if_fail (pfLast->getType() == pf_Frag::PFT_EndOfDoc,false);
841
842 return true;
843 }
844 // PT_DocPosition sum = 0;
845 // pfLast = NULL;
846 // pf_Frag * pf = NULL;
847 // for (pf = m_fragments.getFirst(); (pf); pf=pf->getNext())
848 // {
849 // if ((docPos >= sum) && (docPos < sum+pf->getLength()))
850 // {
851 // *ppf = pf;
852 // if (pFragOffset)
853 // *pFragOffset = docPos - sum;
854
855 // // a FmtMark has length zero. we don't want to find it
856 // // in this loop -- rather we want the thing just past it.
857
858 // UT_ASSERT(pf->getType() != pf_Frag::PFT_FmtMark);
859
860 // return true;
861 // }
862
863 // sum += pf->getLength();
864 // pfLast = pf;
865 // }
866
867 // // if we fall out of the loop, we didn't have a node
868 // // at or around the document position requested.
869 // // since we now have an EOD fragment, we should not
870 // // ever see this -- unless the caller sends a bogus
871 // // doc position.
872
873 // UT_ASSERT(pfLast);
874 // UT_ASSERT(pfLast->getType() == pf_Frag::PFT_EndOfDoc);
875
876 // // TODO if (docPos > sum) we should probably complain...
877
878 // *ppf = pfLast;
879 // if (pFragOffset)
880 // *pFragOffset = docPos - sum;
881
882
883 // return true;
884 // }
885
getFragsFromPositions(PT_DocPosition dPos1,PT_DocPosition dPos2,pf_Frag ** ppf1,PT_BlockOffset * pOffset1,pf_Frag ** ppf2,PT_BlockOffset * pOffset2) const886 bool pt_PieceTable::getFragsFromPositions(PT_DocPosition dPos1, PT_DocPosition dPos2,
887 pf_Frag ** ppf1, PT_BlockOffset * pOffset1,
888 pf_Frag ** ppf2, PT_BlockOffset * pOffset2) const
889 {
890 // compute the (fragment,offset) pairs for each position given.
891
892 UT_return_val_if_fail (dPos1 <= dPos2,false);
893 UT_return_val_if_fail (ppf1,false);
894 UT_return_val_if_fail (pOffset1,false);
895
896 // the first set has to be done the hard way.
897
898 if (!getFragFromPosition(dPos1,ppf1,pOffset1))
899 return false;
900
901 // now get the second set relative to the first.
902
903 PT_DocPosition deltaPos = dPos2 - dPos1;
904 PT_BlockOffset offset = *pOffset1;
905 pf_Frag * pf = *ppf1;
906 UT_uint32 length = pf->getLength();
907 while (offset+deltaPos >= length)
908 {
909 deltaPos -= (length - offset);
910 offset = 0;
911 if (pf->getType() == pf_Frag::PFT_EndOfDoc)
912 break; // TODO if we haven't quite reached dPos2, we should probably complain...
913 pf = pf->getNext();
914 if(pf == NULL)
915 {
916 return false;
917 }
918 length = pf->getLength();
919 }
920
921 // a FmtMark has length zero. we don't want to find it here.
922 // rather we want the thing to the right of it.
923 UT_return_val_if_fail (pf->getType() != pf_Frag::PFT_FmtMark,false);
924
925 if (ppf2)
926 *ppf2 = pf;
927 if (pOffset2)
928 *pOffset2 = offset+deltaPos;
929 return true;
930 }
931
getStruxFromPosition(PL_ListenerId listenerId,PT_DocPosition docPos,fl_ContainerLayout ** psfh) const932 bool pt_PieceTable::getStruxFromPosition(PL_ListenerId listenerId,
933 PT_DocPosition docPos,
934 fl_ContainerLayout* * psfh) const
935 {
936 // return the SFH of the last strux immediately prior to
937 // the given absolute document position.
938
939 pf_Frag_Strux * pfs = NULL;
940 if (!_getStruxFromPosition(docPos,&pfs))
941 return false;
942
943 *psfh = pfs->getFmtHandle(listenerId);
944 return true;
945 }
946
getStruxOfTypeFromPosition(PL_ListenerId listenerId,PT_DocPosition docPos,PTStruxType pts,fl_ContainerLayout ** psfh) const947 bool pt_PieceTable::getStruxOfTypeFromPosition(PL_ListenerId listenerId,
948 PT_DocPosition docPos,
949 PTStruxType pts,
950 fl_ContainerLayout* * psfh) const
951 {
952 // return the SFH of the last strux of the given type
953 // immediately prior to the given absolute document position.
954
955 pf_Frag_Strux * pfs = NULL;
956 if (!_getStruxOfTypeFromPosition(docPos,pts,&pfs))
957 return false;
958
959 *psfh = pfs->getFmtHandle(listenerId);
960 return true;
961 }
962 ///
963 /// return the SDH of the last strux of the given type
964 /// immediately prior to the given absolute document position.
965 ///
getStruxOfTypeFromPosition(PT_DocPosition docPos,PTStruxType pts,pf_Frag_Strux ** sdh) const966 bool pt_PieceTable::getStruxOfTypeFromPosition( PT_DocPosition docPos,
967 PTStruxType pts,
968 pf_Frag_Strux* * sdh) const
969 {
970 return _getStruxOfTypeFromPosition(docPos,pts,sdh);
971 }
972
isEndFootnote(pf_Frag * pf) const973 bool pt_PieceTable::isEndFootnote(pf_Frag * pf) const
974 {
975 if(pf && (pf->getType() == pf_Frag::PFT_Strux))
976 {
977 pf_Frag_Strux * pfs = static_cast<pf_Frag_Strux *>(pf);
978 if((pfs->getStruxType() == PTX_EndFootnote) || (pfs->getStruxType() == PTX_EndEndnote) || (pfs->getStruxType() == PTX_EndTOC) || (pfs->getStruxType() == PTX_EndAnnotation))
979 {
980 return true;
981 }
982 }
983 return false;
984 }
985
986
isFootnote(pf_Frag * pf) const987 bool pt_PieceTable::isFootnote(pf_Frag * pf) const
988 {
989 if(pf && (pf->getType() == pf_Frag::PFT_Strux))
990 {
991 pf_Frag_Strux * pfs = static_cast<pf_Frag_Strux *>(pf);
992 if((pfs->getStruxType() == PTX_SectionFootnote) || (pfs->getStruxType() == PTX_SectionEndnote) || (pfs->getStruxType() == PTX_SectionTOC) || (pfs->getStruxType() == PTX_SectionAnnotation))
993 {
994 return true;
995 }
996 }
997 return false;
998 }
999
1000
isInsideFootnote(PT_DocPosition dpos,pf_Frag ** pfBegin) const1001 bool pt_PieceTable::isInsideFootnote(PT_DocPosition dpos, pf_Frag ** pfBegin) const
1002 {
1003 // return true if pos is inside a footnote, an endnote or an annotation.
1004 // the address of the footnote (endnote or annotation) pfs_strux is
1005 // returned in pfBegin if pfBegin is not NULL
1006 if(m_embeddedStrux.empty())
1007 {
1008 return false;
1009 }
1010
1011 std::list<embeddedStrux>::const_iterator it;
1012 it = m_embeddedStrux.begin();
1013 for (it = m_embeddedStrux.begin(); it != m_embeddedStrux.end(); ++it)
1014 {
1015 if ((*it).endNote->getPos() > dpos)
1016 {
1017 if ((*it).beginNote->getPos() < dpos)
1018 {
1019 if (pfBegin)
1020 {
1021 *pfBegin = (*it).beginNote;
1022 }
1023 return true;
1024 }
1025 break;
1026 }
1027 }
1028 return false;
1029 }
1030
1031
hasEmbedStruxOfTypeInRange(PT_DocPosition posStart,PT_DocPosition posEnd,PTStruxType iType) const1032 bool pt_PieceTable::hasEmbedStruxOfTypeInRange(PT_DocPosition posStart, PT_DocPosition posEnd,
1033 PTStruxType iType) const
1034 {
1035 if(m_embeddedStrux.empty())
1036 {
1037 return false;
1038 }
1039
1040 std::list<embeddedStrux>::const_iterator it;
1041 it = m_embeddedStrux.begin();
1042 for (it = m_embeddedStrux.begin(); it != m_embeddedStrux.end(); ++it)
1043 {
1044 if ((*it).type != iType)
1045 {
1046 continue;
1047 }
1048 if ((*it).beginNote->getPos() > posStart)
1049 {
1050 // if endNote->getPos() > posEnd, there are no notes inside the position range as
1051 // m_embeddedStrux is ordered by position.
1052 return ((*it).endNote->getPos() < posEnd);
1053 }
1054 }
1055 return false;
1056 }
1057
1058
_getStruxFromPosition(PT_DocPosition docPos,pf_Frag_Strux ** ppfs,bool bSkipFootnotes) const1059 bool pt_PieceTable::_getStruxFromPosition(PT_DocPosition docPos,
1060 pf_Frag_Strux ** ppfs,
1061 bool bSkipFootnotes) const
1062 {
1063 // return the strux fragment immediately prior (containing)
1064 // the given absolute document position. If bSkip set, skip past
1065 // Footnote struxes.
1066 xxx_UT_DEBUGMSG(("_getStruxFromPosition bSkipFootnotes %d initial pos %d \n",bSkipFootnotes,docPos));
1067 UT_sint32 countEndFootnotes = 0;
1068 pf_Frag * pfFirst = m_fragments.findFirstFragBeforePos( docPos);
1069 xxx_UT_DEBUGMSG(("Frag found %x pos %d \n",pfFirst,pfFirst->getPos()));
1070 if(isEndFootnote(pfFirst))
1071 countEndFootnotes++;
1072 xxx_UT_DEBUGMSG(("Frag found, count endfootnotes %d \n",countEndFootnotes));
1073
1074 while(pfFirst && pfFirst->getPrev() && pfFirst->getPos() >= docPos)
1075 {
1076 pfFirst = pfFirst->getPrev();
1077 if (isFootnote(pfFirst))
1078 countEndFootnotes--;
1079 else if(isEndFootnote(pfFirst))
1080 countEndFootnotes++;
1081
1082 xxx_UT_DEBUGMSG(("countEndNotes 1 %d \n",countEndFootnotes));
1083 }
1084 while(pfFirst && pfFirst->getPrev() &&
1085 (pfFirst->getType() != pf_Frag::PFT_Strux ||
1086 (bSkipFootnotes && ((countEndFootnotes > 0) || isFootnote(pfFirst) || isEndFootnote(pfFirst)))))
1087 {
1088 pfFirst = pfFirst->getPrev();
1089 xxx_UT_DEBUGMSG(("Frag found %x pos %d \n",pfFirst,pfFirst->getPos()));
1090 if(pfFirst == NULL)
1091 {
1092 break;
1093 }
1094 if(isFootnote(pfFirst))
1095 countEndFootnotes--;
1096 else if(isEndFootnote(pfFirst))
1097 countEndFootnotes++;
1098 xxx_UT_DEBUGMSG(("countEndNotes 2 %d \n",countEndFootnotes));
1099 }
1100 xxx_UT_DEBUGMSG(("countEndNotes final %d \n",countEndFootnotes));
1101 pf_Frag_Strux * pfs = static_cast<pf_Frag_Strux *> (pfFirst);
1102 *ppfs = pfs;
1103 return pfs != NULL;
1104 }
1105
1106
getBlockFromPosition(PT_DocPosition pos) const1107 pf_Frag_Strux* pt_PieceTable::getBlockFromPosition(PT_DocPosition pos) const
1108 {
1109 pf_Frag_Strux* pfs = _getBlockFromPosition(pos);
1110 return pfs;
1111 }
1112
1113
1114 /**
1115 * Get the PTX_Block that contains the given document position. Note that
1116 * pos might itself point right at a PTX_Block in which case that is the block
1117 * that is returned. This might return null if there is no containing block
1118 */
_getBlockFromPosition(PT_DocPosition pos) const1119 pf_Frag_Strux* pt_PieceTable::_getBlockFromPosition(PT_DocPosition pos) const
1120 {
1121 pf_Frag* pf;
1122 PT_BlockOffset offset;
1123 pf_Frag_Strux* ret = 0;
1124
1125 if(!getFragFromPosition( pos, &pf, &offset ))
1126 {
1127 return ret;
1128 }
1129
1130 // if the fragment right at pos is a block, return it.
1131 if( pf_Frag_Strux* pfs = tryDownCastStrux( pf, PTX_Block ))
1132 {
1133 return pfs;
1134 }
1135 // otherwise search backwards for the block.
1136 if(!_getStruxOfTypeFromPosition( pos, PTX_Block, &ret ))
1137 {
1138 return 0;
1139 }
1140 return ret;
1141
1142 }
1143
_getStruxOfTypeFromPosition(PT_DocPosition dpos,PTStruxType pts,pf_Frag_Strux ** ppfs) const1144 bool pt_PieceTable::_getStruxOfTypeFromPosition(PT_DocPosition dpos,
1145 PTStruxType pts,
1146 pf_Frag_Strux ** ppfs) const
1147 {
1148 // return the strux fragment of the given type containing
1149 // the given absolute document position.
1150 UT_return_val_if_fail (ppfs, false);
1151 xxx_UT_DEBUGMSG(("_getStruxOfTypeFromPosition: looking for type %d \n",pts));
1152 *ppfs = NULL;
1153
1154 pf_Frag_Strux * pfs = NULL;
1155 bool wantFootNoteType = (pts == PTX_EndFootnote || pts == PTX_SectionFootnote || pts == PTX_EndEndnote || pts == PTX_SectionEndnote || pts == PTX_SectionAnnotation || pts == PTX_EndAnnotation || pts == PTX_SectionTOC || pts == PTX_EndTOC);
1156
1157 if (!_getStruxFromPosition(dpos,&pfs, !wantFootNoteType))
1158 return false;
1159
1160 PTStruxType pfsType = pfs->getStruxType();
1161 xxx_UT_DEBUGMSG(("Got strux type %d \n",pfs->getStruxType()));
1162 if (pfsType == pts || (pts == PTX_Section && pfsType == PTX_SectionHdrFtr)
1163 || (pts == PTX_SectionFootnote && pfsType == PTX_SectionFootnote)
1164 || (pts == PTX_SectionAnnotation && pfsType == PTX_SectionAnnotation)
1165 || (pts == PTX_SectionEndnote && pfsType == PTX_SectionEndnote)
1166 || (pts == PTX_SectionTable && pfsType == PTX_SectionTable)
1167 || (pts == PTX_SectionCell && pfsType == PTX_SectionCell)
1168 || (pts == PTX_EndTable && pfsType == PTX_EndTable)
1169 || (pts == PTX_EndCell && pfsType == PTX_EndCell)
1170 || (pts == PTX_SectionTOC && pfsType == PTX_SectionTOC) ) // is it of the type we want
1171 {
1172 *ppfs = pfs;
1173 return true;
1174 }
1175
1176 // if not, we walk backwards thru the list and try to find it.
1177 UT_sint32 numEndTable = 0;
1178 for (pf_Frag * pf=pfs; (pf); pf=pf->getPrev())
1179 if (pf->getType() == pf_Frag::PFT_Strux)
1180 {
1181 pf_Frag_Strux * pfsTemp = NULL;
1182 if(!wantFootNoteType && isEndFootnote(pf))
1183 {
1184 _getStruxFromFragSkip(pf,&pfsTemp);
1185 }
1186 else
1187 {
1188 pfsTemp = static_cast<pf_Frag_Strux *>(pf);
1189 }
1190 UT_return_val_if_fail (pfsTemp, false);
1191 if(pfsTemp->getStruxType() == PTX_EndTable)
1192 {
1193 numEndTable++;
1194 }
1195 else if(pfsTemp->getStruxType() == PTX_SectionTable)
1196 {
1197 numEndTable--;
1198 }
1199 if (pfsTemp->getStruxType() == pts || (pts == PTX_Section && pfsTemp->getStruxType() == PTX_SectionHdrFtr) || (pts == PTX_SectionFootnote && pfsTemp->getStruxType() == PTX_SectionFootnote) || (pts == PTX_EndFootnote && pfsTemp->getStruxType() == PTX_EndFootnote) || (pts == PTX_SectionEndnote && pfsTemp->getStruxType() == PTX_SectionEndnote) || (pts == PTX_EndEndnote && pfsTemp->getStruxType() == PTX_EndEndnote) || (pts == PTX_SectionTOC && pfsTemp->getStruxType() == PTX_SectionTOC) || (pts == PTX_EndTOC && pfsTemp->getStruxType() == PTX_EndTOC)) // did we find it
1200 {
1201 if(((numEndTable < 0) && (pfsTemp->getStruxType()==PTX_SectionTable)) || (numEndTable == 0 && (pfsTemp->getStruxType()!=PTX_SectionTable)))
1202 {
1203 *ppfs = pfsTemp;
1204 return true;
1205 }
1206 else if(pfsTemp->getStruxType() != PTX_SectionTable &&
1207 pfsTemp->getStruxType() != PTX_SectionCell &&
1208 pfsTemp->getStruxType() != PTX_EndTable &&
1209 pfsTemp->getStruxType() != PTX_EndCell)
1210 {
1211 *ppfs = pfsTemp;
1212 return true;
1213 }
1214 }
1215 }
1216
1217 // did not find it.
1218
1219 return false;
1220 }
1221
1222 /*!
1223 * Scan backwards from the given frag until a start hyperlink is found.
1224 * This method is used to determine if a frag is inside a hyperlink span.
1225 * Returns NULL if:
1226 * (a) It encounters a strux first.
1227 * (b) It encounters an end hyperlink first
1228 * (c) It encounters the begin of document
1229 *
1230 * FIXME!! Should this code work for annotations too?
1231 */
_findPrevHyperlink(pf_Frag * pfStart)1232 pf_Frag * pt_PieceTable::_findPrevHyperlink(pf_Frag * pfStart)
1233 {
1234 pf_Frag * pf = pfStart;
1235 pf_Frag_Object *pOb = NULL;
1236 UT_sint32 iCountFootnotes = 0;
1237 while(pf)
1238 {
1239 if(pf->getType() == pf_Frag::PFT_Strux)
1240 {
1241 if(isEndFootnote(pf))
1242 {
1243 iCountFootnotes++;
1244 }
1245 else if(isFootnote(pf))
1246 {
1247 iCountFootnotes--;
1248 }
1249 else if(iCountFootnotes == 0)
1250 {
1251 return NULL;
1252 }
1253 }
1254 if(pf->getType() == pf_Frag::PFT_Object)
1255 {
1256 pOb = static_cast<pf_Frag_Object*>(pf);
1257 if(pOb->getObjectType() == PTO_Hyperlink)
1258 {
1259 const PP_AttrProp * pAP = NULL;
1260 pOb->getPieceTable()->getAttrProp(pOb->getIndexAP(),&pAP);
1261 UT_return_val_if_fail (pAP, NULL);
1262 const gchar* pszHref = NULL;
1263 const gchar* pszHname = NULL;
1264 UT_uint32 k = 0;
1265 while((pAP)->getNthAttribute(k++,pszHname, pszHref))
1266 {
1267 if(!strcmp(pszHname, "xlink:href"))
1268 {
1269 return pf;
1270 }
1271 }
1272 return NULL;
1273 }
1274
1275 }
1276 pf = pf->getPrev();
1277 }
1278 return NULL;
1279 }
1280
1281
1282 /*!
1283 * Scan backwards fromthe given frag until an end hyperlink is found.
1284 * This method is used to determine if a frag is inside a hyperlink span.
1285 * Returns NULL if:
1286 * (a) It encounters a strux first.
1287 * (b) It encounters a start hyperlink first
1288 * (c) It encounters the end of document
1289 */
_findNextHyperlink(pf_Frag * pfStart)1290 pf_Frag * pt_PieceTable::_findNextHyperlink(pf_Frag * pfStart)
1291 {
1292 pf_Frag * pf = pfStart;
1293 pf_Frag_Object *pOb = NULL;
1294 UT_sint32 iCountFootnotes = 0;
1295 while(pf && pf != m_fragments.getLast())
1296 {
1297 if(pf->getType() == pf_Frag::PFT_Strux)
1298 {
1299 if(isFootnote(pf))
1300 {
1301 iCountFootnotes++;
1302 }
1303 else if(isEndFootnote(pf))
1304 {
1305 iCountFootnotes--;
1306 }
1307 else if(iCountFootnotes == 0)
1308 {
1309 return NULL;
1310 }
1311 }
1312 if(pf->getType() == pf_Frag::PFT_Object)
1313 {
1314 pOb = static_cast<pf_Frag_Object*>(pf);
1315 if(pOb->getObjectType() == PTO_Hyperlink)
1316 {
1317 const PP_AttrProp * pAP = NULL;
1318 pOb->getPieceTable()->getAttrProp(pOb->getIndexAP(),&pAP);
1319 UT_return_val_if_fail (pAP, NULL);
1320 const gchar* pszHref = NULL;
1321 const gchar* pszHname = NULL;
1322 UT_uint32 k = 0;
1323 while((pAP)->getNthAttribute(k++,pszHname, pszHref))
1324 {
1325 if(!strcmp(pszHname, "xlink:href"))
1326 {
1327 return NULL;
1328 }
1329 }
1330 //
1331 // No start marker => Must be end marker - GOT IT!
1332 //
1333 return pf;
1334 }
1335 }
1336 pf = pf->getNext();
1337 }
1338 return NULL;
1339 }
1340
_getStruxFromFrag(pf_Frag * pfStart,pf_Frag_Strux ** ppfs) const1341 bool pt_PieceTable::_getStruxFromFrag(pf_Frag * pfStart, pf_Frag_Strux ** ppfs) const
1342 {
1343 // return the strux frag immediately prior to (containing)
1344 // the given fragment.
1345
1346 *ppfs = NULL;
1347
1348 pf_Frag * pf;
1349 for (pf=pfStart->getPrev(); (pf && (pf->getType() != pf_Frag::PFT_Strux)); pf=pf->getPrev())
1350 ;
1351 if (!pf)
1352 return false;
1353
1354 *ppfs = static_cast<pf_Frag_Strux *>(pf);
1355 return true;
1356 }
1357
1358
_getNextStruxAfterFragSkip(pf_Frag * pfStart,pf_Frag_Strux ** ppfs)1359 bool pt_PieceTable::_getNextStruxAfterFragSkip(pf_Frag *pfStart, pf_Frag_Strux ** ppfs)
1360 {
1361
1362 *ppfs = NULL;
1363
1364 pf_Frag * pf;
1365 UT_sint32 countFoots = 0;
1366 if(isFootnote(pfStart))
1367 {
1368 countFoots++;
1369 }
1370 pf = pfStart->getNext();
1371 if(pf && isFootnote(pf))
1372 {
1373 countFoots++;
1374 }
1375 xxx_UT_DEBUGMSG(("_getStruxFromFragStrux: 1 countFoots %d \n",countFoots));
1376 while(pf && (pf->getType() != pf_Frag::PFT_EndOfDoc) && ((pf->getType() != pf_Frag::PFT_Strux) || (countFoots > 0)
1377 || isFootnote(pf) || isEndFootnote(pf)))
1378 {
1379 pf=pf->getNext();
1380 if(isFootnote(pf))
1381 {
1382 countFoots++;
1383 }
1384 else if(isEndFootnote(pf))
1385 {
1386 countFoots--;
1387 }
1388 xxx_UT_DEBUGMSG(("_getStruxFromFragStrux: 2 countFoots %d \n",countFoots));
1389 }
1390 ;
1391 if (!pf)
1392 return false;
1393
1394 *ppfs = static_cast<pf_Frag_Strux *>(pf);
1395 return true;
1396 }
1397
1398
_getStruxFromFragSkip(pf_Frag * pfStart,pf_Frag_Strux ** ppfs) const1399 bool pt_PieceTable::_getStruxFromFragSkip(pf_Frag * pfStart, pf_Frag_Strux ** ppfs) const
1400 {
1401 // return the strux frag immediately prior to (containing)
1402 // the given fragment while skipping endFootnote/footnote stuff.
1403
1404 *ppfs = NULL;
1405
1406 pf_Frag * pf;
1407 UT_sint32 countFoots = 0;
1408 if(isEndFootnote(pfStart))
1409 {
1410 countFoots++;
1411 }
1412 pf = pfStart->getPrev();
1413 if(isEndFootnote(pf))
1414 {
1415 countFoots++;
1416 }
1417 if(isFootnote(pf))
1418 {
1419 countFoots--;
1420 }
1421 xxx_UT_DEBUGMSG(("_getStruxFromFragStrux: 1 countFoots %d \n",countFoots));
1422 while(pf && ((pf->getType() != pf_Frag::PFT_Strux) || (countFoots > 0)
1423 || isFootnote(pf) || isEndFootnote(pf)))
1424 {
1425 pf=pf->getPrev();
1426 if(pf && isFootnote(pf))
1427 {
1428 countFoots--;
1429 }
1430 else if(pf && isEndFootnote(pf))
1431 {
1432 countFoots++;
1433 }
1434 xxx_UT_DEBUGMSG(("_getStruxFromFragStrux: 2 countFoots %d \n",countFoots));
1435 }
1436 ;
1437 if (!pf)
1438 return false;
1439
1440 *ppfs = static_cast<pf_Frag_Strux *>(pf);
1441 return true;
1442 }
1443
_computeBlockOffset(pf_Frag_Strux * pfs,pf_Frag * pfTarget) const1444 UT_uint32 pt_PieceTable::_computeBlockOffset(pf_Frag_Strux * pfs,pf_Frag * pfTarget) const
1445 {
1446 // return the block offset of the beginning of pfTarget from the end of pfs.
1447
1448 UT_uint32 sum;
1449 pf_Frag * pf;
1450
1451 for (pf=pfs->getNext(), sum=0; (pf && (pf!=pfTarget)); sum+=pf->getLength(), pf=pf->getNext())
1452 ;
1453 if(pf == NULL)
1454 {
1455 return 0;
1456 }
1457
1458 return sum;
1459 }
1460
1461
clearIfAtFmtMark(PT_DocPosition dpos)1462 void pt_PieceTable::clearIfAtFmtMark(PT_DocPosition dpos)
1463 {
1464 while (_lastUndoIsThisFmtMark(dpos))
1465 {
1466 UT_DEBUGMSG(("clearIfAtFmtMark doing something...\n"));
1467 undoCmd();
1468 }
1469 }
1470
_changePointWithNotify(PT_DocPosition dpos)1471 bool pt_PieceTable::_changePointWithNotify(PT_DocPosition dpos)
1472 {
1473 PX_ChangeRecord * pcr
1474 = new PX_ChangeRecord(PX_ChangeRecord::PXT_ChangePoint,
1475 dpos, 0,0);
1476 UT_return_val_if_fail (pcr,false);
1477
1478 m_history.addChangeRecord(pcr);
1479 m_pDocument->notifyListeners(NULL, pcr);
1480
1481 return true;
1482 }
1483
1484 /*!
1485 This function crawls the entire PT and assignes new xid to any fragment that should
1486 have one and does not. It is primarily to be used by exporters (accessed throught
1487 PD_Document wrapper)
1488 */
fixMissingXIDs()1489 void pt_PieceTable::fixMissingXIDs()
1490 {
1491 for (pf_Frag * pf = m_fragments.getFirst(); (pf); pf=pf->getNext())
1492 {
1493 if(!pf->getXID() && pf->usesXID())
1494 pf->setXID(getXID());
1495 }
1496 }
1497
getXID()1498 UT_uint32 pt_PieceTable::getXID()
1499 {
1500 ++m_iXID;
1501 return m_iXID;
1502 }
1503
1504
1505 /* Return true if neither dpos1 nor dpos2 is within a note and the whole document is not selected*/
_checkSkipFootnote(PT_DocPosition dpos1,PT_DocPosition dpos2,pf_Frag * pf_End) const1506 bool pt_PieceTable::_checkSkipFootnote(PT_DocPosition dpos1, PT_DocPosition dpos2, pf_Frag * pf_End) const
1507 {
1508 if(m_embeddedStrux.empty())
1509 {
1510 return true;
1511 }
1512
1513 if (!pf_End)
1514 {
1515 PT_BlockOffset offset;
1516 getFragFromPosition(dpos2,&pf_End,&offset);
1517 }
1518 if ((dpos1 == 1) && ((pf_End->getType() == pf_Frag::PFT_EndOfDoc) ||
1519 ((pf_End->getType() == pf_Frag::PFT_Strux) &&
1520 (static_cast<pf_Frag_Strux*>(pf_End)->getStruxType() == PTX_SectionHdrFtr))))
1521 {
1522 return false;
1523 }
1524
1525 bool bSkipNote = true;
1526 std::list<embeddedStrux>::const_reverse_iterator it;
1527 for (it = m_embeddedStrux.rbegin(); it != m_embeddedStrux.rend(); ++it)
1528 {
1529 if ((*it).beginNote->getPos() < dpos2)
1530 {
1531 if ((*it).endNote->getPos() > dpos2)
1532 {
1533 bSkipNote = false;
1534 }
1535 break;
1536 }
1537 }
1538 if (bSkipNote)
1539 {
1540 if (it != m_embeddedStrux.rbegin())
1541 {
1542 it--;
1543 }
1544 for (; it != m_embeddedStrux.rend(); ++it)
1545 {
1546 if ((*it).beginNote->getPos() < dpos1)
1547 {
1548 if ((*it).endNote->getPos() > dpos1)
1549 {
1550 bSkipNote = false;
1551 }
1552 break;
1553 }
1554 }
1555 }
1556 return bSkipNote;
1557 }
1558