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"
28 #include "wx/filename.h"
29 #include "wx/clipbrd.h"
30 #include "wx/wfstream.h"
31 #include "wx/sstream.h"
32 #include "wx/txtstrm.h"
33 #include "wx/tokenzr.h"
34 #include "wx/xml/xml.h"
36 IMPLEMENT_DYNAMIC_CLASS(wxRichTextXMLHandler
, wxRichTextFileHandler
)
39 bool wxRichTextXMLHandler::DoLoadFile(wxRichTextBuffer
*buffer
, wxInputStream
& stream
)
44 buffer
->ResetAndClearCommands();
47 wxXmlDocument
* xmlDoc
= new wxXmlDocument
;
50 // This is the encoding to convert to (memory encoding rather than file encoding)
51 wxString
encoding(wxT("UTF-8"));
53 #if !wxUSE_UNICODE && wxUSE_INTL
54 encoding
= wxLocale::GetSystemEncodingName();
57 if (!xmlDoc
->Load(stream
, encoding
))
59 buffer
->ResetAndClearCommands();
64 if (xmlDoc
->GetRoot() && xmlDoc
->GetRoot()->GetType() == wxXML_ELEMENT_NODE
&& xmlDoc
->GetRoot()->GetName() == wxT("richtext"))
66 wxXmlNode
* child
= xmlDoc
->GetRoot()->GetChildren();
69 if (child
->GetType() == wxXML_ELEMENT_NODE
)
71 wxString name
= child
->GetName();
72 if (name
== wxT("richtext-version"))
76 ImportXML(buffer
, child
);
79 child
= child
->GetNext();
90 buffer
->UpdateRanges();
95 /// Recursively import an object
96 bool wxRichTextXMLHandler::ImportXML(wxRichTextBuffer
* buffer
, wxXmlNode
* node
)
98 wxString name
= node
->GetName();
100 bool doneChildren
= false;
102 if (name
== wxT("paragraphlayout"))
104 wxString partial
= node
->GetAttribute(wxT("partialparagraph"), wxEmptyString
);
105 if (partial
== wxT("true"))
106 buffer
->SetPartialParagraph(true);
108 else if (name
== wxT("paragraph"))
110 wxRichTextParagraph
* para
= new wxRichTextParagraph(buffer
);
111 buffer
->AppendChild(para
);
113 GetStyle(para
->GetAttributes(), node
, true);
115 wxXmlNode
* child
= node
->GetChildren();
118 wxString childName
= child
->GetName();
119 if (childName
== wxT("text"))
122 wxXmlNode
* textChild
= child
->GetChildren();
125 if (textChild
->GetType() == wxXML_TEXT_NODE
||
126 textChild
->GetType() == wxXML_CDATA_SECTION_NODE
)
128 wxString text2
= textChild
->GetContent();
130 // Strip whitespace from end
131 if (!text2
.empty() && text2
[text2
.length()-1] == wxT('\n'))
132 text2
= text2
.Mid(0, text2
.length()-1);
134 if (!text2
.empty() && text2
[0] == wxT('"'))
135 text2
= text2
.Mid(1);
136 if (!text2
.empty() && text2
[text2
.length()-1] == wxT('"'))
137 text2
= text2
.Mid(0, text2
.length() - 1);
141 textChild
= textChild
->GetNext();
144 wxRichTextPlainText
* textObject
= new wxRichTextPlainText(text
, para
);
145 GetStyle(textObject
->GetAttributes(), child
, false);
147 para
->AppendChild(textObject
);
149 else if (childName
== wxT("symbol"))
151 // This is a symbol that XML can't read in the normal way
153 wxXmlNode
* textChild
= child
->GetChildren();
156 if (textChild
->GetType() == wxXML_TEXT_NODE
||
157 textChild
->GetType() == wxXML_CDATA_SECTION_NODE
)
159 wxString text2
= textChild
->GetContent();
162 textChild
= textChild
->GetNext();
166 actualText
<< (wxChar
) wxAtoi(text
);
168 wxRichTextPlainText
* textObject
= new wxRichTextPlainText(actualText
, para
);
169 GetStyle(textObject
->GetAttributes(), child
, false);
171 para
->AppendChild(textObject
);
173 else if (childName
== wxT("image"))
175 wxBitmapType imageType
= wxBITMAP_TYPE_PNG
;
176 wxString value
= node
->GetAttribute(wxT("imagetype"), wxEmptyString
);
179 int type
= wxAtoi(value
);
181 // note: 0 == wxBITMAP_TYPE_INVALID
182 if (type
<= 0 || type
>= wxBITMAP_TYPE_MAX
)
183 wxLogWarning("Invalid bitmap type specified for <image> tag: %d", type
);
185 imageType
= (wxBitmapType
)type
;
190 wxXmlNode
* imageChild
= child
->GetChildren();
193 wxString childName
= imageChild
->GetName();
194 if (childName
== wxT("data"))
196 wxXmlNode
* dataChild
= imageChild
->GetChildren();
199 data
= dataChild
->GetContent();
201 dataChild
= dataChild
->GetNext();
205 imageChild
= imageChild
->GetNext();
210 wxRichTextImage
* imageObj
= new wxRichTextImage(para
);
211 GetStyle(imageObj
->GetAttributes(), child
, false);
212 para
->AppendChild(imageObj
);
214 wxStringInputStream
strStream(data
);
216 imageObj
->GetImageBlock().ReadHex(strStream
, data
.length(), imageType
);
219 child
= child
->GetNext();
224 else if (name
== wxT("stylesheet"))
226 if (GetFlags() & wxRICHTEXT_HANDLER_INCLUDE_STYLESHEET
)
228 wxRichTextStyleSheet
* sheet
= new wxRichTextStyleSheet
;
229 wxString sheetName
= node
->GetAttribute(wxT("name"), wxEmptyString
);
230 wxString sheetDescription
= node
->GetAttribute(wxT("description"), wxEmptyString
);
231 sheet
->SetName(sheetName
);
232 sheet
->SetDescription(sheetDescription
);
234 wxXmlNode
* child
= node
->GetChildren();
237 ImportStyleDefinition(sheet
, child
);
239 child
= child
->GetNext();
242 // Notify that styles have changed. If this is vetoed by the app,
243 // the new sheet will be deleted. If it is not vetoed, the
244 // old sheet will be deleted and replaced with the new one.
245 buffer
->SetStyleSheetAndNotify(sheet
);
252 wxXmlNode
* child
= node
->GetChildren();
255 ImportXML(buffer
, child
);
256 child
= child
->GetNext();
263 bool wxRichTextXMLHandler::ImportStyleDefinition(wxRichTextStyleSheet
* sheet
, wxXmlNode
* node
)
265 wxString styleType
= node
->GetName();
266 wxString styleName
= node
->GetAttribute(wxT("name"), wxEmptyString
);
267 wxString baseStyleName
= node
->GetAttribute(wxT("basestyle"), wxEmptyString
);
269 if (styleName
.IsEmpty())
272 if (styleType
== wxT("characterstyle"))
274 wxRichTextCharacterStyleDefinition
* def
= new wxRichTextCharacterStyleDefinition(styleName
);
275 def
->SetBaseStyle(baseStyleName
);
277 wxXmlNode
* child
= node
->GetChildren();
280 if (child
->GetName() == wxT("style"))
283 GetStyle(attr
, child
, false);
286 child
= child
->GetNext();
289 sheet
->AddCharacterStyle(def
);
291 else if (styleType
== wxT("paragraphstyle"))
293 wxRichTextParagraphStyleDefinition
* def
= new wxRichTextParagraphStyleDefinition(styleName
);
295 wxString nextStyleName
= node
->GetAttribute(wxT("nextstyle"), wxEmptyString
);
296 def
->SetNextStyle(nextStyleName
);
297 def
->SetBaseStyle(baseStyleName
);
299 wxXmlNode
* child
= node
->GetChildren();
302 if (child
->GetName() == wxT("style"))
305 GetStyle(attr
, child
, false);
308 child
= child
->GetNext();
311 sheet
->AddParagraphStyle(def
);
313 else if (styleType
== wxT("liststyle"))
315 wxRichTextListStyleDefinition
* def
= new wxRichTextListStyleDefinition(styleName
);
317 wxString nextStyleName
= node
->GetAttribute(wxT("nextstyle"), wxEmptyString
);
318 def
->SetNextStyle(nextStyleName
);
319 def
->SetBaseStyle(baseStyleName
);
321 wxXmlNode
* child
= node
->GetChildren();
324 if (child
->GetName() == wxT("style"))
327 GetStyle(attr
, child
, false);
329 wxString styleLevel
= child
->GetAttribute(wxT("level"), wxEmptyString
);
330 if (styleLevel
.IsEmpty())
336 int level
= wxAtoi(styleLevel
);
337 if (level
> 0 && level
<= 10)
339 def
->SetLevelAttributes(level
-1, attr
);
343 child
= child
->GetNext();
346 sheet
->AddListStyle(def
);
352 //-----------------------------------------------------------------------------
353 // xml support routines
354 //-----------------------------------------------------------------------------
356 bool wxRichTextXMLHandler::HasParam(wxXmlNode
* node
, const wxString
& param
)
358 return (GetParamNode(node
, param
) != NULL
);
361 wxXmlNode
*wxRichTextXMLHandler::GetParamNode(wxXmlNode
* node
, const wxString
& param
)
363 wxCHECK_MSG(node
, NULL
, wxT("You can't access node data before it was initialized!"));
365 wxXmlNode
*n
= node
->GetChildren();
369 if (n
->GetType() == wxXML_ELEMENT_NODE
&& n
->GetName() == param
)
377 wxString
wxRichTextXMLHandler::GetNodeContent(wxXmlNode
*node
)
380 if (n
== NULL
) return wxEmptyString
;
381 n
= n
->GetChildren();
385 if (n
->GetType() == wxXML_TEXT_NODE
||
386 n
->GetType() == wxXML_CDATA_SECTION_NODE
)
387 return n
->GetContent();
390 return wxEmptyString
;
394 wxString
wxRichTextXMLHandler::GetParamValue(wxXmlNode
*node
, const wxString
& param
)
397 return GetNodeContent(node
);
399 return GetNodeContent(GetParamNode(node
, param
));
402 wxString
wxRichTextXMLHandler::GetText(wxXmlNode
*node
, const wxString
& param
, bool WXUNUSED(translate
))
404 wxXmlNode
*parNode
= GetParamNode(node
, param
);
407 wxString
str1(GetNodeContent(parNode
));
411 // For use with earlier versions of wxWidgets
412 #ifndef WXUNUSED_IN_UNICODE
414 #define WXUNUSED_IN_UNICODE(x) WXUNUSED(x)
416 #define WXUNUSED_IN_UNICODE(x) x
420 // write string to output:
421 inline static void OutputString(wxOutputStream
& stream
, const wxString
& str
,
422 wxMBConv
*WXUNUSED_IN_UNICODE(convMem
) = NULL
, wxMBConv
*convFile
= NULL
)
424 if (str
.empty()) return;
428 const wxWX2MBbuf
buf(str
.mb_str(*convFile
));
429 stream
.Write((const char*)buf
, strlen((const char*)buf
));
433 const wxWX2MBbuf
buf(str
.mb_str(wxConvUTF8
));
434 stream
.Write((const char*)buf
, strlen((const char*)buf
));
437 if ( convFile
== NULL
)
438 stream
.Write(str
.mb_str(), str
.Len());
441 wxString
str2(str
.wc_str(*convMem
), *convFile
);
442 stream
.Write(str2
.mb_str(), str2
.Len());
447 // Same as above, but create entities first.
448 // Translates '<' to "<", '>' to ">" and '&' to "&"
449 static void OutputStringEnt(wxOutputStream
& stream
, const wxString
& str
,
450 wxMBConv
*convMem
= NULL
, wxMBConv
*convFile
= NULL
)
458 for (i
= 0; i
< len
; i
++)
462 // Original code excluded "&" but we _do_ want to convert
463 // the ampersand beginning & because otherwise when read in,
464 // the original "&" becomes "&".
466 if (c
== wxT('<') || c
== wxT('>') || c
== wxT('"') ||
467 (c
== wxT('&') /* && (str.Mid(i+1, 4) != wxT("amp;")) */ ))
469 OutputString(stream
, str
.Mid(last
, i
- last
), convMem
, convFile
);
473 OutputString(stream
, wxT("<"), NULL
, NULL
);
476 OutputString(stream
, wxT(">"), NULL
, NULL
);
479 OutputString(stream
, wxT("&"), NULL
, NULL
);
482 OutputString(stream
, wxT("""), NULL
, NULL
);
488 else if (wxUChar(c
) > 127)
490 OutputString(stream
, str
.Mid(last
, i
- last
), convMem
, convFile
);
492 wxString
s(wxT("&#"));
495 OutputString(stream
, s
, NULL
, NULL
);
499 OutputString(stream
, str
.Mid(last
, i
- last
), convMem
, convFile
);
502 static wxString
AttributeToXML(const wxString
& str
)
510 for (i
= 0; i
< len
; i
++)
514 // Original code excluded "&" but we _do_ want to convert
515 // the ampersand beginning & because otherwise when read in,
516 // the original "&" becomes "&".
518 if (c
== wxT('<') || c
== wxT('>') || c
== wxT('"') ||
519 (c
== wxT('&') /* && (str.Mid(i+1, 4) != wxT("amp;")) */ ))
521 str1
+= str
.Mid(last
, i
- last
);
531 str1
+= wxT("&");
534 str1
+= wxT(""");
540 else if (wxUChar(c
) > 127)
542 str1
+= str
.Mid(last
, i
- last
);
544 wxString
s(wxT("&#"));
551 str1
+= str
.Mid(last
, i
- last
);
555 inline static void OutputIndentation(wxOutputStream
& stream
, int indent
)
557 wxString str
= wxT("\n");
558 for (int i
= 0; i
< indent
; i
++)
559 str
<< wxT(' ') << wxT(' ');
560 OutputString(stream
, str
, NULL
, NULL
);
563 // Convert a colour to a 6-digit hex string
564 static wxString
ColourToHexString(const wxColour
& col
)
568 hex
+= wxDecToHex(col
.Red());
569 hex
+= wxDecToHex(col
.Green());
570 hex
+= wxDecToHex(col
.Blue());
575 // Convert 6-digit hex string to a colour
576 static wxColour
HexStringToColour(const wxString
& hex
)
578 unsigned char r
= (unsigned char)wxHexToDec(hex
.Mid(0, 2));
579 unsigned char g
= (unsigned char)wxHexToDec(hex
.Mid(2, 2));
580 unsigned char b
= (unsigned char)wxHexToDec(hex
.Mid(4, 2));
582 return wxColour(r
, g
, b
);
585 bool wxRichTextXMLHandler::DoSaveFile(wxRichTextBuffer
*buffer
, wxOutputStream
& stream
)
590 wxString
version(wxT("1.0") ) ;
592 bool deleteConvFile
= false;
593 wxString fileEncoding
;
594 wxMBConv
* convFile
= NULL
;
597 fileEncoding
= wxT("UTF-8");
598 convFile
= & wxConvUTF8
;
600 fileEncoding
= wxT("ISO-8859-1");
601 convFile
= & wxConvISO8859_1
;
604 // If SetEncoding has been called, change the output encoding.
605 if (!m_encoding
.empty() && m_encoding
.Lower() != fileEncoding
.Lower())
607 if (m_encoding
== wxT("<System>"))
610 fileEncoding
= wxLocale::GetSystemEncodingName();
611 // if !wxUSE_INTL, we fall back to UTF-8 or ISO-8859-1 below
616 fileEncoding
= m_encoding
;
619 // GetSystemEncodingName may not have returned a name
620 if (fileEncoding
.empty())
622 fileEncoding
= wxT("UTF-8");
624 fileEncoding
= wxT("ISO-8859-1");
626 convFile
= new wxCSConv(fileEncoding
);
627 deleteConvFile
= true;
631 wxMBConv
* convMem
= wxConvCurrent
;
633 wxMBConv
* convMem
= NULL
;
637 s
.Printf(wxT("<?xml version=\"%s\" encoding=\"%s\"?>\n"),
638 version
, fileEncoding
);
639 OutputString(stream
, s
, NULL
, NULL
);
640 OutputString(stream
, wxT("<richtext version=\"1.0.0.0\" xmlns=\"http://www.wxwidgets.org\">") , NULL
, NULL
);
644 if (buffer
->GetStyleSheet() && (GetFlags() & wxRICHTEXT_HANDLER_INCLUDE_STYLESHEET
))
646 OutputIndentation(stream
, level
);
647 wxString nameAndDescr
;
648 if (!buffer
->GetStyleSheet()->GetName().IsEmpty())
649 nameAndDescr
<< wxT(" name=\"") << buffer
->GetStyleSheet()->GetName() << wxT("\"");
650 if (!buffer
->GetStyleSheet()->GetDescription().IsEmpty())
651 nameAndDescr
<< wxT(" description=\"") << buffer
->GetStyleSheet()->GetDescription() << wxT("\"");
652 OutputString(stream
, wxString(wxT("<stylesheet")) + nameAndDescr
+ wxT(">"), convMem
, convFile
);
656 for (i
= 0; i
< (int) buffer
->GetStyleSheet()->GetCharacterStyleCount(); i
++)
658 wxRichTextCharacterStyleDefinition
* def
= buffer
->GetStyleSheet()->GetCharacterStyle(i
);
659 ExportStyleDefinition(stream
, convMem
, convFile
, def
, level
+ 1);
662 for (i
= 0; i
< (int) buffer
->GetStyleSheet()->GetParagraphStyleCount(); i
++)
664 wxRichTextParagraphStyleDefinition
* def
= buffer
->GetStyleSheet()->GetParagraphStyle(i
);
665 ExportStyleDefinition(stream
, convMem
, convFile
, def
, level
+ 1);
668 for (i
= 0; i
< (int) buffer
->GetStyleSheet()->GetListStyleCount(); i
++)
670 wxRichTextListStyleDefinition
* def
= buffer
->GetStyleSheet()->GetListStyle(i
);
671 ExportStyleDefinition(stream
, convMem
, convFile
, def
, level
+ 1);
674 OutputIndentation(stream
, level
);
675 OutputString(stream
, wxT("</stylesheet>"), convMem
, convFile
);
679 bool success
= ExportXML(stream
, convMem
, convFile
, *buffer
, level
);
681 OutputString(stream
, wxT("\n</richtext>") , NULL
, NULL
);
682 OutputString(stream
, wxT("\n"), NULL
, NULL
);
690 /// Recursively export an object
691 bool wxRichTextXMLHandler::ExportXML(wxOutputStream
& stream
, wxMBConv
* convMem
, wxMBConv
* convFile
, wxRichTextObject
& obj
, int indent
)
694 if (obj
.IsKindOf(CLASSINFO(wxRichTextParagraphLayoutBox
)))
695 objectName
= wxT("paragraphlayout");
696 else if (obj
.IsKindOf(CLASSINFO(wxRichTextParagraph
)))
697 objectName
= wxT("paragraph");
698 else if (obj
.IsKindOf(CLASSINFO(wxRichTextPlainText
)))
699 objectName
= wxT("text");
700 else if (obj
.IsKindOf(CLASSINFO(wxRichTextImage
)))
701 objectName
= wxT("image");
703 objectName
= wxT("object");
705 bool terminateTag
= true;
707 if (obj
.IsKindOf(CLASSINFO(wxRichTextPlainText
)))
709 wxRichTextPlainText
& textObj
= (wxRichTextPlainText
&) obj
;
711 wxString style
= CreateStyle(obj
.GetAttributes(), false);
715 const wxString
& text
= textObj
.GetText();
716 int len
= (int) text
.Length();
721 OutputIndentation(stream
, indent
);
722 OutputString(stream
, wxT("<") + objectName
, convMem
, convFile
);
723 OutputString(stream
, style
+ wxT(">"), convMem
, convFile
);
724 OutputString(stream
, wxT("</text>"), convMem
, convFile
);
726 else for (i
= 0; i
< len
; i
++)
728 int c
= (int) text
[i
];
729 if ((c
< 32 || c
== 34) && c
!= 9 && c
!= 10 && c
!= 13)
733 OutputIndentation(stream
, indent
);
734 OutputString(stream
, wxT("<") + objectName
, convMem
, convFile
);
736 OutputString(stream
, style
+ wxT(">"), convMem
, convFile
);
738 wxString
fragment(text
.Mid(last
, i
-last
));
739 if (!fragment
.empty() && (fragment
[0] == wxT(' ') || fragment
[fragment
.length()-1] == wxT(' ')))
741 OutputString(stream
, wxT("\""), convMem
, convFile
);
742 OutputStringEnt(stream
, fragment
, convMem
, convFile
);
743 OutputString(stream
, wxT("\""), convMem
, convFile
);
746 OutputStringEnt(stream
, fragment
, convMem
, convFile
);
748 OutputString(stream
, wxT("</text>"), convMem
, convFile
);
752 // Output this character as a number in a separate tag, because XML can't cope
753 // with entities below 32 except for 9, 10 and 13
755 OutputIndentation(stream
, indent
);
756 OutputString(stream
, wxT("<symbol"), convMem
, convFile
);
758 OutputString(stream
, style
+ wxT(">"), convMem
, convFile
);
759 OutputString(stream
, wxString::Format(wxT("%d"), c
), convMem
, convFile
);
761 OutputString(stream
, wxT("</symbol>"), convMem
, convFile
);
769 fragment
= text
.Mid(last
, i
-last
);
773 OutputIndentation(stream
, indent
);
774 OutputString(stream
, wxT("<") + objectName
, convMem
, convFile
);
776 OutputString(stream
, style
+ wxT(">"), convMem
, convFile
);
778 if (!fragment
.empty() && (fragment
[0] == wxT(' ') || fragment
[fragment
.length()-1] == wxT(' ')))
780 OutputString(stream
, wxT("\""), convMem
, convFile
);
781 OutputStringEnt(stream
, fragment
, convMem
, convFile
);
782 OutputString(stream
, wxT("\""), convMem
, convFile
);
785 OutputStringEnt(stream
, fragment
, convMem
, convFile
);
788 terminateTag
= false;
790 else if (obj
.IsKindOf(CLASSINFO(wxRichTextImage
)))
792 wxRichTextImage
& imageObj
= (wxRichTextImage
&) obj
;
794 wxString style
= CreateStyle(obj
.GetAttributes(), false);
796 if (imageObj
.GetImage().Ok() && !imageObj
.GetImageBlock().Ok())
797 imageObj
.MakeBlock();
799 OutputIndentation(stream
, indent
);
800 OutputString(stream
, wxT("<") + objectName
, convMem
, convFile
);
801 if (!imageObj
.GetImageBlock().Ok())
804 OutputString(stream
, style
+ wxT(">"), convMem
, convFile
);
808 OutputString(stream
, wxString::Format(wxT(" imagetype=\"%d\"") + style
+ wxT(">"), (int) imageObj
.GetImageBlock().GetImageType()));
811 OutputIndentation(stream
, indent
+1);
812 OutputString(stream
, wxT("<data>"), convMem
, convFile
);
814 imageObj
.GetImageBlock().WriteHex(stream
);
816 OutputString(stream
, wxT("</data>"), convMem
, convFile
);
818 else if (obj
.IsKindOf(CLASSINFO(wxRichTextCompositeObject
)))
820 OutputIndentation(stream
, indent
);
821 OutputString(stream
, wxT("<") + objectName
, convMem
, convFile
);
824 if (objectName
== wxT("paragraph") || objectName
== wxT("paragraphlayout"))
827 wxString style
= CreateStyle(obj
.GetAttributes(), isPara
);
829 if (objectName
== wxT("paragraphlayout") && ((wxRichTextParagraphLayoutBox
&) obj
).GetPartialParagraph())
830 style
<< wxT(" partialparagraph=\"true\"");
832 OutputString(stream
, style
+ wxT(">"), convMem
, convFile
);
834 wxRichTextCompositeObject
& composite
= (wxRichTextCompositeObject
&) obj
;
836 for (i
= 0; i
< composite
.GetChildCount(); i
++)
838 wxRichTextObject
* child
= composite
.GetChild(i
);
839 ExportXML(stream
, convMem
, convFile
, *child
, indent
+1);
843 if (objectName
!= wxT("text"))
844 OutputIndentation(stream
, indent
);
847 OutputString(stream
, wxT("</") + objectName
+ wxT(">"), convMem
, convFile
);
852 bool wxRichTextXMLHandler::ExportStyleDefinition(wxOutputStream
& stream
, wxMBConv
* convMem
, wxMBConv
* convFile
, wxRichTextStyleDefinition
* def
, int level
)
854 wxRichTextCharacterStyleDefinition
* charDef
= wxDynamicCast(def
, wxRichTextCharacterStyleDefinition
);
855 wxRichTextParagraphStyleDefinition
* paraDef
= wxDynamicCast(def
, wxRichTextParagraphStyleDefinition
);
856 wxRichTextListStyleDefinition
* listDef
= wxDynamicCast(def
, wxRichTextListStyleDefinition
);
858 wxString baseStyle
= def
->GetBaseStyle();
859 wxString baseStyleProp
;
860 if (!baseStyle
.IsEmpty())
861 baseStyleProp
= wxT(" basestyle=\"") + baseStyle
+ wxT("\"");
863 wxString descr
= def
->GetDescription();
865 if (!descr
.IsEmpty())
866 descrProp
= wxT(" description=\"") + descr
+ wxT("\"");
870 OutputIndentation(stream
, level
);
871 OutputString(stream
, wxT("<characterstyle") + baseStyleProp
+ descrProp
+ wxT(">"), convMem
, convFile
);
875 wxString style
= CreateStyle(def
->GetStyle(), false);
877 OutputIndentation(stream
, level
);
878 OutputString(stream
, wxT("<style ") + style
+ wxT(">"), convMem
, convFile
);
880 OutputIndentation(stream
, level
);
881 OutputString(stream
, wxT("</style>"), convMem
, convFile
);
885 OutputIndentation(stream
, level
);
886 OutputString(stream
, wxT("</characterstyle>"), convMem
, convFile
);
890 OutputIndentation(stream
, level
);
892 if (!listDef
->GetNextStyle().IsEmpty())
893 baseStyleProp
<< wxT(" basestyle=\"") << listDef
->GetNextStyle() << wxT("\"");
895 OutputString(stream
, wxT("<liststyle") + baseStyleProp
+ descrProp
+ wxT(">"), convMem
, convFile
);
899 wxString style
= CreateStyle(def
->GetStyle(), false);
901 OutputIndentation(stream
, level
);
902 OutputString(stream
, wxT("<style ") + style
+ wxT(">"), convMem
, convFile
);
904 OutputIndentation(stream
, level
);
905 OutputString(stream
, wxT("</style>"), convMem
, convFile
);
908 for (i
= 0; i
< 10; i
++)
910 wxTextAttr
* levelAttr
= listDef
->GetLevelAttributes(i
);
913 wxString style
= CreateStyle(def
->GetStyle(), false);
914 wxString levelStr
= wxString::Format(wxT(" level=\"%d\" "), (i
+1));
916 OutputIndentation(stream
, level
);
917 OutputString(stream
, wxT("<style ") + levelStr
+ style
+ wxT(">"), convMem
, convFile
);
919 OutputIndentation(stream
, level
);
920 OutputString(stream
, wxT("</style>"), convMem
, convFile
);
926 OutputIndentation(stream
, level
);
927 OutputString(stream
, wxT("</liststyle>"), convMem
, convFile
);
931 OutputIndentation(stream
, level
);
933 if (!paraDef
->GetNextStyle().IsEmpty())
934 baseStyleProp
<< wxT(" basestyle=\"") << paraDef
->GetNextStyle() << wxT("\"");
936 OutputString(stream
, wxT("<paragraphstyle") + baseStyleProp
+ descrProp
+ wxT(">"), convMem
, convFile
);
940 wxString style
= CreateStyle(def
->GetStyle(), false);
942 OutputIndentation(stream
, level
);
943 OutputString(stream
, wxT("<style ") + style
+ wxT(">"), convMem
, convFile
);
945 OutputIndentation(stream
, level
);
946 OutputString(stream
, wxT("</style>"), convMem
, convFile
);
950 OutputIndentation(stream
, level
);
951 OutputString(stream
, wxT("</paragraphstyle>"), convMem
, convFile
);
957 /// Create style parameters
958 wxString
wxRichTextXMLHandler::CreateStyle(const wxTextAttr
& attr
, bool isPara
)
961 if (attr
.HasTextColour() && attr
.GetTextColour().Ok())
963 str
<< wxT(" textcolor=\"#") << ColourToHexString(attr
.GetTextColour()) << wxT("\"");
965 if (attr
.HasBackgroundColour() && attr
.GetBackgroundColour().Ok())
967 str
<< wxT(" bgcolor=\"#") << ColourToHexString(attr
.GetBackgroundColour()) << wxT("\"");
970 if (attr
.HasFontSize())
971 str
<< wxT(" fontsize=\"") << attr
.GetFontSize() << wxT("\"");
973 //if (attr.HasFontFamily())
974 // str << wxT(" fontfamily=\"") << attr.GetFont().GetFamily() << wxT("\"");
976 if (attr
.HasFontItalic())
977 str
<< wxT(" fontstyle=\"") << attr
.GetFontStyle() << wxT("\"");
979 if (attr
.HasFontWeight())
980 str
<< wxT(" fontweight=\"") << attr
.GetFontWeight() << wxT("\"");
982 if (attr
.HasFontUnderlined())
983 str
<< wxT(" fontunderlined=\"") << (int) attr
.GetFontUnderlined() << wxT("\"");
985 if (attr
.HasFontFaceName())
986 str
<< wxT(" fontface=\"") << attr
.GetFontFaceName() << wxT("\"");
988 if (attr
.HasTextEffects())
990 str
<< wxT(" texteffects=\"");
991 str
<< attr
.GetTextEffects();
994 str
<< wxT(" texteffectflags=\"");
995 str
<< attr
.GetTextEffectFlags();
999 if (!attr
.GetCharacterStyleName().empty())
1000 str
<< wxT(" characterstyle=\"") << wxString(attr
.GetCharacterStyleName()) << wxT("\"");
1003 str
<< wxT(" url=\"") << AttributeToXML(attr
.GetURL()) << wxT("\"");
1007 if (attr
.HasAlignment())
1008 str
<< wxT(" alignment=\"") << (int) attr
.GetAlignment() << wxT("\"");
1010 if (attr
.HasLeftIndent())
1012 str
<< wxT(" leftindent=\"") << (int) attr
.GetLeftIndent() << wxT("\"");
1013 str
<< wxT(" leftsubindent=\"") << (int) attr
.GetLeftSubIndent() << wxT("\"");
1016 if (attr
.HasRightIndent())
1017 str
<< wxT(" rightindent=\"") << (int) attr
.GetRightIndent() << wxT("\"");
1019 if (attr
.HasParagraphSpacingAfter())
1020 str
<< wxT(" parspacingafter=\"") << (int) attr
.GetParagraphSpacingAfter() << wxT("\"");
1022 if (attr
.HasParagraphSpacingBefore())
1023 str
<< wxT(" parspacingbefore=\"") << (int) attr
.GetParagraphSpacingBefore() << wxT("\"");
1025 if (attr
.HasLineSpacing())
1026 str
<< wxT(" linespacing=\"") << (int) attr
.GetLineSpacing() << wxT("\"");
1028 if (attr
.HasBulletStyle())
1029 str
<< wxT(" bulletstyle=\"") << (int) attr
.GetBulletStyle() << wxT("\"");
1031 if (attr
.HasBulletNumber())
1032 str
<< wxT(" bulletnumber=\"") << (int) attr
.GetBulletNumber() << wxT("\"");
1034 if (attr
.HasBulletText())
1036 // If using a bullet symbol, convert to integer in case it's a non-XML-friendly character.
1037 // Otherwise, assume it's XML-friendly text such as outline numbering, e.g. 1.2.3.1
1038 if (!attr
.GetBulletText().IsEmpty() && (attr
.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_SYMBOL
))
1039 str
<< wxT(" bulletsymbol=\"") << (int) (attr
.GetBulletText()[0]) << wxT("\"");
1041 str
<< wxT(" bullettext=\"") << attr
.GetBulletText() << wxT("\"");
1043 str
<< wxT(" bulletfont=\"") << attr
.GetBulletFont() << wxT("\"");
1046 if (attr
.HasBulletName())
1047 str
<< wxT(" bulletname=\"") << attr
.GetBulletName() << wxT("\"");
1049 if (!attr
.GetParagraphStyleName().empty())
1050 str
<< wxT(" parstyle=\"") << wxString(attr
.GetParagraphStyleName()) << wxT("\"");
1052 if (!attr
.GetListStyleName().empty())
1053 str
<< wxT(" liststyle=\"") << wxString(attr
.GetListStyleName()) << wxT("\"");
1057 str
<< wxT(" tabs=\"");
1059 for (i
= 0; i
< attr
.GetTabs().GetCount(); i
++)
1063 str
<< attr
.GetTabs()[i
];
1068 if (attr
.HasPageBreak())
1070 str
<< wxT(" pagebreak=\"1\"");
1073 if (attr
.HasOutlineLevel())
1074 str
<< wxT(" outlinelevel=\"") << (int) attr
.GetOutlineLevel() << wxT("\"");
1081 /// Get style parameters
1082 bool wxRichTextXMLHandler::GetStyle(wxTextAttr
& attr
, wxXmlNode
* node
, bool isPara
)
1084 wxString fontFacename
;
1086 // int fontFamily = wxDEFAULT;
1087 int fontWeight
= wxNORMAL
;
1088 int fontStyle
= wxNORMAL
;
1089 bool fontUnderlined
= false;
1091 // int fontFlags = 0;
1093 fontFacename
= node
->GetAttribute(wxT("fontface"), wxEmptyString
);
1094 if (!fontFacename
.IsEmpty())
1095 attr
.SetFontFaceName(fontFacename
);
1098 //value = node->GetAttribute(wxT("fontfamily"), wxEmptyString);
1099 //if (!value.empty())
1100 // fontFamily = wxAtoi(value);
1102 value
= node
->GetAttribute(wxT("fontstyle"), wxEmptyString
);
1105 fontStyle
= wxAtoi(value
);
1106 attr
.SetFontStyle(fontStyle
);
1109 value
= node
->GetAttribute(wxT("fontsize"), wxEmptyString
);
1112 fontSize
= wxAtoi(value
);
1113 attr
.SetFontSize(fontSize
);
1116 value
= node
->GetAttribute(wxT("fontweight"), wxEmptyString
);
1119 fontWeight
= wxAtoi(value
);
1120 attr
.SetFontWeight(fontWeight
);
1123 value
= node
->GetAttribute(wxT("fontunderlined"), wxEmptyString
);
1126 fontUnderlined
= wxAtoi(value
) != 0;
1127 attr
.SetFontUnderlined(fontUnderlined
);
1130 value
= node
->GetAttribute(wxT("textcolor"), wxEmptyString
);
1133 if (value
[0] == wxT('#'))
1134 attr
.SetTextColour(HexStringToColour(value
.Mid(1)));
1136 attr
.SetTextColour(value
);
1139 value
= node
->GetAttribute(wxT("bgcolor"), wxEmptyString
);
1142 if (value
[0] == wxT('#'))
1143 attr
.SetBackgroundColour(HexStringToColour(value
.Mid(1)));
1145 attr
.SetBackgroundColour(value
);
1148 value
= node
->GetAttribute(wxT("characterstyle"), wxEmptyString
);
1150 attr
.SetCharacterStyleName(value
);
1152 value
= node
->GetAttribute(wxT("texteffects"), wxEmptyString
);
1153 if (!value
.IsEmpty())
1155 attr
.SetTextEffects(wxAtoi(value
));
1158 value
= node
->GetAttribute(wxT("texteffectflags"), wxEmptyString
);
1159 if (!value
.IsEmpty())
1161 attr
.SetTextEffectFlags(wxAtoi(value
));
1164 value
= node
->GetAttribute(wxT("url"), wxEmptyString
);
1168 // Set paragraph attributes
1171 value
= node
->GetAttribute(wxT("alignment"), wxEmptyString
);
1173 attr
.SetAlignment((wxTextAttrAlignment
) wxAtoi(value
));
1175 int leftSubIndent
= 0;
1177 bool hasLeftIndent
= false;
1179 value
= node
->GetAttribute(wxT("leftindent"), wxEmptyString
);
1182 leftIndent
= wxAtoi(value
);
1183 hasLeftIndent
= true;
1186 value
= node
->GetAttribute(wxT("leftsubindent"), wxEmptyString
);
1189 leftSubIndent
= wxAtoi(value
);
1190 hasLeftIndent
= true;
1194 attr
.SetLeftIndent(leftIndent
, leftSubIndent
);
1196 value
= node
->GetAttribute(wxT("rightindent"), wxEmptyString
);
1198 attr
.SetRightIndent(wxAtoi(value
));
1200 value
= node
->GetAttribute(wxT("parspacingbefore"), wxEmptyString
);
1202 attr
.SetParagraphSpacingBefore(wxAtoi(value
));
1204 value
= node
->GetAttribute(wxT("parspacingafter"), wxEmptyString
);
1206 attr
.SetParagraphSpacingAfter(wxAtoi(value
));
1208 value
= node
->GetAttribute(wxT("linespacing"), wxEmptyString
);
1210 attr
.SetLineSpacing(wxAtoi(value
));
1212 value
= node
->GetAttribute(wxT("bulletstyle"), wxEmptyString
);
1214 attr
.SetBulletStyle(wxAtoi(value
));
1216 value
= node
->GetAttribute(wxT("bulletnumber"), wxEmptyString
);
1218 attr
.SetBulletNumber(wxAtoi(value
));
1220 value
= node
->GetAttribute(wxT("bulletsymbol"), wxEmptyString
);
1223 wxChar ch
= wxAtoi(value
);
1226 attr
.SetBulletText(s
);
1229 value
= node
->GetAttribute(wxT("bullettext"), wxEmptyString
);
1231 attr
.SetBulletText(value
);
1233 value
= node
->GetAttribute(wxT("bulletfont"), wxEmptyString
);
1235 attr
.SetBulletFont(value
);
1237 value
= node
->GetAttribute(wxT("bulletname"), wxEmptyString
);
1239 attr
.SetBulletName(value
);
1241 value
= node
->GetAttribute(wxT("parstyle"), wxEmptyString
);
1243 attr
.SetParagraphStyleName(value
);
1245 value
= node
->GetAttribute(wxT("liststyle"), wxEmptyString
);
1247 attr
.SetListStyleName(value
);
1249 value
= node
->GetAttribute(wxT("tabs"), wxEmptyString
);
1253 wxStringTokenizer
tkz(value
, wxT(","));
1254 while (tkz
.HasMoreTokens())
1256 wxString token
= tkz
.GetNextToken();
1257 tabs
.Add(wxAtoi(token
));
1262 value
= node
->GetAttribute(wxT("pagebreak"), wxEmptyString
);
1263 if (!value
.IsEmpty())
1265 attr
.SetPageBreak(wxAtoi(value
) != 0);
1268 value
= node
->GetAttribute(wxT("outlinelevel"), wxEmptyString
);
1269 if (!value
.IsEmpty())
1271 attr
.SetOutlineLevel(wxAtoi(value
));
1282 // wxUSE_RICHTEXT && wxUSE_XML