]> git.saurik.com Git - wxWidgets.git/blob - src/richtext/richtextxml.cpp
Fix [ 1574240 ] wx.RadioButton doesn't navigate correctly
[wxWidgets.git] / src / richtext / richtextxml.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/richtext/richtextxml.cpp
3 // Purpose: XML and HTML I/O for wxRichTextCtrl
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 2005-09-30
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #if wxUSE_RICHTEXT && wxUSE_XML
20
21 #include "wx/richtext/richtextxml.h"
22
23 #ifndef WX_PRECOMP
24 #include "wx/intl.h"
25 #include "wx/module.h"
26 #endif
27
28 #include "wx/filename.h"
29 #include "wx/clipbrd.h"
30 #include "wx/wfstream.h"
31 #include "wx/sstream.h"
32 #include "wx/txtstrm.h"
33 #include "wx/tokenzr.h"
34 #include "wx/xml/xml.h"
35
36 IMPLEMENT_DYNAMIC_CLASS(wxRichTextXMLHandler, wxRichTextFileHandler)
37
38 #if wxUSE_STREAMS
39 bool wxRichTextXMLHandler::DoLoadFile(wxRichTextBuffer *buffer, wxInputStream& stream)
40 {
41 if (!stream.IsOk())
42 return false;
43
44 buffer->Clear();
45
46 wxXmlDocument* xmlDoc = new wxXmlDocument;
47 bool success = true;
48
49 // This is the encoding to convert to (memory encoding rather than file encoding)
50 wxString encoding(wxT("UTF-8"));
51
52 #if !wxUSE_UNICODE && wxUSE_INTL
53 encoding = wxLocale::GetSystemEncodingName();
54 #endif
55
56 if (!xmlDoc->Load(stream, encoding))
57 {
58 success = false;
59 }
60 else
61 {
62 if (xmlDoc->GetRoot() && xmlDoc->GetRoot()->GetType() == wxXML_ELEMENT_NODE && xmlDoc->GetRoot()->GetName() == wxT("richtext"))
63 {
64 wxXmlNode* child = xmlDoc->GetRoot()->GetChildren();
65 while (child)
66 {
67 if (child->GetType() == wxXML_ELEMENT_NODE)
68 {
69 wxString name = child->GetName();
70 if (name == wxT("richtext-version"))
71 {
72 }
73 else
74 ImportXML(buffer, child);
75 }
76
77 child = child->GetNext();
78 }
79 }
80 else
81 {
82 success = false;
83 }
84 }
85
86 delete xmlDoc;
87
88 buffer->UpdateRanges();
89
90 return success;
91 }
92
93 /// Recursively import an object
94 bool wxRichTextXMLHandler::ImportXML(wxRichTextBuffer* buffer, wxXmlNode* node)
95 {
96 wxString name = node->GetName();
97
98 bool doneChildren = false;
99
100 if (name == wxT("paragraphlayout"))
101 {
102 wxString partial = node->GetPropVal(wxT("partialparagraph"), wxEmptyString);
103 if (partial == wxT("true"))
104 buffer->SetPartialParagraph(true);
105 }
106 else if (name == wxT("paragraph"))
107 {
108 wxRichTextParagraph* para = new wxRichTextParagraph(buffer);
109 buffer->AppendChild(para);
110
111 GetStyle(para->GetAttributes(), node, true);
112
113 wxXmlNode* child = node->GetChildren();
114 while (child)
115 {
116 wxString childName = child->GetName();
117 if (childName == wxT("text"))
118 {
119 wxString text;
120 wxXmlNode* textChild = child->GetChildren();
121 while (textChild)
122 {
123 if (textChild->GetType() == wxXML_TEXT_NODE ||
124 textChild->GetType() == wxXML_CDATA_SECTION_NODE)
125 {
126 wxString text2 = textChild->GetContent();
127
128 // Strip whitespace from end
129 if (!text2.empty() && text2[text2.length()-1] == wxT('\n'))
130 text2 = text2.Mid(0, text2.length()-1);
131
132 if (!text2.empty() && text2[0] == wxT('"'))
133 text2 = text2.Mid(1);
134 if (!text2.empty() && text2[text2.length()-1] == wxT('"'))
135 text2 = text2.Mid(0, text2.length() - 1);
136
137 text += text2;
138 }
139 textChild = textChild->GetNext();
140 }
141
142 wxRichTextPlainText* textObject = new wxRichTextPlainText(text, para);
143 GetStyle(textObject->GetAttributes(), child, false);
144
145 para->AppendChild(textObject);
146 }
147 else if (childName == wxT("symbol"))
148 {
149 // This is a symbol that XML can't read in the normal way
150 wxString text;
151 wxXmlNode* textChild = child->GetChildren();
152 while (textChild)
153 {
154 if (textChild->GetType() == wxXML_TEXT_NODE ||
155 textChild->GetType() == wxXML_CDATA_SECTION_NODE)
156 {
157 wxString text2 = textChild->GetContent();
158 text += text2;
159 }
160 textChild = textChild->GetNext();
161 }
162
163 wxString actualText;
164 actualText << (wxChar) wxAtoi(text);
165
166 wxRichTextPlainText* textObject = new wxRichTextPlainText(actualText, para);
167 GetStyle(textObject->GetAttributes(), child, false);
168
169 para->AppendChild(textObject);
170 }
171 else if (childName == wxT("image"))
172 {
173 int imageType = wxBITMAP_TYPE_PNG;
174 wxString value = node->GetPropVal(wxT("imagetype"), wxEmptyString);
175 if (!value.empty())
176 imageType = wxAtoi(value);
177
178 wxString data;
179
180 wxXmlNode* imageChild = child->GetChildren();
181 while (imageChild)
182 {
183 wxString childName = imageChild->GetName();
184 if (childName == wxT("data"))
185 {
186 wxXmlNode* dataChild = imageChild->GetChildren();
187 while (dataChild)
188 {
189 data = dataChild->GetContent();
190 // wxLogDebug(data);
191 dataChild = dataChild->GetNext();
192 }
193
194 }
195 imageChild = imageChild->GetNext();
196 }
197
198 if (!data.empty())
199 {
200 wxRichTextImage* imageObj = new wxRichTextImage(para);
201 para->AppendChild(imageObj);
202
203 wxStringInputStream strStream(data);
204
205 imageObj->GetImageBlock().ReadHex(strStream, data.length(), imageType);
206 }
207 }
208 child = child->GetNext();
209 }
210
211 doneChildren = true;
212 }
213
214 if (!doneChildren)
215 {
216 wxXmlNode* child = node->GetChildren();
217 while (child)
218 {
219 ImportXML(buffer, child);
220 child = child->GetNext();
221 }
222 }
223
224 return true;
225 }
226
227
228 //-----------------------------------------------------------------------------
229 // xml support routines
230 //-----------------------------------------------------------------------------
231
232 bool wxRichTextXMLHandler::HasParam(wxXmlNode* node, const wxString& param)
233 {
234 return (GetParamNode(node, param) != NULL);
235 }
236
237 wxXmlNode *wxRichTextXMLHandler::GetParamNode(wxXmlNode* node, const wxString& param)
238 {
239 wxCHECK_MSG(node, NULL, wxT("You can't access node data before it was initialized!"));
240
241 wxXmlNode *n = node->GetChildren();
242
243 while (n)
244 {
245 if (n->GetType() == wxXML_ELEMENT_NODE && n->GetName() == param)
246 return n;
247 n = n->GetNext();
248 }
249 return NULL;
250 }
251
252
253 wxString wxRichTextXMLHandler::GetNodeContent(wxXmlNode *node)
254 {
255 wxXmlNode *n = node;
256 if (n == NULL) return wxEmptyString;
257 n = n->GetChildren();
258
259 while (n)
260 {
261 if (n->GetType() == wxXML_TEXT_NODE ||
262 n->GetType() == wxXML_CDATA_SECTION_NODE)
263 return n->GetContent();
264 n = n->GetNext();
265 }
266 return wxEmptyString;
267 }
268
269
270 wxString wxRichTextXMLHandler::GetParamValue(wxXmlNode *node, const wxString& param)
271 {
272 if (param.empty())
273 return GetNodeContent(node);
274 else
275 return GetNodeContent(GetParamNode(node, param));
276 }
277
278 wxString wxRichTextXMLHandler::GetText(wxXmlNode *node, const wxString& param, bool WXUNUSED(translate))
279 {
280 wxXmlNode *parNode = GetParamNode(node, param);
281 if (!parNode)
282 parNode = node;
283 wxString str1(GetNodeContent(parNode));
284 return str1;
285 }
286
287 // For use with earlier versions of wxWidgets
288 #ifndef WXUNUSED_IN_UNICODE
289 #if wxUSE_UNICODE
290 #define WXUNUSED_IN_UNICODE(x) WXUNUSED(x)
291 #else
292 #define WXUNUSED_IN_UNICODE(x) x
293 #endif
294 #endif
295
296 // write string to output:
297 inline static void OutputString(wxOutputStream& stream, const wxString& str,
298 wxMBConv *WXUNUSED_IN_UNICODE(convMem) = NULL, wxMBConv *convFile = NULL)
299 {
300 if (str.empty()) return;
301 #if wxUSE_UNICODE
302 if (convFile)
303 {
304 const wxWX2MBbuf buf(str.mb_str(*convFile));
305 stream.Write((const char*)buf, strlen((const char*)buf));
306 }
307 else
308 {
309 const wxWX2MBbuf buf(str.mb_str(wxConvUTF8));
310 stream.Write((const char*)buf, strlen((const char*)buf));
311 }
312 #else
313 if ( convFile == NULL )
314 stream.Write(str.mb_str(), str.Len());
315 else
316 {
317 wxString str2(str.wc_str(*convMem), *convFile);
318 stream.Write(str2.mb_str(), str2.Len());
319 }
320 #endif
321 }
322
323 // Same as above, but create entities first.
324 // Translates '<' to "&lt;", '>' to "&gt;" and '&' to "&amp;"
325 static void OutputStringEnt(wxOutputStream& stream, const wxString& str,
326 wxMBConv *convMem = NULL, wxMBConv *convFile = NULL)
327 {
328 wxString buf;
329 size_t i, last, len;
330 wxChar c;
331
332 len = str.Len();
333 last = 0;
334 for (i = 0; i < len; i++)
335 {
336 c = str.GetChar(i);
337
338 // Original code excluded "&amp;" but we _do_ want to convert
339 // the ampersand beginning &amp; because otherwise when read in,
340 // the original "&amp;" becomes "&".
341
342 if (c == wxT('<') || c == wxT('>') || c == wxT('"') ||
343 (c == wxT('&') /* && (str.Mid(i+1, 4) != wxT("amp;")) */ ))
344 {
345 OutputString(stream, str.Mid(last, i - last), convMem, convFile);
346 switch (c)
347 {
348 case wxT('<'):
349 OutputString(stream, wxT("&lt;"), NULL, NULL);
350 break;
351 case wxT('>'):
352 OutputString(stream, wxT("&gt;"), NULL, NULL);
353 break;
354 case wxT('&'):
355 OutputString(stream, wxT("&amp;"), NULL, NULL);
356 break;
357 case wxT('"'):
358 OutputString(stream, wxT("&quot;"), NULL, NULL);
359 break;
360 default: break;
361 }
362 last = i + 1;
363 }
364 else if (wxUChar(c) > 127)
365 {
366 OutputString(stream, str.Mid(last, i - last), convMem, convFile);
367
368 wxString s(wxT("&#"));
369 s << (int) c;
370 s << wxT(";");
371 OutputString(stream, s, NULL, NULL);
372 last = i + 1;
373 }
374 }
375 OutputString(stream, str.Mid(last, i - last), convMem, convFile);
376 }
377
378 inline static void OutputIndentation(wxOutputStream& stream, int indent)
379 {
380 wxString str = wxT("\n");
381 for (int i = 0; i < indent; i++)
382 str << wxT(' ') << wxT(' ');
383 OutputString(stream, str, NULL, NULL);
384 }
385
386 // Convert a colour to a 6-digit hex string
387 static wxString ColourToHexString(const wxColour& col)
388 {
389 wxString hex;
390
391 hex += wxDecToHex(col.Red());
392 hex += wxDecToHex(col.Green());
393 hex += wxDecToHex(col.Blue());
394
395 return hex;
396 }
397
398 // Convert 6-digit hex string to a colour
399 static wxColour HexStringToColour(const wxString& hex)
400 {
401 unsigned char r = (unsigned char)wxHexToDec(hex.Mid(0, 2));
402 unsigned char g = (unsigned char)wxHexToDec(hex.Mid(2, 2));
403 unsigned char b = (unsigned char)wxHexToDec(hex.Mid(4, 2));
404
405 return wxColour(r, g, b);
406 }
407
408 bool wxRichTextXMLHandler::DoSaveFile(wxRichTextBuffer *buffer, wxOutputStream& stream)
409 {
410 if (!stream.IsOk())
411 return false;
412
413 wxString version(wxT("1.0") ) ;
414
415 bool deleteConvFile = false;
416 wxString fileEncoding;
417 wxMBConv* convFile = NULL;
418
419 #if wxUSE_UNICODE
420 fileEncoding = wxT("UTF-8");
421 convFile = & wxConvUTF8;
422 #else
423 fileEncoding = wxT("ISO-8859-1");
424 convFile = & wxConvISO8859_1;
425 #endif
426
427 // If SetEncoding has been called, change the output encoding.
428 if (!m_encoding.empty() && m_encoding.Lower() != fileEncoding.Lower())
429 {
430 if (m_encoding == wxT("<System>"))
431 {
432 fileEncoding = wxLocale::GetSystemEncodingName();
433 }
434 else
435 {
436 fileEncoding = m_encoding;
437 }
438
439 // GetSystemEncodingName may not have returned a name
440 if (fileEncoding.empty())
441 #if wxUSE_UNICODE
442 fileEncoding = wxT("UTF-8");
443 #else
444 fileEncoding = wxT("ISO-8859-1");
445 #endif
446 convFile = new wxCSConv(fileEncoding);
447 deleteConvFile = true;
448 }
449
450 #if !wxUSE_UNICODE
451 wxMBConv* convMem = wxConvCurrent;
452 #else
453 wxMBConv* convMem = NULL;
454 #endif
455
456 wxString s ;
457 s.Printf(wxT("<?xml version=\"%s\" encoding=\"%s\"?>\n"),
458 (const wxChar*) version, (const wxChar*) fileEncoding );
459 OutputString(stream, s, NULL, NULL);
460 OutputString(stream, wxT("<richtext version=\"1.0.0.0\" xmlns=\"http://www.wxwidgets.org\">") , NULL, NULL);
461
462 int level = 1;
463 bool success = ExportXML(stream, convMem, convFile, *buffer, level);
464
465 OutputString(stream, wxT("\n</richtext>") , NULL, NULL);
466 OutputString(stream, wxT("\n"), NULL, NULL);
467
468 if (deleteConvFile)
469 delete convFile;
470
471 return success;
472 }
473
474 /// Recursively export an object
475 bool wxRichTextXMLHandler::ExportXML(wxOutputStream& stream, wxMBConv* convMem, wxMBConv* convFile, wxRichTextObject& obj, int indent)
476 {
477 wxString objectName;
478 if (obj.IsKindOf(CLASSINFO(wxRichTextParagraphLayoutBox)))
479 objectName = wxT("paragraphlayout");
480 else if (obj.IsKindOf(CLASSINFO(wxRichTextParagraph)))
481 objectName = wxT("paragraph");
482 else if (obj.IsKindOf(CLASSINFO(wxRichTextPlainText)))
483 objectName = wxT("text");
484 else if (obj.IsKindOf(CLASSINFO(wxRichTextImage)))
485 objectName = wxT("image");
486 else
487 objectName = wxT("object");
488
489 bool terminateTag = true;
490
491 if (obj.IsKindOf(CLASSINFO(wxRichTextPlainText)))
492 {
493 wxRichTextPlainText& textObj = (wxRichTextPlainText&) obj;
494
495 wxString style = CreateStyle(obj.GetAttributes(), false);
496
497 int i;
498 int last = 0;
499 const wxString& text = textObj.GetText();
500 int len = (int) text.Length();
501 for (i = 0; i < len; i++)
502 {
503 int c = (int) text[i];
504 if (c < 32 && c != 9 && c != 10 && c != 13)
505 {
506 if (i > 0)
507 {
508 OutputIndentation(stream, indent);
509 OutputString(stream, wxT("<") + objectName, convMem, convFile);
510
511 OutputString(stream, style + wxT(">"), convMem, convFile);
512
513 wxString fragment(text.Mid(last, i-last));
514 if (!fragment.empty() && (fragment[0] == wxT(' ') || fragment[fragment.length()-1] == wxT(' ')))
515 {
516 OutputString(stream, wxT("\""), convMem, convFile);
517 OutputStringEnt(stream, fragment, convMem, convFile);
518 OutputString(stream, wxT("\""), convMem, convFile);
519 }
520 else
521 OutputStringEnt(stream, fragment, convMem, convFile);
522
523 OutputString(stream, wxT("</text>"), convMem, convFile);
524 }
525
526
527 // Output this character as a number in a separate tag, because XML can't cope
528 // with entities below 32 except for 9, 10 and 13
529 last = i + 1;
530 OutputIndentation(stream, indent);
531 OutputString(stream, wxT("<symbol"), convMem, convFile);
532
533 OutputString(stream, style + wxT(">"), convMem, convFile);
534 OutputString(stream, wxString::Format(wxT("%d"), c), convMem, convFile);
535
536 OutputString(stream, wxT("</symbol>"), convMem, convFile);
537 }
538 }
539
540 wxString fragment;
541 if (last == 0)
542 fragment = text;
543 else
544 fragment = text.Mid(last, i-last);
545
546 if (last < len)
547 {
548 OutputIndentation(stream, indent);
549 OutputString(stream, wxT("<") + objectName, convMem, convFile);
550
551 OutputString(stream, style + wxT(">"), convMem, convFile);
552
553 if (!fragment.empty() && (fragment[0] == wxT(' ') || fragment[fragment.length()-1] == wxT(' ')))
554 {
555 OutputString(stream, wxT("\""), convMem, convFile);
556 OutputStringEnt(stream, fragment, convMem, convFile);
557 OutputString(stream, wxT("\""), convMem, convFile);
558 }
559 else
560 OutputStringEnt(stream, fragment, convMem, convFile);
561 }
562 else
563 terminateTag = false;
564 }
565 else if (obj.IsKindOf(CLASSINFO(wxRichTextImage)))
566 {
567 wxRichTextImage& imageObj = (wxRichTextImage&) obj;
568
569 if (imageObj.GetImage().Ok() && !imageObj.GetImageBlock().Ok())
570 imageObj.MakeBlock();
571
572 OutputIndentation(stream, indent);
573 OutputString(stream, wxT("<") + objectName, convMem, convFile);
574 if (!imageObj.GetImageBlock().Ok())
575 {
576 // No data
577 OutputString(stream, wxT(">"), convMem, convFile);
578 }
579 else
580 {
581 OutputString(stream, wxString::Format(wxT(" imagetype=\"%d\">"), (int) imageObj.GetImageBlock().GetImageType()));
582 }
583
584 OutputIndentation(stream, indent+1);
585 OutputString(stream, wxT("<data>"), convMem, convFile);
586
587 imageObj.GetImageBlock().WriteHex(stream);
588
589 OutputString(stream, wxT("</data>"), convMem, convFile);
590 }
591 else if (obj.IsKindOf(CLASSINFO(wxRichTextCompositeObject)))
592 {
593 OutputIndentation(stream, indent);
594 OutputString(stream, wxT("<") + objectName, convMem, convFile);
595
596 bool isPara = false;
597 if (objectName == wxT("paragraph") || objectName == wxT("paragraphlayout"))
598 isPara = true;
599
600 wxString style = CreateStyle(obj.GetAttributes(), isPara);
601
602 if (objectName == wxT("paragraphlayout") && ((wxRichTextParagraphLayoutBox&) obj).GetPartialParagraph())
603 style << wxT(" partialparagraph=\"true\"");
604
605 OutputString(stream, style + wxT(">"), convMem, convFile);
606
607 wxRichTextCompositeObject& composite = (wxRichTextCompositeObject&) obj;
608 size_t i;
609 for (i = 0; i < composite.GetChildCount(); i++)
610 {
611 wxRichTextObject* child = composite.GetChild(i);
612 ExportXML(stream, convMem, convFile, *child, indent+1);
613 }
614 }
615
616 if (objectName != wxT("text"))
617 OutputIndentation(stream, indent);
618
619 if (terminateTag)
620 OutputString(stream, wxT("</") + objectName + wxT(">"), convMem, convFile);
621
622 return true;
623 }
624
625 /// Create style parameters
626 wxString wxRichTextXMLHandler::CreateStyle(const wxTextAttrEx& attr, bool isPara)
627 {
628 wxString str;
629 if (attr.HasTextColour() && attr.GetTextColour().Ok())
630 {
631 str << wxT(" textcolor=\"#") << ColourToHexString(attr.GetTextColour()) << wxT("\"");
632 }
633 if (attr.HasBackgroundColour() && attr.GetBackgroundColour().Ok())
634 {
635 str << wxT(" bgcolor=\"#") << ColourToHexString(attr.GetBackgroundColour()) << wxT("\"");
636 }
637
638 if (attr.GetFont().Ok())
639 {
640 if (attr.HasSize())
641 str << wxT(" fontsize=\"") << attr.GetFont().GetPointSize() << wxT("\"");
642
643 //if (attr.HasFamily())
644 // str << wxT(" fontfamily=\"") << attr.GetFont().GetFamily() << wxT("\"");
645
646 if (attr.HasItalic())
647 str << wxT(" fontstyle=\"") << attr.GetFont().GetStyle() << wxT("\"");
648
649 if (attr.HasWeight())
650 str << wxT(" fontweight=\"") << attr.GetFont().GetWeight() << wxT("\"");
651
652 if (attr.HasUnderlined())
653 str << wxT(" fontunderlined=\"") << (int) attr.GetFont().GetUnderlined() << wxT("\"");
654
655 if (attr.HasFaceName())
656 str << wxT(" fontface=\"") << attr.GetFont().GetFaceName() << wxT("\"");
657 }
658
659 if (!attr.GetCharacterStyleName().empty())
660 str << wxT(" charactertyle=\"") << wxString(attr.GetCharacterStyleName()) << wxT("\"");
661
662 if (isPara)
663 {
664 if (attr.HasAlignment())
665 str << wxT(" alignment=\"") << (int) attr.GetAlignment() << wxT("\"");
666
667 if (attr.HasLeftIndent())
668 {
669 str << wxT(" leftindent=\"") << (int) attr.GetLeftIndent() << wxT("\"");
670 str << wxT(" leftsubindent=\"") << (int) attr.GetLeftSubIndent() << wxT("\"");
671 }
672
673 if (attr.HasRightIndent())
674 str << wxT(" rightindent=\"") << (int) attr.GetRightIndent() << wxT("\"");
675
676 if (attr.HasParagraphSpacingAfter())
677 str << wxT(" parspacingafter=\"") << (int) attr.GetParagraphSpacingAfter() << wxT("\"");
678
679 if (attr.HasParagraphSpacingBefore())
680 str << wxT(" parspacingbefore=\"") << (int) attr.GetParagraphSpacingBefore() << wxT("\"");
681
682 if (attr.HasLineSpacing())
683 str << wxT(" linespacing=\"") << (int) attr.GetLineSpacing() << wxT("\"");
684
685 if (attr.HasBulletStyle())
686 str << wxT(" bulletstyle=\"") << (int) attr.GetBulletStyle() << wxT("\"");
687
688 if (attr.HasBulletNumber())
689 str << wxT(" bulletnumber=\"") << (int) attr.GetBulletNumber() << wxT("\"");
690
691 if (attr.HasBulletSymbol())
692 {
693 str << wxT(" bulletsymbol=\"") << (int) (attr.GetBulletSymbol()) << wxT("\"");
694 str << wxT(" bulletfont=\"") << attr.GetBulletFont() << wxT("\"");
695 }
696
697 if (!attr.GetParagraphStyleName().empty())
698 str << wxT(" parstyle=\"") << wxString(attr.GetParagraphStyleName()) << wxT("\"");
699
700 if (attr.HasTabs())
701 {
702 str << wxT(" tabs=\"");
703 size_t i;
704 for (i = 0; i < attr.GetTabs().GetCount(); i++)
705 {
706 if (i > 0)
707 str << wxT(",");
708 str << attr.GetTabs()[i];
709 }
710 str << wxT("\"");
711 }
712 }
713
714 return str;
715 }
716
717 /// Get style parameters
718 bool wxRichTextXMLHandler::GetStyle(wxTextAttrEx& attr, wxXmlNode* node, bool isPara)
719 {
720 wxString fontFacename;
721 int fontSize = 12;
722 int fontFamily = wxDEFAULT;
723 int fontWeight = wxNORMAL;
724 int fontStyle = wxNORMAL;
725 bool fontUnderlined = false;
726
727 int fontFlags = 0;
728
729 fontFacename = node->GetPropVal(wxT("fontface"), wxEmptyString);
730 if (!fontFacename.IsEmpty())
731 fontFlags |= wxTEXT_ATTR_FONT_FACE;
732
733 wxString value;
734 //value = node->GetPropVal(wxT("fontfamily"), wxEmptyString);
735 //if (!value.empty())
736 // fontFamily = wxAtoi(value);
737
738 value = node->GetPropVal(wxT("fontstyle"), wxEmptyString);
739 if (!value.empty())
740 {
741 fontStyle = wxAtoi(value);
742 fontFlags |= wxTEXT_ATTR_FONT_ITALIC;
743 }
744
745 value = node->GetPropVal(wxT("fontsize"), wxEmptyString);
746 if (!value.empty())
747 {
748 fontSize = wxAtoi(value);
749 fontFlags |= wxTEXT_ATTR_FONT_SIZE;
750 }
751
752 value = node->GetPropVal(wxT("fontweight"), wxEmptyString);
753 if (!value.empty())
754 {
755 fontWeight = wxAtoi(value);
756 fontFlags |= wxTEXT_ATTR_FONT_WEIGHT;
757 }
758
759 value = node->GetPropVal(wxT("fontunderlined"), wxEmptyString);
760 if (!value.empty())
761 {
762 fontUnderlined = wxAtoi(value) != 0;
763 fontFlags |= wxTEXT_ATTR_FONT_UNDERLINE;
764 }
765
766 attr.SetFlags(fontFlags);
767
768 if (attr.HasFlag(wxTEXT_ATTR_FONT))
769 attr.SetFont(* wxTheFontList->FindOrCreateFont(fontSize, fontFamily, fontStyle, fontWeight, fontUnderlined, fontFacename));
770
771 // Restore correct font flags
772 attr.SetFlags(fontFlags);
773
774 value = node->GetPropVal(wxT("textcolor"), wxEmptyString);
775 if (!value.empty())
776 {
777 if (value[0] == wxT('#'))
778 attr.SetTextColour(HexStringToColour(value.Mid(1)));
779 else
780 attr.SetTextColour(value);
781 }
782
783 value = node->GetPropVal(wxT("backgroundcolor"), wxEmptyString);
784 if (!value.empty())
785 {
786 if (value[0] == wxT('#'))
787 attr.SetBackgroundColour(HexStringToColour(value.Mid(1)));
788 else
789 attr.SetBackgroundColour(value);
790 }
791
792 value = node->GetPropVal(wxT("characterstyle"), wxEmptyString);
793 if (!value.empty())
794 attr.SetCharacterStyleName(value);
795
796 // Set paragraph attributes
797 if (isPara)
798 {
799 value = node->GetPropVal(wxT("alignment"), wxEmptyString);
800 if (!value.empty())
801 attr.SetAlignment((wxTextAttrAlignment) wxAtoi(value));
802
803 int leftSubIndent = 0;
804 int leftIndent = 0;
805 bool hasLeftIndent = false;
806
807 value = node->GetPropVal(wxT("leftindent"), wxEmptyString);
808 if (!value.empty())
809 {
810 leftIndent = wxAtoi(value);
811 hasLeftIndent = true;
812 }
813
814 value = node->GetPropVal(wxT("leftsubindent"), wxEmptyString);
815 if (!value.empty())
816 {
817 leftSubIndent = wxAtoi(value);
818 hasLeftIndent = true;
819 }
820
821 if (hasLeftIndent)
822 attr.SetLeftIndent(leftIndent, leftSubIndent);
823
824 value = node->GetPropVal(wxT("rightindent"), wxEmptyString);
825 if (!value.empty())
826 attr.SetRightIndent(wxAtoi(value));
827
828 value = node->GetPropVal(wxT("parspacingbefore"), wxEmptyString);
829 if (!value.empty())
830 attr.SetParagraphSpacingBefore(wxAtoi(value));
831
832 value = node->GetPropVal(wxT("parspacingafter"), wxEmptyString);
833 if (!value.empty())
834 attr.SetParagraphSpacingAfter(wxAtoi(value));
835
836 value = node->GetPropVal(wxT("linespacing"), wxEmptyString);
837 if (!value.empty())
838 attr.SetLineSpacing(wxAtoi(value));
839
840 value = node->GetPropVal(wxT("bulletstyle"), wxEmptyString);
841 if (!value.empty())
842 attr.SetBulletStyle(wxAtoi(value));
843
844 value = node->GetPropVal(wxT("bulletnumber"), wxEmptyString);
845 if (!value.empty())
846 attr.SetBulletNumber(wxAtoi(value));
847
848 value = node->GetPropVal(wxT("bulletsymbol"), wxEmptyString);
849 if (!value.empty())
850 attr.SetBulletSymbol(wxAtoi(value));
851
852 value = node->GetPropVal(wxT("bulletfont"), wxEmptyString);
853 if (!value.empty())
854 attr.SetBulletFont(value);
855
856 value = node->GetPropVal(wxT("parstyle"), wxEmptyString);
857 if (!value.empty())
858 attr.SetParagraphStyleName(value);
859
860 value = node->GetPropVal(wxT("tabs"), wxEmptyString);
861 if (!value.empty())
862 {
863 wxArrayInt tabs;
864 wxStringTokenizer tkz(value, wxT(","));
865 while (tkz.HasMoreTokens())
866 {
867 wxString token = tkz.GetNextToken();
868 tabs.Add(wxAtoi(token));
869 }
870 attr.SetTabs(tabs);
871 }
872 }
873
874 return true;
875 }
876
877 #endif
878 // wxUSE_STREAMS
879
880 #endif
881 // wxUSE_RICHTEXT && wxUSE_XML
882