]> git.saurik.com Git - wxWidgets.git/blob - src/richtext/richtextxml.cpp
remove GetImageList(int)
[wxWidgets.git] / src / richtext / richtextxml.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: richtext/richtextxml.cpp
3 // Purpose: XML and HTML I/O for wxRichTextCtrl
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 2005-09-30
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #ifndef WX_PRECOMP
20 #include "wx/wx.h"
21 #endif
22
23 #include "wx/image.h"
24
25 #if wxUSE_RICHTEXT
26
27 #include "wx/filename.h"
28 #include "wx/clipbrd.h"
29 #include "wx/wfstream.h"
30 #include "wx/sstream.h"
31 #include "wx/module.h"
32 #include "wx/txtstrm.h"
33 #include "wx/xml/xml.h"
34
35 #include "wx/richtext/richtextxml.h"
36
37 IMPLEMENT_DYNAMIC_CLASS(wxRichTextXMLHandler, wxRichTextFileHandler)
38
39 #if wxUSE_STREAMS
40 bool wxRichTextXMLHandler::DoLoadFile(wxRichTextBuffer *buffer, wxInputStream& stream)
41 {
42 if (!stream.IsOk())
43 return false;
44
45 buffer->Clear();
46
47 wxXmlDocument* xmlDoc = new wxXmlDocument;
48 bool success = true;
49
50 if (!xmlDoc->Load(stream, wxT("ISO-8859-1")))
51 {
52 success = false;
53 }
54 else
55 {
56 if (xmlDoc->GetRoot() && xmlDoc->GetRoot()->GetType() == wxXML_ELEMENT_NODE && xmlDoc->GetRoot()->GetName() == wxT("richtext"))
57 {
58 wxXmlNode* child = xmlDoc->GetRoot()->GetChildren();
59 while (child)
60 {
61 if (child->GetType() == wxXML_ELEMENT_NODE)
62 {
63 wxString name = child->GetName();
64 if (name == wxT("richtext-version"))
65 {
66 }
67 else
68 ImportXML(buffer, child);
69 }
70
71 child = child->GetNext();
72 }
73 }
74 else
75 {
76 success = false;
77 }
78 }
79
80 delete xmlDoc;
81
82 buffer->UpdateRanges();
83
84 return success;
85 }
86
87 /// Recursively import an object
88 bool wxRichTextXMLHandler::ImportXML(wxRichTextBuffer* buffer, wxXmlNode* node)
89 {
90 wxString name = node->GetName();
91
92 bool doneChildren = false;
93
94 if (name == wxT("paragraphlayout"))
95 {
96 }
97 else if (name == wxT("paragraph"))
98 {
99 wxRichTextParagraph* para = new wxRichTextParagraph(buffer);
100 buffer->AppendChild(para);
101
102 GetStyle(para->GetAttributes(), node, true);
103
104 wxXmlNode* child = node->GetChildren();
105 while (child)
106 {
107 wxString childName = child->GetName();
108 if (childName == wxT("text"))
109 {
110 wxString text;
111 wxXmlNode* textChild = child->GetChildren();
112 while (textChild)
113 {
114 if (textChild->GetType() == wxXML_TEXT_NODE ||
115 textChild->GetType() == wxXML_CDATA_SECTION_NODE)
116 {
117 wxString text2 = textChild->GetContent();
118
119 // Strip whitespace from end
120 if (text2.Length() > 0 && text2[text2.Length()-1] == wxT('\n'))
121 text2 = text2.Mid(0, text2.Length()-1);
122
123 if (text2.Length() > 0 && text2[0] == wxT('"'))
124 text2 = text2.Mid(1);
125 if (text2.Length() > 0 && text2[text2.Length()-1] == wxT('"'))
126 text2 = text2.Mid(0, text2.Length() - 1);
127
128 // TODO: further entity translation
129 text2.Replace(wxT("&lt;"), wxT("<"));
130 text2.Replace(wxT("&gt;"), wxT(">"));
131 text2.Replace(wxT("&amp;"), wxT("&"));
132 text2.Replace(wxT("&quot;"), wxT("\""));
133
134 text += text2;
135 }
136 textChild = textChild->GetNext();
137 }
138
139 wxRichTextPlainText* textObject = new wxRichTextPlainText(text, para);
140 GetStyle(textObject->GetAttributes(), child, false);
141
142 para->AppendChild(textObject);
143 }
144 else if (childName == wxT("image"))
145 {
146 int imageType = wxBITMAP_TYPE_PNG;
147 wxString value = node->GetPropVal(wxT("imagetype"), wxEmptyString);
148 if (!value.empty())
149 imageType = wxAtoi(value);
150
151 wxString data;
152
153 wxXmlNode* imageChild = child->GetChildren();
154 while (imageChild)
155 {
156 wxString childName = imageChild->GetName();
157 if (childName == wxT("data"))
158 {
159 wxXmlNode* dataChild = imageChild->GetChildren();
160 while (dataChild)
161 {
162 data = dataChild->GetContent();
163 // wxLogDebug(data);
164 dataChild = dataChild->GetNext();
165 }
166
167 }
168 imageChild = imageChild->GetNext();
169 }
170
171 if (!data.empty())
172 {
173 wxRichTextImage* imageObj = new wxRichTextImage(para);
174 para->AppendChild(imageObj);
175
176 wxStringInputStream strStream(data);
177
178 imageObj->GetImageBlock().ReadHex(strStream, data.Length(), imageType);
179 }
180 }
181 child = child->GetNext();
182 }
183
184 doneChildren = true;
185 }
186
187 if (!doneChildren)
188 {
189 wxXmlNode* child = node->GetChildren();
190 while (child)
191 {
192 ImportXML(buffer, child);
193 child = child->GetNext();
194 }
195 }
196
197 return true;
198 }
199
200
201 //-----------------------------------------------------------------------------
202 // xml support routines
203 //-----------------------------------------------------------------------------
204
205 bool wxRichTextXMLHandler::HasParam(wxXmlNode* node, const wxString& param)
206 {
207 return (GetParamNode(node, param) != NULL);
208 }
209
210 wxXmlNode *wxRichTextXMLHandler::GetParamNode(wxXmlNode* node, const wxString& param)
211 {
212 wxCHECK_MSG(node, NULL, wxT("You can't access node data before it was initialized!"));
213
214 wxXmlNode *n = node->GetChildren();
215
216 while (n)
217 {
218 if (n->GetType() == wxXML_ELEMENT_NODE && n->GetName() == param)
219 return n;
220 n = n->GetNext();
221 }
222 return NULL;
223 }
224
225
226 wxString wxRichTextXMLHandler::GetNodeContent(wxXmlNode *node)
227 {
228 wxXmlNode *n = node;
229 if (n == NULL) return wxEmptyString;
230 n = n->GetChildren();
231
232 while (n)
233 {
234 if (n->GetType() == wxXML_TEXT_NODE ||
235 n->GetType() == wxXML_CDATA_SECTION_NODE)
236 return n->GetContent();
237 n = n->GetNext();
238 }
239 return wxEmptyString;
240 }
241
242
243 wxString wxRichTextXMLHandler::GetParamValue(wxXmlNode *node, const wxString& param)
244 {
245 if (param.empty())
246 return GetNodeContent(node);
247 else
248 return GetNodeContent(GetParamNode(node, param));
249 }
250
251 wxString wxRichTextXMLHandler::GetText(wxXmlNode *node, const wxString& param, bool WXUNUSED(translate))
252 {
253 wxXmlNode *parNode = GetParamNode(node, param);
254 if (!parNode)
255 parNode = node;
256 wxString str1(GetNodeContent(parNode));
257 return str1;
258 }
259
260 // For use with earlier versions of wxWidgets
261 #ifndef WXUNUSED_IN_UNICODE
262 #if wxUSE_UNICODE
263 #define WXUNUSED_IN_UNICODE(x) WXUNUSED(x)
264 #else
265 #define WXUNUSED_IN_UNICODE(x) x
266 #endif
267 #endif
268
269 // write string to output:
270 inline static void OutputString(wxOutputStream& stream, const wxString& str,
271 wxMBConv *WXUNUSED_IN_UNICODE(convMem) = NULL, wxMBConv *convFile = NULL)
272 {
273 if (str.empty()) return;
274 #if wxUSE_UNICODE
275 if (convFile)
276 {
277 const wxWX2MBbuf buf(str.mb_str(*convFile));
278 stream.Write((const char*)buf, strlen((const char*)buf));
279 }
280 else
281 {
282 const wxWX2MBbuf buf(str.mb_str(wxConvUTF8));
283 stream.Write((const char*)buf, strlen((const char*)buf));
284 }
285 #else
286 if ( convFile == NULL )
287 stream.Write(str.mb_str(), str.Len());
288 else
289 {
290 wxString str2(str.wc_str(*convMem), *convFile);
291 stream.Write(str2.mb_str(), str2.Len());
292 }
293 #endif
294 }
295
296 // Same as above, but create entities first.
297 // Translates '<' to "&lt;", '>' to "&gt;" and '&' to "&amp;"
298 static void OutputStringEnt(wxOutputStream& stream, const wxString& str,
299 wxMBConv *convMem = NULL, wxMBConv *convFile = NULL)
300 {
301 wxString buf;
302 size_t i, last, len;
303 wxChar c;
304
305 len = str.Len();
306 last = 0;
307 for (i = 0; i < len; i++)
308 {
309 c = str.GetChar(i);
310 if (c == wxT('<') || c == wxT('>') || c == wxT('"') ||
311 (c == wxT('&') && (str.Mid(i+1, 4) != wxT("amp;"))))
312 {
313 OutputString(stream, str.Mid(last, i - last), convMem, convFile);
314 switch (c)
315 {
316 case wxT('<'):
317 OutputString(stream, wxT("&lt;"), NULL, NULL);
318 break;
319 case wxT('>'):
320 OutputString(stream, wxT("&gt;"), NULL, NULL);
321 break;
322 case wxT('&'):
323 OutputString(stream, wxT("&amp;"), NULL, NULL);
324 break;
325 case wxT('"'):
326 OutputString(stream, wxT("&quot;"), NULL, NULL);
327 break;
328 default: break;
329 }
330 last = i + 1;
331 }
332 }
333 OutputString(stream, str.Mid(last, i - last), convMem, convFile);
334 }
335
336 inline static void OutputIndentation(wxOutputStream& stream, int indent)
337 {
338 wxString str = wxT("\n");
339 for (int i = 0; i < indent; i++)
340 str << wxT(' ') << wxT(' ');
341 OutputString(stream, str, NULL, NULL);
342 }
343
344 static wxOutputStream& operator <<(wxOutputStream& stream, const wxString& s)
345 {
346 stream.Write(s, s.Length());
347 return stream;
348 }
349
350 #if 0
351 static wxOutputStream& operator <<(wxOutputStream& stream, long l)
352 {
353 wxString str;
354 str.Printf(wxT("%ld"), l);
355 return stream << str;
356 }
357
358 static wxOutputStream& operator <<(wxOutputStream& stream, const char c)
359 {
360 wxString str;
361 str.Printf(wxT("%c"), c);
362 return stream << str;
363 }
364 #endif
365
366 // Convert a colour to a 6-digit hex string
367 static wxString ColourToHexString(const wxColour& col)
368 {
369 wxString hex;
370
371 hex += wxDecToHex(col.Red());
372 hex += wxDecToHex(col.Green());
373 hex += wxDecToHex(col.Blue());
374
375 return hex;
376 }
377
378 // Convert 6-digit hex string to a colour
379 wxColour HexStringToColour(const wxString& hex)
380 {
381 unsigned char r = (unsigned char)wxHexToDec(hex.Mid(0, 2));
382 unsigned char g = (unsigned char)wxHexToDec(hex.Mid(2, 2));
383 unsigned char b = (unsigned char)wxHexToDec(hex.Mid(4, 2));
384
385 return wxColour(r, g, b);
386 }
387
388 bool wxRichTextXMLHandler::DoSaveFile(wxRichTextBuffer *buffer, wxOutputStream& stream)
389 {
390 if (!stream.IsOk())
391 return false;
392
393 wxString version(wxT("1.0") ) ;
394 #if wxUSE_UNICODE
395 wxString fileencoding(wxT("UTF-8")) ;
396 wxString memencoding(wxT("UTF-8")) ;
397 #else
398 wxString fileencoding(wxT("ISO-8859-1")) ;
399 wxString memencoding(wxT("ISO-8859-1")) ;
400 #endif
401 wxString s ;
402
403 wxMBConv *convMem = NULL, *convFile = NULL;
404 #if wxUSE_UNICODE
405 convFile = new wxCSConv(fileencoding);
406 #else
407 if ( fileencoding != memencoding )
408 {
409 convFile = new wxCSConv(fileencoding);
410 convMem = new wxCSConv(memencoding);
411 }
412 #endif
413
414 s.Printf(wxT("<?xml version=\"%s\" encoding=\"%s\"?>\n"),
415 (const wxChar*) version, (const wxChar*) fileencoding );
416 OutputString(stream, s, NULL, NULL);
417 OutputString(stream, wxT("<richtext version=\"1.0.0.0\" xmlns=\"http://www.wxwidgets.org\">") , NULL, NULL);
418
419 int level = 1;
420 ExportXML(stream, convMem, convFile, *buffer, level);
421
422 OutputString(stream, wxT("\n</richtext>") , NULL, NULL);
423 OutputString(stream, wxT("\n"), NULL, NULL);
424
425 delete convFile;
426 delete convMem;
427
428 return true;
429 }
430
431 /// Recursively export an object
432 bool wxRichTextXMLHandler::ExportXML(wxOutputStream& stream, wxMBConv* convMem, wxMBConv* convFile, wxRichTextObject& obj, int indent)
433 {
434 wxString objectName;
435 if (obj.IsKindOf(CLASSINFO(wxRichTextParagraphLayoutBox)))
436 objectName = wxT("paragraphlayout");
437 else if (obj.IsKindOf(CLASSINFO(wxRichTextParagraph)))
438 objectName = wxT("paragraph");
439 else if (obj.IsKindOf(CLASSINFO(wxRichTextPlainText)))
440 objectName = wxT("text");
441 else if (obj.IsKindOf(CLASSINFO(wxRichTextImage)))
442 objectName = wxT("image");
443 else
444 objectName = wxT("object");
445
446 if (obj.IsKindOf(CLASSINFO(wxRichTextPlainText)))
447 {
448 wxRichTextPlainText& text = (wxRichTextPlainText&) obj;
449
450 OutputIndentation(stream, indent);
451 stream << wxT("<") << objectName;
452
453 wxString style = CreateStyle(obj.GetAttributes(), false);
454
455 stream << style << wxT(">");
456
457 wxString str = text.GetText();
458 if (str.Length() > 0 && (str[0] == wxT(' ') || str[str.Length()-1] == wxT(' ')))
459 {
460 stream << wxT("\"");
461 OutputStringEnt(stream, str, convMem, convFile);
462 stream << wxT("\"");
463 }
464 else
465 OutputStringEnt(stream, str, convMem, convFile);
466 }
467 else if (obj.IsKindOf(CLASSINFO(wxRichTextImage)))
468 {
469 wxRichTextImage& imageObj = (wxRichTextImage&) obj;
470
471 if (imageObj.GetImage().Ok() && !imageObj.GetImageBlock().Ok())
472 imageObj.MakeBlock();
473
474 OutputIndentation(stream, indent);
475 stream << wxT("<") << objectName;
476 if (!imageObj.GetImageBlock().Ok())
477 {
478 // No data
479 stream << wxT(">");
480 }
481 else
482 {
483 stream << wxString::Format(wxT(" imagetype=\"%d\""), (int) imageObj.GetImageBlock().GetImageType()) << wxT(">");
484 }
485
486 OutputIndentation(stream, indent+1);
487 stream << wxT("<data>");
488
489 imageObj.GetImageBlock().WriteHex(stream);
490
491 stream << wxT("</data>");
492 }
493 else if (obj.IsKindOf(CLASSINFO(wxRichTextCompositeObject)))
494 {
495 OutputIndentation(stream, indent);
496 stream << wxT("<") << objectName;
497
498 bool isPara = false;
499 if (objectName == wxT("paragraph") || objectName == wxT("paragraphlayout"))
500 isPara = true;
501
502 wxString style = CreateStyle(obj.GetAttributes(), isPara);
503
504 stream << style << wxT(">");
505
506 wxRichTextCompositeObject& composite = (wxRichTextCompositeObject&) obj;
507 size_t i;
508 for (i = 0; i < composite.GetChildCount(); i++)
509 {
510 wxRichTextObject* child = composite.GetChild(i);
511 ExportXML(stream, convMem, convFile, *child, indent+1);
512 }
513 }
514
515 if (objectName != wxT("text"))
516 OutputIndentation(stream, indent);
517
518 stream << wxT("</") << objectName << wxT(">");
519
520 return true;
521 }
522
523 /// Create style parameters
524 wxString wxRichTextXMLHandler::CreateStyle(const wxTextAttrEx& attr, bool isPara)
525 {
526 wxString str;
527 if (attr.GetTextColour().Ok())
528 {
529 str << wxT(" textcolor=\"#") << ColourToHexString(attr.GetTextColour()) << wxT("\"");
530 }
531 if (attr.GetBackgroundColour().Ok())
532 {
533 str << wxT(" bgcolor=\"#") << ColourToHexString(attr.GetBackgroundColour()) << wxT("\"");
534 }
535
536 if (attr.GetFont().Ok())
537 {
538 str << wxT(" fontsize=\"") << attr.GetFont().GetPointSize() << wxT("\"");
539 str << wxT(" fontfamily=\"") << attr.GetFont().GetFamily() << wxT("\"");
540 str << wxT(" fontstyle=\"") << attr.GetFont().GetStyle() << wxT("\"");
541 str << wxT(" fontweight=\"") << attr.GetFont().GetWeight() << wxT("\"");
542 str << wxT(" fontunderlined=\"") << (int) attr.GetFont().GetUnderlined() << wxT("\"");
543 str << wxT(" fontface=\"") << attr.GetFont().GetFaceName() << wxT("\"");
544 }
545
546 if (!attr.GetCharacterStyleName().empty())
547 str << wxT(" charactertyle=\"") << wxString(attr.GetCharacterStyleName()) << wxT("\"");
548
549 if (isPara)
550 {
551 str << wxT(" alignment=\"") << (int) attr.GetAlignment() << wxT("\"");
552 str << wxT(" leftindent=\"") << (int) attr.GetLeftIndent() << wxT("\"");
553 str << wxT(" leftsubindent=\"") << (int) attr.GetLeftSubIndent() << wxT("\"");
554 str << wxT(" rightindent=\"") << (int) attr.GetRightIndent() << wxT("\"");
555 str << wxT(" parspacingafter=\"") << (int) attr.GetParagraphSpacingAfter() << wxT("\"");
556 str << wxT(" parspacingbefore=\"") << (int) attr.GetParagraphSpacingBefore() << wxT("\"");
557 str << wxT(" linespacing=\"") << (int) attr.GetLineSpacing() << wxT("\"");
558 str << wxT(" bulletstyle=\"") << (int) attr.GetBulletStyle() << wxT("\"");
559 str << wxT(" bulletnumber=\"") << (int) attr.GetBulletNumber() << wxT("\"");
560 str << wxT(" bulletsymbol=\"") << wxString(attr.GetBulletSymbol()) << wxT("\"");
561
562 if (!attr.GetParagraphStyleName().empty())
563 str << wxT(" parstyle=\"") << wxString(attr.GetParagraphStyleName()) << wxT("\"");
564 }
565
566 return str;
567 }
568
569 /// Get style parameters
570 bool wxRichTextXMLHandler::GetStyle(wxTextAttrEx& attr, wxXmlNode* node, bool isPara)
571 {
572 wxString fontFacename;
573 int fontSize = 12;
574 int fontFamily = wxDEFAULT;
575 int fontWeight = wxNORMAL;
576 int fontStyle = wxNORMAL;
577 bool fontUnderlined = false;
578
579 fontFacename = node->GetPropVal(wxT("fontface"), wxEmptyString);
580
581 wxString value = node->GetPropVal(wxT("fontfamily"), wxEmptyString);
582 if (!value.empty())
583 fontFamily = wxAtoi(value);
584
585 value = node->GetPropVal(wxT("fontstyle"), wxEmptyString);
586 if (!value.empty())
587 fontStyle = wxAtoi(value);
588
589 value = node->GetPropVal(wxT("fontsize"), wxEmptyString);
590 if (!value.empty())
591 fontSize = wxAtoi(value);
592
593 value = node->GetPropVal(wxT("fontweight"), wxEmptyString);
594 if (!value.empty())
595 fontWeight = wxAtoi(value);
596
597 value = node->GetPropVal(wxT("fontunderlined"), wxEmptyString);
598 if (!value.empty())
599 fontUnderlined = wxAtoi(value) != 0;
600
601 attr.SetFont(* wxTheFontList->FindOrCreateFont(fontSize, fontFamily, fontStyle, fontWeight, fontUnderlined, fontFacename));
602
603 value = node->GetPropVal(wxT("textcolor"), wxEmptyString);
604 if (!value.empty())
605 {
606 if (value[0] == wxT('#'))
607 attr.SetTextColour(HexStringToColour(value.Mid(1)));
608 else
609 attr.SetTextColour(value);
610 }
611
612 value = node->GetPropVal(wxT("backgroundcolor"), wxEmptyString);
613 if (!value.empty())
614 {
615 if (value[0] == wxT('#'))
616 attr.SetBackgroundColour(HexStringToColour(value.Mid(1)));
617 else
618 attr.SetBackgroundColour(value);
619 }
620
621 value = node->GetPropVal(wxT("characterstyle"), wxEmptyString);
622 if (!value.empty())
623 attr.SetCharacterStyleName(value);
624
625 // Set paragraph attributes
626 if (isPara)
627 {
628 value = node->GetPropVal(wxT("alignment"), wxEmptyString);
629 if (!value.empty())
630 attr.SetAlignment((wxTextAttrAlignment) wxAtoi(value));
631
632 int leftSubIndent = 0;
633 int leftIndent = 0;
634 value = node->GetPropVal(wxT("leftindent"), wxEmptyString);
635 if (!value.empty())
636 leftIndent = wxAtoi(value);
637 value = node->GetPropVal(wxT("leftsubindent"), wxEmptyString);
638 if (!value.empty())
639 leftSubIndent = wxAtoi(value);
640 attr.SetLeftIndent(leftIndent, leftSubIndent);
641
642 value = node->GetPropVal(wxT("rightindent"), wxEmptyString);
643 if (!value.empty())
644 attr.SetRightIndent(wxAtoi(value));
645
646 value = node->GetPropVal(wxT("parspacingbefore"), wxEmptyString);
647 if (!value.empty())
648 attr.SetParagraphSpacingBefore(wxAtoi(value));
649
650 value = node->GetPropVal(wxT("parspacingafter"), wxEmptyString);
651 if (!value.empty())
652 attr.SetParagraphSpacingAfter(wxAtoi(value));
653
654 value = node->GetPropVal(wxT("linespacing"), wxEmptyString);
655 if (!value.empty())
656 attr.SetLineSpacing(wxAtoi(value));
657
658 value = node->GetPropVal(wxT("bulletstyle"), wxEmptyString);
659 if (!value.empty())
660 attr.SetBulletStyle(wxAtoi(value));
661
662 value = node->GetPropVal(wxT("bulletnumber"), wxEmptyString);
663 if (!value.empty())
664 attr.SetBulletNumber(wxAtoi(value));
665
666 value = node->GetPropVal(wxT("bulletsymbol"), wxEmptyString);
667 if (!value.empty())
668 attr.SetBulletSymbol(value[0]);
669
670 value = node->GetPropVal(wxT("parstyle"), wxEmptyString);
671 if (!value.empty())
672 attr.SetParagraphStyleName(value);
673 }
674
675 return true;
676 }
677
678 #endif
679
680 IMPLEMENT_DYNAMIC_CLASS(wxRichTextHTMLHandler, wxRichTextFileHandler)
681
682 /// Can we handle this filename (if using files)? By default, checks the extension.
683 bool wxRichTextHTMLHandler::CanHandle(const wxString& filename) const
684 {
685 wxString path, file, ext;
686 wxSplitPath(filename, & path, & file, & ext);
687
688 return (ext.Lower() == wxT("html") || ext.Lower() == wxT("htm"));
689 }
690
691
692 #if wxUSE_STREAMS
693 bool wxRichTextHTMLHandler::DoLoadFile(wxRichTextBuffer *WXUNUSED(buffer), wxInputStream& WXUNUSED(stream))
694 {
695 return false;
696 }
697
698 /*
699 * We need to output only _changes_ in character formatting.
700 */
701
702 bool wxRichTextHTMLHandler::DoSaveFile(wxRichTextBuffer *buffer, wxOutputStream& stream)
703 {
704 buffer->Defragment();
705
706 wxTextOutputStream str(stream);
707
708 wxTextAttrEx currentParaStyle = buffer->GetAttributes();
709 wxTextAttrEx currentCharStyle = buffer->GetAttributes();
710
711 str << wxT("<html><head></head><body>\n");
712
713 wxRichTextObjectList::compatibility_iterator node = buffer->GetChildren().GetFirst();
714 while (node)
715 {
716 wxRichTextParagraph* para = wxDynamicCast(node->GetData(), wxRichTextParagraph);
717 wxASSERT (para != NULL);
718
719 if (para)
720 {
721 OutputParagraphFormatting(currentParaStyle, para->GetAttributes(), stream, true);
722
723 wxRichTextObjectList::compatibility_iterator node2 = para->GetChildren().GetFirst();
724 while (node2)
725 {
726 wxRichTextObject* obj = node2->GetData();
727 wxRichTextPlainText* textObj = wxDynamicCast(obj, wxRichTextPlainText);
728 if (textObj && !textObj->IsEmpty())
729 {
730 OutputCharacterFormatting(currentCharStyle, obj->GetAttributes(), stream, true);
731
732 str << textObj->GetText();
733
734 OutputCharacterFormatting(currentCharStyle, obj->GetAttributes(), stream, false);
735 }
736
737 node2 = node2->GetNext();
738 }
739
740 OutputParagraphFormatting(currentParaStyle, para->GetAttributes(), stream, false);
741
742 str << wxT("<P>\n");
743 }
744
745 node = node->GetNext();
746 }
747
748 str << wxT("</body></html>\n");
749
750 return true;
751 }
752
753 /// Output character formatting
754 void wxRichTextHTMLHandler::OutputCharacterFormatting(const wxTextAttrEx& WXUNUSED(currentStyle), const wxTextAttrEx& thisStyle, wxOutputStream& stream, bool start)
755 {
756 wxTextOutputStream str(stream);
757
758 bool isBold = false;
759 bool isItalic = false;
760 bool isUnderline = false;
761 wxString faceName;
762
763 if (thisStyle.GetFont().Ok())
764 {
765 if (thisStyle.GetFont().GetWeight() == wxBOLD)
766 isBold = true;
767 if (thisStyle.GetFont().GetStyle() == wxITALIC)
768 isItalic = true;
769 if (thisStyle.GetFont().GetUnderlined())
770 isUnderline = true;
771
772 faceName = thisStyle.GetFont().GetFaceName();
773 }
774
775 if (start)
776 {
777 if (isBold)
778 str << wxT("<b>");
779 if (isItalic)
780 str << wxT("<i>");
781 if (isUnderline)
782 str << wxT("<u>");
783 }
784 else
785 {
786 if (isUnderline)
787 str << wxT("</u>");
788 if (isItalic)
789 str << wxT("</i>");
790 if (isBold)
791 str << wxT("</b>");
792 }
793 }
794
795 /// Output paragraph formatting
796 void wxRichTextHTMLHandler::OutputParagraphFormatting(const wxTextAttrEx& WXUNUSED(currentStyle), const wxTextAttrEx& thisStyle, wxOutputStream& stream, bool start)
797 {
798 // TODO: lists, indentation (using tables), fonts, right-align, ...
799
800 wxTextOutputStream str(stream);
801 bool isCentered = false;
802
803 if (thisStyle.GetAlignment() == wxTEXT_ALIGNMENT_CENTRE)
804 {
805 isCentered = true;
806 }
807
808 if (start)
809 {
810 if (isCentered)
811 str << wxT("<center>");
812 }
813 else
814 {
815 if (isCentered)
816 str << wxT("</center>");
817 }
818 }
819
820 #endif
821
822 #endif
823 // wxUSE_RICHTEXT