1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/richtext/richtextxml.cpp 
   3 // Purpose:     XML and HTML I/O for wxRichTextCtrl 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // For compilers that support precompilation, includes "wx.h". 
  13 #include "wx/wxprec.h" 
  19 #if wxUSE_RICHTEXT && wxUSE_XML 
  21 #include "wx/richtext/richtextxml.h" 
  25     #include "wx/module.h" 
  29 #include "wx/filename.h" 
  30 #include "wx/clipbrd.h" 
  31 #include "wx/wfstream.h" 
  32 #include "wx/sstream.h" 
  33 #include "wx/txtstrm.h" 
  34 #include "wx/tokenzr.h" 
  35 #include "wx/xml/xml.h" 
  37 IMPLEMENT_DYNAMIC_CLASS(wxRichTextXMLHandler
, wxRichTextFileHandler
) 
  40 bool wxRichTextXMLHandler::DoLoadFile(wxRichTextBuffer 
*buffer
, wxInputStream
& stream
) 
  45     buffer
->ResetAndClearCommands(); 
  48     wxXmlDocument
* xmlDoc 
= new wxXmlDocument
; 
  51     // This is the encoding to convert to (memory encoding rather than file encoding) 
  52     wxString 
encoding(wxT("UTF-8")); 
  54 #if !wxUSE_UNICODE && wxUSE_INTL 
  55     encoding 
= wxLocale::GetSystemEncodingName(); 
  58     if (!xmlDoc
->Load(stream
, encoding
)) 
  60         buffer
->ResetAndClearCommands(); 
  65         if (xmlDoc
->GetRoot() && xmlDoc
->GetRoot()->GetType() == wxXML_ELEMENT_NODE 
&& xmlDoc
->GetRoot()->GetName() == wxT("richtext")) 
  67             wxXmlNode
* child 
= xmlDoc
->GetRoot()->GetChildren(); 
  70                 if (child
->GetType() == wxXML_ELEMENT_NODE
) 
  72                     wxString name 
= child
->GetName(); 
  73                     if (name 
== wxT("richtext-version")) 
  77                         ImportXML(buffer
, child
); 
  80                 child 
= child
->GetNext(); 
  91     buffer
->UpdateRanges(); 
  96 /// Recursively import an object 
  97 bool wxRichTextXMLHandler::ImportXML(wxRichTextBuffer
* buffer
, wxXmlNode
* node
) 
  99     wxString name 
= node
->GetName(); 
 101     bool doneChildren 
= false; 
 103     if (name 
== wxT("paragraphlayout")) 
 105         wxString partial 
= node
->GetAttribute(wxT("partialparagraph"), wxEmptyString
); 
 106         if (partial 
== wxT("true")) 
 107             buffer
->SetPartialParagraph(true); 
 109     else if (name 
== wxT("paragraph")) 
 111         wxRichTextParagraph
* para 
= new wxRichTextParagraph(buffer
); 
 112         buffer
->AppendChild(para
); 
 114         GetStyle(para
->GetAttributes(), node
, true); 
 116         wxXmlNode
* child 
= node
->GetChildren(); 
 119             wxString childName 
= child
->GetName(); 
 120             if (childName 
== wxT("text")) 
 123                 wxXmlNode
* textChild 
= child
->GetChildren(); 
 126                     if (textChild
->GetType() == wxXML_TEXT_NODE 
|| 
 127                         textChild
->GetType() == wxXML_CDATA_SECTION_NODE
) 
 129                         wxString text2 
= textChild
->GetContent(); 
 131                         // Strip whitespace from end 
 132                         if (!text2
.empty() && text2
[text2
.length()-1] == wxT('\n')) 
 133                             text2 
= text2
.Mid(0, text2
.length()-1); 
 135                         if (!text2
.empty() && text2
[0] == wxT('"')) 
 136                             text2 
= text2
.Mid(1); 
 137                         if (!text2
.empty() && text2
[text2
.length()-1] == wxT('"')) 
 138                             text2 
= text2
.Mid(0, text2
.length() - 1); 
 142                     textChild 
= textChild
->GetNext(); 
 145                 wxRichTextPlainText
* textObject 
= new wxRichTextPlainText(text
, para
); 
 146                 GetStyle(textObject
->GetAttributes(), child
, false); 
 148                 para
->AppendChild(textObject
); 
 150             else if (childName 
== wxT("symbol")) 
 152                 // This is a symbol that XML can't read in the normal way 
 154                 wxXmlNode
* textChild 
= child
->GetChildren(); 
 157                     if (textChild
->GetType() == wxXML_TEXT_NODE 
|| 
 158                         textChild
->GetType() == wxXML_CDATA_SECTION_NODE
) 
 160                         wxString text2 
= textChild
->GetContent(); 
 163                     textChild 
= textChild
->GetNext(); 
 167                 actualText 
<< (wxChar
) wxAtoi(text
); 
 169                 wxRichTextPlainText
* textObject 
= new wxRichTextPlainText(actualText
, para
); 
 170                 GetStyle(textObject
->GetAttributes(), child
, false); 
 172                 para
->AppendChild(textObject
); 
 174             else if (childName 
== wxT("image")) 
 176                 wxBitmapType imageType 
= wxBITMAP_TYPE_PNG
; 
 177                 wxString value 
= child
->GetAttribute(wxT("imagetype"), wxEmptyString
); 
 180                     int type 
= wxAtoi(value
); 
 182                     // note: 0 == wxBITMAP_TYPE_INVALID 
 183                     if (type 
<= 0 || type 
>= wxBITMAP_TYPE_MAX
) 
 185                         wxLogWarning("Invalid bitmap type specified for <image> tag: %d", type
); 
 189                         imageType 
= (wxBitmapType
)type
; 
 195                 wxXmlNode
* imageChild 
= child
->GetChildren(); 
 198                     wxString childName 
= imageChild
->GetName(); 
 199                     if (childName 
== wxT("data")) 
 201                         wxXmlNode
* dataChild 
= imageChild
->GetChildren(); 
 204                             data 
= dataChild
->GetContent(); 
 206                             dataChild 
= dataChild
->GetNext(); 
 210                     imageChild 
= imageChild
->GetNext(); 
 215                     wxRichTextImage
* imageObj 
= new wxRichTextImage(para
); 
 216                     GetStyle(imageObj
->GetAttributes(), child
, false); 
 217                     para
->AppendChild(imageObj
); 
 219                     wxStringInputStream 
strStream(data
); 
 221                     imageObj
->GetImageBlock().ReadHex(strStream
, data
.length(), imageType
); 
 224             child 
= child
->GetNext(); 
 229     else if (name 
== wxT("stylesheet")) 
 231         if (GetFlags() & wxRICHTEXT_HANDLER_INCLUDE_STYLESHEET
) 
 233             wxRichTextStyleSheet
* sheet 
= new wxRichTextStyleSheet
; 
 234             wxString sheetName 
= node
->GetAttribute(wxT("name"), wxEmptyString
); 
 235             wxString sheetDescription 
= node
->GetAttribute(wxT("description"), wxEmptyString
); 
 236             sheet
->SetName(sheetName
); 
 237             sheet
->SetDescription(sheetDescription
); 
 239             wxXmlNode
* child 
= node
->GetChildren(); 
 242                 ImportStyleDefinition(sheet
, child
); 
 244                 child 
= child
->GetNext(); 
 247             // Notify that styles have changed. If this is vetoed by the app, 
 248             // the new sheet will be deleted. If it is not vetoed, the 
 249             // old sheet will be deleted and replaced with the new one. 
 250             buffer
->SetStyleSheetAndNotify(sheet
); 
 257         wxXmlNode
* child 
= node
->GetChildren(); 
 260             ImportXML(buffer
, child
); 
 261             child 
= child
->GetNext(); 
 268 bool wxRichTextXMLHandler::ImportStyleDefinition(wxRichTextStyleSheet
* sheet
, wxXmlNode
* node
) 
 270     wxString styleType 
= node
->GetName(); 
 271     wxString styleName 
= node
->GetAttribute(wxT("name"), wxEmptyString
); 
 272     wxString baseStyleName 
= node
->GetAttribute(wxT("basestyle"), wxEmptyString
); 
 274     if (styleName
.IsEmpty()) 
 277     if (styleType 
== wxT("characterstyle")) 
 279         wxRichTextCharacterStyleDefinition
* def 
= new wxRichTextCharacterStyleDefinition(styleName
); 
 280         def
->SetBaseStyle(baseStyleName
); 
 282         wxXmlNode
* child 
= node
->GetChildren(); 
 285             if (child
->GetName() == wxT("style")) 
 288                 GetStyle(attr
, child
, false); 
 291             child 
= child
->GetNext(); 
 294         sheet
->AddCharacterStyle(def
); 
 296     else if (styleType 
== wxT("paragraphstyle")) 
 298         wxRichTextParagraphStyleDefinition
* def 
= new wxRichTextParagraphStyleDefinition(styleName
); 
 300         wxString nextStyleName 
= node
->GetAttribute(wxT("nextstyle"), wxEmptyString
); 
 301         def
->SetNextStyle(nextStyleName
); 
 302         def
->SetBaseStyle(baseStyleName
); 
 304         wxXmlNode
* child 
= node
->GetChildren(); 
 307             if (child
->GetName() == wxT("style")) 
 310                 GetStyle(attr
, child
, false); 
 313             child 
= child
->GetNext(); 
 316         sheet
->AddParagraphStyle(def
); 
 318     else if (styleType 
== wxT("liststyle")) 
 320         wxRichTextListStyleDefinition
* def 
= new wxRichTextListStyleDefinition(styleName
); 
 322         wxString nextStyleName 
= node
->GetAttribute(wxT("nextstyle"), wxEmptyString
); 
 323         def
->SetNextStyle(nextStyleName
); 
 324         def
->SetBaseStyle(baseStyleName
); 
 326         wxXmlNode
* child 
= node
->GetChildren(); 
 329             if (child
->GetName() == wxT("style")) 
 332                 GetStyle(attr
, child
, false); 
 334                 wxString styleLevel 
= child
->GetAttribute(wxT("level"), wxEmptyString
); 
 335                 if (styleLevel
.IsEmpty()) 
 341                     int level 
= wxAtoi(styleLevel
); 
 342                     if (level 
> 0 && level 
<= 10) 
 344                         def
->SetLevelAttributes(level
-1, attr
); 
 348             child 
= child
->GetNext(); 
 351         sheet
->AddListStyle(def
); 
 357 //----------------------------------------------------------------------------- 
 358 //  xml support routines 
 359 //----------------------------------------------------------------------------- 
 361 bool wxRichTextXMLHandler::HasParam(wxXmlNode
* node
, const wxString
& param
) 
 363     return (GetParamNode(node
, param
) != NULL
); 
 366 wxXmlNode 
*wxRichTextXMLHandler::GetParamNode(wxXmlNode
* node
, const wxString
& param
) 
 368     wxCHECK_MSG(node
, NULL
, wxT("You can't access node data before it was initialized!")); 
 370     wxXmlNode 
*n 
= node
->GetChildren(); 
 374         if (n
->GetType() == wxXML_ELEMENT_NODE 
&& n
->GetName() == param
) 
 382 wxString 
wxRichTextXMLHandler::GetNodeContent(wxXmlNode 
*node
) 
 385     if (n 
== NULL
) return wxEmptyString
; 
 386     n 
= n
->GetChildren(); 
 390         if (n
->GetType() == wxXML_TEXT_NODE 
|| 
 391             n
->GetType() == wxXML_CDATA_SECTION_NODE
) 
 392             return n
->GetContent(); 
 395     return wxEmptyString
; 
 399 wxString 
wxRichTextXMLHandler::GetParamValue(wxXmlNode 
*node
, const wxString
& param
) 
 402         return GetNodeContent(node
); 
 404         return GetNodeContent(GetParamNode(node
, param
)); 
 407 wxString 
wxRichTextXMLHandler::GetText(wxXmlNode 
*node
, const wxString
& param
, bool WXUNUSED(translate
)) 
 409     wxXmlNode 
*parNode 
= GetParamNode(node
, param
); 
 412     wxString 
str1(GetNodeContent(parNode
)); 
 416 // For use with earlier versions of wxWidgets 
 417 #ifndef WXUNUSED_IN_UNICODE 
 419 #define WXUNUSED_IN_UNICODE(x) WXUNUSED(x) 
 421 #define WXUNUSED_IN_UNICODE(x) x 
 425 // write string to output: 
 426 inline static void OutputString(wxOutputStream
& stream
, const wxString
& str
, 
 427                                 wxMBConv 
*WXUNUSED_IN_UNICODE(convMem
) = NULL
, wxMBConv 
*convFile 
= NULL
) 
 429     if (str
.empty()) return; 
 433         const wxWX2MBbuf 
buf(str
.mb_str(*convFile
)); 
 434         stream
.Write((const char*)buf
, strlen((const char*)buf
)); 
 438         const wxWX2MBbuf 
buf(str
.mb_str(wxConvUTF8
)); 
 439         stream
.Write((const char*)buf
, strlen((const char*)buf
)); 
 442     if ( convFile 
== NULL 
) 
 443         stream
.Write(str
.mb_str(), str
.Len()); 
 446         wxString 
str2(str
.wc_str(*convMem
), *convFile
); 
 447         stream
.Write(str2
.mb_str(), str2
.Len()); 
 452 // Same as above, but create entities first. 
 453 // Translates '<' to "<", '>' to ">" and '&' to "&" 
 454 static void OutputStringEnt(wxOutputStream
& stream
, const wxString
& str
, 
 455                             wxMBConv 
*convMem 
= NULL
, wxMBConv 
*convFile 
= NULL
) 
 463     for (i 
= 0; i 
< len
; i
++) 
 467         // Original code excluded "&" but we _do_ want to convert 
 468         // the ampersand beginning & because otherwise when read in, 
 469         // the original "&" becomes "&". 
 471         if (c 
== wxT('<') || c 
== wxT('>') || c 
== wxT('"') || 
 472             (c 
== wxT('&') /* && (str.Mid(i+1, 4) != wxT("amp;")) */ )) 
 474             OutputString(stream
, str
.Mid(last
, i 
- last
), convMem
, convFile
); 
 478                 OutputString(stream
, wxT("<"), NULL
, NULL
); 
 481                 OutputString(stream
, wxT(">"), NULL
, NULL
); 
 484                 OutputString(stream
, wxT("&"), NULL
, NULL
); 
 487                 OutputString(stream
, wxT("""), NULL
, NULL
); 
 493         else if (wxUChar(c
) > 127) 
 495             OutputString(stream
, str
.Mid(last
, i 
- last
), convMem
, convFile
); 
 497             wxString 
s(wxT("&#")); 
 501             s 
<< (int) wxUChar(c
); 
 504             OutputString(stream
, s
, NULL
, NULL
); 
 508     OutputString(stream
, str
.Mid(last
, i 
- last
), convMem
, convFile
); 
 511 static wxString 
AttributeToXML(const wxString
& str
) 
 519     for (i 
= 0; i 
< len
; i
++) 
 523         // Original code excluded "&" but we _do_ want to convert 
 524         // the ampersand beginning & because otherwise when read in, 
 525         // the original "&" becomes "&". 
 527         if (c 
== wxT('<') || c 
== wxT('>') || c 
== wxT('"') || 
 528             (c 
== wxT('&') /* && (str.Mid(i+1, 4) != wxT("amp;")) */ )) 
 530             str1 
+= str
.Mid(last
, i 
- last
); 
 540                 str1 
+= wxT("&"); 
 543                 str1 
+= wxT("""); 
 549         else if (wxUChar(c
) > 127) 
 551             str1 
+= str
.Mid(last
, i 
- last
); 
 553             wxString 
s(wxT("&#")); 
 557             s 
<< (int) wxUChar(c
); 
 564     str1 
+= str
.Mid(last
, i 
- last
); 
 568 inline static void OutputIndentation(wxOutputStream
& stream
, int indent
) 
 570     wxString str 
= wxT("\n"); 
 571     for (int i 
= 0; i 
< indent
; i
++) 
 572         str 
<< wxT(' ') << wxT(' '); 
 573     OutputString(stream
, str
, NULL
, NULL
); 
 576 // Convert a colour to a 6-digit hex string 
 577 static wxString 
ColourToHexString(const wxColour
& col
) 
 581     hex 
+= wxDecToHex(col
.Red()); 
 582     hex 
+= wxDecToHex(col
.Green()); 
 583     hex 
+= wxDecToHex(col
.Blue()); 
 588 // Convert 6-digit hex string to a colour 
 589 static wxColour 
HexStringToColour(const wxString
& hex
) 
 591     unsigned char r 
= (unsigned char)wxHexToDec(hex
.Mid(0, 2)); 
 592     unsigned char g 
= (unsigned char)wxHexToDec(hex
.Mid(2, 2)); 
 593     unsigned char b 
= (unsigned char)wxHexToDec(hex
.Mid(4, 2)); 
 595     return wxColour(r
, g
, b
); 
 598 bool wxRichTextXMLHandler::DoSaveFile(wxRichTextBuffer 
*buffer
, wxOutputStream
& stream
) 
 603     wxString 
version(wxT("1.0") ) ; 
 605     bool deleteConvFile 
= false; 
 606     wxString fileEncoding
; 
 607     wxMBConv
* convFile 
= NULL
; 
 610     fileEncoding 
= wxT("UTF-8"); 
 611     convFile 
= & wxConvUTF8
; 
 613     fileEncoding 
= wxT("ISO-8859-1"); 
 614     convFile 
= & wxConvISO8859_1
; 
 617     // If SetEncoding has been called, change the output encoding. 
 618     if (!m_encoding
.empty() && m_encoding
.Lower() != fileEncoding
.Lower()) 
 620         if (m_encoding 
== wxT("<System>")) 
 623             fileEncoding 
= wxLocale::GetSystemEncodingName(); 
 624             // if !wxUSE_INTL, we fall back to UTF-8 or ISO-8859-1 below 
 629             fileEncoding 
= m_encoding
; 
 632         // GetSystemEncodingName may not have returned a name 
 633         if (fileEncoding
.empty()) 
 635             fileEncoding 
= wxT("UTF-8"); 
 637             fileEncoding 
= wxT("ISO-8859-1"); 
 639         convFile 
= new wxCSConv(fileEncoding
); 
 640         deleteConvFile 
= true; 
 644     wxMBConv
* convMem 
= wxConvCurrent
; 
 646     wxMBConv
* convMem 
= NULL
; 
 650     s
.Printf(wxT("<?xml version=\"%s\" encoding=\"%s\"?>\n"), 
 651              version
, fileEncoding
); 
 652     OutputString(stream
, s
, NULL
, NULL
); 
 653     OutputString(stream
, wxT("<richtext version=\"1.0.0.0\" xmlns=\"http://www.wxwidgets.org\">") , NULL
, NULL
); 
 657     if (buffer
->GetStyleSheet() && (GetFlags() & wxRICHTEXT_HANDLER_INCLUDE_STYLESHEET
)) 
 659         OutputIndentation(stream
, level
); 
 660         wxString nameAndDescr
; 
 661         if (!buffer
->GetStyleSheet()->GetName().IsEmpty()) 
 662             nameAndDescr 
<< wxT(" name=\"") << buffer
->GetStyleSheet()->GetName() << wxT("\""); 
 663         if (!buffer
->GetStyleSheet()->GetDescription().IsEmpty()) 
 664             nameAndDescr 
<< wxT(" description=\"") << buffer
->GetStyleSheet()->GetDescription() << wxT("\""); 
 665         OutputString(stream
, wxString(wxT("<stylesheet")) + nameAndDescr 
+ wxT(">"), convMem
, convFile
); 
 669         for (i 
= 0; i 
< (int) buffer
->GetStyleSheet()->GetCharacterStyleCount(); i
++) 
 671             wxRichTextCharacterStyleDefinition
* def 
= buffer
->GetStyleSheet()->GetCharacterStyle(i
); 
 672             ExportStyleDefinition(stream
, convMem
, convFile
, def
, level 
+ 1); 
 675         for (i 
= 0; i 
< (int) buffer
->GetStyleSheet()->GetParagraphStyleCount(); i
++) 
 677             wxRichTextParagraphStyleDefinition
* def 
= buffer
->GetStyleSheet()->GetParagraphStyle(i
); 
 678             ExportStyleDefinition(stream
, convMem
, convFile
, def
, level 
+ 1); 
 681         for (i 
= 0; i 
< (int) buffer
->GetStyleSheet()->GetListStyleCount(); i
++) 
 683             wxRichTextListStyleDefinition
* def 
= buffer
->GetStyleSheet()->GetListStyle(i
); 
 684             ExportStyleDefinition(stream
, convMem
, convFile
, def
, level 
+ 1); 
 687         OutputIndentation(stream
, level
); 
 688         OutputString(stream
, wxT("</stylesheet>"), convMem
, convFile
); 
 692     bool success 
= ExportXML(stream
, convMem
, convFile
, *buffer
, level
); 
 694     OutputString(stream
, wxT("\n</richtext>") , NULL
, NULL
); 
 695     OutputString(stream
, wxT("\n"), NULL
, NULL
); 
 703 /// Recursively export an object 
 704 bool wxRichTextXMLHandler::ExportXML(wxOutputStream
& stream
, wxMBConv
* convMem
, wxMBConv
* convFile
, wxRichTextObject
& obj
, int indent
) 
 707     if (obj
.IsKindOf(CLASSINFO(wxRichTextParagraphLayoutBox
))) 
 708         objectName 
= wxT("paragraphlayout"); 
 709     else if (obj
.IsKindOf(CLASSINFO(wxRichTextParagraph
))) 
 710         objectName 
= wxT("paragraph"); 
 711     else if (obj
.IsKindOf(CLASSINFO(wxRichTextPlainText
))) 
 712         objectName 
= wxT("text"); 
 713     else if (obj
.IsKindOf(CLASSINFO(wxRichTextImage
))) 
 714         objectName 
= wxT("image"); 
 716         objectName 
= wxT("object"); 
 718     bool terminateTag 
= true; 
 720     if (obj
.IsKindOf(CLASSINFO(wxRichTextPlainText
))) 
 722         wxRichTextPlainText
& textObj 
= (wxRichTextPlainText
&) obj
; 
 724         wxString style 
= CreateStyle(obj
.GetAttributes(), false); 
 728         const wxString
& text 
= textObj
.GetText(); 
 729         int len 
= (int) text
.Length(); 
 734             OutputIndentation(stream
, indent
); 
 735             OutputString(stream
, wxT("<") + objectName
, convMem
, convFile
); 
 736             OutputString(stream
, style 
+ wxT(">"), convMem
, convFile
); 
 737             OutputString(stream
, wxT("</text>"), convMem
, convFile
); 
 739         else for (i 
= 0; i 
< len
; i
++) 
 742             int c 
= (int) text
[i
]; 
 744             int c 
= (int) wxUChar(text
[i
]); 
 746             if ((c 
< 32 || c 
== 34) && /* c != 9 && */ c 
!= 10 && c 
!= 13) 
 750                     wxString 
fragment(text
.Mid(last
, i
-last
)); 
 751                     if (!fragment
.IsEmpty()) 
 753                         OutputIndentation(stream
, indent
); 
 754                         OutputString(stream
, wxT("<") + objectName
, convMem
, convFile
); 
 756                         OutputString(stream
, style 
+ wxT(">"), convMem
, convFile
); 
 758                         if (!fragment
.empty() && (fragment
[0] == wxT(' ') || fragment
[fragment
.length()-1] == wxT(' '))) 
 760                             OutputString(stream
, wxT("\""), convMem
, convFile
); 
 761                             OutputStringEnt(stream
, fragment
, convMem
, convFile
); 
 762                             OutputString(stream
, wxT("\""), convMem
, convFile
); 
 765                             OutputStringEnt(stream
, fragment
, convMem
, convFile
); 
 767                         OutputString(stream
, wxT("</text>"), convMem
, convFile
); 
 772                 // Output this character as a number in a separate tag, because XML can't cope 
 773                 // with entities below 32 except for 10 and 13 
 775                 OutputIndentation(stream
, indent
); 
 776                 OutputString(stream
, wxT("<symbol"), convMem
, convFile
); 
 778                 OutputString(stream
, style 
+ wxT(">"), convMem
, convFile
); 
 779                 OutputString(stream
, wxString::Format(wxT("%d"), c
), convMem
, convFile
); 
 781                 OutputString(stream
, wxT("</symbol>"), convMem
, convFile
); 
 789             fragment 
= text
.Mid(last
, i
-last
); 
 793             OutputIndentation(stream
, indent
); 
 794             OutputString(stream
, wxT("<") + objectName
, convMem
, convFile
); 
 796             OutputString(stream
, style 
+ wxT(">"), convMem
, convFile
); 
 798             if (!fragment
.empty() && (fragment
[0] == wxT(' ') || fragment
[fragment
.length()-1] == wxT(' '))) 
 800                 OutputString(stream
, wxT("\""), convMem
, convFile
); 
 801                 OutputStringEnt(stream
, fragment
, convMem
, convFile
); 
 802                 OutputString(stream
, wxT("\""), convMem
, convFile
); 
 805                 OutputStringEnt(stream
, fragment
, convMem
, convFile
); 
 808             terminateTag 
= false; 
 810     else if (obj
.IsKindOf(CLASSINFO(wxRichTextImage
))) 
 812         wxRichTextImage
& imageObj 
= (wxRichTextImage
&) obj
; 
 814         wxString style 
= CreateStyle(obj
.GetAttributes(), false); 
 816         //if (imageObj.GetImage().Ok() && !imageObj.GetImageBlock().Ok()) 
 817         //    imageObj.MakeBlock(); 
 819         OutputIndentation(stream
, indent
); 
 820         OutputString(stream
, wxT("<") + objectName
, convMem
, convFile
); 
 821         if (!imageObj
.GetImageBlock().Ok()) 
 824             OutputString(stream
, style 
+ wxT(">"), convMem
, convFile
); 
 828             OutputString(stream
, wxString::Format(wxT(" imagetype=\"%d\""), (int) imageObj
.GetImageBlock().GetImageType()) + style 
+ wxT(">")); 
 831         OutputIndentation(stream
, indent
+1); 
 832         OutputString(stream
, wxT("<data>"), convMem
, convFile
); 
 834         imageObj
.GetImageBlock().WriteHex(stream
); 
 836         OutputString(stream
, wxT("</data>"), convMem
, convFile
); 
 838     else if (obj
.IsKindOf(CLASSINFO(wxRichTextCompositeObject
))) 
 840         OutputIndentation(stream
, indent
); 
 841         OutputString(stream
, wxT("<") + objectName
, convMem
, convFile
); 
 844         if (objectName 
== wxT("paragraph") || objectName 
== wxT("paragraphlayout")) 
 847         wxString style 
= CreateStyle(obj
.GetAttributes(), isPara
); 
 849         if (objectName 
== wxT("paragraphlayout") && ((wxRichTextParagraphLayoutBox
&) obj
).GetPartialParagraph()) 
 850             style 
<< wxT(" partialparagraph=\"true\""); 
 852         OutputString(stream
, style 
+ wxT(">"), convMem
, convFile
); 
 854         wxRichTextCompositeObject
& composite 
= (wxRichTextCompositeObject
&) obj
; 
 856         for (i 
= 0; i 
< composite
.GetChildCount(); i
++) 
 858             wxRichTextObject
* child 
= composite
.GetChild(i
); 
 859             ExportXML(stream
, convMem
, convFile
, *child
, indent
+1); 
 863     if (objectName 
!= wxT("text")) 
 864         OutputIndentation(stream
, indent
); 
 867         OutputString(stream
, wxT("</") + objectName 
+ wxT(">"), convMem
, convFile
); 
 872 bool wxRichTextXMLHandler::ExportStyleDefinition(wxOutputStream
& stream
, wxMBConv
* convMem
, wxMBConv
* convFile
, wxRichTextStyleDefinition
* def
, int level
) 
 874     wxRichTextCharacterStyleDefinition
* charDef 
= wxDynamicCast(def
, wxRichTextCharacterStyleDefinition
); 
 875     wxRichTextParagraphStyleDefinition
* paraDef 
= wxDynamicCast(def
, wxRichTextParagraphStyleDefinition
); 
 876     wxRichTextListStyleDefinition
* listDef 
= wxDynamicCast(def
, wxRichTextListStyleDefinition
); 
 878     wxString baseStyle 
= def
->GetBaseStyle(); 
 879     wxString baseStyleProp
; 
 880     if (!baseStyle
.IsEmpty()) 
 881         baseStyleProp 
= wxT(" basestyle=\"") + baseStyle 
+ wxT("\""); 
 883     wxString descr 
= def
->GetDescription(); 
 885     if (!descr
.IsEmpty()) 
 886         descrProp 
= wxT(" description=\"") + descr 
+ wxT("\""); 
 890         OutputIndentation(stream
, level
); 
 891         OutputString(stream
, wxT("<characterstyle") + baseStyleProp 
+ descrProp 
+ wxT(">"), convMem
, convFile
); 
 895         wxString style 
= CreateStyle(def
->GetStyle(), false); 
 897         OutputIndentation(stream
, level
); 
 898         OutputString(stream
, wxT("<style ") + style 
+ wxT(">"), convMem
, convFile
); 
 900         OutputIndentation(stream
, level
); 
 901         OutputString(stream
, wxT("</style>"), convMem
, convFile
); 
 905         OutputIndentation(stream
, level
); 
 906         OutputString(stream
, wxT("</characterstyle>"), convMem
, convFile
); 
 910         OutputIndentation(stream
, level
); 
 912         if (!listDef
->GetNextStyle().IsEmpty()) 
 913             baseStyleProp 
<< wxT(" basestyle=\"") << listDef
->GetNextStyle() << wxT("\""); 
 915         OutputString(stream
, wxT("<liststyle") + baseStyleProp 
+ descrProp 
+ wxT(">"), convMem
, convFile
); 
 919         wxString style 
= CreateStyle(def
->GetStyle(), false); 
 921         OutputIndentation(stream
, level
); 
 922         OutputString(stream
, wxT("<style ") + style 
+ wxT(">"), convMem
, convFile
); 
 924         OutputIndentation(stream
, level
); 
 925         OutputString(stream
, wxT("</style>"), convMem
, convFile
); 
 928         for (i 
= 0; i 
< 10; i 
++) 
 930             wxTextAttr
* levelAttr 
= listDef
->GetLevelAttributes(i
); 
 933                 wxString style 
= CreateStyle(def
->GetStyle(), false); 
 934                 wxString levelStr 
= wxString::Format(wxT(" level=\"%d\" "), (i
+1)); 
 936                 OutputIndentation(stream
, level
); 
 937                 OutputString(stream
, wxT("<style ") + levelStr 
+ style 
+ wxT(">"), convMem
, convFile
); 
 939                 OutputIndentation(stream
, level
); 
 940                 OutputString(stream
, wxT("</style>"), convMem
, convFile
); 
 946         OutputIndentation(stream
, level
); 
 947         OutputString(stream
, wxT("</liststyle>"), convMem
, convFile
); 
 951         OutputIndentation(stream
, level
); 
 953         if (!paraDef
->GetNextStyle().IsEmpty()) 
 954             baseStyleProp 
<< wxT(" basestyle=\"") << paraDef
->GetNextStyle() << wxT("\""); 
 956         OutputString(stream
, wxT("<paragraphstyle") + baseStyleProp 
+ descrProp 
+ wxT(">"), convMem
, convFile
); 
 960         wxString style 
= CreateStyle(def
->GetStyle(), false); 
 962         OutputIndentation(stream
, level
); 
 963         OutputString(stream
, wxT("<style ") + style 
+ wxT(">"), convMem
, convFile
); 
 965         OutputIndentation(stream
, level
); 
 966         OutputString(stream
, wxT("</style>"), convMem
, convFile
); 
 970         OutputIndentation(stream
, level
); 
 971         OutputString(stream
, wxT("</paragraphstyle>"), convMem
, convFile
); 
 977 /// Create style parameters 
 978 wxString 
wxRichTextXMLHandler::CreateStyle(const wxTextAttr
& attr
, bool isPara
) 
 981     if (attr
.HasTextColour() && attr
.GetTextColour().Ok()) 
 983         str 
<< wxT(" textcolor=\"#") << ColourToHexString(attr
.GetTextColour()) << wxT("\""); 
 985     if (attr
.HasBackgroundColour() && attr
.GetBackgroundColour().Ok()) 
 987         str 
<< wxT(" bgcolor=\"#") << ColourToHexString(attr
.GetBackgroundColour()) << wxT("\""); 
 990     if (attr
.HasFontSize()) 
 991         str 
<< wxT(" fontsize=\"") << attr
.GetFontSize() << wxT("\""); 
 993     if (attr
.HasFontFamily()) 
 994         str 
<< wxT(" fontfamily=\"") << attr
.GetFont().GetFamily() << wxT("\""); 
 996     if (attr
.HasFontItalic()) 
 997         str 
<< wxT(" fontstyle=\"") << attr
.GetFontStyle() << wxT("\""); 
 999     if (attr
.HasFontWeight()) 
1000         str 
<< wxT(" fontweight=\"") << attr
.GetFontWeight() << wxT("\""); 
1002     if (attr
.HasFontUnderlined()) 
1003         str 
<< wxT(" fontunderlined=\"") << (int) attr
.GetFontUnderlined() << wxT("\""); 
1005     if (attr
.HasFontFaceName()) 
1006         str 
<< wxT(" fontface=\"") << attr
.GetFontFaceName() << wxT("\""); 
1008     if (attr
.HasTextEffects()) 
1010         str 
<< wxT(" texteffects=\""); 
1011         str 
<< attr
.GetTextEffects(); 
1014         str 
<< wxT(" texteffectflags=\""); 
1015         str 
<< attr
.GetTextEffectFlags(); 
1019     if (!attr
.GetCharacterStyleName().empty()) 
1020         str 
<< wxT(" characterstyle=\"") << wxString(attr
.GetCharacterStyleName()) << wxT("\""); 
1023         str 
<< wxT(" url=\"") << AttributeToXML(attr
.GetURL()) << wxT("\""); 
1027         if (attr
.HasAlignment()) 
1028             str 
<< wxT(" alignment=\"") << (int) attr
.GetAlignment() << wxT("\""); 
1030         if (attr
.HasLeftIndent()) 
1032             str 
<< wxT(" leftindent=\"") << (int) attr
.GetLeftIndent() << wxT("\""); 
1033             str 
<< wxT(" leftsubindent=\"") << (int) attr
.GetLeftSubIndent() << wxT("\""); 
1036         if (attr
.HasRightIndent()) 
1037             str 
<< wxT(" rightindent=\"") << (int) attr
.GetRightIndent() << wxT("\""); 
1039         if (attr
.HasParagraphSpacingAfter()) 
1040             str 
<< wxT(" parspacingafter=\"") << (int) attr
.GetParagraphSpacingAfter() << wxT("\""); 
1042         if (attr
.HasParagraphSpacingBefore()) 
1043             str 
<< wxT(" parspacingbefore=\"") << (int) attr
.GetParagraphSpacingBefore() << wxT("\""); 
1045         if (attr
.HasLineSpacing()) 
1046             str 
<< wxT(" linespacing=\"") << (int) attr
.GetLineSpacing() << wxT("\""); 
1048         if (attr
.HasBulletStyle()) 
1049             str 
<< wxT(" bulletstyle=\"") << (int) attr
.GetBulletStyle() << wxT("\""); 
1051         if (attr
.HasBulletNumber()) 
1052             str 
<< wxT(" bulletnumber=\"") << (int) attr
.GetBulletNumber() << wxT("\""); 
1054         if (attr
.HasBulletText()) 
1056             // If using a bullet symbol, convert to integer in case it's a non-XML-friendly character. 
1057             // Otherwise, assume it's XML-friendly text such as outline numbering, e.g. 1.2.3.1 
1058             if (!attr
.GetBulletText().IsEmpty() && (attr
.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_SYMBOL
)) 
1059                 str 
<< wxT(" bulletsymbol=\"") << (int) (attr
.GetBulletText()[0]) << wxT("\""); 
1061                 str 
<< wxT(" bullettext=\"") << attr
.GetBulletText() << wxT("\""); 
1063             str 
<< wxT(" bulletfont=\"") << attr
.GetBulletFont() << wxT("\""); 
1066         if (attr
.HasBulletName()) 
1067             str 
<< wxT(" bulletname=\"") << attr
.GetBulletName() << wxT("\""); 
1069         if (!attr
.GetParagraphStyleName().empty()) 
1070             str 
<< wxT(" parstyle=\"") << wxString(attr
.GetParagraphStyleName()) << wxT("\""); 
1072         if (!attr
.GetListStyleName().empty()) 
1073             str 
<< wxT(" liststyle=\"") << wxString(attr
.GetListStyleName()) << wxT("\""); 
1077             str 
<< wxT(" tabs=\""); 
1079             for (i 
= 0; i 
< attr
.GetTabs().GetCount(); i
++) 
1083                 str 
<< attr
.GetTabs()[i
]; 
1088         if (attr
.HasPageBreak()) 
1090             str 
<< wxT(" pagebreak=\"1\""); 
1093         if (attr
.HasOutlineLevel()) 
1094             str 
<< wxT(" outlinelevel=\"") << (int) attr
.GetOutlineLevel() << wxT("\""); 
1101 /// Replace face name with current name for platform. 
1102 /// TODO: introduce a virtual function or settable table to 
1103 /// do this comprehensively. 
1104 bool wxRichTextFixFaceName(wxString
& facename
) 
1106     if (facename
.IsEmpty()) 
1110     if (facename 
== wxT("Times")) 
1112         facename 
= wxT("Times New Roman"); 
1115     else if (facename 
== wxT("Helvetica")) 
1117         facename 
= wxT("Arial"); 
1120     else if (facename 
== wxT("Courier")) 
1122         facename 
= wxT("Courier New"); 
1128     if (facename 
== wxT("Times New Roman")) 
1130         facename 
= wxT("Times"); 
1133     else if (facename 
== wxT("Arial")) 
1135         facename 
= wxT("Helvetica"); 
1138     else if (facename 
== wxT("Courier New")) 
1140         facename 
= wxT("Courier"); 
1148 /// Get style parameters 
1149 bool wxRichTextXMLHandler::GetStyle(wxTextAttr
& attr
, wxXmlNode
* node
, bool isPara
) 
1151     wxString fontFacename
; 
1153     wxFontFamily fontFamily 
= wxFONTFAMILY_DEFAULT
; 
1154     wxFontWeight fontWeight 
= wxFONTWEIGHT_NORMAL
; 
1155     wxFontStyle fontStyle 
= wxFONTSTYLE_NORMAL
; 
1156     bool fontUnderlined 
= false; 
1157     const wxString emptyString
; // save a temporary string construction in GetPropVal 
1159     // int fontFlags = 0; 
1161     fontFacename 
= node
->GetAttribute(wxT("fontface"), emptyString
); 
1162     if (!fontFacename
.IsEmpty()) 
1164         attr
.SetFontFaceName(fontFacename
); 
1165         if (GetFlags() & wxRICHTEXT_HANDLER_CONVERT_FACENAMES
) 
1166             wxRichTextFixFaceName(fontFacename
); 
1170     value 
= node
->GetAttribute(wxT("fontfamily"), emptyString
); 
1173         fontFamily 
= (wxFontFamily
)wxAtoi(value
); 
1174         attr
.SetFontFamily(fontFamily
); 
1177     value 
= node
->GetAttribute(wxT("fontstyle"), emptyString
); 
1180         fontStyle 
= (wxFontStyle
)wxAtoi(value
); 
1181         attr
.SetFontStyle(fontStyle
); 
1184     value 
= node
->GetAttribute(wxT("fontsize"), emptyString
); 
1187         fontSize 
= wxAtoi(value
); 
1188         attr
.SetFontSize(fontSize
); 
1191     value 
= node
->GetAttribute(wxT("fontweight"), emptyString
); 
1194         fontWeight 
= (wxFontWeight
)wxAtoi(value
); 
1195         attr
.SetFontWeight(fontWeight
); 
1198     value 
= node
->GetAttribute(wxT("fontunderlined"), emptyString
); 
1201         fontUnderlined 
= wxAtoi(value
) != 0; 
1202         attr
.SetFontUnderlined(fontUnderlined
); 
1205     value 
= node
->GetAttribute(wxT("textcolor"), emptyString
); 
1208         if (value
[0] == wxT('#')) 
1209             attr
.SetTextColour(HexStringToColour(value
.Mid(1))); 
1211             attr
.SetTextColour(value
); 
1214     value 
= node
->GetAttribute(wxT("bgcolor"), emptyString
); 
1217         if (value
[0] == wxT('#')) 
1218             attr
.SetBackgroundColour(HexStringToColour(value
.Mid(1))); 
1220             attr
.SetBackgroundColour(value
); 
1223     value 
= node
->GetAttribute(wxT("characterstyle"), emptyString
); 
1225         attr
.SetCharacterStyleName(value
); 
1227     value 
= node
->GetAttribute(wxT("texteffects"), emptyString
); 
1228     if (!value
.IsEmpty()) 
1230         attr
.SetTextEffects(wxAtoi(value
)); 
1233     value 
= node
->GetAttribute(wxT("texteffectflags"), emptyString
); 
1234     if (!value
.IsEmpty()) 
1236         attr
.SetTextEffectFlags(wxAtoi(value
)); 
1239     value 
= node
->GetAttribute(wxT("url"), emptyString
); 
1243     // Set paragraph attributes 
1246         value 
= node
->GetAttribute(wxT("alignment"), emptyString
); 
1248             attr
.SetAlignment((wxTextAttrAlignment
) wxAtoi(value
)); 
1250         int leftSubIndent 
= 0; 
1252         bool hasLeftIndent 
= false; 
1254         value 
= node
->GetAttribute(wxT("leftindent"), emptyString
); 
1257             leftIndent 
= wxAtoi(value
); 
1258             hasLeftIndent 
= true; 
1261         value 
= node
->GetAttribute(wxT("leftsubindent"), emptyString
); 
1264             leftSubIndent 
= wxAtoi(value
); 
1265             hasLeftIndent 
= true; 
1269             attr
.SetLeftIndent(leftIndent
, leftSubIndent
); 
1271         value 
= node
->GetAttribute(wxT("rightindent"), emptyString
); 
1273             attr
.SetRightIndent(wxAtoi(value
)); 
1275         value 
= node
->GetAttribute(wxT("parspacingbefore"), emptyString
); 
1277             attr
.SetParagraphSpacingBefore(wxAtoi(value
)); 
1279         value 
= node
->GetAttribute(wxT("parspacingafter"), emptyString
); 
1281             attr
.SetParagraphSpacingAfter(wxAtoi(value
)); 
1283         value 
= node
->GetAttribute(wxT("linespacing"), emptyString
); 
1285             attr
.SetLineSpacing(wxAtoi(value
)); 
1287         value 
= node
->GetAttribute(wxT("bulletstyle"), emptyString
); 
1289             attr
.SetBulletStyle(wxAtoi(value
)); 
1291         value 
= node
->GetAttribute(wxT("bulletnumber"), emptyString
); 
1293             attr
.SetBulletNumber(wxAtoi(value
)); 
1295         value 
= node
->GetAttribute(wxT("bulletsymbol"), emptyString
); 
1298             wxChar ch 
= wxAtoi(value
); 
1301             attr
.SetBulletText(s
); 
1304         value 
= node
->GetAttribute(wxT("bullettext"), emptyString
); 
1306             attr
.SetBulletText(value
); 
1308         value 
= node
->GetAttribute(wxT("bulletfont"), emptyString
); 
1310             attr
.SetBulletFont(value
); 
1312         value 
= node
->GetAttribute(wxT("bulletname"), emptyString
); 
1314             attr
.SetBulletName(value
); 
1316         value 
= node
->GetAttribute(wxT("parstyle"), emptyString
); 
1318             attr
.SetParagraphStyleName(value
); 
1320         value 
= node
->GetAttribute(wxT("liststyle"), emptyString
); 
1322             attr
.SetListStyleName(value
); 
1324         value 
= node
->GetAttribute(wxT("tabs"), emptyString
); 
1328             wxStringTokenizer 
tkz(value
, wxT(",")); 
1329             while (tkz
.HasMoreTokens()) 
1331                 wxString token 
= tkz
.GetNextToken(); 
1332                 tabs
.Add(wxAtoi(token
)); 
1337         value 
= node
->GetAttribute(wxT("pagebreak"), emptyString
); 
1338         if (!value
.IsEmpty()) 
1340             attr
.SetPageBreak(wxAtoi(value
) != 0); 
1343         value 
= node
->GetAttribute(wxT("outlinelevel"), emptyString
); 
1344         if (!value
.IsEmpty()) 
1346             attr
.SetOutlineLevel(wxAtoi(value
)); 
1357     // wxUSE_RICHTEXT && wxUSE_XML