]> git.saurik.com Git - wxWidgets.git/blame - src/richtext/richtexthtml.cpp
added missing blank line
[wxWidgets.git] / src / richtext / richtexthtml.cpp
CommitLineData
b71e9aa4 1/////////////////////////////////////////////////////////////////////////////
40989e46 2// Name: src/richtext/richtexthtml.cpp
b71e9aa4
JS
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__
40989e46 16 #pragma hdrstop
b71e9aa4
JS
17#endif
18
19#if wxUSE_RICHTEXT
20
21#include "wx/richtext/richtexthtml.h"
22
23#ifndef WX_PRECOMP
b71e9aa4
JS
24#endif
25
26#include "wx/filename.h"
27#include "wx/wfstream.h"
28#include "wx/txtstrm.h"
29
d2d0adc7
JS
30#if wxUSE_FILESYSTEM
31#include "wx/filesys.h"
32#include "wx/fs_mem.h"
33#endif
34
b71e9aa4
JS
35IMPLEMENT_DYNAMIC_CLASS(wxRichTextHTMLHandler, wxRichTextFileHandler)
36
d2d0adc7
JS
37int wxRichTextHTMLHandler::sm_fileCounter = 1;
38
b71e9aa4
JS
39/// Can we handle this filename (if using files)? By default, checks the extension.
40bool 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
50bool 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
59bool wxRichTextHTMLHandler::DoSaveFile(wxRichTextBuffer *buffer, wxOutputStream& stream)
60{
d2d0adc7
JS
61 ClearTemporaryImageLocations();
62
b71e9aa4 63 buffer->Defragment();
40989e46 64
b71e9aa4 65 wxTextOutputStream str(stream);
40989e46 66
b71e9aa4
JS
67 wxTextAttrEx currentParaStyle = buffer->GetAttributes();
68 wxTextAttrEx currentCharStyle = buffer->GetAttributes();
40989e46 69
b774c698
JS
70 if ((GetFlags() & wxRICHTEXT_HANDLER_NO_HEADER_FOOTER) == 0)
71 str << wxT("<html><head></head><body>\n");
40989e46 72
b774c698 73 str << wxT("<table border=0 cellpadding=0 cellspacing=0><tr><td width=\"100%\">\n");
40989e46
WS
74
75 str << wxString::Format(wxT("<font face=\"%s\" size=\"%ld\" color=\"%s\" >"),
d2d0adc7 76 currentParaStyle.GetFont().GetFaceName().c_str(), PtToSize(currentParaStyle.GetFont().GetPointSize()),
40989e46
WS
77 currentParaStyle.GetTextColour().GetAsString(wxC2S_HTML_SYNTAX).c_str());
78
2dec6761
JS
79 m_font = false;
80 m_indent = 0;
81 m_list = false;
40989e46 82
b71e9aa4
JS
83 wxRichTextObjectList::compatibility_iterator node = buffer->GetChildren().GetFirst();
84 while (node)
85 {
86 wxRichTextParagraph* para = wxDynamicCast(node->GetData(), wxRichTextParagraph);
87 wxASSERT (para != NULL);
40989e46 88
b71e9aa4
JS
89 if (para)
90 {
27507b61
JS
91 wxTextAttrEx paraStyle(para->GetCombinedAttributes());
92
93 OutputParagraphFormatting(currentParaStyle, paraStyle, stream);
40989e46 94
b71e9aa4
JS
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 {
27507b61
JS
102 wxTextAttrEx charStyle(para->GetCombinedAttributes(obj->GetAttributes()));
103 BeginCharacterFormatting(currentCharStyle, charStyle, paraStyle, stream);
42688aea
JS
104
105 wxString text = textObj->GetText();
40989e46 106
42688aea
JS
107 if (charStyle.HasTextEffects() && (charStyle.GetTextEffects() & wxTEXT_ATTR_EFFECT_CAPITALS))
108 text.MakeUpper();
109
110 str << text;
40989e46 111
27507b61 112 EndCharacterFormatting(currentCharStyle, charStyle, paraStyle, stream);
b71e9aa4 113 }
40989e46 114
2dec6761
JS
115 wxRichTextImage* image = wxDynamicCast(obj, wxRichTextImage);
116 if( image && !image->IsEmpty())
d2d0adc7 117 WriteImage( image, stream );
40989e46 118
b71e9aa4
JS
119 node2 = node2->GetNext();
120 }
d5363f57 121 str << wxT("\n");
b71e9aa4 122 }
b71e9aa4
JS
123 node = node->GetNext();
124 }
40989e46 125
b774c698
JS
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");
40989e46 132
b71e9aa4
JS
133 return true;
134}
135
27507b61 136void wxRichTextHTMLHandler::BeginCharacterFormatting(const wxTextAttrEx& currentStyle, const wxTextAttrEx& thisStyle, const wxTextAttrEx& paraStyle, wxOutputStream& stream)
b71e9aa4
JS
137{
138 wxTextOutputStream str(stream);
40989e46 139
d2d0adc7
JS
140 // Is the item a bulleted one?
141 if ( paraStyle.GetBulletStyle() != wxTEXT_ATTR_BULLET_STYLE_NONE )
b71e9aa4 142 {
d2d0adc7
JS
143 // Is there any opened list?
144 if (m_list)
2dec6761 145 {
d2d0adc7 146 // Yes there is
40989e46 147
d2d0adc7
JS
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
2dec6761
JS
152 else
153 {
d2d0adc7 154 // No it isn't, so we should close the list tag
2dec6761 155 str << (m_is_ul ? wxT("</ul>") : wxT("</ol>"));
40989e46 156
d2d0adc7 157 // And renavigate to new list's horizontal position
27507b61 158 NavigateToListPosition(paraStyle, str);
40989e46 159
d2d0adc7 160 // Get the appropriate tag, an ol for numerical values, an ul for dot, square etc.
2dec6761 161 wxString tag;
27507b61 162 TypeOfList(paraStyle, tag);
21e354f1 163 str << tag << wxT("<li>");
2dec6761
JS
164 }
165 }
166 else
167 {
d2d0adc7
JS
168 // No there isn't a list.
169 // navigate to new list's horizontal position(indent)
27507b61 170 NavigateToListPosition(paraStyle, str);
40989e46 171
d2d0adc7 172 // Get the appropriate tag, an ol for numerical values, an ul for dot, square etc.
2dec6761 173 wxString tag;
27507b61 174 TypeOfList(paraStyle, tag);
21e354f1 175 str << tag << wxT("<li>");
40989e46 176
d2d0adc7 177 // Now we have a list, mark it.
2dec6761 178 m_list = true;
40989e46 179 }
b71e9aa4 180 }
2dec6761
JS
181 else if( m_list )
182 {
b774c698 183 // The item is not bulleted and there is a list that should be closed now.
d2d0adc7 184 // So close the list
b71e9aa4 185
2dec6761 186 str << (m_is_ul ? wxT("</ul>") : wxT("</ol>"));
d2d0adc7
JS
187
188 // And mark as there is no an opened list
2dec6761
JS
189 m_list = false;
190 }
40989e46 191
2dec6761 192 // does the item have an indentation ?
27507b61 193 if( paraStyle.GetLeftIndent() )
b71e9aa4 194 {
d2d0adc7 195 if (paraStyle.GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_NONE)
2dec6761 196 {
d2d0adc7 197 if (m_indent)
2dec6761 198 {
d2d0adc7 199 if ((paraStyle.GetLeftIndent() + paraStyle.GetLeftSubIndent()) == m_indent)
2dec6761 200 {
d2d0adc7 201 if (paraStyle.GetLeftSubIndent() < 0)
2dec6761 202 {
27507b61 203 str << SymbolicIndent(~paraStyle.GetLeftSubIndent());
2dec6761
JS
204 }
205 }
206 else
207 {
d2d0adc7 208 if (paraStyle.GetLeftIndent() + paraStyle.GetLeftSubIndent() > m_indent)
2dec6761 209 {
27507b61
JS
210 Indent(paraStyle, str);
211 m_indent = paraStyle.GetLeftIndent() + paraStyle.GetLeftSubIndent();
2dec6761
JS
212 m_indents.Add( m_indent );
213 }
214 else
215 {
216 int i = m_indents.size() - 1;
d2d0adc7 217 for (; i > -1; i--)
2dec6761 218 {
d2d0adc7 219 if (m_indent < (paraStyle.GetLeftIndent() + paraStyle.GetLeftSubIndent()))
2dec6761 220 {
27507b61
JS
221 Indent(paraStyle, str);
222 m_indent = paraStyle.GetLeftIndent() + paraStyle.GetLeftSubIndent();
2dec6761 223 m_indents.Add( m_indent );
40989e46 224
2dec6761
JS
225 break;
226 }
d2d0adc7 227 else if (m_indent == (paraStyle.GetLeftIndent() + paraStyle.GetLeftSubIndent()))
2dec6761 228 {
d2d0adc7 229 if (paraStyle.GetLeftSubIndent() < 0)
2dec6761 230 {
27507b61 231 str << SymbolicIndent(~paraStyle.GetLeftSubIndent());
2dec6761
JS
232 }
233 break;
234 }
235 else
236 {
237 str << wxT("</td></tr></table>");
40989e46 238
2dec6761 239 m_indents.RemoveAt(i);
40989e46 240
d2d0adc7
JS
241 if(i < 1)
242 {
243 m_indent=0; break;
244 }
2dec6761
JS
245 m_indent = m_indents[i-1];
246 }
247 }
248 }
249 }
250 }
251 else
252 {
27507b61
JS
253 Indent(paraStyle, str);
254 m_indent = paraStyle.GetLeftIndent() + paraStyle.GetLeftSubIndent();
2dec6761
JS
255 m_indents.Add( m_indent );
256 }
257 }
b71e9aa4 258 }
d2d0adc7 259 else if (m_indent)
b71e9aa4 260 {
d2d0adc7 261 // The item is not indented and there is a table(s) that should be closed now.
40989e46 262
d2d0adc7 263 for (unsigned int i = 0; i < m_indents.size(); i++)
2dec6761 264 str << wxT("</td></tr></table>");
40989e46 265
2dec6761
JS
266 m_indent = 0;
267 m_indents.Clear();
b71e9aa4 268 }
40989e46
WS
269
270
2dec6761 271 wxString style;
40989e46 272
d2d0adc7
JS
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 }
40989e46 286
d2d0adc7 287 if (style.size())
21e354f1
JS
288 {
289 str << wxString::Format(wxT("<font %s >"), style.c_str());
290 m_font = true;
291 }
40989e46 292
d2d0adc7 293 if (thisStyle.GetFont().GetWeight() == wxBOLD)
2dec6761 294 str << wxT("<b>");
d2d0adc7 295 if (thisStyle.GetFont().GetStyle() == wxITALIC)
2dec6761 296 str << wxT("<i>");
d2d0adc7 297 if (thisStyle.GetFont().GetUnderlined())
2dec6761 298 str << wxT("<u>");
d2d0adc7
JS
299
300 if (thisStyle.HasURL())
301 str << wxT("<a href=\"") << thisStyle.GetURL() << wxT("\">");
b71e9aa4
JS
302}
303
27507b61 304void wxRichTextHTMLHandler::EndCharacterFormatting(const wxTextAttrEx& WXUNUSED(currentStyle), const wxTextAttrEx& thisStyle, const wxTextAttrEx& WXUNUSED(paraStyle), wxOutputStream& stream)
b71e9aa4 305{
b71e9aa4 306 wxTextOutputStream str(stream);
40989e46 307
d2d0adc7
JS
308 if (thisStyle.HasURL())
309 str << wxT("</a>");
310
311 if (thisStyle.GetFont().GetUnderlined())
2dec6761 312 str << wxT("</u>");
d2d0adc7 313 if (thisStyle.GetFont().GetStyle() == wxITALIC)
2dec6761 314 str << wxT("</i>");
d2d0adc7 315 if (thisStyle.GetFont().GetWeight() == wxBOLD)
2dec6761 316 str << wxT("</b>");
40989e46 317
d2d0adc7 318 if (m_font)
2dec6761
JS
319 {
320 m_font = false;
321 str << wxT("</font>");
322 }
323}
b71e9aa4 324
2dec6761
JS
325/// Output paragraph formatting
326void wxRichTextHTMLHandler::OutputParagraphFormatting(const wxTextAttrEx& WXUNUSED(currentStyle), const wxTextAttrEx& thisStyle, wxOutputStream& stream)
327{
d2d0adc7
JS
328 // If there is no opened list currently, insert a <p> after every paragraph
329 if (!m_list)
b71e9aa4 330 {
2dec6761 331 wxTextOutputStream str(stream);
d2d0adc7 332 wxString align = GetAlignment(thisStyle);
21e354f1 333 str << wxString::Format(wxT("<p align=\"%s\">"), align.c_str());
b71e9aa4 334 }
42688aea
JS
335
336 if (thisStyle.HasPageBreak())
337 {
338 wxTextOutputStream str(stream);
339 str << wxT("<div style=\"page-break-after:always\"></div>\n");
340 }
2dec6761 341}
b71e9aa4 342
2dec6761
JS
343void wxRichTextHTMLHandler::NavigateToListPosition(const wxTextAttrEx& thisStyle, wxTextOutputStream& str)
344{
d2d0adc7
JS
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
40989e46 347
d2d0adc7
JS
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())
b71e9aa4 351 {
d2d0adc7 352 // yes it is
2dec6761
JS
353 LIndent(thisStyle, str);
354 m_indent = thisStyle.GetLeftIndent() - 100;
355 m_indents.Add( m_indent );
356 return;
b71e9aa4 357 }
d2d0adc7 358 // No it isn't
40989e46 359
2dec6761 360 int i = m_indents.size() - 1;
d2d0adc7 361 for (; i > -1; i--)
2dec6761 362 {
40989e46 363 //Is the second td's left wall of the current indentaion table at the 100+ point-left-side
2dec6761 364 //of the item ?
d2d0adc7 365 if (m_indent + 100 < thisStyle.GetLeftIndent())
2dec6761 366 {
d2d0adc7 367 // Yes it is
2dec6761
JS
368 LIndent(thisStyle, str);
369 m_indent = thisStyle.GetLeftIndent() - 100;
370 m_indents.Add( m_indent );
371 break;
372 }
d2d0adc7
JS
373 else if (m_indent + 100 == thisStyle.GetLeftIndent())
374 break; //exact match
2dec6761
JS
375 else
376 {
d2d0adc7 377 // No it is not, the second td's left wall of the current indentaion table is at the
2dec6761
JS
378 //right side of the current item horizontally, so close it.
379 str << wxT("</td></tr></table>");
40989e46 380
2dec6761 381 m_indents.RemoveAt(i);
40989e46 382
d2d0adc7
JS
383 if (i < 1)
384 {
385 m_indent=0; break;
386 }
2dec6761
JS
387 m_indent = m_indents[i-1];
388 }
389 }
390}
391void wxRichTextHTMLHandler::Indent( const wxTextAttrEx& thisStyle, wxTextOutputStream& str )
392{
d2d0adc7 393 //There is no way to indent an item in HTML, but we can use tables.
40989e46 394
d2d0adc7
JS
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
40989e46 399
d2d0adc7
JS
400 // 3 x nbsp = 60
401 // 2 x nbsp = 40
402 // LSI = Left Sub Indent
403 // LI = Left Indent - LSI
2dec6761 404 //
d2d0adc7
JS
405 // -------------------------------------------
406 // |&nbsp;&nbsp;nbsp;|nbsp;nbsp;Hello World |
407 // | | | | |
408 // | V | V |
409 // | --LI-- | --LSI-- |
410 // -------------------------------------------
40989e46 411
2dec6761 412 str << wxT("<table width=\"100%\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tr>");
40989e46 413
2dec6761 414 wxString symbolic_indent = SymbolicIndent( (thisStyle.GetLeftIndent() + thisStyle.GetLeftSubIndent()) - m_indent );
21e354f1 415 str << wxString::Format( wxT("<td>%s</td>"), symbolic_indent.c_str() );
2dec6761 416 str << wxT("<td width=\"100%\">");
40989e46 417
d2d0adc7 418 if (thisStyle.GetLeftSubIndent() < 0)
2dec6761 419 {
21e354f1 420 str << SymbolicIndent(~thisStyle.GetLeftSubIndent());
2dec6761
JS
421 }
422}
423
424void wxRichTextHTMLHandler::LIndent( const wxTextAttrEx& thisStyle, wxTextOutputStream& str )
425{
d2d0adc7
JS
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();
2dec6761 435 //
d2d0adc7 436 // A typical indentation-table for the item will be construct as the following
40989e46 437
d2d0adc7
JS
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->|
40989e46
WS
448
449
2dec6761 450 str << wxT("<table width=\"100%\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tr>");
40989e46 451
2dec6761 452 wxString symbolic_indent = SymbolicIndent( (thisStyle.GetLeftIndent() - m_indent) - 100);
21e354f1 453 str << wxString::Format( wxT("<td>%s</td>"), symbolic_indent.c_str() );
2dec6761
JS
454 str << wxT("<td width=\"100%\">");
455}
456
457void wxRichTextHTMLHandler::TypeOfList( const wxTextAttrEx& thisStyle, wxString& tag )
458{
d2d0adc7
JS
459 // We can use number attribute of li tag but not all the browsers support it.
460 // also wxHtmlWindow doesn't support type attribute.
40989e46 461
2dec6761 462 m_is_ul = false;
d2d0adc7 463 if (thisStyle.GetBulletStyle() == (wxTEXT_ATTR_BULLET_STYLE_ARABIC|wxTEXT_ATTR_BULLET_STYLE_PERIOD))
2dec6761 464 tag = wxT("<ol type=\"1\">");
d2d0adc7 465 else if (thisStyle.GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_LETTERS_UPPER)
2dec6761 466 tag = wxT("<ol type=\"A\">");
d2d0adc7 467 else if (thisStyle.GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_LETTERS_LOWER)
2dec6761 468 tag = wxT("<ol type=\"a\">");
d2d0adc7 469 else if (thisStyle.GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_ROMAN_UPPER)
2dec6761 470 tag = wxT("<ol type=\"I\">");
d2d0adc7 471 else if (thisStyle.GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_ROMAN_LOWER)
2dec6761 472 tag = wxT("<ol type=\"i\">");
b71e9aa4
JS
473 else
474 {
2dec6761
JS
475 tag = wxT("<ul>");
476 m_is_ul = true;
b71e9aa4
JS
477 }
478}
479
2dec6761
JS
480wxString 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
d2d0adc7 497void wxRichTextHTMLHandler::WriteImage(wxRichTextImage* image, wxOutputStream& stream)
2dec6761
JS
498{
499 wxTextOutputStream str(stream);
40989e46 500
2dec6761 501 str << wxT("<img src=\"");
40989e46 502
d2d0adc7
JS
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:?");
40989e46 523
d2d0adc7
JS
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());
f2737255 540 wxString tempFilename(wxString::Format(wxT("%s/image%d.%s"), (const wxChar*) tempDir, sm_fileCounter, (const wxChar*) ext));
d2d0adc7
JS
541 image->GetImageBlock().Write(tempFilename);
542
543 m_imageLocations.Add(tempFilename);
544
545 str << wxFileSystem::FileNameToURL(tempFilename);
546 }
547 else
548 str << wxT("file:?");
40989e46 549
d2d0adc7
JS
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 }
40989e46 567
2dec6761
JS
568 str << wxT("\" />");
569}
570
d2d0adc7 571long wxRichTextHTMLHandler::PtToSize(long size)
2dec6761 572{
d2d0adc7
JS
573 // return approximate size
574 if (size < 9 ) return 1;
2dec6761
JS
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
583wxString wxRichTextHTMLHandler::SymbolicIndent(long indent)
584{
585 wxString in;
586 for(;indent > 0; indent -= 20)
587 in.Append( wxT("&nbsp;") );
588 return in;
589}
590
21e354f1 591const wxChar* wxRichTextHTMLHandler::GetMimeType(int imageType)
2dec6761
JS
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
d2d0adc7 610// exim-style base64 encoder
2dec6761
JS
611wxChar* wxRichTextHTMLHandler::b64enc( unsigned char* input, size_t in_len )
612{
d2d0adc7
JS
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?
21e354f1 617 static const wxChar enc64[] = wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
2dec6761
JS
618 wxChar* output = new wxChar[4*((in_len+2)/3)+1];
619 wxChar* p = output;
40989e46 620
2dec6761
JS
621 while( in_len-- > 0 )
622 {
623 register wxChar a, b;
40989e46 624
2dec6761 625 a = *input++;
40989e46 626
2dec6761 627 *p++ = enc64[ (a >> 2) & 0x3f ];
40989e46 628
07854e5e 629 if( in_len-- == 0 )
2dec6761
JS
630 {
631 *p++ = enc64[ (a << 4 ) & 0x30 ];
632 *p++ = '=';
633 *p++ = '=';
634 break;
635 }
40989e46 636
2dec6761 637 b = *input++;
40989e46 638
2dec6761 639 *p++ = enc64[(( a << 4 ) | ((b >> 4) &0xf )) & 0x3f];
40989e46 640
07854e5e 641 if( in_len-- == 0 )
2dec6761
JS
642 {
643 *p++ = enc64[ (b << 2) & 0x3f ];
644 *p++ = '=';
645 break;
646 }
40989e46 647
2dec6761 648 a = *input++;
40989e46 649
2dec6761 650 *p++ = enc64[ ((( b << 2 ) & 0x3f ) | ((a >> 6)& 0x3)) & 0x3f ];
40989e46 651
2dec6761
JS
652 *p++ = enc64[ a & 0x3f ];
653 }
654 *p = 0;
40989e46 655
2dec6761
JS
656 return output;
657}
b71e9aa4 658#endif
2dec6761 659// wxUSE_STREAMS
b71e9aa4 660
d2d0adc7
JS
661/// Delete the in-memory or temporary files generated by the last operation
662bool wxRichTextHTMLHandler::DeleteTemporaryImages()
663{
664 return DeleteTemporaryImages(GetFlags(), m_imageLocations);
665}
666
667/// Delete the in-memory or temporary files generated by the last operation
668bool 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
b71e9aa4 692#endif
2dec6761 693// wxUSE_RICHTEXT
d2d0adc7 694