1 /* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */
2
3 /* AbiSource
4 *
5 * Copyright (C) 2007 Philippe Milot <PhilMilot@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_Common.h>
25
26 // Internal includes
27 #include <OXMLi_Types.h>
28 #include <OXMLi_PackageManager.h>
29 #include <OXML_Document.h>
30 #include <OXML_Element.h>
31 #include <OXML_Element_Run.h>
32 #include <OXML_Element_Text.h>
33 #include <OXML_Element_Field.h>
34 #include <OXML_Types.h>
35 #include <OXML_Theme.h>
36 #include <OXML_Style.h>
37 #include <OXML_Section.h>
38 #include <OXML_FontManager.h>
39
40 // AbiWord includes
41 #include <ut_units.h>
42 #include <ut_misc.h>
43 #include <ut_debugmsg.h>
44 #include <ut_assert.h>
45
46 // External includes
47 #include <cstring>
48
OXMLi_ListenerState_Common()49 OXMLi_ListenerState_Common::OXMLi_ListenerState_Common() :
50 OXMLi_ListenerState(),
51 m_pendingSectBreak(false),
52 m_pendingSectBreakType(NEXTPAGE_BREAK),
53 m_eqField(false),
54 m_pageNumberField(false),
55 m_fldChar(false)
56 {
57
58 }
59
~OXMLi_ListenerState_Common()60 OXMLi_ListenerState_Common::~OXMLi_ListenerState_Common()
61 {
62 }
63
startElement(OXMLi_StartElementRequest * rqst)64 void OXMLi_ListenerState_Common::startElement (OXMLi_StartElementRequest * rqst)
65 {
66 UT_return_if_fail( this->_error_if_fail(rqst != NULL) );
67
68 if(nameMatches(rqst->pName, NS_W_KEY, "instrText"))
69 {
70 rqst->handled = true;
71 } else if(nameMatches(rqst->pName, NS_W_KEY, "fldChar")) {
72 const gchar* fldCharType = attrMatches(NS_W_KEY, "fldCharType", rqst->ppAtts);
73 if(!fldCharType)
74 {
75 UT_DEBUGMSG(("SERHAT: fldChar tag without fldCharType attribute\n"));
76 return;
77 }
78 if(!strcmp(fldCharType, "begin"))
79 {
80 m_eqField = false;
81 m_pageNumberField = false;
82 m_fldChar = true;
83 }
84 else if(!strcmp(fldCharType, "end"))
85 {
86 m_eqField = false;
87 m_pageNumberField = false;
88 m_fldChar = false;
89 }
90 } else if(nameMatches(rqst->pName, NS_W_KEY, "p")) {
91 //New paragraph...
92 OXML_SharedElement elem(new OXML_Element_Paragraph(""));
93 rqst->stck->push(elem);
94
95 rqst->handled = true;
96 } else if (nameMatches(rqst->pName, NS_W_KEY, "r")) {
97 //New text run...
98 OXML_SharedElement elem(new OXML_Element_Run(""));
99 rqst->stck->push(elem);
100
101 rqst->handled = true;
102
103 } else if (nameMatches(rqst->pName, NS_W_KEY, "t")) {
104 if(m_fldChar && m_pageNumberField) // page number is already set with field element correctly.
105 {
106 rqst->handled = true;
107 return;
108 }
109 //New text...
110 OXML_SharedElement elem(new OXML_Element_Text("", 0));
111 rqst->stck->push(elem);
112 rqst->handled = true;
113
114 } else if (nameMatches(rqst->pName, NS_W_KEY, "sectPr")) {
115 //Verify the context...
116 std::string contextTag = rqst->context->back();
117 if (contextMatches(contextTag, NS_W_KEY, "pPr") ||
118 contextMatches(contextTag, NS_W_KEY, "body")) {
119 OXML_SharedElement dummy(new OXML_Element_Paragraph(""));
120 rqst->stck->push(dummy);
121
122 m_pendingSectBreak = true;
123 rqst->handled = true;
124 }
125
126 /********************************
127 **** PARAGRAPH FORMATTING ****
128 ********************************/
129 } else if(nameMatches(rqst->pName, NS_W_KEY, "shd")) {
130 std::string contextTag = rqst->context->back();
131
132 if(!contextMatches(contextTag, NS_W_KEY, "pPr") &&
133 !contextMatches(contextTag, NS_W_KEY, "rPr"))
134 return;
135
136 const gchar* fill = attrMatches(NS_W_KEY, "fill", rqst->ppAtts);
137
138 OXML_SharedElement elem = rqst->stck->top();
139
140 if(fill && strcmp(fill, "auto"))
141 {
142 UT_Error err = UT_OK;
143 err = elem->setProperty("bgcolor", fill);
144 if(err != UT_OK) {
145 UT_DEBUGMSG(("FRT:OpenXML importer can't set background-color:%s\n", fill));
146 }
147 }
148 rqst->handled = true;
149
150 } else if ( nameMatches(rqst->pName, NS_W_KEY, "pageBreakBefore")){
151 OXML_ElementTag tag = PG_BREAK;
152 OXML_SharedElement br ( new OXML_Element("", tag, SPAN) );
153 rqst->stck->push(br);
154 rqst->handled = true;
155
156 } else if ( nameMatches(rqst->pName, NS_W_KEY, "tab")){
157 //verify the context
158 std::string contextTag = rqst->context->back();
159
160 if (contextMatches(contextTag, NS_W_KEY, "r")) {
161 //This is an actual tab to be inserted
162 OXML_SharedElement tab ( new OXML_Element_Text("\t", 2) );
163 rqst->stck->push(tab);
164 rqst->handled = true;
165 }
166 else if(contextMatches(contextTag, NS_W_KEY, "tabs")){
167 OXML_SharedElement para = rqst->stck->top();
168 const gchar* val = attrMatches(NS_W_KEY, "val", rqst->ppAtts);
169 const gchar* pos = attrMatches(NS_W_KEY, "pos", rqst->ppAtts);
170 const gchar* leadCh = attrMatches(NS_W_KEY, "leader", rqst->ppAtts);
171 if(!val || !*val || !pos || !*pos)
172 return;
173
174 std::string value(val);
175 std::string position(_TwipsToInches(pos));
176 position += "in";
177 std::string leader("0"); //no leader by default
178
179 std::string tabstops("");
180 const gchar* tabProp = NULL;
181 para->getProperty("tabstops", tabProp);
182 if(tabProp)
183 {
184 tabstops = tabProp;
185 tabstops += ",";
186 }
187
188 tabstops += position;
189 tabstops += "/";
190
191 if(!value.compare("left"))
192 tabstops += "L";
193 else if(!value.compare("right"))
194 tabstops += "R";
195 else if(!value.compare("center"))
196 tabstops += "C";
197 else if(!value.compare("bar"))
198 tabstops += "B";
199 else if(!value.compare("decimal"))
200 tabstops += "D";
201
202 if(leadCh)
203 {
204 std::string leaderChar(leadCh);
205 if(!leaderChar.compare("dot"))
206 leader = "1";
207 else if(!leaderChar.compare("heavy"))
208 leader = "3";
209 else if(!leaderChar.compare("hyphen"))
210 leader = "2";
211 else if(!leaderChar.compare("middleDot"))
212 leader = "1";
213 else if(!leaderChar.compare("underscore"))
214 leader = "3";
215 }
216 tabstops += leader;
217
218 para->setProperty("tabstops", tabstops);
219 }
220 rqst->handled = true;
221 } else if ( nameMatches(rqst->pName, NS_W_KEY, "ilvl")){
222 //verify the context
223 std::string contextTag = rqst->context->back();
224 if(contextMatches(contextTag, NS_W_KEY, "numPr")){
225 OXML_SharedElement para = rqst->stck->top();
226 const gchar* val = attrMatches(NS_W_KEY, "val", rqst->ppAtts);
227 if(!val || !*val)
228 return;
229 std::string level(val);
230 para->setAttribute("level", level.c_str());
231 }
232 rqst->handled = true;
233 } else if ( nameMatches(rqst->pName, NS_W_KEY, "numId")){
234 //verify the context
235 std::string contextTag = rqst->context->back();
236 if(contextMatches(contextTag, NS_W_KEY, "numPr")){
237 OXML_SharedElement para = rqst->stck->top();
238 const gchar* val = attrMatches(NS_W_KEY, "val", rqst->ppAtts);
239 if(!val || !*val)
240 return;
241 std::string numId(val);
242
243 OXML_Document* doc = OXML_Document::getInstance();
244 std::string absNumId = doc->getMappedNumberingId(numId);
245 if(!absNumId.empty())
246 para->setAttribute("listid", absNumId.c_str());
247 }
248 rqst->handled = true;
249 } else if ( nameMatches(rqst->pName, NS_W_KEY, "jc") ||
250 nameMatches(rqst->pName, NS_W_KEY, "ind") ||
251 nameMatches(rqst->pName, NS_W_KEY, "spacing") ||
252 nameMatches(rqst->pName, NS_W_KEY, "pStyle")) {
253 //Verify the context...
254 std::string contextTag = rqst->context->at(rqst->context->size() - 2);
255 if (contextMatches(contextTag, NS_W_KEY, "p") ||
256 contextMatches(contextTag, NS_W_KEY, "pPrDefault") ||
257 contextMatches(contextTag, NS_W_KEY, "lvl") ||
258 contextMatches(contextTag, NS_W_KEY, "style")) {
259
260 OXML_SharedElement para = rqst->stck->top();
261
262 if (nameMatches(rqst->pName, NS_W_KEY, "jc")) {
263 const gchar * val = attrMatches(NS_W_KEY, "val", rqst->ppAtts);
264
265 if (!val || !*val)
266 return;
267
268 if (!strcmp(val, "left")) {
269 UT_return_if_fail( _error_if_fail( UT_OK == para->setProperty("text-align", "left") ));
270 } else if (!strcmp(val, "center")) {
271 UT_return_if_fail( _error_if_fail( UT_OK == para->setProperty("text-align", "center") ));
272 } else if (!strcmp(val, "right")) {
273 UT_return_if_fail( _error_if_fail( UT_OK == para->setProperty("text-align", "right") ));
274 } else if (!strcmp(val, "numTab")) {
275 //Deprecated; align left
276 UT_return_if_fail( _error_if_fail( UT_OK == para->setProperty("text-align", "left") ));
277 } else {
278 //We justify for the values of "both", "distribute", "thaiDistribute", and the kashida variants
279 UT_return_if_fail( _error_if_fail( UT_OK == para->setProperty("text-align", "justify") ));
280 }
281
282 } else if (nameMatches(rqst->pName, NS_W_KEY, "ind")) {
283 const gchar * left = attrMatches(NS_W_KEY, "left", rqst->ppAtts);
284 const gchar * right = attrMatches(NS_W_KEY, "right", rqst->ppAtts);
285 const gchar * fLine = attrMatches(NS_W_KEY, "firstLine", rqst->ppAtts);
286 const gchar * hanging = attrMatches(NS_W_KEY, "hanging", rqst->ppAtts);
287
288 std::string final = "";
289 if (left != NULL) {
290 final = _TwipsToPoints(left); //convert to points
291 final += "pt";
292 UT_return_if_fail( _error_if_fail( UT_OK == para->setProperty("margin-left", final.c_str()) ));
293 }
294 if (right != NULL) {
295 final = _TwipsToPoints(right); //convert to points
296 final += "pt";
297 UT_return_if_fail( _error_if_fail( UT_OK == para->setProperty("margin-right", final.c_str()) ));
298 }
299 if (fLine != NULL) {
300 final = _TwipsToPoints(fLine); //convert to points
301 final += "pt";
302 UT_return_if_fail( _error_if_fail( UT_OK == para->setProperty("text-indent", final.c_str()) ));
303 } else if (hanging != NULL) {
304 final = _TwipsToPoints(hanging); //convert to points
305 //This is hanging, invert the sign
306 if (final[0] == '-')
307 final.erase(0,1);
308 else
309 final.insert(0,1,'-');
310 final += "pt";
311 UT_return_if_fail( _error_if_fail( UT_OK == para->setProperty("text-indent", final.c_str()) ));
312 }
313
314 } else if (nameMatches(rqst->pName, NS_W_KEY, "spacing")) {
315 const gchar * before = attrMatches(NS_W_KEY, "before", rqst->ppAtts);
316 const gchar * after = attrMatches(NS_W_KEY, "after", rqst->ppAtts);
317 const gchar * lineRule = attrMatches(NS_W_KEY, "lineRule", rqst->ppAtts);
318
319 std::string final = "";
320 if (before != NULL) {
321 final = _TwipsToPoints(before); //convert to points
322 final += "pt";
323 UT_return_if_fail( _error_if_fail( UT_OK == para->setProperty("margin-top", final.c_str()) ));
324 }
325 if (after != NULL) {
326 final = _TwipsToPoints(after); //convert to points
327 final += "pt";
328 UT_return_if_fail( _error_if_fail( UT_OK == para->setProperty("margin-bottom", final.c_str()) ));
329 }
330 if (lineRule != NULL && !strcmp(lineRule, "auto")) {
331 //For now, we only handle "auto".
332 const gchar * line = attrMatches(NS_W_KEY, "line", rqst->ppAtts);
333 UT_return_if_fail( _error_if_fail(line != NULL) );
334 double ln_spc = UT_convertDimensionless(line) / 240;
335 final = UT_convertToDimensionlessString(ln_spc);
336 UT_return_if_fail( _error_if_fail( UT_OK == para->setProperty("line-height", final.c_str()) ));
337 }
338 } else if (nameMatches(rqst->pName, NS_W_KEY, "pStyle")) {
339 const gchar * val = attrMatches(NS_W_KEY, "val", rqst->ppAtts);
340 UT_return_if_fail( _error_if_fail(val != NULL) );
341 if (!strcmp(val, "Normal")) val = "_Normal"; //Cannot interfere with document defaults
342 OXML_Document * doc = OXML_Document::getInstance();
343 UT_return_if_fail( _error_if_fail(doc != NULL) );
344 OXML_SharedStyle ref = doc->getStyleById(val);
345 if (ref.get() != NULL && ref->getName().compare("")) {
346 UT_return_if_fail( _error_if_fail( UT_OK == para->setAttribute(PT_STYLE_ATTRIBUTE_NAME, ref->getName().c_str()) ));
347 }
348
349 }
350
351 rqst->handled = true;
352 }
353
354 /******* END OF PARAGRAPH FORMATTING ********/
355
356 /**************************
357 **** RUN FORMATTING ****
358 **************************/
359 } else if ( nameMatches(rqst->pName, NS_W_KEY, "b") ||
360 nameMatches(rqst->pName, NS_W_KEY, "i") ||
361 nameMatches(rqst->pName, NS_W_KEY, "u") ||
362 nameMatches(rqst->pName, NS_W_KEY, "color") ||
363 nameMatches(rqst->pName, NS_W_KEY, "vertAlign") || // for subscript and superscript
364 nameMatches(rqst->pName, NS_W_KEY, "highlight") ||
365 nameMatches(rqst->pName, NS_W_KEY, "strike") ||
366 nameMatches(rqst->pName, NS_W_KEY, "dstrike") ||
367 nameMatches(rqst->pName, NS_W_KEY, "rFonts") ||
368 nameMatches(rqst->pName, NS_W_KEY, "lang") ||
369 nameMatches(rqst->pName, NS_W_KEY, "noProof") ||
370 nameMatches(rqst->pName, NS_W_KEY, "vanish") ||
371 nameMatches(rqst->pName, NS_W_KEY, "sz") ) {
372 //Verify the context...
373 std::string contextTag = rqst->context->at(rqst->context->size() - 2);
374 if (contextMatches(contextTag, NS_W_KEY, "r") ||
375 contextMatches(contextTag, NS_W_KEY, "rPrDefault") ||
376 contextMatches(contextTag, NS_W_KEY, "style")) {
377 OXML_SharedElement run = rqst->stck->top();
378
379 if (nameMatches(rqst->pName, NS_W_KEY, "b")) {
380 const gchar * isOn = attrMatches(NS_W_KEY, "val", rqst->ppAtts);
381 if (isOn == NULL || !strcmp(isOn, "on") || !strcmp(isOn, "1") || !strcmp(isOn, "true") ) {
382 UT_return_if_fail( this->_error_if_fail( UT_OK == run->setProperty("font-weight", "bold") ));
383 } else {
384 UT_return_if_fail( this->_error_if_fail( UT_OK == run->setProperty("font-weight", "normal") ));
385 }
386
387 } else if (nameMatches(rqst->pName, NS_W_KEY, "i")) {
388 const gchar * isOn = attrMatches(NS_W_KEY, "val", rqst->ppAtts);
389 if (isOn == NULL || !strcmp(isOn, "on") || !strcmp(isOn, "1") || !strcmp(isOn, "true") ) {
390 UT_return_if_fail( this->_error_if_fail( UT_OK == run->setProperty("font-style", "italic") ));
391 } else {
392 UT_return_if_fail( this->_error_if_fail( UT_OK == run->setProperty("font-style", "normal") ));
393 }
394
395 } else if (nameMatches(rqst->pName, NS_W_KEY, "vertAlign")) {
396 const gchar * val = attrMatches(NS_W_KEY, "val", rqst->ppAtts);
397 if (val == NULL || !*val || !strcmp(val, "baseline")) {
398 UT_return_if_fail( this->_error_if_fail( UT_OK == run->setProperty("text-position", "normal") ));
399 } else if (!strcmp(val, "superscript")) {
400 UT_return_if_fail( this->_error_if_fail( UT_OK == run->setProperty("text-position", "superscript") ));
401 } else if (!strcmp(val, "subscript")) {
402 UT_return_if_fail( this->_error_if_fail( UT_OK == run->setProperty("text-position", "subscript") ));
403 }
404
405 } else if (nameMatches(rqst->pName, NS_W_KEY, "u")) {
406 const gchar * newVal = attrMatches(NS_W_KEY, "val", rqst->ppAtts);
407 if(!newVal)
408 {
409 newVal = "single";
410 }
411 std::string final_val = "";
412 const gchar * previousVal = NULL;
413 if (UT_OK == run->getProperty("text-decoration", previousVal)) {
414 final_val = previousVal;
415 }
416 if ( !strcmp(newVal, "none") ) {
417 final_val += " ";
418 final_val += "none";
419 } else { //if NOT "none", we add underline (no matter the underline style, we only support single line)
420 final_val += " ";
421 final_val += "underline";
422 }
423 UT_return_if_fail( this->_error_if_fail( UT_OK == run->setProperty("text-decoration", final_val.c_str()) ));
424
425 } else if (nameMatches(rqst->pName, NS_W_KEY, "color")) {
426 const gchar * val = attrMatches(NS_W_KEY, "val", rqst->ppAtts);
427 if (val != NULL) {
428 if (!strcmp(val, "auto")) val = "#000000";
429 UT_return_if_fail( this->_error_if_fail( UT_OK == run->setProperty("color", val)));
430 } else {
431 val = attrMatches(NS_W_KEY, "themeColor", rqst->ppAtts);
432 UT_return_if_fail( this->_error_if_fail(val != NULL) );
433 std::string color = "#000000"; //default color in case of illegal themeColor value.
434 OXML_Document * doc = OXML_Document::getInstance();
435 UT_return_if_fail( this->_error_if_fail(doc != NULL) );
436 OXML_SharedTheme theme = doc->getTheme();
437 if (!strcmp(val,"accent1")) {
438 color = theme->getColor(ACCENT1);
439 } else if (!strcmp(val,"accent2")) {
440 color = theme->getColor(ACCENT2);
441 } else if (!strcmp(val,"accent3")) {
442 color = theme->getColor(ACCENT3);
443 } else if (!strcmp(val,"accent4")) {
444 color = theme->getColor(ACCENT4);
445 } else if (!strcmp(val,"accent5")) {
446 color = theme->getColor(ACCENT5);
447 } else if (!strcmp(val,"accent6")) {
448 color = theme->getColor(ACCENT6);
449 } else if (!strcmp(val,"dark1")) {
450 color = theme->getColor(DARK1);
451 } else if (!strcmp(val,"dark2")) {
452 color = theme->getColor(DARK2);
453 } else if (!strcmp(val,"light1")) {
454 color = theme->getColor(LIGHT1);
455 } else if (!strcmp(val,"light2")) {
456 color = theme->getColor(LIGHT2);
457 } else if (!strcmp(val,"hlink")) {
458 color = theme->getColor(HYPERLINK);
459 } else if (!strcmp(val,"folHlink")) {
460 color = theme->getColor(FOLLOWED_HYPERLINK);
461 } else if (!strcmp(val,"none")) {
462 color = "#000000";
463 }
464 UT_return_if_fail( this->_error_if_fail( UT_OK == run->setProperty("color", color.c_str())));
465 }
466
467 } else if (nameMatches(rqst->pName, NS_W_KEY, "highlight")) {
468 const gchar * val = attrMatches(NS_W_KEY, "val", rqst->ppAtts);
469 UT_return_if_fail( this->_error_if_fail(val != NULL) );
470 if (!strcmp(val, "darkYellow")) val = "olive"; //the only value not supported by CSS (equivalent to Olive)
471 else if (!strcmp(val, "none")) val = "black"; //bypass inherited color value when "none"
472 std::string hex = "";
473 for (UT_uint32 i = 0; i <= strlen(val); i++) {
474 hex += tolower(val[i]);
475 }
476 UT_HashColor conv;
477 val = conv.setColor(hex.c_str());
478 UT_return_if_fail( this->_error_if_fail( NULL != val ) );
479 UT_return_if_fail( this->_error_if_fail( UT_OK == run->setProperty("bgcolor", val)));
480
481 } else if (nameMatches(rqst->pName, NS_W_KEY, "strike") ||
482 nameMatches(rqst->pName, NS_W_KEY, "dstrike")) {
483 const gchar * isOn = attrMatches(NS_W_KEY, "val", rqst->ppAtts);
484 std::string final_val = "";
485 const gchar * previousVal = NULL;
486 if (UT_OK == run->getProperty("text-decoration", previousVal)) {
487 final_val = previousVal;
488 }
489 if ( isOn == NULL || !strcmp(isOn, "on") || !strcmp(isOn, "1") || !strcmp(isOn, "true") ) {
490 final_val += " ";
491 final_val += "line-through";
492 } else {
493 final_val += " ";
494 final_val += "none";
495 }
496 UT_return_if_fail( this->_error_if_fail( UT_OK == run->setProperty("text-decoration", final_val.c_str()) ));
497
498 } else if (nameMatches(rqst->pName, NS_W_KEY, "rFonts")) {
499 OXML_Document * doc = OXML_Document::getInstance();
500 UT_return_if_fail( this->_error_if_fail(doc != NULL) );
501 OXML_SharedFontManager fmgr = doc->getFontManager();
502 UT_return_if_fail( this->_error_if_fail(fmgr.get() != NULL) );
503
504 std::string fontName;
505 OXML_FontLevel level = UNKNOWN_LEVEL;
506 OXML_CharRange range = UNKNOWN_RANGE;
507
508 const gchar * ascii = NULL;
509 const gchar * eastAsia = NULL;
510 const gchar * bidi = NULL;
511 const gchar * hAnsi = NULL;
512 if (NULL != (ascii = attrMatches(NS_W_KEY, "asciiTheme", rqst->ppAtts))) {
513 this->getFontLevelRange(ascii, level, range);
514 fontName = fmgr->getValidFont(level, range); //Retrieve valid font name from Theme
515 } else if (NULL != (ascii = attrMatches(NS_W_KEY, "ascii", rqst->ppAtts))) {
516 fontName = fmgr->getValidFont(ascii); //Make sure the name is valid
517 } else if (NULL != (eastAsia = attrMatches(NS_W_KEY, "eastAsiaTheme", rqst->ppAtts))) {
518 this->getFontLevelRange(eastAsia, level, range);
519 fontName = fmgr->getValidFont(level, range); //Retrieve valid font name from Theme
520 } else if (NULL != (eastAsia = attrMatches(NS_W_KEY, "eastAsia", rqst->ppAtts))) {
521 fontName = fmgr->getValidFont(eastAsia); //Make sure the name is valid
522 } else if (NULL != (bidi = attrMatches(NS_W_KEY, "csTheme", rqst->ppAtts))) {
523 this->getFontLevelRange(bidi, level, range);
524 fontName = fmgr->getValidFont(level, range); //Retrieve valid font name from Theme
525 } else if (NULL != (bidi = attrMatches(NS_W_KEY, "cs", rqst->ppAtts))) {
526 fontName = fmgr->getValidFont(bidi); //Make sure the name is valid
527 } else if (NULL != (hAnsi = attrMatches(NS_W_KEY, "hAnsiTheme", rqst->ppAtts))) {
528 this->getFontLevelRange(hAnsi, level, range);
529 fontName = fmgr->getValidFont(level, range); //Retrieve valid font name from Theme
530 } else if (NULL != (hAnsi = attrMatches(NS_W_KEY, "hAnsi", rqst->ppAtts))) {
531 fontName = fmgr->getValidFont(hAnsi); //Make sure the name is valid
532 } else {
533 fontName = fmgr->getDefaultFont();
534 }
535 UT_return_if_fail( _error_if_fail( UT_OK == run->setProperty("font-family", fontName.c_str()) ));
536
537 } else if (nameMatches(rqst->pName, NS_W_KEY, "lang")) {
538 const gchar * val = attrMatches(NS_W_KEY, "val", rqst->ppAtts);
539 const gchar * eastAsia = attrMatches(NS_W_KEY, "eastAsia", rqst->ppAtts);
540 const gchar * bidi = attrMatches(NS_W_KEY, "bidi", rqst->ppAtts);
541 const gchar * previousVal = NULL;
542 if (UT_OK == run->getProperty("lang", previousVal)) {
543 if ( 0 != strcmp(previousVal, "-none-"))
544 val = previousVal;
545 }
546 if ( val != NULL)
547 UT_return_if_fail( this->_error_if_fail( UT_OK == run->setProperty("lang", val) ));
548 if ( eastAsia != NULL)
549 UT_return_if_fail( this->_error_if_fail( UT_OK == run->setProperty("lang", eastAsia) ));
550 if ( bidi != NULL)
551 UT_return_if_fail( this->_error_if_fail( UT_OK == run->setProperty("lang", bidi) ));
552
553 } else if (nameMatches(rqst->pName, NS_W_KEY, "noProof")) {
554 //noProof has priority over lang, so no need to check for previous values
555 const gchar * isOn = attrMatches(NS_W_KEY, "val", rqst->ppAtts);
556 if (isOn == NULL || !strcmp(isOn, "on") || !strcmp(isOn, "1") || !strcmp(isOn, "true") )
557 UT_return_if_fail( this->_error_if_fail( UT_OK == run->setProperty("lang", "-none-") ));
558
559 } else if (nameMatches(rqst->pName, NS_W_KEY, "vanish")) {
560 const gchar * isOn = attrMatches(NS_W_KEY, "val", rqst->ppAtts);
561 if (isOn == NULL || !strcmp(isOn, "on") || !strcmp(isOn, "1") || !strcmp(isOn, "true") ) {
562 UT_return_if_fail( this->_error_if_fail( UT_OK == run->setProperty("display", "none") ));
563 } else {
564 UT_return_if_fail( this->_error_if_fail( UT_OK == run->setProperty("display", "inline") ));
565 }
566
567 } else if (nameMatches(rqst->pName, NS_W_KEY, "sz")) {
568 const gchar * szStr = attrMatches(NS_W_KEY, "val", rqst->ppAtts);
569 UT_return_if_fail( this->_error_if_fail(szStr != NULL) );
570 double sz = UT_convertDimensionless(szStr) / 2;
571 UT_return_if_fail( this->_error_if_fail(sz > 0) );
572 std::string pt_value = UT_convertToDimensionlessString(sz);
573 pt_value += "pt";
574 UT_return_if_fail( this->_error_if_fail( UT_OK == run->setProperty("font-size", pt_value.c_str()) ));
575 }
576 rqst->handled = true;
577 }
578
579 /******* END OF RUN FORMATTING ********/
580
581 /******************************
582 **** SECTION FORMATTING ****
583 ******************************/
584
585 } else if ( nameMatches(rqst->pName, NS_W_KEY, "type") ||
586 nameMatches(rqst->pName, NS_W_KEY, "footerReference") ||
587 nameMatches(rqst->pName, NS_W_KEY, "headerReference") ||
588 nameMatches(rqst->pName, NS_W_KEY, "cols")) {
589 //Verify the context...
590 std::string contextTag = rqst->context->back();
591 if (contextMatches(contextTag, NS_W_KEY, "sectPr")) {
592 if (nameMatches(rqst->pName, NS_W_KEY, "type")) {
593 const gchar * val = attrMatches(NS_W_KEY, "val", rqst->ppAtts);
594 UT_return_if_fail( this->_error_if_fail(val != NULL) );
595
596 UT_ASSERT(m_pendingSectBreak == true);
597 if (!strcmp(val, "continuous")) {
598 m_pendingSectBreakType = CONTINUOUS_BREAK;
599 } else if (!strcmp(val, "evenPage")) {
600 m_pendingSectBreakType = EVENPAGE_BREAK;
601 } else if (!strcmp(val, "oddPage")) {
602 m_pendingSectBreakType = ODDPAGE_BREAK;
603 } else { //nextPage and nextColumn
604 m_pendingSectBreakType = NEXTPAGE_BREAK;
605 }
606 rqst->handled = true;
607
608 } else if (nameMatches(rqst->pName, NS_W_KEY, "footerReference")) {
609 const gchar * id = attrMatches(NS_R_KEY, "id", rqst->ppAtts);
610 UT_return_if_fail( this->_error_if_fail(id != NULL) );
611 OXML_SharedSection last = rqst->sect_stck->top();
612
613 OXMLi_PackageManager * mgr = OXMLi_PackageManager::getInstance();
614 UT_return_if_fail( _error_if_fail( UT_OK == mgr->parseDocumentHdrFtr(id) ) );
615
616 OXML_Document * doc = OXML_Document::getInstance();
617 UT_return_if_fail(_error_if_fail(doc != NULL));
618 const gchar * type = attrMatches(NS_W_KEY, "type", rqst->ppAtts);
619 UT_return_if_fail( this->_error_if_fail(type != NULL) );
620
621 if (!strcmp(type, "default")) {
622 last->setFooterId(id, DEFAULT_HDRFTR);
623 type = "footer";
624 } else if (!strcmp(type, "even")) {
625 last->setFooterId(id, EVENPAGE_HDRFTR);
626 type = "footer-even";
627 } else {
628 last->setFooterId(id, FIRSTPAGE_HDRFTR);
629 type = "footer-first";
630 }
631
632 OXML_SharedSection ftr = doc->getFooter(id);
633 UT_return_if_fail(_error_if_fail( UT_OK == ftr->setAttribute("type", type) ));
634
635 } else if (nameMatches(rqst->pName, NS_W_KEY, "headerReference")) {
636 const gchar * id = attrMatches(NS_R_KEY, "id", rqst->ppAtts);
637 UT_return_if_fail( this->_error_if_fail(id != NULL) );
638 OXML_SharedSection last = rqst->sect_stck->top();
639
640 OXMLi_PackageManager * mgr = OXMLi_PackageManager::getInstance();
641 UT_return_if_fail( _error_if_fail( UT_OK == mgr->parseDocumentHdrFtr(id) ) );
642
643 OXML_Document * doc = OXML_Document::getInstance();
644 UT_return_if_fail(_error_if_fail(doc != NULL));
645 const gchar * type = attrMatches(NS_W_KEY, "type", rqst->ppAtts);
646 UT_return_if_fail( this->_error_if_fail(type != NULL) );
647
648 if (!strcmp(type, "default")) {
649 last->setHeaderId(id, DEFAULT_HDRFTR);
650 type = "header";
651 } else if (!strcmp(type, "even")) {
652 last->setHeaderId(id, EVENPAGE_HDRFTR);
653 type = "header-even";
654 } else {
655 last->setHeaderId(id, FIRSTPAGE_HDRFTR);
656 type = "header-first";
657 }
658
659 OXML_SharedSection hdr = doc->getHeader(id);
660 UT_return_if_fail(_error_if_fail( UT_OK == hdr->setAttribute("type", type) ));
661 }
662 else if (nameMatches(rqst->pName, NS_W_KEY, "cols")) {
663 const gchar * num = attrMatches(NS_W_KEY, "num", rqst->ppAtts);
664 const gchar * sep = attrMatches(NS_W_KEY, "sep", rqst->ppAtts);
665
666 if(!num || atoi(num)<1)
667 num = "1";
668
669 if(!sep)
670 sep = "off";
671
672 OXML_SharedSection last = rqst->sect_stck->top();
673 last->setProperty("columns", num);
674 last->setProperty("column-line", sep);
675 }
676 }
677
678 } else if (nameMatches(rqst->pName, NS_W_KEY, "footnoteReference")) {
679 const gchar * id = attrMatches(NS_W_KEY, "id", rqst->ppAtts);
680 if(id)
681 {
682 OXML_SharedElement footnote(new OXML_Element_Field(id, fd_Field::FD_Footnote_Ref, ""));
683 rqst->stck->push(footnote);
684 }
685 rqst->handled = true;
686
687 } else if (nameMatches(rqst->pName, NS_W_KEY, "endnoteReference")) {
688 const gchar * id = attrMatches(NS_W_KEY, "id", rqst->ppAtts);
689 if(id)
690 {
691 OXML_SharedElement endnote(new OXML_Element_Field(id, fd_Field::FD_Endnote_Ref, ""));
692 rqst->stck->push(endnote);
693 }
694 rqst->handled = true;
695
696 } else if (nameMatches(rqst->pName, NS_W_KEY, "hyperlink")) {
697 const gchar * id = attrMatches(NS_R_KEY, "id", rqst->ppAtts);
698 const gchar * anchor = attrMatches(NS_W_KEY, "anchor", rqst->ppAtts);
699 if(id)
700 {
701 OXMLi_PackageManager * mgr = OXMLi_PackageManager::getInstance();
702 std::string target = mgr->getPartName(id);
703 OXML_Element_Hyperlink* hyperlink = new OXML_Element_Hyperlink("");
704 hyperlink->setHyperlinkTarget(target);
705 OXML_SharedElement elem(hyperlink);
706 rqst->stck->push(elem);
707 }
708 else if(anchor)
709 {
710 std::string bookmarkAnchor("#");
711 bookmarkAnchor += anchor;
712 OXML_Element_Hyperlink* hyperlink = new OXML_Element_Hyperlink("");
713 hyperlink->setHyperlinkTarget(bookmarkAnchor);
714 OXML_SharedElement elem(hyperlink);
715 rqst->stck->push(elem);
716 }
717 rqst->handled = true;
718
719 } else if (nameMatches(rqst->pName, NS_W_KEY, "bookmarkStart")) {
720 const gchar * id = attrMatches(NS_W_KEY, "id", rqst->ppAtts);
721 const gchar * name = attrMatches(NS_W_KEY, "name", rqst->ppAtts);
722 if(id && name)
723 {
724 std::string bookmarkId(id);
725 std::string bookmarkName(name);
726 OXML_Element_Bookmark* bookmark = new OXML_Element_Bookmark(bookmarkId);
727 bookmark->setType("start");
728 bookmark->setName(bookmarkName);
729 OXML_SharedElement elem(bookmark);
730 rqst->stck->push(elem);
731 OXML_Document* pDoc = OXML_Document::getInstance();
732 if(!pDoc->setBookmarkName(bookmarkId, bookmarkName))
733 return;
734 }
735 rqst->handled = true;
736
737 } else if (nameMatches(rqst->pName, NS_W_KEY, "bookmarkEnd")) {
738 const gchar * id = attrMatches(NS_W_KEY, "id", rqst->ppAtts);
739 if(id)
740 {
741 std::string bookmarkId(id);
742 OXML_Element_Bookmark* bookmark = new OXML_Element_Bookmark(bookmarkId);
743 bookmark->setType("end");
744 OXML_Document* pDoc = OXML_Document::getInstance();
745 bookmark->setName(pDoc->getBookmarkName(bookmarkId));
746 OXML_SharedElement elem(bookmark);
747 rqst->stck->push(elem);
748 }
749 rqst->handled = true;
750
751 /******* END OF SECTION FORMATTING ********/
752
753 } else if (nameMatches(rqst->pName, NS_W_KEY, "br")) {
754 const gchar * type = attrMatches(NS_W_KEY, "type", rqst->ppAtts);
755 // The optional attribute can be missing. In that case a default
756 // value is implied.
757 // UT_return_if_fail( this->_error_if_fail(type != NULL) );
758
759 OXML_ElementTag tag;
760 if (type && !strcmp(type, "column")) {
761 tag = CL_BREAK;
762 } else if (type && !strcmp(type, "page")) {
763 tag = PG_BREAK;
764 } else { //textWrapping
765 tag = LN_BREAK;
766 }
767 OXML_SharedElement br ( new OXML_Element("", tag, SPAN) );
768 rqst->stck->push(br);
769
770 rqst->handled = true;
771 }
772 }
773
endElement(OXMLi_EndElementRequest * rqst)774 void OXMLi_ListenerState_Common::endElement (OXMLi_EndElementRequest * rqst)
775 {
776 UT_return_if_fail( this->_error_if_fail(rqst != NULL) );
777
778 if (nameMatches(rqst->pName, NS_W_KEY, "p")) {
779 //Paragraph is done, appending it.
780 if (rqst->stck->size() == 1) { //Only the paragraph is on the stack, append to section
781 OXML_SharedElement elem = rqst->stck->top();
782 UT_return_if_fail( this->_error_if_fail(elem.get() != NULL) );
783 OXML_SharedSection sect = rqst->sect_stck->top();
784 UT_return_if_fail( this->_error_if_fail(sect.get() != NULL) );
785 UT_return_if_fail( this->_error_if_fail(UT_OK == sect->appendElement(elem) ) );
786 rqst->stck->pop();
787 } else { //Append to next element on the stack
788 UT_return_if_fail( this->_error_if_fail( UT_OK == _flushTopLevel(rqst->stck, rqst->sect_stck) ) );
789 }
790
791 //Perform the section break if any
792 if (m_pendingSectBreak) {
793 OXML_Document * doc = OXML_Document::getInstance();
794 UT_return_if_fail(_error_if_fail(doc != NULL));
795 OXML_SharedSection sect(new OXML_Section());
796 sect->setBreakType(m_pendingSectBreakType);
797 m_pendingSectBreakType = NEXTPAGE_BREAK;
798 rqst->sect_stck->push(sect);
799 m_pendingSectBreak = false;
800 }
801
802 rqst->handled = true;
803 } else if (nameMatches(rqst->pName, NS_W_KEY, "r")) {
804 //Run is done, appending it.
805 UT_return_if_fail( this->_error_if_fail( UT_OK == _flushTopLevel(rqst->stck, rqst->sect_stck) ) );
806
807 rqst->handled = true;
808 } else if (nameMatches(rqst->pName, NS_W_KEY, "t")) {
809 if(m_fldChar && m_pageNumberField) // page number is already set with field element correctly.
810 {
811 rqst->handled = true;
812 return;
813 }
814 //Text is done, appending it.
815 UT_return_if_fail( this->_error_if_fail( UT_OK == _flushTopLevel(rqst->stck, rqst->sect_stck) ) );
816 rqst->handled = true;
817 } else if(nameMatches(rqst->pName, NS_W_KEY, "instrText")) {
818 if(m_eqField || m_pageNumberField)
819 {
820 //instrText including equation or page number field is done, appending it.
821 UT_return_if_fail( this->_error_if_fail( UT_OK == _flushTopLevel(rqst->stck, rqst->sect_stck) ) );
822 }
823 rqst->handled = true;
824 } else if (nameMatches(rqst->pName, NS_W_KEY, "sectPr")) {
825 std::string contextTag = rqst->context->back();
826 if (contextMatches(contextTag, NS_W_KEY, "pPr") ||
827 contextMatches(contextTag, NS_W_KEY, "body")) {
828 OXML_SharedSection sect = rqst->sect_stck->top();
829 UT_return_if_fail(_error_if_fail(sect.get() != NULL));
830 OXML_SharedElement dummy = rqst->stck->top();
831 const gchar ** atts = dummy->getAttributes();
832 if (atts != NULL) {
833 UT_return_if_fail(_error_if_fail(UT_OK == sect->appendAttributes(atts)));
834 }
835 atts = dummy->getProperties();
836 if (atts != NULL) {
837 UT_return_if_fail(_error_if_fail(UT_OK == sect->appendProperties(atts)));
838 }
839 rqst->stck->pop();
840
841 rqst->handled = true;
842 }
843 } else if ( nameMatches(rqst->pName, NS_W_KEY, "jc") ||
844 nameMatches(rqst->pName, NS_W_KEY, "ind") ||
845 nameMatches(rqst->pName, NS_W_KEY, "spacing") ) {
846 rqst->handled = true;
847 } else if ( nameMatches(rqst->pName, NS_W_KEY, "b") ||
848 nameMatches(rqst->pName, NS_W_KEY, "i") ||
849 nameMatches(rqst->pName, NS_W_KEY, "u") ||
850 nameMatches(rqst->pName, NS_W_KEY, "color") ||
851 nameMatches(rqst->pName, NS_W_KEY, "vertAlign") ||
852 nameMatches(rqst->pName, NS_W_KEY, "highlight") ||
853 nameMatches(rqst->pName, NS_W_KEY, "strike") ||
854 nameMatches(rqst->pName, NS_W_KEY, "dstrike") ||
855 nameMatches(rqst->pName, NS_W_KEY, "rFonts") ||
856 nameMatches(rqst->pName, NS_W_KEY, "lang") ||
857 nameMatches(rqst->pName, NS_W_KEY, "noProof") ||
858 nameMatches(rqst->pName, NS_W_KEY, "vanish") ||
859 nameMatches(rqst->pName, NS_W_KEY, "fldChar") ||
860 nameMatches(rqst->pName, NS_W_KEY, "sz") ) {
861 rqst->handled = true;
862 } else if ( nameMatches(rqst->pName, NS_W_KEY, "type") ||
863 nameMatches(rqst->pName, NS_W_KEY, "footerReference") ||
864 nameMatches(rqst->pName, NS_W_KEY, "headerReference") ||
865 nameMatches(rqst->pName, NS_W_KEY, "cols")) {
866 std::string contextTag = rqst->context->back();
867 if (contextMatches(contextTag, NS_W_KEY, "sectPr")) {
868 rqst->handled = true;
869 }
870 } else if (nameMatches(rqst->pName, NS_W_KEY, "tab")) {
871 std::string contextTag = rqst->context->back();
872 if (contextMatches(contextTag, NS_W_KEY, "r")) {
873 UT_return_if_fail( this->_error_if_fail( UT_OK == _flushTopLevel(rqst->stck, rqst->sect_stck) ) );
874 rqst->handled = true;
875 }
876 else if(contextMatches(contextTag, NS_W_KEY, "tabs"))
877 rqst->handled = true;
878 } else if (nameMatches(rqst->pName, NS_W_KEY, "br")) {
879 UT_return_if_fail( this->_error_if_fail( UT_OK == _flushTopLevel(rqst->stck, rqst->sect_stck) ) );
880 rqst->handled = true;
881 } else if (nameMatches(rqst->pName, NS_W_KEY, "footnoteReference") ||
882 nameMatches(rqst->pName, NS_W_KEY, "endnoteReference")) {
883 UT_return_if_fail( this->_error_if_fail( UT_OK == _flushTopLevel(rqst->stck, rqst->sect_stck) ) );
884 rqst->handled = true;
885 } else if (nameMatches(rqst->pName, NS_W_KEY, "hyperlink")) {
886 UT_return_if_fail( this->_error_if_fail( UT_OK == _flushTopLevel(rqst->stck, rqst->sect_stck) ) );
887 rqst->handled = true;
888 } else if (nameMatches(rqst->pName, NS_W_KEY, "bookmarkStart") ||
889 nameMatches(rqst->pName, NS_W_KEY, "bookmarkEnd")) {
890 UT_return_if_fail( this->_error_if_fail( UT_OK == _flushTopLevel(rqst->stck, rqst->sect_stck) ) );
891 rqst->handled = true;
892 } else if (nameMatches(rqst->pName, NS_W_KEY, "pageBreakBefore")) {
893 UT_return_if_fail( this->_error_if_fail( UT_OK == _flushTopLevel(rqst->stck, rqst->sect_stck) ) );
894 rqst->handled = true;
895 } else if (nameMatches(rqst->pName, NS_W_KEY, "shd")) {
896 std::string contextTag = rqst->context->back();
897 rqst->handled = contextMatches(contextTag, NS_W_KEY, "pPr") || contextMatches(contextTag, NS_W_KEY, "rPr");
898 }
899 }
900
charData(OXMLi_CharDataRequest * rqst)901 void OXMLi_ListenerState_Common::charData (OXMLi_CharDataRequest * rqst)
902 {
903 if(!rqst)
904 {
905 UT_DEBUGMSG(("FRT: OpenXML importer invalid NULL request in OXMLi_ListenerState_Common.charData\n"));
906 return;
907 }
908
909 if(rqst->stck->empty())
910 return;
911
912 std::string contextTag = "";
913 if(!rqst->context->empty())
914 {
915 contextTag = rqst->context->back();
916 }
917 int instrText = contextMatches(contextTag, NS_W_KEY, "instrText");
918 if(instrText)
919 {
920 UT_ASSERT(rqst->buffer != NULL);
921 OXML_SharedElement run = rqst->stck->top();
922 OXML_SharedElement sharedElem(new OXML_Element_Text("", 0));
923 std::string overline = "\\to";
924 std::string underline = "\\bo";
925 std::string eq = "EQ";
926 std::string pageNumber = "PAGE \\* MERGEFORMAT";
927 std::string v(rqst->buffer);
928 std::string value = "";
929 size_t isOverline = v.find(overline);
930 size_t isUnderline = v.find(underline);
931 size_t isEQ = v.find(eq);
932 size_t isPageNumber = v.find(pageNumber);
933 size_t openingParenthesis;
934 size_t closingParenthesis;
935 UT_Error err;
936 if(isEQ != std::string::npos) // handle EQ fields
937 {
938 if(isOverline != std::string::npos && isUnderline == std::string::npos)
939 {
940 // if starts with "EQ \x \to", then overline property is used
941 err = run->setProperty("text-decoration", "overline");
942 if(err != UT_OK)
943 {
944 UT_DEBUGMSG(("SERHAT: Could not set overline property!\n"));
945 return;
946 }
947 }
948 else if(isUnderline != std::string::npos && isOverline == std::string::npos)
949 {
950 // if starts with "EQ \x \bo", then underline property is used
951 err = run->setProperty("text-decoration", "underline");
952 if(err != UT_OK)
953 {
954 UT_DEBUGMSG(("SERHAT: Could not set underline property!\n"));
955 return;
956 }
957 }
958 rqst->stck->push(sharedElem);
959 m_eqField = true;
960 m_pageNumberField = false;
961 openingParenthesis = v.find("(");
962 closingParenthesis = v.find(")");
963 value = v.substr(int(openingParenthesis)+1, int(closingParenthesis)-int(openingParenthesis)-1); // the string between parentheses is extracted
964 OXML_Element* elem = sharedElem.get();
965 OXML_Element_Text* textElement = static_cast<OXML_Element_Text*>(elem);
966 textElement->setText(value.c_str(), value.size());
967 }
968 else if(isPageNumber != std::string::npos) // handle page number fields
969 {
970 m_pageNumberField = true;
971 m_eqField = false;
972 OXML_SharedElement fieldElem(new OXML_Element_Field("", v, ""));
973 rqst->stck->push(fieldElem);
974 }
975 else
976 {
977 m_eqField = false;
978 m_pageNumberField = false;
979 }
980 }
981 else
982 {
983 OXML_SharedElement sharedElem = rqst->stck->top();
984 OXML_Element* elem = sharedElem.get();
985
986 if(!elem || (elem->getTag() != T_TAG))
987 return;
988
989 OXML_Element_Text* textElement = static_cast<OXML_Element_Text*>(elem);
990 textElement->setText(rqst->buffer, rqst->length);
991 }
992 }
993