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