]> git.saurik.com Git - wxWidgets.git/blame - src/richtext/richtexthtml.cpp
don't set A4 paper size, use the system default instead
[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
b71e9aa4 70 str << wxT("<html><head></head><body>\n");
40989e46 71
2dec6761 72 str << wxT("<table border=0 cellpadding=0 cellspacing=0><tr><td width=\"100%\">");
40989e46
WS
73
74 str << wxString::Format(wxT("<font face=\"%s\" size=\"%ld\" color=\"%s\" >"),
d2d0adc7 75 currentParaStyle.GetFont().GetFaceName().c_str(), PtToSize(currentParaStyle.GetFont().GetPointSize()),
40989e46
WS
76 currentParaStyle.GetTextColour().GetAsString(wxC2S_HTML_SYNTAX).c_str());
77
2dec6761
JS
78 m_font = false;
79 m_indent = 0;
80 m_list = false;
40989e46 81
b71e9aa4
JS
82 wxRichTextObjectList::compatibility_iterator node = buffer->GetChildren().GetFirst();
83 while (node)
84 {
85 wxRichTextParagraph* para = wxDynamicCast(node->GetData(), wxRichTextParagraph);
86 wxASSERT (para != NULL);
40989e46 87
b71e9aa4
JS
88 if (para)
89 {
27507b61
JS
90 wxTextAttrEx paraStyle(para->GetCombinedAttributes());
91
92 OutputParagraphFormatting(currentParaStyle, paraStyle, stream);
40989e46 93
b71e9aa4
JS
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 {
27507b61
JS
101 wxTextAttrEx charStyle(para->GetCombinedAttributes(obj->GetAttributes()));
102 BeginCharacterFormatting(currentCharStyle, charStyle, paraStyle, stream);
42688aea
JS
103
104 wxString text = textObj->GetText();
40989e46 105
42688aea
JS
106 if (charStyle.HasTextEffects() && (charStyle.GetTextEffects() & wxTEXT_ATTR_EFFECT_CAPITALS))
107 text.MakeUpper();
108
109 str << text;
40989e46 110
27507b61 111 EndCharacterFormatting(currentCharStyle, charStyle, paraStyle, stream);
b71e9aa4 112 }
40989e46 113
2dec6761
JS
114 wxRichTextImage* image = wxDynamicCast(obj, wxRichTextImage);
115 if( image && !image->IsEmpty())
d2d0adc7 116 WriteImage( image, stream );
40989e46 117
b71e9aa4
JS
118 node2 = node2->GetNext();
119 }
d5363f57 120 str << wxT("\n");
b71e9aa4 121 }
b71e9aa4
JS
122 node = node->GetNext();
123 }
40989e46 124
2dec6761 125 str << wxT("</font></td></tr></table></body></html>\n");
40989e46 126
b71e9aa4
JS
127 return true;
128}
129
27507b61 130void wxRichTextHTMLHandler::BeginCharacterFormatting(const wxTextAttrEx& currentStyle, const wxTextAttrEx& thisStyle, const wxTextAttrEx& paraStyle, wxOutputStream& stream)
b71e9aa4
JS
131{
132 wxTextOutputStream str(stream);
40989e46 133
d2d0adc7
JS
134 // Is the item a bulleted one?
135 if ( paraStyle.GetBulletStyle() != wxTEXT_ATTR_BULLET_STYLE_NONE )
b71e9aa4 136 {
d2d0adc7
JS
137 // Is there any opened list?
138 if (m_list)
2dec6761 139 {
d2d0adc7 140 // Yes there is
40989e46 141
d2d0adc7
JS
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
2dec6761
JS
146 else
147 {
d2d0adc7 148 // No it isn't, so we should close the list tag
2dec6761 149 str << (m_is_ul ? wxT("</ul>") : wxT("</ol>"));
40989e46 150
d2d0adc7 151 // And renavigate to new list's horizontal position
27507b61 152 NavigateToListPosition(paraStyle, str);
40989e46 153
d2d0adc7 154 // Get the appropriate tag, an ol for numerical values, an ul for dot, square etc.
2dec6761 155 wxString tag;
27507b61 156 TypeOfList(paraStyle, tag);
21e354f1 157 str << tag << wxT("<li>");
2dec6761
JS
158 }
159 }
160 else
161 {
d2d0adc7
JS
162 // No there isn't a list.
163 // navigate to new list's horizontal position(indent)
27507b61 164 NavigateToListPosition(paraStyle, str);
40989e46 165
d2d0adc7 166 // Get the appropriate tag, an ol for numerical values, an ul for dot, square etc.
2dec6761 167 wxString tag;
27507b61 168 TypeOfList(paraStyle, tag);
21e354f1 169 str << tag << wxT("<li>");
40989e46 170
d2d0adc7 171 // Now we have a list, mark it.
2dec6761 172 m_list = true;
40989e46 173 }
b71e9aa4 174 }
2dec6761
JS
175 else if( m_list )
176 {
d2d0adc7
JS
177 // The item is not bulleted and there is a list what should be closed now.
178 // So close the list
b71e9aa4 179
2dec6761 180 str << (m_is_ul ? wxT("</ul>") : wxT("</ol>"));
d2d0adc7
JS
181
182 // And mark as there is no an opened list
2dec6761
JS
183 m_list = false;
184 }
40989e46 185
2dec6761 186 // does the item have an indentation ?
27507b61 187 if( paraStyle.GetLeftIndent() )
b71e9aa4 188 {
d2d0adc7 189 if (paraStyle.GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_NONE)
2dec6761 190 {
d2d0adc7 191 if (m_indent)
2dec6761 192 {
d2d0adc7 193 if ((paraStyle.GetLeftIndent() + paraStyle.GetLeftSubIndent()) == m_indent)
2dec6761 194 {
d2d0adc7 195 if (paraStyle.GetLeftSubIndent() < 0)
2dec6761 196 {
27507b61 197 str << SymbolicIndent(~paraStyle.GetLeftSubIndent());
2dec6761
JS
198 }
199 }
200 else
201 {
d2d0adc7 202 if (paraStyle.GetLeftIndent() + paraStyle.GetLeftSubIndent() > m_indent)
2dec6761 203 {
27507b61
JS
204 Indent(paraStyle, str);
205 m_indent = paraStyle.GetLeftIndent() + paraStyle.GetLeftSubIndent();
2dec6761
JS
206 m_indents.Add( m_indent );
207 }
208 else
209 {
210 int i = m_indents.size() - 1;
d2d0adc7 211 for (; i > -1; i--)
2dec6761 212 {
d2d0adc7 213 if (m_indent < (paraStyle.GetLeftIndent() + paraStyle.GetLeftSubIndent()))
2dec6761 214 {
27507b61
JS
215 Indent(paraStyle, str);
216 m_indent = paraStyle.GetLeftIndent() + paraStyle.GetLeftSubIndent();
2dec6761 217 m_indents.Add( m_indent );
40989e46 218
2dec6761
JS
219 break;
220 }
d2d0adc7 221 else if (m_indent == (paraStyle.GetLeftIndent() + paraStyle.GetLeftSubIndent()))
2dec6761 222 {
d2d0adc7 223 if (paraStyle.GetLeftSubIndent() < 0)
2dec6761 224 {
27507b61 225 str << SymbolicIndent(~paraStyle.GetLeftSubIndent());
2dec6761
JS
226 }
227 break;
228 }
229 else
230 {
231 str << wxT("</td></tr></table>");
40989e46 232
2dec6761 233 m_indents.RemoveAt(i);
40989e46 234
d2d0adc7
JS
235 if(i < 1)
236 {
237 m_indent=0; break;
238 }
2dec6761
JS
239 m_indent = m_indents[i-1];
240 }
241 }
242 }
243 }
244 }
245 else
246 {
27507b61
JS
247 Indent(paraStyle, str);
248 m_indent = paraStyle.GetLeftIndent() + paraStyle.GetLeftSubIndent();
2dec6761
JS
249 m_indents.Add( m_indent );
250 }
251 }
b71e9aa4 252 }
d2d0adc7 253 else if (m_indent)
b71e9aa4 254 {
d2d0adc7 255 // The item is not indented and there is a table(s) that should be closed now.
40989e46 256
d2d0adc7 257 for (unsigned int i = 0; i < m_indents.size(); i++)
2dec6761 258 str << wxT("</td></tr></table>");
40989e46 259
2dec6761
JS
260 m_indent = 0;
261 m_indents.Clear();
b71e9aa4 262 }
40989e46
WS
263
264
2dec6761 265 wxString style;
40989e46 266
d2d0adc7
JS
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 }
40989e46 280
d2d0adc7 281 if (style.size())
21e354f1
JS
282 {
283 str << wxString::Format(wxT("<font %s >"), style.c_str());
284 m_font = true;
285 }
40989e46 286
d2d0adc7 287 if (thisStyle.GetFont().GetWeight() == wxBOLD)
2dec6761 288 str << wxT("<b>");
d2d0adc7 289 if (thisStyle.GetFont().GetStyle() == wxITALIC)
2dec6761 290 str << wxT("<i>");
d2d0adc7 291 if (thisStyle.GetFont().GetUnderlined())
2dec6761 292 str << wxT("<u>");
d2d0adc7
JS
293
294 if (thisStyle.HasURL())
295 str << wxT("<a href=\"") << thisStyle.GetURL() << wxT("\">");
b71e9aa4
JS
296}
297
27507b61 298void wxRichTextHTMLHandler::EndCharacterFormatting(const wxTextAttrEx& WXUNUSED(currentStyle), const wxTextAttrEx& thisStyle, const wxTextAttrEx& WXUNUSED(paraStyle), wxOutputStream& stream)
b71e9aa4 299{
b71e9aa4 300 wxTextOutputStream str(stream);
40989e46 301
d2d0adc7
JS
302 if (thisStyle.HasURL())
303 str << wxT("</a>");
304
305 if (thisStyle.GetFont().GetUnderlined())
2dec6761 306 str << wxT("</u>");
d2d0adc7 307 if (thisStyle.GetFont().GetStyle() == wxITALIC)
2dec6761 308 str << wxT("</i>");
d2d0adc7 309 if (thisStyle.GetFont().GetWeight() == wxBOLD)
2dec6761 310 str << wxT("</b>");
40989e46 311
d2d0adc7 312 if (m_font)
2dec6761
JS
313 {
314 m_font = false;
315 str << wxT("</font>");
316 }
317}
b71e9aa4 318
2dec6761
JS
319/// Output paragraph formatting
320void wxRichTextHTMLHandler::OutputParagraphFormatting(const wxTextAttrEx& WXUNUSED(currentStyle), const wxTextAttrEx& thisStyle, wxOutputStream& stream)
321{
d2d0adc7
JS
322 // If there is no opened list currently, insert a <p> after every paragraph
323 if (!m_list)
b71e9aa4 324 {
2dec6761 325 wxTextOutputStream str(stream);
d2d0adc7 326 wxString align = GetAlignment(thisStyle);
21e354f1 327 str << wxString::Format(wxT("<p align=\"%s\">"), align.c_str());
b71e9aa4 328 }
42688aea
JS
329
330 if (thisStyle.HasPageBreak())
331 {
332 wxTextOutputStream str(stream);
333 str << wxT("<div style=\"page-break-after:always\"></div>\n");
334 }
2dec6761 335}
b71e9aa4 336
2dec6761
JS
337void wxRichTextHTMLHandler::NavigateToListPosition(const wxTextAttrEx& thisStyle, wxTextOutputStream& str)
338{
d2d0adc7
JS
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
40989e46 341
d2d0adc7
JS
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())
b71e9aa4 345 {
d2d0adc7 346 // yes it is
2dec6761
JS
347 LIndent(thisStyle, str);
348 m_indent = thisStyle.GetLeftIndent() - 100;
349 m_indents.Add( m_indent );
350 return;
b71e9aa4 351 }
d2d0adc7 352 // No it isn't
40989e46 353
2dec6761 354 int i = m_indents.size() - 1;
d2d0adc7 355 for (; i > -1; i--)
2dec6761 356 {
40989e46 357 //Is the second td's left wall of the current indentaion table at the 100+ point-left-side
2dec6761 358 //of the item ?
d2d0adc7 359 if (m_indent + 100 < thisStyle.GetLeftIndent())
2dec6761 360 {
d2d0adc7 361 // Yes it is
2dec6761
JS
362 LIndent(thisStyle, str);
363 m_indent = thisStyle.GetLeftIndent() - 100;
364 m_indents.Add( m_indent );
365 break;
366 }
d2d0adc7
JS
367 else if (m_indent + 100 == thisStyle.GetLeftIndent())
368 break; //exact match
2dec6761
JS
369 else
370 {
d2d0adc7 371 // No it is not, the second td's left wall of the current indentaion table is at the
2dec6761
JS
372 //right side of the current item horizontally, so close it.
373 str << wxT("</td></tr></table>");
40989e46 374
2dec6761 375 m_indents.RemoveAt(i);
40989e46 376
d2d0adc7
JS
377 if (i < 1)
378 {
379 m_indent=0; break;
380 }
2dec6761
JS
381 m_indent = m_indents[i-1];
382 }
383 }
384}
385void wxRichTextHTMLHandler::Indent( const wxTextAttrEx& thisStyle, wxTextOutputStream& str )
386{
d2d0adc7 387 //There is no way to indent an item in HTML, but we can use tables.
40989e46 388
d2d0adc7
JS
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
40989e46 393
d2d0adc7
JS
394 // 3 x nbsp = 60
395 // 2 x nbsp = 40
396 // LSI = Left Sub Indent
397 // LI = Left Indent - LSI
2dec6761 398 //
d2d0adc7
JS
399 // -------------------------------------------
400 // |&nbsp;&nbsp;nbsp;|nbsp;nbsp;Hello World |
401 // | | | | |
402 // | V | V |
403 // | --LI-- | --LSI-- |
404 // -------------------------------------------
40989e46 405
2dec6761 406 str << wxT("<table width=\"100%\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tr>");
40989e46 407
2dec6761 408 wxString symbolic_indent = SymbolicIndent( (thisStyle.GetLeftIndent() + thisStyle.GetLeftSubIndent()) - m_indent );
21e354f1 409 str << wxString::Format( wxT("<td>%s</td>"), symbolic_indent.c_str() );
2dec6761 410 str << wxT("<td width=\"100%\">");
40989e46 411
d2d0adc7 412 if (thisStyle.GetLeftSubIndent() < 0)
2dec6761 413 {
21e354f1 414 str << SymbolicIndent(~thisStyle.GetLeftSubIndent());
2dec6761
JS
415 }
416}
417
418void wxRichTextHTMLHandler::LIndent( const wxTextAttrEx& thisStyle, wxTextOutputStream& str )
419{
d2d0adc7
JS
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();
2dec6761 429 //
d2d0adc7 430 // A typical indentation-table for the item will be construct as the following
40989e46 431
d2d0adc7
JS
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->|
40989e46
WS
442
443
2dec6761 444 str << wxT("<table width=\"100%\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tr>");
40989e46 445
2dec6761 446 wxString symbolic_indent = SymbolicIndent( (thisStyle.GetLeftIndent() - m_indent) - 100);
21e354f1 447 str << wxString::Format( wxT("<td>%s</td>"), symbolic_indent.c_str() );
2dec6761
JS
448 str << wxT("<td width=\"100%\">");
449}
450
451void wxRichTextHTMLHandler::TypeOfList( const wxTextAttrEx& thisStyle, wxString& tag )
452{
d2d0adc7
JS
453 // We can use number attribute of li tag but not all the browsers support it.
454 // also wxHtmlWindow doesn't support type attribute.
40989e46 455
2dec6761 456 m_is_ul = false;
d2d0adc7 457 if (thisStyle.GetBulletStyle() == (wxTEXT_ATTR_BULLET_STYLE_ARABIC|wxTEXT_ATTR_BULLET_STYLE_PERIOD))
2dec6761 458 tag = wxT("<ol type=\"1\">");
d2d0adc7 459 else if (thisStyle.GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_LETTERS_UPPER)
2dec6761 460 tag = wxT("<ol type=\"A\">");
d2d0adc7 461 else if (thisStyle.GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_LETTERS_LOWER)
2dec6761 462 tag = wxT("<ol type=\"a\">");
d2d0adc7 463 else if (thisStyle.GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_ROMAN_UPPER)
2dec6761 464 tag = wxT("<ol type=\"I\">");
d2d0adc7 465 else if (thisStyle.GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_ROMAN_LOWER)
2dec6761 466 tag = wxT("<ol type=\"i\">");
b71e9aa4
JS
467 else
468 {
2dec6761
JS
469 tag = wxT("<ul>");
470 m_is_ul = true;
b71e9aa4
JS
471 }
472}
473
2dec6761
JS
474wxString 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
d2d0adc7 491void wxRichTextHTMLHandler::WriteImage(wxRichTextImage* image, wxOutputStream& stream)
2dec6761
JS
492{
493 wxTextOutputStream str(stream);
40989e46 494
2dec6761 495 str << wxT("<img src=\"");
40989e46 496
d2d0adc7
JS
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:?");
40989e46 517
d2d0adc7
JS
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());
f2737255 534 wxString tempFilename(wxString::Format(wxT("%s/image%d.%s"), (const wxChar*) tempDir, sm_fileCounter, (const wxChar*) ext));
d2d0adc7
JS
535 image->GetImageBlock().Write(tempFilename);
536
537 m_imageLocations.Add(tempFilename);
538
539 str << wxFileSystem::FileNameToURL(tempFilename);
540 }
541 else
542 str << wxT("file:?");
40989e46 543
d2d0adc7
JS
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 }
40989e46 561
2dec6761
JS
562 str << wxT("\" />");
563}
564
d2d0adc7 565long wxRichTextHTMLHandler::PtToSize(long size)
2dec6761 566{
d2d0adc7
JS
567 // return approximate size
568 if (size < 9 ) return 1;
2dec6761
JS
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
577wxString wxRichTextHTMLHandler::SymbolicIndent(long indent)
578{
579 wxString in;
580 for(;indent > 0; indent -= 20)
581 in.Append( wxT("&nbsp;") );
582 return in;
583}
584
21e354f1 585const wxChar* wxRichTextHTMLHandler::GetMimeType(int imageType)
2dec6761
JS
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
d2d0adc7 604// exim-style base64 encoder
2dec6761
JS
605wxChar* wxRichTextHTMLHandler::b64enc( unsigned char* input, size_t in_len )
606{
d2d0adc7
JS
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?
21e354f1 611 static const wxChar enc64[] = wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
2dec6761
JS
612 wxChar* output = new wxChar[4*((in_len+2)/3)+1];
613 wxChar* p = output;
40989e46 614
2dec6761
JS
615 while( in_len-- > 0 )
616 {
617 register wxChar a, b;
40989e46 618
2dec6761 619 a = *input++;
40989e46 620
2dec6761 621 *p++ = enc64[ (a >> 2) & 0x3f ];
40989e46 622
07854e5e 623 if( in_len-- == 0 )
2dec6761
JS
624 {
625 *p++ = enc64[ (a << 4 ) & 0x30 ];
626 *p++ = '=';
627 *p++ = '=';
628 break;
629 }
40989e46 630
2dec6761 631 b = *input++;
40989e46 632
2dec6761 633 *p++ = enc64[(( a << 4 ) | ((b >> 4) &0xf )) & 0x3f];
40989e46 634
07854e5e 635 if( in_len-- == 0 )
2dec6761
JS
636 {
637 *p++ = enc64[ (b << 2) & 0x3f ];
638 *p++ = '=';
639 break;
640 }
40989e46 641
2dec6761 642 a = *input++;
40989e46 643
2dec6761 644 *p++ = enc64[ ((( b << 2 ) & 0x3f ) | ((a >> 6)& 0x3)) & 0x3f ];
40989e46 645
2dec6761
JS
646 *p++ = enc64[ a & 0x3f ];
647 }
648 *p = 0;
40989e46 649
2dec6761
JS
650 return output;
651}
b71e9aa4 652#endif
2dec6761 653// wxUSE_STREAMS
b71e9aa4 654
d2d0adc7
JS
655/// Delete the in-memory or temporary files generated by the last operation
656bool wxRichTextHTMLHandler::DeleteTemporaryImages()
657{
658 return DeleteTemporaryImages(GetFlags(), m_imageLocations);
659}
660
661/// Delete the in-memory or temporary files generated by the last operation
662bool 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
b71e9aa4 686#endif
2dec6761 687// wxUSE_RICHTEXT
d2d0adc7 688