]> git.saurik.com Git - wxWidgets.git/blob - src/richtext/richtexthtml.cpp
minor tab height bug fix
[wxWidgets.git] / src / richtext / richtexthtml.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/richtext/richtexthtml.cpp
3 // Purpose: 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 #if wxUSE_RICHTEXT
20
21 #include "wx/richtext/richtexthtml.h"
22
23 #ifndef WX_PRECOMP
24 #endif
25
26 #include "wx/filename.h"
27 #include "wx/wfstream.h"
28 #include "wx/txtstrm.h"
29
30 #if wxUSE_FILESYSTEM
31 #include "wx/filesys.h"
32 #include "wx/fs_mem.h"
33 #endif
34
35 IMPLEMENT_DYNAMIC_CLASS(wxRichTextHTMLHandler, wxRichTextFileHandler)
36
37 int wxRichTextHTMLHandler::sm_fileCounter = 1;
38
39 /// Can we handle this filename (if using files)? By default, checks the extension.
40 bool wxRichTextHTMLHandler::CanHandle(const wxString& filename) const
41 {
42 wxString path, file, ext;
43 wxSplitPath(filename, & path, & file, & ext);
44
45 return (ext.Lower() == wxT("html") || ext.Lower() == wxT("htm"));
46 }
47
48
49 #if wxUSE_STREAMS
50 bool wxRichTextHTMLHandler::DoLoadFile(wxRichTextBuffer *WXUNUSED(buffer), wxInputStream& WXUNUSED(stream))
51 {
52 return false;
53 }
54
55 /*
56 * We need to output only _changes_ in character formatting.
57 */
58
59 bool wxRichTextHTMLHandler::DoSaveFile(wxRichTextBuffer *buffer, wxOutputStream& stream)
60 {
61 ClearTemporaryImageLocations();
62
63 buffer->Defragment();
64
65 wxTextOutputStream str(stream);
66
67 wxTextAttrEx currentParaStyle = buffer->GetAttributes();
68 wxTextAttrEx currentCharStyle = buffer->GetAttributes();
69
70 str << wxT("<html><head></head><body>\n");
71
72 str << wxT("<table border=0 cellpadding=0 cellspacing=0><tr><td width=\"100%\">");
73
74 str << wxString::Format(wxT("<font face=\"%s\" size=\"%ld\" color=\"%s\" >"),
75 currentParaStyle.GetFont().GetFaceName().c_str(), PtToSize(currentParaStyle.GetFont().GetPointSize()),
76 currentParaStyle.GetTextColour().GetAsString(wxC2S_HTML_SYNTAX).c_str());
77
78 m_font = false;
79 m_indent = 0;
80 m_list = false;
81
82 wxRichTextObjectList::compatibility_iterator node = buffer->GetChildren().GetFirst();
83 while (node)
84 {
85 wxRichTextParagraph* para = wxDynamicCast(node->GetData(), wxRichTextParagraph);
86 wxASSERT (para != NULL);
87
88 if (para)
89 {
90 wxTextAttrEx paraStyle(para->GetCombinedAttributes());
91
92 OutputParagraphFormatting(currentParaStyle, paraStyle, stream);
93
94 wxRichTextObjectList::compatibility_iterator node2 = para->GetChildren().GetFirst();
95 while (node2)
96 {
97 wxRichTextObject* obj = node2->GetData();
98 wxRichTextPlainText* textObj = wxDynamicCast(obj, wxRichTextPlainText);
99 if (textObj && !textObj->IsEmpty())
100 {
101 wxTextAttrEx charStyle(para->GetCombinedAttributes(obj->GetAttributes()));
102 BeginCharacterFormatting(currentCharStyle, charStyle, paraStyle, stream);
103
104 wxString text = textObj->GetText();
105
106 if (charStyle.HasTextEffects() && (charStyle.GetTextEffects() & wxTEXT_ATTR_EFFECT_CAPITALS))
107 text.MakeUpper();
108
109 str << text;
110
111 EndCharacterFormatting(currentCharStyle, charStyle, paraStyle, stream);
112 }
113
114 wxRichTextImage* image = wxDynamicCast(obj, wxRichTextImage);
115 if( image && !image->IsEmpty())
116 WriteImage( image, stream );
117
118 node2 = node2->GetNext();
119 }
120 str << wxT("\n");
121 }
122 node = node->GetNext();
123 }
124
125 str << wxT("</font></td></tr></table></body></html>\n");
126
127 return true;
128 }
129
130 void wxRichTextHTMLHandler::BeginCharacterFormatting(const wxTextAttrEx& currentStyle, const wxTextAttrEx& thisStyle, const wxTextAttrEx& paraStyle, wxOutputStream& stream)
131 {
132 wxTextOutputStream str(stream);
133
134 // Is the item a bulleted one?
135 if ( paraStyle.GetBulletStyle() != wxTEXT_ATTR_BULLET_STYLE_NONE )
136 {
137 // Is there any opened list?
138 if (m_list)
139 {
140 // Yes there is
141
142 // Is the item among the previous ones?
143 // Is the item one of the previous list tag's child items?
144 if ((paraStyle.GetLeftIndent() == (m_indent + 100)) || (paraStyle.GetLeftIndent() < 100))
145 str << wxT("<li>"); //Yes it is
146 else
147 {
148 // No it isn't, so we should close the list tag
149 str << (m_is_ul ? wxT("</ul>") : wxT("</ol>"));
150
151 // And renavigate to new list's horizontal position
152 NavigateToListPosition(paraStyle, str);
153
154 // Get the appropriate tag, an ol for numerical values, an ul for dot, square etc.
155 wxString tag;
156 TypeOfList(paraStyle, tag);
157 str << tag << wxT("<li>");
158 }
159 }
160 else
161 {
162 // No there isn't a list.
163 // navigate to new list's horizontal position(indent)
164 NavigateToListPosition(paraStyle, str);
165
166 // Get the appropriate tag, an ol for numerical values, an ul for dot, square etc.
167 wxString tag;
168 TypeOfList(paraStyle, tag);
169 str << tag << wxT("<li>");
170
171 // Now we have a list, mark it.
172 m_list = true;
173 }
174 }
175 else if( m_list )
176 {
177 // The item is not bulleted and there is a list what should be closed now.
178 // So close the list
179
180 str << (m_is_ul ? wxT("</ul>") : wxT("</ol>"));
181
182 // And mark as there is no an opened list
183 m_list = false;
184 }
185
186 // does the item have an indentation ?
187 if( paraStyle.GetLeftIndent() )
188 {
189 if (paraStyle.GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_NONE)
190 {
191 if (m_indent)
192 {
193 if ((paraStyle.GetLeftIndent() + paraStyle.GetLeftSubIndent()) == m_indent)
194 {
195 if (paraStyle.GetLeftSubIndent() < 0)
196 {
197 str << SymbolicIndent(~paraStyle.GetLeftSubIndent());
198 }
199 }
200 else
201 {
202 if (paraStyle.GetLeftIndent() + paraStyle.GetLeftSubIndent() > m_indent)
203 {
204 Indent(paraStyle, str);
205 m_indent = paraStyle.GetLeftIndent() + paraStyle.GetLeftSubIndent();
206 m_indents.Add( m_indent );
207 }
208 else
209 {
210 int i = m_indents.size() - 1;
211 for (; i > -1; i--)
212 {
213 if (m_indent < (paraStyle.GetLeftIndent() + paraStyle.GetLeftSubIndent()))
214 {
215 Indent(paraStyle, str);
216 m_indent = paraStyle.GetLeftIndent() + paraStyle.GetLeftSubIndent();
217 m_indents.Add( m_indent );
218
219 break;
220 }
221 else if (m_indent == (paraStyle.GetLeftIndent() + paraStyle.GetLeftSubIndent()))
222 {
223 if (paraStyle.GetLeftSubIndent() < 0)
224 {
225 str << SymbolicIndent(~paraStyle.GetLeftSubIndent());
226 }
227 break;
228 }
229 else
230 {
231 str << wxT("</td></tr></table>");
232
233 m_indents.RemoveAt(i);
234
235 if(i < 1)
236 {
237 m_indent=0; break;
238 }
239 m_indent = m_indents[i-1];
240 }
241 }
242 }
243 }
244 }
245 else
246 {
247 Indent(paraStyle, str);
248 m_indent = paraStyle.GetLeftIndent() + paraStyle.GetLeftSubIndent();
249 m_indents.Add( m_indent );
250 }
251 }
252 }
253 else if (m_indent)
254 {
255 // The item is not indented and there is a table(s) that should be closed now.
256
257 for (unsigned int i = 0; i < m_indents.size(); i++)
258 str << wxT("</td></tr></table>");
259
260 m_indent = 0;
261 m_indents.Clear();
262 }
263
264
265 wxString style;
266
267 // Is there any change in the font properties of the item?
268 if (thisStyle.GetFont().GetFaceName() != currentStyle.GetFont().GetFaceName())
269 {
270 wxString faceName(thisStyle.GetFont().GetFaceName());
271 style += wxString::Format(wxT(" face=\"%s\""), faceName.c_str());
272 }
273 if (thisStyle.GetFont().GetPointSize() != currentStyle.GetFont().GetPointSize())
274 style += wxString::Format(wxT(" size=\"%ld\""), PtToSize(thisStyle.GetFont().GetPointSize()));
275 if (thisStyle.GetTextColour() != currentStyle.GetTextColour() )
276 {
277 wxString color(thisStyle.GetTextColour().GetAsString(wxC2S_HTML_SYNTAX));
278 style += wxString::Format(wxT(" color=\"%s\""), color.c_str());
279 }
280
281 if (style.size())
282 {
283 str << wxString::Format(wxT("<font %s >"), style.c_str());
284 m_font = true;
285 }
286
287 if (thisStyle.GetFont().GetWeight() == wxBOLD)
288 str << wxT("<b>");
289 if (thisStyle.GetFont().GetStyle() == wxITALIC)
290 str << wxT("<i>");
291 if (thisStyle.GetFont().GetUnderlined())
292 str << wxT("<u>");
293
294 if (thisStyle.HasURL())
295 str << wxT("<a href=\"") << thisStyle.GetURL() << wxT("\">");
296 }
297
298 void wxRichTextHTMLHandler::EndCharacterFormatting(const wxTextAttrEx& WXUNUSED(currentStyle), const wxTextAttrEx& thisStyle, const wxTextAttrEx& WXUNUSED(paraStyle), wxOutputStream& stream)
299 {
300 wxTextOutputStream str(stream);
301
302 if (thisStyle.HasURL())
303 str << wxT("</a>");
304
305 if (thisStyle.GetFont().GetUnderlined())
306 str << wxT("</u>");
307 if (thisStyle.GetFont().GetStyle() == wxITALIC)
308 str << wxT("</i>");
309 if (thisStyle.GetFont().GetWeight() == wxBOLD)
310 str << wxT("</b>");
311
312 if (m_font)
313 {
314 m_font = false;
315 str << wxT("</font>");
316 }
317 }
318
319 /// Output paragraph formatting
320 void wxRichTextHTMLHandler::OutputParagraphFormatting(const wxTextAttrEx& WXUNUSED(currentStyle), const wxTextAttrEx& thisStyle, wxOutputStream& stream)
321 {
322 // If there is no opened list currently, insert a <p> after every paragraph
323 if (!m_list)
324 {
325 wxTextOutputStream str(stream);
326 wxString align = GetAlignment(thisStyle);
327 str << wxString::Format(wxT("<p align=\"%s\">"), align.c_str());
328 }
329
330 if (thisStyle.HasPageBreak())
331 {
332 wxTextOutputStream str(stream);
333 str << wxT("<div style=\"page-break-after:always\"></div>\n");
334 }
335 }
336
337 void wxRichTextHTMLHandler::NavigateToListPosition(const wxTextAttrEx& thisStyle, wxTextOutputStream& str)
338 {
339 // indenting an item using an ul/ol tag is equal to inserting 5 x &nbsp; on its left side.
340 // so we should start from 100 point left
341
342 // Is the second td's left wall of the current indentaion table at the 100+ point-left-side
343 // of the item, horizontally?
344 if (m_indent + 100 < thisStyle.GetLeftIndent())
345 {
346 // yes it is
347 LIndent(thisStyle, str);
348 m_indent = thisStyle.GetLeftIndent() - 100;
349 m_indents.Add( m_indent );
350 return;
351 }
352 // No it isn't
353
354 int i = m_indents.size() - 1;
355 for (; i > -1; i--)
356 {
357 //Is the second td's left wall of the current indentaion table at the 100+ point-left-side
358 //of the item ?
359 if (m_indent + 100 < thisStyle.GetLeftIndent())
360 {
361 // Yes it is
362 LIndent(thisStyle, str);
363 m_indent = thisStyle.GetLeftIndent() - 100;
364 m_indents.Add( m_indent );
365 break;
366 }
367 else if (m_indent + 100 == thisStyle.GetLeftIndent())
368 break; //exact match
369 else
370 {
371 // No it is not, the second td's left wall of the current indentaion table is at the
372 //right side of the current item horizontally, so close it.
373 str << wxT("</td></tr></table>");
374
375 m_indents.RemoveAt(i);
376
377 if (i < 1)
378 {
379 m_indent=0; break;
380 }
381 m_indent = m_indents[i-1];
382 }
383 }
384 }
385 void wxRichTextHTMLHandler::Indent( const wxTextAttrEx& thisStyle, wxTextOutputStream& str )
386 {
387 //There is no way to indent an item in HTML, but we can use tables.
388
389 // Item -> "Hello world"
390 // Its Left Indentation -> 100
391 // Its Left Sub-Indentation ->40
392 // A typical indentation-table for the item will be construct as the following
393
394 // 3 x nbsp = 60
395 // 2 x nbsp = 40
396 // LSI = Left Sub Indent
397 // LI = Left Indent - LSI
398 //
399 // -------------------------------------------
400 // |&nbsp;&nbsp;nbsp;|nbsp;nbsp;Hello World |
401 // | | | | |
402 // | V | V |
403 // | --LI-- | --LSI-- |
404 // -------------------------------------------
405
406 str << wxT("<table width=\"100%\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tr>");
407
408 wxString symbolic_indent = SymbolicIndent( (thisStyle.GetLeftIndent() + thisStyle.GetLeftSubIndent()) - m_indent );
409 str << wxString::Format( wxT("<td>%s</td>"), symbolic_indent.c_str() );
410 str << wxT("<td width=\"100%\">");
411
412 if (thisStyle.GetLeftSubIndent() < 0)
413 {
414 str << SymbolicIndent(~thisStyle.GetLeftSubIndent());
415 }
416 }
417
418 void wxRichTextHTMLHandler::LIndent( const wxTextAttrEx& thisStyle, wxTextOutputStream& str )
419 {
420 // Code:
421 // r.BeginNumberedBullet(1, 200, 60);
422 // r.Newline();
423 // r.WriteText(wxT("first item"));
424 // r.EndNumberedBullet();
425 // r.BeginNumberedBullet(2, 200, 60);
426 // r.Newline();
427 // r.WriteText(wxT("second item."));
428 // r.EndNumberedBullet();
429 //
430 // A typical indentation-table for the item will be construct as the following
431
432 // 1 x nbsp = 20 point
433 // ULI -> 100pt (UL/OL tag indents its sub element by 100 point)
434 // <--------- 100 pt ---------->|
435 // ------------------------------------------------------
436 // |&nbsp;&nbsp;nbsp;&nbsp;nbsp;|<ul> |
437 // | |<-ULI-><li>first item |
438 // | |<-ULI-><li>second item |
439 // | |</ul> |
440 // ------------------------------------------------------
441 // |<-100->|
442
443
444 str << wxT("<table width=\"100%\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tr>");
445
446 wxString symbolic_indent = SymbolicIndent( (thisStyle.GetLeftIndent() - m_indent) - 100);
447 str << wxString::Format( wxT("<td>%s</td>"), symbolic_indent.c_str() );
448 str << wxT("<td width=\"100%\">");
449 }
450
451 void wxRichTextHTMLHandler::TypeOfList( const wxTextAttrEx& thisStyle, wxString& tag )
452 {
453 // We can use number attribute of li tag but not all the browsers support it.
454 // also wxHtmlWindow doesn't support type attribute.
455
456 m_is_ul = false;
457 if (thisStyle.GetBulletStyle() == (wxTEXT_ATTR_BULLET_STYLE_ARABIC|wxTEXT_ATTR_BULLET_STYLE_PERIOD))
458 tag = wxT("<ol type=\"1\">");
459 else if (thisStyle.GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_LETTERS_UPPER)
460 tag = wxT("<ol type=\"A\">");
461 else if (thisStyle.GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_LETTERS_LOWER)
462 tag = wxT("<ol type=\"a\">");
463 else if (thisStyle.GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_ROMAN_UPPER)
464 tag = wxT("<ol type=\"I\">");
465 else if (thisStyle.GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_ROMAN_LOWER)
466 tag = wxT("<ol type=\"i\">");
467 else
468 {
469 tag = wxT("<ul>");
470 m_is_ul = true;
471 }
472 }
473
474 wxString wxRichTextHTMLHandler::GetAlignment( const wxTextAttrEx& thisStyle )
475 {
476 switch( thisStyle.GetAlignment() )
477 {
478 case wxTEXT_ALIGNMENT_LEFT:
479 return wxT("left");
480 case wxTEXT_ALIGNMENT_RIGHT:
481 return wxT("right");
482 case wxTEXT_ALIGNMENT_CENTER:
483 return wxT("center");
484 case wxTEXT_ALIGNMENT_JUSTIFIED:
485 return wxT("justify");
486 default:
487 return wxT("left");
488 }
489 }
490
491 void wxRichTextHTMLHandler::WriteImage(wxRichTextImage* image, wxOutputStream& stream)
492 {
493 wxTextOutputStream str(stream);
494
495 str << wxT("<img src=\"");
496
497 #if wxUSE_FILESYSTEM
498 if (GetFlags() & wxRICHTEXT_HANDLER_SAVE_IMAGES_TO_MEMORY)
499 {
500 if (!image->GetImage().Ok() && image->GetImageBlock().GetData())
501 image->LoadFromBlock();
502 if (image->GetImage().Ok() && !image->GetImageBlock().GetData())
503 image->MakeBlock();
504
505 if (image->GetImage().Ok())
506 {
507 wxString ext(image->GetImageBlock().GetExtension());
508 wxString tempFilename(wxString::Format(wxT("image%d.%s"), sm_fileCounter, (const wxChar*) ext));
509 wxMemoryFSHandler::AddFile(tempFilename, image->GetImage(), image->GetImageBlock().GetImageType());
510
511 m_imageLocations.Add(tempFilename);
512
513 str << wxT("memory:") << tempFilename;
514 }
515 else
516 str << wxT("memory:?");
517
518 sm_fileCounter ++;
519 }
520 else if (GetFlags() & wxRICHTEXT_HANDLER_SAVE_IMAGES_TO_FILES)
521 {
522 if (!image->GetImage().Ok() && image->GetImageBlock().GetData())
523 image->LoadFromBlock();
524 if (image->GetImage().Ok() && !image->GetImageBlock().GetData())
525 image->MakeBlock();
526
527 if (image->GetImage().Ok())
528 {
529 wxString tempDir(GetTempDir());
530 if (tempDir.IsEmpty())
531 tempDir = wxFileName::GetTempDir();
532
533 wxString ext(image->GetImageBlock().GetExtension());
534 wxString tempFilename(wxString::Format(wxT("%s/image%d.%s"), (const wxChar*) tempDir, sm_fileCounter, (const wxChar*) ext));
535 image->GetImageBlock().Write(tempFilename);
536
537 m_imageLocations.Add(tempFilename);
538
539 str << wxFileSystem::FileNameToURL(tempFilename);
540 }
541 else
542 str << wxT("file:?");
543
544 sm_fileCounter ++;
545 }
546 else // if (GetFlags() & wxRICHTEXT_HANDLER_SAVE_IMAGES_TO_BASE64) // this is implied
547 #endif
548 {
549 str << wxT("data:");
550 str << GetMimeType(image->GetImageBlock().GetImageType());
551 str << wxT(";base64,");
552
553 if (image->GetImage().Ok() && !image->GetImageBlock().GetData())
554 image->MakeBlock();
555
556 wxChar* data = b64enc( image->GetImageBlock().GetData(), image->GetImageBlock().GetDataSize() );
557 str << data;
558
559 delete[] data;
560 }
561
562 str << wxT("\" />");
563 }
564
565 long wxRichTextHTMLHandler::PtToSize(long size)
566 {
567 // return approximate size
568 if (size < 9 ) return 1;
569 else if( size < 11 ) return 2;
570 else if( size < 14 ) return 3;
571 else if( size < 18 ) return 4;
572 else if( size < 23 ) return 5;
573 else if( size < 30 ) return 6;
574 else return 7;
575 }
576
577 wxString wxRichTextHTMLHandler::SymbolicIndent(long indent)
578 {
579 wxString in;
580 for(;indent > 0; indent -= 20)
581 in.Append( wxT("&nbsp;") );
582 return in;
583 }
584
585 const wxChar* wxRichTextHTMLHandler::GetMimeType(int imageType)
586 {
587 switch(imageType)
588 {
589 case wxBITMAP_TYPE_BMP:
590 return wxT("image/bmp");
591 case wxBITMAP_TYPE_TIF:
592 return wxT("image/tiff");
593 case wxBITMAP_TYPE_GIF:
594 return wxT("image/gif");
595 case wxBITMAP_TYPE_PNG:
596 return wxT("image/png");
597 case wxBITMAP_TYPE_JPEG:
598 return wxT("image/jpeg");
599 default:
600 return wxT("image/unknown");
601 }
602 }
603
604 // exim-style base64 encoder
605 wxChar* wxRichTextHTMLHandler::b64enc( unsigned char* input, size_t in_len )
606 {
607 // elements of enc64 array must be 8 bit values
608 // otherwise encoder will fail
609 // hmmm.. Does wxT macro define a char as 16 bit value
610 // when compiling with UNICODE option?
611 static const wxChar enc64[] = wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
612 wxChar* output = new wxChar[4*((in_len+2)/3)+1];
613 wxChar* p = output;
614
615 while( in_len-- > 0 )
616 {
617 register wxChar a, b;
618
619 a = *input++;
620
621 *p++ = enc64[ (a >> 2) & 0x3f ];
622
623 if( in_len-- == 0 )
624 {
625 *p++ = enc64[ (a << 4 ) & 0x30 ];
626 *p++ = '=';
627 *p++ = '=';
628 break;
629 }
630
631 b = *input++;
632
633 *p++ = enc64[(( a << 4 ) | ((b >> 4) &0xf )) & 0x3f];
634
635 if( in_len-- == 0 )
636 {
637 *p++ = enc64[ (b << 2) & 0x3f ];
638 *p++ = '=';
639 break;
640 }
641
642 a = *input++;
643
644 *p++ = enc64[ ((( b << 2 ) & 0x3f ) | ((a >> 6)& 0x3)) & 0x3f ];
645
646 *p++ = enc64[ a & 0x3f ];
647 }
648 *p = 0;
649
650 return output;
651 }
652 #endif
653 // wxUSE_STREAMS
654
655 /// Delete the in-memory or temporary files generated by the last operation
656 bool wxRichTextHTMLHandler::DeleteTemporaryImages()
657 {
658 return DeleteTemporaryImages(GetFlags(), m_imageLocations);
659 }
660
661 /// Delete the in-memory or temporary files generated by the last operation
662 bool wxRichTextHTMLHandler::DeleteTemporaryImages(int flags, const wxArrayString& imageLocations)
663 {
664 size_t i;
665 for (i = 0; i < imageLocations.GetCount(); i++)
666 {
667 wxString location = imageLocations[i];
668
669 if (flags & wxRICHTEXT_HANDLER_SAVE_IMAGES_TO_MEMORY)
670 {
671 #if wxUSE_FILESYSTEM
672 wxMemoryFSHandler::RemoveFile(location);
673 #endif
674 }
675 else if (flags & wxRICHTEXT_HANDLER_SAVE_IMAGES_TO_FILES)
676 {
677 if (wxFileExists(location))
678 wxRemoveFile(location);
679 }
680 }
681
682 return true;
683 }
684
685
686 #endif
687 // wxUSE_RICHTEXT
688