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
;
173 /// Recursively import an object
174 bool wxRichTextXMLHandler::ImportXML(wxRichTextBuffer
* buffer
, wxRichTextObject
* obj
, wxXmlNode
* node
)
176 obj
->ImportFromXML(buffer
, node
, this);
178 wxRichTextCompositeObject
* compositeParent
= wxDynamicCast(obj
, wxRichTextCompositeObject
);
181 wxXmlNode
* child
= node
->GetChildren();
184 if (child
->GetName() == wxT("stylesheet"))
186 if (GetFlags() & wxRICHTEXT_HANDLER_INCLUDE_STYLESHEET
)
188 wxRichTextStyleSheet
* sheet
= new wxRichTextStyleSheet
;
189 wxString sheetName
= child
->GetAttribute(wxT("name"), wxEmptyString
);
190 wxString sheetDescription
= child
->GetAttribute(wxT("description"), wxEmptyString
);
191 sheet
->SetName(sheetName
);
192 sheet
->SetDescription(sheetDescription
);
194 wxXmlNode
* child2
= child
->GetChildren();
197 ImportStyleDefinition(sheet
, child2
);
199 child2
= child2
->GetNext();
202 // Notify that styles have changed. If this is vetoed by the app,
203 // the new sheet will be deleted. If it is not vetoed, the
204 // old sheet will be deleted and replaced with the new one.
205 buffer
->SetStyleSheetAndNotify(sheet
);
210 wxRichTextObject
* childObj
= CreateObjectForXMLName(obj
, child
->GetName());
213 compositeParent
->AppendChild(childObj
);
214 ImportXML(buffer
, childObj
, child
);
217 child
= child
->GetNext();
224 bool wxRichTextXMLHandler::ImportProperties(wxRichTextObject
* obj
, wxXmlNode
* node
)
226 wxXmlNode
* child
= node
->GetChildren();
229 if (child
->GetName() == wxT("properties"))
231 wxXmlNode
* propertyChild
= child
->GetChildren();
232 while (propertyChild
)
234 if (propertyChild
->GetName() == wxT("property"))
236 wxString name
= propertyChild
->GetAttribute(wxT("name"), wxEmptyString
);
237 wxString value
= propertyChild
->GetAttribute(wxT("value"), wxEmptyString
);
238 wxString type
= propertyChild
->GetAttribute(wxT("type"), wxEmptyString
);
240 wxVariant var
= MakePropertyFromString(name
, value
, type
);
243 obj
->GetProperties().SetProperty(var
);
246 propertyChild
= propertyChild
->GetNext();
249 child
= child
->GetNext();
254 bool wxRichTextXMLHandler::ImportStyleDefinition(wxRichTextStyleSheet
* sheet
, wxXmlNode
* node
)
256 wxString styleType
= node
->GetName();
257 wxString styleName
= node
->GetAttribute(wxT("name"), wxEmptyString
);
258 wxString baseStyleName
= node
->GetAttribute(wxT("basestyle"), wxEmptyString
);
260 if (styleName
.empty())
263 if (styleType
== wxT("characterstyle"))
265 wxRichTextCharacterStyleDefinition
* def
= new wxRichTextCharacterStyleDefinition(styleName
);
266 def
->SetBaseStyle(baseStyleName
);
268 wxXmlNode
* child
= node
->GetChildren();
271 if (child
->GetName() == wxT("style"))
274 ImportStyle(attr
, child
, false);
277 child
= child
->GetNext();
280 sheet
->AddCharacterStyle(def
);
282 else if (styleType
== wxT("paragraphstyle"))
284 wxRichTextParagraphStyleDefinition
* def
= new wxRichTextParagraphStyleDefinition(styleName
);
286 wxString nextStyleName
= node
->GetAttribute(wxT("nextstyle"), wxEmptyString
);
287 def
->SetNextStyle(nextStyleName
);
288 def
->SetBaseStyle(baseStyleName
);
290 wxXmlNode
* child
= node
->GetChildren();
293 if (child
->GetName() == wxT("style"))
296 ImportStyle(attr
, child
, true);
299 child
= child
->GetNext();
302 sheet
->AddParagraphStyle(def
);
304 else if (styleType
== wxT("liststyle"))
306 wxRichTextListStyleDefinition
* def
= new wxRichTextListStyleDefinition(styleName
);
308 wxString nextStyleName
= node
->GetAttribute(wxT("nextstyle"), wxEmptyString
);
309 def
->SetNextStyle(nextStyleName
);
310 def
->SetBaseStyle(baseStyleName
);
312 wxXmlNode
* child
= node
->GetChildren();
315 if (child
->GetName() == wxT("style"))
318 ImportStyle(attr
, child
, true);
320 wxString styleLevel
= child
->GetAttribute(wxT("level"), wxEmptyString
);
321 if (styleLevel
.empty())
327 int level
= wxAtoi(styleLevel
);
328 if (level
> 0 && level
<= 10)
330 def
->SetLevelAttributes(level
-1, attr
);
334 child
= child
->GetNext();
337 sheet
->AddListStyle(def
);
343 //-----------------------------------------------------------------------------
344 // xml support routines
345 //-----------------------------------------------------------------------------
347 bool wxRichTextXMLHandler::HasParam(wxXmlNode
* node
, const wxString
& param
)
349 return (GetParamNode(node
, param
) != NULL
);
352 wxXmlNode
*wxRichTextXMLHandler::GetParamNode(wxXmlNode
* node
, const wxString
& param
)
354 wxCHECK_MSG(node
, NULL
, wxT("You can't access node data before it was initialized!"));
356 wxXmlNode
*n
= node
->GetChildren();
360 if (n
->GetType() == wxXML_ELEMENT_NODE
&& n
->GetName() == param
)
368 wxString
wxRichTextXMLHandler::GetNodeContent(wxXmlNode
*node
)
371 if (n
== NULL
) return wxEmptyString
;
372 n
= n
->GetChildren();
376 if (n
->GetType() == wxXML_TEXT_NODE
||
377 n
->GetType() == wxXML_CDATA_SECTION_NODE
)
378 return n
->GetContent();
381 return wxEmptyString
;
385 wxString
wxRichTextXMLHandler::GetParamValue(wxXmlNode
*node
, const wxString
& param
)
388 return GetNodeContent(node
);
390 return GetNodeContent(GetParamNode(node
, param
));
393 wxString
wxRichTextXMLHandler::GetText(wxXmlNode
*node
, const wxString
& param
, bool WXUNUSED(translate
))
395 wxXmlNode
*parNode
= GetParamNode(node
, param
);
398 wxString
str1(GetNodeContent(parNode
));
402 // For use with earlier versions of wxWidgets
403 #ifndef WXUNUSED_IN_UNICODE
405 #define WXUNUSED_IN_UNICODE(x) WXUNUSED(x)
407 #define WXUNUSED_IN_UNICODE(x) x
411 // write string to output
412 inline static void OutputString(wxOutputStream
& stream
, const wxString
& str
,
413 wxMBConv
*WXUNUSED_IN_UNICODE(convMem
), wxMBConv
*convFile
)
415 if (str
.empty()) return;
419 const wxWX2MBbuf
buf(str
.mb_str(*convFile
));
420 stream
.Write((const char*)buf
, strlen((const char*)buf
));
424 const wxWX2MBbuf
buf(str
.mb_str(wxConvUTF8
));
425 stream
.Write((const char*)buf
, strlen((const char*)buf
));
428 if ( convFile
== NULL
)
429 stream
.Write(str
.mb_str(), str
.Len());
432 wxString
str2(str
.wc_str(*convMem
), *convFile
);
433 stream
.Write(str2
.mb_str(), str2
.Len());
438 static void OutputIndentation(wxOutputStream
& stream
, int indent
)
440 wxString str
= wxT("\n");
441 for (int i
= 0; i
< indent
; i
++)
442 str
<< wxT(' ') << wxT(' ');
443 ::OutputString(stream
, str
, NULL
, NULL
);
446 // Same as above, but create entities first.
447 // Translates '<' to "<", '>' to ">" and '&' to "&"
448 static void OutputStringEnt(wxOutputStream
& stream
, const wxString
& str
,
449 wxMBConv
*convMem
= NULL
, wxMBConv
*convFile
= NULL
)
457 for (i
= 0; i
< len
; i
++)
461 // Original code excluded "&" but we _do_ want to convert
462 // the ampersand beginning & because otherwise when read in,
463 // the original "&" becomes "&".
465 if (c
== wxT('<') || c
== wxT('>') || c
== wxT('"') ||
466 (c
== wxT('&') /* && (str.Mid(i+1, 4) != wxT("amp;")) */ ))
468 OutputString(stream
, str
.Mid(last
, i
- last
), convMem
, convFile
);
472 OutputString(stream
, wxT("<"), NULL
, NULL
);
475 OutputString(stream
, wxT(">"), NULL
, NULL
);
478 OutputString(stream
, wxT("&"), NULL
, NULL
);
481 OutputString(stream
, wxT("""), NULL
, NULL
);
487 else if (wxUChar(c
) > 127)
489 OutputString(stream
, str
.Mid(last
, i
- last
), convMem
, convFile
);
491 wxString
s(wxT("&#"));
495 s
<< (int) wxUChar(c
);
498 OutputString(stream
, s
, NULL
, NULL
);
502 OutputString(stream
, str
.Mid(last
, i
- last
), convMem
, convFile
);
505 void wxRichTextXMLHandler::OutputString(wxOutputStream
& stream
, const wxString
& str
)
507 ::OutputString(stream
, str
, m_convMem
, m_convFile
);
510 void wxRichTextXMLHandler::OutputStringEnt(wxOutputStream
& stream
, const wxString
& str
)
512 ::OutputStringEnt(stream
, str
, m_convMem
, m_convFile
);
515 void wxRichTextXMLHandler::OutputIndentation(wxOutputStream
& stream
, int indent
)
517 wxString str
= wxT("\n");
518 for (int i
= 0; i
< indent
; i
++)
519 str
<< wxT(' ') << wxT(' ');
520 ::OutputString(stream
, str
, NULL
, NULL
);
523 wxString
wxRichTextXMLHandler::AttributeToXML(const wxString
& str
)
531 for (i
= 0; i
< len
; i
++)
535 // Original code excluded "&" but we _do_ want to convert
536 // the ampersand beginning & because otherwise when read in,
537 // the original "&" becomes "&".
539 if (c
== wxT('<') || c
== wxT('>') || c
== wxT('"') ||
540 (c
== wxT('&') /* && (str.Mid(i+1, 4) != wxT("amp;")) */ ))
542 str1
+= str
.Mid(last
, i
- last
);
552 str1
+= wxT("&");
555 str1
+= wxT(""");
561 else if (wxUChar(c
) > 127)
563 str1
+= str
.Mid(last
, i
- last
);
565 wxString
s(wxT("&#"));
569 s
<< (int) wxUChar(c
);
576 str1
+= str
.Mid(last
, i
- last
);
580 #if wxRICHTEXT_HAVE_DIRECT_OUTPUT
582 static inline void AddAttribute(wxString
& str
, const wxChar
* name
, const int& v
)
584 str
<< wxT(" ") << name
<< wxT("=\"") << wxString::Format(wxT("%d"), v
) << wxT("\"");
587 static inline void AddAttribute(wxString
& str
, const wxChar
* name
, const long& v
)
589 str
<< wxT(" ") << name
<< wxT("=\"") << wxString::Format(wxT("%ld"), v
) << wxT("\"");
592 static inline void AddAttribute(wxString
& str
, const wxChar
* name
, const double& v
)
594 str
<< wxT(" ") << name
<< wxT("=\"") << wxString::Format(wxT("%.2f"), (float) v
) << wxT("\"");
597 static inline void AddAttribute(wxString
& str
, const wxChar
* name
, const wxChar
* s
)
599 str
<< wxT(" ") << name
<< wxT("=\"") << s
<< wxT("\"");
602 static inline void AddAttribute(wxString
& str
, const wxChar
* name
, const wxString
& s
)
604 str
<< wxT(" ") << name
<< wxT("=\"") << s
<< wxT("\"");
607 static inline void AddAttribute(wxString
& str
, const wxChar
* name
, const wxColour
& col
)
609 str
<< wxT(" ") << name
<< wxT("=\"") << wxT("#") << ColourToHexString(col
) << wxT("\"");
612 static inline void AddAttribute(wxString
& str
, const wxChar
* name
, const wxTextAttrDimension
& dim
)
616 wxString value
= MakeString(dim
.GetValue()) + wxT(",") + MakeString((int) dim
.GetFlags());
617 str
<< wxT(" ") << name
<< wxT("=\"");
623 static inline void AddAttribute(wxString
& str
, const wxString
& name
, const wxTextAttrDimension
& dim
)
625 AddAttribute(str
, name
.c_str(), dim
);
628 static inline void AddAttribute(wxString
& str
, const wxChar
* rootName
, const wxTextAttrDimensions
& dims
)
630 if (dims
.GetLeft().IsPresent())
631 AddAttribute(str
, rootName
+ wxString(wxT("-left")), dims
.GetLeft());
632 if (dims
.GetRight().IsPresent())
633 AddAttribute(str
, rootName
+ wxString(wxT("-right")), dims
.GetRight());
634 if (dims
.GetTop().IsPresent())
635 AddAttribute(str
, rootName
+ wxString(wxT("-top")), dims
.GetTop());
636 if (dims
.GetBottom().IsPresent())
637 AddAttribute(str
, rootName
+ wxString(wxT("-bottom")), dims
.GetBottom());
640 static inline void AddAttribute(wxString
& str
, const wxChar
* rootName
, const wxTextAttrBorder
& border
)
642 if (border
.HasStyle())
643 AddAttribute(str
, rootName
+ wxString(wxT("-style")), border
.GetStyle());
644 if (border
.HasColour())
645 AddAttribute(str
, rootName
+ wxString(wxT("-color")), border
.GetColour());
646 if (border
.HasWidth())
647 AddAttribute(str
, rootName
+ wxString(wxT("-width")), border
.GetWidth());
650 static inline void AddAttribute(wxString
& str
, const wxChar
* rootName
, const wxTextAttrBorders
& borders
)
652 AddAttribute(str
, rootName
+ wxString(wxT("-left")), borders
.GetLeft());
653 AddAttribute(str
, rootName
+ wxString(wxT("-right")), borders
.GetRight());
654 AddAttribute(str
, rootName
+ wxString(wxT("-top")), borders
.GetTop());
655 AddAttribute(str
, rootName
+ wxString(wxT("-bottom")), borders
.GetBottom());
659 // wxRICHTEXT_HAVE_DIRECT_OUTPUT
661 #if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
663 static inline void AddAttribute(wxXmlNode
* node
, const wxChar
* name
, const int& v
)
665 node
->AddAttribute(name
, MakeString(v
));
668 static inline void AddAttribute(wxXmlNode
* node
, const wxChar
* name
, const long& v
)
670 node
->AddAttribute(name
, MakeString(v
));
673 static inline void AddAttribute(wxXmlNode
* node
, const wxChar
* name
, const double& v
)
675 node
->AddAttribute(name
, MakeString(v
));
678 static inline void AddAttribute(wxXmlNode
* node
, const wxChar
* name
, const wxString
& s
)
680 node
->AddAttribute(name
, s
);
683 static inline void AddAttribute(wxXmlNode
* node
, const wxChar
* name
, const wxColour
& col
)
685 node
->AddAttribute(name
, MakeString(col
));
688 static inline void AddAttribute(wxXmlNode
* node
, const wxChar
* name
, const wxTextAttrDimension
& dim
)
692 wxString value
= MakeString(dim
.GetValue()) + wxT(",") + MakeString(dim
.GetFlags());
693 AddAttribute(node
, name
, value
);
697 static inline void AddAttribute(wxXmlNode
* node
, const wxChar
* rootName
, const wxTextAttrDimensions
& dims
)
699 if (dims
.GetLeft().IsPresent())
700 AddAttribute(node
, rootName
+ wxString(wxT("-left")), dims
.GetLeft());
701 if (dims
.GetRight().IsPresent())
702 AddAttribute(node
, rootName
+ wxString(wxT("-right")), dims
.GetRight());
703 if (dims
.GetTop().IsPresent())
704 AddAttribute(node
, rootName
+ wxString(wxT("-top")), dims
.GetTop());
705 if (dims
.GetBottom().IsPresent())
706 AddAttribute(node
, rootName
+ wxString(wxT("-bottom")), dims
.GetBottom());
709 static inline void AddAttribute(wxXmlNode
* node
, const wxChar
* rootName
, const wxTextAttrBorder
& border
)
711 if (border
.HasStyle())
712 AddAttribute(node
, rootName
+ wxString(wxT("-style")), border
.GetStyle());
713 if (border
.HasColour())
714 AddAttribute(node
, rootName
+ wxString(wxT("-color")), border
.GetColour());
715 if (border
.HasWidth())
716 AddAttribute(node
, rootName
+ wxString(wxT("-width")), border
.GetWidth());
719 static inline void AddAttribute(wxXmlNode
* node
, const wxChar
* rootName
, const wxTextAttrBorders
& borders
)
721 AddAttribute(node
, rootName
+ wxString(wxT("-left")), borders
.GetLeft());
722 AddAttribute(node
, rootName
+ wxString(wxT("-right")), borders
.GetRight());
723 AddAttribute(node
, rootName
+ wxString(wxT("-top")), borders
.GetTop());
724 AddAttribute(node
, rootName
+ wxString(wxT("-bottom")), borders
.GetBottom());
727 // wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
729 bool wxRichTextXMLHandler::DoSaveFile(wxRichTextBuffer
*buffer
, wxOutputStream
& stream
)
734 wxString
version(wxT("1.0") ) ;
736 bool deleteConvFile
= false;
737 wxString fileEncoding
;
738 //wxMBConv* convFile = NULL;
741 fileEncoding
= wxT("UTF-8");
742 m_convFile
= & wxConvUTF8
;
744 fileEncoding
= wxT("ISO-8859-1");
745 m_convFile
= & wxConvISO8859_1
;
748 // If SetEncoding has been called, change the output encoding.
749 if (!m_encoding
.empty() && m_encoding
.Lower() != fileEncoding
.Lower())
751 if (m_encoding
== wxT("<System>"))
754 fileEncoding
= wxLocale::GetSystemEncodingName();
755 // if !wxUSE_INTL, we fall back to UTF-8 or ISO-8859-1 below
760 fileEncoding
= m_encoding
;
763 // GetSystemEncodingName may not have returned a name
764 if (fileEncoding
.empty())
766 fileEncoding
= wxT("UTF-8");
768 fileEncoding
= wxT("ISO-8859-1");
770 m_convFile
= new wxCSConv(fileEncoding
);
771 deleteConvFile
= true;
774 #if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT && wxRICHTEXT_USE_XMLDOCUMENT_OUTPUT
775 #if wxRICHTEXT_USE_OUTPUT_TIMINGS
776 wxStopWatch stopwatch
;
778 wxXmlDocument
* doc
= new wxXmlDocument
;
779 doc
->SetFileEncoding(fileEncoding
);
781 wxXmlNode
* rootNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, wxT("richtext"));
782 doc
->SetRoot(rootNode
);
783 rootNode
->AddAttribute(wxT("version"), wxT("1.0.0.0"));
784 rootNode
->AddAttribute(wxT("xmlns"), wxT("http://www.wxwidgets.org"));
786 if (buffer
->GetStyleSheet() && (GetFlags() & wxRICHTEXT_HANDLER_INCLUDE_STYLESHEET
))
788 wxXmlNode
* styleSheetNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, wxT("stylesheet"));
789 rootNode
->AddChild(styleSheetNode
);
791 wxString nameAndDescr
;
793 if (!buffer
->GetStyleSheet()->GetName().empty())
794 styleSheetNode
->AddAttribute(wxT("name"), buffer
->GetStyleSheet()->GetName());
796 if (!buffer
->GetStyleSheet()->GetDescription().empty())
797 styleSheetNode
->AddAttribute(wxT("description"), buffer
->GetStyleSheet()->GetDescription());
800 for (i
= 0; i
< (int) buffer
->GetStyleSheet()->GetCharacterStyleCount(); i
++)
802 wxRichTextCharacterStyleDefinition
* def
= buffer
->GetStyleSheet()->GetCharacterStyle(i
);
803 ExportStyleDefinition(styleSheetNode
, def
);
806 for (i
= 0; i
< (int) buffer
->GetStyleSheet()->GetParagraphStyleCount(); i
++)
808 wxRichTextParagraphStyleDefinition
* def
= buffer
->GetStyleSheet()->GetParagraphStyle(i
);
809 ExportStyleDefinition(styleSheetNode
, def
);
812 for (i
= 0; i
< (int) buffer
->GetStyleSheet()->GetListStyleCount(); i
++)
814 wxRichTextListStyleDefinition
* def
= buffer
->GetStyleSheet()->GetListStyle(i
);
815 ExportStyleDefinition(styleSheetNode
, def
);
818 bool success
= ExportXML(rootNode
, *buffer
);
819 #if wxRICHTEXT_USE_OUTPUT_TIMINGS
820 long t
= stopwatch
.Time();
821 wxLogDebug(wxT("Creating the document took %ldms"), t
);
822 wxMessageBox(wxString::Format(wxT("Creating the document took %ldms"), t
));
826 #if wxRICHTEXT_USE_OUTPUT_TIMINGS
829 success
= doc
->Save(stream
);
830 #if wxRICHTEXT_USE_OUTPUT_TIMINGS
832 wxLogDebug(wxT("Save() took %ldms"), t2
);
833 wxMessageBox(wxString::Format(wxT("Save() took %ldms"), t2
));
840 // !(wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT && wxRICHTEXT_USE_XMLDOCUMENT_OUTPUT)
843 m_convMem
= wxConvCurrent
;
849 s
.Printf(wxT("<?xml version=\"%s\" encoding=\"%s\"?>\n"),
850 version
, fileEncoding
);
851 OutputString(stream
, s
);
852 OutputString(stream
, wxT("<richtext version=\"1.0.0.0\" xmlns=\"http://www.wxwidgets.org\">"));
856 if (buffer
->GetStyleSheet() && (GetFlags() & wxRICHTEXT_HANDLER_INCLUDE_STYLESHEET
))
858 OutputIndentation(stream
, level
);
859 wxString nameAndDescr
;
860 if (!buffer
->GetStyleSheet()->GetName().empty())
861 nameAndDescr
<< wxT(" name=\"") << buffer
->GetStyleSheet()->GetName() << wxT("\"");
862 if (!buffer
->GetStyleSheet()->GetDescription().empty())
863 nameAndDescr
<< wxT(" description=\"") << buffer
->GetStyleSheet()->GetDescription() << wxT("\"");
864 OutputString(stream
, wxString(wxT("<stylesheet")) + nameAndDescr
+ wxT(">"));
868 for (i
= 0; i
< (int) buffer
->GetStyleSheet()->GetCharacterStyleCount(); i
++)
870 wxRichTextCharacterStyleDefinition
* def
= buffer
->GetStyleSheet()->GetCharacterStyle(i
);
871 ExportStyleDefinition(stream
, def
, level
+ 1);
874 for (i
= 0; i
< (int) buffer
->GetStyleSheet()->GetParagraphStyleCount(); i
++)
876 wxRichTextParagraphStyleDefinition
* def
= buffer
->GetStyleSheet()->GetParagraphStyle(i
);
877 ExportStyleDefinition(stream
, def
, level
+ 1);
880 for (i
= 0; i
< (int) buffer
->GetStyleSheet()->GetListStyleCount(); i
++)
882 wxRichTextListStyleDefinition
* def
= buffer
->GetStyleSheet()->GetListStyle(i
);
883 ExportStyleDefinition(stream
, def
, level
+ 1);
886 OutputIndentation(stream
, level
);
887 OutputString(stream
, wxT("</stylesheet>"));
891 bool success
= ExportXML(stream
, *buffer
, level
);
893 OutputString(stream
, wxT("\n</richtext>"));
894 OutputString(stream
, wxT("\n"));
905 #if wxRICHTEXT_HAVE_DIRECT_OUTPUT
907 /// Recursively export an object
908 bool wxRichTextXMLHandler::ExportXML(wxOutputStream
& stream
, wxRichTextObject
& obj
, int indent
)
910 obj
.ExportXML(stream
, indent
, this);
915 bool wxRichTextXMLHandler::ExportStyleDefinition(wxOutputStream
& stream
, wxRichTextStyleDefinition
* def
, int level
)
917 wxRichTextCharacterStyleDefinition
* charDef
= wxDynamicCast(def
, wxRichTextCharacterStyleDefinition
);
918 wxRichTextParagraphStyleDefinition
* paraDef
= wxDynamicCast(def
, wxRichTextParagraphStyleDefinition
);
919 wxRichTextListStyleDefinition
* listDef
= wxDynamicCast(def
, wxRichTextListStyleDefinition
);
921 wxString baseStyle
= def
->GetBaseStyle();
922 wxString baseStyleProp
;
923 if (!baseStyle
.empty())
924 baseStyleProp
= wxT(" basestyle=\"") + baseStyle
+ wxT("\"");
926 wxString descr
= def
->GetDescription();
929 descrProp
= wxT(" description=\"") + descr
+ wxT("\"");
933 OutputIndentation(stream
, level
);
934 OutputString(stream
, wxT("<characterstyle") + baseStyleProp
+ descrProp
+ wxT(">"));
938 wxString style
= AddAttributes(def
->GetStyle(), false);
940 OutputIndentation(stream
, level
);
941 OutputString(stream
, wxT("<style ") + style
+ wxT(">"));
943 OutputIndentation(stream
, level
);
944 OutputString(stream
, wxT("</style>"));
948 OutputIndentation(stream
, level
);
949 OutputString(stream
, wxT("</characterstyle>"));
953 OutputIndentation(stream
, level
);
955 if (!listDef
->GetNextStyle().empty())
956 baseStyleProp
<< wxT(" nextstyle=\"") << listDef
->GetNextStyle() << wxT("\"");
958 OutputString(stream
, wxT("<liststyle") + baseStyleProp
+ descrProp
+ wxT(">"));
962 wxString style
= AddAttributes(def
->GetStyle(), true);
964 OutputIndentation(stream
, level
);
965 OutputString(stream
, wxT("<style ") + style
+ wxT(">"));
967 OutputIndentation(stream
, level
);
968 OutputString(stream
, wxT("</style>"));
971 for (i
= 0; i
< 10; i
++)
973 wxRichTextAttr
* levelAttr
= listDef
->GetLevelAttributes(i
);
976 wxString style
= AddAttributes(def
->GetStyle(), true);
977 wxString levelStr
= wxString::Format(wxT(" level=\"%d\" "), (i
+1));
979 OutputIndentation(stream
, level
);
980 OutputString(stream
, wxT("<style ") + levelStr
+ style
+ wxT(">"));
982 OutputIndentation(stream
, level
);
983 OutputString(stream
, wxT("</style>"));
989 OutputIndentation(stream
, level
);
990 OutputString(stream
, wxT("</liststyle>"));
994 OutputIndentation(stream
, level
);
996 if (!paraDef
->GetNextStyle().empty())
997 baseStyleProp
<< wxT(" nextstyle=\"") << paraDef
->GetNextStyle() << wxT("\"");
999 OutputString(stream
, wxT("<paragraphstyle") + baseStyleProp
+ descrProp
+ wxT(">"));
1003 wxString style
= AddAttributes(def
->GetStyle(), false);
1005 OutputIndentation(stream
, level
);
1006 OutputString(stream
, wxT("<style ") + style
+ wxT(">"));
1008 OutputIndentation(stream
, level
);
1009 OutputString(stream
, wxT("</style>"));
1013 OutputIndentation(stream
, level
);
1014 OutputString(stream
, wxT("</paragraphstyle>"));
1020 /// Create a string containing style attributes
1021 wxString
wxRichTextXMLHandler::AddAttributes(const wxRichTextAttr
& attr
, bool isPara
)
1024 if (attr
.HasTextColour() && attr
.GetTextColour().Ok())
1025 AddAttribute(str
, wxT("textcolor"), attr
.GetTextColour());
1027 if (attr
.HasBackgroundColour() && attr
.GetBackgroundColour().Ok())
1028 AddAttribute(str
, wxT("bgcolor"), attr
.GetBackgroundColour());
1030 if (attr
.HasFontSize())
1031 AddAttribute(str
, wxT("fontsize"), attr
.GetFontSize());
1033 if (attr
.HasFontFamily())
1034 AddAttribute(str
, wxT("fontfamily"), attr
.GetFontFamily());
1036 if (attr
.HasFontItalic())
1037 AddAttribute(str
, wxT("fontstyle"), attr
.GetFontStyle());
1039 if (attr
.HasFontWeight())
1040 AddAttribute(str
, wxT("fontweight"), attr
.GetFontWeight());
1042 if (attr
.HasFontUnderlined())
1043 AddAttribute(str
, wxT("fontunderlined"), (int) attr
.GetFontUnderlined());
1045 if (attr
.HasFontFaceName())
1046 AddAttribute(str
, wxT("fontface"), attr
.GetFontFaceName());
1048 if (attr
.HasTextEffects())
1050 AddAttribute(str
, wxT("texteffects"), attr
.GetTextEffects());
1051 AddAttribute(str
, wxT("texteffectflags"), attr
.GetTextEffectFlags());
1054 if (!attr
.GetCharacterStyleName().empty())
1055 AddAttribute(str
, wxT("characterstyle"), attr
.GetCharacterStyleName());
1058 AddAttribute(str
, wxT("url"), AttributeToXML(attr
.GetURL()));
1062 if (attr
.HasAlignment())
1063 AddAttribute(str
, wxT("alignment"), (int) attr
.GetAlignment());
1065 if (attr
.HasLeftIndent())
1067 AddAttribute(str
, wxT("leftindent"), (int) attr
.GetLeftIndent());
1068 AddAttribute(str
, wxT("leftsubindent"), (int) attr
.GetLeftSubIndent());
1071 if (attr
.HasRightIndent())
1072 AddAttribute(str
, wxT("rightindent"), (int) attr
.GetRightIndent());
1074 if (attr
.HasParagraphSpacingAfter())
1075 AddAttribute(str
, wxT("parspacingafter"), (int) attr
.GetParagraphSpacingAfter());
1077 if (attr
.HasParagraphSpacingBefore())
1078 AddAttribute(str
, wxT("parspacingbefore"), (int) attr
.GetParagraphSpacingBefore());
1080 if (attr
.HasLineSpacing())
1081 AddAttribute(str
, wxT("linespacing"), (int) attr
.GetLineSpacing());
1083 if (attr
.HasBulletStyle())
1084 AddAttribute(str
, wxT("bulletstyle"), (int) attr
.GetBulletStyle());
1086 if (attr
.HasBulletNumber())
1087 AddAttribute(str
, wxT("bulletnumber"), (int) attr
.GetBulletNumber());
1089 if (attr
.HasBulletText())
1091 // If using a bullet symbol, convert to integer in case it's a non-XML-friendly character.
1092 // Otherwise, assume it's XML-friendly text such as outline numbering, e.g. 1.2.3.1
1093 if (!attr
.GetBulletText().empty() && (attr
.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_SYMBOL
))
1094 AddAttribute(str
, wxT("bulletsymbol"), (int) (attr
.GetBulletText()[0]));
1096 AddAttribute(str
, wxT("bullettext"), attr
.GetBulletText());
1098 AddAttribute(str
, wxT("bulletfont"), attr
.GetBulletFont());
1101 if (attr
.HasBulletName())
1102 AddAttribute(str
, wxT("bulletname"), attr
.GetBulletName());
1104 if (!attr
.GetParagraphStyleName().empty())
1105 AddAttribute(str
, wxT("parstyle"), attr
.GetParagraphStyleName());
1107 if (!attr
.GetListStyleName().empty())
1108 AddAttribute(str
, wxT("liststyle"), attr
.GetListStyleName());
1114 for (i
= 0; i
< attr
.GetTabs().GetCount(); i
++)
1116 if (i
> 0) strTabs
<< wxT(",");
1117 strTabs
<< attr
.GetTabs()[i
];
1119 AddAttribute(str
, wxT("tabs"), strTabs
);
1122 if (attr
.HasPageBreak())
1124 AddAttribute(str
, wxT("pagebreak"), 1);
1127 if (attr
.HasOutlineLevel())
1128 AddAttribute(str
, wxT("outlinelevel"), (int) attr
.GetOutlineLevel());
1131 AddAttribute(str
, wxT("margin"), attr
.GetTextBoxAttr().GetMargins());
1132 AddAttribute(str
, wxT("padding"), attr
.GetTextBoxAttr().GetPadding());
1133 AddAttribute(str
, wxT("position"), attr
.GetTextBoxAttr().GetPosition());
1134 AddAttribute(str
, wxT("border"), attr
.GetTextBoxAttr().GetBorder());
1135 AddAttribute(str
, wxT("outline"), attr
.GetTextBoxAttr().GetOutline());
1136 AddAttribute(str
, wxT("width"), attr
.GetTextBoxAttr().GetWidth());
1137 AddAttribute(str
, wxT("height"), attr
.GetTextBoxAttr().GetWidth());
1139 if (attr
.GetTextBoxAttr().HasFloatMode())
1142 if (attr
.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_LEFT
)
1143 value
= wxT("left");
1144 else if (attr
.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_RIGHT
)
1145 value
= wxT("right");
1147 value
= wxT("none");
1148 AddAttribute(str
, wxT("float"), value
);
1151 if (attr
.GetTextBoxAttr().HasClearMode())
1154 if (attr
.GetTextBoxAttr().GetClearMode() == wxTEXT_BOX_ATTR_CLEAR_LEFT
)
1155 value
= wxT("left");
1156 else if (attr
.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_CLEAR_RIGHT
)
1157 value
= wxT("right");
1158 else if (attr
.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_CLEAR_BOTH
)
1159 value
= wxT("both");
1161 value
= wxT("none");
1162 AddAttribute(str
, wxT("clear"), value
);
1165 if (attr
.GetTextBoxAttr().HasCollapseBorders())
1166 AddAttribute(str
, wxT("collapse-borders"), (int) attr
.GetTextBoxAttr().GetCollapseBorders());
1171 // Make a string from the given property. This can be overridden for custom variants.
1172 wxString
wxRichTextXMLHandler::MakeStringFromProperty(const wxVariant
& var
)
1174 return var
.MakeString();
1177 // Create a proprty from the string read from the XML file.
1178 wxVariant
wxRichTextXMLHandler::MakePropertyFromString(const wxString
& name
, const wxString
& value
, const wxString
& WXUNUSED(type
))
1180 wxVariant
var(value
, name
);
1181 // TODO: use type to create using common types
1185 // Write the properties
1186 bool wxRichTextXMLHandler::WriteProperties(wxOutputStream
& stream
, const wxRichTextProperties
& properties
, int level
)
1188 if (properties
.GetCount() > 0)
1192 OutputIndentation(stream
, level
);
1193 OutputString(stream
, wxT("<properties"));
1198 for (i
= 0; i
< properties
.GetCount(); i
++)
1200 const wxVariant
& var
= properties
[i
];
1203 const wxString
& name
= var
.GetName();
1204 wxString value
= MakeStringFromProperty(var
);
1206 OutputIndentation(stream
, level
);
1207 OutputString(stream
, wxT("<property name=\"") + name
+
1208 wxT("\" type=\"") + var
.GetType() + wxT("\" value=\""));
1209 OutputStringEnt(stream
, value
);
1210 OutputString(stream
, wxT("\"/>\n"));
1216 OutputIndentation(stream
, level
);
1217 OutputString(stream
, wxT("</properties>\n"));
1227 // wxRICHTEXT_HAVE_DIRECT_OUTPUT
1229 #if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
1230 bool wxRichTextXMLHandler::ExportXML(wxXmlNode
* parent
, wxRichTextObject
& obj
)
1232 obj
.ExportXML(parent
, this);
1237 bool wxRichTextXMLHandler::ExportStyleDefinition(wxXmlNode
* parent
, wxRichTextStyleDefinition
* def
)
1239 wxRichTextCharacterStyleDefinition
* charDef
= wxDynamicCast(def
, wxRichTextCharacterStyleDefinition
);
1240 wxRichTextParagraphStyleDefinition
* paraDef
= wxDynamicCast(def
, wxRichTextParagraphStyleDefinition
);
1241 wxRichTextListStyleDefinition
* listDef
= wxDynamicCast(def
, wxRichTextListStyleDefinition
);
1243 wxString baseStyle
= def
->GetBaseStyle();
1244 wxString descr
= def
->GetDescription();
1246 wxXmlNode
* defNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, wxEmptyString
);
1247 parent
->AddChild(defNode
);
1248 if (!baseStyle
.empty())
1249 defNode
->AddAttribute(wxT("basestyle"), baseStyle
);
1251 defNode
->AddAttribute(wxT("description"), descr
);
1253 wxXmlNode
* styleNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, wxT("style"));
1254 defNode
->AddChild(styleNode
);
1258 defNode
->SetName(wxT("characterstyle"));
1259 AddAttributes(styleNode
, def
->GetStyle(), false);
1263 defNode
->SetName(wxT("liststyle"));
1265 if (!listDef
->GetNextStyle().empty())
1266 defNode
->AddAttribute(wxT("nextstyle"), listDef
->GetNextStyle());
1268 AddAttributes(styleNode
, def
->GetStyle(), true);
1271 for (i
= 0; i
< 10; i
++)
1273 wxRichTextAttr
* levelAttr
= listDef
->GetLevelAttributes(i
);
1276 wxXmlNode
* levelNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, wxT("style"));
1277 defNode
->AddChild(levelNode
);
1278 levelNode
->AddAttribute(wxT("level"), MakeString(i
+1));
1279 AddAttributes(levelNode
, * levelAttr
, true);
1285 defNode
->SetName(wxT("paragraphstyle"));
1287 if (!paraDef
->GetNextStyle().empty())
1288 defNode
->AddAttribute(wxT("nextstyle"), paraDef
->GetNextStyle());
1290 AddAttributes(styleNode
, def
->GetStyle(), true);
1296 bool wxRichTextXMLHandler::AddAttributes(wxXmlNode
* node
, wxRichTextAttr
& attr
, bool isPara
)
1298 if (attr
.HasTextColour() && attr
.GetTextColour().Ok())
1299 node
->AddAttribute(wxT("textcolor"), MakeString(attr
.GetTextColour()));
1300 if (attr
.HasBackgroundColour() && attr
.GetBackgroundColour().Ok())
1301 node
->AddAttribute(wxT("bgcolor"), MakeString(attr
.GetBackgroundColour()));
1303 if (attr
.HasFontSize())
1304 node
->AddAttribute(wxT("fontsize"), MakeString(attr
.GetFontSize()));
1305 if (attr
.HasFontFamily())
1306 node
->AddAttribute(wxT("fontfamily"), MakeString(attr
.GetFontFamily()));
1307 if (attr
.HasFontItalic())
1308 node
->AddAttribute(wxT("fontstyle"), MakeString(attr
.GetFontStyle()));
1309 if (attr
.HasFontWeight())
1310 node
->AddAttribute(wxT("fontweight"), MakeString(attr
.GetFontWeight()));
1311 if (attr
.HasFontUnderlined())
1312 node
->AddAttribute(wxT("fontunderlined"), MakeString((int) attr
.GetFontUnderlined()));
1313 if (attr
.HasFontFaceName())
1314 node
->AddAttribute(wxT("fontface"), attr
.GetFontFaceName());
1316 if (attr
.HasTextEffects())
1318 node
->AddAttribute(wxT("texteffects"), MakeString(attr
.GetTextEffects()));
1319 node
->AddAttribute(wxT("texteffectflags"), MakeString(attr
.GetTextEffectFlags()));
1321 if (attr
.HasCharacterStyleName() && !attr
.GetCharacterStyleName().empty())
1322 node
->AddAttribute(wxT("characterstyle"), attr
.GetCharacterStyleName());
1325 node
->AddAttribute(wxT("url"), attr
.GetURL()); // TODO: do we need to wrap this in AttributeToXML?
1329 if (attr
.HasAlignment())
1330 node
->AddAttribute(wxT("alignment"), MakeString((int) attr
.GetAlignment()));
1332 if (attr
.HasLeftIndent())
1334 node
->AddAttribute(wxT("leftindent"), MakeString((int) attr
.GetLeftIndent()));
1335 node
->AddAttribute(wxT("leftsubindent"), MakeString((int) attr
.GetLeftSubIndent()));
1338 if (attr
.HasRightIndent())
1339 node
->AddAttribute(wxT("rightindent"), MakeString((int) attr
.GetRightIndent()));
1341 if (attr
.HasParagraphSpacingAfter())
1342 node
->AddAttribute(wxT("parspacingafter"), MakeString((int) attr
.GetParagraphSpacingAfter()));
1344 if (attr
.HasParagraphSpacingBefore())
1345 node
->AddAttribute(wxT("parspacingbefore"), MakeString((int) attr
.GetParagraphSpacingBefore()));
1347 if (attr
.HasLineSpacing())
1348 node
->AddAttribute(wxT("linespacing"), MakeString((int) attr
.GetLineSpacing()));
1350 if (attr
.HasBulletStyle())
1351 node
->AddAttribute(wxT("bulletstyle"), MakeString((int) attr
.GetBulletStyle()));
1353 if (attr
.HasBulletNumber())
1354 node
->AddAttribute(wxT("bulletnumber"), MakeString((int) attr
.GetBulletNumber()));
1356 if (attr
.HasBulletText())
1358 // If using a bullet symbol, convert to integer in case it's a non-XML-friendly character.
1359 // Otherwise, assume it's XML-friendly text such as outline numbering, e.g. 1.2.3.1
1360 if (!attr
.GetBulletText().empty() && (attr
.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_SYMBOL
))
1361 node
->AddAttribute(wxT("bulletsymbol"), MakeString((int) (attr
.GetBulletText()[0])));
1363 node
->AddAttribute(wxT("bullettext"), attr
.GetBulletText());
1365 if (!attr
.GetBulletFont().empty())
1366 node
->AddAttribute(wxT("bulletfont"), attr
.GetBulletFont());
1369 if (attr
.HasBulletName())
1370 node
->AddAttribute(wxT("bulletname"), attr
.GetBulletName());
1372 if (!attr
.GetParagraphStyleName().empty())
1373 node
->AddAttribute(wxT("parstyle"), attr
.GetParagraphStyleName());
1375 if (!attr
.GetListStyleName().empty())
1376 node
->AddAttribute(wxT("liststyle"), attr
.GetListStyleName());
1382 for (i
= 0; i
< attr
.GetTabs().GetCount(); i
++)
1386 tabs
<< attr
.GetTabs()[i
];
1388 node
->AddAttribute(wxT("tabs"), tabs
);
1391 if (attr
.HasPageBreak())
1392 node
->AddAttribute(wxT("pagebreak"), wxT("1"));
1394 if (attr
.HasOutlineLevel())
1395 node
->AddAttribute(wxT("outlinelevel"), MakeString((int) attr
.GetOutlineLevel()));
1398 AddAttribute(node
, wxT("margin"), attr
.GetTextBoxAttr().GetMargins());
1399 AddAttribute(node
, wxT("padding"), attr
.GetTextBoxAttr().GetPadding());
1400 AddAttribute(node
, wxT("position"), attr
.GetTextBoxAttr().GetPosition());
1401 AddAttribute(node
, wxT("border"), attr
.GetTextBoxAttr().GetBorder());
1402 AddAttribute(node
, wxT("outline"), attr
.GetTextBoxAttr().GetOutline());
1403 AddAttribute(node
, wxT("width"), attr
.GetTextBoxAttr().GetWidth());
1404 AddAttribute(node
, wxT("height"), attr
.GetTextBoxAttr().GetWidth());
1406 if (attr
.GetTextBoxAttr().HasFloatMode())
1409 if (attr
.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_LEFT
)
1410 value
= wxT("left");
1411 else if (attr
.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_RIGHT
)
1412 value
= wxT("right");
1414 value
= wxT("none");
1415 AddAttribute(node
, wxT("float"), value
);
1418 if (attr
.GetTextBoxAttr().HasClearMode())
1421 if (attr
.GetTextBoxAttr().GetClearMode() == wxTEXT_BOX_ATTR_CLEAR_LEFT
)
1422 value
= wxT("left");
1423 else if (attr
.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_CLEAR_RIGHT
)
1424 value
= wxT("right");
1425 else if (attr
.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_CLEAR_BOTH
)
1426 value
= wxT("both");
1428 value
= wxT("none");
1429 AddAttribute(node
, wxT("clear"), value
);
1432 if (attr
.GetTextBoxAttr().HasCollapseBorders())
1433 AddAttribute(node
, wxT("collapse-borders"), (int) attr
.GetTextBoxAttr().GetCollapseBorders());
1438 bool wxRichTextXMLHandler::WriteProperties(wxXmlNode
* node
, const wxRichTextProperties
& properties
)
1440 if (properties
.GetCount() > 0)
1442 wxXmlNode
* propertiesNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, wxT("properties"));
1443 node
->AddChild(propertiesNode
);
1445 for (i
= 0; i
< properties
.GetCount(); i
++)
1447 const wxVariant
& var
= properties
[i
];
1450 wxXmlNode
* propertyNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, wxT("property"));
1451 propertiesNode
->AddChild(propertyNode
);
1453 const wxString
& name
= var
.GetName();
1454 wxString value
= MakeStringFromProperty(var
);
1456 AddAttribute(propertyNode
, wxT("name"), name
);
1457 AddAttribute(propertyNode
, wxT("type"), var
.GetType());
1458 AddAttribute(propertyNode
, wxT("value"), value
);
1466 // wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
1468 /// Replace face name with current name for platform.
1469 /// TODO: introduce a virtual function or settable table to
1470 /// do this comprehensively.
1471 bool wxRichTextFixFaceName(wxString
& facename
)
1473 if (facename
.empty())
1477 if (facename
== wxT("Times"))
1479 facename
= wxT("Times New Roman");
1482 else if (facename
== wxT("Helvetica"))
1484 facename
= wxT("Arial");
1487 else if (facename
== wxT("Courier"))
1489 facename
= wxT("Courier New");
1495 if (facename
== wxT("Times New Roman"))
1497 facename
= wxT("Times");
1500 else if (facename
== wxT("Arial"))
1502 facename
= wxT("Helvetica");
1505 else if (facename
== wxT("Courier New"))
1507 facename
= wxT("Courier");
1515 static inline long wxRichTextColourStringToLong(const wxString
& colStr
)
1517 if (!colStr
.IsEmpty())
1519 wxColour
col(colStr
);
1520 return col
.GetRGB();
1526 static inline wxTextAttrDimension
wxRichTextParseDimension(const wxString
& dimStr
)
1528 wxString valuePart
= dimStr
.BeforeFirst(wxT(','));
1530 if (dimStr
.Contains(wxT(",")))
1531 flagsPart
= dimStr
.AfterFirst(wxT(','));
1532 wxTextAttrDimension dim
;
1533 dim
.SetValue(wxAtoi(valuePart
));
1534 dim
.SetFlags(wxAtoi(flagsPart
));
1539 /// Import style parameters
1540 bool wxRichTextXMLHandler::ImportStyle(wxRichTextAttr
& attr
, wxXmlNode
* node
, bool isPara
)
1542 wxXmlAttribute
* xmlAttr
= node
->GetAttributes();
1546 const wxString
& name
= xmlAttr
->GetName();
1547 const wxString
& value
= xmlAttr
->GetValue();
1550 if (name
== wxT("fontface"))
1555 if (GetFlags() & wxRICHTEXT_HANDLER_CONVERT_FACENAMES
)
1556 wxRichTextFixFaceName(v
);
1557 attr
.SetFontFaceName(v
);
1560 else if (name
== wxT("fontfamily"))
1563 attr
.SetFontFamily((wxFontFamily
)wxAtoi(value
));
1565 else if (name
== wxT("fontstyle"))
1568 attr
.SetFontStyle((wxFontStyle
)wxAtoi(value
));
1570 else if (name
== wxT("fontsize"))
1573 attr
.SetFontSize(wxAtoi(value
));
1575 else if (name
== wxT("fontweight"))
1578 attr
.SetFontWeight((wxFontWeight
) wxAtoi(value
));
1580 else if (name
== wxT("fontunderlined"))
1583 attr
.SetFontUnderlined(wxAtoi(value
) != 0);
1585 else if (name
== wxT("textcolor"))
1589 if (value
[0] == wxT('#'))
1590 attr
.SetTextColour(HexStringToColour(value
.Mid(1)));
1592 attr
.SetTextColour(value
);
1595 else if (name
== wxT("bgcolor"))
1599 if (value
[0] == wxT('#'))
1600 attr
.SetBackgroundColour(HexStringToColour(value
.Mid(1)));
1602 attr
.SetBackgroundColour(value
);
1605 else if (name
== wxT("characterstyle"))
1608 attr
.SetCharacterStyleName(value
);
1610 else if (name
== wxT("texteffects"))
1613 attr
.SetTextEffects(wxAtoi(value
));
1615 else if (name
== wxT("texteffectflags"))
1618 attr
.SetTextEffectFlags(wxAtoi(value
));
1620 else if (name
== wxT("url"))
1627 if (name
== wxT("alignment"))
1630 attr
.SetAlignment((wxTextAttrAlignment
) wxAtoi(value
));
1632 else if (name
== wxT("leftindent"))
1635 attr
.SetLeftIndent(wxAtoi(value
), attr
.GetLeftSubIndent());
1637 else if (name
== wxT("leftsubindent"))
1640 attr
.SetLeftIndent(attr
.GetLeftIndent(), wxAtoi(value
));
1642 else if (name
== wxT("rightindent"))
1645 attr
.SetRightIndent(wxAtoi(value
));
1647 else if (name
== wxT("parspacingbefore"))
1650 attr
.SetParagraphSpacingBefore(wxAtoi(value
));
1652 else if (name
== wxT("parspacingafter"))
1655 attr
.SetParagraphSpacingAfter(wxAtoi(value
));
1657 else if (name
== wxT("linespacing"))
1660 attr
.SetLineSpacing(wxAtoi(value
));
1662 else if (name
== wxT("bulletstyle"))
1665 attr
.SetBulletStyle(wxAtoi(value
));
1667 else if (name
== wxT("bulletnumber"))
1670 attr
.SetBulletNumber(wxAtoi(value
));
1672 else if (name
== wxT("bulletsymbol"))
1676 wxChar ch
= wxAtoi(value
);
1679 attr
.SetBulletText(s
);
1682 else if (name
== wxT("bullettext"))
1686 attr
.SetBulletText(value
);
1689 else if (name
== wxT("bulletfont"))
1693 attr
.SetBulletFont(value
);
1696 else if (name
== wxT("bulletname"))
1700 attr
.SetBulletName(value
);
1703 else if (name
== wxT("parstyle"))
1707 attr
.SetParagraphStyleName(value
);
1710 else if (name
== wxT("liststyle"))
1714 attr
.SetListStyleName(value
);
1717 else if (name
== wxT("tabs"))
1722 wxStringTokenizer
tkz(value
, wxT(","));
1723 while (tkz
.HasMoreTokens())
1725 wxString token
= tkz
.GetNextToken();
1726 tabs
.Add(wxAtoi(token
));
1731 else if (name
== wxT("pagebreak"))
1735 attr
.SetPageBreak(wxAtoi(value
) != 0);
1738 else if (name
== wxT("outlinelevel"))
1742 attr
.SetOutlineLevel(wxAtoi(value
));
1755 if (name
== wxT("width"))
1757 attr
.GetTextBoxAttr().GetWidth().SetValue(wxRichTextParseDimension(value
));
1759 else if (name
== wxT("height"))
1761 attr
.GetTextBoxAttr().GetHeight().SetValue(wxRichTextParseDimension(value
));
1764 else if (name
== wxT("float"))
1766 if (value
== wxT("left"))
1767 attr
.GetTextBoxAttr().SetFloatMode(wxTEXT_BOX_ATTR_FLOAT_LEFT
);
1768 else if (value
== wxT("right"))
1769 attr
.GetTextBoxAttr().SetFloatMode(wxTEXT_BOX_ATTR_FLOAT_RIGHT
);
1770 else if (value
== wxT("none"))
1771 attr
.GetTextBoxAttr().SetFloatMode(wxTEXT_BOX_ATTR_FLOAT_NONE
);
1773 else if (name
== wxT("clear"))
1775 if (value
== wxT("left"))
1776 attr
.GetTextBoxAttr().SetClearMode(wxTEXT_BOX_ATTR_CLEAR_LEFT
);
1777 else if (value
== wxT("right"))
1778 attr
.GetTextBoxAttr().SetClearMode(wxTEXT_BOX_ATTR_CLEAR_RIGHT
);
1779 else if (value
== wxT("both"))
1780 attr
.GetTextBoxAttr().SetClearMode(wxTEXT_BOX_ATTR_CLEAR_BOTH
);
1781 else if (value
== wxT("none"))
1782 attr
.GetTextBoxAttr().SetClearMode(wxTEXT_BOX_ATTR_CLEAR_NONE
);
1784 else if (name
== wxT("collapse-borders"))
1785 attr
.GetTextBoxAttr().SetCollapseBorders(value
== wxT("1"));
1787 else if (name
.Contains(wxT("border-")))
1789 if (name
== wxT("border-left-style"))
1790 attr
.GetTextBoxAttr().GetBorder().GetLeft().SetStyle(wxAtoi(value
));
1791 else if (name
== wxT("border-right-style"))
1792 attr
.GetTextBoxAttr().GetBorder().GetRight().SetStyle(wxAtoi(value
));
1793 else if (name
== wxT("border-top-style"))
1794 attr
.GetTextBoxAttr().GetBorder().GetTop().SetStyle(wxAtoi(value
));
1795 else if (name
== wxT("border-bottom-style"))
1796 attr
.GetTextBoxAttr().GetBorder().GetBottom().SetStyle(wxAtoi(value
));
1798 else if (name
== wxT("border-left-colour"))
1799 attr
.GetTextBoxAttr().GetBorder().GetLeft().SetColour(wxRichTextColourStringToLong(value
));
1800 else if (name
== wxT("border-right-colour"))
1801 attr
.GetTextBoxAttr().GetBorder().GetRight().SetColour(wxRichTextColourStringToLong(value
));
1802 else if (name
== wxT("border-top-colour"))
1803 attr
.GetTextBoxAttr().GetBorder().GetTop().SetColour(wxRichTextColourStringToLong(value
));
1804 else if (name
== wxT("border-bottom-colour"))
1805 attr
.GetTextBoxAttr().GetBorder().GetBottom().SetColour(wxRichTextColourStringToLong(value
));
1807 else if (name
== wxT("border-left-width"))
1808 attr
.GetTextBoxAttr().GetBorder().GetLeft().SetWidth(wxRichTextParseDimension(value
));
1809 else if (name
== wxT("border-right-width"))
1810 attr
.GetTextBoxAttr().GetBorder().GetRight().SetWidth(wxRichTextParseDimension(value
));
1811 else if (name
== wxT("border-top-width"))
1812 attr
.GetTextBoxAttr().GetBorder().GetTop().SetWidth(wxRichTextParseDimension(value
));
1813 else if (name
== wxT("border-bottom-width"))
1814 attr
.GetTextBoxAttr().GetBorder().GetBottom().SetWidth(wxRichTextParseDimension(value
));
1816 else if (name
.Contains(wxT("outline-")))
1818 if (name
== wxT("outline-left-style"))
1819 attr
.GetTextBoxAttr().GetOutline().GetLeft().SetStyle(wxAtoi(value
));
1820 else if (name
== wxT("outline-right-style"))
1821 attr
.GetTextBoxAttr().GetOutline().GetRight().SetStyle(wxAtoi(value
));
1822 else if (name
== wxT("outline-top-style"))
1823 attr
.GetTextBoxAttr().GetOutline().GetTop().SetStyle(wxAtoi(value
));
1824 else if (name
== wxT("outline-bottom-style"))
1825 attr
.GetTextBoxAttr().GetOutline().GetBottom().SetStyle(wxAtoi(value
));
1827 else if (name
== wxT("outline-left-colour"))
1828 attr
.GetTextBoxAttr().GetOutline().GetLeft().SetColour(wxRichTextColourStringToLong(value
));
1829 else if (name
== wxT("outline-right-colour"))
1830 attr
.GetTextBoxAttr().GetOutline().GetRight().SetColour(wxRichTextColourStringToLong(value
));
1831 else if (name
== wxT("outline-top-colour"))
1832 attr
.GetTextBoxAttr().GetOutline().GetTop().SetColour(wxRichTextColourStringToLong(value
));
1833 else if (name
== wxT("outline-bottom-colour"))
1834 attr
.GetTextBoxAttr().GetOutline().GetBottom().SetColour(wxRichTextColourStringToLong(value
));
1836 else if (name
== wxT("outline-left-width"))
1837 attr
.GetTextBoxAttr().GetOutline().GetLeft().SetWidth(wxRichTextParseDimension(value
));
1838 else if (name
== wxT("outline-right-width"))
1839 attr
.GetTextBoxAttr().GetOutline().GetRight().SetWidth(wxRichTextParseDimension(value
));
1840 else if (name
== wxT("outline-top-width"))
1841 attr
.GetTextBoxAttr().GetOutline().GetTop().SetWidth(wxRichTextParseDimension(value
));
1842 else if (name
== wxT("outline-bottom-width"))
1843 attr
.GetTextBoxAttr().GetOutline().GetBottom().SetWidth(wxRichTextParseDimension(value
));
1845 else if (name
.Contains(wxT("margin-")))
1847 if (name
== wxT("margin-left"))
1848 attr
.GetTextBoxAttr().GetMargins().GetLeft().SetValue(wxRichTextParseDimension(value
));
1849 else if (name
== wxT("margin-right"))
1850 attr
.GetTextBoxAttr().GetMargins().GetRight().SetValue(wxRichTextParseDimension(value
));
1851 else if (name
== wxT("margin-top"))
1852 attr
.GetTextBoxAttr().GetMargins().GetTop().SetValue(wxRichTextParseDimension(value
));
1853 else if (name
== wxT("margin-bottom"))
1854 attr
.GetTextBoxAttr().GetMargins().GetBottom().SetValue(wxRichTextParseDimension(value
));
1856 else if (name
.Contains(wxT("padding-")))
1858 if (name
== wxT("padding-left"))
1859 attr
.GetTextBoxAttr().GetPadding().GetLeft().SetValue(wxRichTextParseDimension(value
));
1860 else if (name
== wxT("padding-right"))
1861 attr
.GetTextBoxAttr().GetPadding().GetRight().SetValue(wxRichTextParseDimension(value
));
1862 else if (name
== wxT("padding-top"))
1863 attr
.GetTextBoxAttr().GetPadding().GetTop().SetValue(wxRichTextParseDimension(value
));
1864 else if (name
== wxT("padding-bottom"))
1865 attr
.GetTextBoxAttr().GetPadding().GetBottom().SetValue(wxRichTextParseDimension(value
));
1867 else if (name
.Contains(wxT("position-")))
1869 if (name
== wxT("position-left"))
1870 attr
.GetTextBoxAttr().GetPosition().GetLeft().SetValue(wxRichTextParseDimension(value
));
1871 else if (name
== wxT("position-right"))
1872 attr
.GetTextBoxAttr().GetPosition().GetRight().SetValue(wxRichTextParseDimension(value
));
1873 else if (name
== wxT("position-top"))
1874 attr
.GetTextBoxAttr().GetPosition().GetTop().SetValue(wxRichTextParseDimension(value
));
1875 else if (name
== wxT("position-bottom"))
1876 attr
.GetTextBoxAttr().GetPosition().GetBottom().SetValue(wxRichTextParseDimension(value
));
1880 xmlAttr
= xmlAttr
->GetNext();
1889 // Import this object from XML
1890 bool wxRichTextObject::ImportFromXML(wxRichTextBuffer
* WXUNUSED(buffer
), wxXmlNode
* node
, wxRichTextXMLHandler
* handler
)
1892 handler
->ImportProperties(this, node
);
1893 handler
->ImportStyle(GetAttributes(), node
, UsesParagraphAttributes());
1898 #if wxRICHTEXT_HAVE_DIRECT_OUTPUT
1899 // Export this object directly to the given stream.
1900 bool wxRichTextObject::ExportXML(wxOutputStream
& stream
, int indent
, wxRichTextXMLHandler
* handler
)
1902 ::OutputIndentation(stream
, indent
);
1903 ::OutputString(stream
, wxT("<") + GetXMLNodeName(), handler
->GetConvMem(), handler
->GetConvFile());
1905 wxString style
= handler
->AddAttributes(GetAttributes(), true);
1907 ::OutputString(stream
, style
+ wxT(">"), handler
->GetConvMem(), handler
->GetConvFile());
1909 if (GetProperties().GetCount() > 0)
1911 handler
->WriteProperties(stream
, GetProperties(), indent
);
1914 wxRichTextCompositeObject
* composite
= wxDynamicCast(this, wxRichTextCompositeObject
);
1918 for (i
= 0; i
< composite
->GetChildCount(); i
++)
1920 wxRichTextObject
* child
= composite
->GetChild(i
);
1921 child
->ExportXML(stream
, indent
+1, handler
);
1925 ::OutputIndentation(stream
, indent
);
1926 ::OutputString(stream
, wxT("</") + GetXMLNodeName() + wxT(">"), handler
->GetConvMem(), handler
->GetConvFile());
1931 #if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
1932 // Export this object to the given parent node, usually creating at least one child node.
1933 bool wxRichTextObject::ExportXML(wxXmlNode
* parent
, wxRichTextXMLHandler
* handler
)
1935 wxXmlNode
* elementNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, GetXMLNodeName());
1936 parent
->AddChild(elementNode
);
1937 handler
->AddAttributes(elementNode
, GetAttributes(), true);
1938 handler
->WriteProperties(elementNode
, GetProperties());
1940 wxRichTextCompositeObject
* composite
= wxDynamicCast(this, wxRichTextCompositeObject
);
1944 for (i
= 0; i
< composite
->GetChildCount(); i
++)
1946 wxRichTextObject
* child
= composite
->GetChild(i
);
1947 child
->ExportXML(elementNode
, handler
);
1955 // Import this object from XML
1956 bool wxRichTextPlainText::ImportFromXML(wxRichTextBuffer
* buffer
, wxXmlNode
* node
, wxRichTextXMLHandler
* handler
)
1958 wxRichTextObject::ImportFromXML(buffer
, node
, handler
);
1960 if (node
->GetName() == wxT("text"))
1963 wxXmlNode
* textChild
= node
->GetChildren();
1966 if (textChild
->GetType() == wxXML_TEXT_NODE
||
1967 textChild
->GetType() == wxXML_CDATA_SECTION_NODE
)
1969 wxString text2
= textChild
->GetContent();
1971 // Strip whitespace from end
1972 if (!text2
.empty() && text2
[text2
.length()-1] == wxT('\n'))
1973 text2
= text2
.Mid(0, text2
.length()-1);
1975 if (!text2
.empty() && text2
[0] == wxT('"'))
1976 text2
= text2
.Mid(1);
1977 if (!text2
.empty() && text2
[text2
.length()-1] == wxT('"'))
1978 text2
= text2
.Mid(0, text2
.length() - 1);
1982 textChild
= textChild
->GetNext();
1987 else if (node
->GetName() == wxT("symbol"))
1989 // This is a symbol that XML can't read in the normal way
1991 wxXmlNode
* textChild
= node
->GetChildren();
1994 if (textChild
->GetType() == wxXML_TEXT_NODE
||
1995 textChild
->GetType() == wxXML_CDATA_SECTION_NODE
)
1997 wxString text2
= textChild
->GetContent();
2000 textChild
= textChild
->GetNext();
2003 wxString actualText
;
2004 actualText
<< (wxChar
) wxAtoi(text
);
2005 SetText(actualText
);
2013 #if wxRICHTEXT_HAVE_DIRECT_OUTPUT
2014 // Export this object directly to the given stream.
2015 bool wxRichTextPlainText::ExportXML(wxOutputStream
& stream
, int indent
, wxRichTextXMLHandler
* handler
)
2017 wxString style
= handler
->AddAttributes(GetAttributes(), false);
2021 const wxString
& text
= GetText();
2022 int len
= (int) text
.Length();
2027 ::OutputIndentation(stream
, indent
);
2028 ::OutputString(stream
, wxT("<text"), handler
->GetConvMem(), handler
->GetConvFile());
2029 ::OutputString(stream
, style
+ wxT(">"), handler
->GetConvMem(), handler
->GetConvFile());
2030 if (GetProperties().GetCount() > 0)
2032 handler
->WriteProperties(stream
, GetProperties(), indent
);
2033 ::OutputIndentation(stream
, indent
);
2035 ::OutputString(stream
, wxT("</text>"), handler
->GetConvMem(), handler
->GetConvFile());
2037 else for (i
= 0; i
< len
; i
++)
2040 int c
= (int) text
[i
];
2042 int c
= (int) wxUChar(text
[i
]);
2044 if ((c
< 32 || c
== 34) && /* c != 9 && */ c
!= 10 && c
!= 13)
2048 wxString
fragment(text
.Mid(last
, i
-last
));
2049 if (!fragment
.empty())
2051 ::OutputIndentation(stream
, indent
);
2052 ::OutputString(stream
, wxT("<text"), handler
->GetConvMem(), handler
->GetConvFile());
2054 ::OutputString(stream
, style
+ wxT(">"), handler
->GetConvMem(), handler
->GetConvFile());
2056 if (!fragment
.empty() && (fragment
[0] == wxT(' ') || fragment
[fragment
.length()-1] == wxT(' ')))
2058 ::OutputString(stream
, wxT("\""), handler
->GetConvMem(), handler
->GetConvFile());
2059 ::OutputStringEnt(stream
, fragment
, handler
->GetConvMem(), handler
->GetConvFile());
2060 ::OutputString(stream
, wxT("\""), handler
->GetConvMem(), handler
->GetConvFile());
2063 ::OutputStringEnt(stream
, fragment
, handler
->GetConvMem(), handler
->GetConvFile());
2065 if (GetProperties().GetCount() > 0)
2067 handler
->WriteProperties(stream
, GetProperties(), indent
);
2068 ::OutputIndentation(stream
, indent
);
2070 ::OutputString(stream
, wxT("</text>"), handler
->GetConvMem(), handler
->GetConvFile());
2075 // Output this character as a number in a separate tag, because XML can't cope
2076 // with entities below 32 except for 10 and 13
2078 ::OutputIndentation(stream
, indent
);
2079 ::OutputString(stream
, wxT("<symbol"), handler
->GetConvMem(), handler
->GetConvFile());
2081 ::OutputString(stream
, style
+ wxT(">"), handler
->GetConvMem(), handler
->GetConvFile());
2082 ::OutputString(stream
, wxString::Format(wxT("%d"), c
), handler
->GetConvMem(), handler
->GetConvFile());
2084 if (GetProperties().GetCount() > 0)
2086 handler
->WriteProperties(stream
, GetProperties(), indent
);
2087 ::OutputIndentation(stream
, indent
);
2089 ::OutputString(stream
, wxT("</symbol>"), handler
->GetConvMem(), handler
->GetConvFile());
2097 fragment
= text
.Mid(last
, i
-last
);
2101 ::OutputIndentation(stream
, indent
);
2102 ::OutputString(stream
, wxT("<text"), handler
->GetConvMem(), handler
->GetConvFile());
2104 ::OutputString(stream
, style
+ wxT(">"), handler
->GetConvMem(), handler
->GetConvFile());
2106 if (GetProperties().GetCount() > 0)
2108 handler
->WriteProperties(stream
, GetProperties(), indent
);
2109 ::OutputIndentation(stream
, indent
);
2112 if (!fragment
.empty() && (fragment
[0] == wxT(' ') || fragment
[fragment
.length()-1] == wxT(' ')))
2114 ::OutputString(stream
, wxT("\""), handler
->GetConvMem(), handler
->GetConvFile());
2115 ::OutputStringEnt(stream
, fragment
, handler
->GetConvMem(), handler
->GetConvFile());
2116 ::OutputString(stream
, wxT("\""), handler
->GetConvMem(), handler
->GetConvFile());
2119 ::OutputStringEnt(stream
, fragment
, handler
->GetConvMem(), handler
->GetConvFile());
2121 ::OutputString(stream
, wxT("</text>"), handler
->GetConvMem(), handler
->GetConvFile());
2127 #if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
2128 // Export this object to the given parent node, usually creating at least one child node.
2129 bool wxRichTextPlainText::ExportXML(wxXmlNode
* parent
, wxRichTextXMLHandler
* handler
)
2133 const wxString
& text
= GetText();
2134 int len
= (int) text
.Length();
2140 wxXmlNode
* elementNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, wxT("text"));
2141 parent
->AddChild(elementNode
);
2143 handler
->AddAttributes(elementNode
, GetAttributes(), false);
2144 handler
->WriteProperties(elementNode
, GetProperties());
2146 else for (i
= 0; i
< len
; i
++)
2149 int c
= (int) text
[i
];
2151 int c
= (int) wxUChar(text
[i
]);
2153 if ((c
< 32 || c
== 34) && c
!= 10 && c
!= 13)
2157 wxString
fragment(text
.Mid(last
, i
-last
));
2158 if (!fragment
.empty())
2160 // TODO: I'm assuming wxXmlDocument will output quotes if necessary
2161 wxXmlNode
* elementNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, wxT("text"));
2162 parent
->AddChild(elementNode
);
2163 handler
->AddAttributes(elementNode
, GetAttributes(), false);
2164 handler
->WriteProperties(elementNode
, GetProperties());
2166 wxXmlNode
* textNode
= new wxXmlNode(wxXML_TEXT_NODE
, wxT("text"));
2167 elementNode
->AddChild(textNode
);
2169 if (fragment
[0] == wxT(' ') || fragment
[fragment
.length()-1] == wxT(' '))
2170 fragment
= wxT("\"") + fragment
+ wxT("\"");
2172 textNode
->SetContent(fragment
);
2177 // Output this character as a number in a separate tag, because XML can't cope
2178 // with entities below 32 except for 10 and 13
2180 wxXmlNode
* elementNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, wxT("symbol"));
2181 parent
->AddChild(elementNode
);
2183 handler
->AddAttributes(elementNode
, GetAttributes(), false);
2184 handler
->WriteProperties(elementNode
, GetProperties());
2186 wxXmlNode
* textNode
= new wxXmlNode(wxXML_TEXT_NODE
, wxT("text"));
2187 elementNode
->AddChild(textNode
);
2188 textNode
->SetContent(wxString::Format(wxT("%d"), c
));
2198 fragment
= text
.Mid(last
, i
-last
);
2202 wxXmlNode
* elementNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, wxT("text"));
2203 parent
->AddChild(elementNode
);
2204 handler
->AddAttributes(elementNode
, GetAttributes(), false);
2206 wxXmlNode
* textNode
= new wxXmlNode(wxXML_TEXT_NODE
, wxT("text"));
2207 elementNode
->AddChild(textNode
);
2209 if (fragment
[0] == wxT(' ') || fragment
[fragment
.length()-1] == wxT(' '))
2210 fragment
= wxT("\"") + fragment
+ wxT("\"");
2212 textNode
->SetContent(fragment
);
2219 // Import this object from XML
2220 bool wxRichTextImage::ImportFromXML(wxRichTextBuffer
* buffer
, wxXmlNode
* node
, wxRichTextXMLHandler
* handler
)
2222 wxRichTextObject::ImportFromXML(buffer
, node
, handler
);
2224 wxBitmapType imageType
= wxBITMAP_TYPE_PNG
;
2225 wxString value
= node
->GetAttribute(wxT("imagetype"), wxEmptyString
);
2228 int type
= wxAtoi(value
);
2230 // note: 0 == wxBITMAP_TYPE_INVALID
2231 if (type
<= 0 || type
>= wxBITMAP_TYPE_MAX
)
2233 wxLogWarning("Invalid bitmap type specified for <image> tag: %d", type
);
2237 imageType
= (wxBitmapType
)type
;
2243 wxXmlNode
* imageChild
= node
->GetChildren();
2246 wxString childName
= imageChild
->GetName();
2247 if (childName
== wxT("data"))
2249 wxXmlNode
* dataChild
= imageChild
->GetChildren();
2252 data
= dataChild
->GetContent();
2253 // wxLogDebug(data);
2254 dataChild
= dataChild
->GetNext();
2258 imageChild
= imageChild
->GetNext();
2263 wxStringInputStream
strStream(data
);
2265 GetImageBlock().ReadHex(strStream
, data
.length(), imageType
);
2273 #if wxRICHTEXT_HAVE_DIRECT_OUTPUT
2274 // Export this object directly to the given stream.
2275 bool wxRichTextImage::ExportXML(wxOutputStream
& stream
, int indent
, wxRichTextXMLHandler
* handler
)
2277 wxString style
= handler
->AddAttributes(GetAttributes(), false);
2279 ::OutputIndentation(stream
, indent
);
2280 ::OutputString(stream
, wxT("<image"), handler
->GetConvMem(), handler
->GetConvFile());
2281 if (!GetImageBlock().Ok())
2284 ::OutputString(stream
, style
+ wxT(">"), handler
->GetConvMem(), handler
->GetConvFile());
2288 ::OutputString(stream
, wxString::Format(wxT(" imagetype=\"%d\""), (int) GetImageBlock().GetImageType()) + style
+ wxT(">"), handler
->GetConvMem(), handler
->GetConvFile());
2290 if (GetProperties().GetCount() > 0)
2292 handler
->WriteProperties(stream
, GetProperties(), indent
);
2293 ::OutputIndentation(stream
, indent
);
2296 ::OutputIndentation(stream
, indent
+1);
2297 ::OutputString(stream
, wxT("<data>"), handler
->GetConvMem(), handler
->GetConvFile());
2299 // wxStopWatch stopwatch;
2301 GetImageBlock().WriteHex(stream
);
2303 // wxLogDebug(wxT("Image conversion to hex took %ldms"), stopwatch.Time());
2305 ::OutputString(stream
, wxT("</data>\n"), handler
->GetConvMem(), handler
->GetConvFile());
2306 ::OutputIndentation(stream
, indent
);
2307 ::OutputString(stream
, wxT("</image>"), handler
->GetConvMem(), handler
->GetConvFile());
2312 #if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
2313 // Export this object to the given parent node, usually creating at least one child node.
2314 bool wxRichTextImage::ExportXML(wxXmlNode
* parent
, wxRichTextXMLHandler
* handler
)
2316 wxXmlNode
* elementNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, wxT("image"));
2317 parent
->AddChild(elementNode
);
2319 if (GetImageBlock().Ok())
2320 elementNode
->AddAttribute(wxT("imagetype"), MakeString((int) GetImageBlock().GetImageType()));
2322 handler
->AddAttributes(elementNode
, GetAttributes(), false);
2323 handler
->WriteProperties(elementNode
, GetProperties());
2325 wxXmlNode
* dataNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, wxT("data"));
2326 elementNode
->AddChild(dataNode
);
2327 wxXmlNode
* textNode
= new wxXmlNode(wxXML_TEXT_NODE
, wxT("text"));
2328 dataNode
->AddChild(textNode
);
2333 wxMemoryOutputStream stream
;
2334 if (GetImageBlock().WriteHex(stream
))
2336 if (stream
.GetSize() > 0)
2338 int size
= stream
.GetSize();
2339 int size2
= stream
.GetOutputStreamBuffer()->GetIntPosition();
2340 wxASSERT(size
== size2
);
2342 unsigned char* data
= new unsigned char[size
];
2343 stream
.CopyTo(data
, size
);
2344 strData
= wxString((const char*) data
, wxConvUTF8
, size
);
2348 strData
= wxEmptyString
;
2354 wxStringOutputStream
strStream(& strData
);
2355 GetImageBlock().WriteHex(strStream
);
2359 textNode
->SetContent(strData
);
2360 textNode
->SetNoConversion(true); // optimize speed
2367 // Import this object from XML
2368 bool wxRichTextParagraphLayoutBox::ImportFromXML(wxRichTextBuffer
* buffer
, wxXmlNode
* node
, wxRichTextXMLHandler
* handler
)
2370 wxRichTextObject::ImportFromXML(buffer
, node
, handler
);
2372 wxString partial
= node
->GetAttribute(wxT("partialparagraph"), wxEmptyString
);
2373 if (partial
== wxT("true"))
2374 SetPartialParagraph(true);
2379 #if wxRICHTEXT_HAVE_DIRECT_OUTPUT
2380 // Export this object directly to the given stream.
2381 bool wxRichTextParagraphLayoutBox::ExportXML(wxOutputStream
& stream
, int indent
, wxRichTextXMLHandler
* handler
)
2383 ::OutputIndentation(stream
, indent
);
2384 ::OutputString(stream
, wxT("<paragraphlayout"), handler
->GetConvMem(), handler
->GetConvFile());
2386 wxString style
= handler
->AddAttributes(GetAttributes(), true);
2388 if (GetPartialParagraph())
2389 style
<< wxT(" partialparagraph=\"true\"");
2391 ::OutputString(stream
, style
+ wxT(">"), handler
->GetConvMem(), handler
->GetConvFile());
2393 if (GetProperties().GetCount() > 0)
2395 handler
->WriteProperties(stream
, GetProperties(), indent
);
2399 for (i
= 0; i
< GetChildCount(); i
++)
2401 wxRichTextObject
* child
= GetChild(i
);
2402 child
->ExportXML(stream
, indent
+1, handler
);
2405 ::OutputIndentation(stream
, indent
);
2406 ::OutputString(stream
, wxT("</paragraphlayout>"), handler
->GetConvMem(), handler
->GetConvFile());
2411 #if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
2412 // Export this object to the given parent node, usually creating at least one child node.
2413 bool wxRichTextParagraphLayoutBox::ExportXML(wxXmlNode
* parent
, wxRichTextXMLHandler
* handler
)
2415 wxXmlNode
* elementNode
= new wxXmlNode(wxXML_ELEMENT_NODE
, wxT("paragraphlayout"));
2416 parent
->AddChild(elementNode
);
2417 handler
->AddAttributes(elementNode
, GetAttributes(), true);
2418 handler
->WriteProperties(elementNode
, GetProperties());
2420 if (GetPartialParagraph())
2421 elementNode
->AddAttribute(wxT("partialparagraph"), wxT("true"));
2424 for (i
= 0; i
< GetChildCount(); i
++)
2426 wxRichTextObject
* child
= GetChild(i
);
2427 child
->ExportXML(elementNode
, handler
);
2435 // wxUSE_RICHTEXT && wxUSE_XML