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