+ handler->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("</symbol>"));
+ }
+ }
+
+ wxString fragment;
+ if (last == 0)
+ fragment = text;
+ else
+ fragment = text.Mid(last, i-last);
+
+ if (last < len)
+ {
+ handler->GetHelper().OutputIndentation(stream, indent);
+ handler->GetHelper().OutputString(stream, wxT("<text"));
+
+ handler->GetHelper().OutputString(stream, style + wxT(">"));
+
+ if (GetProperties().GetCount() > 0)
+ {
+ handler->GetHelper().WriteProperties(stream, GetProperties(), indent);
+ handler->GetHelper().OutputIndentation(stream, indent);
+ }
+
+ 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);
+
+ handler->GetHelper().OutputString(stream, wxT("</text>"));
+ }
+ 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)
+{
+ int i;
+ int last = 0;
+ const wxString& text = GetText();
+ int len = (int) text.Length();
+
+ if (len == 0)
+ {
+ i = 0;
+
+ wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("text"));
+ parent->AddChild(elementNode);
+
+ 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());
+
+ wxXmlNode* textNode = new wxXmlNode(wxXML_TEXT_NODE, wxT("text"));
+ elementNode->AddChild(textNode);
+
+ if (fragment[0] == wxT(' ') || fragment[fragment.length()-1] == wxT(' '))
+ fragment = wxT("\"") + fragment + wxT("\"");
+
+ textNode->SetContent(fragment);
+ }
+ }
+
+ // Output this character as a number in a separate tag, because XML can't cope
+ // with entities below 32 except for 10 and 13
+
+ wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("symbol"));
+ parent->AddChild(elementNode);
+
+ handler->GetHelper().AddAttributes(elementNode, GetAttributes(), false);
+ handler->GetHelper().WriteProperties(elementNode, GetProperties());
+
+ wxXmlNode* textNode = new wxXmlNode(wxXML_TEXT_NODE, wxT("text"));
+ elementNode->AddChild(textNode);
+ textNode->SetContent(wxString::Format(wxT("%d"), c));
+
+ last = i + 1;
+ }
+ }
+
+ wxString fragment;
+ if (last == 0)
+ fragment = text;
+ else
+ fragment = text.Mid(last, i-last);
+
+ if (last < len)
+ {
+ wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("text"));
+ parent->AddChild(elementNode);
+ handler->GetHelper().AddAttributes(elementNode, GetAttributes(), false);
+
+ wxXmlNode* textNode = new wxXmlNode(wxXML_TEXT_NODE, wxT("text"));
+ elementNode->AddChild(textNode);
+
+ if (fragment[0] == wxT(' ') || fragment[fragment.length()-1] == wxT(' '))
+ fragment = wxT("\"") + fragment + wxT("\"");
+
+ textNode->SetContent(fragment);
+ }
+ return true;
+}
+#endif
+
+// Import this object from XML
+bool wxRichTextImage::ImportFromXML(wxRichTextBuffer* buffer, wxXmlNode* node, wxRichTextXMLHandler* handler, bool* recurse)
+{
+ wxRichTextObject::ImportFromXML(buffer, node, handler, recurse);
+
+ wxBitmapType imageType = wxBITMAP_TYPE_PNG;
+ wxString value = node->GetAttribute(wxT("imagetype"), wxEmptyString);
+ if (!value.empty())
+ {
+ int type = wxAtoi(value);
+
+ // note: 0 == wxBITMAP_TYPE_INVALID
+ if (type <= 0 || type >= wxBITMAP_TYPE_MAX)
+ {
+ wxLogWarning("Invalid bitmap type specified for <image> tag: %d", type);
+ }
+ else
+ {
+ imageType = (wxBitmapType)type;
+ }
+ }
+
+ 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 (!data.empty())
+ {
+ wxStringInputStream strStream(data);
+
+ GetImageBlock().ReadHex(strStream, data.length(), imageType);
+
+ 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("<image"));
+ if (!GetImageBlock().IsOk())
+ {
+ // 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);
+ }
+
+ handler->GetHelper().OutputIndentation(stream, indent+1);
+ handler->GetHelper().OutputString(stream, wxT("<data>"));
+
+ // wxStopWatch stopwatch;
+
+ GetImageBlock().WriteHex(stream);
+
+ // wxLogDebug(wxT("Image conversion to hex took %ldms"), stopwatch.Time());
+
+ handler->GetHelper().OutputString(stream, wxT("</data>\n"));
+ handler->GetHelper().OutputIndentation(stream, indent);
+ handler->GetHelper().OutputString(stream, wxT("</image>"));
+ return true;
+}
+#endif
+
+#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);
+
+ 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))
+ {
+ 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;
+ }
+
+ }
+#else
+ {
+ wxStringOutputStream strStream(& strData);
+ GetImageBlock().WriteHex(strStream);
+ }
+#endif
+
+ textNode->SetContent(strData);
+#if wxCHECK_VERSION(2,9,0)
+ textNode->SetNoConversion(true); // optimize speed
+#endif
+
+ return true;
+}
+#endif
+
+// Import this object from XML
+bool wxRichTextParagraphLayoutBox::ImportFromXML(wxRichTextBuffer* buffer, wxXmlNode* node, wxRichTextXMLHandler* handler, bool* recurse)
+{
+ wxRichTextObject::ImportFromXML(buffer, node, handler, recurse);
+
+ *recurse = true;
+
+ wxString partial = node->GetAttribute(wxT("partialparagraph"), wxEmptyString);
+ if (partial == wxT("true"))
+ SetPartialParagraph(true);
+
+ 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);
+
+ wxXmlNode* child2 = child->GetChildren();
+ while (child2)
+ {
+ handler->GetHelper().ImportStyleDefinition(sheet, child2);
+
+ child2 = child2->GetNext();
+ }
+ handler->GetHelper().ImportProperties(sheet->GetProperties(), child);
+
+ // 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);
+ }
+
+ return true;
+}
+
+#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);
+
+ wxString style = handler->GetHelper().AddAttributes(GetAttributes(), true);
+
+ if (GetPartialParagraph())
+ style << wxT(" partialparagraph=\"true\"");
+
+ handler->GetHelper().OutputString(stream, style + wxT(">"));
+
+ if (GetProperties().GetCount() > 0)
+ {
+ handler->GetHelper().WriteProperties(stream, GetProperties(), indent);
+ }
+
+ size_t i;
+ for (i = 0; i < GetChildCount(); i++)
+ {
+ wxRichTextObject* child = GetChild(i);
+ child->ExportXML(stream, indent+1, handler);
+ }
+
+ handler->GetHelper().OutputIndentation(stream, indent);
+ handler->GetHelper().OutputString(stream, wxT("</") + nodeName + wxT(">"));
+ return true;
+}
+#endif
+
+#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->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
+
+// Import this object from XML
+bool wxRichTextTable::ImportFromXML(wxRichTextBuffer* buffer, wxXmlNode* node, wxRichTextXMLHandler* handler, bool* recurse)
+{
+ wxRichTextBox::ImportFromXML(buffer, node, handler, recurse);
+
+ *recurse = false;
+
+ m_rowCount = wxAtoi(node->GetAttribute(wxT("rows"), wxEmptyString));
+ m_colCount = wxAtoi(node->GetAttribute(wxT("cols"), wxEmptyString));
+
+ 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();
+ }
+
+ 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++)
+ {
+ int idx = i * m_colCount + j;
+ if (idx < (int) GetChildren().GetCount())
+ {
+ wxRichTextCell* cell = wxDynamicCast(GetChildren().Item(idx)->GetData(), wxRichTextCell);
+ if (cell)
+ colArray.Add(cell);
+ }
+ }
+ }
+
+ return true;
+}
+
+#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);
+
+ wxString style = handler->GetHelper().AddAttributes(GetAttributes(), true);
+
+ style << wxT(" rows=\"") << m_rowCount << wxT("\"");
+ style << wxT(" cols=\"") << m_colCount << wxT("\"");
+
+ handler->GetHelper().OutputString(stream, style + wxT(">"));
+
+ if (GetProperties().GetCount() > 0)
+ {
+ handler->GetHelper().WriteProperties(stream, GetProperties(), indent);
+ }
+
+ 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);
+ }
+ }
+
+ handler->GetHelper().OutputIndentation(stream, indent);
+ handler->GetHelper().OutputString(stream, wxT("</") + nodeName + wxT(">"));
+
+ 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)
+{
+ wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, GetXMLNodeName());
+ parent->AddChild(elementNode);
+ handler->GetHelper().AddAttributes(elementNode, GetAttributes(), true);
+ handler->GetHelper().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++)
+ {
+ for (j = 0; j < m_colCount; j ++)
+ {
+ wxRichTextCell* cell = GetCell(i, j);
+ cell->ExportXML(elementNode, handler);
+ }
+ }
+
+ return true;
+}
+#endif
+
+wxRichTextXMLHelper::~wxRichTextXMLHelper()
+{
+ Clear();
+}
+
+void wxRichTextXMLHelper::Init()
+{
+#if wxRICHTEXT_HAVE_DIRECT_OUTPUT
+ m_deleteConvFile = false;
+ m_convMem = NULL;
+ m_convFile = NULL;
+#endif
+ m_flags = 0;
+}
+
+void wxRichTextXMLHelper::Clear()
+{
+#if wxRICHTEXT_HAVE_DIRECT_OUTPUT
+ if (m_deleteConvFile)
+ delete m_convFile;
+ m_convFile = NULL;
+ m_convMem = NULL;
+ m_deleteConvFile = false;
+#endif
+ m_fileEncoding = wxEmptyString;
+}
+
+void wxRichTextXMLHelper::SetupForSaving(const wxString& enc)
+{
+ Clear();
+
+#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
+
+ // If we pass an explicit encoding, change the output encoding.
+ if (!enc.empty() && enc.Lower() != m_fileEncoding.Lower())
+ {
+ if (enc == wxT("<System>"))
+ {
+#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;
+ }
+
+ // 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
+ }
+
+#if wxRICHTEXT_HAVE_DIRECT_OUTPUT
+#if !wxUSE_UNICODE
+ m_convMem = wxConvCurrent;
+#else
+ m_convMem = NULL;
+#endif
+#endif
+}
+
+// Convert a colour to a 6-digit hex string
+wxString wxRichTextXMLHelper::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
+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));
+
+ return wxColour(r, g, b);
+}