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