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