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