Applied #12941: Fixes and enhancements for wxRTC (Robert Hoffman)
[wxWidgets.git] / src / richtext / richtextxml.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/richtext/richtextxml.cpp
3 // Purpose: XML and HTML I/O for wxRichTextCtrl
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 2005-09-30
7 // RCS-ID: $Id$
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__
16 #pragma hdrstop
17 #endif
18
19 #if wxUSE_RICHTEXT && wxUSE_XML
20
21 #include "wx/richtext/richtextxml.h"
22
23 #ifndef WX_PRECOMP
24 #include "wx/intl.h"
25 #include "wx/module.h"
26 #include "wx/log.h"
27 #endif
28
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"
38
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
41 // method.
42 #define wxRICHTEXT_USE_XMLDOCUMENT_OUTPUT 0
43
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.
46 #endif
47
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.
50 #endif
51
52 // Set to 1 to time file saving
53 #define wxRICHTEXT_USE_OUTPUT_TIMINGS 0
54
55 // Convert a colour to a 6-digit hex string
56 static wxString ColourToHexString(const wxColour& col)
57 {
58 wxString hex;
59
60 hex += wxDecToHex(col.Red());
61 hex += wxDecToHex(col.Green());
62 hex += wxDecToHex(col.Blue());
63
64 return hex;
65 }
66
67 // Convert 6-digit hex string to a colour
68 static wxColour HexStringToColour(const wxString& hex)
69 {
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));
73
74 return wxColour(r, g, b);
75 }
76
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); }
82
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); }
89
90 IMPLEMENT_DYNAMIC_CLASS(wxRichTextXMLHandler, wxRichTextFileHandler)
91
92 void wxRichTextXMLHandler::Init()
93 {
94 #if wxRICHTEXT_HAVE_DIRECT_OUTPUT
95 // Used during saving
96 m_convMem = NULL;
97 m_convFile = NULL;
98 #endif
99 }
100
101 #if wxUSE_STREAMS
102 bool wxRichTextXMLHandler::DoLoadFile(wxRichTextBuffer *buffer, wxInputStream& stream)
103 {
104 if (!stream.IsOk())
105 return false;
106
107 buffer->ResetAndClearCommands();
108 buffer->Clear();
109
110 wxXmlDocument* xmlDoc = new wxXmlDocument;
111 bool success = true;
112
113 // This is the encoding to convert to (memory encoding rather than file encoding)
114 wxString encoding(wxT("UTF-8"));
115
116 #if !wxUSE_UNICODE && wxUSE_INTL
117 encoding = wxLocale::GetSystemEncodingName();
118 #endif
119
120 if (!xmlDoc->Load(stream, encoding))
121 {
122 buffer->ResetAndClearCommands();
123 success = false;
124 }
125 else
126 {
127 if (xmlDoc->GetRoot() && xmlDoc->GetRoot()->GetType() == wxXML_ELEMENT_NODE && xmlDoc->GetRoot()->GetName() == wxT("richtext"))
128 {
129 wxXmlNode* child = xmlDoc->GetRoot()->GetChildren();
130 while (child)
131 {
132 if (child->GetType() == wxXML_ELEMENT_NODE)
133 {
134 wxString name = child->GetName();
135 if (name == wxT("richtext-version"))
136 {
137 }
138 else
139 ImportXML(buffer, buffer, child);
140 }
141
142 child = child->GetNext();
143 }
144 }
145 else
146 {
147 success = false;
148 }
149 }
150
151 delete xmlDoc;
152
153 buffer->UpdateRanges();
154
155 return success;
156 }
157
158 /// Creates an object given an XML element name
159 wxRichTextObject* wxRichTextXMLHandler::CreateObjectForXMLName(wxRichTextObject* WXUNUSED(parent), const wxString& name) const
160 {
161 if (name == wxT("text") || name == wxT("symbol"))
162 return new wxRichTextPlainText;
163 else if (name == wxT("image"))
164 return new wxRichTextImage;
165 else if (name == wxT("paragraph"))
166 return new wxRichTextParagraph;
167 else if (name == wxT("paragraphlayout"))
168 return new wxRichTextParagraphLayoutBox;
169 else if (name == wxT("textbox"))
170 return new wxRichTextBox;
171 else if (name == wxT("cell"))
172 return new wxRichTextCell;
173 else if (name == wxT("table"))
174 return new wxRichTextTable;
175 else
176 return NULL;
177 }
178
179 /// Recursively import an object
180 bool wxRichTextXMLHandler::ImportXML(wxRichTextBuffer* buffer, wxRichTextObject* obj, wxXmlNode* node)
181 {
182 bool recurse = false;
183 obj->ImportFromXML(buffer, node, this, & recurse);
184
185 // TODO: how to control whether to import children.
186
187 wxRichTextCompositeObject* compositeParent = wxDynamicCast(obj, wxRichTextCompositeObject);
188 if (recurse && compositeParent)
189 {
190 wxXmlNode* child = node->GetChildren();
191 while (child)
192 {
193 if (child->GetName() != wxT("stylesheet"))
194 {
195 wxRichTextObject* childObj = CreateObjectForXMLName(obj, child->GetName());
196 if (childObj)
197 {
198 compositeParent->AppendChild(childObj);
199 ImportXML(buffer, childObj, child);
200 }
201 }
202 child = child->GetNext();
203 }
204 }
205
206 return true;
207 }
208
209 bool wxRichTextXMLHandler::ImportProperties(wxRichTextObject* obj, wxXmlNode* node)
210 {
211 wxXmlNode* child = node->GetChildren();
212 while (child)
213 {
214 if (child->GetName() == wxT("properties"))
215 {
216 wxXmlNode* propertyChild = child->GetChildren();
217 while (propertyChild)
218 {
219 if (propertyChild->GetName() == wxT("property"))
220 {
221 wxString name = propertyChild->GetAttribute(wxT("name"), wxEmptyString);
222 wxString value = propertyChild->GetAttribute(wxT("value"), wxEmptyString);
223 wxString type = propertyChild->GetAttribute(wxT("type"), wxEmptyString);
224
225 wxVariant var = MakePropertyFromString(name, value, type);
226 if (!var.IsNull())
227 {
228 obj->GetProperties().SetProperty(var);
229 }
230 }
231 propertyChild = propertyChild->GetNext();
232 }
233 }
234 child = child->GetNext();
235 }
236 return true;
237 }
238
239 bool wxRichTextXMLHandler::ImportStyleDefinition(wxRichTextStyleSheet* sheet, wxXmlNode* node)
240 {
241 wxString styleType = node->GetName();
242 wxString styleName = node->GetAttribute(wxT("name"), wxEmptyString);
243 wxString baseStyleName = node->GetAttribute(wxT("basestyle"), wxEmptyString);
244
245 if (styleName.empty())
246 return false;
247
248 if (styleType == wxT("characterstyle"))
249 {
250 wxRichTextCharacterStyleDefinition* def = new wxRichTextCharacterStyleDefinition(styleName);
251 def->SetBaseStyle(baseStyleName);
252
253 wxXmlNode* child = node->GetChildren();
254 while (child)
255 {
256 if (child->GetName() == wxT("style"))
257 {
258 wxRichTextAttr attr;
259 ImportStyle(attr, child, false);
260 def->SetStyle(attr);
261 }
262 child = child->GetNext();
263 }
264
265 sheet->AddCharacterStyle(def);
266 }
267 else if (styleType == wxT("paragraphstyle"))
268 {
269 wxRichTextParagraphStyleDefinition* def = new wxRichTextParagraphStyleDefinition(styleName);
270
271 wxString nextStyleName = node->GetAttribute(wxT("nextstyle"), wxEmptyString);
272 def->SetNextStyle(nextStyleName);
273 def->SetBaseStyle(baseStyleName);
274
275 wxXmlNode* child = node->GetChildren();
276 while (child)
277 {
278 if (child->GetName() == wxT("style"))
279 {
280 wxRichTextAttr attr;
281 ImportStyle(attr, child, true);
282 def->SetStyle(attr);
283 }
284 child = child->GetNext();
285 }
286
287 sheet->AddParagraphStyle(def);
288 }
289 else if (styleType == wxT("boxstyle"))
290 {
291 wxRichTextBoxStyleDefinition* def = new wxRichTextBoxStyleDefinition(styleName);
292
293 def->SetBaseStyle(baseStyleName);
294
295 wxXmlNode* child = node->GetChildren();
296 while (child)
297 {
298 if (child->GetName() == wxT("style"))
299 {
300 wxRichTextAttr attr;
301 ImportStyle(attr, child, true);
302 def->SetStyle(attr);
303 }
304 child = child->GetNext();
305 }
306
307 sheet->AddBoxStyle(def);
308 }
309 else if (styleType == wxT("liststyle"))
310 {
311 wxRichTextListStyleDefinition* def = new wxRichTextListStyleDefinition(styleName);
312
313 wxString nextStyleName = node->GetAttribute(wxT("nextstyle"), wxEmptyString);
314 def->SetNextStyle(nextStyleName);
315 def->SetBaseStyle(baseStyleName);
316
317 wxXmlNode* child = node->GetChildren();
318 while (child)
319 {
320 if (child->GetName() == wxT("style"))
321 {
322 wxRichTextAttr attr;
323 ImportStyle(attr, child, true);
324
325 wxString styleLevel = child->GetAttribute(wxT("level"), wxEmptyString);
326 if (styleLevel.empty())
327 {
328 def->SetStyle(attr);
329 }
330 else
331 {
332 int level = wxAtoi(styleLevel);
333 if (level > 0 && level <= 10)
334 {
335 def->SetLevelAttributes(level-1, attr);
336 }
337 }
338 }
339 child = child->GetNext();
340 }
341
342 sheet->AddListStyle(def);
343 }
344
345 return true;
346 }
347
348 //-----------------------------------------------------------------------------
349 // xml support routines
350 //-----------------------------------------------------------------------------
351
352 bool wxRichTextXMLHandler::HasParam(wxXmlNode* node, const wxString& param)
353 {
354 return (GetParamNode(node, param) != NULL);
355 }
356
357 wxXmlNode *wxRichTextXMLHandler::GetParamNode(wxXmlNode* node, const wxString& param)
358 {
359 wxCHECK_MSG(node, NULL, wxT("You can't access node data before it was initialized!"));
360
361 wxXmlNode *n = node->GetChildren();
362
363 while (n)
364 {
365 if (n->GetType() == wxXML_ELEMENT_NODE && n->GetName() == param)
366 return n;
367 n = n->GetNext();
368 }
369 return NULL;
370 }
371
372
373 wxString wxRichTextXMLHandler::GetNodeContent(wxXmlNode *node)
374 {
375 wxXmlNode *n = node;
376 if (n == NULL) return wxEmptyString;
377 n = n->GetChildren();
378
379 while (n)
380 {
381 if (n->GetType() == wxXML_TEXT_NODE ||
382 n->GetType() == wxXML_CDATA_SECTION_NODE)
383 return n->GetContent();
384 n = n->GetNext();
385 }
386 return wxEmptyString;
387 }
388
389
390 wxString wxRichTextXMLHandler::GetParamValue(wxXmlNode *node, const wxString& param)
391 {
392 if (param.empty())
393 return GetNodeContent(node);
394 else
395 return GetNodeContent(GetParamNode(node, param));
396 }
397
398 wxString wxRichTextXMLHandler::GetText(wxXmlNode *node, const wxString& param, bool WXUNUSED(translate))
399 {
400 wxXmlNode *parNode = GetParamNode(node, param);
401 if (!parNode)
402 parNode = node;
403 wxString str1(GetNodeContent(parNode));
404 return str1;
405 }
406
407 wxXmlNode* wxRichTextXMLHandler::FindNode(wxXmlNode* node, const wxString& name)
408 {
409 if (node->GetName() == name && name == wxT("stylesheet"))
410 return node;
411
412 wxXmlNode* child = node->GetChildren();
413 while (child)
414 {
415 if (child->GetName() == name)
416 return child;
417 child = child->GetNext();
418 }
419 return NULL;
420 }
421
422 // For use with earlier versions of wxWidgets
423 #ifndef WXUNUSED_IN_UNICODE
424 #if wxUSE_UNICODE
425 #define WXUNUSED_IN_UNICODE(x) WXUNUSED(x)
426 #else
427 #define WXUNUSED_IN_UNICODE(x) x
428 #endif
429 #endif
430
431 // write string to output
432 inline static void OutputString(wxOutputStream& stream, const wxString& str,
433 wxMBConv *WXUNUSED_IN_UNICODE(convMem), wxMBConv *convFile)
434 {
435 if (str.empty()) return;
436 #if wxUSE_UNICODE
437 if (convFile)
438 {
439 const wxWX2MBbuf buf(str.mb_str(*convFile));
440 stream.Write((const char*)buf, strlen((const char*)buf));
441 }
442 else
443 {
444 const wxWX2MBbuf buf(str.mb_str(wxConvUTF8));
445 stream.Write((const char*)buf, strlen((const char*)buf));
446 }
447 #else
448 if ( convFile == NULL )
449 stream.Write(str.mb_str(), str.Len());
450 else
451 {
452 wxString str2(str.wc_str(*convMem), *convFile);
453 stream.Write(str2.mb_str(), str2.Len());
454 }
455 #endif
456 }
457
458 static void OutputIndentation(wxOutputStream& stream, int indent)
459 {
460 wxString str = wxT("\n");
461 for (int i = 0; i < indent; i++)
462 str << wxT(' ') << wxT(' ');
463 ::OutputString(stream, str, NULL, NULL);
464 }
465
466 // Same as above, but create entities first.
467 // Translates '<' to "&lt;", '>' to "&gt;" and '&' to "&amp;"
468 static void OutputStringEnt(wxOutputStream& stream, const wxString& str,
469 wxMBConv *convMem = NULL, wxMBConv *convFile = NULL)
470 {
471 wxString buf;
472 size_t i, last, len;
473 wxChar c;
474
475 len = str.Len();
476 last = 0;
477 for (i = 0; i < len; i++)
478 {
479 c = str.GetChar(i);
480
481 // Original code excluded "&amp;" but we _do_ want to convert
482 // the ampersand beginning &amp; because otherwise when read in,
483 // the original "&amp;" becomes "&".
484
485 if (c == wxT('<') || c == wxT('>') || c == wxT('"') ||
486 (c == wxT('&') /* && (str.Mid(i+1, 4) != wxT("amp;")) */ ))
487 {
488 OutputString(stream, str.Mid(last, i - last), convMem, convFile);
489 switch (c)
490 {
491 case wxT('<'):
492 OutputString(stream, wxT("&lt;"), NULL, NULL);
493 break;
494 case wxT('>'):
495 OutputString(stream, wxT("&gt;"), NULL, NULL);
496 break;
497 case wxT('&'):
498 OutputString(stream, wxT("&amp;"), NULL, NULL);
499 break;
500 case wxT('"'):
501 OutputString(stream, wxT("&quot;"), NULL, NULL);
502 break;
503 default: break;
504 }
505 last = i + 1;
506 }
507 else if (wxUChar(c) > 127)
508 {
509 OutputString(stream, str.Mid(last, i - last), convMem, convFile);
510
511 wxString s(wxT("&#"));
512 #if wxUSE_UNICODE
513 s << (int) c;
514 #else
515 s << (int) wxUChar(c);
516 #endif
517 s << wxT(";");
518 OutputString(stream, s, NULL, NULL);
519 last = i + 1;
520 }
521 }
522 OutputString(stream, str.Mid(last, i - last), convMem, convFile);
523 }
524
525 void wxRichTextXMLHandler::OutputString(wxOutputStream& stream, const wxString& str)
526 {
527 ::OutputString(stream, str, m_convMem, m_convFile);
528 }
529
530 void wxRichTextXMLHandler::OutputStringEnt(wxOutputStream& stream, const wxString& str)
531 {
532 ::OutputStringEnt(stream, str, m_convMem, m_convFile);
533 }
534
535 void wxRichTextXMLHandler::OutputIndentation(wxOutputStream& stream, int indent)
536 {
537 wxString str = wxT("\n");
538 for (int i = 0; i < indent; i++)
539 str << wxT(' ') << wxT(' ');
540 ::OutputString(stream, str, NULL, NULL);
541 }
542
543 wxString wxRichTextXMLHandler::AttributeToXML(const wxString& str)
544 {
545 wxString str1;
546 size_t i, last, len;
547 wxChar c;
548
549 len = str.Len();
550 last = 0;
551 for (i = 0; i < len; i++)
552 {
553 c = str.GetChar(i);
554
555 // Original code excluded "&amp;" but we _do_ want to convert
556 // the ampersand beginning &amp; because otherwise when read in,
557 // the original "&amp;" becomes "&".
558
559 if (c == wxT('<') || c == wxT('>') || c == wxT('"') ||
560 (c == wxT('&') /* && (str.Mid(i+1, 4) != wxT("amp;")) */ ))
561 {
562 str1 += str.Mid(last, i - last);
563 switch (c)
564 {
565 case wxT('<'):
566 str1 += wxT("&lt;");
567 break;
568 case wxT('>'):
569 str1 += wxT("&gt;");
570 break;
571 case wxT('&'):
572 str1 += wxT("&amp;");
573 break;
574 case wxT('"'):
575 str1 += wxT("&quot;");
576 break;
577 default: break;
578 }
579 last = i + 1;
580 }
581 else if (wxUChar(c) > 127)
582 {
583 str1 += str.Mid(last, i - last);
584
585 wxString s(wxT("&#"));
586 #if wxUSE_UNICODE
587 s << (int) c;
588 #else
589 s << (int) wxUChar(c);
590 #endif
591 s << wxT(";");
592 str1 += s;
593 last = i + 1;
594 }
595 }
596 str1 += str.Mid(last, i - last);
597 return str1;
598 }
599
600 #if wxRICHTEXT_HAVE_DIRECT_OUTPUT
601
602 static inline void AddAttribute(wxString& str, const wxString& name, const int& v)
603 {
604 str << wxT(" ") << name << wxT("=\"") << wxString::Format(wxT("%d"), v) << wxT("\"");
605 }
606
607 static inline void AddAttribute(wxString& str, const wxString& name, const long& v)
608 {
609 str << wxT(" ") << name << wxT("=\"") << wxString::Format(wxT("%ld"), v) << wxT("\"");
610 }
611
612 static inline void AddAttribute(wxString& str, const wxString& name, const double& v)
613 {
614 str << wxT(" ") << name << wxT("=\"") << wxString::Format(wxT("%.2f"), (float) v) << wxT("\"");
615 }
616
617 static inline void AddAttribute(wxString& str, const wxString& name, const wxChar* s)
618 {
619 str << wxT(" ") << name << wxT("=\"") << s << wxT("\"");
620 }
621
622 static inline void AddAttribute(wxString& str, const wxString& name, const wxString& s)
623 {
624 str << wxT(" ") << name << wxT("=\"") << s << wxT("\"");
625 }
626
627 static inline void AddAttribute(wxString& str, const wxString& name, const wxColour& col)
628 {
629 str << wxT(" ") << name << wxT("=\"") << wxT("#") << ColourToHexString(col) << wxT("\"");
630 }
631
632 static inline void AddAttribute(wxString& str, const wxString& name, const wxTextAttrDimension& dim)
633 {
634 if (dim.IsValid())
635 {
636 wxString value = MakeString(dim.GetValue()) + wxT(",") + MakeString((int) dim.GetFlags());
637 str << wxT(" ") << name << wxT("=\"");
638 str << value;
639 str << wxT("\"");
640 }
641 }
642
643 static inline void AddAttribute(wxString& str, const wxString& rootName, const wxTextAttrDimensions& dims)
644 {
645 if (dims.GetLeft().IsValid())
646 AddAttribute(str, rootName + wxString(wxT("-left")), dims.GetLeft());
647 if (dims.GetRight().IsValid())
648 AddAttribute(str, rootName + wxString(wxT("-right")), dims.GetRight());
649 if (dims.GetTop().IsValid())
650 AddAttribute(str, rootName + wxString(wxT("-top")), dims.GetTop());
651 if (dims.GetBottom().IsValid())
652 AddAttribute(str, rootName + wxString(wxT("-bottom")), dims.GetBottom());
653 }
654
655 static inline void AddAttribute(wxString& str, const wxString& rootName, const wxTextAttrBorder& border)
656 {
657 if (border.HasStyle())
658 AddAttribute(str, rootName + wxString(wxT("-style")), border.GetStyle());
659 if (border.HasColour())
660 AddAttribute(str, rootName + wxString(wxT("-color")), border.GetColour());
661 if (border.HasWidth())
662 AddAttribute(str, rootName + wxString(wxT("-width")), border.GetWidth());
663 }
664
665 static inline void AddAttribute(wxString& str, const wxString& rootName, const wxTextAttrBorders& borders)
666 {
667 AddAttribute(str, rootName + wxString(wxT("-left")), borders.GetLeft());
668 AddAttribute(str, rootName + wxString(wxT("-right")), borders.GetRight());
669 AddAttribute(str, rootName + wxString(wxT("-top")), borders.GetTop());
670 AddAttribute(str, rootName + wxString(wxT("-bottom")), borders.GetBottom());
671 }
672
673 #endif
674 // wxRICHTEXT_HAVE_DIRECT_OUTPUT
675
676 #if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
677
678 static inline void AddAttribute(wxXmlNode* node, const wxString& name, const int& v)
679 {
680 node->AddAttribute(name, MakeString(v));
681 }
682
683 static inline void AddAttribute(wxXmlNode* node, const wxString& name, const long& v)
684 {
685 node->AddAttribute(name, MakeString(v));
686 }
687
688 static inline void AddAttribute(wxXmlNode* node, const wxString& name, const double& v)
689 {
690 node->AddAttribute(name, MakeString(v));
691 }
692
693 static inline void AddAttribute(wxXmlNode* node, const wxString& name, const wxString& s)
694 {
695 node->AddAttribute(name, s);
696 }
697
698 static inline void AddAttribute(wxXmlNode* node, const wxString& name, const wxColour& col)
699 {
700 node->AddAttribute(name, MakeString(col));
701 }
702
703 static inline void AddAttribute(wxXmlNode* node, const wxString& name, const wxTextAttrDimension& dim)
704 {
705 if (dim.IsValid())
706 {
707 wxString value = MakeString(dim.GetValue()) + wxT(",") + MakeString(dim.GetFlags());
708 AddAttribute(node, name, value);
709 }
710 }
711
712 static inline void AddAttribute(wxXmlNode* node, const wxString& rootName, const wxTextAttrDimensions& dims)
713 {
714 if (dims.GetLeft().IsValid())
715 AddAttribute(node, rootName + wxString(wxT("-left")), dims.GetLeft());
716 if (dims.GetRight().IsValid())
717 AddAttribute(node, rootName + wxString(wxT("-right")), dims.GetRight());
718 if (dims.GetTop().IsValid())
719 AddAttribute(node, rootName + wxString(wxT("-top")), dims.GetTop());
720 if (dims.GetBottom().IsValid())
721 AddAttribute(node, rootName + wxString(wxT("-bottom")), dims.GetBottom());
722 }
723
724 static inline void AddAttribute(wxXmlNode* node, const wxString& rootName, const wxTextAttrBorder& border)
725 {
726 if (border.HasStyle())
727 AddAttribute(node, rootName + wxString(wxT("-style")), border.GetStyle());
728 if (border.HasColour())
729 AddAttribute(node, rootName + wxString(wxT("-color")), border.GetColour());
730 if (border.HasWidth())
731 AddAttribute(node, rootName + wxString(wxT("-width")), border.GetWidth());
732 }
733
734 static inline void AddAttribute(wxXmlNode* node, const wxString& rootName, const wxTextAttrBorders& borders)
735 {
736 AddAttribute(node, rootName + wxString(wxT("-left")), borders.GetLeft());
737 AddAttribute(node, rootName + wxString(wxT("-right")), borders.GetRight());
738 AddAttribute(node, rootName + wxString(wxT("-top")), borders.GetTop());
739 AddAttribute(node, rootName + wxString(wxT("-bottom")), borders.GetBottom());
740 }
741 #endif
742 // wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
743
744 bool wxRichTextXMLHandler::DoSaveFile(wxRichTextBuffer *buffer, wxOutputStream& stream)
745 {
746 if (!stream.IsOk())
747 return false;
748
749 wxString version(wxT("1.0") ) ;
750
751 bool deleteConvFile = false;
752 wxString fileEncoding;
753 //wxMBConv* convFile = NULL;
754
755 #if wxUSE_UNICODE
756 fileEncoding = wxT("UTF-8");
757 m_convFile = & wxConvUTF8;
758 #else
759 fileEncoding = wxT("ISO-8859-1");
760 m_convFile = & wxConvISO8859_1;
761 #endif
762
763 // If SetEncoding has been called, change the output encoding.
764 if (!m_encoding.empty() && m_encoding.Lower() != fileEncoding.Lower())
765 {
766 if (m_encoding == wxT("<System>"))
767 {
768 #if wxUSE_INTL
769 fileEncoding = wxLocale::GetSystemEncodingName();
770 // if !wxUSE_INTL, we fall back to UTF-8 or ISO-8859-1 below
771 #endif
772 }
773 else
774 {
775 fileEncoding = m_encoding;
776 }
777
778 // GetSystemEncodingName may not have returned a name
779 if (fileEncoding.empty())
780 #if wxUSE_UNICODE
781 fileEncoding = wxT("UTF-8");
782 #else
783 fileEncoding = wxT("ISO-8859-1");
784 #endif
785 m_convFile = new wxCSConv(fileEncoding);
786 deleteConvFile = true;
787 }
788
789 #if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT && wxRICHTEXT_USE_XMLDOCUMENT_OUTPUT
790 #if wxRICHTEXT_USE_OUTPUT_TIMINGS
791 wxStopWatch stopwatch;
792 #endif
793 wxXmlDocument* doc = new wxXmlDocument;
794 doc->SetFileEncoding(fileEncoding);
795
796 wxXmlNode* rootNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("richtext"));
797 doc->SetRoot(rootNode);
798 rootNode->AddAttribute(wxT("version"), wxT("1.0.0.0"));
799 rootNode->AddAttribute(wxT("xmlns"), wxT("http://www.wxwidgets.org"));
800
801 if (buffer->GetStyleSheet() && (GetFlags() & wxRICHTEXT_HANDLER_INCLUDE_STYLESHEET))
802 {
803 wxXmlNode* styleSheetNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("stylesheet"));
804 rootNode->AddChild(styleSheetNode);
805
806 wxString nameAndDescr;
807
808 if (!buffer->GetStyleSheet()->GetName().empty())
809 styleSheetNode->AddAttribute(wxT("name"), buffer->GetStyleSheet()->GetName());
810
811 if (!buffer->GetStyleSheet()->GetDescription().empty())
812 styleSheetNode->AddAttribute(wxT("description"), buffer->GetStyleSheet()->GetDescription());
813
814 int i;
815 for (i = 0; i < (int) buffer->GetStyleSheet()->GetCharacterStyleCount(); i++)
816 {
817 wxRichTextCharacterStyleDefinition* def = buffer->GetStyleSheet()->GetCharacterStyle(i);
818 ExportStyleDefinition(styleSheetNode, def);
819 }
820
821 for (i = 0; i < (int) buffer->GetStyleSheet()->GetParagraphStyleCount(); i++)
822 {
823 wxRichTextParagraphStyleDefinition* def = buffer->GetStyleSheet()->GetParagraphStyle(i);
824 ExportStyleDefinition(styleSheetNode, def);
825 }
826
827 for (i = 0; i < (int) buffer->GetStyleSheet()->GetListStyleCount(); i++)
828 {
829 wxRichTextListStyleDefinition* def = buffer->GetStyleSheet()->GetListStyle(i);
830 ExportStyleDefinition(styleSheetNode, def);
831 }
832
833 for (i = 0; i < (int) buffer->GetStyleSheet()->GetBoxStyleCount(); i++)
834 {
835 wxRichTextBoxStyleDefinition* def = buffer->GetStyleSheet()->GetBoxStyle(i);
836 ExportStyleDefinition(styleSheetNode, def);
837 }
838 }
839 bool success = ExportXML(rootNode, *buffer);
840 #if wxRICHTEXT_USE_OUTPUT_TIMINGS
841 long t = stopwatch.Time();
842 wxLogDebug(wxT("Creating the document took %ldms"), t);
843 wxMessageBox(wxString::Format(wxT("Creating the document took %ldms"), t));
844 #endif
845 if (success)
846 {
847 #if wxRICHTEXT_USE_OUTPUT_TIMINGS
848 wxStopWatch s2;
849 #endif
850 success = doc->Save(stream);
851 #if wxRICHTEXT_USE_OUTPUT_TIMINGS
852 long t2 = s2.Time();
853 wxLogDebug(wxT("Save() took %ldms"), t2);
854 wxMessageBox(wxString::Format(wxT("Save() took %ldms"), t2));
855 #endif
856 }
857 delete doc;
858 doc = NULL;
859
860 #else
861 // !(wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT && wxRICHTEXT_USE_XMLDOCUMENT_OUTPUT)
862
863 #if !wxUSE_UNICODE
864 m_convMem = wxConvCurrent;
865 #else
866 m_convMem = NULL;
867 #endif
868
869 wxString s ;
870 s.Printf(wxT("<?xml version=\"%s\" encoding=\"%s\"?>\n"),
871 version, fileEncoding);
872 OutputString(stream, s);
873 OutputString(stream, wxT("<richtext version=\"1.0.0.0\" xmlns=\"http://www.wxwidgets.org\">"));
874
875 int level = 1;
876
877 if (buffer->GetStyleSheet() && (GetFlags() & wxRICHTEXT_HANDLER_INCLUDE_STYLESHEET))
878 {
879 OutputIndentation(stream, level);
880 wxString nameAndDescr;
881 if (!buffer->GetStyleSheet()->GetName().empty())
882 nameAndDescr << wxT(" name=\"") << buffer->GetStyleSheet()->GetName() << wxT("\"");
883 if (!buffer->GetStyleSheet()->GetDescription().empty())
884 nameAndDescr << wxT(" description=\"") << buffer->GetStyleSheet()->GetDescription() << wxT("\"");
885 OutputString(stream, wxString(wxT("<stylesheet")) + nameAndDescr + wxT(">"));
886
887 int i;
888
889 for (i = 0; i < (int) buffer->GetStyleSheet()->GetCharacterStyleCount(); i++)
890 {
891 wxRichTextCharacterStyleDefinition* def = buffer->GetStyleSheet()->GetCharacterStyle(i);
892 ExportStyleDefinition(stream, def, level + 1);
893 }
894
895 for (i = 0; i < (int) buffer->GetStyleSheet()->GetParagraphStyleCount(); i++)
896 {
897 wxRichTextParagraphStyleDefinition* def = buffer->GetStyleSheet()->GetParagraphStyle(i);
898 ExportStyleDefinition(stream, def, level + 1);
899 }
900
901 for (i = 0; i < (int) buffer->GetStyleSheet()->GetListStyleCount(); i++)
902 {
903 wxRichTextListStyleDefinition* def = buffer->GetStyleSheet()->GetListStyle(i);
904 ExportStyleDefinition(stream, def, level + 1);
905 }
906
907 for (i = 0; i < (int) buffer->GetStyleSheet()->GetBoxStyleCount(); i++)
908 {
909 wxRichTextBoxStyleDefinition* def = buffer->GetStyleSheet()->GetBoxStyle(i);
910 ExportStyleDefinition(stream, def, level + 1);
911 }
912
913 OutputIndentation(stream, level);
914 OutputString(stream, wxT("</stylesheet>"));
915 }
916
917
918 bool success = ExportXML(stream, *buffer, level);
919
920 OutputString(stream, wxT("\n</richtext>"));
921 OutputString(stream, wxT("\n"));
922
923 if (deleteConvFile)
924 delete m_convFile;
925 m_convFile = NULL;
926 m_convMem = NULL;
927 #endif
928
929 return success;
930 }
931
932 #if wxRICHTEXT_HAVE_DIRECT_OUTPUT
933
934 /// Recursively export an object
935 bool wxRichTextXMLHandler::ExportXML(wxOutputStream& stream, wxRichTextObject& obj, int indent)
936 {
937 obj.ExportXML(stream, indent, this);
938
939 return true;
940 }
941
942 bool wxRichTextXMLHandler::ExportStyleDefinition(wxOutputStream& stream, wxRichTextStyleDefinition* def, int level)
943 {
944 wxRichTextCharacterStyleDefinition* charDef = wxDynamicCast(def, wxRichTextCharacterStyleDefinition);
945 wxRichTextParagraphStyleDefinition* paraDef = wxDynamicCast(def, wxRichTextParagraphStyleDefinition);
946 wxRichTextListStyleDefinition* listDef = wxDynamicCast(def, wxRichTextListStyleDefinition);
947 wxRichTextBoxStyleDefinition* boxDef = wxDynamicCast(def, wxRichTextBoxStyleDefinition);
948
949 wxString name = def->GetName();
950 wxString nameProp;
951 if (!name.empty())
952 nameProp = wxT(" name=\"") + name + wxT("\"");
953
954 wxString baseStyle = def->GetBaseStyle();
955 wxString baseStyleProp;
956 if (!baseStyle.empty())
957 baseStyleProp = wxT(" basestyle=\"") + baseStyle + wxT("\"");
958
959 wxString descr = def->GetDescription();
960 wxString descrProp;
961 if (!descr.empty())
962 descrProp = wxT(" description=\"") + descr + wxT("\"");
963
964 if (charDef)
965 {
966 OutputIndentation(stream, level);
967 OutputString(stream, wxT("<characterstyle") + nameProp + baseStyleProp + descrProp + wxT(">"));
968
969 level ++;
970
971 wxString style = AddAttributes(def->GetStyle(), false);
972
973 OutputIndentation(stream, level);
974 OutputString(stream, wxT("<style ") + style + wxT(">"));
975
976 OutputIndentation(stream, level);
977 OutputString(stream, wxT("</style>"));
978
979 level --;
980
981 OutputIndentation(stream, level);
982 OutputString(stream, wxT("</characterstyle>"));
983 }
984 else if (listDef)
985 {
986 OutputIndentation(stream, level);
987
988 if (!listDef->GetNextStyle().empty())
989 baseStyleProp << wxT(" nextstyle=\"") << listDef->GetNextStyle() << wxT("\"");
990
991 OutputString(stream, wxT("<liststyle") + nameProp + baseStyleProp + descrProp + wxT(">"));
992
993 level ++;
994
995 wxString style = AddAttributes(def->GetStyle(), true);
996
997 OutputIndentation(stream, level);
998 OutputString(stream, wxT("<style ") + style + wxT(">"));
999
1000 OutputIndentation(stream, level);
1001 OutputString(stream, wxT("</style>"));
1002
1003 int i;
1004 for (i = 0; i < 10; i ++)
1005 {
1006 wxRichTextAttr* levelAttr = listDef->GetLevelAttributes(i);
1007 if (levelAttr)
1008 {
1009 wxString style = AddAttributes(def->GetStyle(), true);
1010 wxString levelStr = wxString::Format(wxT(" level=\"%d\" "), (i+1));
1011
1012 OutputIndentation(stream, level);
1013 OutputString(stream, wxT("<style ") + levelStr + style + wxT(">"));
1014
1015 OutputIndentation(stream, level);
1016 OutputString(stream, wxT("</style>"));
1017 }
1018 }
1019
1020 level --;
1021
1022 OutputIndentation(stream, level);
1023 OutputString(stream, wxT("</liststyle>"));
1024 }
1025 else if (paraDef)
1026 {
1027 OutputIndentation(stream, level);
1028
1029 if (!paraDef->GetNextStyle().empty())
1030 baseStyleProp << wxT(" nextstyle=\"") << paraDef->GetNextStyle() << wxT("\"");
1031
1032 OutputString(stream, wxT("<paragraphstyle") + nameProp + baseStyleProp + descrProp + wxT(">"));
1033
1034 level ++;
1035
1036 wxString style = AddAttributes(def->GetStyle(), true);
1037
1038 OutputIndentation(stream, level);
1039 OutputString(stream, wxT("<style ") + style + wxT(">"));
1040
1041 OutputIndentation(stream, level);
1042 OutputString(stream, wxT("</style>"));
1043
1044 level --;
1045
1046 OutputIndentation(stream, level);
1047 OutputString(stream, wxT("</paragraphstyle>"));
1048 }
1049 else if (boxDef)
1050 {
1051 OutputIndentation(stream, level);
1052
1053 OutputString(stream, wxT("<boxstyle") + nameProp + baseStyleProp + descrProp + wxT(">"));
1054
1055 level ++;
1056
1057 wxString style = AddAttributes(def->GetStyle(), true);
1058
1059 OutputIndentation(stream, level);
1060 OutputString(stream, wxT("<style ") + style + wxT(">"));
1061
1062 OutputIndentation(stream, level);
1063 OutputString(stream, wxT("</style>"));
1064
1065 level --;
1066
1067 OutputIndentation(stream, level);
1068 OutputString(stream, wxT("</boxstyle>"));
1069 }
1070
1071
1072 return true;
1073 }
1074
1075 /// Create a string containing style attributes
1076 wxString wxRichTextXMLHandler::AddAttributes(const wxRichTextAttr& attr, bool isPara)
1077 {
1078 wxString str;
1079 if (attr.HasTextColour() && attr.GetTextColour().Ok())
1080 AddAttribute(str, wxT("textcolor"), attr.GetTextColour());
1081
1082 if (attr.HasBackgroundColour() && attr.GetBackgroundColour().Ok())
1083 AddAttribute(str, wxT("bgcolor"), attr.GetBackgroundColour());
1084
1085 if (attr.HasFontSize())
1086 AddAttribute(str, wxT("fontsize"), attr.GetFontSize());
1087
1088 if (attr.HasFontFamily())
1089 AddAttribute(str, wxT("fontfamily"), attr.GetFontFamily());
1090
1091 if (attr.HasFontItalic())
1092 AddAttribute(str, wxT("fontstyle"), attr.GetFontStyle());
1093
1094 if (attr.HasFontWeight())
1095 AddAttribute(str, wxT("fontweight"), attr.GetFontWeight());
1096
1097 if (attr.HasFontUnderlined())
1098 AddAttribute(str, wxT("fontunderlined"), (int) attr.GetFontUnderlined());
1099
1100 if (attr.HasFontFaceName())
1101 AddAttribute(str, wxT("fontface"), attr.GetFontFaceName());
1102
1103 if (attr.HasTextEffects())
1104 {
1105 AddAttribute(str, wxT("texteffects"), attr.GetTextEffects());
1106 AddAttribute(str, wxT("texteffectflags"), attr.GetTextEffectFlags());
1107 }
1108
1109 if (!attr.GetCharacterStyleName().empty())
1110 AddAttribute(str, wxT("characterstyle"), attr.GetCharacterStyleName());
1111
1112 if (attr.HasURL())
1113 AddAttribute(str, wxT("url"), AttributeToXML(attr.GetURL()));
1114
1115 if (isPara)
1116 {
1117 if (attr.HasAlignment())
1118 AddAttribute(str, wxT("alignment"), (int) attr.GetAlignment());
1119
1120 if (attr.HasLeftIndent())
1121 {
1122 AddAttribute(str, wxT("leftindent"), (int) attr.GetLeftIndent());
1123 AddAttribute(str, wxT("leftsubindent"), (int) attr.GetLeftSubIndent());
1124 }
1125
1126 if (attr.HasRightIndent())
1127 AddAttribute(str, wxT("rightindent"), (int) attr.GetRightIndent());
1128
1129 if (attr.HasParagraphSpacingAfter())
1130 AddAttribute(str, wxT("parspacingafter"), (int) attr.GetParagraphSpacingAfter());
1131
1132 if (attr.HasParagraphSpacingBefore())
1133 AddAttribute(str, wxT("parspacingbefore"), (int) attr.GetParagraphSpacingBefore());
1134
1135 if (attr.HasLineSpacing())
1136 AddAttribute(str, wxT("linespacing"), (int) attr.GetLineSpacing());
1137
1138 if (attr.HasBulletStyle())
1139 AddAttribute(str, wxT("bulletstyle"), (int) attr.GetBulletStyle());
1140
1141 if (attr.HasBulletNumber())
1142 AddAttribute(str, wxT("bulletnumber"), (int) attr.GetBulletNumber());
1143
1144 if (attr.HasBulletText())
1145 {
1146 // If using a bullet symbol, convert to integer in case it's a non-XML-friendly character.
1147 // Otherwise, assume it's XML-friendly text such as outline numbering, e.g. 1.2.3.1
1148 if (!attr.GetBulletText().empty() && (attr.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_SYMBOL))
1149 AddAttribute(str, wxT("bulletsymbol"), (int) (attr.GetBulletText()[0]));
1150 else
1151 AddAttribute(str, wxT("bullettext"), attr.GetBulletText());
1152
1153 AddAttribute(str, wxT("bulletfont"), attr.GetBulletFont());
1154 }
1155
1156 if (attr.HasBulletName())
1157 AddAttribute(str, wxT("bulletname"), attr.GetBulletName());
1158
1159 if (!attr.GetParagraphStyleName().empty())
1160 AddAttribute(str, wxT("parstyle"), attr.GetParagraphStyleName());
1161
1162 if (!attr.GetListStyleName().empty())
1163 AddAttribute(str, wxT("liststyle"), attr.GetListStyleName());
1164
1165 if (attr.HasTabs())
1166 {
1167 wxString strTabs;
1168 size_t i;
1169 for (i = 0; i < attr.GetTabs().GetCount(); i++)
1170 {
1171 if (i > 0) strTabs << wxT(",");
1172 strTabs << attr.GetTabs()[i];
1173 }
1174 AddAttribute(str, wxT("tabs"), strTabs);
1175 }
1176
1177 if (attr.HasPageBreak())
1178 {
1179 AddAttribute(str, wxT("pagebreak"), 1);
1180 }
1181
1182 if (attr.HasOutlineLevel())
1183 AddAttribute(str, wxT("outlinelevel"), (int) attr.GetOutlineLevel());
1184 }
1185
1186 AddAttribute(str, wxT("margin"), attr.GetTextBoxAttr().GetMargins());
1187 AddAttribute(str, wxT("padding"), attr.GetTextBoxAttr().GetPadding());
1188 AddAttribute(str, wxT("position"), attr.GetTextBoxAttr().GetPosition());
1189 AddAttribute(str, wxT("border"), attr.GetTextBoxAttr().GetBorder());
1190 AddAttribute(str, wxT("outline"), attr.GetTextBoxAttr().GetOutline());
1191 AddAttribute(str, wxT("width"), attr.GetTextBoxAttr().GetWidth());
1192 AddAttribute(str, wxT("height"), attr.GetTextBoxAttr().GetHeight());
1193
1194 if (attr.GetTextBoxAttr().HasVerticalAlignment())
1195 {
1196 wxString value;
1197 if (attr.GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_TOP)
1198 value = wxT("top");
1199 else if (attr.GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_CENTRE)
1200 value = wxT("centre");
1201 else if (attr.GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_BOTTOM)
1202 value = wxT("bottom");
1203 else
1204 value = wxT("none");
1205 AddAttribute(str, wxT("verticalalignment"), value);
1206 }
1207
1208 if (attr.GetTextBoxAttr().HasFloatMode())
1209 {
1210 wxString value;
1211 if (attr.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_LEFT)
1212 value = wxT("left");
1213 else if (attr.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_RIGHT)
1214 value = wxT("right");
1215 else
1216 value = wxT("none");
1217 AddAttribute(str, wxT("float"), value);
1218 }
1219
1220 if (attr.GetTextBoxAttr().HasClearMode())
1221 {
1222 wxString value;
1223 if (attr.GetTextBoxAttr().GetClearMode() == wxTEXT_BOX_ATTR_CLEAR_LEFT)
1224 value = wxT("left");
1225 else if (attr.GetTextBoxAttr().GetClearMode() == wxTEXT_BOX_ATTR_CLEAR_RIGHT)
1226 value = wxT("right");
1227 else if (attr.GetTextBoxAttr().GetClearMode() == wxTEXT_BOX_ATTR_CLEAR_BOTH)
1228 value = wxT("both");
1229 else
1230 value = wxT("none");
1231 AddAttribute(str, wxT("clear"), value);
1232 }
1233
1234 if (attr.GetTextBoxAttr().HasCollapseBorders())
1235 AddAttribute(str, wxT("collapse-borders"), (int) attr.GetTextBoxAttr().GetCollapseBorders());
1236
1237 return str;
1238 }
1239
1240 // Make a string from the given property. This can be overridden for custom variants.
1241 wxString wxRichTextXMLHandler::MakeStringFromProperty(const wxVariant& var)
1242 {
1243 return var.MakeString();
1244 }
1245
1246 // Create a proprty from the string read from the XML file.
1247 wxVariant wxRichTextXMLHandler::MakePropertyFromString(const wxString& name, const wxString& value, const wxString& WXUNUSED(type))
1248 {
1249 wxVariant var(value, name);
1250 // TODO: use type to create using common types
1251 return var;
1252 }
1253
1254 // Write the properties
1255 bool wxRichTextXMLHandler::WriteProperties(wxOutputStream& stream, const wxRichTextProperties& properties, int level)
1256 {
1257 if (properties.GetCount() > 0)
1258 {
1259 level ++;
1260
1261 OutputIndentation(stream, level);
1262 OutputString(stream, wxT("<properties"));
1263
1264 level ++;
1265
1266 size_t i;
1267 for (i = 0; i < properties.GetCount(); i++)
1268 {
1269 const wxVariant& var = properties[i];
1270 if (!var.IsNull())
1271 {
1272 const wxString& name = var.GetName();
1273 wxString value = MakeStringFromProperty(var);
1274
1275 OutputIndentation(stream, level);
1276 OutputString(stream, wxT("<property name=\"") + name +
1277 wxT("\" type=\"") + var.GetType() + wxT("\" value=\""));
1278 OutputStringEnt(stream, value);
1279 OutputString(stream, wxT("\"/>\n"));
1280 }
1281 }
1282
1283 level --;
1284
1285 OutputIndentation(stream, level);
1286 OutputString(stream, wxT("</properties>\n"));
1287
1288 level --;
1289 }
1290
1291 return true;
1292 }
1293
1294
1295 #endif
1296 // wxRICHTEXT_HAVE_DIRECT_OUTPUT
1297
1298 #if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
1299 bool wxRichTextXMLHandler::ExportXML(wxXmlNode* parent, wxRichTextObject& obj)
1300 {
1301 obj.ExportXML(parent, this);
1302
1303 return true;
1304 }
1305
1306 bool wxRichTextXMLHandler::ExportStyleDefinition(wxXmlNode* parent, wxRichTextStyleDefinition* def)
1307 {
1308 wxRichTextCharacterStyleDefinition* charDef = wxDynamicCast(def, wxRichTextCharacterStyleDefinition);
1309 wxRichTextParagraphStyleDefinition* paraDef = wxDynamicCast(def, wxRichTextParagraphStyleDefinition);
1310 wxRichTextBoxStyleDefinition* boxDef = wxDynamicCast(def, wxRichTextBoxStyleDefinition);
1311 wxRichTextListStyleDefinition* listDef = wxDynamicCast(def, wxRichTextListStyleDefinition);
1312
1313 wxString baseStyle = def->GetBaseStyle();
1314 wxString descr = def->GetDescription();
1315
1316 wxXmlNode* defNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxEmptyString);
1317 parent->AddChild(defNode);
1318 if (!baseStyle.empty())
1319 defNode->AddAttribute(wxT("basestyle"), baseStyle);
1320 if (!descr.empty())
1321 defNode->AddAttribute(wxT("description"), descr);
1322
1323 wxXmlNode* styleNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("style"));
1324 defNode->AddChild(styleNode);
1325
1326 if (charDef)
1327 {
1328 defNode->SetName(wxT("characterstyle"));
1329 AddAttributes(styleNode, def->GetStyle(), false);
1330 }
1331 else if (listDef)
1332 {
1333 defNode->SetName(wxT("liststyle"));
1334
1335 if (!listDef->GetNextStyle().empty())
1336 defNode->AddAttribute(wxT("nextstyle"), listDef->GetNextStyle());
1337
1338 AddAttributes(styleNode, def->GetStyle(), true);
1339
1340 int i;
1341 for (i = 0; i < 10; i ++)
1342 {
1343 wxRichTextAttr* levelAttr = listDef->GetLevelAttributes(i);
1344 if (levelAttr)
1345 {
1346 wxXmlNode* levelNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("style"));
1347 defNode->AddChild(levelNode);
1348 levelNode->AddAttribute(wxT("level"), MakeString(i+1));
1349 AddAttributes(levelNode, * levelAttr, true);
1350 }
1351 }
1352 }
1353 else if (boxDef)
1354 {
1355 defNode->SetName(wxT("boxstyle"));
1356
1357 AddAttributes(styleNode, def->GetStyle(), true);
1358 }
1359 else if (paraDef)
1360 {
1361 defNode->SetName(wxT("paragraphstyle"));
1362
1363 if (!paraDef->GetNextStyle().empty())
1364 defNode->AddAttribute(wxT("nextstyle"), paraDef->GetNextStyle());
1365
1366 AddAttributes(styleNode, def->GetStyle(), true);
1367 }
1368
1369 return true;
1370 }
1371
1372 bool wxRichTextXMLHandler::AddAttributes(wxXmlNode* node, wxRichTextAttr& attr, bool isPara)
1373 {
1374 if (attr.HasTextColour() && attr.GetTextColour().Ok())
1375 node->AddAttribute(wxT("textcolor"), MakeString(attr.GetTextColour()));
1376 if (attr.HasBackgroundColour() && attr.GetBackgroundColour().Ok())
1377 node->AddAttribute(wxT("bgcolor"), MakeString(attr.GetBackgroundColour()));
1378
1379 if (attr.HasFontSize())
1380 node->AddAttribute(wxT("fontsize"), MakeString(attr.GetFontSize()));
1381 if (attr.HasFontFamily())
1382 node->AddAttribute(wxT("fontfamily"), MakeString(attr.GetFontFamily()));
1383 if (attr.HasFontItalic())
1384 node->AddAttribute(wxT("fontstyle"), MakeString(attr.GetFontStyle()));
1385 if (attr.HasFontWeight())
1386 node->AddAttribute(wxT("fontweight"), MakeString(attr.GetFontWeight()));
1387 if (attr.HasFontUnderlined())
1388 node->AddAttribute(wxT("fontunderlined"), MakeString((int) attr.GetFontUnderlined()));
1389 if (attr.HasFontFaceName())
1390 node->AddAttribute(wxT("fontface"), attr.GetFontFaceName());
1391
1392 if (attr.HasTextEffects())
1393 {
1394 node->AddAttribute(wxT("texteffects"), MakeString(attr.GetTextEffects()));
1395 node->AddAttribute(wxT("texteffectflags"), MakeString(attr.GetTextEffectFlags()));
1396 }
1397 if (attr.HasCharacterStyleName() && !attr.GetCharacterStyleName().empty())
1398 node->AddAttribute(wxT("characterstyle"), attr.GetCharacterStyleName());
1399
1400 if (attr.HasURL())
1401 node->AddAttribute(wxT("url"), attr.GetURL()); // TODO: do we need to wrap this in AttributeToXML?
1402
1403 if (isPara)
1404 {
1405 if (attr.HasAlignment())
1406 node->AddAttribute(wxT("alignment"), MakeString((int) attr.GetAlignment()));
1407
1408 if (attr.HasLeftIndent())
1409 {
1410 node->AddAttribute(wxT("leftindent"), MakeString((int) attr.GetLeftIndent()));
1411 node->AddAttribute(wxT("leftsubindent"), MakeString((int) attr.GetLeftSubIndent()));
1412 }
1413
1414 if (attr.HasRightIndent())
1415 node->AddAttribute(wxT("rightindent"), MakeString((int) attr.GetRightIndent()));
1416
1417 if (attr.HasParagraphSpacingAfter())
1418 node->AddAttribute(wxT("parspacingafter"), MakeString((int) attr.GetParagraphSpacingAfter()));
1419
1420 if (attr.HasParagraphSpacingBefore())
1421 node->AddAttribute(wxT("parspacingbefore"), MakeString((int) attr.GetParagraphSpacingBefore()));
1422
1423 if (attr.HasLineSpacing())
1424 node->AddAttribute(wxT("linespacing"), MakeString((int) attr.GetLineSpacing()));
1425
1426 if (attr.HasBulletStyle())
1427 node->AddAttribute(wxT("bulletstyle"), MakeString((int) attr.GetBulletStyle()));
1428
1429 if (attr.HasBulletNumber())
1430 node->AddAttribute(wxT("bulletnumber"), MakeString((int) attr.GetBulletNumber()));
1431
1432 if (attr.HasBulletText())
1433 {
1434 // If using a bullet symbol, convert to integer in case it's a non-XML-friendly character.
1435 // Otherwise, assume it's XML-friendly text such as outline numbering, e.g. 1.2.3.1
1436 if (!attr.GetBulletText().empty() && (attr.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_SYMBOL))
1437 node->AddAttribute(wxT("bulletsymbol"), MakeString((int) (attr.GetBulletText()[0])));
1438 else
1439 node->AddAttribute(wxT("bullettext"), attr.GetBulletText());
1440
1441 if (!attr.GetBulletFont().empty())
1442 node->AddAttribute(wxT("bulletfont"), attr.GetBulletFont());
1443 }
1444
1445 if (attr.HasBulletName())
1446 node->AddAttribute(wxT("bulletname"), attr.GetBulletName());
1447
1448 if (!attr.GetParagraphStyleName().empty())
1449 node->AddAttribute(wxT("parstyle"), attr.GetParagraphStyleName());
1450
1451 if (!attr.GetListStyleName().empty())
1452 node->AddAttribute(wxT("liststyle"), attr.GetListStyleName());
1453
1454 if (attr.HasTabs())
1455 {
1456 wxString tabs;
1457 size_t i;
1458 for (i = 0; i < attr.GetTabs().GetCount(); i++)
1459 {
1460 if (i > 0)
1461 tabs << wxT(",");
1462 tabs << attr.GetTabs()[i];
1463 }
1464 node->AddAttribute(wxT("tabs"), tabs);
1465 }
1466
1467 if (attr.HasPageBreak())
1468 node->AddAttribute(wxT("pagebreak"), wxT("1"));
1469
1470 if (attr.HasOutlineLevel())
1471 node->AddAttribute(wxT("outlinelevel"), MakeString((int) attr.GetOutlineLevel()));
1472 }
1473
1474 AddAttribute(node, wxT("margin"), attr.GetTextBoxAttr().GetMargins());
1475 AddAttribute(node, wxT("padding"), attr.GetTextBoxAttr().GetPadding());
1476 AddAttribute(node, wxT("position"), attr.GetTextBoxAttr().GetPosition());
1477 AddAttribute(node, wxT("border"), attr.GetTextBoxAttr().GetBorder());
1478 AddAttribute(node, wxT("outline"), attr.GetTextBoxAttr().GetOutline());
1479 AddAttribute(node, wxT("width"), attr.GetTextBoxAttr().GetWidth());
1480 AddAttribute(node, wxT("height"), attr.GetTextBoxAttr().GetHeight());
1481
1482 if (attr.GetTextBoxAttr().HasVerticalAlignment())
1483 {
1484 wxString value;
1485 if (attr.GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_TOP)
1486 value = wxT("top");
1487 else if (attr.GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_CENTRE)
1488 value = wxT("centre");
1489 else if (attr.GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_BOTTOM)
1490 value = wxT("bottom");
1491 else
1492 value = wxT("none");
1493 AddAttribute(node, wxT("verticalalignment"), value);
1494 }
1495
1496 if (attr.GetTextBoxAttr().HasFloatMode())
1497 {
1498 wxString value;
1499 if (attr.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_LEFT)
1500 value = wxT("left");
1501 else if (attr.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_RIGHT)
1502 value = wxT("right");
1503 else
1504 value = wxT("none");
1505 AddAttribute(node, wxT("float"), value);
1506 }
1507
1508 if (attr.GetTextBoxAttr().HasClearMode())
1509 {
1510 wxString value;
1511 if (attr.GetTextBoxAttr().GetClearMode() == wxTEXT_BOX_ATTR_CLEAR_LEFT)
1512 value = wxT("left");
1513 else if (attr.GetTextBoxAttr().GetClearMode() == wxTEXT_BOX_ATTR_CLEAR_RIGHT)
1514 value = wxT("right");
1515 else if (attr.GetTextBoxAttr().GetClearMode() == wxTEXT_BOX_ATTR_CLEAR_BOTH)
1516 value = wxT("both");
1517 else
1518 value = wxT("none");
1519 AddAttribute(node, wxT("clear"), value);
1520 }
1521
1522 if (attr.GetTextBoxAttr().HasCollapseBorders())
1523 AddAttribute(node, wxT("collapse-borders"), (int) attr.GetTextBoxAttr().GetCollapseBorders());
1524
1525 return true;
1526 }
1527
1528 bool wxRichTextXMLHandler::WriteProperties(wxXmlNode* node, const wxRichTextProperties& properties)
1529 {
1530 if (properties.GetCount() > 0)
1531 {
1532 wxXmlNode* propertiesNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("properties"));
1533 node->AddChild(propertiesNode);
1534 size_t i;
1535 for (i = 0; i < properties.GetCount(); i++)
1536 {
1537 const wxVariant& var = properties[i];
1538 if (!var.IsNull())
1539 {
1540 wxXmlNode* propertyNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("property"));
1541 propertiesNode->AddChild(propertyNode);
1542
1543 const wxString& name = var.GetName();
1544 wxString value = MakeStringFromProperty(var);
1545
1546 AddAttribute(propertyNode, wxT("name"), name);
1547 AddAttribute(propertyNode, wxT("type"), var.GetType());
1548 AddAttribute(propertyNode, wxT("value"), value);
1549 }
1550 }
1551 }
1552 return true;
1553 }
1554
1555 #endif
1556 // wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
1557
1558 /// Replace face name with current name for platform.
1559 /// TODO: introduce a virtual function or settable table to
1560 /// do this comprehensively.
1561 bool wxRichTextFixFaceName(wxString& facename)
1562 {
1563 if (facename.empty())
1564 return false;
1565
1566 #ifdef __WXMSW__
1567 if (facename == wxT("Times"))
1568 {
1569 facename = wxT("Times New Roman");
1570 return true;
1571 }
1572 else if (facename == wxT("Helvetica"))
1573 {
1574 facename = wxT("Arial");
1575 return true;
1576 }
1577 else if (facename == wxT("Courier"))
1578 {
1579 facename = wxT("Courier New");
1580 return true;
1581 }
1582 else
1583 return false;
1584 #else
1585 if (facename == wxT("Times New Roman"))
1586 {
1587 facename = wxT("Times");
1588 return true;
1589 }
1590 else if (facename == wxT("Arial"))
1591 {
1592 facename = wxT("Helvetica");
1593 return true;
1594 }
1595 else if (facename == wxT("Courier New"))
1596 {
1597 facename = wxT("Courier");
1598 return true;
1599 }
1600 else
1601 return false;
1602 #endif
1603 }
1604
1605 static inline long wxRichTextColourStringToLong(const wxString& colStr)
1606 {
1607 if (!colStr.IsEmpty())
1608 {
1609 wxColour col(colStr);
1610 return col.GetRGB();
1611 }
1612 else
1613 return 0;
1614 }
1615
1616 static inline wxTextAttrDimension wxRichTextParseDimension(const wxString& dimStr)
1617 {
1618 wxString valuePart = dimStr.BeforeFirst(wxT(','));
1619 wxString flagsPart;
1620 if (dimStr.Contains(wxT(",")))
1621 flagsPart = dimStr.AfterFirst(wxT(','));
1622 wxTextAttrDimension dim;
1623 dim.SetValue(wxAtoi(valuePart));
1624 dim.SetFlags(wxAtoi(flagsPart));
1625
1626 return dim;
1627 }
1628
1629 /// Import style parameters
1630 bool wxRichTextXMLHandler::ImportStyle(wxRichTextAttr& attr, wxXmlNode* node, bool isPara)
1631 {
1632 wxXmlAttribute* xmlAttr = node->GetAttributes();
1633 bool found;
1634 while (xmlAttr)
1635 {
1636 const wxString& name = xmlAttr->GetName();
1637 const wxString& value = xmlAttr->GetValue();
1638 found = true;
1639
1640 if (name == wxT("fontface"))
1641 {
1642 if (!value.empty())
1643 {
1644 wxString v = value;
1645 if (GetFlags() & wxRICHTEXT_HANDLER_CONVERT_FACENAMES)
1646 wxRichTextFixFaceName(v);
1647 attr.SetFontFaceName(v);
1648 }
1649 }
1650 else if (name == wxT("fontfamily"))
1651 {
1652 if (!value.empty())
1653 attr.SetFontFamily((wxFontFamily)wxAtoi(value));
1654 }
1655 else if (name == wxT("fontstyle"))
1656 {
1657 if (!value.empty())
1658 attr.SetFontStyle((wxFontStyle)wxAtoi(value));
1659 }
1660 else if (name == wxT("fontsize"))
1661 {
1662 if (!value.empty())
1663 attr.SetFontSize(wxAtoi(value));
1664 }
1665 else if (name == wxT("fontweight"))
1666 {
1667 if (!value.empty())
1668 attr.SetFontWeight((wxFontWeight) wxAtoi(value));
1669 }
1670 else if (name == wxT("fontunderlined"))
1671 {
1672 if (!value.empty())
1673 attr.SetFontUnderlined(wxAtoi(value) != 0);
1674 }
1675 else if (name == wxT("textcolor"))
1676 {
1677 if (!value.empty())
1678 {
1679 if (value[0] == wxT('#'))
1680 attr.SetTextColour(HexStringToColour(value.Mid(1)));
1681 else
1682 attr.SetTextColour(value);
1683 }
1684 }
1685 else if (name == wxT("bgcolor"))
1686 {
1687 if (!value.empty())
1688 {
1689 if (value[0] == wxT('#'))
1690 attr.SetBackgroundColour(HexStringToColour(value.Mid(1)));
1691 else
1692 attr.SetBackgroundColour(value);
1693 }
1694 }
1695 else if (name == wxT("characterstyle"))
1696 {
1697 if (!value.empty())
1698 attr.SetCharacterStyleName(value);
1699 }
1700 else if (name == wxT("texteffects"))
1701 {
1702 if (!value.empty())
1703 attr.SetTextEffects(wxAtoi(value));
1704 }
1705 else if (name == wxT("texteffectflags"))
1706 {
1707 if (!value.empty())
1708 attr.SetTextEffectFlags(wxAtoi(value));
1709 }
1710 else if (name == wxT("url"))
1711 {
1712 if (!value.empty())
1713 attr.SetURL(value);
1714 }
1715 else if (isPara)
1716 {
1717 if (name == wxT("alignment"))
1718 {
1719 if (!value.empty())
1720 attr.SetAlignment((wxTextAttrAlignment) wxAtoi(value));
1721 }
1722 else if (name == wxT("leftindent"))
1723 {
1724 if (!value.empty())
1725 attr.SetLeftIndent(wxAtoi(value), attr.GetLeftSubIndent());
1726 }
1727 else if (name == wxT("leftsubindent"))
1728 {
1729 if (!value.empty())
1730 attr.SetLeftIndent(attr.GetLeftIndent(), wxAtoi(value));
1731 }
1732 else if (name == wxT("rightindent"))
1733 {
1734 if (!value.empty())
1735 attr.SetRightIndent(wxAtoi(value));
1736 }
1737 else if (name == wxT("parspacingbefore"))
1738 {
1739 if (!value.empty())
1740 attr.SetParagraphSpacingBefore(wxAtoi(value));
1741 }
1742 else if (name == wxT("parspacingafter"))
1743 {
1744 if (!value.empty())
1745 attr.SetParagraphSpacingAfter(wxAtoi(value));
1746 }
1747 else if (name == wxT("linespacing"))
1748 {
1749 if (!value.empty())
1750 attr.SetLineSpacing(wxAtoi(value));
1751 }
1752 else if (name == wxT("bulletstyle"))
1753 {
1754 if (!value.empty())
1755 attr.SetBulletStyle(wxAtoi(value));
1756 }
1757 else if (name == wxT("bulletnumber"))
1758 {
1759 if (!value.empty())
1760 attr.SetBulletNumber(wxAtoi(value));
1761 }
1762 else if (name == wxT("bulletsymbol"))
1763 {
1764 if (!value.empty())
1765 {
1766 wxChar ch = wxAtoi(value);
1767 wxString s;
1768 s << ch;
1769 attr.SetBulletText(s);
1770 }
1771 }
1772 else if (name == wxT("bullettext"))
1773 {
1774 if (!value.empty())
1775 {
1776 attr.SetBulletText(value);
1777 }
1778 }
1779 else if (name == wxT("bulletfont"))
1780 {
1781 if (!value.empty())
1782 {
1783 attr.SetBulletFont(value);
1784 }
1785 }
1786 else if (name == wxT("bulletname"))
1787 {
1788 if (!value.empty())
1789 {
1790 attr.SetBulletName(value);
1791 }
1792 }
1793 else if (name == wxT("parstyle"))
1794 {
1795 if (!value.empty())
1796 {
1797 attr.SetParagraphStyleName(value);
1798 }
1799 }
1800 else if (name == wxT("liststyle"))
1801 {
1802 if (!value.empty())
1803 {
1804 attr.SetListStyleName(value);
1805 }
1806 }
1807 else if (name == wxT("tabs"))
1808 {
1809 if (!value.empty())
1810 {
1811 wxArrayInt tabs;
1812 wxStringTokenizer tkz(value, wxT(","));
1813 while (tkz.HasMoreTokens())
1814 {
1815 wxString token = tkz.GetNextToken();
1816 tabs.Add(wxAtoi(token));
1817 }
1818 attr.SetTabs(tabs);
1819 }
1820 }
1821 else if (name == wxT("pagebreak"))
1822 {
1823 if (!value.empty())
1824 {
1825 attr.SetPageBreak(wxAtoi(value) != 0);
1826 }
1827 }
1828 else if (name == wxT("outlinelevel"))
1829 {
1830 if (!value.empty())
1831 {
1832 attr.SetOutlineLevel(wxAtoi(value));
1833 }
1834 }
1835 else
1836 found = false;
1837 }
1838 else
1839 found = false;
1840
1841 if (!found)
1842 {
1843 // Box attributes
1844
1845 if (name == wxT("width"))
1846 {
1847 attr.GetTextBoxAttr().GetWidth().SetValue(wxRichTextParseDimension(value));
1848 }
1849 else if (name == wxT("height"))
1850 {
1851 attr.GetTextBoxAttr().GetHeight().SetValue(wxRichTextParseDimension(value));
1852 }
1853
1854 else if (name == wxT("verticalalignment"))
1855 {
1856 if (value == wxT("top"))
1857 attr.GetTextBoxAttr().SetVerticalAlignment(wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_TOP);
1858 else if (value == wxT("centre"))
1859 attr.GetTextBoxAttr().SetVerticalAlignment(wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_CENTRE);
1860 else if (value == wxT("bottom"))
1861 attr.GetTextBoxAttr().SetVerticalAlignment(wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_BOTTOM);
1862 else if (value == wxT("none"))
1863 attr.GetTextBoxAttr().SetVerticalAlignment(wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_NONE);
1864 }
1865 else if (name == wxT("float"))
1866 {
1867 if (value == wxT("left"))
1868 attr.GetTextBoxAttr().SetFloatMode(wxTEXT_BOX_ATTR_FLOAT_LEFT);
1869 else if (value == wxT("right"))
1870 attr.GetTextBoxAttr().SetFloatMode(wxTEXT_BOX_ATTR_FLOAT_RIGHT);
1871 else if (value == wxT("none"))
1872 attr.GetTextBoxAttr().SetFloatMode(wxTEXT_BOX_ATTR_FLOAT_NONE);
1873 }
1874 else if (name == wxT("clear"))
1875 {
1876 if (value == wxT("left"))
1877 attr.GetTextBoxAttr().SetClearMode(wxTEXT_BOX_ATTR_CLEAR_LEFT);
1878 else if (value == wxT("right"))
1879 attr.GetTextBoxAttr().SetClearMode(wxTEXT_BOX_ATTR_CLEAR_RIGHT);
1880 else if (value == wxT("both"))
1881 attr.GetTextBoxAttr().SetClearMode(wxTEXT_BOX_ATTR_CLEAR_BOTH);
1882 else if (value == wxT("none"))
1883 attr.GetTextBoxAttr().SetClearMode(wxTEXT_BOX_ATTR_CLEAR_NONE);
1884 }
1885 else if (name == wxT("collapse-borders"))
1886 attr.GetTextBoxAttr().SetCollapseBorders((wxTextBoxAttrCollapseMode) wxAtoi(value));
1887
1888 else if (name.Contains(wxT("border-")))
1889 {
1890 if (name == wxT("border-left-style"))
1891 attr.GetTextBoxAttr().GetBorder().GetLeft().SetStyle(wxAtoi(value));
1892 else if (name == wxT("border-right-style"))
1893 attr.GetTextBoxAttr().GetBorder().GetRight().SetStyle(wxAtoi(value));
1894 else if (name == wxT("border-top-style"))
1895 attr.GetTextBoxAttr().GetBorder().GetTop().SetStyle(wxAtoi(value));
1896 else if (name == wxT("border-bottom-style"))
1897 attr.GetTextBoxAttr().GetBorder().GetBottom().SetStyle(wxAtoi(value));
1898
1899 else if (name == wxT("border-left-colour"))
1900 attr.GetTextBoxAttr().GetBorder().GetLeft().SetColour(wxRichTextColourStringToLong(value));
1901 else if (name == wxT("border-right-colour"))
1902 attr.GetTextBoxAttr().GetBorder().GetRight().SetColour(wxRichTextColourStringToLong(value));
1903 else if (name == wxT("border-top-colour"))
1904 attr.GetTextBoxAttr().GetBorder().GetTop().SetColour(wxRichTextColourStringToLong(value));
1905 else if (name == wxT("border-bottom-colour"))
1906 attr.GetTextBoxAttr().GetBorder().GetBottom().SetColour(wxRichTextColourStringToLong(value));
1907
1908 else if (name == wxT("border-left-width"))
1909 attr.GetTextBoxAttr().GetBorder().GetLeft().SetWidth(wxRichTextParseDimension(value));
1910 else if (name == wxT("border-right-width"))
1911 attr.GetTextBoxAttr().GetBorder().GetRight().SetWidth(wxRichTextParseDimension(value));
1912 else if (name == wxT("border-top-width"))
1913 attr.GetTextBoxAttr().GetBorder().GetTop().SetWidth(wxRichTextParseDimension(value));
1914 else if (name == wxT("border-bottom-width"))
1915 attr.GetTextBoxAttr().GetBorder().GetBottom().SetWidth(wxRichTextParseDimension(value));
1916 }
1917 else if (name.Contains(wxT("outline-")))
1918 {
1919 if (name == wxT("outline-left-style"))
1920 attr.GetTextBoxAttr().GetOutline().GetLeft().SetStyle(wxAtoi(value));
1921 else if (name == wxT("outline-right-style"))
1922 attr.GetTextBoxAttr().GetOutline().GetRight().SetStyle(wxAtoi(value));
1923 else if (name == wxT("outline-top-style"))
1924 attr.GetTextBoxAttr().GetOutline().GetTop().SetStyle(wxAtoi(value));
1925 else if (name == wxT("outline-bottom-style"))
1926 attr.GetTextBoxAttr().GetOutline().GetBottom().SetStyle(wxAtoi(value));
1927
1928 else if (name == wxT("outline-left-colour"))
1929 attr.GetTextBoxAttr().GetOutline().GetLeft().SetColour(wxRichTextColourStringToLong(value));
1930 else if (name == wxT("outline-right-colour"))
1931 attr.GetTextBoxAttr().GetOutline().GetRight().SetColour(wxRichTextColourStringToLong(value));
1932 else if (name == wxT("outline-top-colour"))
1933 attr.GetTextBoxAttr().GetOutline().GetTop().SetColour(wxRichTextColourStringToLong(value));
1934 else if (name == wxT("outline-bottom-colour"))
1935 attr.GetTextBoxAttr().GetOutline().GetBottom().SetColour(wxRichTextColourStringToLong(value));
1936
1937 else if (name == wxT("outline-left-width"))
1938 attr.GetTextBoxAttr().GetOutline().GetLeft().SetWidth(wxRichTextParseDimension(value));
1939 else if (name == wxT("outline-right-width"))
1940 attr.GetTextBoxAttr().GetOutline().GetRight().SetWidth(wxRichTextParseDimension(value));
1941 else if (name == wxT("outline-top-width"))
1942 attr.GetTextBoxAttr().GetOutline().GetTop().SetWidth(wxRichTextParseDimension(value));
1943 else if (name == wxT("outline-bottom-width"))
1944 attr.GetTextBoxAttr().GetOutline().GetBottom().SetWidth(wxRichTextParseDimension(value));
1945 }
1946 else if (name.Contains(wxT("margin-")))
1947 {
1948 if (name == wxT("margin-left"))
1949 attr.GetTextBoxAttr().GetMargins().GetLeft().SetValue(wxRichTextParseDimension(value));
1950 else if (name == wxT("margin-right"))
1951 attr.GetTextBoxAttr().GetMargins().GetRight().SetValue(wxRichTextParseDimension(value));
1952 else if (name == wxT("margin-top"))
1953 attr.GetTextBoxAttr().GetMargins().GetTop().SetValue(wxRichTextParseDimension(value));
1954 else if (name == wxT("margin-bottom"))
1955 attr.GetTextBoxAttr().GetMargins().GetBottom().SetValue(wxRichTextParseDimension(value));
1956 }
1957 else if (name.Contains(wxT("padding-")))
1958 {
1959 if (name == wxT("padding-left"))
1960 attr.GetTextBoxAttr().GetPadding().GetLeft().SetValue(wxRichTextParseDimension(value));
1961 else if (name == wxT("padding-right"))
1962 attr.GetTextBoxAttr().GetPadding().GetRight().SetValue(wxRichTextParseDimension(value));
1963 else if (name == wxT("padding-top"))
1964 attr.GetTextBoxAttr().GetPadding().GetTop().SetValue(wxRichTextParseDimension(value));
1965 else if (name == wxT("padding-bottom"))
1966 attr.GetTextBoxAttr().GetPadding().GetBottom().SetValue(wxRichTextParseDimension(value));
1967 }
1968 else if (name.Contains(wxT("position-")))
1969 {
1970 if (name == wxT("position-left"))
1971 attr.GetTextBoxAttr().GetPosition().GetLeft().SetValue(wxRichTextParseDimension(value));
1972 else if (name == wxT("position-right"))
1973 attr.GetTextBoxAttr().GetPosition().GetRight().SetValue(wxRichTextParseDimension(value));
1974 else if (name == wxT("position-top"))
1975 attr.GetTextBoxAttr().GetPosition().GetTop().SetValue(wxRichTextParseDimension(value));
1976 else if (name == wxT("position-bottom"))
1977 attr.GetTextBoxAttr().GetPosition().GetBottom().SetValue(wxRichTextParseDimension(value));
1978 }
1979 }
1980
1981 xmlAttr = xmlAttr->GetNext();
1982 }
1983
1984 return true;
1985 }
1986
1987 #endif
1988 // wxUSE_STREAMS
1989
1990 // Import this object from XML
1991 bool wxRichTextObject::ImportFromXML(wxRichTextBuffer* WXUNUSED(buffer), wxXmlNode* node, wxRichTextXMLHandler* handler, bool* recurse)
1992 {
1993 handler->ImportProperties(this, node);
1994 handler->ImportStyle(GetAttributes(), node, UsesParagraphAttributes());
1995
1996 *recurse = true;
1997
1998 return true;
1999 }
2000
2001 #if wxRICHTEXT_HAVE_DIRECT_OUTPUT
2002 // Export this object directly to the given stream.
2003 bool wxRichTextObject::ExportXML(wxOutputStream& stream, int indent, wxRichTextXMLHandler* handler)
2004 {
2005 ::OutputIndentation(stream, indent);
2006 ::OutputString(stream, wxT("<") + GetXMLNodeName(), handler->GetConvMem(), handler->GetConvFile());
2007
2008 wxString style = handler->AddAttributes(GetAttributes(), true);
2009
2010 ::OutputString(stream, style + wxT(">"), handler->GetConvMem(), handler->GetConvFile());
2011
2012 if (GetProperties().GetCount() > 0)
2013 {
2014 handler->WriteProperties(stream, GetProperties(), indent);
2015 }
2016
2017 wxRichTextCompositeObject* composite = wxDynamicCast(this, wxRichTextCompositeObject);
2018 if (composite)
2019 {
2020 size_t i;
2021 for (i = 0; i < composite->GetChildCount(); i++)
2022 {
2023 wxRichTextObject* child = composite->GetChild(i);
2024 child->ExportXML(stream, indent+1, handler);
2025 }
2026 }
2027
2028 ::OutputIndentation(stream, indent);
2029 ::OutputString(stream, wxT("</") + GetXMLNodeName() + wxT(">"), handler->GetConvMem(), handler->GetConvFile());
2030 return true;
2031 }
2032 #endif
2033
2034 #if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
2035 // Export this object to the given parent node, usually creating at least one child node.
2036 bool wxRichTextObject::ExportXML(wxXmlNode* parent, wxRichTextXMLHandler* handler)
2037 {
2038 wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, GetXMLNodeName());
2039 parent->AddChild(elementNode);
2040 handler->AddAttributes(elementNode, GetAttributes(), true);
2041 handler->WriteProperties(elementNode, GetProperties());
2042
2043 wxRichTextCompositeObject* composite = wxDynamicCast(this, wxRichTextCompositeObject);
2044 if (composite)
2045 {
2046 size_t i;
2047 for (i = 0; i < composite->GetChildCount(); i++)
2048 {
2049 wxRichTextObject* child = composite->GetChild(i);
2050 child->ExportXML(elementNode, handler);
2051 }
2052 }
2053 return true;
2054 }
2055 #endif
2056
2057
2058 // Import this object from XML
2059 bool wxRichTextPlainText::ImportFromXML(wxRichTextBuffer* buffer, wxXmlNode* node, wxRichTextXMLHandler* handler, bool* recurse)
2060 {
2061 wxRichTextObject::ImportFromXML(buffer, node, handler, recurse);
2062
2063 if (node->GetName() == wxT("text"))
2064 {
2065 wxString text;
2066 wxXmlNode* textChild = node->GetChildren();
2067 while (textChild)
2068 {
2069 if (textChild->GetType() == wxXML_TEXT_NODE ||
2070 textChild->GetType() == wxXML_CDATA_SECTION_NODE)
2071 {
2072 wxString text2 = textChild->GetContent();
2073
2074 // Strip whitespace from end
2075 if (!text2.empty() && text2[text2.length()-1] == wxT('\n'))
2076 text2 = text2.Mid(0, text2.length()-1);
2077
2078 if (!text2.empty() && text2[0] == wxT('"'))
2079 text2 = text2.Mid(1);
2080 if (!text2.empty() && text2[text2.length()-1] == wxT('"'))
2081 text2 = text2.Mid(0, text2.length() - 1);
2082
2083 text += text2;
2084 }
2085 textChild = textChild->GetNext();
2086 }
2087
2088 SetText(text);
2089 }
2090 else if (node->GetName() == wxT("symbol"))
2091 {
2092 // This is a symbol that XML can't read in the normal way
2093 wxString text;
2094 wxXmlNode* textChild = node->GetChildren();
2095 while (textChild)
2096 {
2097 if (textChild->GetType() == wxXML_TEXT_NODE ||
2098 textChild->GetType() == wxXML_CDATA_SECTION_NODE)
2099 {
2100 wxString text2 = textChild->GetContent();
2101 text += text2;
2102 }
2103 textChild = textChild->GetNext();
2104 }
2105
2106 wxString actualText;
2107 actualText << (wxChar) wxAtoi(text);
2108 SetText(actualText);
2109 }
2110 else
2111 return false;
2112
2113 return true;
2114 }
2115
2116 #if wxRICHTEXT_HAVE_DIRECT_OUTPUT
2117 // Export this object directly to the given stream.
2118 bool wxRichTextPlainText::ExportXML(wxOutputStream& stream, int indent, wxRichTextXMLHandler* handler)
2119 {
2120 wxString style = handler->AddAttributes(GetAttributes(), false);
2121
2122 int i;
2123 int last = 0;
2124 const wxString& text = GetText();
2125 int len = (int) text.Length();
2126
2127 if (len == 0)
2128 {
2129 i = 0;
2130 ::OutputIndentation(stream, indent);
2131 ::OutputString(stream, wxT("<text"), handler->GetConvMem(), handler->GetConvFile());
2132 ::OutputString(stream, style + wxT(">"), handler->GetConvMem(), handler->GetConvFile());
2133 if (GetProperties().GetCount() > 0)
2134 {
2135 handler->WriteProperties(stream, GetProperties(), indent);
2136 ::OutputIndentation(stream, indent);
2137 }
2138 ::OutputString(stream, wxT("</text>"), handler->GetConvMem(), handler->GetConvFile());
2139 }
2140 else for (i = 0; i < len; i++)
2141 {
2142 #if wxUSE_UNICODE
2143 int c = (int) text[i];
2144 #else
2145 int c = (int) wxUChar(text[i]);
2146 #endif
2147 if ((c < 32 || c == 34) && /* c != 9 && */ c != 10 && c != 13)
2148 {
2149 if (i > 0)
2150 {
2151 wxString fragment(text.Mid(last, i-last));
2152 if (!fragment.empty())
2153 {
2154 ::OutputIndentation(stream, indent);
2155 ::OutputString(stream, wxT("<text"), handler->GetConvMem(), handler->GetConvFile());
2156
2157 ::OutputString(stream, style + wxT(">"), handler->GetConvMem(), handler->GetConvFile());
2158
2159 if (!fragment.empty() && (fragment[0] == wxT(' ') || fragment[fragment.length()-1] == wxT(' ')))
2160 {
2161 ::OutputString(stream, wxT("\""), handler->GetConvMem(), handler->GetConvFile());
2162 ::OutputStringEnt(stream, fragment, handler->GetConvMem(), handler->GetConvFile());
2163 ::OutputString(stream, wxT("\""), handler->GetConvMem(), handler->GetConvFile());
2164 }
2165 else
2166 ::OutputStringEnt(stream, fragment, handler->GetConvMem(), handler->GetConvFile());
2167
2168 if (GetProperties().GetCount() > 0)
2169 {
2170 handler->WriteProperties(stream, GetProperties(), indent);
2171 ::OutputIndentation(stream, indent);
2172 }
2173 ::OutputString(stream, wxT("</text>"), handler->GetConvMem(), handler->GetConvFile());
2174 }
2175 }
2176
2177
2178 // Output this character as a number in a separate tag, because XML can't cope
2179 // with entities below 32 except for 10 and 13
2180 last = i + 1;
2181 ::OutputIndentation(stream, indent);
2182 ::OutputString(stream, wxT("<symbol"), handler->GetConvMem(), handler->GetConvFile());
2183
2184 ::OutputString(stream, style + wxT(">"), handler->GetConvMem(), handler->GetConvFile());
2185 ::OutputString(stream, wxString::Format(wxT("%d"), c), handler->GetConvMem(), handler->GetConvFile());
2186
2187 if (GetProperties().GetCount() > 0)
2188 {
2189 handler->WriteProperties(stream, GetProperties(), indent);
2190 ::OutputIndentation(stream, indent);
2191 }
2192 ::OutputString(stream, wxT("</symbol>"), handler->GetConvMem(), handler->GetConvFile());
2193 }
2194 }
2195
2196 wxString fragment;
2197 if (last == 0)
2198 fragment = text;
2199 else
2200 fragment = text.Mid(last, i-last);
2201
2202 if (last < len)
2203 {
2204 ::OutputIndentation(stream, indent);
2205 ::OutputString(stream, wxT("<text"), handler->GetConvMem(), handler->GetConvFile());
2206
2207 ::OutputString(stream, style + wxT(">"), handler->GetConvMem(), handler->GetConvFile());
2208
2209 if (GetProperties().GetCount() > 0)
2210 {
2211 handler->WriteProperties(stream, GetProperties(), indent);
2212 ::OutputIndentation(stream, indent);
2213 }
2214
2215 if (!fragment.empty() && (fragment[0] == wxT(' ') || fragment[fragment.length()-1] == wxT(' ')))
2216 {
2217 ::OutputString(stream, wxT("\""), handler->GetConvMem(), handler->GetConvFile());
2218 ::OutputStringEnt(stream, fragment, handler->GetConvMem(), handler->GetConvFile());
2219 ::OutputString(stream, wxT("\""), handler->GetConvMem(), handler->GetConvFile());
2220 }
2221 else
2222 ::OutputStringEnt(stream, fragment, handler->GetConvMem(), handler->GetConvFile());
2223
2224 ::OutputString(stream, wxT("</text>"), handler->GetConvMem(), handler->GetConvFile());
2225 }
2226 return true;
2227 }
2228 #endif
2229
2230 #if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
2231 // Export this object to the given parent node, usually creating at least one child node.
2232 bool wxRichTextPlainText::ExportXML(wxXmlNode* parent, wxRichTextXMLHandler* handler)
2233 {
2234 int i;
2235 int last = 0;
2236 const wxString& text = GetText();
2237 int len = (int) text.Length();
2238
2239 if (len == 0)
2240 {
2241 i = 0;
2242
2243 wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("text"));
2244 parent->AddChild(elementNode);
2245
2246 handler->AddAttributes(elementNode, GetAttributes(), false);
2247 handler->WriteProperties(elementNode, GetProperties());
2248 }
2249 else for (i = 0; i < len; i++)
2250 {
2251 #if wxUSE_UNICODE
2252 int c = (int) text[i];
2253 #else
2254 int c = (int) wxUChar(text[i]);
2255 #endif
2256 if ((c < 32 || c == 34) && c != 10 && c != 13)
2257 {
2258 if (i > 0)
2259 {
2260 wxString fragment(text.Mid(last, i-last));
2261 if (!fragment.empty())
2262 {
2263 // TODO: I'm assuming wxXmlDocument will output quotes if necessary
2264 wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("text"));
2265 parent->AddChild(elementNode);
2266 handler->AddAttributes(elementNode, GetAttributes(), false);
2267 handler->WriteProperties(elementNode, GetProperties());
2268
2269 wxXmlNode* textNode = new wxXmlNode(wxXML_TEXT_NODE, wxT("text"));
2270 elementNode->AddChild(textNode);
2271
2272 if (fragment[0] == wxT(' ') || fragment[fragment.length()-1] == wxT(' '))
2273 fragment = wxT("\"") + fragment + wxT("\"");
2274
2275 textNode->SetContent(fragment);
2276 }
2277 }
2278
2279
2280 // Output this character as a number in a separate tag, because XML can't cope
2281 // with entities below 32 except for 10 and 13
2282
2283 wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("symbol"));
2284 parent->AddChild(elementNode);
2285
2286 handler->AddAttributes(elementNode, GetAttributes(), false);
2287 handler->WriteProperties(elementNode, GetProperties());
2288
2289 wxXmlNode* textNode = new wxXmlNode(wxXML_TEXT_NODE, wxT("text"));
2290 elementNode->AddChild(textNode);
2291 textNode->SetContent(wxString::Format(wxT("%d"), c));
2292
2293 last = i + 1;
2294 }
2295 }
2296
2297 wxString fragment;
2298 if (last == 0)
2299 fragment = text;
2300 else
2301 fragment = text.Mid(last, i-last);
2302
2303 if (last < len)
2304 {
2305 wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("text"));
2306 parent->AddChild(elementNode);
2307 handler->AddAttributes(elementNode, GetAttributes(), false);
2308
2309 wxXmlNode* textNode = new wxXmlNode(wxXML_TEXT_NODE, wxT("text"));
2310 elementNode->AddChild(textNode);
2311
2312 if (fragment[0] == wxT(' ') || fragment[fragment.length()-1] == wxT(' '))
2313 fragment = wxT("\"") + fragment + wxT("\"");
2314
2315 textNode->SetContent(fragment);
2316 }
2317 return true;
2318 }
2319 #endif
2320
2321
2322 // Import this object from XML
2323 bool wxRichTextImage::ImportFromXML(wxRichTextBuffer* buffer, wxXmlNode* node, wxRichTextXMLHandler* handler, bool* recurse)
2324 {
2325 wxRichTextObject::ImportFromXML(buffer, node, handler, recurse);
2326
2327 wxBitmapType imageType = wxBITMAP_TYPE_PNG;
2328 wxString value = node->GetAttribute(wxT("imagetype"), wxEmptyString);
2329 if (!value.empty())
2330 {
2331 int type = wxAtoi(value);
2332
2333 // note: 0 == wxBITMAP_TYPE_INVALID
2334 if (type <= 0 || type >= wxBITMAP_TYPE_MAX)
2335 {
2336 wxLogWarning("Invalid bitmap type specified for <image> tag: %d", type);
2337 }
2338 else
2339 {
2340 imageType = (wxBitmapType)type;
2341 }
2342 }
2343
2344 wxString data;
2345
2346 wxXmlNode* imageChild = node->GetChildren();
2347 while (imageChild)
2348 {
2349 wxString childName = imageChild->GetName();
2350 if (childName == wxT("data"))
2351 {
2352 wxXmlNode* dataChild = imageChild->GetChildren();
2353 while (dataChild)
2354 {
2355 data = dataChild->GetContent();
2356 // wxLogDebug(data);
2357 dataChild = dataChild->GetNext();
2358 }
2359
2360 }
2361 imageChild = imageChild->GetNext();
2362 }
2363
2364 if (!data.empty())
2365 {
2366 wxStringInputStream strStream(data);
2367
2368 GetImageBlock().ReadHex(strStream, data.length(), imageType);
2369
2370 return true;
2371 }
2372 else
2373 return false;
2374 }
2375
2376 #if wxRICHTEXT_HAVE_DIRECT_OUTPUT
2377 // Export this object directly to the given stream.
2378 bool wxRichTextImage::ExportXML(wxOutputStream& stream, int indent, wxRichTextXMLHandler* handler)
2379 {
2380 wxString style = handler->AddAttributes(GetAttributes(), false);
2381
2382 ::OutputIndentation(stream, indent);
2383 ::OutputString(stream, wxT("<image"), handler->GetConvMem(), handler->GetConvFile());
2384 if (!GetImageBlock().Ok())
2385 {
2386 // No data
2387 ::OutputString(stream, style + wxT(">"), handler->GetConvMem(), handler->GetConvFile());
2388 }
2389 else
2390 {
2391 ::OutputString(stream, wxString::Format(wxT(" imagetype=\"%d\""), (int) GetImageBlock().GetImageType()) + style + wxT(">"), handler->GetConvMem(), handler->GetConvFile());
2392 }
2393 if (GetProperties().GetCount() > 0)
2394 {
2395 handler->WriteProperties(stream, GetProperties(), indent);
2396 ::OutputIndentation(stream, indent);
2397 }
2398
2399 ::OutputIndentation(stream, indent+1);
2400 ::OutputString(stream, wxT("<data>"), handler->GetConvMem(), handler->GetConvFile());
2401
2402 // wxStopWatch stopwatch;
2403
2404 GetImageBlock().WriteHex(stream);
2405
2406 // wxLogDebug(wxT("Image conversion to hex took %ldms"), stopwatch.Time());
2407
2408 ::OutputString(stream, wxT("</data>\n"), handler->GetConvMem(), handler->GetConvFile());
2409 ::OutputIndentation(stream, indent);
2410 ::OutputString(stream, wxT("</image>"), handler->GetConvMem(), handler->GetConvFile());
2411 return true;
2412 }
2413 #endif
2414
2415 #if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
2416 // Export this object to the given parent node, usually creating at least one child node.
2417 bool wxRichTextImage::ExportXML(wxXmlNode* parent, wxRichTextXMLHandler* handler)
2418 {
2419 wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("image"));
2420 parent->AddChild(elementNode);
2421
2422 if (GetImageBlock().Ok())
2423 elementNode->AddAttribute(wxT("imagetype"), MakeString((int) GetImageBlock().GetImageType()));
2424
2425 handler->AddAttributes(elementNode, GetAttributes(), false);
2426 handler->WriteProperties(elementNode, GetProperties());
2427
2428 wxXmlNode* dataNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("data"));
2429 elementNode->AddChild(dataNode);
2430 wxXmlNode* textNode = new wxXmlNode(wxXML_TEXT_NODE, wxT("text"));
2431 dataNode->AddChild(textNode);
2432
2433 wxString strData;
2434 #if 1
2435 {
2436 wxMemoryOutputStream stream;
2437 if (GetImageBlock().WriteHex(stream))
2438 {
2439 if (stream.GetSize() > 0)
2440 {
2441 int size = stream.GetSize();
2442 #ifdef __WXDEBUG__
2443 int size2 = stream.GetOutputStreamBuffer()->GetIntPosition();
2444 wxASSERT(size == size2);
2445 #endif
2446 unsigned char* data = new unsigned char[size];
2447 stream.CopyTo(data, size);
2448 strData = wxString((const char*) data, wxConvUTF8, size);
2449 delete[] data;
2450 }
2451 else
2452 strData = wxEmptyString;
2453 }
2454
2455 }
2456 #else
2457 {
2458 wxStringOutputStream strStream(& strData);
2459 GetImageBlock().WriteHex(strStream);
2460 }
2461 #endif
2462
2463 textNode->SetContent(strData);
2464 textNode->SetNoConversion(true); // optimize speed
2465
2466 return true;
2467 }
2468 #endif
2469
2470
2471 // Import this object from XML
2472 bool wxRichTextParagraphLayoutBox::ImportFromXML(wxRichTextBuffer* buffer, wxXmlNode* node, wxRichTextXMLHandler* handler, bool* recurse)
2473 {
2474 wxRichTextObject::ImportFromXML(buffer, node, handler, recurse);
2475
2476 *recurse = true;
2477
2478 wxString partial = node->GetAttribute(wxT("partialparagraph"), wxEmptyString);
2479 if (partial == wxT("true"))
2480 SetPartialParagraph(true);
2481
2482 wxXmlNode* child = wxRichTextXMLHandler::FindNode(node, wxT("stylesheet"));
2483 if (child && (handler->GetFlags() & wxRICHTEXT_HANDLER_INCLUDE_STYLESHEET))
2484 {
2485 wxRichTextStyleSheet* sheet = new wxRichTextStyleSheet;
2486 wxString sheetName = child->GetAttribute(wxT("name"), wxEmptyString);
2487 wxString sheetDescription = child->GetAttribute(wxT("description"), wxEmptyString);
2488 sheet->SetName(sheetName);
2489 sheet->SetDescription(sheetDescription);
2490
2491 wxXmlNode* child2 = child->GetChildren();
2492 while (child2)
2493 {
2494 handler->ImportStyleDefinition(sheet, child2);
2495
2496 child2 = child2->GetNext();
2497 }
2498
2499 // Notify that styles have changed. If this is vetoed by the app,
2500 // the new sheet will be deleted. If it is not vetoed, the
2501 // old sheet will be deleted and replaced with the new one.
2502 buffer->SetStyleSheetAndNotify(sheet);
2503 }
2504
2505 return true;
2506 }
2507
2508 #if wxRICHTEXT_HAVE_DIRECT_OUTPUT
2509 // Export this object directly to the given stream.
2510 bool wxRichTextParagraphLayoutBox::ExportXML(wxOutputStream& stream, int indent, wxRichTextXMLHandler* handler)
2511 {
2512 ::OutputIndentation(stream, indent);
2513 wxString nodeName = GetXMLNodeName();
2514 ::OutputString(stream, wxT("<") + nodeName, handler->GetConvMem(), handler->GetConvFile());
2515
2516 wxString style = handler->AddAttributes(GetAttributes(), true);
2517
2518 if (GetPartialParagraph())
2519 style << wxT(" partialparagraph=\"true\"");
2520
2521 ::OutputString(stream, style + wxT(">"), handler->GetConvMem(), handler->GetConvFile());
2522
2523 if (GetProperties().GetCount() > 0)
2524 {
2525 handler->WriteProperties(stream, GetProperties(), indent);
2526 }
2527
2528 size_t i;
2529 for (i = 0; i < GetChildCount(); i++)
2530 {
2531 wxRichTextObject* child = GetChild(i);
2532 child->ExportXML(stream, indent+1, handler);
2533 }
2534
2535 ::OutputIndentation(stream, indent);
2536 ::OutputString(stream, wxT("</") + nodeName + wxT(">"), handler->GetConvMem(), handler->GetConvFile());
2537 return true;
2538 }
2539 #endif
2540
2541 #if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
2542 // Export this object to the given parent node, usually creating at least one child node.
2543 bool wxRichTextParagraphLayoutBox::ExportXML(wxXmlNode* parent, wxRichTextXMLHandler* handler)
2544 {
2545 wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, GetXMLNodeName());
2546 parent->AddChild(elementNode);
2547 handler->AddAttributes(elementNode, GetAttributes(), true);
2548 handler->WriteProperties(elementNode, GetProperties());
2549
2550 if (GetPartialParagraph())
2551 elementNode->AddAttribute(wxT("partialparagraph"), wxT("true"));
2552
2553 size_t i;
2554 for (i = 0; i < GetChildCount(); i++)
2555 {
2556 wxRichTextObject* child = GetChild(i);
2557 child->ExportXML(elementNode, handler);
2558 }
2559
2560 return true;
2561 }
2562 #endif
2563
2564 // Import this object from XML
2565 bool wxRichTextTable::ImportFromXML(wxRichTextBuffer* buffer, wxXmlNode* node, wxRichTextXMLHandler* handler, bool* recurse)
2566 {
2567 wxRichTextBox::ImportFromXML(buffer, node, handler, recurse);
2568
2569 *recurse = false;
2570
2571 m_rowCount = wxAtoi(node->GetAttribute(wxT("rows"), wxEmptyString));
2572 m_colCount = wxAtoi(node->GetAttribute(wxT("cols"), wxEmptyString));
2573
2574 wxXmlNode* child = node->GetChildren();
2575 while (child)
2576 {
2577 wxRichTextObject* childObj = handler->CreateObjectForXMLName(this, child->GetName());
2578 if (childObj)
2579 {
2580 AppendChild(childObj);
2581 handler->ImportXML(buffer, childObj, child);
2582 }
2583 child = child->GetNext();
2584 }
2585
2586 m_cells.Add(wxRichTextObjectPtrArray(), m_rowCount);
2587 int i, j;
2588 for (i = 0; i < m_rowCount; i++)
2589 {
2590 wxRichTextObjectPtrArray& colArray = m_cells[i];
2591 for (j = 0; j < m_colCount; j++)
2592 {
2593 int idx = i * m_colCount + j;
2594 if (idx < (int) GetChildren().GetCount())
2595 {
2596 wxRichTextCell* cell = wxDynamicCast(GetChildren().Item(idx)->GetData(), wxRichTextCell);
2597 if (cell)
2598 colArray.Add(cell);
2599 }
2600 }
2601 }
2602
2603 return true;
2604 }
2605
2606 #if wxRICHTEXT_HAVE_DIRECT_OUTPUT
2607 // Export this object directly to the given stream.
2608 bool wxRichTextTable::ExportXML(wxOutputStream& stream, int indent, wxRichTextXMLHandler* handler)
2609 {
2610 ::OutputIndentation(stream, indent);
2611 wxString nodeName = GetXMLNodeName();
2612 ::OutputString(stream, wxT("<") + nodeName, handler->GetConvMem(), handler->GetConvFile());
2613
2614 wxString style = handler->AddAttributes(GetAttributes(), true);
2615
2616 style << wxT(" rows=\"") << m_rowCount << wxT("\"");
2617 style << wxT(" cols=\"") << m_colCount << wxT("\"");
2618
2619 ::OutputString(stream, style + wxT(">"), handler->GetConvMem(), handler->GetConvFile());
2620
2621 if (GetProperties().GetCount() > 0)
2622 {
2623 handler->WriteProperties(stream, GetProperties(), indent);
2624 }
2625
2626 int i, j;
2627 for (i = 0; i < m_rowCount; i++)
2628 {
2629 for (j = 0; j < m_colCount; j ++)
2630 {
2631 wxRichTextCell* cell = GetCell(i, j);
2632 cell->ExportXML(stream, indent+1, handler);
2633 }
2634 }
2635
2636 ::OutputIndentation(stream, indent);
2637 ::OutputString(stream, wxT("</") + nodeName + wxT(">"), handler->GetConvMem(), handler->GetConvFile());
2638
2639 return true;
2640 }
2641 #endif
2642
2643 #if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
2644 // Export this object to the given parent node, usually creating at least one child node.
2645 bool wxRichTextTable::ExportXML(wxXmlNode* parent, wxRichTextXMLHandler* handler)
2646 {
2647 wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, GetXMLNodeName());
2648 parent->AddChild(elementNode);
2649 handler->AddAttributes(elementNode, GetAttributes(), true);
2650 handler->WriteProperties(elementNode, GetProperties());
2651
2652 elementNode->AddAttribute(wxT("rows"), wxString::Format(wxT("%d"), m_rowCount));
2653 elementNode->AddAttribute(wxT("cols"), wxString::Format(wxT("%d"), m_colCount));
2654
2655 int i, j;
2656 for (i = 0; i < m_rowCount; i++)
2657 {
2658 for (j = 0; j < m_colCount; j ++)
2659 {
2660 wxRichTextCell* cell = GetCell(i, j);
2661 cell->ExportXML(elementNode, handler);
2662 }
2663 }
2664
2665 return true;
2666 }
2667 #endif
2668
2669
2670 #endif
2671 // wxUSE_RICHTEXT && wxUSE_XML
2672