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