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