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