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