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