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