1 /* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */
2 
3 /* AbiSource
4  *
5  * Copyright (C) 2009 Firat Kiyak <firatkiyak@gmail.com>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20  * 02110-1301 USA.
21  */
22 
23 // Class definition include
24 #include <OXMLi_ListenerState_Numbering.h>
25 
26 // Internal includes
27 #include <OXML_Document.h>
28 #include <OXML_FontManager.h>
29 #include <OXML_Types.h>
30 #include <OXML_List.h>
31 
32 // AbiWord includes
33 #include <ut_assert.h>
34 #include <ut_misc.h>
35 
36 // External includes
37 #include <string>
38 
OXMLi_ListenerState_Numbering()39 OXMLi_ListenerState_Numbering::OXMLi_ListenerState_Numbering():
40 	OXMLi_ListenerState(),
41 	m_currentList(NULL),
42 	m_currentNumId(""),
43 	m_parentListId("")
44 {
45 
46 }
47 
startElement(OXMLi_StartElementRequest * rqst)48 void OXMLi_ListenerState_Numbering::startElement (OXMLi_StartElementRequest * rqst)
49 {
50 	if (
51 		nameMatches(rqst->pName, NS_W_KEY, "numbering") ||
52 		nameMatches(rqst->pName, NS_W_KEY, "multiLevelType") ||
53 		nameMatches(rqst->pName, NS_W_KEY, "name") ||
54 		nameMatches(rqst->pName, NS_W_KEY, "nsid") ||
55 		nameMatches(rqst->pName, NS_W_KEY, "numStyleLink") ||
56 		nameMatches(rqst->pName, NS_W_KEY, "styleLink") ||
57 		nameMatches(rqst->pName, NS_W_KEY, "tmpl") ||
58 		nameMatches(rqst->pName, NS_W_KEY, "isLgl") ||
59 		nameMatches(rqst->pName, NS_W_KEY, "legacy") ||
60 		nameMatches(rqst->pName, NS_W_KEY, "lvlJc") ||
61 		nameMatches(rqst->pName, NS_W_KEY, "lvlPicBulletId") ||
62 		nameMatches(rqst->pName, NS_W_KEY, "lvlRestart") ||
63 		nameMatches(rqst->pName, NS_W_KEY, "suff")
64 		)
65 	{
66 		//TODO: add functionality here
67 		rqst->handled = true;
68 	}
69 	else if(nameMatches(rqst->pName, NS_W_KEY, "abstractNum"))
70 	{
71 		const gchar* abstractNumId = attrMatches(NS_W_KEY, "abstractNumId", rqst->ppAtts);
72 		if(abstractNumId)
73 		{
74 			m_parentListId = std::string("1");
75 			m_parentListId += abstractNumId;
76 		}
77 		rqst->handled = true;
78 	}
79 	else if(nameMatches(rqst->pName, NS_W_KEY, "lvl"))
80 	{
81 		const gchar* ilvl = attrMatches(NS_W_KEY, "ilvl", rqst->ppAtts);
82 		if(ilvl)
83 		{
84 			handleLevel(ilvl);
85 		}
86 		rqst->handled = true;
87 	}
88 	else if(nameMatches(rqst->pName, NS_W_KEY, "start"))
89 	{
90 		const gchar* val = attrMatches(NS_W_KEY, "val", rqst->ppAtts);
91 		if(val && m_currentList)
92 		{
93 			m_currentList->setStartValue(atoi(val));
94 		}
95 		rqst->handled = true;
96 	}
97 	else if(nameMatches(rqst->pName, NS_W_KEY, "numFmt"))
98 	{
99 		const gchar* val = attrMatches(NS_W_KEY, "val", rqst->ppAtts);
100 		if(val)
101 		{
102 			handleFormattingType(val);
103 		}
104 		rqst->handled = true;
105 	}
106 	else if(nameMatches(rqst->pName, NS_W_KEY, "lvlText"))
107 	{
108 		const gchar* val = attrMatches(NS_W_KEY, "val", rqst->ppAtts);
109 		if(val && m_currentList)
110 		{
111 			std::string delim(val);
112 			m_currentList->setDelim(delim);
113 		}
114 		rqst->handled = true;
115 	}
116 	else if(nameMatches(rqst->pName, NS_W_KEY, "num"))
117 	{
118 		const gchar* numId = attrMatches(NS_W_KEY, "numId", rqst->ppAtts);
119 		if(numId)
120 		{
121 			m_currentNumId = std::string(numId);
122 		}
123 		rqst->handled = true;
124 	}
125 	else if(nameMatches(rqst->pName, NS_W_KEY, "abstractNumId"))
126 	{
127 		const gchar* val = attrMatches(NS_W_KEY, "val", rqst->ppAtts);
128 		if(val && !m_currentNumId.empty())
129 		{
130 			std::string abstractNumId("1"); //starts at 10 instead of zero
131 			abstractNumId += val;
132 			OXML_Document* doc = OXML_Document::getInstance();
133 			if(doc)
134 				doc->setMappedNumberingId(m_currentNumId, abstractNumId);
135 		}
136 		rqst->handled = true;
137 	}
138 	else if(nameMatches(rqst->pName, NS_W_KEY, "pPr"))
139 	{
140 		//insert a dummy paragraph element to stack
141 		//so that we can collect the properties from common listener
142 		OXML_SharedElement dummy(new OXML_Element_Paragraph(""));
143 		rqst->stck->push(dummy);
144 		rqst->handled = true;
145 	}
146 	else if(nameMatches(rqst->pName, NS_W_KEY, "rPr"))
147 	{
148 		OXML_SharedElement dummy(new OXML_Element_Run(""));
149 		rqst->stck->push(dummy);
150 		rqst->handled = true;
151 	}
152 }
153 
endElement(OXMLi_EndElementRequest * rqst)154 void OXMLi_ListenerState_Numbering::endElement (OXMLi_EndElementRequest * rqst)
155 {
156 	if (
157 		nameMatches(rqst->pName, NS_W_KEY, "numbering") ||
158 		nameMatches(rqst->pName, NS_W_KEY, "abstractNum") ||
159 		nameMatches(rqst->pName, NS_W_KEY, "multiLevelType") ||
160 		nameMatches(rqst->pName, NS_W_KEY, "name") ||
161 		nameMatches(rqst->pName, NS_W_KEY, "nsid") ||
162 		nameMatches(rqst->pName, NS_W_KEY, "numStyleLink") ||
163 		nameMatches(rqst->pName, NS_W_KEY, "styleLink") ||
164 		nameMatches(rqst->pName, NS_W_KEY, "tmpl") ||
165 		nameMatches(rqst->pName, NS_W_KEY, "isLgl") ||
166 		nameMatches(rqst->pName, NS_W_KEY, "legacy") ||
167 		nameMatches(rqst->pName, NS_W_KEY, "lvlJc") ||
168 		nameMatches(rqst->pName, NS_W_KEY, "lvlPicBulletId") ||
169 		nameMatches(rqst->pName, NS_W_KEY, "lvlRestart") ||
170 		nameMatches(rqst->pName, NS_W_KEY, "lvlText") ||
171 		nameMatches(rqst->pName, NS_W_KEY, "numFmt") ||
172 		nameMatches(rqst->pName, NS_W_KEY, "start") ||
173 		nameMatches(rqst->pName, NS_W_KEY, "suff") ||
174 		nameMatches(rqst->pName, NS_W_KEY, "abstractNumId")
175 		)
176 	{
177 		//TODO: add functionality here
178 		rqst->handled = true;
179 	}
180 	else if(nameMatches(rqst->pName, NS_W_KEY, "lvl"))
181 	{
182 		OXML_Document * doc = OXML_Document::getInstance();
183 		if(!doc)
184 		{
185 			doc = OXML_Document::getNewInstance();
186 		}
187 		OXML_SharedList sharedList(m_currentList);
188 		doc->addList(sharedList);
189 		m_currentList = NULL;
190 		rqst->handled = true;
191 	}
192 	else if(nameMatches(rqst->pName, NS_W_KEY, "num"))
193 	{
194 		m_currentNumId.clear(); //set it to empty string
195 		rqst->handled = true;
196 	}
197 	else if(nameMatches(rqst->pName, NS_W_KEY, "pPr") ||
198 			nameMatches(rqst->pName, NS_W_KEY, "rPr"))
199 	{
200 		if(rqst->stck->empty())
201 		{
202 			rqst->handled = false;
203 			rqst->valid = false;
204 			return;
205 		}
206 		OXML_SharedElement dummy = rqst->stck->top();
207 
208 		if(m_currentList)
209 		{
210 			m_currentList->setAttributes(dummy->getAttributes());
211 			m_currentList->setProperties(dummy->getProperties());
212 		}
213 		rqst->stck->pop(); //remove the dummy element
214 		rqst->handled = true;
215 	}
216 }
217 
charData(OXMLi_CharDataRequest *)218 void OXMLi_ListenerState_Numbering::charData (OXMLi_CharDataRequest * /*rqst*/)
219 {
220 	//don't do anything here
221 }
222 
223 
224 //private helper functions
225 
226 
227 /**
228  * Handles the new level tag in the form <lvl ilvl="3">
229  */
handleLevel(const gchar * ilvl)230 void OXMLi_ListenerState_Numbering::handleLevel(const gchar* ilvl)
231 {
232 	m_currentList = new OXML_List();
233 	m_currentList->setLevel(atoi(ilvl)+1); //levels start with index 1
234 	//create a new list with the list id and parent id
235 	//all lists are encoded as id=parentId+ilvl
236 	std::string listId(m_parentListId);
237 	listId += ilvl;
238 	m_currentList->setId(atoi(listId.c_str()));
239 	if(!strcmp(ilvl, "0"))
240 	{
241 		//this is the first level
242 		m_currentList->setParentId(0); //no parent
243 	}
244 	else
245 	{
246 		std::string parentListId(m_parentListId);
247 		parentListId += ('0'+(atoi(ilvl)-1));
248 		m_currentList->setParentId(atoi(parentListId.c_str())); //has parent (ilvl-1)
249 	}
250 }
251 
handleFormattingType(const gchar * val)252 void OXMLi_ListenerState_Numbering::handleFormattingType(const gchar* val)
253 {
254 	if(!m_currentList)
255 		return;
256 
257 	if(!strcmp(val, "decimal"))
258 		m_currentList->setType(NUMBERED_LIST);
259 	else if(!strcmp(val, "lowerLetter"))
260 		m_currentList->setType(LOWERCASE_LIST);
261 	else if(!strcmp(val, "upperLetter"))
262 		m_currentList->setType(UPPERCASE_LIST);
263 	else if(!strcmp(val, "lowerRoman"))
264 		m_currentList->setType(LOWERROMAN_LIST);
265 	else if(!strcmp(val, "upperRoman"))
266 		m_currentList->setType(UPPERROMAN_LIST);
267 	else if(!strcmp(val, "aravicAbjad"))
268 		m_currentList->setType(ARABICNUMBERED_LIST);
269 	else if(!strcmp(val, "hebrew1"))
270 		m_currentList->setType(HEBREW_LIST);
271 	else //default
272 		m_currentList->setType(BULLETED_LIST);
273 	//TODO: add more types here
274 }
275 
276