From bd21f7eaf01f7056ff2cb1529209eb9d0e7b74f4 Mon Sep 17 00:00:00 2001 From: Julian Smart Date: Tue, 3 Sep 2013 16:47:09 +0000 Subject: [PATCH] wxRTC: extracted XML utilities into a separate class for potential reuse. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74749 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 1 + include/wx/richtext/richtextxml.h | 183 +- interface/wx/richtext/richtextxml.h | 27 - src/richtext/richtextxml.cpp | 3475 ++++++++++++++------------- 4 files changed, 1886 insertions(+), 1800 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 42d0bc5095..9a3493850f 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -571,6 +571,7 @@ All (GUI): - Fix crash in wxHTML on mal-formed elements (LukasK). - Set correct cursor when the mouse is over image map links in wxHTML (LukasK). - Add wxPropertyGridPageState::GetColumnFullWidth() (Teodor Petrov). +- wxRTC: extracted XML utilities into a separate class for potential reuse. wxGTK: diff --git a/include/wx/richtext/richtextxml.h b/include/wx/richtext/richtextxml.h index 964ae238a5..8f14f7a30a 100644 --- a/include/wx/richtext/richtextxml.h +++ b/include/wx/richtext/richtextxml.h @@ -22,7 +22,147 @@ #if wxUSE_RICHTEXT && wxUSE_XML /*! - * wxRichTextXMLHandler + @class wxRichTextXMLHelper + A utility class to help with XML import/export, that can be used outside + saving a buffer if needed. + */ + +class wxRichTextXMLHelper: public wxObject +{ +public: + wxRichTextXMLHelper() { Init(); } + wxRichTextXMLHelper(const wxString& enc) { Init(); SetupForSaving(enc); } + ~wxRichTextXMLHelper(); + + void Init(); + + void SetupForSaving(const wxString& enc); + + void Clear(); + + void SetFileEncoding(const wxString& encoding) { m_fileEncoding = encoding; } + const wxString& GetFileEncoding() const { return m_fileEncoding; } + + // Convert a colour to a 6-digit hex string + static wxString ColourToHexString(const wxColour& col); + + // Convert 6-digit hex string to a colour + static wxColour HexStringToColour(const wxString& hex); + + static wxString MakeString(const int& v) { return wxString::Format(wxT("%d"), v); } + static wxString MakeString(const long& v) { return wxString::Format(wxT("%ld"), v); } + static wxString MakeString(const double& v) { return wxString::Format(wxT("%.2f"), (float) v); } + static wxString MakeString(const wxString& s) { return s; } + static wxString MakeString(const wxColour& col) { return wxT("#") + ColourToHexString(col); } + + static bool HasParam(wxXmlNode* node, const wxString& param); + static wxXmlNode *GetParamNode(wxXmlNode* node, const wxString& param); + static wxString GetNodeContent(wxXmlNode *node); + static wxString GetParamValue(wxXmlNode *node, const wxString& param); + static wxString GetText(wxXmlNode *node, const wxString& param = wxEmptyString); + static wxXmlNode* FindNode(wxXmlNode* node, const wxString& name); + + static wxString AttributeToXML(const wxString& str); + + static bool RichTextFixFaceName(wxString& facename); + static long ColourStringToLong(const wxString& colStr); + static wxTextAttrDimension ParseDimension(const wxString& dimStr); + + // Make a string from the given property. This can be overridden for custom variants. + virtual wxString MakeStringFromProperty(const wxVariant& var); + + // Create a proprty from the string read from the XML file. + virtual wxVariant MakePropertyFromString(const wxString& name, const wxString& value, const wxString& type); + + // Import properties + virtual bool ImportProperties(wxRichTextProperties& properties, wxXmlNode* node); + + virtual bool ImportStyle(wxRichTextAttr& attr, wxXmlNode* node, bool isPara = false); + virtual bool ImportStyleDefinition(wxRichTextStyleSheet* sheet, wxXmlNode* node); + + // Get flags, as per handler flags + int GetFlags() const { return m_flags; } + void SetFlags(int flags) { m_flags = flags; } + +#if wxRICHTEXT_HAVE_DIRECT_OUTPUT + // write string to output + static void OutputString(wxOutputStream& stream, const wxString& str, + wxMBConv *convMem, wxMBConv *convFile); + + static void OutputIndentation(wxOutputStream& stream, int indent); + + // Same as above, but create entities first. + // Translates '<' to "<", '>' to ">" and '&' to "&" + static void OutputStringEnt(wxOutputStream& stream, const wxString& str, + wxMBConv *convMem, wxMBConv *convFile); + + void OutputString(wxOutputStream& stream, const wxString& str); + void OutputStringEnt(wxOutputStream& stream, const wxString& str); + + static void AddString(wxString& str, const int& v) { str << wxString::Format(wxT("%d"), v); } + static void AddString(wxString& str, const long& v) { str << wxString::Format(wxT("%ld"), v); } + static void AddString(wxString& str, const double& v) { str << wxString::Format(wxT("%.2f"), (float) v); } + static void AddString(wxString& str, const wxChar* s) { str << s; } + static void AddString(wxString& str, const wxString& s) { str << s; } + static void AddString(wxString& str, const wxColour& col) { str << wxT("#") << ColourToHexString(col); } + + static void AddAttribute(wxString& str, const wxString& name, const int& v); + static void AddAttribute(wxString& str, const wxString& name, const long& v); + static void AddAttribute(wxString& str, const wxString& name, const double& v); + static void AddAttribute(wxString& str, const wxString& name, const wxChar* s); + static void AddAttribute(wxString& str, const wxString& name, const wxString& s); + static void AddAttribute(wxString& str, const wxString& name, const wxColour& col); + static void AddAttribute(wxString& str, const wxString& name, const wxTextAttrDimension& dim); + static void AddAttribute(wxString& str, const wxString& rootName, const wxTextAttrDimensions& dims); + static void AddAttribute(wxString& str, const wxString& rootName, const wxTextAttrBorder& border); + static void AddAttribute(wxString& str, const wxString& rootName, const wxTextAttrBorders& borders); + + /// Create a string containing style attributes + static wxString AddAttributes(const wxRichTextAttr& attr, bool isPara = false); + virtual bool ExportStyleDefinition(wxOutputStream& stream, wxRichTextStyleDefinition* def, int level); + + virtual bool WriteProperties(wxOutputStream& stream, const wxRichTextProperties& properties, int level); +#endif + +#if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT + static void AddAttribute(wxXmlNode* node, const wxString& name, const int& v); + static void AddAttribute(wxXmlNode* node, const wxString& name, const long& v); + static void AddAttribute(wxXmlNode* node, const wxString& name, const double& v); + static void AddAttribute(wxXmlNode* node, const wxString& name, const wxString& s); + static void AddAttribute(wxXmlNode* node, const wxString& name, const wxColour& col); + static void AddAttribute(wxXmlNode* node, const wxString& name, const wxTextAttrDimension& dim); + static void AddAttribute(wxXmlNode* node, const wxString& rootName, const wxTextAttrDimensions& dims); + static void AddAttribute(wxXmlNode* node, const wxString& rootName, const wxTextAttrBorder& border); + static void AddAttribute(wxXmlNode* node, const wxString& rootName, const wxTextAttrBorders& borders); + + static bool AddAttributes(wxXmlNode* node, wxRichTextAttr& attr, bool isPara = false); + + virtual bool ExportStyleDefinition(wxXmlNode* parent, wxRichTextStyleDefinition* def); + + // Write the properties + virtual bool WriteProperties(wxXmlNode* node, const wxRichTextProperties& properties); +#endif + +public: + +#if wxRICHTEXT_HAVE_DIRECT_OUTPUT + // Used during saving + wxMBConv* m_convMem; + wxMBConv* m_convFile; + bool m_deleteConvFile; +#endif + + wxString m_fileEncoding; + int m_flags; +}; + +/*! + @class wxRichTextXMLHandler + + Implements XML loading and saving. Two methods of saving are included: + writing directly to a text stream, and populating an wxXmlDocument + before writing it. The former method is considerably faster, so we favour + that one, even though the code is a little less elegant. */ class WXDLLIMPEXP_FWD_XML wxXmlNode; @@ -43,36 +183,14 @@ public: #if wxRICHTEXT_HAVE_DIRECT_OUTPUT /// Recursively export an object bool ExportXML(wxOutputStream& stream, wxRichTextObject& obj, int level); - bool ExportStyleDefinition(wxOutputStream& stream, wxRichTextStyleDefinition* def, int level); - wxString AddAttributes(const wxRichTextAttr& attr, bool isPara = false); - bool WriteProperties(wxOutputStream& stream, const wxRichTextProperties& properties, int level); - void OutputString(wxOutputStream& stream, const wxString& str); - void OutputStringEnt(wxOutputStream& stream, const wxString& str); - void OutputIndentation(wxOutputStream& stream, int indent); - static wxString AttributeToXML(const wxString& str); #endif #if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT bool ExportXML(wxXmlNode* parent, wxRichTextObject& obj); - bool ExportStyleDefinition(wxXmlNode* parent, wxRichTextStyleDefinition* def); - bool AddAttributes(wxXmlNode* node, wxRichTextAttr& attr, bool isPara = false); - bool WriteProperties(wxXmlNode* node, const wxRichTextProperties& properties); #endif - /// Make a string from the given property. This can be overridden for custom variants. - virtual wxString MakeStringFromProperty(const wxVariant& var); - - /// Create a proprty from the string read from the XML file. - virtual wxVariant MakePropertyFromString(const wxString& name, const wxString& value, const wxString& type); - /// Recursively import an object bool ImportXML(wxRichTextBuffer* buffer, wxRichTextObject* obj, wxXmlNode* node); - bool ImportStyleDefinition(wxRichTextStyleSheet* sheet, wxXmlNode* node); - bool ImportProperties(wxRichTextObject* obj, wxXmlNode* node); - bool ImportProperties(wxRichTextProperties& properties, wxXmlNode* node); - - /// Import style parameters - bool ImportStyle(wxRichTextAttr& attr, wxXmlNode* node, bool isPara = false); #endif /// Creates an object given an XML element name @@ -84,19 +202,12 @@ public: /// Can we load using this handler? virtual bool CanLoad() const { return true; } - // Used during saving - wxMBConv* GetConvMem() const { return m_convMem; } - wxMBConv* GetConvFile() const { return m_convFile; } + /// Returns the XML helper object, implementing functionality + /// that can be reused elsewhere. + wxRichTextXMLHelper& GetHelper() { return m_helper; } // Implementation - bool HasParam(wxXmlNode* node, const wxString& param); - wxXmlNode *GetParamNode(wxXmlNode* node, const wxString& param); - wxString GetNodeContent(wxXmlNode *node); - wxString GetParamValue(wxXmlNode *node, const wxString& param); - wxString GetText(wxXmlNode *node, const wxString& param = wxEmptyString, bool translate = false); - static wxXmlNode* FindNode(wxXmlNode* node, const wxString& name); - /** Call with XML node name, C++ class name so that wxRTC can read in the node. If you add a custom object, call this. @@ -114,11 +225,7 @@ protected: virtual bool DoSaveFile(wxRichTextBuffer *buffer, wxOutputStream& stream); #endif -#if wxRICHTEXT_HAVE_DIRECT_OUTPUT - // Used during saving - wxMBConv* m_convMem; - wxMBConv* m_convFile; -#endif + wxRichTextXMLHelper m_helper; static wxStringToStringHashMap sm_nodeNameToClassMap; }; diff --git a/interface/wx/richtext/richtextxml.h b/interface/wx/richtext/richtextxml.h index aff5e56a8d..ccfd3b828c 100644 --- a/interface/wx/richtext/richtextxml.h +++ b/interface/wx/richtext/richtextxml.h @@ -53,33 +53,6 @@ public: */ bool ExportXML(wxOutputStream& stream, wxRichTextObject& obj, int level); - /** - Helper function: gets node context. - */ - wxString GetNodeContent(wxXmlNode* node); - - /** - Helper function: gets a named parameter from the XML node. - */ - wxXmlNode* GetParamNode(wxXmlNode* node, const wxString& param); - - /** - Helper function: gets a named parameter from the XML node. - */ - wxString GetParamValue(wxXmlNode* node, const wxString& param); - - /** - Helper function: gets text from the node. - */ - wxString GetText(wxXmlNode* node, - const wxString& param = wxEmptyString, - bool translate = false); - - /** - Helper function: returns @true if the node has the given parameter. - */ - bool HasParam(wxXmlNode* node, const wxString& param); - /** Recursively imports an object. */ diff --git a/src/richtext/richtextxml.cpp b/src/richtext/richtextxml.cpp index 2243f7c936..443a9c2145 100644 --- a/src/richtext/richtextxml.cpp +++ b/src/richtext/richtextxml.cpp @@ -35,6 +35,15 @@ #include "wx/stopwatch.h" #include "wx/xml/xml.h" +// For use with earlier versions of wxWidgets +#ifndef WXUNUSED_IN_UNICODE +#if wxUSE_UNICODE +#define WXUNUSED_IN_UNICODE(x) WXUNUSED(x) +#else +#define WXUNUSED_IN_UNICODE(x) x +#endif +#endif + // Set to 1 for slower wxXmlDocument method, 0 for faster direct method. // If we make wxXmlDocument::Save more efficient, we might switch to this // method. @@ -51,52 +60,12 @@ // Set to 1 to time file saving #define wxRICHTEXT_USE_OUTPUT_TIMINGS 0 -// Convert a colour to a 6-digit hex string -static wxString ColourToHexString(const wxColour& col) -{ - wxString hex; - - hex += wxDecToHex(col.Red()); - hex += wxDecToHex(col.Green()); - hex += wxDecToHex(col.Blue()); - - return hex; -} - -// Convert 6-digit hex string to a colour -static wxColour HexStringToColour(const wxString& hex) -{ - unsigned char r = (unsigned char)wxHexToDec(hex.Mid(0, 2)); - unsigned char g = (unsigned char)wxHexToDec(hex.Mid(2, 2)); - unsigned char b = (unsigned char)wxHexToDec(hex.Mid(4, 2)); - - return wxColour(r, g, b); -} - -static inline wxString MakeString(const int& v) { return wxString::Format(wxT("%d"), v); } -static inline wxString MakeString(const long& v) { return wxString::Format(wxT("%ld"), v); } -static inline wxString MakeString(const double& v) { return wxString::Format(wxT("%.2f"), (float) v); } -static inline wxString MakeString(const wxString& s) { return s; } -static inline wxString MakeString(const wxColour& col) { return wxT("#") + ColourToHexString(col); } - -static inline void AddString(wxString& str, const int& v) { str << wxString::Format(wxT("%d"), v); } -static inline void AddString(wxString& str, const long& v) { str << wxString::Format(wxT("%ld"), v); } -static inline void AddString(wxString& str, const double& v) { str << wxString::Format(wxT("%.2f"), (float) v); } -static inline void AddString(wxString& str, const wxChar* s) { str << s; } -static inline void AddString(wxString& str, const wxString& s) { str << s; } -static inline void AddString(wxString& str, const wxColour& col) { str << wxT("#") << ColourToHexString(col); } - IMPLEMENT_DYNAMIC_CLASS(wxRichTextXMLHandler, wxRichTextFileHandler) wxStringToStringHashMap wxRichTextXMLHandler::sm_nodeNameToClassMap; void wxRichTextXMLHandler::Init() { -#if wxRICHTEXT_HAVE_DIRECT_OUTPUT - // Used during saving - m_convMem = NULL; - m_convFile = NULL; -#endif } #if wxUSE_STREAMS @@ -105,6 +74,8 @@ bool wxRichTextXMLHandler::DoLoadFile(wxRichTextBuffer *buffer, wxInputStream& s if (!stream.IsOk()) return false; + m_helper.SetFlags(GetFlags()); + buffer->ResetAndClearCommands(); buffer->Clear(); @@ -197,1397 +168,1107 @@ bool wxRichTextXMLHandler::ImportXML(wxRichTextBuffer* buffer, wxRichTextObject* return true; } -bool wxRichTextXMLHandler::ImportProperties(wxRichTextObject* obj, wxXmlNode* node) +bool wxRichTextXMLHandler::DoSaveFile(wxRichTextBuffer *buffer, wxOutputStream& stream) { - return ImportProperties(obj->GetProperties(), node); -} + if (!stream.IsOk()) + return false; -bool wxRichTextXMLHandler::ImportProperties(wxRichTextProperties& properties, wxXmlNode* node) -{ - wxXmlNode* child = node->GetChildren(); - while (child) - { - if (child->GetName() == wxT("properties")) - { - wxXmlNode* propertyChild = child->GetChildren(); - while (propertyChild) - { - if (propertyChild->GetName() == wxT("property")) - { - wxString name = propertyChild->GetAttribute(wxT("name"), wxEmptyString); - wxString value = propertyChild->GetAttribute(wxT("value"), wxEmptyString); - wxString type = propertyChild->GetAttribute(wxT("type"), wxEmptyString); + m_helper.SetupForSaving(m_encoding); + m_helper.SetFlags(GetFlags()); - wxVariant var = MakePropertyFromString(name, value, type); - if (!var.IsNull()) - { - properties.SetProperty(var); - } - } - propertyChild = propertyChild->GetNext(); - } - } - child = child->GetNext(); - } - return true; -} + wxString version(wxT("1.0") ) ; -bool wxRichTextXMLHandler::ImportStyleDefinition(wxRichTextStyleSheet* sheet, wxXmlNode* node) -{ - wxString styleType = node->GetName(); - wxString styleName = node->GetAttribute(wxT("name"), wxEmptyString); - wxString baseStyleName = node->GetAttribute(wxT("basestyle"), wxEmptyString); + wxString fileEncoding = m_helper.GetFileEncoding(); - if (styleName.empty()) - return false; +#if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT && wxRICHTEXT_USE_XMLDOCUMENT_OUTPUT +#if wxRICHTEXT_USE_OUTPUT_TIMINGS + wxStopWatch stopwatch; +#endif + wxXmlDocument* doc = new wxXmlDocument; + doc->SetFileEncoding(fileEncoding); - if (styleType == wxT("characterstyle")) + wxXmlNode* rootNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("richtext")); + doc->SetRoot(rootNode); + rootNode->AddAttribute(wxT("version"), wxT("1.0.0.0")); + rootNode->AddAttribute(wxT("xmlns"), wxT("http://www.wxwidgets.org")); + + if (buffer->GetStyleSheet() && (GetFlags() & wxRICHTEXT_HANDLER_INCLUDE_STYLESHEET)) { - wxRichTextCharacterStyleDefinition* def = new wxRichTextCharacterStyleDefinition(styleName); - def->SetBaseStyle(baseStyleName); + wxXmlNode* styleSheetNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("stylesheet")); + rootNode->AddChild(styleSheetNode); - wxXmlNode* child = node->GetChildren(); - while (child) - { - if (child->GetName() == wxT("style")) - { - wxRichTextAttr attr; - ImportStyle(attr, child, false); - def->SetStyle(attr); - } - child = child->GetNext(); - } + wxString nameAndDescr; - ImportProperties(def->GetProperties(), node); + if (!buffer->GetStyleSheet()->GetName().empty()) + styleSheetNode->AddAttribute(wxT("name"), buffer->GetStyleSheet()->GetName()); - sheet->AddCharacterStyle(def); - } - else if (styleType == wxT("paragraphstyle")) - { - wxRichTextParagraphStyleDefinition* def = new wxRichTextParagraphStyleDefinition(styleName); + if (!buffer->GetStyleSheet()->GetDescription().empty()) + styleSheetNode->AddAttribute(wxT("description"), buffer->GetStyleSheet()->GetDescription()); - wxString nextStyleName = node->GetAttribute(wxT("nextstyle"), wxEmptyString); - def->SetNextStyle(nextStyleName); - def->SetBaseStyle(baseStyleName); + int i; + for (i = 0; i < (int) buffer->GetStyleSheet()->GetCharacterStyleCount(); i++) + { + wxRichTextCharacterStyleDefinition* def = buffer->GetStyleSheet()->GetCharacterStyle(i); + m_helper.ExportStyleDefinition(styleSheetNode, def); + } - wxXmlNode* child = node->GetChildren(); - while (child) + for (i = 0; i < (int) buffer->GetStyleSheet()->GetParagraphStyleCount(); i++) { - if (child->GetName() == wxT("style")) - { - wxRichTextAttr attr; - ImportStyle(attr, child, true); - def->SetStyle(attr); - } - child = child->GetNext(); + wxRichTextParagraphStyleDefinition* def = buffer->GetStyleSheet()->GetParagraphStyle(i); + m_helper.ExportStyleDefinition(styleSheetNode, def); } - ImportProperties(def->GetProperties(), node); + for (i = 0; i < (int) buffer->GetStyleSheet()->GetListStyleCount(); i++) + { + wxRichTextListStyleDefinition* def = buffer->GetStyleSheet()->GetListStyle(i); + m_helper.ExportStyleDefinition(styleSheetNode, def); + } - sheet->AddParagraphStyle(def); + for (i = 0; i < (int) buffer->GetStyleSheet()->GetBoxStyleCount(); i++) + { + wxRichTextBoxStyleDefinition* def = buffer->GetStyleSheet()->GetBoxStyle(i); + m_helper.ExportStyleDefinition(styleSheetNode, def); + } + + m_helper.WriteProperties(styleSheetNode, buffer->GetStyleSheet()->GetProperties()); } - else if (styleType == wxT("boxstyle")) + bool success = ExportXML(rootNode, *buffer); +#if wxRICHTEXT_USE_OUTPUT_TIMINGS + long t = stopwatch.Time(); + wxLogDebug(wxT("Creating the document took %ldms"), t); + wxMessageBox(wxString::Format(wxT("Creating the document took %ldms"), t)); +#endif + if (success) { - wxRichTextBoxStyleDefinition* def = new wxRichTextBoxStyleDefinition(styleName); +#if wxRICHTEXT_USE_OUTPUT_TIMINGS + wxStopWatch s2; +#endif + success = doc->Save(stream); +#if wxRICHTEXT_USE_OUTPUT_TIMINGS + long t2 = s2.Time(); + wxLogDebug(wxT("Save() took %ldms"), t2); + wxMessageBox(wxString::Format(wxT("Save() took %ldms"), t2)); +#endif + } + delete doc; + doc = NULL; - def->SetBaseStyle(baseStyleName); +#else + // !(wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT && wxRICHTEXT_USE_XMLDOCUMENT_OUTPUT) - wxXmlNode* child = node->GetChildren(); - while (child) - { - if (child->GetName() == wxT("style")) - { - wxRichTextAttr attr; - ImportStyle(attr, child, true); - def->SetStyle(attr); - } - child = child->GetNext(); - } + wxString s ; + s.Printf(wxT("\n"), + version.c_str(), fileEncoding.c_str()); + m_helper.OutputString(stream, s); + m_helper.OutputString(stream, wxT("")); - ImportProperties(def->GetProperties(), node); + int level = 1; - sheet->AddBoxStyle(def); - } - else if (styleType == wxT("liststyle")) + if (buffer->GetStyleSheet() && (GetFlags() & wxRICHTEXT_HANDLER_INCLUDE_STYLESHEET)) { - wxRichTextListStyleDefinition* def = new wxRichTextListStyleDefinition(styleName); + m_helper.OutputIndentation(stream, level); + wxString nameAndDescr; + if (!buffer->GetStyleSheet()->GetName().empty()) + nameAndDescr << wxT(" name=\"") << buffer->GetStyleSheet()->GetName() << wxT("\""); + if (!buffer->GetStyleSheet()->GetDescription().empty()) + nameAndDescr << wxT(" description=\"") << buffer->GetStyleSheet()->GetDescription() << wxT("\""); + m_helper.OutputString(stream, wxString(wxT("")); - wxString nextStyleName = node->GetAttribute(wxT("nextstyle"), wxEmptyString); - def->SetNextStyle(nextStyleName); - def->SetBaseStyle(baseStyleName); + int i; - wxXmlNode* child = node->GetChildren(); - while (child) + for (i = 0; i < (int) buffer->GetStyleSheet()->GetCharacterStyleCount(); i++) { - if (child->GetName() == wxT("style")) - { - wxRichTextAttr attr; - ImportStyle(attr, child, true); + wxRichTextCharacterStyleDefinition* def = buffer->GetStyleSheet()->GetCharacterStyle(i); + m_helper.ExportStyleDefinition(stream, def, level + 1); + } - wxString styleLevel = child->GetAttribute(wxT("level"), wxEmptyString); - if (styleLevel.empty()) - { - def->SetStyle(attr); - } - else - { - int level = wxAtoi(styleLevel); - if (level > 0 && level <= 10) - { - def->SetLevelAttributes(level-1, attr); - } - } - } - child = child->GetNext(); + for (i = 0; i < (int) buffer->GetStyleSheet()->GetParagraphStyleCount(); i++) + { + wxRichTextParagraphStyleDefinition* def = buffer->GetStyleSheet()->GetParagraphStyle(i); + m_helper.ExportStyleDefinition(stream, def, level + 1); } - ImportProperties(def->GetProperties(), node); + for (i = 0; i < (int) buffer->GetStyleSheet()->GetListStyleCount(); i++) + { + wxRichTextListStyleDefinition* def = buffer->GetStyleSheet()->GetListStyle(i); + m_helper.ExportStyleDefinition(stream, def, level + 1); + } - sheet->AddListStyle(def); + for (i = 0; i < (int) buffer->GetStyleSheet()->GetBoxStyleCount(); i++) + { + wxRichTextBoxStyleDefinition* def = buffer->GetStyleSheet()->GetBoxStyle(i); + m_helper.ExportStyleDefinition(stream, def, level + 1); + } + + m_helper.WriteProperties(stream, buffer->GetStyleSheet()->GetProperties(), level); + + m_helper.OutputIndentation(stream, level); + m_helper.OutputString(stream, wxT("")); } - return true; -} -//----------------------------------------------------------------------------- -// xml support routines -//----------------------------------------------------------------------------- + bool success = ExportXML(stream, *buffer, level); -bool wxRichTextXMLHandler::HasParam(wxXmlNode* node, const wxString& param) -{ - return (GetParamNode(node, param) != NULL); + m_helper.OutputString(stream, wxT("\n")); + m_helper.OutputString(stream, wxT("\n")); +#endif + + return success; } -wxXmlNode *wxRichTextXMLHandler::GetParamNode(wxXmlNode* node, const wxString& param) +#if wxRICHTEXT_HAVE_DIRECT_OUTPUT + +/// Recursively export an object +bool wxRichTextXMLHandler::ExportXML(wxOutputStream& stream, wxRichTextObject& obj, int indent) { - wxCHECK_MSG(node, NULL, wxT("You can't access node data before it was initialized!")); + obj.ExportXML(stream, indent, this); - wxXmlNode *n = node->GetChildren(); - - while (n) - { - if (n->GetType() == wxXML_ELEMENT_NODE && n->GetName() == param) - return n; - n = n->GetNext(); - } - return NULL; -} + return true; +} +#endif + // wxRICHTEXT_HAVE_DIRECT_OUTPUT -wxString wxRichTextXMLHandler::GetNodeContent(wxXmlNode *node) +#if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT +bool wxRichTextXMLHandler::ExportXML(wxXmlNode* parent, wxRichTextObject& obj) { - wxXmlNode *n = node; - if (n == NULL) return wxEmptyString; - n = n->GetChildren(); + obj.ExportXML(parent, this); - while (n) - { - if (n->GetType() == wxXML_TEXT_NODE || - n->GetType() == wxXML_CDATA_SECTION_NODE) - return n->GetContent(); - n = n->GetNext(); - } - return wxEmptyString; + return true; } +#endif + // wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT -wxString wxRichTextXMLHandler::GetParamValue(wxXmlNode *node, const wxString& param) -{ - if (param.empty()) - return GetNodeContent(node); - else - return GetNodeContent(GetParamNode(node, param)); -} +#endif + // wxUSE_STREAMS -wxString wxRichTextXMLHandler::GetText(wxXmlNode *node, const wxString& param, bool WXUNUSED(translate)) +// Import this object from XML +bool wxRichTextObject::ImportFromXML(wxRichTextBuffer* WXUNUSED(buffer), wxXmlNode* node, wxRichTextXMLHandler* handler, bool* recurse) { - wxXmlNode *parNode = GetParamNode(node, param); - if (!parNode) - parNode = node; - wxString str1(GetNodeContent(parNode)); - return str1; + handler->GetHelper().ImportProperties(GetProperties(), node); + handler->GetHelper().ImportStyle(GetAttributes(), node, UsesParagraphAttributes()); + + *recurse = true; + + return true; } -wxXmlNode* wxRichTextXMLHandler::FindNode(wxXmlNode* node, const wxString& name) +#if wxRICHTEXT_HAVE_DIRECT_OUTPUT +// Export this object directly to the given stream. +bool wxRichTextObject::ExportXML(wxOutputStream& stream, int indent, wxRichTextXMLHandler* handler) { - if (node->GetName() == name && name == wxT("stylesheet")) - return node; + handler->GetHelper().OutputIndentation(stream, indent); + handler->GetHelper().OutputString(stream, wxT("<") + GetXMLNodeName()); - wxXmlNode* child = node->GetChildren(); - while (child) - { - if (child->GetName() == name) - return child; - child = child->GetNext(); - } - return NULL; -} + wxString style = handler->GetHelper().AddAttributes(GetAttributes(), true); -// For use with earlier versions of wxWidgets -#ifndef WXUNUSED_IN_UNICODE -#if wxUSE_UNICODE -#define WXUNUSED_IN_UNICODE(x) WXUNUSED(x) -#else -#define WXUNUSED_IN_UNICODE(x) x -#endif -#endif + handler->GetHelper().OutputString(stream, style + wxT(">")); -// write string to output -inline static void OutputString(wxOutputStream& stream, const wxString& str, - wxMBConv *WXUNUSED_IN_UNICODE(convMem), wxMBConv *convFile) -{ - if (str.empty()) return; -#if wxUSE_UNICODE - if (convFile) - { - const wxWX2MBbuf buf(str.mb_str(*convFile)); - stream.Write((const char*)buf, strlen((const char*)buf)); - } - else + if (GetProperties().GetCount() > 0) { - const wxWX2MBbuf buf(str.mb_str(wxConvUTF8)); - stream.Write((const char*)buf, strlen((const char*)buf)); + handler->GetHelper().WriteProperties(stream, GetProperties(), indent); } -#else - if ( convFile == NULL ) - stream.Write(str.mb_str(), str.Len()); - else + + wxRichTextCompositeObject* composite = wxDynamicCast(this, wxRichTextCompositeObject); + if (composite) { - wxString str2(str.wc_str(*convMem), *convFile); - stream.Write(str2.mb_str(), str2.Len()); + size_t i; + for (i = 0; i < composite->GetChildCount(); i++) + { + wxRichTextObject* child = composite->GetChild(i); + child->ExportXML(stream, indent+1, handler); + } } -#endif + + handler->GetHelper().OutputIndentation(stream, indent); + handler->GetHelper().OutputString(stream, wxT("")); + return true; } +#endif -static void OutputIndentation(wxOutputStream& stream, int indent) +#if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT +// Export this object to the given parent node, usually creating at least one child node. +bool wxRichTextObject::ExportXML(wxXmlNode* parent, wxRichTextXMLHandler* handler) { - wxString str = wxT("\n"); - for (int i = 0; i < indent; i++) - str << wxT(' ') << wxT(' '); - ::OutputString(stream, str, NULL, NULL); + wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, GetXMLNodeName()); + parent->AddChild(elementNode); + handler->GetHelper().AddAttributes(elementNode, GetAttributes(), true); + handler->GetHelper().WriteProperties(elementNode, GetProperties()); + + wxRichTextCompositeObject* composite = wxDynamicCast(this, wxRichTextCompositeObject); + if (composite) + { + size_t i; + for (i = 0; i < composite->GetChildCount(); i++) + { + wxRichTextObject* child = composite->GetChild(i); + child->ExportXML(elementNode, handler); + } + } + return true; } +#endif -// Same as above, but create entities first. -// Translates '<' to "<", '>' to ">" and '&' to "&" -static void OutputStringEnt(wxOutputStream& stream, const wxString& str, - wxMBConv *convMem = NULL, wxMBConv *convFile = NULL) +// Import this object from XML +bool wxRichTextPlainText::ImportFromXML(wxRichTextBuffer* buffer, wxXmlNode* node, wxRichTextXMLHandler* handler, bool* recurse) { - wxString buf; - size_t i, last, len; - wxChar c; + wxRichTextObject::ImportFromXML(buffer, node, handler, recurse); - len = str.Len(); - last = 0; - for (i = 0; i < len; i++) + if (node->GetName() == wxT("text")) { - c = str.GetChar(i); + wxString text; + wxXmlNode* textChild = node->GetChildren(); + while (textChild) + { + if (textChild->GetType() == wxXML_TEXT_NODE || + textChild->GetType() == wxXML_CDATA_SECTION_NODE) + { + wxString text2 = textChild->GetContent(); - // Original code excluded "&" but we _do_ want to convert - // the ampersand beginning & because otherwise when read in, - // the original "&" becomes "&". + // Strip whitespace from end + if (!text2.empty() && text2[text2.length()-1] == wxT('\n')) + text2 = text2.Mid(0, text2.length()-1); - if (c == wxT('<') || c == wxT('>') || c == wxT('"') || - (c == wxT('&') /* && (str.Mid(i+1, 4) != wxT("amp;")) */ )) + if (!text2.empty() && text2[0] == wxT('"')) + text2 = text2.Mid(1); + if (!text2.empty() && text2[text2.length()-1] == wxT('"')) + text2 = text2.Mid(0, text2.length() - 1); + + text += text2; + } + textChild = textChild->GetNext(); + } + + SetText(text); + } + else if (node->GetName() == wxT("symbol")) + { + // This is a symbol that XML can't read in the normal way + wxString text; + wxXmlNode* textChild = node->GetChildren(); + while (textChild) { - OutputString(stream, str.Mid(last, i - last), convMem, convFile); - switch (c) + if (textChild->GetType() == wxXML_TEXT_NODE || + textChild->GetType() == wxXML_CDATA_SECTION_NODE) { - case wxT('<'): - OutputString(stream, wxT("<"), NULL, NULL); - break; - case wxT('>'): - OutputString(stream, wxT(">"), NULL, NULL); - break; - case wxT('&'): - OutputString(stream, wxT("&"), NULL, NULL); - break; - case wxT('"'): - OutputString(stream, wxT("""), NULL, NULL); - break; - default: break; + wxString text2 = textChild->GetContent(); + text += text2; } - last = i + 1; + textChild = textChild->GetNext(); } - else if (wxUChar(c) > 127) - { - OutputString(stream, str.Mid(last, i - last), convMem, convFile); - wxString s(wxT("&#")); -#if wxUSE_UNICODE - s << (int) c; -#else - s << (int) wxUChar(c); -#endif - s << wxT(";"); - OutputString(stream, s, NULL, NULL); - last = i + 1; - } + wxString actualText; + actualText << (wxChar) wxAtoi(text); + SetText(actualText); } - OutputString(stream, str.Mid(last, i - last), convMem, convFile); -} - -void wxRichTextXMLHandler::OutputString(wxOutputStream& stream, const wxString& str) -{ - ::OutputString(stream, str, m_convMem, m_convFile); -} + else + return false; -void wxRichTextXMLHandler::OutputStringEnt(wxOutputStream& stream, const wxString& str) -{ - ::OutputStringEnt(stream, str, m_convMem, m_convFile); + return true; } -void wxRichTextXMLHandler::OutputIndentation(wxOutputStream& stream, int indent) +#if wxRICHTEXT_HAVE_DIRECT_OUTPUT +// Export this object directly to the given stream. +bool wxRichTextPlainText::ExportXML(wxOutputStream& stream, int indent, wxRichTextXMLHandler* handler) { - wxString str = wxT("\n"); - for (int i = 0; i < indent; i++) - str << wxT(' ') << wxT(' '); - ::OutputString(stream, str, NULL, NULL); -} + wxString style = handler->GetHelper().AddAttributes(GetAttributes(), false); -wxString wxRichTextXMLHandler::AttributeToXML(const wxString& str) -{ - wxString str1; - size_t i, last, len; - wxChar c; + int i; + int last = 0; + const wxString& text = GetText(); + int len = (int) text.Length(); - len = str.Len(); - last = 0; - for (i = 0; i < len; i++) + if (len == 0) { - c = str.GetChar(i); - - // Original code excluded "&" but we _do_ want to convert - // the ampersand beginning & because otherwise when read in, - // the original "&" becomes "&". - - if (c == wxT('<') || c == wxT('>') || c == wxT('"') || - (c == wxT('&') /* && (str.Mid(i+1, 4) != wxT("amp;")) */ )) + i = 0; + handler->GetHelper().OutputIndentation(stream, indent); + handler->GetHelper().OutputString(stream, wxT("GetHelper().OutputString(stream, style + wxT(">")); + if (GetProperties().GetCount() > 0) { - str1 += str.Mid(last, i - last); - switch (c) - { - case wxT('<'): - str1 += wxT("<"); - break; - case wxT('>'): - str1 += wxT(">"); - break; - case wxT('&'): - str1 += wxT("&"); - break; - case wxT('"'): - str1 += wxT("""); - break; - default: break; - } - last = i + 1; + handler->GetHelper().WriteProperties(stream, GetProperties(), indent); + handler->GetHelper().OutputIndentation(stream, indent); } - else if (wxUChar(c) > 127) - { - str1 += str.Mid(last, i - last); - - wxString s(wxT("&#")); + handler->GetHelper().OutputString(stream, wxT("")); + } + else for (i = 0; i < len; i++) + { #if wxUSE_UNICODE - s << (int) c; + int c = (int) text[i]; #else - s << (int) wxUChar(c); + int c = (int) wxUChar(text[i]); #endif - s << wxT(";"); - str1 += s; + if ((c < 32 || c == 34) && /* c != 9 && */ c != 10 && c != 13) + { + if (i > 0) + { + wxString fragment(text.Mid(last, i-last)); + if (!fragment.empty()) + { + handler->GetHelper().OutputIndentation(stream, indent); + handler->GetHelper().OutputString(stream, wxT("GetHelper().OutputString(stream, style + wxT(">")); + + if (!fragment.empty() && (fragment[0] == wxT(' ') || fragment[fragment.length()-1] == wxT(' '))) + { + handler->GetHelper().OutputString(stream, wxT("\"")); + handler->GetHelper().OutputStringEnt(stream, fragment); + handler->GetHelper().OutputString(stream, wxT("\"")); + } + else + handler->GetHelper().OutputStringEnt(stream, fragment); + + if (GetProperties().GetCount() > 0) + { + handler->GetHelper().WriteProperties(stream, GetProperties(), indent); + handler->GetHelper().OutputIndentation(stream, indent); + } + handler->GetHelper().OutputString(stream, wxT("")); + } + } + + // Output this character as a number in a separate tag, because XML can't cope + // with entities below 32 except for 10 and 13 last = i + 1; + handler->GetHelper().OutputIndentation(stream, indent); + handler->GetHelper().OutputString(stream, wxT("GetHelper().OutputString(stream, style + wxT(">")); + handler->GetHelper().OutputString(stream, wxString::Format(wxT("%d"), c)); + + if (GetProperties().GetCount() > 0) + { + handler->GetHelper().WriteProperties(stream, GetProperties(), indent); + handler->GetHelper().OutputIndentation(stream, indent); + } + handler->GetHelper().OutputString(stream, wxT("")); } } - str1 += str.Mid(last, i - last); - return str1; -} -#if wxRICHTEXT_HAVE_DIRECT_OUTPUT + wxString fragment; + if (last == 0) + fragment = text; + else + fragment = text.Mid(last, i-last); -static inline void AddAttribute(wxString& str, const wxString& name, const int& v) -{ - str << wxT(" ") << name << wxT("=\"") << wxString::Format(wxT("%d"), v) << wxT("\""); -} + if (last < len) + { + handler->GetHelper().OutputIndentation(stream, indent); + handler->GetHelper().OutputString(stream, wxT("GetHelper().OutputString(stream, style + wxT(">")); -static inline void AddAttribute(wxString& str, const wxString& name, const double& v) -{ - str << wxT(" ") << name << wxT("=\"") << wxString::Format(wxT("%.2f"), (float) v) << wxT("\""); -} + if (GetProperties().GetCount() > 0) + { + handler->GetHelper().WriteProperties(stream, GetProperties(), indent); + handler->GetHelper().OutputIndentation(stream, indent); + } -static inline void AddAttribute(wxString& str, const wxString& name, const wxChar* s) -{ - str << wxT(" ") << name << wxT("=\"") << s << wxT("\""); -} + if (!fragment.empty() && (fragment[0] == wxT(' ') || fragment[fragment.length()-1] == wxT(' '))) + { + handler->GetHelper().OutputString(stream, wxT("\"")); + handler->GetHelper().OutputStringEnt(stream, fragment); + handler->GetHelper().OutputString(stream, wxT("\"")); + } + else + handler->GetHelper().OutputStringEnt(stream, fragment); -static inline void AddAttribute(wxString& str, const wxString& name, const wxString& s) -{ - str << wxT(" ") << name << wxT("=\"") << s << wxT("\""); + handler->GetHelper().OutputString(stream, wxT("")); + } + return true; } +#endif -static inline void AddAttribute(wxString& str, const wxString& name, const wxColour& col) +#if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT +// Export this object to the given parent node, usually creating at least one child node. +bool wxRichTextPlainText::ExportXML(wxXmlNode* parent, wxRichTextXMLHandler* handler) { - str << wxT(" ") << name << wxT("=\"") << wxT("#") << ColourToHexString(col) << wxT("\""); -} + int i; + int last = 0; + const wxString& text = GetText(); + int len = (int) text.Length(); -static inline void AddAttribute(wxString& str, const wxString& name, const wxTextAttrDimension& dim) -{ - if (dim.IsValid()) + if (len == 0) { - wxString value = MakeString(dim.GetValue()) + wxT(",") + MakeString((int) dim.GetFlags()); - str << wxT(" ") << name << wxT("=\""); - str << value; - str << wxT("\""); - } -} + i = 0; -static inline void AddAttribute(wxString& str, const wxString& rootName, const wxTextAttrDimensions& dims) -{ - if (dims.GetLeft().IsValid()) - AddAttribute(str, rootName + wxString(wxT("-left")), dims.GetLeft()); - if (dims.GetRight().IsValid()) - AddAttribute(str, rootName + wxString(wxT("-right")), dims.GetRight()); - if (dims.GetTop().IsValid()) - AddAttribute(str, rootName + wxString(wxT("-top")), dims.GetTop()); - if (dims.GetBottom().IsValid()) - AddAttribute(str, rootName + wxString(wxT("-bottom")), dims.GetBottom()); -} + wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("text")); + parent->AddChild(elementNode); -static inline void AddAttribute(wxString& str, const wxString& rootName, const wxTextAttrBorder& border) -{ - if (border.HasStyle()) - AddAttribute(str, rootName + wxString(wxT("-style")), border.GetStyle()); - if (border.HasColour()) - AddAttribute(str, rootName + wxString(wxT("-color")), border.GetColour()); - if (border.HasWidth()) - AddAttribute(str, rootName + wxString(wxT("-width")), border.GetWidth()); -} + handler->GetHelper().AddAttributes(elementNode, GetAttributes(), false); + handler->GetHelper().WriteProperties(elementNode, GetProperties()); + } + else for (i = 0; i < len; i++) + { +#if wxUSE_UNICODE + int c = (int) text[i]; +#else + int c = (int) wxUChar(text[i]); +#endif + if ((c < 32 || c == 34) && c != 10 && c != 13) + { + if (i > 0) + { + wxString fragment(text.Mid(last, i-last)); + if (!fragment.empty()) + { + // TODO: I'm assuming wxXmlDocument will output quotes if necessary + wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("text")); + parent->AddChild(elementNode); + handler->GetHelper().AddAttributes(elementNode, GetAttributes(), false); + handler->GetHelper().WriteProperties(elementNode, GetProperties()); -static inline void AddAttribute(wxString& str, const wxString& rootName, const wxTextAttrBorders& borders) -{ - AddAttribute(str, rootName + wxString(wxT("-left")), borders.GetLeft()); - AddAttribute(str, rootName + wxString(wxT("-right")), borders.GetRight()); - AddAttribute(str, rootName + wxString(wxT("-top")), borders.GetTop()); - AddAttribute(str, rootName + wxString(wxT("-bottom")), borders.GetBottom()); -} + wxXmlNode* textNode = new wxXmlNode(wxXML_TEXT_NODE, wxT("text")); + elementNode->AddChild(textNode); -#endif - // wxRICHTEXT_HAVE_DIRECT_OUTPUT + if (fragment[0] == wxT(' ') || fragment[fragment.length()-1] == wxT(' ')) + fragment = wxT("\"") + fragment + wxT("\""); -#if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT + textNode->SetContent(fragment); + } + } -static inline void AddAttribute(wxXmlNode* node, const wxString& name, const int& v) -{ - node->AddAttribute(name, MakeString(v)); -} + // Output this character as a number in a separate tag, because XML can't cope + // with entities below 32 except for 10 and 13 -static inline void AddAttribute(wxXmlNode* node, const wxString& name, const long& v) -{ - node->AddAttribute(name, MakeString(v)); -} + wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("symbol")); + parent->AddChild(elementNode); -static inline void AddAttribute(wxXmlNode* node, const wxString& name, const double& v) -{ - node->AddAttribute(name, MakeString(v)); -} + handler->GetHelper().AddAttributes(elementNode, GetAttributes(), false); + handler->GetHelper().WriteProperties(elementNode, GetProperties()); -static inline void AddAttribute(wxXmlNode* node, const wxString& name, const wxString& s) -{ - node->AddAttribute(name, s); -} + wxXmlNode* textNode = new wxXmlNode(wxXML_TEXT_NODE, wxT("text")); + elementNode->AddChild(textNode); + textNode->SetContent(wxString::Format(wxT("%d"), c)); -static inline void AddAttribute(wxXmlNode* node, const wxString& name, const wxColour& col) -{ - node->AddAttribute(name, MakeString(col)); -} + last = i + 1; + } + } -static inline void AddAttribute(wxXmlNode* node, const wxString& name, const wxTextAttrDimension& dim) -{ - if (dim.IsValid()) + wxString fragment; + if (last == 0) + fragment = text; + else + fragment = text.Mid(last, i-last); + + if (last < len) { - wxString value = MakeString(dim.GetValue()) + wxT(",") + MakeString(dim.GetFlags()); - AddAttribute(node, name, value); - } -} + wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("text")); + parent->AddChild(elementNode); + handler->GetHelper().AddAttributes(elementNode, GetAttributes(), false); -static inline void AddAttribute(wxXmlNode* node, const wxString& rootName, const wxTextAttrDimensions& dims) -{ - if (dims.GetLeft().IsValid()) - AddAttribute(node, rootName + wxString(wxT("-left")), dims.GetLeft()); - if (dims.GetRight().IsValid()) - AddAttribute(node, rootName + wxString(wxT("-right")), dims.GetRight()); - if (dims.GetTop().IsValid()) - AddAttribute(node, rootName + wxString(wxT("-top")), dims.GetTop()); - if (dims.GetBottom().IsValid()) - AddAttribute(node, rootName + wxString(wxT("-bottom")), dims.GetBottom()); -} + wxXmlNode* textNode = new wxXmlNode(wxXML_TEXT_NODE, wxT("text")); + elementNode->AddChild(textNode); -static inline void AddAttribute(wxXmlNode* node, const wxString& rootName, const wxTextAttrBorder& border) -{ - if (border.HasStyle()) - AddAttribute(node, rootName + wxString(wxT("-style")), border.GetStyle()); - if (border.HasColour()) - AddAttribute(node, rootName + wxString(wxT("-color")), border.GetColour()); - if (border.HasWidth()) - AddAttribute(node, rootName + wxString(wxT("-width")), border.GetWidth()); -} + if (fragment[0] == wxT(' ') || fragment[fragment.length()-1] == wxT(' ')) + fragment = wxT("\"") + fragment + wxT("\""); -static inline void AddAttribute(wxXmlNode* node, const wxString& rootName, const wxTextAttrBorders& borders) -{ - AddAttribute(node, rootName + wxString(wxT("-left")), borders.GetLeft()); - AddAttribute(node, rootName + wxString(wxT("-right")), borders.GetRight()); - AddAttribute(node, rootName + wxString(wxT("-top")), borders.GetTop()); - AddAttribute(node, rootName + wxString(wxT("-bottom")), borders.GetBottom()); + textNode->SetContent(fragment); + } + return true; } #endif - // wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT -bool wxRichTextXMLHandler::DoSaveFile(wxRichTextBuffer *buffer, wxOutputStream& stream) +// Import this object from XML +bool wxRichTextImage::ImportFromXML(wxRichTextBuffer* buffer, wxXmlNode* node, wxRichTextXMLHandler* handler, bool* recurse) { - if (!stream.IsOk()) - return false; - - wxString version(wxT("1.0") ) ; - - bool deleteConvFile = false; - wxString fileEncoding; - //wxMBConv* convFile = NULL; - -#if wxUSE_UNICODE - fileEncoding = wxT("UTF-8"); - m_convFile = & wxConvUTF8; -#else - fileEncoding = wxT("ISO-8859-1"); - m_convFile = & wxConvISO8859_1; -#endif + wxRichTextObject::ImportFromXML(buffer, node, handler, recurse); - // If SetEncoding has been called, change the output encoding. - if (!m_encoding.empty() && m_encoding.Lower() != fileEncoding.Lower()) + wxBitmapType imageType = wxBITMAP_TYPE_PNG; + wxString value = node->GetAttribute(wxT("imagetype"), wxEmptyString); + if (!value.empty()) { - if (m_encoding == wxT("")) + int type = wxAtoi(value); + + // note: 0 == wxBITMAP_TYPE_INVALID + if (type <= 0 || type >= wxBITMAP_TYPE_MAX) { -#if wxUSE_INTL - fileEncoding = wxLocale::GetSystemEncodingName(); - // if !wxUSE_INTL, we fall back to UTF-8 or ISO-8859-1 below -#endif + wxLogWarning("Invalid bitmap type specified for tag: %d", type); } else { - fileEncoding = m_encoding; + imageType = (wxBitmapType)type; } + } - // GetSystemEncodingName may not have returned a name - if (fileEncoding.empty()) -#if wxUSE_UNICODE - fileEncoding = wxT("UTF-8"); -#else - fileEncoding = wxT("ISO-8859-1"); -#endif - m_convFile = new wxCSConv(fileEncoding); - deleteConvFile = true; + wxString data; + + wxXmlNode* imageChild = node->GetChildren(); + while (imageChild) + { + wxString childName = imageChild->GetName(); + if (childName == wxT("data")) + { + wxXmlNode* dataChild = imageChild->GetChildren(); + while (dataChild) + { + data = dataChild->GetContent(); + // wxLogDebug(data); + dataChild = dataChild->GetNext(); + } + + } + imageChild = imageChild->GetNext(); } -#if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT && wxRICHTEXT_USE_XMLDOCUMENT_OUTPUT -#if wxRICHTEXT_USE_OUTPUT_TIMINGS - wxStopWatch stopwatch; -#endif - wxXmlDocument* doc = new wxXmlDocument; - doc->SetFileEncoding(fileEncoding); + if (!data.empty()) + { + wxStringInputStream strStream(data); - wxXmlNode* rootNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("richtext")); - doc->SetRoot(rootNode); - rootNode->AddAttribute(wxT("version"), wxT("1.0.0.0")); - rootNode->AddAttribute(wxT("xmlns"), wxT("http://www.wxwidgets.org")); + GetImageBlock().ReadHex(strStream, data.length(), imageType); - if (buffer->GetStyleSheet() && (GetFlags() & wxRICHTEXT_HANDLER_INCLUDE_STYLESHEET)) + return true; + } + else + return false; +} + +#if wxRICHTEXT_HAVE_DIRECT_OUTPUT +// Export this object directly to the given stream. +bool wxRichTextImage::ExportXML(wxOutputStream& stream, int indent, wxRichTextXMLHandler* handler) +{ + wxString style = handler->GetHelper().AddAttributes(GetAttributes(), false); + + handler->GetHelper().OutputIndentation(stream, indent); + handler->GetHelper().OutputString(stream, wxT("AddChild(styleSheetNode); + // No data + handler->GetHelper().OutputString(stream, style + wxT(">")); + } + else + { + handler->GetHelper().OutputString(stream, wxString::Format(wxT(" imagetype=\"%d\""), (int) GetImageBlock().GetImageType()) + style + wxT(">")); + } + if (GetProperties().GetCount() > 0) + { + handler->GetHelper().WriteProperties(stream, GetProperties(), indent); + handler->GetHelper().OutputIndentation(stream, indent); + } - wxString nameAndDescr; + handler->GetHelper().OutputIndentation(stream, indent+1); + handler->GetHelper().OutputString(stream, wxT("")); - if (!buffer->GetStyleSheet()->GetName().empty()) - styleSheetNode->AddAttribute(wxT("name"), buffer->GetStyleSheet()->GetName()); + // wxStopWatch stopwatch; - if (!buffer->GetStyleSheet()->GetDescription().empty()) - styleSheetNode->AddAttribute(wxT("description"), buffer->GetStyleSheet()->GetDescription()); + GetImageBlock().WriteHex(stream); - int i; - for (i = 0; i < (int) buffer->GetStyleSheet()->GetCharacterStyleCount(); i++) - { - wxRichTextCharacterStyleDefinition* def = buffer->GetStyleSheet()->GetCharacterStyle(i); - ExportStyleDefinition(styleSheetNode, def); - } + // wxLogDebug(wxT("Image conversion to hex took %ldms"), stopwatch.Time()); - for (i = 0; i < (int) buffer->GetStyleSheet()->GetParagraphStyleCount(); i++) - { - wxRichTextParagraphStyleDefinition* def = buffer->GetStyleSheet()->GetParagraphStyle(i); - ExportStyleDefinition(styleSheetNode, def); - } + handler->GetHelper().OutputString(stream, wxT("\n")); + handler->GetHelper().OutputIndentation(stream, indent); + handler->GetHelper().OutputString(stream, wxT("")); + return true; +} +#endif - for (i = 0; i < (int) buffer->GetStyleSheet()->GetListStyleCount(); i++) - { - wxRichTextListStyleDefinition* def = buffer->GetStyleSheet()->GetListStyle(i); - ExportStyleDefinition(styleSheetNode, def); - } +#if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT +// Export this object to the given parent node, usually creating at least one child node. +bool wxRichTextImage::ExportXML(wxXmlNode* parent, wxRichTextXMLHandler* handler) +{ + wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("image")); + parent->AddChild(elementNode); - for (i = 0; i < (int) buffer->GetStyleSheet()->GetBoxStyleCount(); i++) + if (GetImageBlock().IsOk()) + elementNode->AddAttribute(wxT("imagetype"), wxRichTextXMLHelper::MakeString((int) GetImageBlock().GetImageType())); + + handler->GetHelper().AddAttributes(elementNode, GetAttributes(), false); + handler->GetHelper().WriteProperties(elementNode, GetProperties()); + + wxXmlNode* dataNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("data")); + elementNode->AddChild(dataNode); + wxXmlNode* textNode = new wxXmlNode(wxXML_TEXT_NODE, wxT("text")); + dataNode->AddChild(textNode); + + wxString strData; +#if 1 + { + wxMemoryOutputStream stream; + if (GetImageBlock().WriteHex(stream)) { - wxRichTextBoxStyleDefinition* def = buffer->GetStyleSheet()->GetBoxStyle(i); - ExportStyleDefinition(styleSheetNode, def); + if (stream.GetSize() > 0) + { + int size = stream.GetSize(); +#ifdef __WXDEBUG__ + int size2 = stream.GetOutputStreamBuffer()->GetIntPosition(); + wxASSERT(size == size2); +#endif + unsigned char* data = new unsigned char[size]; + stream.CopyTo(data, size); + strData = wxString((const char*) data, wxConvUTF8, size); + delete[] data; + } + else + strData = wxEmptyString; } - WriteProperties(styleSheetNode, buffer->GetStyleSheet()->GetProperties()); } - bool success = ExportXML(rootNode, *buffer); -#if wxRICHTEXT_USE_OUTPUT_TIMINGS - long t = stopwatch.Time(); - wxLogDebug(wxT("Creating the document took %ldms"), t); - wxMessageBox(wxString::Format(wxT("Creating the document took %ldms"), t)); -#endif - if (success) +#else { -#if wxRICHTEXT_USE_OUTPUT_TIMINGS - wxStopWatch s2; -#endif - success = doc->Save(stream); -#if wxRICHTEXT_USE_OUTPUT_TIMINGS - long t2 = s2.Time(); - wxLogDebug(wxT("Save() took %ldms"), t2); - wxMessageBox(wxString::Format(wxT("Save() took %ldms"), t2)); -#endif + wxStringOutputStream strStream(& strData); + GetImageBlock().WriteHex(strStream); } - delete doc; - doc = NULL; +#endif -#else - // !(wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT && wxRICHTEXT_USE_XMLDOCUMENT_OUTPUT) + textNode->SetContent(strData); +#if wxCHECK_VERSION(2,9,0) + textNode->SetNoConversion(true); // optimize speed +#endif -#if !wxUSE_UNICODE - m_convMem = wxConvCurrent; -#else - m_convMem = NULL; + return true; +} #endif - wxString s ; - s.Printf(wxT("\n"), - version, fileEncoding); - OutputString(stream, s); - OutputString(stream, wxT("")); +// Import this object from XML +bool wxRichTextParagraphLayoutBox::ImportFromXML(wxRichTextBuffer* buffer, wxXmlNode* node, wxRichTextXMLHandler* handler, bool* recurse) +{ + wxRichTextObject::ImportFromXML(buffer, node, handler, recurse); - int level = 1; + *recurse = true; - if (buffer->GetStyleSheet() && (GetFlags() & wxRICHTEXT_HANDLER_INCLUDE_STYLESHEET)) - { - OutputIndentation(stream, level); - wxString nameAndDescr; - if (!buffer->GetStyleSheet()->GetName().empty()) - nameAndDescr << wxT(" name=\"") << buffer->GetStyleSheet()->GetName() << wxT("\""); - if (!buffer->GetStyleSheet()->GetDescription().empty()) - nameAndDescr << wxT(" description=\"") << buffer->GetStyleSheet()->GetDescription() << wxT("\""); - OutputString(stream, wxString(wxT("")); + wxString partial = node->GetAttribute(wxT("partialparagraph"), wxEmptyString); + if (partial == wxT("true")) + SetPartialParagraph(true); - int i; + wxXmlNode* child = handler->GetHelper().FindNode(node, wxT("stylesheet")); + if (child && (handler->GetFlags() & wxRICHTEXT_HANDLER_INCLUDE_STYLESHEET)) + { + wxRichTextStyleSheet* sheet = new wxRichTextStyleSheet; + wxString sheetName = child->GetAttribute(wxT("name"), wxEmptyString); + wxString sheetDescription = child->GetAttribute(wxT("description"), wxEmptyString); + sheet->SetName(sheetName); + sheet->SetDescription(sheetDescription); - for (i = 0; i < (int) buffer->GetStyleSheet()->GetCharacterStyleCount(); i++) + wxXmlNode* child2 = child->GetChildren(); + while (child2) { - wxRichTextCharacterStyleDefinition* def = buffer->GetStyleSheet()->GetCharacterStyle(i); - ExportStyleDefinition(stream, def, level + 1); - } + handler->GetHelper().ImportStyleDefinition(sheet, child2); - for (i = 0; i < (int) buffer->GetStyleSheet()->GetParagraphStyleCount(); i++) - { - wxRichTextParagraphStyleDefinition* def = buffer->GetStyleSheet()->GetParagraphStyle(i); - ExportStyleDefinition(stream, def, level + 1); + child2 = child2->GetNext(); } + handler->GetHelper().ImportProperties(sheet->GetProperties(), child); - for (i = 0; i < (int) buffer->GetStyleSheet()->GetListStyleCount(); i++) - { - wxRichTextListStyleDefinition* def = buffer->GetStyleSheet()->GetListStyle(i); - ExportStyleDefinition(stream, def, level + 1); - } + // Notify that styles have changed. If this is vetoed by the app, + // the new sheet will be deleted. If it is not vetoed, the + // old sheet will be deleted and replaced with the new one. + buffer->SetStyleSheetAndNotify(sheet); + } - for (i = 0; i < (int) buffer->GetStyleSheet()->GetBoxStyleCount(); i++) - { - wxRichTextBoxStyleDefinition* def = buffer->GetStyleSheet()->GetBoxStyle(i); - ExportStyleDefinition(stream, def, level + 1); - } + return true; +} - WriteProperties(stream, buffer->GetStyleSheet()->GetProperties(), level); +#if wxRICHTEXT_HAVE_DIRECT_OUTPUT +// Export this object directly to the given stream. +bool wxRichTextParagraphLayoutBox::ExportXML(wxOutputStream& stream, int indent, wxRichTextXMLHandler* handler) +{ + handler->GetHelper().OutputIndentation(stream, indent); + wxString nodeName = GetXMLNodeName(); + handler->GetHelper().OutputString(stream, wxT("<") + nodeName); - OutputIndentation(stream, level); - OutputString(stream, wxT("")); - } + wxString style = handler->GetHelper().AddAttributes(GetAttributes(), true); + if (GetPartialParagraph()) + style << wxT(" partialparagraph=\"true\""); - bool success = ExportXML(stream, *buffer, level); + handler->GetHelper().OutputString(stream, style + wxT(">")); - OutputString(stream, wxT("\n")); - OutputString(stream, wxT("\n")); + if (GetProperties().GetCount() > 0) + { + handler->GetHelper().WriteProperties(stream, GetProperties(), indent); + } - if (deleteConvFile) - delete m_convFile; - m_convFile = NULL; - m_convMem = NULL; -#endif + size_t i; + for (i = 0; i < GetChildCount(); i++) + { + wxRichTextObject* child = GetChild(i); + child->ExportXML(stream, indent+1, handler); + } - return success; + handler->GetHelper().OutputIndentation(stream, indent); + handler->GetHelper().OutputString(stream, wxT("")); + return true; } +#endif -#if wxRICHTEXT_HAVE_DIRECT_OUTPUT - -/// Recursively export an object -bool wxRichTextXMLHandler::ExportXML(wxOutputStream& stream, wxRichTextObject& obj, int indent) +#if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT +// Export this object to the given parent node, usually creating at least one child node. +bool wxRichTextParagraphLayoutBox::ExportXML(wxXmlNode* parent, wxRichTextXMLHandler* handler) { - obj.ExportXML(stream, indent, this); + wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, GetXMLNodeName()); + parent->AddChild(elementNode); + handler->GetHelper().AddAttributes(elementNode, GetAttributes(), true); + handler->GetHelper().WriteProperties(elementNode, GetProperties()); + + if (GetPartialParagraph()) + elementNode->AddAttribute(wxT("partialparagraph"), wxT("true")); + + size_t i; + for (i = 0; i < GetChildCount(); i++) + { + wxRichTextObject* child = GetChild(i); + child->ExportXML(elementNode, handler); + } return true; } +#endif -bool wxRichTextXMLHandler::ExportStyleDefinition(wxOutputStream& stream, wxRichTextStyleDefinition* def, int level) +// Import this object from XML +bool wxRichTextTable::ImportFromXML(wxRichTextBuffer* buffer, wxXmlNode* node, wxRichTextXMLHandler* handler, bool* recurse) { - wxRichTextCharacterStyleDefinition* charDef = wxDynamicCast(def, wxRichTextCharacterStyleDefinition); - wxRichTextParagraphStyleDefinition* paraDef = wxDynamicCast(def, wxRichTextParagraphStyleDefinition); - wxRichTextListStyleDefinition* listDef = wxDynamicCast(def, wxRichTextListStyleDefinition); - wxRichTextBoxStyleDefinition* boxDef = wxDynamicCast(def, wxRichTextBoxStyleDefinition); + wxRichTextBox::ImportFromXML(buffer, node, handler, recurse); - wxString name = def->GetName(); - wxString nameProp; - if (!name.empty()) - nameProp = wxT(" name=\"") + AttributeToXML(name) + wxT("\""); + *recurse = false; - wxString baseStyle = def->GetBaseStyle(); - wxString baseStyleProp; - if (!baseStyle.empty()) - baseStyleProp = wxT(" basestyle=\"") + AttributeToXML(baseStyle) + wxT("\""); + m_rowCount = wxAtoi(node->GetAttribute(wxT("rows"), wxEmptyString)); + m_colCount = wxAtoi(node->GetAttribute(wxT("cols"), wxEmptyString)); - wxString descr = def->GetDescription(); - wxString descrProp; - if (!descr.empty()) - descrProp = wxT(" description=\"") + AttributeToXML(descr) + wxT("\""); + wxXmlNode* child = node->GetChildren(); + while (child) + { + wxRichTextObject* childObj = handler->CreateObjectForXMLName(this, child->GetName()); + if (childObj) + { + AppendChild(childObj); + handler->ImportXML(buffer, childObj, child); + } + child = child->GetNext(); + } - if (charDef) + m_cells.Add(wxRichTextObjectPtrArray(), m_rowCount); + int i, j; + for (i = 0; i < m_rowCount; i++) { - OutputIndentation(stream, level); - OutputString(stream, wxT("")); + wxRichTextObjectPtrArray& colArray = m_cells[i]; + for (j = 0; j < m_colCount; j++) + { + int idx = i * m_colCount + j; + if (idx < (int) GetChildren().GetCount()) + { + wxRichTextCell* cell = wxDynamicCast(GetChildren().Item(idx)->GetData(), wxRichTextCell); + if (cell) + colArray.Add(cell); + } + } + } - level ++; + return true; +} - wxString style = AddAttributes(def->GetStyle(), false); +#if wxRICHTEXT_HAVE_DIRECT_OUTPUT +// Export this object directly to the given stream. +bool wxRichTextTable::ExportXML(wxOutputStream& stream, int indent, wxRichTextXMLHandler* handler) +{ + handler->GetHelper().OutputIndentation(stream, indent); + wxString nodeName = GetXMLNodeName(); + handler->GetHelper().OutputString(stream, wxT("<") + nodeName); - OutputIndentation(stream, level); - OutputString(stream, wxT("")); + style << wxT(" rows=\"") << m_rowCount << wxT("\""); + style << wxT(" cols=\"") << m_colCount << wxT("\""); - level --; + handler->GetHelper().OutputString(stream, style + wxT(">")); - OutputIndentation(stream, level); - OutputString(stream, wxT("")); - } - else if (listDef) + if (GetProperties().GetCount() > 0) { - OutputIndentation(stream, level); - - if (!listDef->GetNextStyle().empty()) - baseStyleProp << wxT(" nextstyle=\"") << AttributeToXML(listDef->GetNextStyle()) << wxT("\""); + handler->GetHelper().WriteProperties(stream, GetProperties(), indent); + } - OutputString(stream, wxT("")); + int i, j; + for (i = 0; i < m_rowCount; i++) + { + for (j = 0; j < m_colCount; j ++) + { + wxRichTextCell* cell = GetCell(i, j); + cell->ExportXML(stream, indent+1, handler); + } + } - level ++; + handler->GetHelper().OutputIndentation(stream, indent); + handler->GetHelper().OutputString(stream, wxT("")); - wxString style = AddAttributes(def->GetStyle(), true); + return true; +} +#endif - OutputIndentation(stream, level); - OutputString(stream, wxT("")); + elementNode->AddAttribute(wxT("rows"), wxString::Format(wxT("%d"), m_rowCount)); + elementNode->AddAttribute(wxT("cols"), wxString::Format(wxT("%d"), m_colCount)); - int i; - for (i = 0; i < 10; i ++) + int i, j; + for (i = 0; i < m_rowCount; i++) + { + for (j = 0; j < m_colCount; j ++) { - wxRichTextAttr* levelAttr = listDef->GetLevelAttributes(i); - if (levelAttr) - { - wxString style = AddAttributes(def->GetStyle(), true); - wxString levelStr = wxString::Format(wxT(" level=\"%d\" "), (i+1)); - - OutputIndentation(stream, level); - OutputString(stream, wxT("")); - } + wxRichTextCell* cell = GetCell(i, j); + cell->ExportXML(elementNode, handler); } - - level --; - - OutputIndentation(stream, level); - OutputString(stream, wxT("")); } - else if (paraDef) - { - OutputIndentation(stream, level); - - if (!paraDef->GetNextStyle().empty()) - baseStyleProp << wxT(" nextstyle=\"") << AttributeToXML(paraDef->GetNextStyle()) << wxT("\""); - OutputString(stream, wxT("")); + return true; +} +#endif - level ++; +wxRichTextXMLHelper::~wxRichTextXMLHelper() +{ + Clear(); +} - wxString style = AddAttributes(def->GetStyle(), true); +void wxRichTextXMLHelper::Init() +{ +#if wxRICHTEXT_HAVE_DIRECT_OUTPUT + m_deleteConvFile = false; + m_convMem = NULL; + m_convFile = NULL; +#endif + m_flags = 0; +} - OutputIndentation(stream, level); - OutputString(stream, wxT("")); +void wxRichTextXMLHelper::SetupForSaving(const wxString& enc) +{ + Clear(); - level --; +#if wxUSE_UNICODE + m_fileEncoding = wxT("UTF-8"); +#if wxRICHTEXT_HAVE_DIRECT_OUTPUT + m_convFile = & wxConvUTF8; +#endif +#else + m_fileEncoding = wxT("ISO-8859-1"); +#if wxRICHTEXT_HAVE_DIRECT_OUTPUT + m_convFile = & wxConvISO8859_1; +#endif +#endif - OutputIndentation(stream, level); - OutputString(stream, wxT("")); - } - else if (boxDef) + // If we pass an explicit encoding, change the output encoding. + if (!enc.empty() && enc.Lower() != m_fileEncoding.Lower()) { - OutputIndentation(stream, level); + if (enc == wxT("")) + { +#if wxUSE_INTL + m_fileEncoding = wxLocale::GetSystemEncodingName(); + // if !wxUSE_INTL, we fall back to UTF-8 or ISO-8859-1 below +#endif + } + else + { + m_fileEncoding = enc; + } - OutputString(stream, wxT("")); + // GetSystemEncodingName may not have returned a name + if (m_fileEncoding.empty()) +#if wxUSE_UNICODE + m_fileEncoding = wxT("UTF-8"); +#else + m_fileEncoding = wxT("ISO-8859-1"); +#endif +#if wxRICHTEXT_HAVE_DIRECT_OUTPUT + m_convFile = new wxCSConv(m_fileEncoding); + m_deleteConvFile = true; +#endif + } - level ++; +#if wxRICHTEXT_HAVE_DIRECT_OUTPUT +#if !wxUSE_UNICODE + m_convMem = wxConvCurrent; +#else + m_convMem = NULL; +#endif +#endif +} - wxString style = AddAttributes(def->GetStyle(), true); +// Convert a colour to a 6-digit hex string +wxString wxRichTextXMLHelper::ColourToHexString(const wxColour& col) +{ + wxString hex; - OutputIndentation(stream, level); - OutputString(stream, wxT("")); + return hex; +} - level --; +// Convert 6-digit hex string to a colour +wxColour wxRichTextXMLHelper::HexStringToColour(const wxString& hex) +{ + unsigned char r = (unsigned char)wxHexToDec(hex.Mid(0, 2)); + unsigned char g = (unsigned char)wxHexToDec(hex.Mid(2, 2)); + unsigned char b = (unsigned char)wxHexToDec(hex.Mid(4, 2)); - OutputIndentation(stream, level); - OutputString(stream, wxT("")); - } + return wxColour(r, g, b); +} - WriteProperties(stream, def->GetProperties(), level); +//----------------------------------------------------------------------------- +// xml support routines +//----------------------------------------------------------------------------- - return true; +bool wxRichTextXMLHelper::HasParam(wxXmlNode* node, const wxString& param) +{ + return (GetParamNode(node, param) != NULL); } -/// Create a string containing style attributes -wxString wxRichTextXMLHandler::AddAttributes(const wxRichTextAttr& attr, bool isPara) +wxXmlNode *wxRichTextXMLHelper::GetParamNode(wxXmlNode* node, const wxString& param) { - wxString str; - if (attr.HasTextColour() && attr.GetTextColour().IsOk()) - AddAttribute(str, wxT("textcolor"), attr.GetTextColour()); - - if (attr.HasBackgroundColour() && attr.GetBackgroundColour().IsOk()) - AddAttribute(str, wxT("bgcolor"), attr.GetBackgroundColour()); - - if (attr.HasFontPointSize()) - AddAttribute(str, wxT("fontpointsize"), attr.GetFontSize()); - else if (attr.HasFontPixelSize()) - AddAttribute(str, wxT("fontpixelsize"), attr.GetFontSize()); + wxCHECK_MSG(node, NULL, wxT("You can't access node data before it was initialized!")); - if (attr.HasFontFamily()) - AddAttribute(str, wxT("fontfamily"), attr.GetFontFamily()); + wxXmlNode *n = node->GetChildren(); - if (attr.HasFontItalic()) - AddAttribute(str, wxT("fontstyle"), attr.GetFontStyle()); + while (n) + { + if (n->GetType() == wxXML_ELEMENT_NODE && n->GetName() == param) + return n; + n = n->GetNext(); + } + return NULL; +} - if (attr.HasFontWeight()) - AddAttribute(str, wxT("fontweight"), attr.GetFontWeight()); +wxString wxRichTextXMLHelper::GetNodeContent(wxXmlNode *node) +{ + wxXmlNode *n = node; + if (n == NULL) return wxEmptyString; + n = n->GetChildren(); - if (attr.HasFontUnderlined()) - AddAttribute(str, wxT("fontunderlined"), (int) attr.GetFontUnderlined()); - - if (attr.HasFontFaceName()) - AddAttribute(str, wxT("fontface"), AttributeToXML(attr.GetFontFaceName())); - - if (attr.HasTextEffects()) - { - AddAttribute(str, wxT("texteffects"), attr.GetTextEffects()); - AddAttribute(str, wxT("texteffectflags"), attr.GetTextEffectFlags()); - } - - if (!attr.GetCharacterStyleName().empty()) - AddAttribute(str, wxT("characterstyle"), AttributeToXML(attr.GetCharacterStyleName())); - - if (attr.HasURL()) - AddAttribute(str, wxT("url"), AttributeToXML(attr.GetURL())); - - if (isPara) - { - if (attr.HasAlignment()) - AddAttribute(str, wxT("alignment"), (int) attr.GetAlignment()); - - if (attr.HasLeftIndent()) - { - AddAttribute(str, wxT("leftindent"), (int) attr.GetLeftIndent()); - AddAttribute(str, wxT("leftsubindent"), (int) attr.GetLeftSubIndent()); - } - - if (attr.HasRightIndent()) - AddAttribute(str, wxT("rightindent"), (int) attr.GetRightIndent()); - - if (attr.HasParagraphSpacingAfter()) - AddAttribute(str, wxT("parspacingafter"), (int) attr.GetParagraphSpacingAfter()); - - if (attr.HasParagraphSpacingBefore()) - AddAttribute(str, wxT("parspacingbefore"), (int) attr.GetParagraphSpacingBefore()); - - if (attr.HasLineSpacing()) - AddAttribute(str, wxT("linespacing"), (int) attr.GetLineSpacing()); - - if (attr.HasBulletStyle()) - AddAttribute(str, wxT("bulletstyle"), (int) attr.GetBulletStyle()); - - if (attr.HasBulletNumber()) - AddAttribute(str, wxT("bulletnumber"), (int) attr.GetBulletNumber()); - - if (attr.HasBulletText()) - { - // If using a bullet symbol, convert to integer in case it's a non-XML-friendly character. - // Otherwise, assume it's XML-friendly text such as outline numbering, e.g. 1.2.3.1 - if (!attr.GetBulletText().empty() && (attr.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_SYMBOL)) - AddAttribute(str, wxT("bulletsymbol"), (int) (attr.GetBulletText()[0])); - else - AddAttribute(str, wxT("bullettext"), AttributeToXML(attr.GetBulletText())); - - AddAttribute(str, wxT("bulletfont"), attr.GetBulletFont()); - } - - if (attr.HasBulletName()) - AddAttribute(str, wxT("bulletname"), AttributeToXML(attr.GetBulletName())); - - if (!attr.GetParagraphStyleName().empty()) - AddAttribute(str, wxT("parstyle"), AttributeToXML(attr.GetParagraphStyleName())); - - if (!attr.GetListStyleName().empty()) - AddAttribute(str, wxT("liststyle"), AttributeToXML(attr.GetListStyleName())); - - if (!attr.GetTextBoxAttr().GetBoxStyleName().empty()) - AddAttribute(str, wxT("boxstyle"), AttributeToXML(attr.GetTextBoxAttr().GetBoxStyleName())); - - if (attr.HasTabs()) - { - wxString strTabs; - size_t i; - for (i = 0; i < attr.GetTabs().GetCount(); i++) - { - if (i > 0) strTabs << wxT(","); - strTabs << attr.GetTabs()[i]; - } - AddAttribute(str, wxT("tabs"), strTabs); - } - - if (attr.HasPageBreak()) - { - AddAttribute(str, wxT("pagebreak"), 1); - } - - if (attr.HasOutlineLevel()) - AddAttribute(str, wxT("outlinelevel"), (int) attr.GetOutlineLevel()); - } - - AddAttribute(str, wxT("margin"), attr.GetTextBoxAttr().GetMargins()); - AddAttribute(str, wxT("padding"), attr.GetTextBoxAttr().GetPadding()); - AddAttribute(str, wxT("position"), attr.GetTextBoxAttr().GetPosition()); - AddAttribute(str, wxT("border"), attr.GetTextBoxAttr().GetBorder()); - AddAttribute(str, wxT("outline"), attr.GetTextBoxAttr().GetOutline()); - AddAttribute(str, wxT("width"), attr.GetTextBoxAttr().GetWidth()); - AddAttribute(str, wxT("height"), attr.GetTextBoxAttr().GetHeight()); - AddAttribute(str, wxT("minwidth"), attr.GetTextBoxAttr().GetMinSize().GetWidth()); - AddAttribute(str, wxT("minheight"), attr.GetTextBoxAttr().GetMinSize().GetHeight()); - AddAttribute(str, wxT("maxwidth"), attr.GetTextBoxAttr().GetMaxSize().GetWidth()); - AddAttribute(str, wxT("maxheight"), attr.GetTextBoxAttr().GetMaxSize().GetHeight()); - - if (attr.GetTextBoxAttr().HasVerticalAlignment()) - { - wxString value; - if (attr.GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_TOP) - value = wxT("top"); - else if (attr.GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_CENTRE) - value = wxT("centre"); - else if (attr.GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_BOTTOM) - value = wxT("bottom"); - else - value = wxT("none"); - AddAttribute(str, wxT("verticalalignment"), value); - } - - if (attr.GetTextBoxAttr().HasFloatMode()) - { - wxString value; - if (attr.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_LEFT) - value = wxT("left"); - else if (attr.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_RIGHT) - value = wxT("right"); - else - value = wxT("none"); - AddAttribute(str, wxT("float"), value); - } - - if (attr.GetTextBoxAttr().HasClearMode()) + while (n) { - wxString value; - if (attr.GetTextBoxAttr().GetClearMode() == wxTEXT_BOX_ATTR_CLEAR_LEFT) - value = wxT("left"); - else if (attr.GetTextBoxAttr().GetClearMode() == wxTEXT_BOX_ATTR_CLEAR_RIGHT) - value = wxT("right"); - else if (attr.GetTextBoxAttr().GetClearMode() == wxTEXT_BOX_ATTR_CLEAR_BOTH) - value = wxT("both"); - else - value = wxT("none"); - AddAttribute(str, wxT("clear"), value); + if (n->GetType() == wxXML_TEXT_NODE || + n->GetType() == wxXML_CDATA_SECTION_NODE) + return n->GetContent(); + n = n->GetNext(); } - - if (attr.GetTextBoxAttr().HasCollapseBorders()) - AddAttribute(str, wxT("collapse-borders"), (int) attr.GetTextBoxAttr().GetCollapseBorders()); - - return str; + return wxEmptyString; } -// Make a string from the given property. This can be overridden for custom variants. -wxString wxRichTextXMLHandler::MakeStringFromProperty(const wxVariant& var) +wxString wxRichTextXMLHelper::GetParamValue(wxXmlNode *node, const wxString& param) { - return var.MakeString(); -} - -// Create a proprty from the string read from the XML file. -wxVariant wxRichTextXMLHandler::MakePropertyFromString(const wxString& name, const wxString& value, const wxString& WXUNUSED(type)) -{ - wxVariant var(value, name); - // TODO: use type to create using common types - return var; -} - -// Write the properties -bool wxRichTextXMLHandler::WriteProperties(wxOutputStream& stream, const wxRichTextProperties& properties, int level) -{ - if (properties.GetCount() > 0) - { - level ++; - - OutputIndentation(stream, level); - OutputString(stream, wxT("")); - - level ++; - - size_t i; - for (i = 0; i < properties.GetCount(); i++) - { - const wxVariant& var = properties[i]; - if (!var.IsNull()) - { - const wxString& name = var.GetName(); - wxString value = MakeStringFromProperty(var); - - OutputIndentation(stream, level); - OutputString(stream, wxT("")); - } - } - - level --; - - OutputIndentation(stream, level); - OutputString(stream, wxT("")); - - level --; - } - - return true; + if (param.empty()) + return GetNodeContent(node); + else + return GetNodeContent(GetParamNode(node, param)); } - -#endif - // wxRICHTEXT_HAVE_DIRECT_OUTPUT - -#if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT -bool wxRichTextXMLHandler::ExportXML(wxXmlNode* parent, wxRichTextObject& obj) +wxString wxRichTextXMLHelper::GetText(wxXmlNode *node, const wxString& param) { - obj.ExportXML(parent, this); - - return true; + wxXmlNode *parNode = GetParamNode(node, param); + if (!parNode) + parNode = node; + wxString str1(GetNodeContent(parNode)); + return str1; } -bool wxRichTextXMLHandler::ExportStyleDefinition(wxXmlNode* parent, wxRichTextStyleDefinition* def) +wxXmlNode* wxRichTextXMLHelper::FindNode(wxXmlNode* node, const wxString& name) { - wxRichTextCharacterStyleDefinition* charDef = wxDynamicCast(def, wxRichTextCharacterStyleDefinition); - wxRichTextParagraphStyleDefinition* paraDef = wxDynamicCast(def, wxRichTextParagraphStyleDefinition); - wxRichTextBoxStyleDefinition* boxDef = wxDynamicCast(def, wxRichTextBoxStyleDefinition); - wxRichTextListStyleDefinition* listDef = wxDynamicCast(def, wxRichTextListStyleDefinition); - - wxString baseStyle = def->GetBaseStyle(); - wxString descr = def->GetDescription(); - - wxXmlNode* defNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxEmptyString); - parent->AddChild(defNode); - if (!baseStyle.empty()) - defNode->AddAttribute(wxT("basestyle"), baseStyle); - if (!descr.empty()) - defNode->AddAttribute(wxT("description"), descr); - - wxXmlNode* styleNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("style")); - defNode->AddChild(styleNode); - - if (charDef) - { - defNode->SetName(wxT("characterstyle")); - AddAttributes(styleNode, def->GetStyle(), false); - } - else if (listDef) - { - defNode->SetName(wxT("liststyle")); - - if (!listDef->GetNextStyle().empty()) - defNode->AddAttribute(wxT("nextstyle"), listDef->GetNextStyle()); - - AddAttributes(styleNode, def->GetStyle(), true); - - int i; - for (i = 0; i < 10; i ++) - { - wxRichTextAttr* levelAttr = listDef->GetLevelAttributes(i); - if (levelAttr) - { - wxXmlNode* levelNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("style")); - defNode->AddChild(levelNode); - levelNode->AddAttribute(wxT("level"), MakeString(i+1)); - AddAttributes(levelNode, * levelAttr, true); - } - } - } - else if (boxDef) - { - defNode->SetName(wxT("boxstyle")); + if (node->GetName() == name && name == wxT("stylesheet")) + return node; - AddAttributes(styleNode, def->GetStyle(), true); - } - else if (paraDef) + wxXmlNode* child = node->GetChildren(); + while (child) { - defNode->SetName(wxT("paragraphstyle")); - - if (!paraDef->GetNextStyle().empty()) - defNode->AddAttribute(wxT("nextstyle"), paraDef->GetNextStyle()); - - AddAttributes(styleNode, def->GetStyle(), true); + if (child->GetName() == name) + return child; + child = child->GetNext(); } - - WriteProperties(defNode, def->GetProperties()); - - return true; + return NULL; } -bool wxRichTextXMLHandler::AddAttributes(wxXmlNode* node, wxRichTextAttr& attr, bool isPara) +wxString wxRichTextXMLHelper::AttributeToXML(const wxString& str) { - if (attr.HasTextColour() && attr.GetTextColour().IsOk()) - node->AddAttribute(wxT("textcolor"), MakeString(attr.GetTextColour())); - if (attr.HasBackgroundColour() && attr.GetBackgroundColour().IsOk()) - node->AddAttribute(wxT("bgcolor"), MakeString(attr.GetBackgroundColour())); - - if (attr.HasFontPointSize()) - node->AddAttribute(wxT("fontpointsize"), MakeString(attr.GetFontSize())); - else if (attr.HasFontPixelSize()) - node->AddAttribute(wxT("fontpixelsize"), MakeString(attr.GetFontSize())); - if (attr.HasFontFamily()) - node->AddAttribute(wxT("fontfamily"), MakeString(attr.GetFontFamily())); - if (attr.HasFontItalic()) - node->AddAttribute(wxT("fontstyle"), MakeString(attr.GetFontStyle())); - if (attr.HasFontWeight()) - node->AddAttribute(wxT("fontweight"), MakeString(attr.GetFontWeight())); - if (attr.HasFontUnderlined()) - node->AddAttribute(wxT("fontunderlined"), MakeString((int) attr.GetFontUnderlined())); - if (attr.HasFontFaceName()) - node->AddAttribute(wxT("fontface"), attr.GetFontFaceName()); - - if (attr.HasTextEffects()) - { - node->AddAttribute(wxT("texteffects"), MakeString(attr.GetTextEffects())); - node->AddAttribute(wxT("texteffectflags"), MakeString(attr.GetTextEffectFlags())); - } - if (attr.HasCharacterStyleName() && !attr.GetCharacterStyleName().empty()) - node->AddAttribute(wxT("characterstyle"), attr.GetCharacterStyleName()); - - if (attr.HasURL()) - node->AddAttribute(wxT("url"), attr.GetURL()); // TODO: do we need to wrap this in AttributeToXML? + wxString str1; + size_t i, last, len; + wxChar c; - if (isPara) + len = str.Len(); + last = 0; + for (i = 0; i < len; i++) { - if (attr.HasAlignment()) - node->AddAttribute(wxT("alignment"), MakeString((int) attr.GetAlignment())); - - if (attr.HasLeftIndent()) - { - node->AddAttribute(wxT("leftindent"), MakeString((int) attr.GetLeftIndent())); - node->AddAttribute(wxT("leftsubindent"), MakeString((int) attr.GetLeftSubIndent())); - } - - if (attr.HasRightIndent()) - node->AddAttribute(wxT("rightindent"), MakeString((int) attr.GetRightIndent())); - - if (attr.HasParagraphSpacingAfter()) - node->AddAttribute(wxT("parspacingafter"), MakeString((int) attr.GetParagraphSpacingAfter())); - - if (attr.HasParagraphSpacingBefore()) - node->AddAttribute(wxT("parspacingbefore"), MakeString((int) attr.GetParagraphSpacingBefore())); - - if (attr.HasLineSpacing()) - node->AddAttribute(wxT("linespacing"), MakeString((int) attr.GetLineSpacing())); - - if (attr.HasBulletStyle()) - node->AddAttribute(wxT("bulletstyle"), MakeString((int) attr.GetBulletStyle())); - - if (attr.HasBulletNumber()) - node->AddAttribute(wxT("bulletnumber"), MakeString((int) attr.GetBulletNumber())); - - if (attr.HasBulletText()) - { - // If using a bullet symbol, convert to integer in case it's a non-XML-friendly character. - // Otherwise, assume it's XML-friendly text such as outline numbering, e.g. 1.2.3.1 - if (!attr.GetBulletText().empty() && (attr.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_SYMBOL)) - node->AddAttribute(wxT("bulletsymbol"), MakeString((int) (attr.GetBulletText()[0]))); - else - node->AddAttribute(wxT("bullettext"), attr.GetBulletText()); - - if (!attr.GetBulletFont().empty()) - node->AddAttribute(wxT("bulletfont"), attr.GetBulletFont()); - } - - if (attr.HasBulletName()) - node->AddAttribute(wxT("bulletname"), attr.GetBulletName()); - - if (!attr.GetParagraphStyleName().empty()) - node->AddAttribute(wxT("parstyle"), attr.GetParagraphStyleName()); - - if (!attr.GetListStyleName().empty()) - node->AddAttribute(wxT("liststyle"), attr.GetListStyleName()); + c = str.GetChar(i); - if (!attr.GetTextBoxAttr().GetBoxStyleName().empty()) - node->AddAttribute(wxT("boxstyle"), attr.GetTextBoxAttr().GetBoxStyleName()); + // Original code excluded "&" but we _do_ want to convert + // the ampersand beginning & because otherwise when read in, + // the original "&" becomes "&". - if (attr.HasTabs()) + if (c == wxT('<') || c == wxT('>') || c == wxT('"') || + (c == wxT('&') /* && (str.Mid(i+1, 4) != wxT("amp;")) */ )) { - wxString tabs; - size_t i; - for (i = 0; i < attr.GetTabs().GetCount(); i++) + str1 += str.Mid(last, i - last); + switch (c) { - if (i > 0) - tabs << wxT(","); - tabs << attr.GetTabs()[i]; - } - node->AddAttribute(wxT("tabs"), tabs); - } - - if (attr.HasPageBreak()) - node->AddAttribute(wxT("pagebreak"), wxT("1")); - - if (attr.HasOutlineLevel()) - node->AddAttribute(wxT("outlinelevel"), MakeString((int) attr.GetOutlineLevel())); - } - - AddAttribute(node, wxT("margin"), attr.GetTextBoxAttr().GetMargins()); - AddAttribute(node, wxT("padding"), attr.GetTextBoxAttr().GetPadding()); - AddAttribute(node, wxT("position"), attr.GetTextBoxAttr().GetPosition()); - AddAttribute(node, wxT("border"), attr.GetTextBoxAttr().GetBorder()); - AddAttribute(node, wxT("outline"), attr.GetTextBoxAttr().GetOutline()); - AddAttribute(node, wxT("width"), attr.GetTextBoxAttr().GetWidth()); - AddAttribute(node, wxT("height"), attr.GetTextBoxAttr().GetHeight()); - AddAttribute(node, wxT("minwidth"), attr.GetTextBoxAttr().GetMinSize().GetWidth()); - AddAttribute(node, wxT("minheight"), attr.GetTextBoxAttr().GetMinSize().GetHeight()); - AddAttribute(node, wxT("maxwidth"), attr.GetTextBoxAttr().GetMaxSize().GetWidth()); - AddAttribute(node, wxT("maxheight"), attr.GetTextBoxAttr().GetMaxSize().GetHeight()); - - if (attr.GetTextBoxAttr().HasVerticalAlignment()) - { - wxString value; - if (attr.GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_TOP) - value = wxT("top"); - else if (attr.GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_CENTRE) - value = wxT("centre"); - else if (attr.GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_BOTTOM) - value = wxT("bottom"); - else - value = wxT("none"); - AddAttribute(node, wxT("verticalalignment"), value); - } - - if (attr.GetTextBoxAttr().HasFloatMode()) - { - wxString value; - if (attr.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_LEFT) - value = wxT("left"); - else if (attr.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_RIGHT) - value = wxT("right"); - else - value = wxT("none"); - AddAttribute(node, wxT("float"), value); - } - - if (attr.GetTextBoxAttr().HasClearMode()) - { - wxString value; - if (attr.GetTextBoxAttr().GetClearMode() == wxTEXT_BOX_ATTR_CLEAR_LEFT) - value = wxT("left"); - else if (attr.GetTextBoxAttr().GetClearMode() == wxTEXT_BOX_ATTR_CLEAR_RIGHT) - value = wxT("right"); - else if (attr.GetTextBoxAttr().GetClearMode() == wxTEXT_BOX_ATTR_CLEAR_BOTH) - value = wxT("both"); - else - value = wxT("none"); - AddAttribute(node, wxT("clear"), value); - } - - if (attr.GetTextBoxAttr().HasCollapseBorders()) - AddAttribute(node, wxT("collapse-borders"), (int) attr.GetTextBoxAttr().GetCollapseBorders()); - - return true; -} - -bool wxRichTextXMLHandler::WriteProperties(wxXmlNode* node, const wxRichTextProperties& properties) -{ - if (properties.GetCount() > 0) - { - wxXmlNode* propertiesNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("properties")); - node->AddChild(propertiesNode); - size_t i; - for (i = 0; i < properties.GetCount(); i++) + case wxT('<'): + str1 += wxT("<"); + break; + case wxT('>'): + str1 += wxT(">"); + break; + case wxT('&'): + str1 += wxT("&"); + break; + case wxT('"'): + str1 += wxT("""); + break; + default: break; + } + last = i + 1; + } + else if (wxUChar(c) > 127) { - const wxVariant& var = properties[i]; - if (!var.IsNull()) - { - wxXmlNode* propertyNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("property")); - propertiesNode->AddChild(propertyNode); - - const wxString& name = var.GetName(); - wxString value = MakeStringFromProperty(var); + str1 += str.Mid(last, i - last); - AddAttribute(propertyNode, wxT("name"), name); - AddAttribute(propertyNode, wxT("type"), var.GetType()); - AddAttribute(propertyNode, wxT("value"), value); - } + wxString s(wxT("&#")); +#if wxUSE_UNICODE + s << (int) c; +#else + s << (int) wxUChar(c); +#endif + s << wxT(";"); + str1 += s; + last = i + 1; } } - return true; + str1 += str.Mid(last, i - last); + return str1; } -#endif - // wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT +// Make a string from the given property. This can be overridden for custom variants. +wxString wxRichTextXMLHelper::MakeStringFromProperty(const wxVariant& var) +{ + return var.MakeString(); +} + +// Create a proprty from the string read from the XML file. +wxVariant wxRichTextXMLHelper::MakePropertyFromString(const wxString& name, const wxString& value, const wxString& WXUNUSED(type)) +{ + wxVariant var(value, name); + // TODO: use type to create using common types + return var; +} /// Replace face name with current name for platform. /// TODO: introduce a virtual function or settable table to /// do this comprehensively. -bool wxRichTextFixFaceName(wxString& facename) +bool wxRichTextXMLHelper::RichTextFixFaceName(wxString& facename) { if (facename.empty()) return false; @@ -1631,18 +1312,22 @@ bool wxRichTextFixFaceName(wxString& facename) #endif } -static inline long wxRichTextColourStringToLong(const wxString& colStr) +long wxRichTextXMLHelper::ColourStringToLong(const wxString& colStr) { if (!colStr.IsEmpty()) { wxColour col(colStr); +#if wxCHECK_VERSION(2,9,0) return col.GetRGB(); +#else + return (col.Red() | (col.Green() << 8) | (col.Blue() << 16)); +#endif } else return 0; } -static inline wxTextAttrDimension wxRichTextParseDimension(const wxString& dimStr) +wxTextAttrDimension wxRichTextXMLHelper::ParseDimension(const wxString& dimStr) { wxString valuePart = dimStr.BeforeFirst(wxT(',')); wxString flagsPart; @@ -1656,7 +1341,7 @@ static inline wxTextAttrDimension wxRichTextParseDimension(const wxString& dimSt } /// Import style parameters -bool wxRichTextXMLHandler::ImportStyle(wxRichTextAttr& attr, wxXmlNode* node, bool isPara) +bool wxRichTextXMLHelper::ImportStyle(wxRichTextAttr& attr, wxXmlNode* node, bool isPara) { wxXmlAttribute* xmlAttr = node->GetAttributes(); bool found; @@ -1672,7 +1357,7 @@ bool wxRichTextXMLHandler::ImportStyle(wxRichTextAttr& attr, wxXmlNode* node, bo { wxString v = value; if (GetFlags() & wxRICHTEXT_HANDLER_CONVERT_FACENAMES) - wxRichTextFixFaceName(v); + RichTextFixFaceName(v); attr.SetFontFaceName(v); } } @@ -1885,27 +1570,27 @@ bool wxRichTextXMLHandler::ImportStyle(wxRichTextAttr& attr, wxXmlNode* node, bo if (name == wxT("width")) { - attr.GetTextBoxAttr().GetWidth().SetValue(wxRichTextParseDimension(value)); + attr.GetTextBoxAttr().GetWidth().SetValue(ParseDimension(value)); } else if (name == wxT("height")) { - attr.GetTextBoxAttr().GetHeight().SetValue(wxRichTextParseDimension(value)); + attr.GetTextBoxAttr().GetHeight().SetValue(ParseDimension(value)); } else if (name == wxT("minwidth")) { - attr.GetTextBoxAttr().GetMinSize().GetWidth().SetValue(wxRichTextParseDimension(value)); + attr.GetTextBoxAttr().GetMinSize().GetWidth().SetValue(ParseDimension(value)); } else if (name == wxT("minheight")) { - attr.GetTextBoxAttr().GetMinSize().GetHeight().SetValue(wxRichTextParseDimension(value)); + attr.GetTextBoxAttr().GetMinSize().GetHeight().SetValue(ParseDimension(value)); } else if (name == wxT("maxwidth")) { - attr.GetTextBoxAttr().GetMaxSize().GetWidth().SetValue(wxRichTextParseDimension(value)); + attr.GetTextBoxAttr().GetMaxSize().GetWidth().SetValue(ParseDimension(value)); } else if (name == wxT("maxheight")) { - attr.GetTextBoxAttr().GetMaxSize().GetHeight().SetValue(wxRichTextParseDimension(value)); + attr.GetTextBoxAttr().GetMaxSize().GetHeight().SetValue(ParseDimension(value)); } else if (name == wxT("verticalalignment")) @@ -1954,22 +1639,22 @@ bool wxRichTextXMLHandler::ImportStyle(wxRichTextAttr& attr, wxXmlNode* node, bo attr.GetTextBoxAttr().GetBorder().GetBottom().SetStyle(wxAtoi(value)); else if (name == wxT("border-left-colour")) - attr.GetTextBoxAttr().GetBorder().GetLeft().SetColour(wxRichTextColourStringToLong(value)); + attr.GetTextBoxAttr().GetBorder().GetLeft().SetColour(ColourStringToLong(value)); else if (name == wxT("border-right-colour")) - attr.GetTextBoxAttr().GetBorder().GetRight().SetColour(wxRichTextColourStringToLong(value)); + attr.GetTextBoxAttr().GetBorder().GetRight().SetColour(ColourStringToLong(value)); else if (name == wxT("border-top-colour")) - attr.GetTextBoxAttr().GetBorder().GetTop().SetColour(wxRichTextColourStringToLong(value)); + attr.GetTextBoxAttr().GetBorder().GetTop().SetColour(ColourStringToLong(value)); else if (name == wxT("border-bottom-colour")) - attr.GetTextBoxAttr().GetBorder().GetBottom().SetColour(wxRichTextColourStringToLong(value)); + attr.GetTextBoxAttr().GetBorder().GetBottom().SetColour(ColourStringToLong(value)); else if (name == wxT("border-left-width")) - attr.GetTextBoxAttr().GetBorder().GetLeft().SetWidth(wxRichTextParseDimension(value)); + attr.GetTextBoxAttr().GetBorder().GetLeft().SetWidth(ParseDimension(value)); else if (name == wxT("border-right-width")) - attr.GetTextBoxAttr().GetBorder().GetRight().SetWidth(wxRichTextParseDimension(value)); + attr.GetTextBoxAttr().GetBorder().GetRight().SetWidth(ParseDimension(value)); else if (name == wxT("border-top-width")) - attr.GetTextBoxAttr().GetBorder().GetTop().SetWidth(wxRichTextParseDimension(value)); + attr.GetTextBoxAttr().GetBorder().GetTop().SetWidth(ParseDimension(value)); else if (name == wxT("border-bottom-width")) - attr.GetTextBoxAttr().GetBorder().GetBottom().SetWidth(wxRichTextParseDimension(value)); + attr.GetTextBoxAttr().GetBorder().GetBottom().SetWidth(ParseDimension(value)); } else if (name.Contains(wxT("outline-"))) { @@ -1983,747 +1668,1067 @@ bool wxRichTextXMLHandler::ImportStyle(wxRichTextAttr& attr, wxXmlNode* node, bo attr.GetTextBoxAttr().GetOutline().GetBottom().SetStyle(wxAtoi(value)); else if (name == wxT("outline-left-colour")) - attr.GetTextBoxAttr().GetOutline().GetLeft().SetColour(wxRichTextColourStringToLong(value)); + attr.GetTextBoxAttr().GetOutline().GetLeft().SetColour(ColourStringToLong(value)); else if (name == wxT("outline-right-colour")) - attr.GetTextBoxAttr().GetOutline().GetRight().SetColour(wxRichTextColourStringToLong(value)); + attr.GetTextBoxAttr().GetOutline().GetRight().SetColour(ColourStringToLong(value)); else if (name == wxT("outline-top-colour")) - attr.GetTextBoxAttr().GetOutline().GetTop().SetColour(wxRichTextColourStringToLong(value)); + attr.GetTextBoxAttr().GetOutline().GetTop().SetColour(ColourStringToLong(value)); else if (name == wxT("outline-bottom-colour")) - attr.GetTextBoxAttr().GetOutline().GetBottom().SetColour(wxRichTextColourStringToLong(value)); + attr.GetTextBoxAttr().GetOutline().GetBottom().SetColour(ColourStringToLong(value)); else if (name == wxT("outline-left-width")) - attr.GetTextBoxAttr().GetOutline().GetLeft().SetWidth(wxRichTextParseDimension(value)); + attr.GetTextBoxAttr().GetOutline().GetLeft().SetWidth(ParseDimension(value)); else if (name == wxT("outline-right-width")) - attr.GetTextBoxAttr().GetOutline().GetRight().SetWidth(wxRichTextParseDimension(value)); + attr.GetTextBoxAttr().GetOutline().GetRight().SetWidth(ParseDimension(value)); else if (name == wxT("outline-top-width")) - attr.GetTextBoxAttr().GetOutline().GetTop().SetWidth(wxRichTextParseDimension(value)); + attr.GetTextBoxAttr().GetOutline().GetTop().SetWidth(ParseDimension(value)); else if (name == wxT("outline-bottom-width")) - attr.GetTextBoxAttr().GetOutline().GetBottom().SetWidth(wxRichTextParseDimension(value)); + attr.GetTextBoxAttr().GetOutline().GetBottom().SetWidth(ParseDimension(value)); } else if (name.Contains(wxT("margin-"))) { if (name == wxT("margin-left")) - attr.GetTextBoxAttr().GetMargins().GetLeft().SetValue(wxRichTextParseDimension(value)); + attr.GetTextBoxAttr().GetMargins().GetLeft().SetValue(ParseDimension(value)); else if (name == wxT("margin-right")) - attr.GetTextBoxAttr().GetMargins().GetRight().SetValue(wxRichTextParseDimension(value)); + attr.GetTextBoxAttr().GetMargins().GetRight().SetValue(ParseDimension(value)); else if (name == wxT("margin-top")) - attr.GetTextBoxAttr().GetMargins().GetTop().SetValue(wxRichTextParseDimension(value)); + attr.GetTextBoxAttr().GetMargins().GetTop().SetValue(ParseDimension(value)); else if (name == wxT("margin-bottom")) - attr.GetTextBoxAttr().GetMargins().GetBottom().SetValue(wxRichTextParseDimension(value)); + attr.GetTextBoxAttr().GetMargins().GetBottom().SetValue(ParseDimension(value)); } else if (name.Contains(wxT("padding-"))) { if (name == wxT("padding-left")) - attr.GetTextBoxAttr().GetPadding().GetLeft().SetValue(wxRichTextParseDimension(value)); + attr.GetTextBoxAttr().GetPadding().GetLeft().SetValue(ParseDimension(value)); else if (name == wxT("padding-right")) - attr.GetTextBoxAttr().GetPadding().GetRight().SetValue(wxRichTextParseDimension(value)); + attr.GetTextBoxAttr().GetPadding().GetRight().SetValue(ParseDimension(value)); else if (name == wxT("padding-top")) - attr.GetTextBoxAttr().GetPadding().GetTop().SetValue(wxRichTextParseDimension(value)); + attr.GetTextBoxAttr().GetPadding().GetTop().SetValue(ParseDimension(value)); else if (name == wxT("padding-bottom")) - attr.GetTextBoxAttr().GetPadding().GetBottom().SetValue(wxRichTextParseDimension(value)); + attr.GetTextBoxAttr().GetPadding().GetBottom().SetValue(ParseDimension(value)); } else if (name.Contains(wxT("position-"))) { - if (name == wxT("position-left")) - attr.GetTextBoxAttr().GetPosition().GetLeft().SetValue(wxRichTextParseDimension(value)); - else if (name == wxT("position-right")) - attr.GetTextBoxAttr().GetPosition().GetRight().SetValue(wxRichTextParseDimension(value)); - else if (name == wxT("position-top")) - attr.GetTextBoxAttr().GetPosition().GetTop().SetValue(wxRichTextParseDimension(value)); - else if (name == wxT("position-bottom")) - attr.GetTextBoxAttr().GetPosition().GetBottom().SetValue(wxRichTextParseDimension(value)); + if (name == wxT("position-left")) + attr.GetTextBoxAttr().GetPosition().GetLeft().SetValue(ParseDimension(value)); + else if (name == wxT("position-right")) + attr.GetTextBoxAttr().GetPosition().GetRight().SetValue(ParseDimension(value)); + else if (name == wxT("position-top")) + attr.GetTextBoxAttr().GetPosition().GetTop().SetValue(ParseDimension(value)); + else if (name == wxT("position-bottom")) + attr.GetTextBoxAttr().GetPosition().GetBottom().SetValue(ParseDimension(value)); + } + } + + xmlAttr = xmlAttr->GetNext(); + } + + return true; +} + +bool wxRichTextXMLHelper::ImportStyleDefinition(wxRichTextStyleSheet* sheet, wxXmlNode* node) +{ + wxString styleType = node->GetName(); + wxString styleName = node->GetAttribute(wxT("name"), wxEmptyString); + wxString baseStyleName = node->GetAttribute(wxT("basestyle"), wxEmptyString); + + if (styleName.empty()) + return false; + + if (styleType == wxT("characterstyle")) + { + wxRichTextCharacterStyleDefinition* def = new wxRichTextCharacterStyleDefinition(styleName); + def->SetBaseStyle(baseStyleName); + + wxXmlNode* child = node->GetChildren(); + while (child) + { + if (child->GetName() == wxT("style")) + { + wxRichTextAttr attr; + ImportStyle(attr, child, false); + def->SetStyle(attr); + } + child = child->GetNext(); + } + + ImportProperties(def->GetProperties(), node); + + sheet->AddCharacterStyle(def); + } + else if (styleType == wxT("paragraphstyle")) + { + wxRichTextParagraphStyleDefinition* def = new wxRichTextParagraphStyleDefinition(styleName); + + wxString nextStyleName = node->GetAttribute(wxT("nextstyle"), wxEmptyString); + def->SetNextStyle(nextStyleName); + def->SetBaseStyle(baseStyleName); + + wxXmlNode* child = node->GetChildren(); + while (child) + { + if (child->GetName() == wxT("style")) + { + wxRichTextAttr attr; + ImportStyle(attr, child, true); + def->SetStyle(attr); + } + child = child->GetNext(); + } + + ImportProperties(def->GetProperties(), node); + + sheet->AddParagraphStyle(def); + } + else if (styleType == wxT("boxstyle")) + { + wxRichTextBoxStyleDefinition* def = new wxRichTextBoxStyleDefinition(styleName); + + def->SetBaseStyle(baseStyleName); + + wxXmlNode* child = node->GetChildren(); + while (child) + { + if (child->GetName() == wxT("style")) + { + wxRichTextAttr attr; + ImportStyle(attr, child, true); + def->SetStyle(attr); + } + child = child->GetNext(); + } + + ImportProperties(def->GetProperties(), node); + + sheet->AddBoxStyle(def); + } + else if (styleType == wxT("liststyle")) + { + wxRichTextListStyleDefinition* def = new wxRichTextListStyleDefinition(styleName); + + wxString nextStyleName = node->GetAttribute(wxT("nextstyle"), wxEmptyString); + def->SetNextStyle(nextStyleName); + def->SetBaseStyle(baseStyleName); + + wxXmlNode* child = node->GetChildren(); + while (child) + { + if (child->GetName() == wxT("style")) + { + wxRichTextAttr attr; + ImportStyle(attr, child, true); + + wxString styleLevel = child->GetAttribute(wxT("level"), wxEmptyString); + if (styleLevel.empty()) + { + def->SetStyle(attr); + } + else + { + int level = wxAtoi(styleLevel); + if (level > 0 && level <= 10) + { + def->SetLevelAttributes(level-1, attr); + } + } + } + child = child->GetNext(); + } + + ImportProperties(def->GetProperties(), node); + + sheet->AddListStyle(def); + } + + return true; +} + +bool wxRichTextXMLHelper::ImportProperties(wxRichTextProperties& properties, wxXmlNode* node) +{ + wxXmlNode* child = node->GetChildren(); + while (child) + { + if (child->GetName() == wxT("properties")) + { + wxXmlNode* propertyChild = child->GetChildren(); + while (propertyChild) + { + if (propertyChild->GetName() == wxT("property")) + { + wxString name = propertyChild->GetAttribute(wxT("name"), wxEmptyString); + wxString value = propertyChild->GetAttribute(wxT("value"), wxEmptyString); + wxString type = propertyChild->GetAttribute(wxT("type"), wxEmptyString); + + wxVariant var = MakePropertyFromString(name, value, type); + if (!var.IsNull()) + { + properties.SetProperty(var); + } + } + propertyChild = propertyChild->GetNext(); + } + } + child = child->GetNext(); + } + return true; +} + +#if wxRICHTEXT_HAVE_DIRECT_OUTPUT +// write string to output +void wxRichTextXMLHelper::OutputString(wxOutputStream& stream, const wxString& str, + wxMBConv *WXUNUSED_IN_UNICODE(convMem), wxMBConv *convFile) +{ + if (str.empty()) return; +#if wxUSE_UNICODE + if (convFile) + { + const wxWX2MBbuf buf(str.mb_str(*convFile)); + stream.Write((const char*)buf, strlen((const char*)buf)); + } + else + { + const wxWX2MBbuf buf(str.mb_str(wxConvUTF8)); + stream.Write((const char*)buf, strlen((const char*)buf)); + } +#else + if ( convFile == NULL ) + stream.Write(str.mb_str(), str.Len()); + else + { + wxString str2(str.wc_str(*convMem), *convFile); + stream.Write(str2.mb_str(), str2.Len()); + } +#endif +} + +void wxRichTextXMLHelper::OutputIndentation(wxOutputStream& stream, int indent) +{ + wxString str = wxT("\n"); + for (int i = 0; i < indent; i++) + str << wxT(' ') << wxT(' '); + OutputString(stream, str, NULL, NULL); +} + +// Same as above, but create entities first. +// Translates '<' to "<", '>' to ">" and '&' to "&" +void wxRichTextXMLHelper::OutputStringEnt(wxOutputStream& stream, const wxString& str, + wxMBConv *convMem, wxMBConv *convFile) +{ + wxString buf; + size_t i, last, len; + wxChar c; + + len = str.Len(); + last = 0; + for (i = 0; i < len; i++) + { + c = str.GetChar(i); + + // Original code excluded "&" but we _do_ want to convert + // the ampersand beginning & because otherwise when read in, + // the original "&" becomes "&". + + if (c == wxT('<') || c == wxT('>') || c == wxT('"') || + (c == wxT('&') /* && (str.Mid(i+1, 4) != wxT("amp;")) */ )) + { + OutputString(stream, str.Mid(last, i - last), convMem, convFile); + switch (c) + { + case wxT('<'): + OutputString(stream, wxT("<"), NULL, NULL); + break; + case wxT('>'): + OutputString(stream, wxT(">"), NULL, NULL); + break; + case wxT('&'): + OutputString(stream, wxT("&"), NULL, NULL); + break; + case wxT('"'): + OutputString(stream, wxT("""), NULL, NULL); + break; + default: break; } + last = i + 1; } + else if (wxUChar(c) > 127) + { + OutputString(stream, str.Mid(last, i - last), convMem, convFile); - xmlAttr = xmlAttr->GetNext(); + wxString s(wxT("&#")); +#if wxUSE_UNICODE + s << (int) c; +#else + s << (int) wxUChar(c); +#endif + s << wxT(";"); + OutputString(stream, s, NULL, NULL); + last = i + 1; + } } + OutputString(stream, str.Mid(last, i - last), convMem, convFile); +} - return true; +void wxRichTextXMLHelper::OutputString(wxOutputStream& stream, const wxString& str) +{ + OutputString(stream, str, m_convMem, m_convFile); } -#endif - // wxUSE_STREAMS +void wxRichTextXMLHelper::OutputStringEnt(wxOutputStream& stream, const wxString& str) +{ + OutputStringEnt(stream, str, m_convMem, m_convFile); +} -// Import this object from XML -bool wxRichTextObject::ImportFromXML(wxRichTextBuffer* WXUNUSED(buffer), wxXmlNode* node, wxRichTextXMLHandler* handler, bool* recurse) +void wxRichTextXMLHelper::AddAttribute(wxString& str, const wxString& name, const int& v) { - handler->ImportProperties(this, node); - handler->ImportStyle(GetAttributes(), node, UsesParagraphAttributes()); + str << wxT(" ") << name << wxT("=\"") << wxString::Format(wxT("%d"), v) << wxT("\""); +} - *recurse = true; +void wxRichTextXMLHelper::AddAttribute(wxString& str, const wxString& name, const long& v) +{ + str << wxT(" ") << name << wxT("=\"") << wxString::Format(wxT("%ld"), v) << wxT("\""); +} - return true; +void wxRichTextXMLHelper::AddAttribute(wxString& str, const wxString& name, const double& v) +{ + str << wxT(" ") << name << wxT("=\"") << wxString::Format(wxT("%.2f"), (float) v) << wxT("\""); } -#if wxRICHTEXT_HAVE_DIRECT_OUTPUT -// Export this object directly to the given stream. -bool wxRichTextObject::ExportXML(wxOutputStream& stream, int indent, wxRichTextXMLHandler* handler) +void wxRichTextXMLHelper::AddAttribute(wxString& str, const wxString& name, const wxChar* s) { - ::OutputIndentation(stream, indent); - ::OutputString(stream, wxT("<") + GetXMLNodeName(), handler->GetConvMem(), handler->GetConvFile()); + str << wxT(" ") << name << wxT("=\"") << s << wxT("\""); +} - wxString style = handler->AddAttributes(GetAttributes(), true); +void wxRichTextXMLHelper::AddAttribute(wxString& str, const wxString& name, const wxString& s) +{ + str << wxT(" ") << name << wxT("=\"") << s << wxT("\""); +} - ::OutputString(stream, style + wxT(">"), handler->GetConvMem(), handler->GetConvFile()); +void wxRichTextXMLHelper::AddAttribute(wxString& str, const wxString& name, const wxColour& col) +{ + str << wxT(" ") << name << wxT("=\"") << wxT("#") << ColourToHexString(col) << wxT("\""); +} - if (GetProperties().GetCount() > 0) +void wxRichTextXMLHelper::AddAttribute(wxString& str, const wxString& name, const wxTextAttrDimension& dim) +{ + if (dim.IsValid()) { - handler->WriteProperties(stream, GetProperties(), indent); + wxString value = MakeString(dim.GetValue()) + wxT(",") + MakeString((int) dim.GetFlags()); + str << wxT(" ") << name << wxT("=\""); + str << value; + str << wxT("\""); } +} - wxRichTextCompositeObject* composite = wxDynamicCast(this, wxRichTextCompositeObject); - if (composite) - { - size_t i; - for (i = 0; i < composite->GetChildCount(); i++) - { - wxRichTextObject* child = composite->GetChild(i); - child->ExportXML(stream, indent+1, handler); - } - } +void wxRichTextXMLHelper::AddAttribute(wxString& str, const wxString& rootName, const wxTextAttrDimensions& dims) +{ + if (dims.GetLeft().IsValid()) + AddAttribute(str, rootName + wxString(wxT("-left")), dims.GetLeft()); + if (dims.GetRight().IsValid()) + AddAttribute(str, rootName + wxString(wxT("-right")), dims.GetRight()); + if (dims.GetTop().IsValid()) + AddAttribute(str, rootName + wxString(wxT("-top")), dims.GetTop()); + if (dims.GetBottom().IsValid()) + AddAttribute(str, rootName + wxString(wxT("-bottom")), dims.GetBottom()); +} - ::OutputIndentation(stream, indent); - ::OutputString(stream, wxT(""), handler->GetConvMem(), handler->GetConvFile()); - return true; +void wxRichTextXMLHelper::AddAttribute(wxString& str, const wxString& rootName, const wxTextAttrBorder& border) +{ + if (border.HasStyle()) + AddAttribute(str, rootName + wxString(wxT("-style")), border.GetStyle()); + if (border.HasColour()) + AddAttribute(str, rootName + wxString(wxT("-color")), border.GetColour()); + if (border.HasWidth()) + AddAttribute(str, rootName + wxString(wxT("-width")), border.GetWidth()); } -#endif -#if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT -// Export this object to the given parent node, usually creating at least one child node. -bool wxRichTextObject::ExportXML(wxXmlNode* parent, wxRichTextXMLHandler* handler) +void wxRichTextXMLHelper::AddAttribute(wxString& str, const wxString& rootName, const wxTextAttrBorders& borders) { - wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, GetXMLNodeName()); - parent->AddChild(elementNode); - handler->AddAttributes(elementNode, GetAttributes(), true); - handler->WriteProperties(elementNode, GetProperties()); + AddAttribute(str, rootName + wxString(wxT("-left")), borders.GetLeft()); + AddAttribute(str, rootName + wxString(wxT("-right")), borders.GetRight()); + AddAttribute(str, rootName + wxString(wxT("-top")), borders.GetTop()); + AddAttribute(str, rootName + wxString(wxT("-bottom")), borders.GetBottom()); +} - wxRichTextCompositeObject* composite = wxDynamicCast(this, wxRichTextCompositeObject); - if (composite) +/// Create a string containing style attributes +wxString wxRichTextXMLHelper::AddAttributes(const wxRichTextAttr& attr, bool isPara) +{ + wxString str; + if (attr.HasTextColour() && attr.GetTextColour().IsOk()) + AddAttribute(str, wxT("textcolor"), attr.GetTextColour()); + + if (attr.HasBackgroundColour() && attr.GetBackgroundColour().IsOk()) + AddAttribute(str, wxT("bgcolor"), attr.GetBackgroundColour()); + + if (attr.HasFontPointSize()) + AddAttribute(str, wxT("fontpointsize"), attr.GetFontSize()); + else if (attr.HasFontPixelSize()) + AddAttribute(str, wxT("fontpixelsize"), attr.GetFontSize()); + + if (attr.HasFontFamily()) + AddAttribute(str, wxT("fontfamily"), attr.GetFontFamily()); + + if (attr.HasFontItalic()) + AddAttribute(str, wxT("fontstyle"), attr.GetFontStyle()); + + if (attr.HasFontWeight()) + AddAttribute(str, wxT("fontweight"), attr.GetFontWeight()); + + if (attr.HasFontUnderlined()) + AddAttribute(str, wxT("fontunderlined"), (int) attr.GetFontUnderlined()); + + if (attr.HasFontFaceName()) + AddAttribute(str, wxT("fontface"), AttributeToXML(attr.GetFontFaceName())); + + if (attr.HasTextEffects()) { - size_t i; - for (i = 0; i < composite->GetChildCount(); i++) - { - wxRichTextObject* child = composite->GetChild(i); - child->ExportXML(elementNode, handler); - } + AddAttribute(str, wxT("texteffects"), attr.GetTextEffects()); + AddAttribute(str, wxT("texteffectflags"), attr.GetTextEffectFlags()); } - return true; -} -#endif + if (!attr.GetCharacterStyleName().empty()) + AddAttribute(str, wxT("characterstyle"), AttributeToXML(attr.GetCharacterStyleName())); -// Import this object from XML -bool wxRichTextPlainText::ImportFromXML(wxRichTextBuffer* buffer, wxXmlNode* node, wxRichTextXMLHandler* handler, bool* recurse) -{ - wxRichTextObject::ImportFromXML(buffer, node, handler, recurse); + if (attr.HasURL()) + AddAttribute(str, wxT("url"), AttributeToXML(attr.GetURL())); - if (node->GetName() == wxT("text")) + if (isPara) { - wxString text; - wxXmlNode* textChild = node->GetChildren(); - while (textChild) + if (attr.HasAlignment()) + AddAttribute(str, wxT("alignment"), (int) attr.GetAlignment()); + + if (attr.HasLeftIndent()) { - if (textChild->GetType() == wxXML_TEXT_NODE || - textChild->GetType() == wxXML_CDATA_SECTION_NODE) - { - wxString text2 = textChild->GetContent(); + AddAttribute(str, wxT("leftindent"), (int) attr.GetLeftIndent()); + AddAttribute(str, wxT("leftsubindent"), (int) attr.GetLeftSubIndent()); + } - // Strip whitespace from end - if (!text2.empty() && text2[text2.length()-1] == wxT('\n')) - text2 = text2.Mid(0, text2.length()-1); + if (attr.HasRightIndent()) + AddAttribute(str, wxT("rightindent"), (int) attr.GetRightIndent()); - if (!text2.empty() && text2[0] == wxT('"')) - text2 = text2.Mid(1); - if (!text2.empty() && text2[text2.length()-1] == wxT('"')) - text2 = text2.Mid(0, text2.length() - 1); + if (attr.HasParagraphSpacingAfter()) + AddAttribute(str, wxT("parspacingafter"), (int) attr.GetParagraphSpacingAfter()); - text += text2; - } - textChild = textChild->GetNext(); + if (attr.HasParagraphSpacingBefore()) + AddAttribute(str, wxT("parspacingbefore"), (int) attr.GetParagraphSpacingBefore()); + + if (attr.HasLineSpacing()) + AddAttribute(str, wxT("linespacing"), (int) attr.GetLineSpacing()); + + if (attr.HasBulletStyle()) + AddAttribute(str, wxT("bulletstyle"), (int) attr.GetBulletStyle()); + + if (attr.HasBulletNumber()) + AddAttribute(str, wxT("bulletnumber"), (int) attr.GetBulletNumber()); + + if (attr.HasBulletText()) + { + // If using a bullet symbol, convert to integer in case it's a non-XML-friendly character. + // Otherwise, assume it's XML-friendly text such as outline numbering, e.g. 1.2.3.1 + if (!attr.GetBulletText().empty() && (attr.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_SYMBOL)) + AddAttribute(str, wxT("bulletsymbol"), (int) (attr.GetBulletText()[0])); + else + AddAttribute(str, wxT("bullettext"), AttributeToXML(attr.GetBulletText())); + + AddAttribute(str, wxT("bulletfont"), attr.GetBulletFont()); } - SetText(text); - } - else if (node->GetName() == wxT("symbol")) - { - // This is a symbol that XML can't read in the normal way - wxString text; - wxXmlNode* textChild = node->GetChildren(); - while (textChild) + if (attr.HasBulletName()) + AddAttribute(str, wxT("bulletname"), AttributeToXML(attr.GetBulletName())); + + if (!attr.GetParagraphStyleName().empty()) + AddAttribute(str, wxT("parstyle"), AttributeToXML(attr.GetParagraphStyleName())); + + if (!attr.GetListStyleName().empty()) + AddAttribute(str, wxT("liststyle"), AttributeToXML(attr.GetListStyleName())); + + if (!attr.GetTextBoxAttr().GetBoxStyleName().empty()) + AddAttribute(str, wxT("boxstyle"), AttributeToXML(attr.GetTextBoxAttr().GetBoxStyleName())); + + if (attr.HasTabs()) { - if (textChild->GetType() == wxXML_TEXT_NODE || - textChild->GetType() == wxXML_CDATA_SECTION_NODE) + wxString strTabs; + size_t i; + for (i = 0; i < attr.GetTabs().GetCount(); i++) { - wxString text2 = textChild->GetContent(); - text += text2; + if (i > 0) strTabs << wxT(","); + strTabs << attr.GetTabs()[i]; } - textChild = textChild->GetNext(); + AddAttribute(str, wxT("tabs"), strTabs); + } + + if (attr.HasPageBreak()) + { + AddAttribute(str, wxT("pagebreak"), 1); } - wxString actualText; - actualText << (wxChar) wxAtoi(text); - SetText(actualText); + if (attr.HasOutlineLevel()) + AddAttribute(str, wxT("outlinelevel"), (int) attr.GetOutlineLevel()); } - else - return false; - - return true; -} - -#if wxRICHTEXT_HAVE_DIRECT_OUTPUT -// Export this object directly to the given stream. -bool wxRichTextPlainText::ExportXML(wxOutputStream& stream, int indent, wxRichTextXMLHandler* handler) -{ - wxString style = handler->AddAttributes(GetAttributes(), false); - int i; - int last = 0; - const wxString& text = GetText(); - int len = (int) text.Length(); + AddAttribute(str, wxT("margin"), attr.GetTextBoxAttr().GetMargins()); + AddAttribute(str, wxT("padding"), attr.GetTextBoxAttr().GetPadding()); + AddAttribute(str, wxT("position"), attr.GetTextBoxAttr().GetPosition()); + AddAttribute(str, wxT("border"), attr.GetTextBoxAttr().GetBorder()); + AddAttribute(str, wxT("outline"), attr.GetTextBoxAttr().GetOutline()); + AddAttribute(str, wxT("width"), attr.GetTextBoxAttr().GetWidth()); + AddAttribute(str, wxT("height"), attr.GetTextBoxAttr().GetHeight()); + AddAttribute(str, wxT("minwidth"), attr.GetTextBoxAttr().GetMinSize().GetWidth()); + AddAttribute(str, wxT("minheight"), attr.GetTextBoxAttr().GetMinSize().GetHeight()); + AddAttribute(str, wxT("maxwidth"), attr.GetTextBoxAttr().GetMaxSize().GetWidth()); + AddAttribute(str, wxT("maxheight"), attr.GetTextBoxAttr().GetMaxSize().GetHeight()); - if (len == 0) + if (attr.GetTextBoxAttr().HasVerticalAlignment()) { - i = 0; - ::OutputIndentation(stream, indent); - ::OutputString(stream, wxT("GetConvMem(), handler->GetConvFile()); - ::OutputString(stream, style + wxT(">"), handler->GetConvMem(), handler->GetConvFile()); - if (GetProperties().GetCount() > 0) - { - handler->WriteProperties(stream, GetProperties(), indent); - ::OutputIndentation(stream, indent); - } - ::OutputString(stream, wxT(""), handler->GetConvMem(), handler->GetConvFile()); + wxString value; + if (attr.GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_TOP) + value = wxT("top"); + else if (attr.GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_CENTRE) + value = wxT("centre"); + else if (attr.GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_BOTTOM) + value = wxT("bottom"); + else + value = wxT("none"); + AddAttribute(str, wxT("verticalalignment"), value); } - else for (i = 0; i < len; i++) + + if (attr.GetTextBoxAttr().HasFloatMode()) { -#if wxUSE_UNICODE - int c = (int) text[i]; -#else - int c = (int) wxUChar(text[i]); -#endif - if ((c < 32 || c == 34) && /* c != 9 && */ c != 10 && c != 13) - { - if (i > 0) - { - wxString fragment(text.Mid(last, i-last)); - if (!fragment.empty()) - { - ::OutputIndentation(stream, indent); - ::OutputString(stream, wxT("GetConvMem(), handler->GetConvFile()); + wxString value; + if (attr.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_LEFT) + value = wxT("left"); + else if (attr.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_RIGHT) + value = wxT("right"); + else + value = wxT("none"); + AddAttribute(str, wxT("float"), value); + } - ::OutputString(stream, style + wxT(">"), handler->GetConvMem(), handler->GetConvFile()); + if (attr.GetTextBoxAttr().HasClearMode()) + { + wxString value; + if (attr.GetTextBoxAttr().GetClearMode() == wxTEXT_BOX_ATTR_CLEAR_LEFT) + value = wxT("left"); + else if (attr.GetTextBoxAttr().GetClearMode() == wxTEXT_BOX_ATTR_CLEAR_RIGHT) + value = wxT("right"); + else if (attr.GetTextBoxAttr().GetClearMode() == wxTEXT_BOX_ATTR_CLEAR_BOTH) + value = wxT("both"); + else + value = wxT("none"); + AddAttribute(str, wxT("clear"), value); + } - if (!fragment.empty() && (fragment[0] == wxT(' ') || fragment[fragment.length()-1] == wxT(' '))) - { - ::OutputString(stream, wxT("\""), handler->GetConvMem(), handler->GetConvFile()); - ::OutputStringEnt(stream, fragment, handler->GetConvMem(), handler->GetConvFile()); - ::OutputString(stream, wxT("\""), handler->GetConvMem(), handler->GetConvFile()); - } - else - ::OutputStringEnt(stream, fragment, handler->GetConvMem(), handler->GetConvFile()); + if (attr.GetTextBoxAttr().HasCollapseBorders()) + AddAttribute(str, wxT("collapse-borders"), (int) attr.GetTextBoxAttr().GetCollapseBorders()); - if (GetProperties().GetCount() > 0) - { - handler->WriteProperties(stream, GetProperties(), indent); - ::OutputIndentation(stream, indent); - } - ::OutputString(stream, wxT(""), handler->GetConvMem(), handler->GetConvFile()); - } - } + return str; +} +// Write the properties +bool wxRichTextXMLHelper::WriteProperties(wxOutputStream& stream, const wxRichTextProperties& properties, int level) +{ + if (properties.GetCount() > 0) + { + level ++; - // Output this character as a number in a separate tag, because XML can't cope - // with entities below 32 except for 10 and 13 - last = i + 1; - ::OutputIndentation(stream, indent); - ::OutputString(stream, wxT("GetConvMem(), handler->GetConvFile()); + OutputIndentation(stream, level); + OutputString(stream, wxT("")); - ::OutputString(stream, style + wxT(">"), handler->GetConvMem(), handler->GetConvFile()); - ::OutputString(stream, wxString::Format(wxT("%d"), c), handler->GetConvMem(), handler->GetConvFile()); + level ++; - if (GetProperties().GetCount() > 0) + size_t i; + for (i = 0; i < properties.GetCount(); i++) + { + const wxVariant& var = properties[i]; + if (!var.IsNull()) { - handler->WriteProperties(stream, GetProperties(), indent); - ::OutputIndentation(stream, indent); + const wxString& name = var.GetName(); + wxString value = MakeStringFromProperty(var); + + OutputIndentation(stream, level); + OutputString(stream, wxT("")); } - ::OutputString(stream, wxT(""), handler->GetConvMem(), handler->GetConvFile()); } - } - - wxString fragment; - if (last == 0) - fragment = text; - else - fragment = text.Mid(last, i-last); - - if (last < len) - { - ::OutputIndentation(stream, indent); - ::OutputString(stream, wxT("GetConvMem(), handler->GetConvFile()); - ::OutputString(stream, style + wxT(">"), handler->GetConvMem(), handler->GetConvFile()); - - if (GetProperties().GetCount() > 0) - { - handler->WriteProperties(stream, GetProperties(), indent); - ::OutputIndentation(stream, indent); - } + level --; - if (!fragment.empty() && (fragment[0] == wxT(' ') || fragment[fragment.length()-1] == wxT(' '))) - { - ::OutputString(stream, wxT("\""), handler->GetConvMem(), handler->GetConvFile()); - ::OutputStringEnt(stream, fragment, handler->GetConvMem(), handler->GetConvFile()); - ::OutputString(stream, wxT("\""), handler->GetConvMem(), handler->GetConvFile()); - } - else - ::OutputStringEnt(stream, fragment, handler->GetConvMem(), handler->GetConvFile()); + OutputIndentation(stream, level); + OutputString(stream, wxT("")); - ::OutputString(stream, wxT(""), handler->GetConvMem(), handler->GetConvFile()); + level --; } + return true; } -#endif -#if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT -// Export this object to the given parent node, usually creating at least one child node. -bool wxRichTextPlainText::ExportXML(wxXmlNode* parent, wxRichTextXMLHandler* handler) +bool wxRichTextXMLHelper::ExportStyleDefinition(wxOutputStream& stream, wxRichTextStyleDefinition* def, int level) { - int i; - int last = 0; - const wxString& text = GetText(); - int len = (int) text.Length(); + wxRichTextCharacterStyleDefinition* charDef = wxDynamicCast(def, wxRichTextCharacterStyleDefinition); + wxRichTextParagraphStyleDefinition* paraDef = wxDynamicCast(def, wxRichTextParagraphStyleDefinition); + wxRichTextListStyleDefinition* listDef = wxDynamicCast(def, wxRichTextListStyleDefinition); + wxRichTextBoxStyleDefinition* boxDef = wxDynamicCast(def, wxRichTextBoxStyleDefinition); - if (len == 0) - { - i = 0; + wxString name = def->GetName(); + wxString nameProp; + if (!name.empty()) + nameProp = wxT(" name=\"") + AttributeToXML(name) + wxT("\""); - wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("text")); - parent->AddChild(elementNode); + wxString baseStyle = def->GetBaseStyle(); + wxString baseStyleProp; + if (!baseStyle.empty()) + baseStyleProp = wxT(" basestyle=\"") + AttributeToXML(baseStyle) + wxT("\""); - handler->AddAttributes(elementNode, GetAttributes(), false); - handler->WriteProperties(elementNode, GetProperties()); - } - else for (i = 0; i < len; i++) + wxString descr = def->GetDescription(); + wxString descrProp; + if (!descr.empty()) + descrProp = wxT(" description=\"") + AttributeToXML(descr) + wxT("\""); + + if (charDef) { -#if wxUSE_UNICODE - int c = (int) text[i]; -#else - int c = (int) wxUChar(text[i]); -#endif - if ((c < 32 || c == 34) && c != 10 && c != 13) - { - if (i > 0) - { - wxString fragment(text.Mid(last, i-last)); - if (!fragment.empty()) - { - // TODO: I'm assuming wxXmlDocument will output quotes if necessary - wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("text")); - parent->AddChild(elementNode); - handler->AddAttributes(elementNode, GetAttributes(), false); - handler->WriteProperties(elementNode, GetProperties()); + OutputIndentation(stream, level); + OutputString(stream, wxT("")); - wxXmlNode* textNode = new wxXmlNode(wxXML_TEXT_NODE, wxT("text")); - elementNode->AddChild(textNode); + level ++; - if (fragment[0] == wxT(' ') || fragment[fragment.length()-1] == wxT(' ')) - fragment = wxT("\"") + fragment + wxT("\""); + wxString style = AddAttributes(def->GetStyle(), false); - textNode->SetContent(fragment); - } - } + OutputIndentation(stream, level); + OutputString(stream, wxT("")); - // Output this character as a number in a separate tag, because XML can't cope - // with entities below 32 except for 10 and 13 + level --; - wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("symbol")); - parent->AddChild(elementNode); + OutputIndentation(stream, level); + OutputString(stream, wxT("")); + } + else if (listDef) + { + OutputIndentation(stream, level); - handler->AddAttributes(elementNode, GetAttributes(), false); - handler->WriteProperties(elementNode, GetProperties()); + if (!listDef->GetNextStyle().empty()) + baseStyleProp << wxT(" nextstyle=\"") << AttributeToXML(listDef->GetNextStyle()) << wxT("\""); - wxXmlNode* textNode = new wxXmlNode(wxXML_TEXT_NODE, wxT("text")); - elementNode->AddChild(textNode); - textNode->SetContent(wxString::Format(wxT("%d"), c)); + OutputString(stream, wxT("")); - last = i + 1; - } - } + level ++; - wxString fragment; - if (last == 0) - fragment = text; - else - fragment = text.Mid(last, i-last); + wxString style = AddAttributes(def->GetStyle(), true); - if (last < len) - { - wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("text")); - parent->AddChild(elementNode); - handler->AddAttributes(elementNode, GetAttributes(), false); + OutputIndentation(stream, level); + OutputString(stream, wxT("")); + + int i; + for (i = 0; i < 10; i ++) + { + wxRichTextAttr* levelAttr = listDef->GetLevelAttributes(i); + if (levelAttr) + { + wxString style = AddAttributes(def->GetStyle(), true); + wxString levelStr = wxString::Format(wxT(" level=\"%d\" "), (i+1)); + + OutputIndentation(stream, level); + OutputString(stream, wxT("")); + } + } - if (fragment[0] == wxT(' ') || fragment[fragment.length()-1] == wxT(' ')) - fragment = wxT("\"") + fragment + wxT("\""); + level --; - textNode->SetContent(fragment); + OutputIndentation(stream, level); + OutputString(stream, wxT("")); } - return true; -} -#endif + else if (paraDef) + { + OutputIndentation(stream, level); + if (!paraDef->GetNextStyle().empty()) + baseStyleProp << wxT(" nextstyle=\"") << AttributeToXML(paraDef->GetNextStyle()) << wxT("\""); -// Import this object from XML -bool wxRichTextImage::ImportFromXML(wxRichTextBuffer* buffer, wxXmlNode* node, wxRichTextXMLHandler* handler, bool* recurse) -{ - wxRichTextObject::ImportFromXML(buffer, node, handler, recurse); + OutputString(stream, wxT("")); - wxBitmapType imageType = wxBITMAP_TYPE_PNG; - wxString value = node->GetAttribute(wxT("imagetype"), wxEmptyString); - if (!value.empty()) - { - int type = wxAtoi(value); + level ++; - // note: 0 == wxBITMAP_TYPE_INVALID - if (type <= 0 || type >= wxBITMAP_TYPE_MAX) - { - wxLogWarning("Invalid bitmap type specified for tag: %d", type); - } - else - { - imageType = (wxBitmapType)type; - } - } + wxString style = AddAttributes(def->GetStyle(), true); - wxString data; + OutputIndentation(stream, level); + OutputString(stream, wxT("")); - } - imageChild = imageChild->GetNext(); - } + level --; - if (!data.empty()) + OutputIndentation(stream, level); + OutputString(stream, wxT("")); + } + else if (boxDef) { - wxStringInputStream strStream(data); + OutputIndentation(stream, level); - GetImageBlock().ReadHex(strStream, data.length(), imageType); + OutputString(stream, wxT("")); - return true; - } - else - return false; -} + level ++; -#if wxRICHTEXT_HAVE_DIRECT_OUTPUT -// Export this object directly to the given stream. -bool wxRichTextImage::ExportXML(wxOutputStream& stream, int indent, wxRichTextXMLHandler* handler) -{ - wxString style = handler->AddAttributes(GetAttributes(), false); + wxString style = AddAttributes(def->GetStyle(), true); - ::OutputIndentation(stream, indent); - ::OutputString(stream, wxT("GetConvMem(), handler->GetConvFile()); - if (!GetImageBlock().IsOk()) - { - // No data - ::OutputString(stream, style + wxT(">"), handler->GetConvMem(), handler->GetConvFile()); - } - else - { - ::OutputString(stream, wxString::Format(wxT(" imagetype=\"%d\""), (int) GetImageBlock().GetImageType()) + style + wxT(">"), handler->GetConvMem(), handler->GetConvFile()); - } - if (GetProperties().GetCount() > 0) - { - handler->WriteProperties(stream, GetProperties(), indent); - ::OutputIndentation(stream, indent); - } + OutputIndentation(stream, level); + OutputString(stream, wxT("")); - // wxStopWatch stopwatch; + level --; - GetImageBlock().WriteHex(stream); + OutputIndentation(stream, level); + OutputString(stream, wxT("")); + } - // wxLogDebug(wxT("Image conversion to hex took %ldms"), stopwatch.Time()); + WriteProperties(stream, def->GetProperties(), level); - ::OutputString(stream, wxT("\n"), handler->GetConvMem(), handler->GetConvFile()); - ::OutputIndentation(stream, indent); - ::OutputString(stream, wxT(""), handler->GetConvMem(), handler->GetConvFile()); return true; } + #endif + // wxRICHTEXT_HAVE_DIRECT_OUTPUT + #if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT -// Export this object to the given parent node, usually creating at least one child node. -bool wxRichTextImage::ExportXML(wxXmlNode* parent, wxRichTextXMLHandler* handler) + +void wxRichTextXMLHelper::AddAttribute(wxXmlNode* node, const wxString& name, const int& v) { - wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("image")); - parent->AddChild(elementNode); + node->AddAttribute(name, MakeString(v)); +} - if (GetImageBlock().IsOk()) - elementNode->AddAttribute(wxT("imagetype"), MakeString((int) GetImageBlock().GetImageType())); +void wxRichTextXMLHelper::AddAttribute(wxXmlNode* node, const wxString& name, const long& v) +{ + node->AddAttribute(name, MakeString(v)); +} - handler->AddAttributes(elementNode, GetAttributes(), false); - handler->WriteProperties(elementNode, GetProperties()); +void wxRichTextXMLHelper::AddAttribute(wxXmlNode* node, const wxString& name, const double& v) +{ + node->AddAttribute(name, MakeString(v)); +} - wxXmlNode* dataNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("data")); - elementNode->AddChild(dataNode); - wxXmlNode* textNode = new wxXmlNode(wxXML_TEXT_NODE, wxT("text")); - dataNode->AddChild(textNode); +void wxRichTextXMLHelper::AddAttribute(wxXmlNode* node, const wxString& name, const wxString& s) +{ + node->AddAttribute(name, s); +} - wxString strData; -#if 1 - { - wxMemoryOutputStream stream; - if (GetImageBlock().WriteHex(stream)) - { - if (stream.GetSize() > 0) - { - int size = stream.GetSize(); -#ifdef __WXDEBUG__ - int size2 = stream.GetOutputStreamBuffer()->GetIntPosition(); - wxASSERT(size == size2); -#endif - unsigned char* data = new unsigned char[size]; - stream.CopyTo(data, size); - strData = wxString((const char*) data, wxConvUTF8, size); - delete[] data; - } - else - strData = wxEmptyString; - } +void wxRichTextXMLHelper::AddAttribute(wxXmlNode* node, const wxString& name, const wxColour& col) +{ + node->AddAttribute(name, MakeString(col)); +} - } -#else +void wxRichTextXMLHelper::AddAttribute(wxXmlNode* node, const wxString& name, const wxTextAttrDimension& dim) +{ + if (dim.IsValid()) { - wxStringOutputStream strStream(& strData); - GetImageBlock().WriteHex(strStream); + wxString value = MakeString(dim.GetValue()) + wxT(",") + MakeString(dim.GetFlags()); + AddAttribute(node, name, value); } -#endif +} - textNode->SetContent(strData); - textNode->SetNoConversion(true); // optimize speed +void wxRichTextXMLHelper::AddAttribute(wxXmlNode* node, const wxString& rootName, const wxTextAttrDimensions& dims) +{ + if (dims.GetLeft().IsValid()) + AddAttribute(node, rootName + wxString(wxT("-left")), dims.GetLeft()); + if (dims.GetRight().IsValid()) + AddAttribute(node, rootName + wxString(wxT("-right")), dims.GetRight()); + if (dims.GetTop().IsValid()) + AddAttribute(node, rootName + wxString(wxT("-top")), dims.GetTop()); + if (dims.GetBottom().IsValid()) + AddAttribute(node, rootName + wxString(wxT("-bottom")), dims.GetBottom()); +} - return true; +void wxRichTextXMLHelper::AddAttribute(wxXmlNode* node, const wxString& rootName, const wxTextAttrBorder& border) +{ + if (border.HasStyle()) + AddAttribute(node, rootName + wxString(wxT("-style")), border.GetStyle()); + if (border.HasColour()) + AddAttribute(node, rootName + wxString(wxT("-color")), border.GetColour()); + if (border.HasWidth()) + AddAttribute(node, rootName + wxString(wxT("-width")), border.GetWidth()); } -#endif +void wxRichTextXMLHelper::AddAttribute(wxXmlNode* node, const wxString& rootName, const wxTextAttrBorders& borders) +{ + AddAttribute(node, rootName + wxString(wxT("-left")), borders.GetLeft()); + AddAttribute(node, rootName + wxString(wxT("-right")), borders.GetRight()); + AddAttribute(node, rootName + wxString(wxT("-top")), borders.GetTop()); + AddAttribute(node, rootName + wxString(wxT("-bottom")), borders.GetBottom()); +} -// Import this object from XML -bool wxRichTextParagraphLayoutBox::ImportFromXML(wxRichTextBuffer* buffer, wxXmlNode* node, wxRichTextXMLHandler* handler, bool* recurse) +bool wxRichTextXMLHelper::ExportStyleDefinition(wxXmlNode* parent, wxRichTextStyleDefinition* def) { - wxRichTextObject::ImportFromXML(buffer, node, handler, recurse); + wxRichTextCharacterStyleDefinition* charDef = wxDynamicCast(def, wxRichTextCharacterStyleDefinition); + wxRichTextParagraphStyleDefinition* paraDef = wxDynamicCast(def, wxRichTextParagraphStyleDefinition); + wxRichTextBoxStyleDefinition* boxDef = wxDynamicCast(def, wxRichTextBoxStyleDefinition); + wxRichTextListStyleDefinition* listDef = wxDynamicCast(def, wxRichTextListStyleDefinition); - *recurse = true; + wxString baseStyle = def->GetBaseStyle(); + wxString descr = def->GetDescription(); - wxString partial = node->GetAttribute(wxT("partialparagraph"), wxEmptyString); - if (partial == wxT("true")) - SetPartialParagraph(true); + wxXmlNode* defNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxEmptyString); + parent->AddChild(defNode); + if (!baseStyle.empty()) + defNode->AddAttribute(wxT("basestyle"), baseStyle); + if (!descr.empty()) + defNode->AddAttribute(wxT("description"), descr); - wxXmlNode* child = wxRichTextXMLHandler::FindNode(node, wxT("stylesheet")); - if (child && (handler->GetFlags() & wxRICHTEXT_HANDLER_INCLUDE_STYLESHEET)) + wxXmlNode* styleNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("style")); + defNode->AddChild(styleNode); + + if (charDef) { - wxRichTextStyleSheet* sheet = new wxRichTextStyleSheet; - wxString sheetName = child->GetAttribute(wxT("name"), wxEmptyString); - wxString sheetDescription = child->GetAttribute(wxT("description"), wxEmptyString); - sheet->SetName(sheetName); - sheet->SetDescription(sheetDescription); + defNode->SetName(wxT("characterstyle")); + AddAttributes(styleNode, def->GetStyle(), false); + } + else if (listDef) + { + defNode->SetName(wxT("liststyle")); - wxXmlNode* child2 = child->GetChildren(); - while (child2) + if (!listDef->GetNextStyle().empty()) + defNode->AddAttribute(wxT("nextstyle"), listDef->GetNextStyle()); + + AddAttributes(styleNode, def->GetStyle(), true); + + int i; + for (i = 0; i < 10; i ++) { - handler->ImportStyleDefinition(sheet, child2); + wxRichTextAttr* levelAttr = listDef->GetLevelAttributes(i); + if (levelAttr) + { + wxXmlNode* levelNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("style")); + defNode->AddChild(levelNode); + levelNode->AddAttribute(wxT("level"), MakeString(i+1)); + AddAttributes(levelNode, * levelAttr, true); + } + } + } + else if (boxDef) + { + defNode->SetName(wxT("boxstyle")); + + AddAttributes(styleNode, def->GetStyle(), true); + } + else if (paraDef) + { + defNode->SetName(wxT("paragraphstyle")); - child2 = child2->GetNext(); - } - handler->ImportProperties(sheet->GetProperties(), child); + if (!paraDef->GetNextStyle().empty()) + defNode->AddAttribute(wxT("nextstyle"), paraDef->GetNextStyle()); - // Notify that styles have changed. If this is vetoed by the app, - // the new sheet will be deleted. If it is not vetoed, the - // old sheet will be deleted and replaced with the new one. - buffer->SetStyleSheetAndNotify(sheet); + AddAttributes(styleNode, def->GetStyle(), true); } + WriteProperties(defNode, def->GetProperties()); + return true; } -#if wxRICHTEXT_HAVE_DIRECT_OUTPUT -// Export this object directly to the given stream. -bool wxRichTextParagraphLayoutBox::ExportXML(wxOutputStream& stream, int indent, wxRichTextXMLHandler* handler) +bool wxRichTextXMLHelper::AddAttributes(wxXmlNode* node, wxRichTextAttr& attr, bool isPara) { - ::OutputIndentation(stream, indent); - wxString nodeName = GetXMLNodeName(); - ::OutputString(stream, wxT("<") + nodeName, handler->GetConvMem(), handler->GetConvFile()); - - wxString style = handler->AddAttributes(GetAttributes(), true); - - if (GetPartialParagraph()) - style << wxT(" partialparagraph=\"true\""); + if (attr.HasTextColour() && attr.GetTextColour().IsOk()) + node->AddAttribute(wxT("textcolor"), MakeString(attr.GetTextColour())); + if (attr.HasBackgroundColour() && attr.GetBackgroundColour().IsOk()) + node->AddAttribute(wxT("bgcolor"), MakeString(attr.GetBackgroundColour())); - ::OutputString(stream, style + wxT(">"), handler->GetConvMem(), handler->GetConvFile()); + if (attr.HasFontPointSize()) + node->AddAttribute(wxT("fontpointsize"), MakeString(attr.GetFontSize())); + else if (attr.HasFontPixelSize()) + node->AddAttribute(wxT("fontpixelsize"), MakeString(attr.GetFontSize())); + if (attr.HasFontFamily()) + node->AddAttribute(wxT("fontfamily"), MakeString(attr.GetFontFamily())); + if (attr.HasFontItalic()) + node->AddAttribute(wxT("fontstyle"), MakeString(attr.GetFontStyle())); + if (attr.HasFontWeight()) + node->AddAttribute(wxT("fontweight"), MakeString(attr.GetFontWeight())); + if (attr.HasFontUnderlined()) + node->AddAttribute(wxT("fontunderlined"), MakeString((int) attr.GetFontUnderlined())); + if (attr.HasFontFaceName()) + node->AddAttribute(wxT("fontface"), attr.GetFontFaceName()); - if (GetProperties().GetCount() > 0) + if (attr.HasTextEffects()) { - handler->WriteProperties(stream, GetProperties(), indent); + node->AddAttribute(wxT("texteffects"), MakeString(attr.GetTextEffects())); + node->AddAttribute(wxT("texteffectflags"), MakeString(attr.GetTextEffectFlags())); } + if (attr.HasCharacterStyleName() && !attr.GetCharacterStyleName().empty()) + node->AddAttribute(wxT("characterstyle"), attr.GetCharacterStyleName()); - size_t i; - for (i = 0; i < GetChildCount(); i++) - { - wxRichTextObject* child = GetChild(i); - child->ExportXML(stream, indent+1, handler); - } + if (attr.HasURL()) + node->AddAttribute(wxT("url"), attr.GetURL()); // TODO: do we need to wrap this in AttributeToXML? - ::OutputIndentation(stream, indent); - ::OutputString(stream, wxT(""), handler->GetConvMem(), handler->GetConvFile()); - return true; -} -#endif + if (isPara) + { + if (attr.HasAlignment()) + node->AddAttribute(wxT("alignment"), MakeString((int) attr.GetAlignment())); -#if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT -// Export this object to the given parent node, usually creating at least one child node. -bool wxRichTextParagraphLayoutBox::ExportXML(wxXmlNode* parent, wxRichTextXMLHandler* handler) -{ - wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, GetXMLNodeName()); - parent->AddChild(elementNode); - handler->AddAttributes(elementNode, GetAttributes(), true); - handler->WriteProperties(elementNode, GetProperties()); + if (attr.HasLeftIndent()) + { + node->AddAttribute(wxT("leftindent"), MakeString((int) attr.GetLeftIndent())); + node->AddAttribute(wxT("leftsubindent"), MakeString((int) attr.GetLeftSubIndent())); + } - if (GetPartialParagraph()) - elementNode->AddAttribute(wxT("partialparagraph"), wxT("true")); + if (attr.HasRightIndent()) + node->AddAttribute(wxT("rightindent"), MakeString((int) attr.GetRightIndent())); - size_t i; - for (i = 0; i < GetChildCount(); i++) - { - wxRichTextObject* child = GetChild(i); - child->ExportXML(elementNode, handler); - } + if (attr.HasParagraphSpacingAfter()) + node->AddAttribute(wxT("parspacingafter"), MakeString((int) attr.GetParagraphSpacingAfter())); - return true; -} -#endif + if (attr.HasParagraphSpacingBefore()) + node->AddAttribute(wxT("parspacingbefore"), MakeString((int) attr.GetParagraphSpacingBefore())); -// Import this object from XML -bool wxRichTextTable::ImportFromXML(wxRichTextBuffer* buffer, wxXmlNode* node, wxRichTextXMLHandler* handler, bool* recurse) -{ - wxRichTextBox::ImportFromXML(buffer, node, handler, recurse); + if (attr.HasLineSpacing()) + node->AddAttribute(wxT("linespacing"), MakeString((int) attr.GetLineSpacing())); - *recurse = false; + if (attr.HasBulletStyle()) + node->AddAttribute(wxT("bulletstyle"), MakeString((int) attr.GetBulletStyle())); - m_rowCount = wxAtoi(node->GetAttribute(wxT("rows"), wxEmptyString)); - m_colCount = wxAtoi(node->GetAttribute(wxT("cols"), wxEmptyString)); + if (attr.HasBulletNumber()) + node->AddAttribute(wxT("bulletnumber"), MakeString((int) attr.GetBulletNumber())); - wxXmlNode* child = node->GetChildren(); - while (child) - { - wxRichTextObject* childObj = handler->CreateObjectForXMLName(this, child->GetName()); - if (childObj) + if (attr.HasBulletText()) { - AppendChild(childObj); - handler->ImportXML(buffer, childObj, child); + // If using a bullet symbol, convert to integer in case it's a non-XML-friendly character. + // Otherwise, assume it's XML-friendly text such as outline numbering, e.g. 1.2.3.1 + if (!attr.GetBulletText().empty() && (attr.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_SYMBOL)) + node->AddAttribute(wxT("bulletsymbol"), MakeString((int) (attr.GetBulletText()[0]))); + else + node->AddAttribute(wxT("bullettext"), attr.GetBulletText()); + + if (!attr.GetBulletFont().empty()) + node->AddAttribute(wxT("bulletfont"), attr.GetBulletFont()); } - child = child->GetNext(); - } - m_cells.Add(wxRichTextObjectPtrArray(), m_rowCount); - int i, j; - for (i = 0; i < m_rowCount; i++) - { - wxRichTextObjectPtrArray& colArray = m_cells[i]; - for (j = 0; j < m_colCount; j++) + if (attr.HasBulletName()) + node->AddAttribute(wxT("bulletname"), attr.GetBulletName()); + + if (!attr.GetParagraphStyleName().empty()) + node->AddAttribute(wxT("parstyle"), attr.GetParagraphStyleName()); + + if (!attr.GetListStyleName().empty()) + node->AddAttribute(wxT("liststyle"), attr.GetListStyleName()); + + if (!attr.GetTextBoxAttr().GetBoxStyleName().empty()) + node->AddAttribute(wxT("boxstyle"), attr.GetTextBoxAttr().GetBoxStyleName()); + + if (attr.HasTabs()) { - int idx = i * m_colCount + j; - if (idx < (int) GetChildren().GetCount()) + wxString tabs; + size_t i; + for (i = 0; i < attr.GetTabs().GetCount(); i++) { - wxRichTextCell* cell = wxDynamicCast(GetChildren().Item(idx)->GetData(), wxRichTextCell); - if (cell) - colArray.Add(cell); + if (i > 0) + tabs << wxT(","); + tabs << attr.GetTabs()[i]; } + node->AddAttribute(wxT("tabs"), tabs); } - } - - return true; -} -#if wxRICHTEXT_HAVE_DIRECT_OUTPUT -// Export this object directly to the given stream. -bool wxRichTextTable::ExportXML(wxOutputStream& stream, int indent, wxRichTextXMLHandler* handler) -{ - ::OutputIndentation(stream, indent); - wxString nodeName = GetXMLNodeName(); - ::OutputString(stream, wxT("<") + nodeName, handler->GetConvMem(), handler->GetConvFile()); + if (attr.HasPageBreak()) + node->AddAttribute(wxT("pagebreak"), wxT("1")); - wxString style = handler->AddAttributes(GetAttributes(), true); + if (attr.HasOutlineLevel()) + node->AddAttribute(wxT("outlinelevel"), MakeString((int) attr.GetOutlineLevel())); + } - style << wxT(" rows=\"") << m_rowCount << wxT("\""); - style << wxT(" cols=\"") << m_colCount << wxT("\""); + AddAttribute(node, wxT("margin"), attr.GetTextBoxAttr().GetMargins()); + AddAttribute(node, wxT("padding"), attr.GetTextBoxAttr().GetPadding()); + AddAttribute(node, wxT("position"), attr.GetTextBoxAttr().GetPosition()); + AddAttribute(node, wxT("border"), attr.GetTextBoxAttr().GetBorder()); + AddAttribute(node, wxT("outline"), attr.GetTextBoxAttr().GetOutline()); + AddAttribute(node, wxT("width"), attr.GetTextBoxAttr().GetWidth()); + AddAttribute(node, wxT("height"), attr.GetTextBoxAttr().GetHeight()); + AddAttribute(node, wxT("minwidth"), attr.GetTextBoxAttr().GetMinSize().GetWidth()); + AddAttribute(node, wxT("minheight"), attr.GetTextBoxAttr().GetMinSize().GetHeight()); + AddAttribute(node, wxT("maxwidth"), attr.GetTextBoxAttr().GetMaxSize().GetWidth()); + AddAttribute(node, wxT("maxheight"), attr.GetTextBoxAttr().GetMaxSize().GetHeight()); - ::OutputString(stream, style + wxT(">"), handler->GetConvMem(), handler->GetConvFile()); + if (attr.GetTextBoxAttr().HasVerticalAlignment()) + { + wxString value; + if (attr.GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_TOP) + value = wxT("top"); + else if (attr.GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_CENTRE) + value = wxT("centre"); + else if (attr.GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_BOTTOM) + value = wxT("bottom"); + else + value = wxT("none"); + AddAttribute(node, wxT("verticalalignment"), value); + } - if (GetProperties().GetCount() > 0) + if (attr.GetTextBoxAttr().HasFloatMode()) { - handler->WriteProperties(stream, GetProperties(), indent); + wxString value; + if (attr.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_LEFT) + value = wxT("left"); + else if (attr.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_RIGHT) + value = wxT("right"); + else + value = wxT("none"); + AddAttribute(node, wxT("float"), value); } - int i, j; - for (i = 0; i < m_rowCount; i++) + if (attr.GetTextBoxAttr().HasClearMode()) { - for (j = 0; j < m_colCount; j ++) - { - wxRichTextCell* cell = GetCell(i, j); - cell->ExportXML(stream, indent+1, handler); - } + wxString value; + if (attr.GetTextBoxAttr().GetClearMode() == wxTEXT_BOX_ATTR_CLEAR_LEFT) + value = wxT("left"); + else if (attr.GetTextBoxAttr().GetClearMode() == wxTEXT_BOX_ATTR_CLEAR_RIGHT) + value = wxT("right"); + else if (attr.GetTextBoxAttr().GetClearMode() == wxTEXT_BOX_ATTR_CLEAR_BOTH) + value = wxT("both"); + else + value = wxT("none"); + AddAttribute(node, wxT("clear"), value); } - ::OutputIndentation(stream, indent); - ::OutputString(stream, wxT(""), handler->GetConvMem(), handler->GetConvFile()); + if (attr.GetTextBoxAttr().HasCollapseBorders()) + AddAttribute(node, wxT("collapse-borders"), (int) attr.GetTextBoxAttr().GetCollapseBorders()); return true; } -#endif -#if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT -// Export this object to the given parent node, usually creating at least one child node. -bool wxRichTextTable::ExportXML(wxXmlNode* parent, wxRichTextXMLHandler* handler) +bool wxRichTextXMLHelper::WriteProperties(wxXmlNode* node, const wxRichTextProperties& properties) { - wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, GetXMLNodeName()); - parent->AddChild(elementNode); - handler->AddAttributes(elementNode, GetAttributes(), true); - handler->WriteProperties(elementNode, GetProperties()); - - elementNode->AddAttribute(wxT("rows"), wxString::Format(wxT("%d"), m_rowCount)); - elementNode->AddAttribute(wxT("cols"), wxString::Format(wxT("%d"), m_colCount)); - - int i, j; - for (i = 0; i < m_rowCount; i++) + if (properties.GetCount() > 0) { - for (j = 0; j < m_colCount; j ++) + wxXmlNode* propertiesNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("properties")); + node->AddChild(propertiesNode); + size_t i; + for (i = 0; i < properties.GetCount(); i++) { - wxRichTextCell* cell = GetCell(i, j); - cell->ExportXML(elementNode, handler); + const wxVariant& var = properties[i]; + if (!var.IsNull()) + { + wxXmlNode* propertyNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("property")); + propertiesNode->AddChild(propertyNode); + + const wxString& name = var.GetName(); + wxString value = MakeStringFromProperty(var); + + AddAttribute(propertyNode, wxT("name"), name); + AddAttribute(propertyNode, wxT("type"), var.GetType()); + AddAttribute(propertyNode, wxT("value"), value); + } } } - return true; } -#endif +#endif + // wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT #endif // wxUSE_RICHTEXT && wxUSE_XML -- 2.45.2