1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/richtext/richtextxml.cpp
3 // Purpose: XML and HTML I/O for wxRichTextCtrl
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
19 #if wxUSE_RICHTEXT && wxUSE_XML
21 #include "wx/richtext/richtextxml.h"
25 #include "wx/module.h"
29 #include "wx/filename.h"
30 #include "wx/clipbrd.h"
31 #include "wx/wfstream.h"
32 #include "wx/sstream.h"
33 #include "wx/txtstrm.h"
34 #include "wx/mstream.h"
35 #include "wx/tokenzr.h"
36 #include "wx/stopwatch.h"
37 #include "wx/xml/xml.h"
39 // Set to 1 for slower wxXmlDocument method, 0 for faster direct method.
40 // If we make wxXmlDocument::Save more efficient, we might switch to this
42 #define wxRICHTEXT_USE_XMLDOCUMENT_OUTPUT 0
44 #if wxRICHTEXT_USE_XMLDOCUMENT_OUTPUT && !wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
45 # error Must define wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT in richtextxml.h to use this method.
48 #if !wxRICHTEXT_USE_XMLDOCUMENT_OUTPUT && !wxRICHTEXT_HAVE_DIRECT_OUTPUT
49 # error Must define wxRICHTEXT_HAVE_DIRECT_OUTPUT in richtextxml.h to use this method.
52 // Set to 1 to time file saving
53 #define wxRICHTEXT_USE_OUTPUT_TIMINGS 0
55 // Convert a colour to a 6-digit hex string
56 static wxString
ColourToHexString(const wxColour
& col
)
60 hex
+= wxDecToHex(col
.Red());
61 hex
+= wxDecToHex(col
.Green());
62 hex
+= wxDecToHex(col
.Blue());
67 // Convert 6-digit hex string to a colour
68 static wxColour
HexStringToColour(const wxString
& hex
)
70 unsigned char r
= (unsigned char)wxHexToDec(hex
.Mid(0, 2));
71 unsigned char g
= (unsigned char)wxHexToDec(hex
.Mid(2, 2));
72 unsigned char b
= (unsigned char)wxHexToDec(hex
.Mid(4, 2));
74 return wxColour(r
, g
, b
);
77 static inline wxString
MakeString(const int& v
) { return wxString::Format(wxT("%d"), v
); }
78 static inline wxString
MakeString(const long& v
) { return wxString::Format(wxT("%ld"), v
); }
79 static inline wxString
MakeString(const double& v
) { return wxString::Format(wxT("%.2f"), (float) v
); }
80 static inline wxString
MakeString(const wxString
& s
) { return s
; }
81 static inline wxString
MakeString(const wxColour
& col
) { return wxT("#") + ColourToHexString(col
); }
83 static inline void AddString(wxString
& str
, const int& v
) { str
<< wxString::Format(wxT("%d"), v
); }
84 static inline void AddString(wxString
& str
, const long& v
) { str
<< wxString::Format(wxT("%ld"), v
); }
85 static inline void AddString(wxString
& str
, const double& v
) { str
<< wxString::Format(wxT("%.2f"), (float) v
); }
86 static inline void AddString(wxString
& str
, const wxChar
* s
) { str
<< s
; }
87 static inline void AddString(wxString
& str
, const wxString
& s
) { str
<< s
; }
88 static inline void AddString(wxString
& str
, const wxColour
& col
) { str
<< wxT("#") << ColourToHexString(col
); }
90 IMPLEMENT_DYNAMIC_CLASS(wxRichTextXMLHandler
, wxRichTextFileHandler
)
92 void wxRichTextXMLHandler::Init()
94 #if wxRICHTEXT_HAVE_DIRECT_OUTPUT
102 bool wxRichTextXMLHandler::DoLoadFile(wxRichTextBuffer
*buffer
, wxInputStream
& stream
)
107 buffer
->ResetAndClearCommands();
110 wxXmlDocument
* xmlDoc
= new wxXmlDocument
;
113 // This is the encoding to convert to (memory encoding rather than file encoding)
114 wxString
encoding(wxT("UTF-8"));
116 #if !wxUSE_UNICODE && wxUSE_INTL
117 encoding
= wxLocale::GetSystemEncodingName();
120 if (!xmlDoc
->Load(stream
, encoding
))
122 buffer
->ResetAndClearCommands();
127 if (xmlDoc
->GetRoot() && xmlDoc
->GetRoot()->GetType() == wxXML_ELEMENT_NODE
&& xmlDoc
->GetRoot()->GetName() == wxT("richtext"))
129 wxXmlNode
* child
= xmlDoc
->GetRoot()->GetChildren();
132 if (child
->GetType() == wxXML_ELEMENT_NODE
)
134 wxString name
= child
->GetName();
135 if (name
== wxT("richtext-version"))
139 ImportXML(buffer
, buffer
, child
);
142 child
= child
->GetNext();
153 buffer
->UpdateRanges();
158 /// Creates an object given an XML element name
159 wxRichTextObject
* wxRichTextXMLHandler::CreateObjectForXMLName(wxRichTextObject
* WXUNUSED(parent
), const wxString
& name
) const
161 if (name
== wxT("text") || name
== wxT("symbol"))
162 return new wxRichTextPlainText
;
163 else if (name
== wxT("image"))
164 return new wxRichTextImage
;
165 else if (name
== wxT("paragraph"))
166 return new wxRichTextParagraph
;
167 else if (name
== wxT("paragraphlayout"))
168 return new wxRichTextParagraphLayoutBox
;
169 else if (name
== wxT("textbox"))
170 return new wxRichTextBox
;
171 else if (name
== wxT("cell"))
172 return new wxRichTextCell
;
173 else if (name
== wxT("table"))
174 return new wxRichTextTable
;
179 /// Recursively import an object
180 bool wxRichTextXMLHandler::ImportXML(wxRichTextBuffer
* buffer
, wxRichTextObject
* obj
, wxXmlNode
* node
)
182 bool recurse
= false;
183 obj
->ImportFromXML(buffer
, node
, this, & recurse
);
185 // TODO: how to control whether to import children.
187 wxRichTextCompositeObject
* compositeParent
= wxDynamicCast(obj
, wxRichTextCompositeObject
);
188 if (recurse
&& compositeParent
)
190 wxXmlNode
* child
= node
->GetChildren();
193 if (child
->GetName() != wxT("stylesheet"))
195 wxRichTextObject
* childObj
= CreateObjectForXMLName(obj
, child
->GetName());
198 compositeParent
->AppendChild(childObj
);
199 ImportXML(buffer
, childObj
, child
);
202 child
= child
->GetNext();
209 bool wxRichTextXMLHandler::ImportProperties(wxRichTextObject
* obj
, wxXmlNode
* node
)
211 wxXmlNode
* child
= node
->GetChildren();
214 if (child
->GetName() == wxT("properties"))
216 wxXmlNode
* propertyChild
= child
->GetChildren();
217 while (propertyChild
)
219 if (propertyChild
->GetName() == wxT("property"))
221 wxString name
= propertyChild
->GetAttribute(wxT("name"), wxEmptyString
);
222 wxString value
= propertyChild
->GetAttribute(wxT("value"), wxEmptyString
);
223 wxString type
= propertyChild
->GetAttribute(wxT("type"), wxEmptyString
);
225 wxVariant var
= MakePropertyFromString(name
, value
, type
);
228 obj
->GetProperties().SetProperty(var
);
231 propertyChild
= propertyChild
->GetNext();
234 child
= child
->GetNext();
239 bool wxRichTextXMLHandler::ImportStyleDefinition(wxRichTextStyleSheet
* sheet
, wxXmlNode
* node
)
241 wxString styleType
= node
->GetName();
242 wxString styleName
= node
->GetAttribute(wxT("name"), wxEmptyString
);
243 wxString baseStyleName
= node
->GetAttribute(wxT("basestyle"), wxEmptyString
);
245 if (styleName
.empty())
248 if (styleType
== wxT("characterstyle"))
250 wxRichTextCharacterStyleDefinition
* def
= new wxRichTextCharacterStyleDefinition(styleName
);
251 def
->SetBaseStyle(baseStyleName
);
253 wxXmlNode
* child
= node
->GetChildren();
256 if (child
->GetName() == wxT("style"))
259 ImportStyle(attr
, child
, false);
262 child
= child
->GetNext();
265 sheet
->AddCharacterStyle(def
);
267 else if (styleType
== wxT("paragraphstyle"))
269 wxRichTextParagraphStyleDefinition
* def
= new wxRichTextParagraphStyleDefinition(styleName
);
271 wxString nextStyleName
= node
->GetAttribute(wxT("nextstyle"), wxEmptyString
);
272 def
->SetNextStyle(nextStyleName
);
273 def
->SetBaseStyle(baseStyleName
);
275 wxXmlNode
* child
= node
->GetChildren();
278 if (child
->GetName() == wxT("style"))
281 ImportStyle(attr
, child
, true);
284 child
= child
->GetNext();
287 sheet
->AddParagraphStyle(def
);
289 else if (styleType
== wxT("boxstyle"))
291 wxRichTextBoxStyleDefinition
* def
= new wxRichTextBoxStyleDefinition(styleName
);
293 def
->SetBaseStyle(baseStyleName
);
295 wxXmlNode
* child
= node
->GetChildren();
298 if (child
->GetName() == wxT("style"))
301 ImportStyle(attr
, child
, true);
304 child
= child
->GetNext();
307 sheet
->AddBoxStyle(def
);
309 else if (styleType
== wxT("liststyle"))
311 wxRichTextListStyleDefinition
* def
= new wxRichTextListStyleDefinition(styleName
);
313 wxString nextStyleName
= node
->GetAttribute(wxT("nextstyle"), wxEmptyString
);
314 def
->SetNextStyle(nextStyleName
);
315 def
->SetBaseStyle(baseStyleName
);
317 wxXmlNode
* child
= node
->GetChildren();
320 if (child
->GetName() == wxT("style"))
323 ImportStyle(attr
, child
, true);
325 wxString styleLevel
= child
->GetAttribute(wxT("level"), wxEmptyString
);
326 if (styleLevel
.empty())
332 int level
= wxAtoi(styleLevel
);
333 if (level
> 0 && level
<= 10)
335 def
->SetLevelAttributes(level
-1, attr
);
339 child
= child
->GetNext();
342 sheet
->AddListStyle(def
);
348 //-----------------------------------------------------------------------------
349 // xml support routines
350 //-----------------------------------------------------------------------------
352 bool wxRichTextXMLHandler::HasParam(wxXmlNode
* node
, const wxString
& param
)
354 return (GetParamNode(node
, param
) != NULL
);
357 wxXmlNode
*wxRichTextXMLHandler::GetParamNode(wxXmlNode
* node
, const wxString
& param
)
359 wxCHECK_MSG(node
, NULL
, wxT("You can't access node data before it was initialized!"));
361 wxXmlNode
*n
= node
->GetChildren();
365 if (n
->GetType() == wxXML_ELEMENT_NODE
&& n
->GetName() == param
)
373 wxString
wxRichTextXMLHandler::GetNodeContent(wxXmlNode
*node
)
376 if (n
== NULL
) return wxEmptyString
;
377 n
= n
->GetChildren();
381 if (n
->GetType() == wxXML_TEXT_NODE
||
382 n
->GetType() == wxXML_CDATA_SECTION_NODE
)
383 return n
->GetContent();
386 return wxEmptyString
;
390 wxString
wxRichTextXMLHandler::GetParamValue(wxXmlNode
*node
, const wxString
& param
)
393 return GetNodeContent(node
);
395 return GetNodeContent(GetParamNode(node
, param
));
398 wxString
wxRichTextXMLHandler::GetText(wxXmlNode
*node
, const wxString
& param
, bool WXUNUSED(translate
))
400 wxXmlNode
*parNode
= GetParamNode(node
, param
);
403 wxString
str1(GetNodeContent(parNode
));
407 wxXmlNode
* wxRichTextXMLHandler::FindNode(wxXmlNode
* node
, const wxString
& name
)
409 if (node
->GetName() == name
&& name
== wxT("stylesheet"))
412 wxXmlNode
* child
= node
->GetChildren();
415 if (child
->GetName() == name
)
417 child
= child
->GetNext();
422 // For use with earlier versions of wxWidgets
423 #ifndef WXUNUSED_IN_UNICODE
425 #define WXUNUSED_IN_UNICODE(x) WXUNUSED(x)
427 #define WXUNUSED_IN_UNICODE(x) x
431 // write string to output
432 inline static void OutputString(wxOutputStream
& stream
, const wxString
& str
,
433 wxMBConv
*WXUNUSED_IN_UNICODE(convMem
), wxMBConv
*convFile
)
435 if (str
.empty()) return;
439 const wxWX2MBbuf
buf(str
.mb_str(*convFile
));
440 stream
.Write((const char*)buf
, strlen((const char*)buf
));
444 const wxWX2MBbuf
buf(str
.mb_str(wxConvUTF8
));
445 stream
.Write((const char*)buf
, strlen((const char*)buf
));
448 if ( convFile
== NULL
)
449 stream
.Write(str
.mb_str(), str
.Len());
452 wxString
str2(str
.wc_str(*convMem
), *convFile
);
453 stream
.Write(str2
.mb_str(), str2
.Len());
458 static void OutputIndentation(wxOutputStream
& stream
, int indent
)
460 wxString str
= wxT("\n");
461 for (int i
= 0; i
< indent
; i
++)
462 str
<< wxT(' ') << wxT(' ');
463 ::OutputString(stream
, str
, NULL
, NULL
);
466 // Same as above, but create entities first.
467 // Translates '<' to "<", '>' to ">" and '&' to "&"
468 static void OutputStringEnt(wxOutputStream
& stream
, const wxString
& str
,
469 wxMBConv
*convMem
= NULL
, wxMBConv
*convFile
= NULL
)
477 for (i
= 0; i
< len
; i
++)
481 // Original code excluded "&" but we _do_ want to convert
482 // the ampersand beginning & because otherwise when read in,
483 // the original "&" becomes "&".
485 if (c
== wxT('<') || c
== wxT('>') || c
== wxT('"') ||
486 (c
== wxT('&') /* && (str.Mid(i+1, 4) != wxT("amp;")) */ ))
488 OutputString(stream
, str
.Mid(last
, i
- last
), convMem
, convFile
);
492 OutputString(stream
, wxT("<"), NULL
, NULL
);
495 OutputString(stream
, wxT(">"), NULL
, NULL
);
498 OutputString(stream
, wxT("&"), NULL
, NULL
);
501 OutputString(stream
, wxT("""), NULL
, NULL
);
507 else if (wxUChar(c
) > 127)
509 OutputString(stream
, str
.Mid(last
, i
- last
), convMem
, convFile
);
511 wxString
s(wxT("&#"));
515 s
<< (int) wxUChar(c
);
518 OutputString(stream
, s
, NULL
, NULL
);
522 OutputString(stream
, str
.Mid(last
, i
- last
), convMem
, convFile
);
525 void wxRichTextXMLHandler::OutputString(wxOutputStream
& stream
, const wxString
& str
)
527 ::OutputString(stream
, str
, m_convMem
, m_convFile
);
530 void wxRichTextXMLHandler::OutputStringEnt(wxOutputStream
& stream
, const wxString
& str
)
532 ::OutputStringEnt(stream
, str
, m_convMem
, m_convFile
);
535 void wxRichTextXMLHandler::OutputIndentation(wxOutputStream
& stream
, int indent
)
537 wxString str
= wxT("\n");
538 for (int i
= 0; i
< indent
; i
++)
539 str
<< wxT(' ') << wxT(' ');
540 ::OutputString(stream
, str
, NULL
, NULL
);
543 wxString
wxRichTextXMLHandler::AttributeToXML(const wxString
& str
)
551 for (i
= 0; i
< len
; i
++)
555 // Original code excluded "&" but we _do_ want to convert
556 // the ampersand beginning & because otherwise when read in,
557 // the original "&" becomes "&".
559 if (c
== wxT('<') || c
== wxT('>') || c
== wxT('"') ||
560 (c
== wxT('&') /* && (str.Mid(i+1, 4) != wxT("amp;")) */ ))
562 str1
+= str
.Mid(last
, i
- last
);
572 str1
+= wxT("&");
575 str1
+= wxT(""");
581 else if (wxUChar(c
) > 127)
583 str1
+= str
.Mid(last
, i
- last
);
585 wxString
s(wxT("&#"));
589 s
<< (int) wxUChar(c
);
596 str1
+= str
.Mid(last
, i
- last
);
600 #if wxRICHTEXT_HAVE_DIRECT_OUTPUT
602 static inline void AddAttribute(wxString
& str
, const wxString
& name
, const int& v
)
604 str
<< wxT(" ") << name
<< wxT("=\"") << wxString::Format(wxT("%d"), v
) << wxT("\"");
607 static inline void AddAttribute(wxString
& str
, const wxString
& name
, const long& v
)
609 str
<< wxT(" ") << name
<< wxT("=\"") << wxString::Format(wxT("%ld"), v
) << wxT("\"");
612 static inline void AddAttribute(wxString
& str
, const wxString
& name
, const double& v
)
614 str
<< wxT(" ") << name
<< wxT("=\"") << wxString::Format(wxT("%.2f"), (float) v
) << wxT("\"");
617 static inline void AddAttribute(wxString
& str
, const wxString
& name
, const wxChar
* s
)
619 str
<< wxT(" ") << name
<< wxT("=\"") << s
<< wxT("\"");
622 static inline void AddAttribute(wxString
& str
, const wxString
& name
, const wxString
& s
)
624 str
<< wxT(" ") << name
<< wxT("=\"") << s
<< wxT("\"");
627 static inline void AddAttribute(wxString
& str
, const wxString
& name
, const wxColour
& col
)
629 str
<< wxT(" ") << name
<< wxT("=\"") << wxT("#") << ColourToHexString(col
) << wxT("\"");
632 static inline void AddAttribute(wxString
& str
, const wxString
& name
, const wxTextAttrDimension
& dim
)
636 wxString value
= MakeString(dim
.GetValue()) + wxT(",") + MakeString((int) dim
.GetFlags());
637 str
<< wxT(" ") << name
<< wxT("=\"");
643 static inline void AddAttribute(wxString
& str
, const wxString
& rootName
, const wxTextAttrDimensions
& dims
)
645 if (dims
.GetLeft().IsValid())
646 AddAttribute(str
, rootName
+ wxString(wxT("-left")), dims
.GetLeft());
647 if (dims
.GetRight().IsValid())
648 AddAttribute(str
, rootName
+ wxString(wxT("-right")), dims
.GetRight());
649 if (dims
.GetTop().IsValid())
650 AddAttribute(str
, rootName
+ wxString(wxT("-top")), dims
.GetTop());
651 if (dims
.GetBottom().IsValid())
652 AddAttribute(str
, rootName
+ wxString(wxT("-bottom")), dims
.GetBottom());
655 static inline void AddAttribute(wxString
& str
, const wxString
& rootName
, const wxTextAttrBorder
& border
)
657 if (border
.HasStyle())
658 AddAttribute(str
, rootName
+ wxString(wxT("-style")), border
.GetStyle());
659 if (border
.HasColour())
660 AddAttribute(str
, rootName
+ wxString(wxT("-color")), border
.GetColour());
661 if (border
.HasWidth())
662 AddAttribute(str
, rootName
+ wxString(wxT("-width")), border
.GetWidth());
665 static inline void AddAttribute(wxString
& str
, const wxString
& rootName
, const wxTextAttrBorders
& borders
)
667 AddAttribute(str
, rootName
+ wxString(wxT("-left")), borders
.GetLeft());
668 AddAttribute(str
, rootName
+ wxString(wxT("-right")), borders
.GetRight());
669 AddAttribute(str
, rootName
+ wxString(wxT("-top")), borders
.GetTop());
670 AddAttribute(str
, rootName
+ wxString(wxT("-bottom")), borders
.GetBottom());
674 // wxRICHTEXT_HAVE_DIRECT_OUTPUT
676 #if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
678 static inline void AddAttribute(wxXmlNode
* node
, const wxString
& name
, const int& v
)
680 node
->AddAttribute(name
, MakeString(v
));
683 static inline void AddAttribute(wxXmlNode
* node
, const wxString
& name
, const long& v
)
685 node
->AddAttribute(name
, MakeString(v
));
688 static inline void AddAttribute(wxXmlNode
* node
, const wxString
& name
, const double& v
)
690 node
->AddAttribute(name
, MakeString(v
));
693 static inline void AddAttribute(wxXmlNode
* node
, const wxString
& name
, const wxString
& s
)
695 node
->AddAttribute(name
, s
);
698 static inline void AddAttribute(wxXmlNode
* node
, const wxString
& name
, const wxColour
& col
)
700 node
->AddAttribute(name
, MakeString(col
));
703 static inline void AddAttribute(wxXmlNode
* node
, const wxString
& name
, const wxTextAttrDimension
& dim
)
707 wxString value
= MakeString(dim
.GetValue()) + wxT(",") + MakeString(dim
.GetFlags());
708 AddAttribute(node
, name
, value
);
712 static inline void AddAttribute(wxXmlNode
* node
, const wxString
& rootName
, const wxTextAttrDimensions
& dims
)
714 if (dims
.GetLeft().IsValid())
715 AddAttribute(node
, rootName
+ wxString(wxT("-left")), dims
.GetLeft());
716 if (dims
.GetRight().IsValid())
717 AddAttribute(node
, rootName
+ wxString(wxT("-right")), dims
.GetRight());
718 if (dims
.GetTop().IsValid())
719 AddAttribute(node
, rootName
+ wxString(wxT("-top")), dims
.GetTop());
720 if (dims
.GetBottom().IsValid())
721 AddAttribute(node
, rootName
+ wxString(wxT("-bottom")), dims
.GetBottom());
724 static inline void AddAttribute(wxXmlNode
* node
, const wxString
& rootName
, const wxTextAttrBorder
& border
)
726 if (border
.HasStyle())
727 AddAttribute(node
, rootName
+ wxString(wxT("-style")), border
.GetStyle());
728 if (border
.HasColour())
729 AddAttribute(node
, rootName
+ wxString(wxT("-color")), border
.GetColour());
730 if (border
.HasWidth())
731 AddAttribute(node
, rootName
+ wxString(wxT("-width")), border
.GetWidth());
734 static inline void AddAttribute(wxXmlNode
* node
, const wxString
& rootName
, const wxTextAttrBorders
& borders
)
736 AddAttribute(node
, rootName
+ wxString(wxT("-left")), borders
.GetLeft());
737 AddAttribute(node
, rootName
+ wxString(wxT("-right")), borders
.GetRight());
738 AddAttribute(node
, rootName
+ wxString(wxT("-top")), borders
.GetTop());
739 AddAttribute(node
, rootName
+ wxString(wxT("-bottom")), borders
.GetBottom());
742 // wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
744 bool wxRichTextXMLHandler::DoSaveFile(wxRichTextBuffer
*buffer
, wxOutputStream
& stream
)
749 wxString
version(wxT("1.0") ) ;
751 bool deleteConvFile
= false;
752 wxString fileEncoding
;
753 //wxMBConv* convFile = NULL;
756 fileEncoding
= wxT("UTF-8");
757 m_convFile
= & wxConvUTF8
;
759 fileEncoding
= wxT("ISO-8859-1");
760 m_convFile
= & wxConvISO8859_1
;
763 // If SetEncoding has been called, change the output encoding.
764 if (!m_encoding
.empty() && m_encoding
.Lower() != fileEncoding
.Lower())
766 if (m_encoding
== wxT("<System>"))
769 fileEncoding
= wxLocale::GetSystemEncodingName();
770 // if !wxUSE_INTL, we fall back to UTF-8 or ISO-8859-1 below
775 fileEncoding
= m_encoding
;
778 // GetSystemEncodingName may not have returned a name
779 if (fileEncoding
.empty())
781 fileEncoding
= wxT("UTF-8");
783 fileEncoding
= wxT("ISO-8859-1");
785 m_convFile
= new wxCSConv(fileEncoding
);
786 deleteConvFile
= true;
789 #if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT && wxRICHTEXT_USE_XMLDOCUMENT_OUTPUT
790 #if wxRICHTEXT_USE_OUTPUT_TIMINGS
791 wxStopWatch stopwatch
;
793 wxXmlDocument
* doc
= new wxXmlDocument
;
794 doc
->SetFileEncoding(fileEncoding
);
796 wxXmlNode
* rootNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, wxT("richtext"));
797 doc
->SetRoot(rootNode
);
798 rootNode
->AddAttribute(wxT("version"), wxT("1.0.0.0"));
799 rootNode
->AddAttribute(wxT("xmlns"), wxT("http://www.wxwidgets.org"));
801 if (buffer
->GetStyleSheet() && (GetFlags() & wxRICHTEXT_HANDLER_INCLUDE_STYLESHEET
))
803 wxXmlNode
* styleSheetNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, wxT("stylesheet"));
804 rootNode
->AddChild(styleSheetNode
);
806 wxString nameAndDescr
;
808 if (!buffer
->GetStyleSheet()->GetName().empty())
809 styleSheetNode
->AddAttribute(wxT("name"), buffer
->GetStyleSheet()->GetName());
811 if (!buffer
->GetStyleSheet()->GetDescription().empty())
812 styleSheetNode
->AddAttribute(wxT("description"), buffer
->GetStyleSheet()->GetDescription());
815 for (i
= 0; i
< (int) buffer
->GetStyleSheet()->GetCharacterStyleCount(); i
++)
817 wxRichTextCharacterStyleDefinition
* def
= buffer
->GetStyleSheet()->GetCharacterStyle(i
);
818 ExportStyleDefinition(styleSheetNode
, def
);
821 for (i
= 0; i
< (int) buffer
->GetStyleSheet()->GetParagraphStyleCount(); i
++)
823 wxRichTextParagraphStyleDefinition
* def
= buffer
->GetStyleSheet()->GetParagraphStyle(i
);
824 ExportStyleDefinition(styleSheetNode
, def
);
827 for (i
= 0; i
< (int) buffer
->GetStyleSheet()->GetListStyleCount(); i
++)
829 wxRichTextListStyleDefinition
* def
= buffer
->GetStyleSheet()->GetListStyle(i
);
830 ExportStyleDefinition(styleSheetNode
, def
);
833 for (i
= 0; i
< (int) buffer
->GetStyleSheet()->GetBoxStyleCount(); i
++)
835 wxRichTextBoxStyleDefinition
* def
= buffer
->GetStyleSheet()->GetBoxStyle(i
);
836 ExportStyleDefinition(styleSheetNode
, def
);
839 bool success
= ExportXML(rootNode
, *buffer
);
840 #if wxRICHTEXT_USE_OUTPUT_TIMINGS
841 long t
= stopwatch
.Time();
842 wxLogDebug(wxT("Creating the document took %ldms"), t
);
843 wxMessageBox(wxString::Format(wxT("Creating the document took %ldms"), t
));
847 #if wxRICHTEXT_USE_OUTPUT_TIMINGS
850 success
= doc
->Save(stream
);
851 #if wxRICHTEXT_USE_OUTPUT_TIMINGS
853 wxLogDebug(wxT("Save() took %ldms"), t2
);
854 wxMessageBox(wxString::Format(wxT("Save() took %ldms"), t2
));
861 // !(wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT && wxRICHTEXT_USE_XMLDOCUMENT_OUTPUT)
864 m_convMem
= wxConvCurrent
;
870 s
.Printf(wxT("<?xml version=\"%s\" encoding=\"%s\"?>\n"),
871 version
, fileEncoding
);
872 OutputString(stream
, s
);
873 OutputString(stream
, wxT("<richtext version=\"1.0.0.0\" xmlns=\"http://www.wxwidgets.org\">"));
877 if (buffer
->GetStyleSheet() && (GetFlags() & wxRICHTEXT_HANDLER_INCLUDE_STYLESHEET
))
879 OutputIndentation(stream
, level
);
880 wxString nameAndDescr
;
881 if (!buffer
->GetStyleSheet()->GetName().empty())
882 nameAndDescr
<< wxT(" name=\"") << buffer
->GetStyleSheet()->GetName() << wxT("\"");
883 if (!buffer
->GetStyleSheet()->GetDescription().empty())
884 nameAndDescr
<< wxT(" description=\"") << buffer
->GetStyleSheet()->GetDescription() << wxT("\"");
885 OutputString(stream
, wxString(wxT("<stylesheet")) + nameAndDescr
+ wxT(">"));
889 for (i
= 0; i
< (int) buffer
->GetStyleSheet()->GetCharacterStyleCount(); i
++)
891 wxRichTextCharacterStyleDefinition
* def
= buffer
->GetStyleSheet()->GetCharacterStyle(i
);
892 ExportStyleDefinition(stream
, def
, level
+ 1);
895 for (i
= 0; i
< (int) buffer
->GetStyleSheet()->GetParagraphStyleCount(); i
++)
897 wxRichTextParagraphStyleDefinition
* def
= buffer
->GetStyleSheet()->GetParagraphStyle(i
);
898 ExportStyleDefinition(stream
, def
, level
+ 1);
901 for (i
= 0; i
< (int) buffer
->GetStyleSheet()->GetListStyleCount(); i
++)
903 wxRichTextListStyleDefinition
* def
= buffer
->GetStyleSheet()->GetListStyle(i
);
904 ExportStyleDefinition(stream
, def
, level
+ 1);
907 for (i
= 0; i
< (int) buffer
->GetStyleSheet()->GetBoxStyleCount(); i
++)
909 wxRichTextBoxStyleDefinition
* def
= buffer
->GetStyleSheet()->GetBoxStyle(i
);
910 ExportStyleDefinition(stream
, def
, level
+ 1);
913 OutputIndentation(stream
, level
);
914 OutputString(stream
, wxT("</stylesheet>"));
918 bool success
= ExportXML(stream
, *buffer
, level
);
920 OutputString(stream
, wxT("\n</richtext>"));
921 OutputString(stream
, wxT("\n"));
932 #if wxRICHTEXT_HAVE_DIRECT_OUTPUT
934 /// Recursively export an object
935 bool wxRichTextXMLHandler::ExportXML(wxOutputStream
& stream
, wxRichTextObject
& obj
, int indent
)
937 obj
.ExportXML(stream
, indent
, this);
942 bool wxRichTextXMLHandler::ExportStyleDefinition(wxOutputStream
& stream
, wxRichTextStyleDefinition
* def
, int level
)
944 wxRichTextCharacterStyleDefinition
* charDef
= wxDynamicCast(def
, wxRichTextCharacterStyleDefinition
);
945 wxRichTextParagraphStyleDefinition
* paraDef
= wxDynamicCast(def
, wxRichTextParagraphStyleDefinition
);
946 wxRichTextListStyleDefinition
* listDef
= wxDynamicCast(def
, wxRichTextListStyleDefinition
);
947 wxRichTextBoxStyleDefinition
* boxDef
= wxDynamicCast(def
, wxRichTextBoxStyleDefinition
);
949 wxString name
= def
->GetName();
952 nameProp
= wxT(" name=\"") + AttributeToXML(name
) + wxT("\"");
954 wxString baseStyle
= def
->GetBaseStyle();
955 wxString baseStyleProp
;
956 if (!baseStyle
.empty())
957 baseStyleProp
= wxT(" basestyle=\"") + AttributeToXML(baseStyle
) + wxT("\"");
959 wxString descr
= def
->GetDescription();
962 descrProp
= wxT(" description=\"") + AttributeToXML(descr
) + wxT("\"");
966 OutputIndentation(stream
, level
);
967 OutputString(stream
, wxT("<characterstyle") + nameProp
+ baseStyleProp
+ descrProp
+ wxT(">"));
971 wxString style
= AddAttributes(def
->GetStyle(), false);
973 OutputIndentation(stream
, level
);
974 OutputString(stream
, wxT("<style ") + style
+ wxT(">"));
976 OutputIndentation(stream
, level
);
977 OutputString(stream
, wxT("</style>"));
981 OutputIndentation(stream
, level
);
982 OutputString(stream
, wxT("</characterstyle>"));
986 OutputIndentation(stream
, level
);
988 if (!listDef
->GetNextStyle().empty())
989 baseStyleProp
<< wxT(" nextstyle=\"") << AttributeToXML(listDef
->GetNextStyle()) << wxT("\"");
991 OutputString(stream
, wxT("<liststyle") + nameProp
+ baseStyleProp
+ descrProp
+ wxT(">"));
995 wxString style
= AddAttributes(def
->GetStyle(), true);
997 OutputIndentation(stream
, level
);
998 OutputString(stream
, wxT("<style ") + style
+ wxT(">"));
1000 OutputIndentation(stream
, level
);
1001 OutputString(stream
, wxT("</style>"));
1004 for (i
= 0; i
< 10; i
++)
1006 wxRichTextAttr
* levelAttr
= listDef
->GetLevelAttributes(i
);
1009 wxString style
= AddAttributes(def
->GetStyle(), true);
1010 wxString levelStr
= wxString::Format(wxT(" level=\"%d\" "), (i
+1));
1012 OutputIndentation(stream
, level
);
1013 OutputString(stream
, wxT("<style ") + levelStr
+ style
+ wxT(">"));
1015 OutputIndentation(stream
, level
);
1016 OutputString(stream
, wxT("</style>"));
1022 OutputIndentation(stream
, level
);
1023 OutputString(stream
, wxT("</liststyle>"));
1027 OutputIndentation(stream
, level
);
1029 if (!paraDef
->GetNextStyle().empty())
1030 baseStyleProp
<< wxT(" nextstyle=\"") << AttributeToXML(paraDef
->GetNextStyle()) << wxT("\"");
1032 OutputString(stream
, wxT("<paragraphstyle") + nameProp
+ baseStyleProp
+ descrProp
+ wxT(">"));
1036 wxString style
= AddAttributes(def
->GetStyle(), true);
1038 OutputIndentation(stream
, level
);
1039 OutputString(stream
, wxT("<style ") + style
+ wxT(">"));
1041 OutputIndentation(stream
, level
);
1042 OutputString(stream
, wxT("</style>"));
1046 OutputIndentation(stream
, level
);
1047 OutputString(stream
, wxT("</paragraphstyle>"));
1051 OutputIndentation(stream
, level
);
1053 OutputString(stream
, wxT("<boxstyle") + nameProp
+ baseStyleProp
+ descrProp
+ wxT(">"));
1057 wxString style
= AddAttributes(def
->GetStyle(), true);
1059 OutputIndentation(stream
, level
);
1060 OutputString(stream
, wxT("<style ") + style
+ wxT(">"));
1062 OutputIndentation(stream
, level
);
1063 OutputString(stream
, wxT("</style>"));
1067 OutputIndentation(stream
, level
);
1068 OutputString(stream
, wxT("</boxstyle>"));
1075 /// Create a string containing style attributes
1076 wxString
wxRichTextXMLHandler::AddAttributes(const wxRichTextAttr
& attr
, bool isPara
)
1079 if (attr
.HasTextColour() && attr
.GetTextColour().IsOk())
1080 AddAttribute(str
, wxT("textcolor"), attr
.GetTextColour());
1082 if (attr
.HasBackgroundColour() && attr
.GetBackgroundColour().IsOk())
1083 AddAttribute(str
, wxT("bgcolor"), attr
.GetBackgroundColour());
1085 if (attr
.HasFontSize())
1086 AddAttribute(str
, wxT("fontsize"), attr
.GetFontSize());
1088 if (attr
.HasFontFamily())
1089 AddAttribute(str
, wxT("fontfamily"), attr
.GetFontFamily());
1091 if (attr
.HasFontItalic())
1092 AddAttribute(str
, wxT("fontstyle"), attr
.GetFontStyle());
1094 if (attr
.HasFontWeight())
1095 AddAttribute(str
, wxT("fontweight"), attr
.GetFontWeight());
1097 if (attr
.HasFontUnderlined())
1098 AddAttribute(str
, wxT("fontunderlined"), (int) attr
.GetFontUnderlined());
1100 if (attr
.HasFontFaceName())
1101 AddAttribute(str
, wxT("fontface"), AttributeToXML(attr
.GetFontFaceName()));
1103 if (attr
.HasTextEffects())
1105 AddAttribute(str
, wxT("texteffects"), attr
.GetTextEffects());
1106 AddAttribute(str
, wxT("texteffectflags"), attr
.GetTextEffectFlags());
1109 if (!attr
.GetCharacterStyleName().empty())
1110 AddAttribute(str
, wxT("characterstyle"), AttributeToXML(attr
.GetCharacterStyleName()));
1113 AddAttribute(str
, wxT("url"), AttributeToXML(attr
.GetURL()));
1117 if (attr
.HasAlignment())
1118 AddAttribute(str
, wxT("alignment"), (int) attr
.GetAlignment());
1120 if (attr
.HasLeftIndent())
1122 AddAttribute(str
, wxT("leftindent"), (int) attr
.GetLeftIndent());
1123 AddAttribute(str
, wxT("leftsubindent"), (int) attr
.GetLeftSubIndent());
1126 if (attr
.HasRightIndent())
1127 AddAttribute(str
, wxT("rightindent"), (int) attr
.GetRightIndent());
1129 if (attr
.HasParagraphSpacingAfter())
1130 AddAttribute(str
, wxT("parspacingafter"), (int) attr
.GetParagraphSpacingAfter());
1132 if (attr
.HasParagraphSpacingBefore())
1133 AddAttribute(str
, wxT("parspacingbefore"), (int) attr
.GetParagraphSpacingBefore());
1135 if (attr
.HasLineSpacing())
1136 AddAttribute(str
, wxT("linespacing"), (int) attr
.GetLineSpacing());
1138 if (attr
.HasBulletStyle())
1139 AddAttribute(str
, wxT("bulletstyle"), (int) attr
.GetBulletStyle());
1141 if (attr
.HasBulletNumber())
1142 AddAttribute(str
, wxT("bulletnumber"), (int) attr
.GetBulletNumber());
1144 if (attr
.HasBulletText())
1146 // If using a bullet symbol, convert to integer in case it's a non-XML-friendly character.
1147 // Otherwise, assume it's XML-friendly text such as outline numbering, e.g. 1.2.3.1
1148 if (!attr
.GetBulletText().empty() && (attr
.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_SYMBOL
))
1149 AddAttribute(str
, wxT("bulletsymbol"), (int) (attr
.GetBulletText()[0]));
1151 AddAttribute(str
, wxT("bullettext"), AttributeToXML(attr
.GetBulletText()));
1153 AddAttribute(str
, wxT("bulletfont"), attr
.GetBulletFont());
1156 if (attr
.HasBulletName())
1157 AddAttribute(str
, wxT("bulletname"), AttributeToXML(attr
.GetBulletName()));
1159 if (!attr
.GetParagraphStyleName().empty())
1160 AddAttribute(str
, wxT("parstyle"), AttributeToXML(attr
.GetParagraphStyleName()));
1162 if (!attr
.GetListStyleName().empty())
1163 AddAttribute(str
, wxT("liststyle"), AttributeToXML(attr
.GetListStyleName()));
1165 if (!attr
.GetTextBoxAttr().GetBoxStyleName().empty())
1166 AddAttribute(str
, wxT("boxstyle"), AttributeToXML(attr
.GetTextBoxAttr().GetBoxStyleName()));
1172 for (i
= 0; i
< attr
.GetTabs().GetCount(); i
++)
1174 if (i
> 0) strTabs
<< wxT(",");
1175 strTabs
<< attr
.GetTabs()[i
];
1177 AddAttribute(str
, wxT("tabs"), strTabs
);
1180 if (attr
.HasPageBreak())
1182 AddAttribute(str
, wxT("pagebreak"), 1);
1185 if (attr
.HasOutlineLevel())
1186 AddAttribute(str
, wxT("outlinelevel"), (int) attr
.GetOutlineLevel());
1189 AddAttribute(str
, wxT("margin"), attr
.GetTextBoxAttr().GetMargins());
1190 AddAttribute(str
, wxT("padding"), attr
.GetTextBoxAttr().GetPadding());
1191 AddAttribute(str
, wxT("position"), attr
.GetTextBoxAttr().GetPosition());
1192 AddAttribute(str
, wxT("border"), attr
.GetTextBoxAttr().GetBorder());
1193 AddAttribute(str
, wxT("outline"), attr
.GetTextBoxAttr().GetOutline());
1194 AddAttribute(str
, wxT("width"), attr
.GetTextBoxAttr().GetWidth());
1195 AddAttribute(str
, wxT("height"), attr
.GetTextBoxAttr().GetHeight());
1197 if (attr
.GetTextBoxAttr().HasVerticalAlignment())
1200 if (attr
.GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_TOP
)
1202 else if (attr
.GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_CENTRE
)
1203 value
= wxT("centre");
1204 else if (attr
.GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_BOTTOM
)
1205 value
= wxT("bottom");
1207 value
= wxT("none");
1208 AddAttribute(str
, wxT("verticalalignment"), value
);
1211 if (attr
.GetTextBoxAttr().HasFloatMode())
1214 if (attr
.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_LEFT
)
1215 value
= wxT("left");
1216 else if (attr
.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_RIGHT
)
1217 value
= wxT("right");
1219 value
= wxT("none");
1220 AddAttribute(str
, wxT("float"), value
);
1223 if (attr
.GetTextBoxAttr().HasClearMode())
1226 if (attr
.GetTextBoxAttr().GetClearMode() == wxTEXT_BOX_ATTR_CLEAR_LEFT
)
1227 value
= wxT("left");
1228 else if (attr
.GetTextBoxAttr().GetClearMode() == wxTEXT_BOX_ATTR_CLEAR_RIGHT
)
1229 value
= wxT("right");
1230 else if (attr
.GetTextBoxAttr().GetClearMode() == wxTEXT_BOX_ATTR_CLEAR_BOTH
)
1231 value
= wxT("both");
1233 value
= wxT("none");
1234 AddAttribute(str
, wxT("clear"), value
);
1237 if (attr
.GetTextBoxAttr().HasCollapseBorders())
1238 AddAttribute(str
, wxT("collapse-borders"), (int) attr
.GetTextBoxAttr().GetCollapseBorders());
1243 // Make a string from the given property. This can be overridden for custom variants.
1244 wxString
wxRichTextXMLHandler::MakeStringFromProperty(const wxVariant
& var
)
1246 return var
.MakeString();
1249 // Create a proprty from the string read from the XML file.
1250 wxVariant
wxRichTextXMLHandler::MakePropertyFromString(const wxString
& name
, const wxString
& value
, const wxString
& WXUNUSED(type
))
1252 wxVariant
var(value
, name
);
1253 // TODO: use type to create using common types
1257 // Write the properties
1258 bool wxRichTextXMLHandler::WriteProperties(wxOutputStream
& stream
, const wxRichTextProperties
& properties
, int level
)
1260 if (properties
.GetCount() > 0)
1264 OutputIndentation(stream
, level
);
1265 OutputString(stream
, wxT("<properties"));
1270 for (i
= 0; i
< properties
.GetCount(); i
++)
1272 const wxVariant
& var
= properties
[i
];
1275 const wxString
& name
= var
.GetName();
1276 wxString value
= MakeStringFromProperty(var
);
1278 OutputIndentation(stream
, level
);
1279 OutputString(stream
, wxT("<property name=\"") + name
+
1280 wxT("\" type=\"") + var
.GetType() + wxT("\" value=\""));
1281 OutputStringEnt(stream
, value
);
1282 OutputString(stream
, wxT("\"/>\n"));
1288 OutputIndentation(stream
, level
);
1289 OutputString(stream
, wxT("</properties>\n"));
1299 // wxRICHTEXT_HAVE_DIRECT_OUTPUT
1301 #if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
1302 bool wxRichTextXMLHandler::ExportXML(wxXmlNode
* parent
, wxRichTextObject
& obj
)
1304 obj
.ExportXML(parent
, this);
1309 bool wxRichTextXMLHandler::ExportStyleDefinition(wxXmlNode
* parent
, wxRichTextStyleDefinition
* def
)
1311 wxRichTextCharacterStyleDefinition
* charDef
= wxDynamicCast(def
, wxRichTextCharacterStyleDefinition
);
1312 wxRichTextParagraphStyleDefinition
* paraDef
= wxDynamicCast(def
, wxRichTextParagraphStyleDefinition
);
1313 wxRichTextBoxStyleDefinition
* boxDef
= wxDynamicCast(def
, wxRichTextBoxStyleDefinition
);
1314 wxRichTextListStyleDefinition
* listDef
= wxDynamicCast(def
, wxRichTextListStyleDefinition
);
1316 wxString baseStyle
= def
->GetBaseStyle();
1317 wxString descr
= def
->GetDescription();
1319 wxXmlNode
* defNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, wxEmptyString
);
1320 parent
->AddChild(defNode
);
1321 if (!baseStyle
.empty())
1322 defNode
->AddAttribute(wxT("basestyle"), baseStyle
);
1324 defNode
->AddAttribute(wxT("description"), descr
);
1326 wxXmlNode
* styleNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, wxT("style"));
1327 defNode
->AddChild(styleNode
);
1331 defNode
->SetName(wxT("characterstyle"));
1332 AddAttributes(styleNode
, def
->GetStyle(), false);
1336 defNode
->SetName(wxT("liststyle"));
1338 if (!listDef
->GetNextStyle().empty())
1339 defNode
->AddAttribute(wxT("nextstyle"), listDef
->GetNextStyle());
1341 AddAttributes(styleNode
, def
->GetStyle(), true);
1344 for (i
= 0; i
< 10; i
++)
1346 wxRichTextAttr
* levelAttr
= listDef
->GetLevelAttributes(i
);
1349 wxXmlNode
* levelNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, wxT("style"));
1350 defNode
->AddChild(levelNode
);
1351 levelNode
->AddAttribute(wxT("level"), MakeString(i
+1));
1352 AddAttributes(levelNode
, * levelAttr
, true);
1358 defNode
->SetName(wxT("boxstyle"));
1360 AddAttributes(styleNode
, def
->GetStyle(), true);
1364 defNode
->SetName(wxT("paragraphstyle"));
1366 if (!paraDef
->GetNextStyle().empty())
1367 defNode
->AddAttribute(wxT("nextstyle"), paraDef
->GetNextStyle());
1369 AddAttributes(styleNode
, def
->GetStyle(), true);
1375 bool wxRichTextXMLHandler::AddAttributes(wxXmlNode
* node
, wxRichTextAttr
& attr
, bool isPara
)
1377 if (attr
.HasTextColour() && attr
.GetTextColour().IsOk())
1378 node
->AddAttribute(wxT("textcolor"), MakeString(attr
.GetTextColour()));
1379 if (attr
.HasBackgroundColour() && attr
.GetBackgroundColour().IsOk())
1380 node
->AddAttribute(wxT("bgcolor"), MakeString(attr
.GetBackgroundColour()));
1382 if (attr
.HasFontSize())
1383 node
->AddAttribute(wxT("fontsize"), MakeString(attr
.GetFontSize()));
1384 if (attr
.HasFontFamily())
1385 node
->AddAttribute(wxT("fontfamily"), MakeString(attr
.GetFontFamily()));
1386 if (attr
.HasFontItalic())
1387 node
->AddAttribute(wxT("fontstyle"), MakeString(attr
.GetFontStyle()));
1388 if (attr
.HasFontWeight())
1389 node
->AddAttribute(wxT("fontweight"), MakeString(attr
.GetFontWeight()));
1390 if (attr
.HasFontUnderlined())
1391 node
->AddAttribute(wxT("fontunderlined"), MakeString((int) attr
.GetFontUnderlined()));
1392 if (attr
.HasFontFaceName())
1393 node
->AddAttribute(wxT("fontface"), attr
.GetFontFaceName());
1395 if (attr
.HasTextEffects())
1397 node
->AddAttribute(wxT("texteffects"), MakeString(attr
.GetTextEffects()));
1398 node
->AddAttribute(wxT("texteffectflags"), MakeString(attr
.GetTextEffectFlags()));
1400 if (attr
.HasCharacterStyleName() && !attr
.GetCharacterStyleName().empty())
1401 node
->AddAttribute(wxT("characterstyle"), attr
.GetCharacterStyleName());
1404 node
->AddAttribute(wxT("url"), attr
.GetURL()); // TODO: do we need to wrap this in AttributeToXML?
1408 if (attr
.HasAlignment())
1409 node
->AddAttribute(wxT("alignment"), MakeString((int) attr
.GetAlignment()));
1411 if (attr
.HasLeftIndent())
1413 node
->AddAttribute(wxT("leftindent"), MakeString((int) attr
.GetLeftIndent()));
1414 node
->AddAttribute(wxT("leftsubindent"), MakeString((int) attr
.GetLeftSubIndent()));
1417 if (attr
.HasRightIndent())
1418 node
->AddAttribute(wxT("rightindent"), MakeString((int) attr
.GetRightIndent()));
1420 if (attr
.HasParagraphSpacingAfter())
1421 node
->AddAttribute(wxT("parspacingafter"), MakeString((int) attr
.GetParagraphSpacingAfter()));
1423 if (attr
.HasParagraphSpacingBefore())
1424 node
->AddAttribute(wxT("parspacingbefore"), MakeString((int) attr
.GetParagraphSpacingBefore()));
1426 if (attr
.HasLineSpacing())
1427 node
->AddAttribute(wxT("linespacing"), MakeString((int) attr
.GetLineSpacing()));
1429 if (attr
.HasBulletStyle())
1430 node
->AddAttribute(wxT("bulletstyle"), MakeString((int) attr
.GetBulletStyle()));
1432 if (attr
.HasBulletNumber())
1433 node
->AddAttribute(wxT("bulletnumber"), MakeString((int) attr
.GetBulletNumber()));
1435 if (attr
.HasBulletText())
1437 // If using a bullet symbol, convert to integer in case it's a non-XML-friendly character.
1438 // Otherwise, assume it's XML-friendly text such as outline numbering, e.g. 1.2.3.1
1439 if (!attr
.GetBulletText().empty() && (attr
.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_SYMBOL
))
1440 node
->AddAttribute(wxT("bulletsymbol"), MakeString((int) (attr
.GetBulletText()[0])));
1442 node
->AddAttribute(wxT("bullettext"), attr
.GetBulletText());
1444 if (!attr
.GetBulletFont().empty())
1445 node
->AddAttribute(wxT("bulletfont"), attr
.GetBulletFont());
1448 if (attr
.HasBulletName())
1449 node
->AddAttribute(wxT("bulletname"), attr
.GetBulletName());
1451 if (!attr
.GetParagraphStyleName().empty())
1452 node
->AddAttribute(wxT("parstyle"), attr
.GetParagraphStyleName());
1454 if (!attr
.GetListStyleName().empty())
1455 node
->AddAttribute(wxT("liststyle"), attr
.GetListStyleName());
1457 if (!attr
.GetTextBoxAttr().GetBoxStyleName().empty())
1458 node
->AddAttribute(wxT("boxstyle"), attr
.GetTextBoxAttr().GetBoxStyleName());
1464 for (i
= 0; i
< attr
.GetTabs().GetCount(); i
++)
1468 tabs
<< attr
.GetTabs()[i
];
1470 node
->AddAttribute(wxT("tabs"), tabs
);
1473 if (attr
.HasPageBreak())
1474 node
->AddAttribute(wxT("pagebreak"), wxT("1"));
1476 if (attr
.HasOutlineLevel())
1477 node
->AddAttribute(wxT("outlinelevel"), MakeString((int) attr
.GetOutlineLevel()));
1480 AddAttribute(node
, wxT("margin"), attr
.GetTextBoxAttr().GetMargins());
1481 AddAttribute(node
, wxT("padding"), attr
.GetTextBoxAttr().GetPadding());
1482 AddAttribute(node
, wxT("position"), attr
.GetTextBoxAttr().GetPosition());
1483 AddAttribute(node
, wxT("border"), attr
.GetTextBoxAttr().GetBorder());
1484 AddAttribute(node
, wxT("outline"), attr
.GetTextBoxAttr().GetOutline());
1485 AddAttribute(node
, wxT("width"), attr
.GetTextBoxAttr().GetWidth());
1486 AddAttribute(node
, wxT("height"), attr
.GetTextBoxAttr().GetHeight());
1488 if (attr
.GetTextBoxAttr().HasVerticalAlignment())
1491 if (attr
.GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_TOP
)
1493 else if (attr
.GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_CENTRE
)
1494 value
= wxT("centre");
1495 else if (attr
.GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_BOTTOM
)
1496 value
= wxT("bottom");
1498 value
= wxT("none");
1499 AddAttribute(node
, wxT("verticalalignment"), value
);
1502 if (attr
.GetTextBoxAttr().HasFloatMode())
1505 if (attr
.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_LEFT
)
1506 value
= wxT("left");
1507 else if (attr
.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_RIGHT
)
1508 value
= wxT("right");
1510 value
= wxT("none");
1511 AddAttribute(node
, wxT("float"), value
);
1514 if (attr
.GetTextBoxAttr().HasClearMode())
1517 if (attr
.GetTextBoxAttr().GetClearMode() == wxTEXT_BOX_ATTR_CLEAR_LEFT
)
1518 value
= wxT("left");
1519 else if (attr
.GetTextBoxAttr().GetClearMode() == wxTEXT_BOX_ATTR_CLEAR_RIGHT
)
1520 value
= wxT("right");
1521 else if (attr
.GetTextBoxAttr().GetClearMode() == wxTEXT_BOX_ATTR_CLEAR_BOTH
)
1522 value
= wxT("both");
1524 value
= wxT("none");
1525 AddAttribute(node
, wxT("clear"), value
);
1528 if (attr
.GetTextBoxAttr().HasCollapseBorders())
1529 AddAttribute(node
, wxT("collapse-borders"), (int) attr
.GetTextBoxAttr().GetCollapseBorders());
1534 bool wxRichTextXMLHandler::WriteProperties(wxXmlNode
* node
, const wxRichTextProperties
& properties
)
1536 if (properties
.GetCount() > 0)
1538 wxXmlNode
* propertiesNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, wxT("properties"));
1539 node
->AddChild(propertiesNode
);
1541 for (i
= 0; i
< properties
.GetCount(); i
++)
1543 const wxVariant
& var
= properties
[i
];
1546 wxXmlNode
* propertyNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, wxT("property"));
1547 propertiesNode
->AddChild(propertyNode
);
1549 const wxString
& name
= var
.GetName();
1550 wxString value
= MakeStringFromProperty(var
);
1552 AddAttribute(propertyNode
, wxT("name"), name
);
1553 AddAttribute(propertyNode
, wxT("type"), var
.GetType());
1554 AddAttribute(propertyNode
, wxT("value"), value
);
1562 // wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
1564 /// Replace face name with current name for platform.
1565 /// TODO: introduce a virtual function or settable table to
1566 /// do this comprehensively.
1567 bool wxRichTextFixFaceName(wxString
& facename
)
1569 if (facename
.empty())
1573 if (facename
== wxT("Times"))
1575 facename
= wxT("Times New Roman");
1578 else if (facename
== wxT("Helvetica"))
1580 facename
= wxT("Arial");
1583 else if (facename
== wxT("Courier"))
1585 facename
= wxT("Courier New");
1591 if (facename
== wxT("Times New Roman"))
1593 facename
= wxT("Times");
1596 else if (facename
== wxT("Arial"))
1598 facename
= wxT("Helvetica");
1601 else if (facename
== wxT("Courier New"))
1603 facename
= wxT("Courier");
1611 static inline long wxRichTextColourStringToLong(const wxString
& colStr
)
1613 if (!colStr
.IsEmpty())
1615 wxColour
col(colStr
);
1616 return col
.GetRGB();
1622 static inline wxTextAttrDimension
wxRichTextParseDimension(const wxString
& dimStr
)
1624 wxString valuePart
= dimStr
.BeforeFirst(wxT(','));
1626 if (dimStr
.Contains(wxT(",")))
1627 flagsPart
= dimStr
.AfterFirst(wxT(','));
1628 wxTextAttrDimension dim
;
1629 dim
.SetValue(wxAtoi(valuePart
));
1630 dim
.SetFlags(wxAtoi(flagsPart
));
1635 /// Import style parameters
1636 bool wxRichTextXMLHandler::ImportStyle(wxRichTextAttr
& attr
, wxXmlNode
* node
, bool isPara
)
1638 wxXmlAttribute
* xmlAttr
= node
->GetAttributes();
1642 const wxString
& name
= xmlAttr
->GetName();
1643 const wxString
& value
= xmlAttr
->GetValue();
1646 if (name
== wxT("fontface"))
1651 if (GetFlags() & wxRICHTEXT_HANDLER_CONVERT_FACENAMES
)
1652 wxRichTextFixFaceName(v
);
1653 attr
.SetFontFaceName(v
);
1656 else if (name
== wxT("fontfamily"))
1659 attr
.SetFontFamily((wxFontFamily
)wxAtoi(value
));
1661 else if (name
== wxT("fontstyle"))
1664 attr
.SetFontStyle((wxFontStyle
)wxAtoi(value
));
1666 else if (name
== wxT("fontsize"))
1669 attr
.SetFontSize(wxAtoi(value
));
1671 else if (name
== wxT("fontweight"))
1674 attr
.SetFontWeight((wxFontWeight
) wxAtoi(value
));
1676 else if (name
== wxT("fontunderlined"))
1679 attr
.SetFontUnderlined(wxAtoi(value
) != 0);
1681 else if (name
== wxT("textcolor"))
1685 if (value
[0] == wxT('#'))
1686 attr
.SetTextColour(HexStringToColour(value
.Mid(1)));
1688 attr
.SetTextColour(value
);
1691 else if (name
== wxT("bgcolor"))
1695 if (value
[0] == wxT('#'))
1696 attr
.SetBackgroundColour(HexStringToColour(value
.Mid(1)));
1698 attr
.SetBackgroundColour(value
);
1701 else if (name
== wxT("characterstyle"))
1704 attr
.SetCharacterStyleName(value
);
1706 else if (name
== wxT("texteffects"))
1709 attr
.SetTextEffects(wxAtoi(value
));
1711 else if (name
== wxT("texteffectflags"))
1714 attr
.SetTextEffectFlags(wxAtoi(value
));
1716 else if (name
== wxT("url"))
1723 if (name
== wxT("alignment"))
1726 attr
.SetAlignment((wxTextAttrAlignment
) wxAtoi(value
));
1728 else if (name
== wxT("leftindent"))
1731 attr
.SetLeftIndent(wxAtoi(value
), attr
.GetLeftSubIndent());
1733 else if (name
== wxT("leftsubindent"))
1736 attr
.SetLeftIndent(attr
.GetLeftIndent(), wxAtoi(value
));
1738 else if (name
== wxT("rightindent"))
1741 attr
.SetRightIndent(wxAtoi(value
));
1743 else if (name
== wxT("parspacingbefore"))
1746 attr
.SetParagraphSpacingBefore(wxAtoi(value
));
1748 else if (name
== wxT("parspacingafter"))
1751 attr
.SetParagraphSpacingAfter(wxAtoi(value
));
1753 else if (name
== wxT("linespacing"))
1756 attr
.SetLineSpacing(wxAtoi(value
));
1758 else if (name
== wxT("bulletstyle"))
1761 attr
.SetBulletStyle(wxAtoi(value
));
1763 else if (name
== wxT("bulletnumber"))
1766 attr
.SetBulletNumber(wxAtoi(value
));
1768 else if (name
== wxT("bulletsymbol"))
1772 wxChar ch
= wxAtoi(value
);
1775 attr
.SetBulletText(s
);
1778 else if (name
== wxT("bullettext"))
1782 attr
.SetBulletText(value
);
1785 else if (name
== wxT("bulletfont"))
1789 attr
.SetBulletFont(value
);
1792 else if (name
== wxT("bulletname"))
1796 attr
.SetBulletName(value
);
1799 else if (name
== wxT("parstyle"))
1803 attr
.SetParagraphStyleName(value
);
1806 else if (name
== wxT("liststyle"))
1810 attr
.SetListStyleName(value
);
1813 else if (name
== wxT("boxstyle"))
1817 attr
.GetTextBoxAttr().SetBoxStyleName(value
);
1820 else if (name
== wxT("tabs"))
1825 wxStringTokenizer
tkz(value
, wxT(","));
1826 while (tkz
.HasMoreTokens())
1828 wxString token
= tkz
.GetNextToken();
1829 tabs
.Add(wxAtoi(token
));
1834 else if (name
== wxT("pagebreak"))
1838 attr
.SetPageBreak(wxAtoi(value
) != 0);
1841 else if (name
== wxT("outlinelevel"))
1845 attr
.SetOutlineLevel(wxAtoi(value
));
1858 if (name
== wxT("width"))
1860 attr
.GetTextBoxAttr().GetWidth().SetValue(wxRichTextParseDimension(value
));
1862 else if (name
== wxT("height"))
1864 attr
.GetTextBoxAttr().GetHeight().SetValue(wxRichTextParseDimension(value
));
1867 else if (name
== wxT("verticalalignment"))
1869 if (value
== wxT("top"))
1870 attr
.GetTextBoxAttr().SetVerticalAlignment(wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_TOP
);
1871 else if (value
== wxT("centre"))
1872 attr
.GetTextBoxAttr().SetVerticalAlignment(wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_CENTRE
);
1873 else if (value
== wxT("bottom"))
1874 attr
.GetTextBoxAttr().SetVerticalAlignment(wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_BOTTOM
);
1875 else if (value
== wxT("none"))
1876 attr
.GetTextBoxAttr().SetVerticalAlignment(wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_NONE
);
1878 else if (name
== wxT("float"))
1880 if (value
== wxT("left"))
1881 attr
.GetTextBoxAttr().SetFloatMode(wxTEXT_BOX_ATTR_FLOAT_LEFT
);
1882 else if (value
== wxT("right"))
1883 attr
.GetTextBoxAttr().SetFloatMode(wxTEXT_BOX_ATTR_FLOAT_RIGHT
);
1884 else if (value
== wxT("none"))
1885 attr
.GetTextBoxAttr().SetFloatMode(wxTEXT_BOX_ATTR_FLOAT_NONE
);
1887 else if (name
== wxT("clear"))
1889 if (value
== wxT("left"))
1890 attr
.GetTextBoxAttr().SetClearMode(wxTEXT_BOX_ATTR_CLEAR_LEFT
);
1891 else if (value
== wxT("right"))
1892 attr
.GetTextBoxAttr().SetClearMode(wxTEXT_BOX_ATTR_CLEAR_RIGHT
);
1893 else if (value
== wxT("both"))
1894 attr
.GetTextBoxAttr().SetClearMode(wxTEXT_BOX_ATTR_CLEAR_BOTH
);
1895 else if (value
== wxT("none"))
1896 attr
.GetTextBoxAttr().SetClearMode(wxTEXT_BOX_ATTR_CLEAR_NONE
);
1898 else if (name
== wxT("collapse-borders"))
1899 attr
.GetTextBoxAttr().SetCollapseBorders((wxTextBoxAttrCollapseMode
) wxAtoi(value
));
1901 else if (name
.Contains(wxT("border-")))
1903 if (name
== wxT("border-left-style"))
1904 attr
.GetTextBoxAttr().GetBorder().GetLeft().SetStyle(wxAtoi(value
));
1905 else if (name
== wxT("border-right-style"))
1906 attr
.GetTextBoxAttr().GetBorder().GetRight().SetStyle(wxAtoi(value
));
1907 else if (name
== wxT("border-top-style"))
1908 attr
.GetTextBoxAttr().GetBorder().GetTop().SetStyle(wxAtoi(value
));
1909 else if (name
== wxT("border-bottom-style"))
1910 attr
.GetTextBoxAttr().GetBorder().GetBottom().SetStyle(wxAtoi(value
));
1912 else if (name
== wxT("border-left-colour"))
1913 attr
.GetTextBoxAttr().GetBorder().GetLeft().SetColour(wxRichTextColourStringToLong(value
));
1914 else if (name
== wxT("border-right-colour"))
1915 attr
.GetTextBoxAttr().GetBorder().GetRight().SetColour(wxRichTextColourStringToLong(value
));
1916 else if (name
== wxT("border-top-colour"))
1917 attr
.GetTextBoxAttr().GetBorder().GetTop().SetColour(wxRichTextColourStringToLong(value
));
1918 else if (name
== wxT("border-bottom-colour"))
1919 attr
.GetTextBoxAttr().GetBorder().GetBottom().SetColour(wxRichTextColourStringToLong(value
));
1921 else if (name
== wxT("border-left-width"))
1922 attr
.GetTextBoxAttr().GetBorder().GetLeft().SetWidth(wxRichTextParseDimension(value
));
1923 else if (name
== wxT("border-right-width"))
1924 attr
.GetTextBoxAttr().GetBorder().GetRight().SetWidth(wxRichTextParseDimension(value
));
1925 else if (name
== wxT("border-top-width"))
1926 attr
.GetTextBoxAttr().GetBorder().GetTop().SetWidth(wxRichTextParseDimension(value
));
1927 else if (name
== wxT("border-bottom-width"))
1928 attr
.GetTextBoxAttr().GetBorder().GetBottom().SetWidth(wxRichTextParseDimension(value
));
1930 else if (name
.Contains(wxT("outline-")))
1932 if (name
== wxT("outline-left-style"))
1933 attr
.GetTextBoxAttr().GetOutline().GetLeft().SetStyle(wxAtoi(value
));
1934 else if (name
== wxT("outline-right-style"))
1935 attr
.GetTextBoxAttr().GetOutline().GetRight().SetStyle(wxAtoi(value
));
1936 else if (name
== wxT("outline-top-style"))
1937 attr
.GetTextBoxAttr().GetOutline().GetTop().SetStyle(wxAtoi(value
));
1938 else if (name
== wxT("outline-bottom-style"))
1939 attr
.GetTextBoxAttr().GetOutline().GetBottom().SetStyle(wxAtoi(value
));
1941 else if (name
== wxT("outline-left-colour"))
1942 attr
.GetTextBoxAttr().GetOutline().GetLeft().SetColour(wxRichTextColourStringToLong(value
));
1943 else if (name
== wxT("outline-right-colour"))
1944 attr
.GetTextBoxAttr().GetOutline().GetRight().SetColour(wxRichTextColourStringToLong(value
));
1945 else if (name
== wxT("outline-top-colour"))
1946 attr
.GetTextBoxAttr().GetOutline().GetTop().SetColour(wxRichTextColourStringToLong(value
));
1947 else if (name
== wxT("outline-bottom-colour"))
1948 attr
.GetTextBoxAttr().GetOutline().GetBottom().SetColour(wxRichTextColourStringToLong(value
));
1950 else if (name
== wxT("outline-left-width"))
1951 attr
.GetTextBoxAttr().GetOutline().GetLeft().SetWidth(wxRichTextParseDimension(value
));
1952 else if (name
== wxT("outline-right-width"))
1953 attr
.GetTextBoxAttr().GetOutline().GetRight().SetWidth(wxRichTextParseDimension(value
));
1954 else if (name
== wxT("outline-top-width"))
1955 attr
.GetTextBoxAttr().GetOutline().GetTop().SetWidth(wxRichTextParseDimension(value
));
1956 else if (name
== wxT("outline-bottom-width"))
1957 attr
.GetTextBoxAttr().GetOutline().GetBottom().SetWidth(wxRichTextParseDimension(value
));
1959 else if (name
.Contains(wxT("margin-")))
1961 if (name
== wxT("margin-left"))
1962 attr
.GetTextBoxAttr().GetMargins().GetLeft().SetValue(wxRichTextParseDimension(value
));
1963 else if (name
== wxT("margin-right"))
1964 attr
.GetTextBoxAttr().GetMargins().GetRight().SetValue(wxRichTextParseDimension(value
));
1965 else if (name
== wxT("margin-top"))
1966 attr
.GetTextBoxAttr().GetMargins().GetTop().SetValue(wxRichTextParseDimension(value
));
1967 else if (name
== wxT("margin-bottom"))
1968 attr
.GetTextBoxAttr().GetMargins().GetBottom().SetValue(wxRichTextParseDimension(value
));
1970 else if (name
.Contains(wxT("padding-")))
1972 if (name
== wxT("padding-left"))
1973 attr
.GetTextBoxAttr().GetPadding().GetLeft().SetValue(wxRichTextParseDimension(value
));
1974 else if (name
== wxT("padding-right"))
1975 attr
.GetTextBoxAttr().GetPadding().GetRight().SetValue(wxRichTextParseDimension(value
));
1976 else if (name
== wxT("padding-top"))
1977 attr
.GetTextBoxAttr().GetPadding().GetTop().SetValue(wxRichTextParseDimension(value
));
1978 else if (name
== wxT("padding-bottom"))
1979 attr
.GetTextBoxAttr().GetPadding().GetBottom().SetValue(wxRichTextParseDimension(value
));
1981 else if (name
.Contains(wxT("position-")))
1983 if (name
== wxT("position-left"))
1984 attr
.GetTextBoxAttr().GetPosition().GetLeft().SetValue(wxRichTextParseDimension(value
));
1985 else if (name
== wxT("position-right"))
1986 attr
.GetTextBoxAttr().GetPosition().GetRight().SetValue(wxRichTextParseDimension(value
));
1987 else if (name
== wxT("position-top"))
1988 attr
.GetTextBoxAttr().GetPosition().GetTop().SetValue(wxRichTextParseDimension(value
));
1989 else if (name
== wxT("position-bottom"))
1990 attr
.GetTextBoxAttr().GetPosition().GetBottom().SetValue(wxRichTextParseDimension(value
));
1994 xmlAttr
= xmlAttr
->GetNext();
2003 // Import this object from XML
2004 bool wxRichTextObject::ImportFromXML(wxRichTextBuffer
* WXUNUSED(buffer
), wxXmlNode
* node
, wxRichTextXMLHandler
* handler
, bool* recurse
)
2006 handler
->ImportProperties(this, node
);
2007 handler
->ImportStyle(GetAttributes(), node
, UsesParagraphAttributes());
2014 #if wxRICHTEXT_HAVE_DIRECT_OUTPUT
2015 // Export this object directly to the given stream.
2016 bool wxRichTextObject::ExportXML(wxOutputStream
& stream
, int indent
, wxRichTextXMLHandler
* handler
)
2018 ::OutputIndentation(stream
, indent
);
2019 ::OutputString(stream
, wxT("<") + GetXMLNodeName(), handler
->GetConvMem(), handler
->GetConvFile());
2021 wxString style
= handler
->AddAttributes(GetAttributes(), true);
2023 ::OutputString(stream
, style
+ wxT(">"), handler
->GetConvMem(), handler
->GetConvFile());
2025 if (GetProperties().GetCount() > 0)
2027 handler
->WriteProperties(stream
, GetProperties(), indent
);
2030 wxRichTextCompositeObject
* composite
= wxDynamicCast(this, wxRichTextCompositeObject
);
2034 for (i
= 0; i
< composite
->GetChildCount(); i
++)
2036 wxRichTextObject
* child
= composite
->GetChild(i
);
2037 child
->ExportXML(stream
, indent
+1, handler
);
2041 ::OutputIndentation(stream
, indent
);
2042 ::OutputString(stream
, wxT("</") + GetXMLNodeName() + wxT(">"), handler
->GetConvMem(), handler
->GetConvFile());
2047 #if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
2048 // Export this object to the given parent node, usually creating at least one child node.
2049 bool wxRichTextObject::ExportXML(wxXmlNode
* parent
, wxRichTextXMLHandler
* handler
)
2051 wxXmlNode
* elementNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, GetXMLNodeName());
2052 parent
->AddChild(elementNode
);
2053 handler
->AddAttributes(elementNode
, GetAttributes(), true);
2054 handler
->WriteProperties(elementNode
, GetProperties());
2056 wxRichTextCompositeObject
* composite
= wxDynamicCast(this, wxRichTextCompositeObject
);
2060 for (i
= 0; i
< composite
->GetChildCount(); i
++)
2062 wxRichTextObject
* child
= composite
->GetChild(i
);
2063 child
->ExportXML(elementNode
, handler
);
2071 // Import this object from XML
2072 bool wxRichTextPlainText::ImportFromXML(wxRichTextBuffer
* buffer
, wxXmlNode
* node
, wxRichTextXMLHandler
* handler
, bool* recurse
)
2074 wxRichTextObject::ImportFromXML(buffer
, node
, handler
, recurse
);
2076 if (node
->GetName() == wxT("text"))
2079 wxXmlNode
* textChild
= node
->GetChildren();
2082 if (textChild
->GetType() == wxXML_TEXT_NODE
||
2083 textChild
->GetType() == wxXML_CDATA_SECTION_NODE
)
2085 wxString text2
= textChild
->GetContent();
2087 // Strip whitespace from end
2088 if (!text2
.empty() && text2
[text2
.length()-1] == wxT('\n'))
2089 text2
= text2
.Mid(0, text2
.length()-1);
2091 if (!text2
.empty() && text2
[0] == wxT('"'))
2092 text2
= text2
.Mid(1);
2093 if (!text2
.empty() && text2
[text2
.length()-1] == wxT('"'))
2094 text2
= text2
.Mid(0, text2
.length() - 1);
2098 textChild
= textChild
->GetNext();
2103 else if (node
->GetName() == wxT("symbol"))
2105 // This is a symbol that XML can't read in the normal way
2107 wxXmlNode
* textChild
= node
->GetChildren();
2110 if (textChild
->GetType() == wxXML_TEXT_NODE
||
2111 textChild
->GetType() == wxXML_CDATA_SECTION_NODE
)
2113 wxString text2
= textChild
->GetContent();
2116 textChild
= textChild
->GetNext();
2119 wxString actualText
;
2120 actualText
<< (wxChar
) wxAtoi(text
);
2121 SetText(actualText
);
2129 #if wxRICHTEXT_HAVE_DIRECT_OUTPUT
2130 // Export this object directly to the given stream.
2131 bool wxRichTextPlainText::ExportXML(wxOutputStream
& stream
, int indent
, wxRichTextXMLHandler
* handler
)
2133 wxString style
= handler
->AddAttributes(GetAttributes(), false);
2137 const wxString
& text
= GetText();
2138 int len
= (int) text
.Length();
2143 ::OutputIndentation(stream
, indent
);
2144 ::OutputString(stream
, wxT("<text"), handler
->GetConvMem(), handler
->GetConvFile());
2145 ::OutputString(stream
, style
+ wxT(">"), handler
->GetConvMem(), handler
->GetConvFile());
2146 if (GetProperties().GetCount() > 0)
2148 handler
->WriteProperties(stream
, GetProperties(), indent
);
2149 ::OutputIndentation(stream
, indent
);
2151 ::OutputString(stream
, wxT("</text>"), handler
->GetConvMem(), handler
->GetConvFile());
2153 else for (i
= 0; i
< len
; i
++)
2156 int c
= (int) text
[i
];
2158 int c
= (int) wxUChar(text
[i
]);
2160 if ((c
< 32 || c
== 34) && /* c != 9 && */ c
!= 10 && c
!= 13)
2164 wxString
fragment(text
.Mid(last
, i
-last
));
2165 if (!fragment
.empty())
2167 ::OutputIndentation(stream
, indent
);
2168 ::OutputString(stream
, wxT("<text"), handler
->GetConvMem(), handler
->GetConvFile());
2170 ::OutputString(stream
, style
+ wxT(">"), handler
->GetConvMem(), handler
->GetConvFile());
2172 if (!fragment
.empty() && (fragment
[0] == wxT(' ') || fragment
[fragment
.length()-1] == wxT(' ')))
2174 ::OutputString(stream
, wxT("\""), handler
->GetConvMem(), handler
->GetConvFile());
2175 ::OutputStringEnt(stream
, fragment
, handler
->GetConvMem(), handler
->GetConvFile());
2176 ::OutputString(stream
, wxT("\""), handler
->GetConvMem(), handler
->GetConvFile());
2179 ::OutputStringEnt(stream
, fragment
, handler
->GetConvMem(), handler
->GetConvFile());
2181 if (GetProperties().GetCount() > 0)
2183 handler
->WriteProperties(stream
, GetProperties(), indent
);
2184 ::OutputIndentation(stream
, indent
);
2186 ::OutputString(stream
, wxT("</text>"), handler
->GetConvMem(), handler
->GetConvFile());
2191 // Output this character as a number in a separate tag, because XML can't cope
2192 // with entities below 32 except for 10 and 13
2194 ::OutputIndentation(stream
, indent
);
2195 ::OutputString(stream
, wxT("<symbol"), handler
->GetConvMem(), handler
->GetConvFile());
2197 ::OutputString(stream
, style
+ wxT(">"), handler
->GetConvMem(), handler
->GetConvFile());
2198 ::OutputString(stream
, wxString::Format(wxT("%d"), c
), handler
->GetConvMem(), handler
->GetConvFile());
2200 if (GetProperties().GetCount() > 0)
2202 handler
->WriteProperties(stream
, GetProperties(), indent
);
2203 ::OutputIndentation(stream
, indent
);
2205 ::OutputString(stream
, wxT("</symbol>"), handler
->GetConvMem(), handler
->GetConvFile());
2213 fragment
= text
.Mid(last
, i
-last
);
2217 ::OutputIndentation(stream
, indent
);
2218 ::OutputString(stream
, wxT("<text"), handler
->GetConvMem(), handler
->GetConvFile());
2220 ::OutputString(stream
, style
+ wxT(">"), handler
->GetConvMem(), handler
->GetConvFile());
2222 if (GetProperties().GetCount() > 0)
2224 handler
->WriteProperties(stream
, GetProperties(), indent
);
2225 ::OutputIndentation(stream
, indent
);
2228 if (!fragment
.empty() && (fragment
[0] == wxT(' ') || fragment
[fragment
.length()-1] == wxT(' ')))
2230 ::OutputString(stream
, wxT("\""), handler
->GetConvMem(), handler
->GetConvFile());
2231 ::OutputStringEnt(stream
, fragment
, handler
->GetConvMem(), handler
->GetConvFile());
2232 ::OutputString(stream
, wxT("\""), handler
->GetConvMem(), handler
->GetConvFile());
2235 ::OutputStringEnt(stream
, fragment
, handler
->GetConvMem(), handler
->GetConvFile());
2237 ::OutputString(stream
, wxT("</text>"), handler
->GetConvMem(), handler
->GetConvFile());
2243 #if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
2244 // Export this object to the given parent node, usually creating at least one child node.
2245 bool wxRichTextPlainText::ExportXML(wxXmlNode
* parent
, wxRichTextXMLHandler
* handler
)
2249 const wxString
& text
= GetText();
2250 int len
= (int) text
.Length();
2256 wxXmlNode
* elementNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, wxT("text"));
2257 parent
->AddChild(elementNode
);
2259 handler
->AddAttributes(elementNode
, GetAttributes(), false);
2260 handler
->WriteProperties(elementNode
, GetProperties());
2262 else for (i
= 0; i
< len
; i
++)
2265 int c
= (int) text
[i
];
2267 int c
= (int) wxUChar(text
[i
]);
2269 if ((c
< 32 || c
== 34) && c
!= 10 && c
!= 13)
2273 wxString
fragment(text
.Mid(last
, i
-last
));
2274 if (!fragment
.empty())
2276 // TODO: I'm assuming wxXmlDocument will output quotes if necessary
2277 wxXmlNode
* elementNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, wxT("text"));
2278 parent
->AddChild(elementNode
);
2279 handler
->AddAttributes(elementNode
, GetAttributes(), false);
2280 handler
->WriteProperties(elementNode
, GetProperties());
2282 wxXmlNode
* textNode
= new wxXmlNode(wxXML_TEXT_NODE
, wxT("text"));
2283 elementNode
->AddChild(textNode
);
2285 if (fragment
[0] == wxT(' ') || fragment
[fragment
.length()-1] == wxT(' '))
2286 fragment
= wxT("\"") + fragment
+ wxT("\"");
2288 textNode
->SetContent(fragment
);
2293 // Output this character as a number in a separate tag, because XML can't cope
2294 // with entities below 32 except for 10 and 13
2296 wxXmlNode
* elementNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, wxT("symbol"));
2297 parent
->AddChild(elementNode
);
2299 handler
->AddAttributes(elementNode
, GetAttributes(), false);
2300 handler
->WriteProperties(elementNode
, GetProperties());
2302 wxXmlNode
* textNode
= new wxXmlNode(wxXML_TEXT_NODE
, wxT("text"));
2303 elementNode
->AddChild(textNode
);
2304 textNode
->SetContent(wxString::Format(wxT("%d"), c
));
2314 fragment
= text
.Mid(last
, i
-last
);
2318 wxXmlNode
* elementNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, wxT("text"));
2319 parent
->AddChild(elementNode
);
2320 handler
->AddAttributes(elementNode
, GetAttributes(), false);
2322 wxXmlNode
* textNode
= new wxXmlNode(wxXML_TEXT_NODE
, wxT("text"));
2323 elementNode
->AddChild(textNode
);
2325 if (fragment
[0] == wxT(' ') || fragment
[fragment
.length()-1] == wxT(' '))
2326 fragment
= wxT("\"") + fragment
+ wxT("\"");
2328 textNode
->SetContent(fragment
);
2335 // Import this object from XML
2336 bool wxRichTextImage::ImportFromXML(wxRichTextBuffer
* buffer
, wxXmlNode
* node
, wxRichTextXMLHandler
* handler
, bool* recurse
)
2338 wxRichTextObject::ImportFromXML(buffer
, node
, handler
, recurse
);
2340 wxBitmapType imageType
= wxBITMAP_TYPE_PNG
;
2341 wxString value
= node
->GetAttribute(wxT("imagetype"), wxEmptyString
);
2344 int type
= wxAtoi(value
);
2346 // note: 0 == wxBITMAP_TYPE_INVALID
2347 if (type
<= 0 || type
>= wxBITMAP_TYPE_MAX
)
2349 wxLogWarning("Invalid bitmap type specified for <image> tag: %d", type
);
2353 imageType
= (wxBitmapType
)type
;
2359 wxXmlNode
* imageChild
= node
->GetChildren();
2362 wxString childName
= imageChild
->GetName();
2363 if (childName
== wxT("data"))
2365 wxXmlNode
* dataChild
= imageChild
->GetChildren();
2368 data
= dataChild
->GetContent();
2369 // wxLogDebug(data);
2370 dataChild
= dataChild
->GetNext();
2374 imageChild
= imageChild
->GetNext();
2379 wxStringInputStream
strStream(data
);
2381 GetImageBlock().ReadHex(strStream
, data
.length(), imageType
);
2389 #if wxRICHTEXT_HAVE_DIRECT_OUTPUT
2390 // Export this object directly to the given stream.
2391 bool wxRichTextImage::ExportXML(wxOutputStream
& stream
, int indent
, wxRichTextXMLHandler
* handler
)
2393 wxString style
= handler
->AddAttributes(GetAttributes(), false);
2395 ::OutputIndentation(stream
, indent
);
2396 ::OutputString(stream
, wxT("<image"), handler
->GetConvMem(), handler
->GetConvFile());
2397 if (!GetImageBlock().IsOk())
2400 ::OutputString(stream
, style
+ wxT(">"), handler
->GetConvMem(), handler
->GetConvFile());
2404 ::OutputString(stream
, wxString::Format(wxT(" imagetype=\"%d\""), (int) GetImageBlock().GetImageType()) + style
+ wxT(">"), handler
->GetConvMem(), handler
->GetConvFile());
2406 if (GetProperties().GetCount() > 0)
2408 handler
->WriteProperties(stream
, GetProperties(), indent
);
2409 ::OutputIndentation(stream
, indent
);
2412 ::OutputIndentation(stream
, indent
+1);
2413 ::OutputString(stream
, wxT("<data>"), handler
->GetConvMem(), handler
->GetConvFile());
2415 // wxStopWatch stopwatch;
2417 GetImageBlock().WriteHex(stream
);
2419 // wxLogDebug(wxT("Image conversion to hex took %ldms"), stopwatch.Time());
2421 ::OutputString(stream
, wxT("</data>\n"), handler
->GetConvMem(), handler
->GetConvFile());
2422 ::OutputIndentation(stream
, indent
);
2423 ::OutputString(stream
, wxT("</image>"), handler
->GetConvMem(), handler
->GetConvFile());
2428 #if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
2429 // Export this object to the given parent node, usually creating at least one child node.
2430 bool wxRichTextImage::ExportXML(wxXmlNode
* parent
, wxRichTextXMLHandler
* handler
)
2432 wxXmlNode
* elementNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, wxT("image"));
2433 parent
->AddChild(elementNode
);
2435 if (GetImageBlock().IsOk())
2436 elementNode
->AddAttribute(wxT("imagetype"), MakeString((int) GetImageBlock().GetImageType()));
2438 handler
->AddAttributes(elementNode
, GetAttributes(), false);
2439 handler
->WriteProperties(elementNode
, GetProperties());
2441 wxXmlNode
* dataNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, wxT("data"));
2442 elementNode
->AddChild(dataNode
);
2443 wxXmlNode
* textNode
= new wxXmlNode(wxXML_TEXT_NODE
, wxT("text"));
2444 dataNode
->AddChild(textNode
);
2449 wxMemoryOutputStream stream
;
2450 if (GetImageBlock().WriteHex(stream
))
2452 if (stream
.GetSize() > 0)
2454 int size
= stream
.GetSize();
2456 int size2
= stream
.GetOutputStreamBuffer()->GetIntPosition();
2457 wxASSERT(size
== size2
);
2459 unsigned char* data
= new unsigned char[size
];
2460 stream
.CopyTo(data
, size
);
2461 strData
= wxString((const char*) data
, wxConvUTF8
, size
);
2465 strData
= wxEmptyString
;
2471 wxStringOutputStream
strStream(& strData
);
2472 GetImageBlock().WriteHex(strStream
);
2476 textNode
->SetContent(strData
);
2477 textNode
->SetNoConversion(true); // optimize speed
2484 // Import this object from XML
2485 bool wxRichTextParagraphLayoutBox::ImportFromXML(wxRichTextBuffer
* buffer
, wxXmlNode
* node
, wxRichTextXMLHandler
* handler
, bool* recurse
)
2487 wxRichTextObject::ImportFromXML(buffer
, node
, handler
, recurse
);
2491 wxString partial
= node
->GetAttribute(wxT("partialparagraph"), wxEmptyString
);
2492 if (partial
== wxT("true"))
2493 SetPartialParagraph(true);
2495 wxXmlNode
* child
= wxRichTextXMLHandler::FindNode(node
, wxT("stylesheet"));
2496 if (child
&& (handler
->GetFlags() & wxRICHTEXT_HANDLER_INCLUDE_STYLESHEET
))
2498 wxRichTextStyleSheet
* sheet
= new wxRichTextStyleSheet
;
2499 wxString sheetName
= child
->GetAttribute(wxT("name"), wxEmptyString
);
2500 wxString sheetDescription
= child
->GetAttribute(wxT("description"), wxEmptyString
);
2501 sheet
->SetName(sheetName
);
2502 sheet
->SetDescription(sheetDescription
);
2504 wxXmlNode
* child2
= child
->GetChildren();
2507 handler
->ImportStyleDefinition(sheet
, child2
);
2509 child2
= child2
->GetNext();
2512 // Notify that styles have changed. If this is vetoed by the app,
2513 // the new sheet will be deleted. If it is not vetoed, the
2514 // old sheet will be deleted and replaced with the new one.
2515 buffer
->SetStyleSheetAndNotify(sheet
);
2521 #if wxRICHTEXT_HAVE_DIRECT_OUTPUT
2522 // Export this object directly to the given stream.
2523 bool wxRichTextParagraphLayoutBox::ExportXML(wxOutputStream
& stream
, int indent
, wxRichTextXMLHandler
* handler
)
2525 ::OutputIndentation(stream
, indent
);
2526 wxString nodeName
= GetXMLNodeName();
2527 ::OutputString(stream
, wxT("<") + nodeName
, handler
->GetConvMem(), handler
->GetConvFile());
2529 wxString style
= handler
->AddAttributes(GetAttributes(), true);
2531 if (GetPartialParagraph())
2532 style
<< wxT(" partialparagraph=\"true\"");
2534 ::OutputString(stream
, style
+ wxT(">"), handler
->GetConvMem(), handler
->GetConvFile());
2536 if (GetProperties().GetCount() > 0)
2538 handler
->WriteProperties(stream
, GetProperties(), indent
);
2542 for (i
= 0; i
< GetChildCount(); i
++)
2544 wxRichTextObject
* child
= GetChild(i
);
2545 child
->ExportXML(stream
, indent
+1, handler
);
2548 ::OutputIndentation(stream
, indent
);
2549 ::OutputString(stream
, wxT("</") + nodeName
+ wxT(">"), handler
->GetConvMem(), handler
->GetConvFile());
2554 #if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
2555 // Export this object to the given parent node, usually creating at least one child node.
2556 bool wxRichTextParagraphLayoutBox::ExportXML(wxXmlNode
* parent
, wxRichTextXMLHandler
* handler
)
2558 wxXmlNode
* elementNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, GetXMLNodeName());
2559 parent
->AddChild(elementNode
);
2560 handler
->AddAttributes(elementNode
, GetAttributes(), true);
2561 handler
->WriteProperties(elementNode
, GetProperties());
2563 if (GetPartialParagraph())
2564 elementNode
->AddAttribute(wxT("partialparagraph"), wxT("true"));
2567 for (i
= 0; i
< GetChildCount(); i
++)
2569 wxRichTextObject
* child
= GetChild(i
);
2570 child
->ExportXML(elementNode
, handler
);
2577 // Import this object from XML
2578 bool wxRichTextTable::ImportFromXML(wxRichTextBuffer
* buffer
, wxXmlNode
* node
, wxRichTextXMLHandler
* handler
, bool* recurse
)
2580 wxRichTextBox::ImportFromXML(buffer
, node
, handler
, recurse
);
2584 m_rowCount
= wxAtoi(node
->GetAttribute(wxT("rows"), wxEmptyString
));
2585 m_colCount
= wxAtoi(node
->GetAttribute(wxT("cols"), wxEmptyString
));
2587 wxXmlNode
* child
= node
->GetChildren();
2590 wxRichTextObject
* childObj
= handler
->CreateObjectForXMLName(this, child
->GetName());
2593 AppendChild(childObj
);
2594 handler
->ImportXML(buffer
, childObj
, child
);
2596 child
= child
->GetNext();
2599 m_cells
.Add(wxRichTextObjectPtrArray(), m_rowCount
);
2601 for (i
= 0; i
< m_rowCount
; i
++)
2603 wxRichTextObjectPtrArray
& colArray
= m_cells
[i
];
2604 for (j
= 0; j
< m_colCount
; j
++)
2606 int idx
= i
* m_colCount
+ j
;
2607 if (idx
< (int) GetChildren().GetCount())
2609 wxRichTextCell
* cell
= wxDynamicCast(GetChildren().Item(idx
)->GetData(), wxRichTextCell
);
2619 #if wxRICHTEXT_HAVE_DIRECT_OUTPUT
2620 // Export this object directly to the given stream.
2621 bool wxRichTextTable::ExportXML(wxOutputStream
& stream
, int indent
, wxRichTextXMLHandler
* handler
)
2623 ::OutputIndentation(stream
, indent
);
2624 wxString nodeName
= GetXMLNodeName();
2625 ::OutputString(stream
, wxT("<") + nodeName
, handler
->GetConvMem(), handler
->GetConvFile());
2627 wxString style
= handler
->AddAttributes(GetAttributes(), true);
2629 style
<< wxT(" rows=\"") << m_rowCount
<< wxT("\"");
2630 style
<< wxT(" cols=\"") << m_colCount
<< wxT("\"");
2632 ::OutputString(stream
, style
+ wxT(">"), handler
->GetConvMem(), handler
->GetConvFile());
2634 if (GetProperties().GetCount() > 0)
2636 handler
->WriteProperties(stream
, GetProperties(), indent
);
2640 for (i
= 0; i
< m_rowCount
; i
++)
2642 for (j
= 0; j
< m_colCount
; j
++)
2644 wxRichTextCell
* cell
= GetCell(i
, j
);
2645 cell
->ExportXML(stream
, indent
+1, handler
);
2649 ::OutputIndentation(stream
, indent
);
2650 ::OutputString(stream
, wxT("</") + nodeName
+ wxT(">"), handler
->GetConvMem(), handler
->GetConvFile());
2656 #if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
2657 // Export this object to the given parent node, usually creating at least one child node.
2658 bool wxRichTextTable::ExportXML(wxXmlNode
* parent
, wxRichTextXMLHandler
* handler
)
2660 wxXmlNode
* elementNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, GetXMLNodeName());
2661 parent
->AddChild(elementNode
);
2662 handler
->AddAttributes(elementNode
, GetAttributes(), true);
2663 handler
->WriteProperties(elementNode
, GetProperties());
2665 elementNode
->AddAttribute(wxT("rows"), wxString::Format(wxT("%d"), m_rowCount
));
2666 elementNode
->AddAttribute(wxT("cols"), wxString::Format(wxT("%d"), m_colCount
));
2669 for (i
= 0; i
< m_rowCount
; i
++)
2671 for (j
= 0; j
< m_colCount
; j
++)
2673 wxRichTextCell
* cell
= GetCell(i
, j
);
2674 cell
->ExportXML(elementNode
, handler
);
2684 // wxUSE_RICHTEXT && wxUSE_XML