1 /* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */
2 /* AbiWord
3 * Copyright (C) Luke Jordan, Martin Sevior.
4 * BIDI Copyright (c) 2001,2002 Tomas Frydrych, Yaacov Akiba Slama
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 <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25
26 #include "fl_AutoNum.h"
27 #include "fl_Layout.h"
28 #include "fl_BlockLayout.h"
29 #include "fp_Run.h"
30 #include "fp_Line.h"
31 #include "fv_View.h"
32 #include "pd_Document.h"
33 #include "pt_PieceTable.h"
34 #include "pf_Frag.h"
35 #include "xap_App.h"
36 #include "xap_Frame.h"
37 #include "ut_string.h"
38 #include "ut_assert.h"
39 #include "ut_debugmsg.h"
40
41 #include "ut_string_class.h"
42
43 #define CONV_TO_UCS (UT_UCSChar) (unsigned char)
44
45 class pf_Frag;
46
fl_AutoNum(UT_uint32 id,UT_uint32 start,pf_Frag_Strux * pFirst,fl_AutoNum * pParent,const gchar * lDelim,const gchar * lDecimal,FL_ListType lType,PD_Document * pDoc,FV_View * pView)47 fl_AutoNum::fl_AutoNum( UT_uint32 id,
48 UT_uint32 start,
49 pf_Frag_Strux* pFirst,
50 fl_AutoNum * pParent,
51 const gchar * lDelim,
52 const gchar * lDecimal,
53 FL_ListType lType,
54 PD_Document * pDoc,
55 FV_View * pView)
56 : m_pParent(pParent),
57 m_pDoc(pDoc),
58 m_pView(pView),
59 m_List_Type(lType),
60 m_iID(id),
61 m_iParentID(0),
62 m_iLevel(pParent ? pParent->getLevel() + 1 : 1),
63 m_iStartValue(start),
64 m_iAsciiOffset(0),
65 m_bUpdatingItems(false),
66 m_bDirty(false),
67 m_ioffset(0),
68 m_bWordMultiStyle(true),
69 m_pParentItem(0)
70 {
71 _setParent(pParent);
72 UT_ASSERT(m_pDoc);
73 memset(m_pszDelim, 0, 80);
74 memset(m_pszDecimal, 0, 80);
75 strncpy( m_pszDelim, lDelim, 80);
76 strncpy( m_pszDecimal, lDecimal, 80);
77 addItem(pFirst);
78
79 m_pDoc->addList(this);
80 // New 6/11/2000. m_pParentItem is the item in the parent list
81 // that the new list points
82 }
83
fl_AutoNum(UT_uint32 id,UT_uint32 parent_id,FL_ListType lType,UT_uint32 start,const gchar * lDelim,const gchar * lDecimal,PD_Document * pDoc,FV_View * pView)84 fl_AutoNum::fl_AutoNum( UT_uint32 id,
85 UT_uint32 parent_id,
86 FL_ListType lType,
87 UT_uint32 start,
88 const gchar * lDelim,
89 const gchar * lDecimal,
90 PD_Document * pDoc,
91 FV_View * pView)
92 : m_pParent(0),
93 m_pDoc(pDoc),
94 m_pView(pView),
95 m_List_Type(lType),
96 m_iID(id),
97 m_iParentID(parent_id),
98 m_iLevel(1),
99 m_iStartValue(start),
100 m_iAsciiOffset(0),
101 m_bUpdatingItems(false),
102 m_bDirty(false),
103 m_ioffset(0),
104 m_bWordMultiStyle(true),
105 m_pParentItem(0)
106 {
107 // Set in Block???
108 memset(m_pszDelim, 0, 80);
109 memset(m_pszDecimal, 0, 80);
110 UT_ASSERT(m_pDoc);
111 if (lDelim)
112 strncpy( m_pszDelim, lDelim, 80);
113
114 if (lDecimal)
115 strncpy( m_pszDecimal, lDecimal, 80);
116
117 if(m_iParentID != 0)
118 {
119 _setParent(m_pDoc->getListByID(parent_id));
120 }
121 }
122
checkReference(fl_AutoNum * pAuto)123 bool fl_AutoNum::checkReference(fl_AutoNum * pAuto)
124 {
125 if(pAuto == m_pParent)
126 {
127 return false;
128 }
129 if(m_pParent)
130 {
131 return m_pParent->checkReference(pAuto);
132 }
133 return true;
134 }
135
addItem(pf_Frag_Strux * pItem)136 void fl_AutoNum::addItem(pf_Frag_Strux* pItem)
137 {
138 UT_sint32 i = m_pItems.findItem(pItem);
139 if(i < 0 )
140 {
141 m_pItems.addItem(pItem);
142 fixListOrder();
143 }
144 m_bDirty = true;
145 }
146
147 /*!
148 * Check that this list is not a member of another list.
149 */
fixHierarchy(void)150 void fl_AutoNum::fixHierarchy(void)
151 {
152 fl_AutoNum * pParent;
153 const char * pszParentID =NULL;
154 #if 1
155 UT_uint32 docParentID = 0;
156 if(m_pItems.getItemCount() >0)
157 {
158 pf_Frag_Strux* sdh = m_pItems.getNthItem(0);
159 XAP_Frame * pFrame = XAP_App::getApp()->getLastFocussedFrame();
160 FV_View* pView = NULL;
161 if (pFrame)
162 pView = static_cast<FV_View *>(pFrame->getCurrentView());
163
164 bool bFound = m_pDoc->getAttributeFromSDH(sdh,
165 pView ? pView->isShowRevisions() : true,
166 pView ? pView->getRevisionLevel(): PD_MAX_REVISION,
167 PT_PARENTID_ATTRIBUTE_NAME,&pszParentID);
168 if(bFound)
169 {
170 docParentID= atoi(pszParentID);
171 }
172 }
173 if((m_iID != 0) && (docParentID != 0) && (docParentID != m_iParentID) && (docParentID != m_iID))
174 {
175 pParent = m_pDoc->getListByID(docParentID);
176 UT_ASSERT(this != pParent);
177 if(pParent != NULL)
178 {
179 m_iParentID = docParentID;
180 m_bDirty = true;
181 }
182 }
183 #endif
184 if (m_iParentID != 0)
185 {
186 pParent = m_pDoc->getListByID(m_iParentID);
187 }
188 // TODO Add error checking?
189 else
190 pParent = NULL;
191
192 if(pParent != m_pParent)
193 {
194 _setParent(pParent);
195 }
196 UT_uint32 oldlevel = m_iLevel;
197 if (m_pParent)
198 m_iLevel = m_pParent->getLevel() + 1;
199 else
200 m_iLevel = 1;
201 if(oldlevel != m_iLevel)
202 {
203 m_bDirty = true;
204 }
205 }
206
~fl_AutoNum()207 fl_AutoNum::~fl_AutoNum()
208 {
209 }
210
211 static PD_Document * pCurDoc;
212
compareListItems(const void * p1,const void * p2)213 static int compareListItems(const void* p1, const void* p2)
214 {
215 //
216 // Fun with (void *) pointers!
217 //
218 // pf_Frag * pf1 = static_cast<pf_Frag *>(p1);
219 // PD_Document * pDoc = pf1->getPieceTable()->getDocument();
220 pf_Frag_Strux* const * sdh1 = reinterpret_cast<pf_Frag_Strux* const *>(p1);
221 pf_Frag_Strux* const * sdh2 = reinterpret_cast<pf_Frag_Strux* const *>(p2);
222 PT_DocPosition pos1 = pCurDoc->getStruxPosition(*sdh1);
223 PT_DocPosition pos2 = pCurDoc->getStruxPosition(*sdh2);
224 if(pos1 < pos2)
225 {
226 return -1;
227 }
228 if(pos1 > pos2)
229 {
230 return 1;
231 }
232 return 0;
233 }
234
fixListOrder(void)235 void fl_AutoNum::fixListOrder(void)
236 {
237 pCurDoc = m_pDoc;
238 m_pItems.qsort(compareListItems);
239 m_bDirty = true;
240 }
241
markAsDirty(void)242 void fl_AutoNum::markAsDirty(void)
243 {
244 m_bDirty = true;
245 }
246
findAndSetParentItem(void)247 void fl_AutoNum::findAndSetParentItem(void)
248 {
249 if(m_iParentID == 0)
250 {
251 return;
252 }
253 else if( m_pParent == NULL)
254 {
255 _setParent(m_pDoc->getListByID(m_iParentID));
256 }
257 else
258 {
259 fl_AutoNum * pParent = m_pDoc->getListByID(m_iParentID);
260 if(pParent == NULL)
261 {
262 _setParent(NULL);
263 }
264 }
265
266 // pCurDoc = m_pDoc;
267 // fixListOrder();
268 // m_pParent->fixListOrder();
269 // m_pParent->update(0);
270
271 if (m_pItems.getItemCount() == 0)
272 {
273 return;
274 }
275 pf_Frag_Strux* pCurFirst = m_pItems.getFirstItem();
276 if(pCurFirst == NULL)
277 return;
278 PT_DocPosition posCur = m_pDoc->getStruxPosition(pCurFirst);
279 PT_DocPosition posParent = 0;
280 UT_uint32 cnt = m_pDoc->getListsCount();
281 UT_ASSERT(cnt!=0);
282 UT_uint32 iList;
283 fl_AutoNum * pClosestAuto = NULL;
284 PT_DocPosition posClosest = 0;
285 pf_Frag_Strux* pClosestItem = NULL;
286 bool bReparent = false;
287 if(m_pParent != NULL)
288 {
289 UT_uint32 i=0;
290 for(i=0; i <m_pParent->getNumLabels(); i++)
291 {
292 pf_Frag_Strux* pParentItem = m_pParent->getNthBlock(i);
293 if(pParentItem != NULL)
294 {
295 posParent = m_pDoc->getStruxPosition(pParentItem);
296 if( posParent > posClosest && posParent < posCur)
297 {
298 posClosest = posParent;
299 pClosestAuto = m_pParent;
300 pClosestItem = pParentItem;
301 bReparent = true;
302 }
303 }
304 }
305 }
306 //
307 // Reparent this list if the first item of the parent is after the first
308 // item of this list.
309 //
310 if((m_pParent == NULL) || (posClosest == 0))
311 {
312 for(iList = 0; iList < cnt; iList++)
313 {
314 fl_AutoNum * pParent = m_pDoc->getNthList(iList);
315 UT_uint32 i=0;
316 pf_Frag_Strux* pParentItem = pParent->getNthBlock(i);
317 posParent=0;
318 if(pParentItem != NULL)
319 {
320 posParent = m_pDoc->getStruxPosition(pParentItem);
321 }
322 while(pParentItem != NULL && (posParent < posCur))
323 {
324 i++;
325 pParentItem = pParent->getNthBlock(i);
326 if(pParentItem != NULL)
327 {
328 posParent = m_pDoc->getStruxPosition(pParentItem);
329 }
330 }
331 if( i > 0)
332 {
333 i--;
334 pParentItem = pParent->getNthBlock(i);
335 posParent = m_pDoc->getStruxPosition(pParentItem);
336 if( posParent > posClosest)
337 {
338 posClosest = posParent;
339 pClosestAuto = pParent;
340 pClosestItem = pParentItem;
341 bReparent = true;
342 }
343 }
344 }
345 }
346 if(m_pParentItem != pClosestItem)
347 m_bDirty = true;
348 if(m_pParent != pClosestAuto)
349 m_bDirty = true;
350 if(bReparent)
351 {
352 m_pParentItem = pClosestItem;
353 if(m_pParent != pClosestAuto)
354 {
355 _setParent(pClosestAuto);
356 _setParentID(m_pParent->getID());
357 }
358 }
359 if(m_pParent != NULL)
360 {
361 m_iLevel = m_pParent->getLevel()+ 1;
362 //
363 // TODO: change all the para attributes in the list to reflect
364 // this change of Parent ID and Level.
365 }
366 else
367 {
368 // m_iParentID = 0;
369 m_iLevel = 1;
370 }
371 if(m_bDirty == true)
372 update(0);
373 }
374
375 /*!
376 * This method recursively calculates a label based on the type of label
377 * of the AutoNum Class. This is output to the label string labelStr.
378 *
379 * insPoint is the position in the string where the new text goes. It starts
380 * Pointing to the byte == 0
381 * depth is the level of recursion
382 * pLayout is a pointer to the Layout item containing the current list item
383 */
_getLabelstr(UT_UCSChar labelStr[],UT_uint32 * insPoint,UT_uint32 depth,pf_Frag_Strux * pLayout) const384 void fl_AutoNum::_getLabelstr( UT_UCSChar labelStr[], UT_uint32 * insPoint,
385 UT_uint32 depth, pf_Frag_Strux* pLayout) const
386 {
387 // Keep these arrays the same length to prevent overflows; see Bug 10580
388 char p[100], leftDelim[100], rightDelim[100];
389 UT_uint32 i,psz;
390 //
391 // Don't get the next level if we don't have a list
392 //
393 if(m_List_Type == NOT_A_LIST)
394 {
395 *insPoint = 0;
396 return;
397 }
398 // if(depth > 0 && m_List_Type >= BULLETED_LIST)
399 // {
400 // *insPoint = 0;
401 // return;
402 // }
403
404 // TODO This is a bit of a hack to split the delim string. It would be
405 // TODO nice to clear it up.
406
407 strncpy (p, m_pszDelim, sizeof(p));
408 UT_uint32 rTmp;
409
410 i = 0;
411
412 while (((i + 1) < G_N_ELEMENTS(p)) && p[i] && p[i] != '%' && p[i+1] != 'L')
413 {
414 // FIXME check the bounds to not overflow leftDelim
415 // Update: the arrays are now the same length to prevent overflows
416 leftDelim[i] = p[i];
417 i++;
418 }
419 if (i >= G_N_ELEMENTS(p) || p[i] == '\0') {
420 // UT_ASSERT(UT_NOT_REACHED);
421 UT_DEBUGMSG (("Hub: not a delim (SHOULD NOT HAPPEN)!!!\n"));
422 *insPoint = 0;
423 return;
424 }
425 leftDelim[i] = '\0';
426 i += 2;
427 rTmp = i;
428 while ((i < G_N_ELEMENTS(p)) && p[i])
429 {
430 // FIXME check the bounds to not overflow rightDelim
431 // Update: the arrays are now the same length to prevent overflows
432 rightDelim[i - rTmp] = p[i];
433 i++;
434 }
435 rightDelim[i - rTmp] = '\0';
436
437 if(m_pParent != NULL && m_List_Type < BULLETED_LIST)
438 {
439 m_pParent->_getLabelstr( labelStr, insPoint, depth+1,getParentItem());
440 if(*insPoint != 0)
441 {
442 psz = strlen(m_pszDecimal);
443 for(i=0; i<=psz;i++)
444 {
445 labelStr[(*insPoint)++] = CONV_TO_UCS m_pszDecimal[i];
446 }
447 (*insPoint)--;
448 }
449 }
450
451 UT_sint32 place = getPositionInList(pLayout,depth);
452 if (place == -1)
453 {
454 // UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
455 labelStr[0] = 0;
456 (*insPoint) = 0;
457 return;
458 }
459 place += m_iStartValue;
460
461 // if (depth == 0 )
462 if(IS_NUMBERED_LIST_TYPE(m_List_Type))
463 {
464 psz = strlen(leftDelim);
465 char *pSrc = leftDelim;
466 char *pLim = leftDelim + psz;
467 while (pSrc < pLim)
468 {
469 UT_UCS4Char ch = g_utf8_get_char_validated(pSrc,pLim-pSrc);
470 if (((signed)ch) < 0) ch=UCS_REPLACECHAR;
471 labelStr[(*insPoint)++] = ch;
472 pSrc = g_utf8_next_char(pSrc);
473 }
474 }
475 switch( m_List_Type)
476 {
477 case NUMBERED_LIST:
478 sprintf(p,"%i",place);
479 psz = strlen( p);
480 for(i=0; i<psz; i++)
481 {
482 labelStr[(*insPoint)++] = CONV_TO_UCS p[i];
483 }
484 break;
485
486 case UPPERCASE_LIST:
487 {
488 char * val = dec2ascii(place - 1, 65);
489 sprintf(p,"%s",val);
490 FREEP(val);
491 psz = strlen( p);
492 for(i=0; i<psz; i++)
493 {
494 labelStr[(*insPoint)++] = CONV_TO_UCS p[i];
495 }
496 break;
497 }
498
499 case LOWERCASE_LIST:
500 {
501 char * val = dec2ascii(place - 1, 97);
502 sprintf(p,"%s",val);
503 FREEP(val);
504 psz = strlen( p);
505 for(i=0; i<psz; i++)
506 {
507 labelStr[(*insPoint)++] = CONV_TO_UCS p[i];
508 }
509 break;
510 }
511
512 case UPPERROMAN_LIST:
513 {
514 char * val = dec2roman(place,false);
515 sprintf(p,"%s",val);
516 FREEP(val);
517 psz = strlen( p);
518 for(i=0; i<psz; i++)
519 {
520 labelStr[(*insPoint)++] = CONV_TO_UCS p[i];
521 }
522 break;
523 }
524
525 case LOWERROMAN_LIST:
526 {
527 char * val = dec2roman(place,true);
528 sprintf(p,"%s",val);
529 FREEP(val);
530 psz = strlen( p);
531 for(i=0; i<psz; i++)
532 {
533 labelStr[(*insPoint)++] = CONV_TO_UCS p[i];
534 }
535 break;
536 }
537
538 case ARABICNUMBERED_LIST:
539 sprintf(p,"%i",place);
540 psz = strlen( p);
541 for(i=0; i<psz; i++)
542 {
543 labelStr[(*insPoint)++] = (CONV_TO_UCS p[i]) + 0x0660 - (CONV_TO_UCS '0');
544 }
545 break;
546
547 case HEBREW_LIST:
548 dec2hebrew(labelStr,insPoint,place);
549 break;
550
551 case BULLETED_LIST:
552 labelStr[(*insPoint)++] = 0x2022;
553 break;
554
555 case DASHED_LIST:
556 labelStr[(*insPoint)++] = 0x002D;
557 break;
558
559 case SQUARE_LIST:
560 labelStr[(*insPoint)++] = 0x25A0;
561 break;
562
563 case TRIANGLE_LIST:
564 labelStr[(*insPoint)++] = 0x25B2;
565 break;
566
567 case DIAMOND_LIST:
568 labelStr[(*insPoint)++] = 0x2666;
569 break;
570
571 case STAR_LIST:
572 labelStr[(*insPoint)++] = 0x2733;
573 break;
574
575 case IMPLIES_LIST:
576 labelStr[(*insPoint)++] = 0x21D2;
577 break;
578
579 case TICK_LIST:
580 labelStr[(*insPoint)++] = 0x2713;
581 break;
582
583 case BOX_LIST:
584 labelStr[(*insPoint)++] = 0x2752;
585 break;
586
587 case HAND_LIST:
588 labelStr[(*insPoint)++] = 0x261E;
589 break;
590
591 case HEART_LIST:
592 labelStr[(*insPoint)++] = 0x2665;
593 break;
594
595 case ARROWHEAD_LIST:
596 labelStr[(*insPoint)++] = 0x27A3;
597 break;
598
599 default:
600 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
601 break;
602 }
603
604 if( m_List_Type < BULLETED_LIST &&
605 (g_ascii_strncasecmp(m_pszDecimal,rightDelim,4) != 0 || depth == 0) )
606 {
607 psz = strlen(rightDelim);
608 char *pSrc = rightDelim;
609 char *pLim = rightDelim + psz;
610 while (pSrc < pLim)
611 {
612 UT_UCS4Char ch = g_utf8_get_char_validated(pSrc,pLim-pSrc);
613 if (((signed)ch) < 0) ch=UCS_REPLACECHAR;
614 labelStr[(*insPoint)++] = ch;
615 pSrc = g_utf8_next_char(pSrc);
616 }
617 }
618 labelStr[(*insPoint)] = 0;
619 return;
620 }
621
getLabel(pf_Frag_Strux * pItem) const622 const UT_UCSChar * fl_AutoNum::getLabel(pf_Frag_Strux* pItem) const
623 {
624 static UT_UCSChar label[100];
625 UT_uint32 insPoint = 0;
626 UT_uint32 depth = 0;
627 _getLabelstr( label, &insPoint, depth , pItem);
628 if(insPoint == 0 )
629 {
630 return static_cast<const UT_UCSChar *>(NULL);
631 }
632 else
633 {
634 return static_cast<const UT_UCSChar *>(label);
635 }
636 }
637
getValue(pf_Frag_Strux * pItem) const638 UT_uint32 fl_AutoNum::getValue(pf_Frag_Strux* pItem) const
639 {
640 return getPositionInList(pItem,0) + m_iStartValue;
641 }
642
643
setListType(FL_ListType lType)644 void fl_AutoNum::setListType(FL_ListType lType)
645 {
646 m_List_Type = lType;
647 }
648
isDirty() const649 bool fl_AutoNum::isDirty() const
650 {
651 return m_bDirty;
652 }
653
setDelim(const gchar * lDelim)654 void fl_AutoNum::setDelim(const gchar * lDelim)
655 {
656 strncpy( m_pszDelim, lDelim, 80);
657 m_bDirty = true;
658 }
659
getDelim() const660 const gchar * fl_AutoNum::getDelim() const
661 {
662 return m_pszDelim;
663 }
664
665
getDecimal() const666 const gchar * fl_AutoNum::getDecimal() const
667 {
668 return m_pszDecimal;
669 }
670
setDecimal(const gchar * lDecimal)671 void fl_AutoNum::setDecimal(const gchar * lDecimal)
672 {
673 strncpy( m_pszDecimal, lDecimal, 80);
674 m_bDirty = true;
675 }
676
getType() const677 FL_ListType fl_AutoNum::getType() const
678 {
679 return m_List_Type;
680 }
681
setStartValue(UT_uint32 start)682 void fl_AutoNum::setStartValue(UT_uint32 start)
683 {
684 m_iStartValue = start;
685 m_bDirty = true;
686 _updateItems(0,NULL);
687 }
688
setAsciiOffset(UT_uint32 new_asciioffset)689 void fl_AutoNum::setAsciiOffset(UT_uint32 new_asciioffset)
690 {
691 m_iAsciiOffset = static_cast<UT_uint16>(new_asciioffset);
692 m_bDirty = true;
693 }
694
getStartValue32() const695 UT_uint32 fl_AutoNum::getStartValue32() const
696 {
697 return m_iStartValue;
698 }
699
insertFirstItem(pf_Frag_Strux * pItem,pf_Frag_Strux * pLast,UT_uint32,bool bDoFix)700 void fl_AutoNum::insertFirstItem(pf_Frag_Strux* pItem, pf_Frag_Strux* pLast, UT_uint32 /*depth*/, bool bDoFix)
701 {
702 UT_sint32 i = -1;
703 if(m_pItems.getItemCount() > 0)
704 i = m_pItems.findItem(pItem);
705 if(i < 0)
706 {
707 m_pItems.insertItemAt(pItem, 0);
708 m_bDirty = true;
709 }
710 if(bDoFix)
711 {
712 fixListOrder();
713 }
714 if (m_pParent)
715 {
716 m_pParentItem = pLast;
717 m_bDirty = true;
718 }
719 if(m_pDoc->areListUpdatesAllowed() == false)
720 return;
721 if ( getAutoNumFromSdh(pItem) == this)
722 _updateItems(0,NULL);
723 }
724
getParentItem() const725 pf_Frag_Strux* fl_AutoNum::getParentItem() const
726 {
727 return m_pParentItem;
728 }
729
730
setParentItem(pf_Frag_Strux * pItem)731 void fl_AutoNum::setParentItem(pf_Frag_Strux* pItem)
732 {
733 m_pParentItem = pItem;
734 m_bDirty = true;
735 }
736
insertItem(pf_Frag_Strux * pItem,pf_Frag_Strux * pPrev,bool bDoFix)737 void fl_AutoNum::insertItem(pf_Frag_Strux* pItem, pf_Frag_Strux* pPrev, bool bDoFix)
738 {
739 UT_sint32 ndx,i;
740 UT_ASSERT(pItem);
741 ndx = m_pItems.findItem(pItem);
742 if(ndx >= 0)
743 return;
744 m_bDirty = true;
745 ndx = m_pItems.findItem(pPrev) + 1;
746 m_pItems.insertItemAt(pItem, ndx);
747 if(bDoFix)
748 {
749 fixListOrder();
750 }
751 if(m_pDoc->areListUpdatesAllowed() == false)
752 return;
753
754 // scan through all the lists and update parent pointers
755
756 UT_sint32 numlists = m_pDoc->getListsCount();
757 for(i=0; i<numlists; i++)
758 {
759 fl_AutoNum * pAuto = m_pDoc->getNthList(i);
760 if( pPrev == pAuto->getParentItem())
761 {
762 pAuto->setParentItem(pItem);
763 pAuto->m_bDirty = true;
764 if(!pAuto->_updateItems(0,NULL))
765 return;
766 }
767 }
768
769 _updateItems(ndx+1,NULL);
770 }
771
772
prependItem(pf_Frag_Strux * pItem,pf_Frag_Strux * pNext,bool bDoFix)773 void fl_AutoNum::prependItem(pf_Frag_Strux* pItem, pf_Frag_Strux* pNext, bool bDoFix)
774 {
775 UT_sint32 ndx;
776 UT_sint32 i;
777 UT_ASSERT(pItem);
778 pf_Frag_Strux* pPrev = NULL;
779 ndx = m_pItems.findItem(pItem);
780 if(ndx >= 0)
781 return;
782 m_bDirty = true;
783 ndx = m_pItems.findItem(pNext);
784 if(ndx > 0)
785 {
786 pPrev = m_pItems.getNthItem(ndx-1);
787 }
788 m_pItems.insertItemAt(pItem, ndx);
789 if(bDoFix)
790 fixListOrder(); // safety!!
791 if(m_pDoc->areListUpdatesAllowed() == false)
792 return;
793 if(pPrev != NULL)
794 {
795 // scan through all the lists and update parent pointers
796
797 UT_sint32 numlists = m_pDoc->getListsCount();
798 for(i=0; i<numlists; i++)
799 {
800 fl_AutoNum * pAuto = m_pDoc->getNthList(i);
801 if( pPrev == pAuto->getParentItem())
802 {
803 pAuto->setParentItem(pItem);
804 pAuto->m_bDirty = true;
805 if( pAuto->_updateItems(0,NULL))
806 return;
807 }
808 }
809 }
810 _updateItems(ndx,NULL);
811 }
812
removeItem(pf_Frag_Strux * pItem)813 void fl_AutoNum::removeItem(pf_Frag_Strux* pItem)
814 {
815 UT_sint32 ndx = m_pItems.findItem(pItem);
816 UT_sint32 i;
817 //
818 // For multi-views we might have already deleted pItem from the
819 // fl_AutoNum
820 //
821 //
822 UT_ASSERT(ndx != -1);
823 if(ndx < 0 )
824 {
825 m_bDirty = true;
826 _updateItems(0,NULL);
827 return;
828 }
829 pf_Frag_Strux* ppItem = NULL;
830 if(ndx > 0)
831 {
832 ppItem = m_pItems.getNthItem(ndx - 1);
833 }
834 m_pItems.deleteNthItem(ndx);
835 m_bDirty = true;
836
837 // scan through all the lists and update parent pointers
838
839 UT_sint32 numlists = m_pDoc->getListsCount();
840 for(i=0; i<numlists; i++)
841 {
842 fl_AutoNum * pAuto = m_pDoc->getNthList(i);
843 if( pItem == pAuto->getParentItem())
844 {
845 pAuto->setParentItem(ppItem);
846 if(ppItem == NULL)
847 {
848 UT_uint32 level = pAuto->getLevel();
849 if(level > 0)
850 {
851 level = level - 1;
852 }
853 else
854 {
855 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
856 }
857 pAuto->setLevel(level);
858 pAuto->_setParent(getParent());
859 pAuto->m_bDirty = true;
860 pAuto->setParentItem(getParentItem());
861 }
862 if(m_pDoc->areListUpdatesAllowed() == true)
863 if(!pAuto->_updateItems(0,NULL))
864 return;
865 }
866 }
867 _updateItems(ndx,NULL);
868 }
869
getNumLabels() const870 UT_uint32 fl_AutoNum::getNumLabels() const
871 {
872 return m_pItems.getItemCount();
873 }
874
getPositionInList(pf_Frag_Strux * pItem,UT_uint32) const875 UT_sint32 fl_AutoNum::getPositionInList(pf_Frag_Strux* pItem, UT_uint32 /*depth*/) const
876 {
877 UT_return_val_if_fail(m_pItems.getItemCount() >= 0, -1)
878
879 pf_Frag_Strux* pTmp;
880 UT_uint32 ndx = 0;
881 UT_uint32 count = m_pItems.getItemCount();
882 bool bOnLevel = true;
883 bool bFirstItem = false;
884
885 for (UT_uint32 i = 0; i < count; i++)
886 {
887 pTmp = static_cast<pf_Frag_Strux*>(m_pItems.getNthItem(i));
888 // bOnLevel = (depth == 0);
889 const fl_AutoNum* pAuto = getAutoNumFromSdh(pItem);
890 bOnLevel = static_cast<bool>( pAuto == this);
891 bFirstItem = static_cast<bool>(pTmp == m_pItems.getFirstItem());
892 if (pTmp == pItem)
893 {
894 if (m_bWordMultiStyle && !bOnLevel && !bFirstItem)
895 ndx--;
896 return ndx;
897 }
898 else if (!m_bWordMultiStyle || bOnLevel || bFirstItem)
899 {
900 ndx++;
901 }
902 }
903
904 return -1;
905 // return m_pItems.findItem(pItem);
906 }
907
getAutoNumFromSdh(pf_Frag_Strux * sdh)908 fl_AutoNum * fl_AutoNum::getAutoNumFromSdh(pf_Frag_Strux* sdh)
909 {
910 UT_sint32 i;
911 fl_AutoNum * pAuto = NULL;
912 if(m_pDoc->areListUpdatesAllowed() == false)
913 {
914 if(isItem(sdh) == false)
915 {
916 return static_cast<fl_AutoNum *>(NULL);
917 }
918 return this;
919 }
920 UT_sint32 numLists = m_pDoc->getListsCount();
921 for(i=0; i<numLists; i++)
922 {
923 pAuto = m_pDoc->getNthList(i);
924 if(pAuto->isItem(sdh))
925 break;
926 }
927 if(i>= numLists)
928 {
929 return static_cast<fl_AutoNum *>(NULL);
930 }
931 return pAuto;
932 }
933
getAutoNumFromSdh(pf_Frag_Strux * sdh) const934 const fl_AutoNum* fl_AutoNum::getAutoNumFromSdh(pf_Frag_Strux* sdh) const
935 {
936 UT_sint32 i;
937 const fl_AutoNum* pAuto = 0;
938
939 if (m_pDoc->areListUpdatesAllowed() == false)
940 {
941 if (isItem(sdh) == false)
942 return 0;
943
944 return this;
945 }
946
947 UT_sint32 numLists = m_pDoc->getListsCount();
948 for (i = 0; i < numLists; ++i)
949 {
950 pAuto = m_pDoc->getNthList(i);
951 if (pAuto->isItem(sdh))
952 break;
953 }
954
955 if (i >= numLists)
956 return 0;
957
958 return pAuto;
959 }
960
getLastItemInHeiracy(void) const961 pf_Frag_Strux* fl_AutoNum::getLastItemInHeiracy(void) const
962 {
963 const fl_AutoNum * pAuto = this;
964 pf_Frag_Strux* pLastItem = NULL;
965 bool bLoop = true;
966 fl_AutoNum * pNext = NULL;
967 UT_uint32 numLists = m_pDoc->getListsCount();
968 UT_uint32 i=0;
969 while(bLoop)
970 {
971 pLastItem = pAuto->getLastItem();
972 for(i=0; i<numLists; i++)
973 {
974 pNext = m_pDoc->getNthList(i);
975 if(pNext->isItem(pLastItem) && pNext->getLevel() > pAuto->getLevel())
976 {
977 pAuto = pNext;
978 break;
979 }
980 }
981 if(i >= numLists)
982 {
983 bLoop = false;
984 }
985 }
986 return pLastItem;
987 }
988
isItem(pf_Frag_Strux * pItem) const989 bool fl_AutoNum::isItem(pf_Frag_Strux* pItem) const
990 {
991 if (m_pItems.findItem(pItem) == -1)
992 return false;
993 else
994 return true;
995 }
996
isEmpty() const997 bool fl_AutoNum::isEmpty() const
998 {
999 if (m_pItems.getItemCount() > 0)
1000 return false;
1001 else
1002 return true;
1003 }
1004
getFirstItem() const1005 pf_Frag_Strux* fl_AutoNum::getFirstItem() const
1006 {
1007 return (m_pItems.getItemCount() ? m_pItems.getFirstItem() : 0);
1008 }
1009
1010
getLastItem() const1011 pf_Frag_Strux* fl_AutoNum::getLastItem() const
1012 {
1013 UT_uint32 i = m_pItems.getItemCount();
1014 if(i == 0 )
1015 return NULL;
1016 else
1017 {
1018 return m_pItems.getNthItem(i-1);
1019 }
1020 }
1021
doesItemHaveLabel(fl_BlockLayout * pItem) const1022 bool fl_AutoNum::doesItemHaveLabel( fl_BlockLayout * pItem) const
1023 {
1024 fp_Run * pRun = pItem->getFirstRun();
1025 bool bStop = false;
1026 while(bStop == false)
1027 {
1028 if(pRun->getType() == FPRUN_FIELD)
1029 {
1030 fp_FieldRun * pFRun = static_cast<fp_FieldRun *>(pRun);
1031 if(pFRun->getFieldType() == FPFIELD_list_label)
1032 {
1033 bStop = true;
1034 return true;
1035 }
1036 }
1037 pRun = pRun->getNextRun();
1038 if(pRun == NULL)
1039 {
1040 bStop = true;
1041 return false;
1042 }
1043 }
1044 return false;
1045 }
1046
1047
isLastOnLevel(pf_Frag_Strux * pItem) const1048 bool fl_AutoNum::isLastOnLevel(pf_Frag_Strux* pItem) const
1049 {
1050 UT_sint32 itemloc = m_pItems.findItem(pItem);
1051 if (itemloc == -1)
1052 return false;
1053 if(itemloc == m_pItems.getItemCount() - 1)
1054 return true;
1055 else
1056 return false;
1057 }
1058
getActiveParent(void) const1059 fl_AutoNum * fl_AutoNum::getActiveParent(void) const
1060 {
1061 fl_AutoNum * pAutoNum = m_pParent;
1062
1063 while (pAutoNum && pAutoNum->isEmpty())
1064 pAutoNum = pAutoNum->getParent();
1065
1066 return pAutoNum;
1067 }
1068
1069 /*!
1070 * This method returns true if the requested ID is somewhere in this
1071 * List heiracy.
1072 */
isIDSomeWhere(UT_uint32 ID) const1073 bool fl_AutoNum::isIDSomeWhere(UT_uint32 ID) const
1074 {
1075 const fl_AutoNum * pAuto = this;
1076 while(pAuto != NULL)
1077 {
1078 if(pAuto->getID() == ID)
1079 {
1080 return true;
1081 }
1082 pAuto = pAuto->getParent();
1083 }
1084 return false;
1085 }
1086
_setParent(fl_AutoNum * pParent)1087 void fl_AutoNum::_setParent(fl_AutoNum * pParent)
1088 {
1089 if(pParent == this)
1090 {
1091 m_pParent = NULL;
1092 m_iParentID = 0;
1093 m_bDirty = true;
1094 return;
1095 }
1096 if(pParent != m_pParent)
1097 {
1098 char szParent[13];
1099 m_pParent = pParent;
1100 if(m_pParent != NULL)
1101 {
1102 if(!pParent->checkReference(this))
1103 {
1104 m_pParent = NULL;
1105 m_iParentID = 0;
1106 m_bDirty = true;
1107 return;
1108 }
1109 m_iParentID = pParent->getID();
1110 }
1111 else
1112 {
1113 m_iParentID = 0;
1114 }
1115
1116 sprintf(szParent,"%d",m_iParentID);
1117 m_bDirty = true;
1118 UT_sint32 i = 0;
1119 for(i=0; i < m_pItems.getItemCount() ; i++)
1120 {
1121 pf_Frag_Strux* sdh = m_pItems.getNthItem(i);
1122 m_pDoc->changeStruxForLists(sdh, static_cast<const char *>(szParent));
1123 }
1124 }
1125 }
1126
1127
_setParentID(UT_uint32 iParentID)1128 void fl_AutoNum::_setParentID(UT_uint32 iParentID)
1129 {
1130 m_bDirty = true;
1131 m_iParentID = iParentID;
1132 }
1133
update(UT_uint32 start)1134 void fl_AutoNum::update(UT_uint32 start)
1135 {
1136 UT_DEBUGMSG(("Updating List %d There are %d items here \n",m_iID,m_pItems.getItemCount()));
1137 if (isUpdating())
1138 return;
1139 //_calculateLabelStr(0);
1140 if(!_updateItems(start, NULL))
1141 return;
1142 pf_Frag_Strux* sdh = getFirstItem();
1143 UT_return_if_fail(sdh);
1144 if (m_pParent && !m_pParent->isUpdating())
1145 {
1146 UT_uint32 ndx = m_pParent->m_pItems.findItem(sdh);
1147 m_pParent->update(ndx + 1);
1148 }
1149 }
1150
_updateItems(UT_sint32 start,pf_Frag_Strux * notMe)1151 bool fl_AutoNum::_updateItems(UT_sint32 start, pf_Frag_Strux* notMe)
1152 {
1153 // UT_DEBUGMSG(("Entering _updateItems\n"));
1154 UT_sint32 j;
1155 UT_return_val_if_fail(m_pDoc,false);
1156 if(m_pDoc->areListUpdatesAllowed() == true)
1157 {
1158 //if(start == 0)
1159 // {
1160 // pCurDoc = m_pDoc;
1161 // fixListOrder();
1162 // }
1163 UT_sint32 numlists = m_pDoc->getListsCount();
1164 m_bUpdatingItems = true;
1165 for (UT_sint32 i = start; i < m_pItems.getItemCount(); i++)
1166 {
1167 // UT_DEBUGMSG(("Entering _updateItems for loop\n"));
1168 pf_Frag_Strux* pTmp = m_pItems.getNthItem(i);
1169 UT_ASSERT(pTmp);
1170 m_pDoc->listUpdate(pTmp);
1171
1172 // scan through all the lists and update child lists if connected to this item
1173
1174 pf_Frag_Strux* pItem = m_pItems.getNthItem(i);
1175 for(j=0; j<numlists; j++)
1176 {
1177 fl_AutoNum * pAuto = m_pDoc->getNthList(j);
1178 UT_ASSERT_HARMLESS(pAuto);
1179 if( pAuto && (pItem == pAuto->getParentItem()) && (pItem != notMe))
1180 {
1181 if(!pAuto->_updateItems(0,pItem))
1182 return false;
1183 }
1184 }
1185 }
1186 m_bUpdatingItems = false;
1187 m_bDirty = false;
1188 }
1189 return true;
1190 }
1191
1192 ///
1193 /// Returns true if item is contained or immediately adjacent to the list
1194 ///
isContainedByList(pf_Frag_Strux * pItem) const1195 bool fl_AutoNum::isContainedByList(pf_Frag_Strux* pItem) const
1196 {
1197 pf_Frag_Strux* sdh, *sdh_prev, *sdh_next;
1198 PT_DocPosition pos_prev,pos_next,pos;
1199 bool bret;
1200 UT_uint32 no_items = m_pItems.getItemCount();
1201 if(no_items == 0)
1202 return false;
1203 sdh = m_pItems.getFirstItem();
1204 bret = m_pDoc->getPrevStruxOfType(sdh,PTX_Block, &sdh_prev);
1205 if(bret == false)
1206 sdh_prev = sdh;
1207 pos_prev = m_pDoc->getStruxPosition(sdh_prev);
1208 sdh = m_pItems.getNthItem(no_items-1);
1209 bret = m_pDoc->getNextStruxOfType(sdh,PTX_Block, &sdh_next);
1210 if(bret == false)
1211 sdh_next = sdh;
1212 pos_next = m_pDoc->getStruxPosition(sdh_next);
1213 pos = m_pDoc->getStruxPosition(pItem);
1214 if((pos >= pos_prev) && (pos <= pos_next))
1215 return true;
1216 return false;
1217 }
1218
1219
getNthBlock(UT_sint32 list_num) const1220 pf_Frag_Strux* fl_AutoNum::getNthBlock( UT_sint32 list_num) const
1221 {
1222 if(list_num >= m_pItems.getItemCount())
1223 return NULL;
1224 else
1225 return m_pItems.getNthItem(list_num);
1226 }
1227
getPrevInList(pf_Frag_Strux * pItem) const1228 pf_Frag_Strux* fl_AutoNum::getPrevInList( pf_Frag_Strux* pItem) const
1229 {
1230 UT_sint32 itemloc = m_pItems.findItem(pItem);
1231 if (itemloc == -1 || itemloc == 0)
1232 return NULL;
1233 return m_pItems.getNthItem( static_cast<UT_uint32>(itemloc) - 1);
1234 }
1235
_getLevelValue(fl_AutoNum * pAutoNum) const1236 inline UT_uint32 fl_AutoNum::_getLevelValue(fl_AutoNum * pAutoNum) const
1237 {
1238 pf_Frag_Strux* pBlock = const_cast<pf_Frag_Strux*>(getFirstItem());
1239 const fl_AutoNum * pCurr = this;
1240
1241 while (1)
1242 {
1243 if (pAutoNum->isItem(pBlock))
1244 {
1245 break;
1246 }
1247 else
1248 {
1249 pCurr = pCurr->getParent();
1250 pBlock = pCurr->getFirstItem();
1251 }
1252 }
1253
1254 return pAutoNum->getValue(pBlock);
1255 }
1256
dec2roman(UT_sint32 value,bool lower)1257 char * fl_AutoNum::dec2roman(UT_sint32 value, bool lower)
1258 {
1259 UT_String roman;
1260
1261 while( value >= 1000 )
1262 {
1263 roman += "M";
1264 value -= 1000;
1265 }
1266 if( value >= 900 )
1267 {
1268 roman += "CM";
1269 value -= 900;
1270 }
1271 while( value >= 500 )
1272 {
1273 roman += "D";
1274 value -= 500;
1275 }
1276 if( value >= 400 )
1277 {
1278 roman += "CD";
1279 value -= 400;
1280 }
1281 while( value >= 100 )
1282 {
1283 roman += "C";
1284 value -= 100;
1285 }
1286 if( value >= 90 )
1287 {
1288 roman += "XC";
1289 value -= 90;
1290 }
1291 while( value >= 50 )
1292 {
1293 roman += "L";
1294 value -= 50;
1295 }
1296 if( value >= 40 )
1297 {
1298 roman += "XL";
1299 value -= 40;
1300 }
1301 while( value >= 10 )
1302 {
1303 roman += "X";
1304 value -= 10;
1305 }
1306 if( value >= 9 )
1307 {
1308 roman += "IX";
1309 value -= 9;
1310 }
1311 while( value >= 5 )
1312 {
1313 roman += "V";
1314 value -= 5;
1315 }
1316 if( value >= 4 )
1317 {
1318 roman += "IV";
1319 value -= 4;
1320 }
1321 while( value > 0 )
1322 {
1323 roman += "I";
1324 value--;
1325 }
1326
1327 char * rmn = g_strdup (roman.c_str());
1328
1329 if (lower == true)
1330 {
1331 int len;
1332 len = roman.size();
1333 while (--len >= 0)
1334 {
1335 UT_sint32 r = static_cast<UT_sint32>(roman[len]);
1336 if( (r >= (UT_sint32) 'A') && (r <= (UT_sint32) 'Z'))
1337 r = r + 32;
1338 rmn[len] = static_cast<char>(r);
1339 }
1340 }
1341
1342 return rmn;
1343 }
1344
dec2ascii(UT_sint32 value,UT_uint32 offset)1345 char * fl_AutoNum::dec2ascii(UT_sint32 value, UT_uint32 offset)
1346 {
1347 char ascii[30];
1348 UT_uint32 ndx, count, i;
1349
1350 ascii[0] = '\0';
1351 ndx = abs(value % 26);
1352 count = abs(value / 26);
1353
1354 // For now, we do this like Word. A preference would be nice.
1355 for (i = 0; i <= count; i++)
1356 {
1357 ascii[i] = static_cast<char>(ndx + offset);
1358 }
1359 ascii[i] = '\0';
1360
1361 return g_strdup(ascii);
1362 }
1363
dec2hebrew(UT_UCSChar labelStr[],UT_uint32 * insPoint,UT_sint32 value)1364 void fl_AutoNum::dec2hebrew(UT_UCSChar labelStr[], UT_uint32 * insPoint, UT_sint32 value)
1365 {
1366 UT_UCSChar gHebrewDigit[22] =
1367 {
1368 // 1 2 3 4 5 6 7 8 9
1369 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8,
1370 // 10 20 30 40 50 60 70 80 90
1371 0x05D9, 0x05DB, 0x05DC, 0x05DE, 0x05E0, 0x05E1, 0x05E2, 0x05E4, 0x05E6,
1372 // 100 200 300 400
1373 0x05E7, 0x05E8, 0x05E9, 0x05EA
1374 };
1375
1376 bool outputSep = false;
1377 UT_UCSChar digit;
1378 do
1379 {
1380 UT_sint32 n3 = value % 1000;
1381
1382 if(outputSep)
1383 labelStr[(*insPoint)++] = 0x0020; // output thousand seperator
1384 outputSep = ( n3 > 0); // request to output thousand seperator next time.
1385
1386 // Process digit for 100 - 900
1387 for(UT_sint32 n1 = 400; n1 > 0; )
1388 {
1389 if( n3 >= n1)
1390 {
1391 n3 -= n1;
1392 labelStr[(*insPoint)++] = gHebrewDigit[(n1/100)-1+18];
1393 } else {
1394 n1 -= 100;
1395 } // if
1396 } // for
1397
1398 // Process digit for 10 - 90
1399 UT_sint32 n2;
1400 if( n3 >= 10 )
1401 {
1402 // Special process for 15 and 16
1403 if(( 15 == n3 ) || (16 == n3)) {
1404 // Special rule for religious reason...
1405 // 15 is represented by 9 and 6, not 10 and 5
1406 // 16 is represented by 9 and 7, not 10 and 6
1407 n2 = 9;
1408 digit = gHebrewDigit[ n2 - 1];
1409 } else {
1410 n2 = n3 - (n3 % 10);
1411 digit = gHebrewDigit[(n2/10)-1+9];
1412 } // if
1413
1414 n3 -= n2;
1415 labelStr[(*insPoint)++] = digit;
1416 } // if
1417
1418 // Process digit for 1 - 9
1419 if ( n3 > 0)
1420 {
1421 labelStr[(*insPoint)++] = gHebrewDigit[n3-1];
1422 } // if
1423 value /= 1000;
1424 } while (value >= 1);
1425 }
1426
1427 /* FIXME -- cannot use UT_GenericVector<> here due to the way
1428 * getNthItem() is implemented -- UT_GenericVector<UT_UTF8String>
1429 * cannot be constructed (see comment in ut_vector.h); do not want
1430 * to mess with that class at this very moment.
1431 */
getAttributes(std::vector<UT_UTF8String> & v,bool bEscapeXML) const1432 void fl_AutoNum::getAttributes (std::vector<UT_UTF8String> & v,
1433 bool bEscapeXML) const
1434 {
1435 char szID[15], szPid[15], szType[12], szStart[12];
1436
1437 sprintf(szID, "%i", m_iID);
1438 v.push_back("id");
1439 v.push_back(szID);
1440
1441 if (m_pParent)
1442 sprintf(szPid, "%i", m_pParent->getID());
1443 else
1444 sprintf(szPid, "0");
1445 v.push_back("parentid");
1446 v.push_back(szPid);
1447
1448 sprintf(szType, "%i", m_List_Type);
1449 v.push_back("type");
1450 v.push_back(szType);
1451
1452 sprintf(szStart, "%i", m_iStartValue);
1453 v.push_back("start-value");
1454 v.push_back(szStart);
1455
1456 v.push_back("list-delim");
1457 v.push_back (m_pszDelim);
1458 if (bEscapeXML)
1459 {
1460 v.back().escapeXML();
1461 }
1462
1463 v.push_back("list-decimal");
1464 v.push_back (m_pszDecimal);
1465 if (bEscapeXML)
1466 {
1467 v.back().escapeXML();
1468 }
1469 }
1470
1471