]> git.saurik.com Git - wxWidgets.git/blame - src/richtext/richtextxml.cpp
[ 1574264 ] Fix height of wxComboCtrl's wxTextCtrl
[wxWidgets.git] / src / richtext / richtextxml.cpp
CommitLineData
5d7836c4 1/////////////////////////////////////////////////////////////////////////////
88a7a4e1 2// Name: src/richtext/richtextxml.cpp
5d7836c4
JS
3// Purpose: XML and HTML I/O for wxRichTextCtrl
4// Author: Julian Smart
7fe8059f 5// Modified by:
5d7836c4 6// Created: 2005-09-30
7fe8059f 7// RCS-ID: $Id$
5d7836c4
JS
8// Copyright: (c) Julian Smart
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
15#ifdef __BORLANDC__
61399247 16 #pragma hdrstop
5d7836c4
JS
17#endif
18
fcdbeefa 19#if wxUSE_RICHTEXT && wxUSE_XML
b01ca8b6
JS
20
21#include "wx/richtext/richtextxml.h"
22
5d7836c4 23#ifndef WX_PRECOMP
88a7a4e1 24 #include "wx/intl.h"
02761f6c 25 #include "wx/module.h"
5d7836c4
JS
26#endif
27
5d7836c4
JS
28#include "wx/filename.h"
29#include "wx/clipbrd.h"
30#include "wx/wfstream.h"
31#include "wx/sstream.h"
5d7836c4 32#include "wx/txtstrm.h"
0ca07313 33#include "wx/tokenzr.h"
5d7836c4
JS
34#include "wx/xml/xml.h"
35
5d7836c4
JS
36IMPLEMENT_DYNAMIC_CLASS(wxRichTextXMLHandler, wxRichTextFileHandler)
37
38#if wxUSE_STREAMS
7fe8059f 39bool wxRichTextXMLHandler::DoLoadFile(wxRichTextBuffer *buffer, wxInputStream& stream)
5d7836c4
JS
40{
41 if (!stream.IsOk())
42 return false;
43
44 buffer->Clear();
45
46 wxXmlDocument* xmlDoc = new wxXmlDocument;
47 bool success = true;
48
b71e9aa4
JS
49 // This is the encoding to convert to (memory encoding rather than file encoding)
50 wxString encoding(wxT("UTF-8"));
51
52#if !wxUSE_UNICODE && wxUSE_INTL
53 encoding = wxLocale::GetSystemEncodingName();
54#endif
55
56 if (!xmlDoc->Load(stream, encoding))
5d7836c4
JS
57 {
58 success = false;
59 }
60 else
61 {
62 if (xmlDoc->GetRoot() && xmlDoc->GetRoot()->GetType() == wxXML_ELEMENT_NODE && xmlDoc->GetRoot()->GetName() == wxT("richtext"))
63 {
64 wxXmlNode* child = xmlDoc->GetRoot()->GetChildren();
65 while (child)
66 {
67 if (child->GetType() == wxXML_ELEMENT_NODE)
68 {
69 wxString name = child->GetName();
70 if (name == wxT("richtext-version"))
71 {
72 }
73 else
74 ImportXML(buffer, child);
75 }
7fe8059f 76
5d7836c4
JS
77 child = child->GetNext();
78 }
79 }
80 else
81 {
82 success = false;
83 }
84 }
7fe8059f 85
5d7836c4
JS
86 delete xmlDoc;
87
88 buffer->UpdateRanges();
89
90 return success;
91}
92
93/// Recursively import an object
94bool wxRichTextXMLHandler::ImportXML(wxRichTextBuffer* buffer, wxXmlNode* node)
95{
96 wxString name = node->GetName();
97
98 bool doneChildren = false;
99
100 if (name == wxT("paragraphlayout"))
101 {
0ca07313
JS
102 wxString partial = node->GetPropVal(wxT("partialparagraph"), wxEmptyString);
103 if (partial == wxT("true"))
104 buffer->SetPartialParagraph(true);
5d7836c4
JS
105 }
106 else if (name == wxT("paragraph"))
107 {
108 wxRichTextParagraph* para = new wxRichTextParagraph(buffer);
109 buffer->AppendChild(para);
110
111 GetStyle(para->GetAttributes(), node, true);
112
113 wxXmlNode* child = node->GetChildren();
114 while (child)
115 {
116 wxString childName = child->GetName();
117 if (childName == wxT("text"))
118 {
119 wxString text;
120 wxXmlNode* textChild = child->GetChildren();
121 while (textChild)
122 {
123 if (textChild->GetType() == wxXML_TEXT_NODE ||
124 textChild->GetType() == wxXML_CDATA_SECTION_NODE)
125 {
126 wxString text2 = textChild->GetContent();
127
128 // Strip whitespace from end
88a7a4e1
WS
129 if (!text2.empty() && text2[text2.length()-1] == wxT('\n'))
130 text2 = text2.Mid(0, text2.length()-1);
5d7836c4 131
88a7a4e1 132 if (!text2.empty() && text2[0] == wxT('"'))
5d7836c4 133 text2 = text2.Mid(1);
88a7a4e1
WS
134 if (!text2.empty() && text2[text2.length()-1] == wxT('"'))
135 text2 = text2.Mid(0, text2.length() - 1);
5d7836c4 136
5d7836c4
JS
137 text += text2;
138 }
139 textChild = textChild->GetNext();
140 }
141
142 wxRichTextPlainText* textObject = new wxRichTextPlainText(text, para);
143 GetStyle(textObject->GetAttributes(), child, false);
144
145 para->AppendChild(textObject);
146 }
7b907278
JS
147 else if (childName == wxT("symbol"))
148 {
149 // This is a symbol that XML can't read in the normal way
150 wxString text;
151 wxXmlNode* textChild = child->GetChildren();
152 while (textChild)
153 {
154 if (textChild->GetType() == wxXML_TEXT_NODE ||
155 textChild->GetType() == wxXML_CDATA_SECTION_NODE)
156 {
157 wxString text2 = textChild->GetContent();
158 text += text2;
159 }
160 textChild = textChild->GetNext();
161 }
162
163 wxString actualText;
164 actualText << (wxChar) wxAtoi(text);
165
166 wxRichTextPlainText* textObject = new wxRichTextPlainText(actualText, para);
167 GetStyle(textObject->GetAttributes(), child, false);
168
169 para->AppendChild(textObject);
170 }
5d7836c4
JS
171 else if (childName == wxT("image"))
172 {
173 int imageType = wxBITMAP_TYPE_PNG;
174 wxString value = node->GetPropVal(wxT("imagetype"), wxEmptyString);
7fe8059f 175 if (!value.empty())
5d7836c4
JS
176 imageType = wxAtoi(value);
177
178 wxString data;
179
180 wxXmlNode* imageChild = child->GetChildren();
181 while (imageChild)
182 {
183 wxString childName = imageChild->GetName();
184 if (childName == wxT("data"))
185 {
186 wxXmlNode* dataChild = imageChild->GetChildren();
187 while (dataChild)
188 {
189 data = dataChild->GetContent();
190 // wxLogDebug(data);
191 dataChild = dataChild->GetNext();
192 }
7fe8059f 193
5d7836c4
JS
194 }
195 imageChild = imageChild->GetNext();
196 }
197
7fe8059f 198 if (!data.empty())
5d7836c4
JS
199 {
200 wxRichTextImage* imageObj = new wxRichTextImage(para);
201 para->AppendChild(imageObj);
202
203 wxStringInputStream strStream(data);
204
88a7a4e1 205 imageObj->GetImageBlock().ReadHex(strStream, data.length(), imageType);
5d7836c4
JS
206 }
207 }
208 child = child->GetNext();
209 }
210
211 doneChildren = true;
212 }
213
214 if (!doneChildren)
215 {
216 wxXmlNode* child = node->GetChildren();
217 while (child)
218 {
219 ImportXML(buffer, child);
220 child = child->GetNext();
221 }
7fe8059f 222 }
5d7836c4
JS
223
224 return true;
225}
226
227
228//-----------------------------------------------------------------------------
229// xml support routines
230//-----------------------------------------------------------------------------
231
232bool wxRichTextXMLHandler::HasParam(wxXmlNode* node, const wxString& param)
233{
234 return (GetParamNode(node, param) != NULL);
235}
236
237wxXmlNode *wxRichTextXMLHandler::GetParamNode(wxXmlNode* node, const wxString& param)
238{
239 wxCHECK_MSG(node, NULL, wxT("You can't access node data before it was initialized!"));
240
241 wxXmlNode *n = node->GetChildren();
242
243 while (n)
244 {
245 if (n->GetType() == wxXML_ELEMENT_NODE && n->GetName() == param)
246 return n;
247 n = n->GetNext();
248 }
249 return NULL;
250}
251
252
253wxString wxRichTextXMLHandler::GetNodeContent(wxXmlNode *node)
254{
255 wxXmlNode *n = node;
256 if (n == NULL) return wxEmptyString;
257 n = n->GetChildren();
258
259 while (n)
260 {
261 if (n->GetType() == wxXML_TEXT_NODE ||
262 n->GetType() == wxXML_CDATA_SECTION_NODE)
263 return n->GetContent();
264 n = n->GetNext();
265 }
266 return wxEmptyString;
267}
268
269
270wxString wxRichTextXMLHandler::GetParamValue(wxXmlNode *node, const wxString& param)
271{
7fe8059f 272 if (param.empty())
5d7836c4
JS
273 return GetNodeContent(node);
274 else
275 return GetNodeContent(GetParamNode(node, param));
276}
277
278wxString wxRichTextXMLHandler::GetText(wxXmlNode *node, const wxString& param, bool WXUNUSED(translate))
279{
280 wxXmlNode *parNode = GetParamNode(node, param);
281 if (!parNode)
282 parNode = node;
283 wxString str1(GetNodeContent(parNode));
284 return str1;
285}
286
1e967276
JS
287// For use with earlier versions of wxWidgets
288#ifndef WXUNUSED_IN_UNICODE
289#if wxUSE_UNICODE
290#define WXUNUSED_IN_UNICODE(x) WXUNUSED(x)
291#else
292#define WXUNUSED_IN_UNICODE(x) x
293#endif
294#endif
295
5d7836c4
JS
296// write string to output:
297inline static void OutputString(wxOutputStream& stream, const wxString& str,
7fe8059f 298 wxMBConv *WXUNUSED_IN_UNICODE(convMem) = NULL, wxMBConv *convFile = NULL)
5d7836c4 299{
7fe8059f 300 if (str.empty()) return;
5d7836c4 301#if wxUSE_UNICODE
0bab774b
JS
302 if (convFile)
303 {
304 const wxWX2MBbuf buf(str.mb_str(*convFile));
305 stream.Write((const char*)buf, strlen((const char*)buf));
306 }
307 else
308 {
309 const wxWX2MBbuf buf(str.mb_str(wxConvUTF8));
310 stream.Write((const char*)buf, strlen((const char*)buf));
311 }
5d7836c4
JS
312#else
313 if ( convFile == NULL )
314 stream.Write(str.mb_str(), str.Len());
315 else
316 {
317 wxString str2(str.wc_str(*convMem), *convFile);
318 stream.Write(str2.mb_str(), str2.Len());
319 }
320#endif
321}
322
323// Same as above, but create entities first.
324// Translates '<' to "&lt;", '>' to "&gt;" and '&' to "&amp;"
325static void OutputStringEnt(wxOutputStream& stream, const wxString& str,
326 wxMBConv *convMem = NULL, wxMBConv *convFile = NULL)
327{
328 wxString buf;
329 size_t i, last, len;
330 wxChar c;
7fe8059f 331
5d7836c4
JS
332 len = str.Len();
333 last = 0;
334 for (i = 0; i < len; i++)
335 {
336 c = str.GetChar(i);
88a7a4e1 337
b71e9aa4
JS
338 // Original code excluded "&amp;" but we _do_ want to convert
339 // the ampersand beginning &amp; because otherwise when read in,
340 // the original "&amp;" becomes "&".
341
5d7836c4 342 if (c == wxT('<') || c == wxT('>') || c == wxT('"') ||
b71e9aa4 343 (c == wxT('&') /* && (str.Mid(i+1, 4) != wxT("amp;")) */ ))
5d7836c4
JS
344 {
345 OutputString(stream, str.Mid(last, i - last), convMem, convFile);
346 switch (c)
347 {
348 case wxT('<'):
349 OutputString(stream, wxT("&lt;"), NULL, NULL);
350 break;
351 case wxT('>'):
352 OutputString(stream, wxT("&gt;"), NULL, NULL);
353 break;
354 case wxT('&'):
355 OutputString(stream, wxT("&amp;"), NULL, NULL);
356 break;
357 case wxT('"'):
358 OutputString(stream, wxT("&quot;"), NULL, NULL);
359 break;
360 default: break;
361 }
362 last = i + 1;
363 }
07854e5e 364 else if (wxUChar(c) > 127)
7b907278
JS
365 {
366 OutputString(stream, str.Mid(last, i - last), convMem, convFile);
367
368 wxString s(wxT("&#"));
369 s << (int) c;
370 s << wxT(";");
371 OutputString(stream, s, NULL, NULL);
372 last = i + 1;
373 }
5d7836c4
JS
374 }
375 OutputString(stream, str.Mid(last, i - last), convMem, convFile);
376}
377
378inline static void OutputIndentation(wxOutputStream& stream, int indent)
379{
380 wxString str = wxT("\n");
381 for (int i = 0; i < indent; i++)
382 str << wxT(' ') << wxT(' ');
383 OutputString(stream, str, NULL, NULL);
384}
385
5d7836c4
JS
386// Convert a colour to a 6-digit hex string
387static wxString ColourToHexString(const wxColour& col)
388{
389 wxString hex;
390
391 hex += wxDecToHex(col.Red());
392 hex += wxDecToHex(col.Green());
393 hex += wxDecToHex(col.Blue());
394
395 return hex;
396}
397
398// Convert 6-digit hex string to a colour
b71e9aa4 399static wxColour HexStringToColour(const wxString& hex)
5d7836c4 400{
7fe8059f
WS
401 unsigned char r = (unsigned char)wxHexToDec(hex.Mid(0, 2));
402 unsigned char g = (unsigned char)wxHexToDec(hex.Mid(2, 2));
403 unsigned char b = (unsigned char)wxHexToDec(hex.Mid(4, 2));
5d7836c4
JS
404
405 return wxColour(r, g, b);
406}
407
7fe8059f 408bool wxRichTextXMLHandler::DoSaveFile(wxRichTextBuffer *buffer, wxOutputStream& stream)
5d7836c4
JS
409{
410 if (!stream.IsOk())
411 return false;
412
413 wxString version(wxT("1.0") ) ;
b71e9aa4
JS
414
415 bool deleteConvFile = false;
416 wxString fileEncoding;
417 wxMBConv* convFile = NULL;
418
5d7836c4 419#if wxUSE_UNICODE
b71e9aa4
JS
420 fileEncoding = wxT("UTF-8");
421 convFile = & wxConvUTF8;
5d7836c4 422#else
b71e9aa4
JS
423 fileEncoding = wxT("ISO-8859-1");
424 convFile = & wxConvISO8859_1;
5d7836c4 425#endif
7fe8059f 426
b71e9aa4 427 // If SetEncoding has been called, change the output encoding.
88a7a4e1 428 if (!m_encoding.empty() && m_encoding.Lower() != fileEncoding.Lower())
b71e9aa4
JS
429 {
430 if (m_encoding == wxT("<System>"))
431 {
432 fileEncoding = wxLocale::GetSystemEncodingName();
433 }
434 else
435 {
436 fileEncoding = m_encoding;
437 }
438
439 // GetSystemEncodingName may not have returned a name
88a7a4e1 440 if (fileEncoding.empty())
5d7836c4 441#if wxUSE_UNICODE
b71e9aa4 442 fileEncoding = wxT("UTF-8");
5d7836c4 443#else
b71e9aa4
JS
444 fileEncoding = wxT("ISO-8859-1");
445#endif
446 convFile = new wxCSConv(fileEncoding);
447 deleteConvFile = true;
5d7836c4 448 }
b71e9aa4
JS
449
450#if !wxUSE_UNICODE
451 wxMBConv* convMem = wxConvCurrent;
452#else
453 wxMBConv* convMem = NULL;
5d7836c4 454#endif
7fe8059f 455
b71e9aa4 456 wxString s ;
5d7836c4 457 s.Printf(wxT("<?xml version=\"%s\" encoding=\"%s\"?>\n"),
b71e9aa4 458 (const wxChar*) version, (const wxChar*) fileEncoding );
5d7836c4
JS
459 OutputString(stream, s, NULL, NULL);
460 OutputString(stream, wxT("<richtext version=\"1.0.0.0\" xmlns=\"http://www.wxwidgets.org\">") , NULL, NULL);
461
462 int level = 1;
b71e9aa4 463 bool success = ExportXML(stream, convMem, convFile, *buffer, level);
5d7836c4
JS
464
465 OutputString(stream, wxT("\n</richtext>") , NULL, NULL);
466 OutputString(stream, wxT("\n"), NULL, NULL);
7fe8059f 467
b71e9aa4
JS
468 if (deleteConvFile)
469 delete convFile;
88a7a4e1 470
b71e9aa4 471 return success;
5d7836c4
JS
472}
473
474/// Recursively export an object
475bool wxRichTextXMLHandler::ExportXML(wxOutputStream& stream, wxMBConv* convMem, wxMBConv* convFile, wxRichTextObject& obj, int indent)
476{
477 wxString objectName;
478 if (obj.IsKindOf(CLASSINFO(wxRichTextParagraphLayoutBox)))
479 objectName = wxT("paragraphlayout");
480 else if (obj.IsKindOf(CLASSINFO(wxRichTextParagraph)))
481 objectName = wxT("paragraph");
482 else if (obj.IsKindOf(CLASSINFO(wxRichTextPlainText)))
483 objectName = wxT("text");
484 else if (obj.IsKindOf(CLASSINFO(wxRichTextImage)))
485 objectName = wxT("image");
486 else
487 objectName = wxT("object");
7b907278
JS
488
489 bool terminateTag = true;
5d7836c4
JS
490
491 if (obj.IsKindOf(CLASSINFO(wxRichTextPlainText)))
492 {
7b907278
JS
493 wxRichTextPlainText& textObj = (wxRichTextPlainText&) obj;
494
495 wxString style = CreateStyle(obj.GetAttributes(), false);
496
497 int i;
498 int last = 0;
499 const wxString& text = textObj.GetText();
500 int len = (int) text.Length();
501 for (i = 0; i < len; i++)
502 {
503 int c = (int) text[i];
504 if (c < 32 && c != 9 && c != 10 && c != 13)
505 {
506 if (i > 0)
507 {
508 OutputIndentation(stream, indent);
509 OutputString(stream, wxT("<") + objectName, convMem, convFile);
5d7836c4 510
7b907278 511 OutputString(stream, style + wxT(">"), convMem, convFile);
7fe8059f 512
7b907278
JS
513 wxString fragment(text.Mid(last, i-last));
514 if (!fragment.empty() && (fragment[0] == wxT(' ') || fragment[fragment.length()-1] == wxT(' ')))
515 {
516 OutputString(stream, wxT("\""), convMem, convFile);
517 OutputStringEnt(stream, fragment, convMem, convFile);
518 OutputString(stream, wxT("\""), convMem, convFile);
519 }
520 else
521 OutputStringEnt(stream, fragment, convMem, convFile);
7fe8059f 522
7b907278
JS
523 OutputString(stream, wxT("</text>"), convMem, convFile);
524 }
525
526
527 // Output this character as a number in a separate tag, because XML can't cope
528 // with entities below 32 except for 9, 10 and 13
529 last = i + 1;
530 OutputIndentation(stream, indent);
531 OutputString(stream, wxT("<symbol"), convMem, convFile);
7fe8059f 532
7b907278
JS
533 OutputString(stream, style + wxT(">"), convMem, convFile);
534 OutputString(stream, wxString::Format(wxT("%d"), c), convMem, convFile);
535
536 OutputString(stream, wxT("</symbol>"), convMem, convFile);
537 }
538 }
539
540 wxString fragment;
541 if (last == 0)
542 fragment = text;
543 else
544 fragment = text.Mid(last, i-last);
545
546 if (last < len)
5d7836c4 547 {
7b907278
JS
548 OutputIndentation(stream, indent);
549 OutputString(stream, wxT("<") + objectName, convMem, convFile);
550
551 OutputString(stream, style + wxT(">"), convMem, convFile);
552
553 if (!fragment.empty() && (fragment[0] == wxT(' ') || fragment[fragment.length()-1] == wxT(' ')))
554 {
555 OutputString(stream, wxT("\""), convMem, convFile);
556 OutputStringEnt(stream, fragment, convMem, convFile);
557 OutputString(stream, wxT("\""), convMem, convFile);
558 }
559 else
560 OutputStringEnt(stream, fragment, convMem, convFile);
5d7836c4
JS
561 }
562 else
7b907278 563 terminateTag = false;
5d7836c4
JS
564 }
565 else if (obj.IsKindOf(CLASSINFO(wxRichTextImage)))
566 {
567 wxRichTextImage& imageObj = (wxRichTextImage&) obj;
568
569 if (imageObj.GetImage().Ok() && !imageObj.GetImageBlock().Ok())
570 imageObj.MakeBlock();
571
572 OutputIndentation(stream, indent);
b71e9aa4 573 OutputString(stream, wxT("<") + objectName, convMem, convFile);
5d7836c4
JS
574 if (!imageObj.GetImageBlock().Ok())
575 {
576 // No data
b71e9aa4 577 OutputString(stream, wxT(">"), convMem, convFile);
5d7836c4
JS
578 }
579 else
580 {
b71e9aa4 581 OutputString(stream, wxString::Format(wxT(" imagetype=\"%d\">"), (int) imageObj.GetImageBlock().GetImageType()));
5d7836c4
JS
582 }
583
584 OutputIndentation(stream, indent+1);
b71e9aa4 585 OutputString(stream, wxT("<data>"), convMem, convFile);
5d7836c4
JS
586
587 imageObj.GetImageBlock().WriteHex(stream);
588
b71e9aa4 589 OutputString(stream, wxT("</data>"), convMem, convFile);
5d7836c4
JS
590 }
591 else if (obj.IsKindOf(CLASSINFO(wxRichTextCompositeObject)))
592 {
593 OutputIndentation(stream, indent);
b71e9aa4 594 OutputString(stream, wxT("<") + objectName, convMem, convFile);
7fe8059f 595
5d7836c4
JS
596 bool isPara = false;
597 if (objectName == wxT("paragraph") || objectName == wxT("paragraphlayout"))
598 isPara = true;
599
600 wxString style = CreateStyle(obj.GetAttributes(), isPara);
7b907278 601
0ca07313
JS
602 if (objectName == wxT("paragraphlayout") && ((wxRichTextParagraphLayoutBox&) obj).GetPartialParagraph())
603 style << wxT(" partialparagraph=\"true\"");
604
b71e9aa4 605 OutputString(stream, style + wxT(">"), convMem, convFile);
7fe8059f 606
5d7836c4
JS
607 wxRichTextCompositeObject& composite = (wxRichTextCompositeObject&) obj;
608 size_t i;
609 for (i = 0; i < composite.GetChildCount(); i++)
610 {
611 wxRichTextObject* child = composite.GetChild(i);
612 ExportXML(stream, convMem, convFile, *child, indent+1);
613 }
614 }
615
616 if (objectName != wxT("text"))
617 OutputIndentation(stream, indent);
618
7b907278
JS
619 if (terminateTag)
620 OutputString(stream, wxT("</") + objectName + wxT(">"), convMem, convFile);
5d7836c4
JS
621
622 return true;
623}
624
625/// Create style parameters
626wxString wxRichTextXMLHandler::CreateStyle(const wxTextAttrEx& attr, bool isPara)
627{
628 wxString str;
0ca07313 629 if (attr.HasTextColour() && attr.GetTextColour().Ok())
5d7836c4
JS
630 {
631 str << wxT(" textcolor=\"#") << ColourToHexString(attr.GetTextColour()) << wxT("\"");
632 }
0ca07313 633 if (attr.HasBackgroundColour() && attr.GetBackgroundColour().Ok())
5d7836c4
JS
634 {
635 str << wxT(" bgcolor=\"#") << ColourToHexString(attr.GetBackgroundColour()) << wxT("\"");
636 }
637
638 if (attr.GetFont().Ok())
639 {
0ca07313
JS
640 if (attr.HasSize())
641 str << wxT(" fontsize=\"") << attr.GetFont().GetPointSize() << wxT("\"");
7b907278 642
0ca07313
JS
643 //if (attr.HasFamily())
644 // str << wxT(" fontfamily=\"") << attr.GetFont().GetFamily() << wxT("\"");
645
646 if (attr.HasItalic())
647 str << wxT(" fontstyle=\"") << attr.GetFont().GetStyle() << wxT("\"");
648
649 if (attr.HasWeight())
650 str << wxT(" fontweight=\"") << attr.GetFont().GetWeight() << wxT("\"");
651
652 if (attr.HasUnderlined())
653 str << wxT(" fontunderlined=\"") << (int) attr.GetFont().GetUnderlined() << wxT("\"");
654
655 if (attr.HasFaceName())
656 str << wxT(" fontface=\"") << attr.GetFont().GetFaceName() << wxT("\"");
5d7836c4
JS
657 }
658
7fe8059f 659 if (!attr.GetCharacterStyleName().empty())
5d7836c4
JS
660 str << wxT(" charactertyle=\"") << wxString(attr.GetCharacterStyleName()) << wxT("\"");
661
662 if (isPara)
663 {
0ca07313
JS
664 if (attr.HasAlignment())
665 str << wxT(" alignment=\"") << (int) attr.GetAlignment() << wxT("\"");
666
667 if (attr.HasLeftIndent())
668 {
669 str << wxT(" leftindent=\"") << (int) attr.GetLeftIndent() << wxT("\"");
670 str << wxT(" leftsubindent=\"") << (int) attr.GetLeftSubIndent() << wxT("\"");
671 }
672
673 if (attr.HasRightIndent())
674 str << wxT(" rightindent=\"") << (int) attr.GetRightIndent() << wxT("\"");
675
676 if (attr.HasParagraphSpacingAfter())
677 str << wxT(" parspacingafter=\"") << (int) attr.GetParagraphSpacingAfter() << wxT("\"");
678
679 if (attr.HasParagraphSpacingBefore())
680 str << wxT(" parspacingbefore=\"") << (int) attr.GetParagraphSpacingBefore() << wxT("\"");
681
682 if (attr.HasLineSpacing())
683 str << wxT(" linespacing=\"") << (int) attr.GetLineSpacing() << wxT("\"");
684
685 if (attr.HasBulletStyle())
686 str << wxT(" bulletstyle=\"") << (int) attr.GetBulletStyle() << wxT("\"");
687
688 if (attr.HasBulletNumber())
689 str << wxT(" bulletnumber=\"") << (int) attr.GetBulletNumber() << wxT("\"");
690
691 if (attr.HasBulletSymbol())
7b907278
JS
692 {
693 str << wxT(" bulletsymbol=\"") << (int) (attr.GetBulletSymbol()) << wxT("\"");
694 str << wxT(" bulletfont=\"") << attr.GetBulletFont() << wxT("\"");
695 }
5d7836c4 696
7fe8059f 697 if (!attr.GetParagraphStyleName().empty())
5d7836c4 698 str << wxT(" parstyle=\"") << wxString(attr.GetParagraphStyleName()) << wxT("\"");
7b907278 699
0ca07313
JS
700 if (attr.HasTabs())
701 {
702 str << wxT(" tabs=\"");
703 size_t i;
704 for (i = 0; i < attr.GetTabs().GetCount(); i++)
705 {
706 if (i > 0)
707 str << wxT(",");
708 str << attr.GetTabs()[i];
709 }
7b907278 710 str << wxT("\"");
0ca07313 711 }
5d7836c4
JS
712 }
713
714 return str;
715}
716
717/// Get style parameters
718bool wxRichTextXMLHandler::GetStyle(wxTextAttrEx& attr, wxXmlNode* node, bool isPara)
719{
720 wxString fontFacename;
721 int fontSize = 12;
722 int fontFamily = wxDEFAULT;
723 int fontWeight = wxNORMAL;
724 int fontStyle = wxNORMAL;
725 bool fontUnderlined = false;
7b907278 726
0ca07313
JS
727 int fontFlags = 0;
728
5d7836c4 729 fontFacename = node->GetPropVal(wxT("fontface"), wxEmptyString);
0ca07313
JS
730 if (!fontFacename.IsEmpty())
731 fontFlags |= wxTEXT_ATTR_FONT_FACE;
5d7836c4 732
0ca07313
JS
733 wxString value;
734 //value = node->GetPropVal(wxT("fontfamily"), wxEmptyString);
735 //if (!value.empty())
736 // fontFamily = wxAtoi(value);
5d7836c4
JS
737
738 value = node->GetPropVal(wxT("fontstyle"), wxEmptyString);
7fe8059f 739 if (!value.empty())
0ca07313 740 {
5d7836c4 741 fontStyle = wxAtoi(value);
0ca07313
JS
742 fontFlags |= wxTEXT_ATTR_FONT_ITALIC;
743 }
5d7836c4
JS
744
745 value = node->GetPropVal(wxT("fontsize"), wxEmptyString);
7fe8059f 746 if (!value.empty())
0ca07313 747 {
5d7836c4 748 fontSize = wxAtoi(value);
0ca07313
JS
749 fontFlags |= wxTEXT_ATTR_FONT_SIZE;
750 }
5d7836c4
JS
751
752 value = node->GetPropVal(wxT("fontweight"), wxEmptyString);
7fe8059f 753 if (!value.empty())
0ca07313 754 {
5d7836c4 755 fontWeight = wxAtoi(value);
0ca07313
JS
756 fontFlags |= wxTEXT_ATTR_FONT_WEIGHT;
757 }
5d7836c4
JS
758
759 value = node->GetPropVal(wxT("fontunderlined"), wxEmptyString);
7fe8059f 760 if (!value.empty())
0ca07313 761 {
5d7836c4 762 fontUnderlined = wxAtoi(value) != 0;
0ca07313
JS
763 fontFlags |= wxTEXT_ATTR_FONT_UNDERLINE;
764 }
7b907278 765
0ca07313 766 attr.SetFlags(fontFlags);
7b907278 767
0ca07313
JS
768 if (attr.HasFlag(wxTEXT_ATTR_FONT))
769 attr.SetFont(* wxTheFontList->FindOrCreateFont(fontSize, fontFamily, fontStyle, fontWeight, fontUnderlined, fontFacename));
770
771 // Restore correct font flags
772 attr.SetFlags(fontFlags);
7b907278 773
5d7836c4 774 value = node->GetPropVal(wxT("textcolor"), wxEmptyString);
7fe8059f 775 if (!value.empty())
5d7836c4
JS
776 {
777 if (value[0] == wxT('#'))
778 attr.SetTextColour(HexStringToColour(value.Mid(1)));
779 else
780 attr.SetTextColour(value);
781 }
782
783 value = node->GetPropVal(wxT("backgroundcolor"), wxEmptyString);
7fe8059f 784 if (!value.empty())
5d7836c4
JS
785 {
786 if (value[0] == wxT('#'))
787 attr.SetBackgroundColour(HexStringToColour(value.Mid(1)));
788 else
789 attr.SetBackgroundColour(value);
790 }
791
792 value = node->GetPropVal(wxT("characterstyle"), wxEmptyString);
7fe8059f 793 if (!value.empty())
5d7836c4
JS
794 attr.SetCharacterStyleName(value);
795
796 // Set paragraph attributes
797 if (isPara)
798 {
799 value = node->GetPropVal(wxT("alignment"), wxEmptyString);
7fe8059f 800 if (!value.empty())
5d7836c4
JS
801 attr.SetAlignment((wxTextAttrAlignment) wxAtoi(value));
802
803 int leftSubIndent = 0;
804 int leftIndent = 0;
0ca07313 805 bool hasLeftIndent = false;
7b907278 806
5d7836c4 807 value = node->GetPropVal(wxT("leftindent"), wxEmptyString);
7fe8059f 808 if (!value.empty())
0ca07313 809 {
5d7836c4 810 leftIndent = wxAtoi(value);
0ca07313
JS
811 hasLeftIndent = true;
812 }
813
5d7836c4 814 value = node->GetPropVal(wxT("leftsubindent"), wxEmptyString);
7fe8059f 815 if (!value.empty())
0ca07313 816 {
5d7836c4 817 leftSubIndent = wxAtoi(value);
0ca07313
JS
818 hasLeftIndent = true;
819 }
820
821 if (hasLeftIndent)
822 attr.SetLeftIndent(leftIndent, leftSubIndent);
5d7836c4
JS
823
824 value = node->GetPropVal(wxT("rightindent"), wxEmptyString);
7fe8059f 825 if (!value.empty())
5d7836c4
JS
826 attr.SetRightIndent(wxAtoi(value));
827
828 value = node->GetPropVal(wxT("parspacingbefore"), wxEmptyString);
7fe8059f 829 if (!value.empty())
5d7836c4
JS
830 attr.SetParagraphSpacingBefore(wxAtoi(value));
831
832 value = node->GetPropVal(wxT("parspacingafter"), wxEmptyString);
7fe8059f 833 if (!value.empty())
5d7836c4
JS
834 attr.SetParagraphSpacingAfter(wxAtoi(value));
835
836 value = node->GetPropVal(wxT("linespacing"), wxEmptyString);
7fe8059f 837 if (!value.empty())
5d7836c4
JS
838 attr.SetLineSpacing(wxAtoi(value));
839
840 value = node->GetPropVal(wxT("bulletstyle"), wxEmptyString);
7fe8059f 841 if (!value.empty())
5d7836c4
JS
842 attr.SetBulletStyle(wxAtoi(value));
843
844 value = node->GetPropVal(wxT("bulletnumber"), wxEmptyString);
7fe8059f 845 if (!value.empty())
5d7836c4
JS
846 attr.SetBulletNumber(wxAtoi(value));
847
848 value = node->GetPropVal(wxT("bulletsymbol"), wxEmptyString);
7fe8059f 849 if (!value.empty())
7b907278
JS
850 attr.SetBulletSymbol(wxAtoi(value));
851
852 value = node->GetPropVal(wxT("bulletfont"), wxEmptyString);
853 if (!value.empty())
854 attr.SetBulletFont(value);
5d7836c4
JS
855
856 value = node->GetPropVal(wxT("parstyle"), wxEmptyString);
7fe8059f 857 if (!value.empty())
5d7836c4 858 attr.SetParagraphStyleName(value);
7b907278 859
0ca07313
JS
860 value = node->GetPropVal(wxT("tabs"), wxEmptyString);
861 if (!value.empty())
862 {
863 wxArrayInt tabs;
864 wxStringTokenizer tkz(value, wxT(","));
865 while (tkz.HasMoreTokens())
866 {
867 wxString token = tkz.GetNextToken();
868 tabs.Add(wxAtoi(token));
869 }
870 attr.SetTabs(tabs);
871 }
5d7836c4
JS
872 }
873
874 return true;
875}
876
877#endif
b71e9aa4 878 // wxUSE_STREAMS
88a7a4e1 879
5d7836c4 880#endif
fcdbeefa 881 // wxUSE_RICHTEXT && wxUSE_XML
7b907278 882