A patch adding wxHTMLDataObject which can be used for handling the standard platform formats for transfering HTML formatted text.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@71610 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robin Dunn
2012-05-30 19:21:42 +00:00
parent f5f0774124
commit b8acf11e74
7 changed files with 231 additions and 10 deletions

View File

@@ -334,6 +334,45 @@ private:
#endif
#endif // wxUSE_UNICODE
class WXDLLIMPEXP_CORE wxHTMLDataObject : public wxDataObjectSimple
{
public:
// ctor: you can specify the text here or in SetText(), or override
// GetText()
wxHTMLDataObject(const wxString& html = wxEmptyString)
: wxDataObjectSimple(wxDF_HTML),
m_html(html)
{
}
// virtual functions which you may override if you want to provide text on
// demand only - otherwise, the trivial default versions will be used
virtual size_t GetLength() const { return m_html.Len() + 1; }
virtual wxString GetHTML() const { return m_html; }
virtual void SetHTML(const wxString& html) { m_html = html; }
virtual size_t GetDataSize() const;
virtual bool GetDataHere(void *buf) const;
virtual bool SetData(size_t len, const void *buf);
// Must provide overloads to avoid hiding them (and warnings about it)
virtual size_t GetDataSize(const wxDataFormat&) const
{
return GetDataSize();
}
virtual bool GetDataHere(const wxDataFormat&, void *buf) const
{
return GetDataHere(buf);
}
virtual bool SetData(const wxDataFormat&, size_t len, const void *buf)
{
return SetData(len, buf);
}
private:
wxString m_html;
};
class WXDLLIMPEXP_CORE wxTextDataObject : public wxDataObjectSimple
{
public:

View File

@@ -34,9 +34,7 @@
@itemdef{wxDF_FILENAME,
A list of filenames.}
@itemdef{wxDF_HTML,
An HTML string. This is only valid when passed to
wxSetClipboardData when compiled with Visual C++ in non-Unicode
mode.}
An HTML string. This is currently only valid on Mac and MSW.}
@endDefList
As mentioned above, these standard formats may be passed to any function
@@ -789,4 +787,31 @@ public:
const wxArrayString& GetFilenames() const;
};
/**
@class wxHTMLDataObject
wxHTMLDataObject is used for working with HTML-formatted text.
@library{wxcore}
@category{dnd}
@see wxDataObject, wxDataObjectSimple
*/
class wxHTMLDataObject : public wxDataObjectSimple
{
public:
/**
Constructor.
*/
wxHTMLDataObject(const wxString& html = wxEmptyString);
/**
Returns the HTML string.
*/
virtual wxString GetHTML() const;
/**
Sets the HTML string.
*/
virtual void SetHTML(const wxString& html);
};

View File

@@ -427,6 +427,117 @@ bool wxTextDataObject::SetData(size_t len, const void *buf)
#endif // different wxTextDataObject implementations
size_t wxHTMLDataObject::GetDataSize() const
{
size_t size = 0;
// Windows and Mac always use UTF-8, and docs suggest GTK does as well.
wxCharBuffer buffer = wxConvUTF8.cWX2MB( GetHTML().c_str() );
if (buffer)
{
size = strlen( buffer );
#if __WXMSW__
// On Windows we need to add some stuff to the string to satisfy
// its clipboard format requirements.
size += 400;
#endif
}
return size;
}
bool wxHTMLDataObject::GetDataHere(void *buf) const
{
if ( !buf )
return false;
// Windows and Mac always use UTF-8, and docs suggest GTK does as well.
wxCharBuffer html = wxConvUTF8.cWX2MB( GetHTML().c_str() );
if ( !html )
return false;
size_t bytes = GetDataSize();
#if __WXMSW__
// add the extra info that the MSW clipboard format requires.
char* buffer = new char[bytes];
// Create a template string for the HTML header...
strcpy(buffer,
"Version:0.9\r\n"
"StartHTML:00000000\r\n"
"EndHTML:00000000\r\n"
"StartFragment:00000000\r\n"
"EndFragment:00000000\r\n"
"<html><body>\r\n"
"<!--StartFragment -->\r\n");
// Append the HTML...
strcat(buffer, html);
strcat(buffer, "\r\n");
// Finish up the HTML format...
strcat(buffer,
"<!--EndFragment-->\r\n"
"</body>\r\n"
"</html>");
// Now go back, calculate all the lengths, and write out the
// necessary header information. Note, wsprintf() truncates the
// string when you overwrite it so you follow up with code to replace
// the 0 appended at the end with a '\r'...
char *ptr = strstr(buffer, "StartHTML");
sprintf(ptr+10, "%08u", (unsigned)(strstr(buffer, "<html>") - buffer));
*(ptr+10+8) = '\r';
ptr = strstr(buffer, "EndHTML");
sprintf(ptr+8, "%08u", (unsigned)strlen(buffer));
*(ptr+8+8) = '\r';
ptr = strstr(buffer, "StartFragment");
sprintf(ptr+14, "%08u", (unsigned)(strstr(buffer, "<!--StartFrag") - buffer));
*(ptr+14+8) = '\r';
ptr = strstr(buffer, "EndFragment");
sprintf(ptr+12, "%08u", (unsigned)(strstr(buffer, "<!--EndFrag") - buffer));
*(ptr+12+8) = '\r';
#else
wxCharBuffer buffer = html;
#endif // __WXMSW__
memcpy( (char*) buf, buffer, bytes );
return true;
}
bool wxHTMLDataObject::SetData(size_t WXUNUSED(len), const void *buf)
{
if ( buf == NULL )
return false;
// Windows and Mac always use UTF-8, and docs suggest GTK does as well.
wxWCharBuffer buffer = wxConvUTF8.cMB2WX( (const char*)buf );
wxString html(buffer);
// To be consistent with other platforms, we only add the Fragment part
// of the Windows HTML clipboard format to the data object.
#if __WXMSW__
int fragmentStart = html.rfind("StartFragment");
int fragmentEnd = html.rfind("EndFragment");
if (fragmentStart != wxNOT_FOUND && fragmentEnd != wxNOT_FOUND)
{
int startCommentEnd = html.find("-->", fragmentStart) + 3;
int endCommentStart = html.rfind("<!--", fragmentEnd);
if (startCommentEnd != wxNOT_FOUND && endCommentStart != wxNOT_FOUND)
html = html.Mid(startCommentEnd, endCommentStart - startCommentEnd);
}
#endif
SetHTML( html );
return true;
}
// ----------------------------------------------------------------------------
// wxCustomDataObject
// ----------------------------------------------------------------------------

View File

@@ -33,6 +33,7 @@ GdkAtom g_textAtom = 0;
GdkAtom g_altTextAtom = 0;
GdkAtom g_pngAtom = 0;
GdkAtom g_fileAtom = 0;
GdkAtom g_htmlAtom = 0;
//-------------------------------------------------------------------------
// wxDataFormat
@@ -95,6 +96,9 @@ void wxDataFormat::SetType( wxDataFormatId type )
if (m_type == wxDF_FILENAME)
m_format = g_fileAtom;
else
if (m_type == wxDF_HTML)
m_format = g_htmlAtom;
else
{
wxFAIL_MSG( wxT("invalid dataformat") );
}
@@ -131,6 +135,9 @@ void wxDataFormat::SetId( NativeFormat format )
else
if (m_format == g_fileAtom)
m_type = wxDF_FILENAME;
else
if (m_format == g_htmlAtom)
m_type = wxDF_HTML;
else
m_type = wxDF_PRIVATE;
}
@@ -164,6 +171,8 @@ void wxDataFormat::PrepareFormats()
g_pngAtom = gdk_atom_intern( "image/png", FALSE );
if (!g_fileAtom)
g_fileAtom = gdk_atom_intern( "text/uri-list", FALSE );
if (!g_htmlAtom)
g_htmlAtom = gdk_atom_intern( "text/html", FALSE );
}
//-------------------------------------------------------------------------

View File

@@ -79,6 +79,7 @@
// ---------------------------------------------------------------------------
static bool gs_wxClipboardIsOpen = false;
static int gs_htmlcfid = 0;
bool wxOpenClipboard()
{
@@ -139,7 +140,9 @@ bool wxIsClipboardOpened()
bool wxIsClipboardFormatAvailable(wxDataFormat dataFormat)
{
wxDataFormat::NativeFormat cf = dataFormat.GetFormatId();
wxDataFormat::NativeFormat cf = dataFormat.GetFormatId();
if (cf == wxDF_HTML)
cf = gs_htmlcfid;
if ( ::IsClipboardFormatAvailable(cf) )
{
@@ -304,10 +307,6 @@ bool wxSetClipboardData(wxDataFormat dataFormat,
char *buf = new char [400 + strlen(html)];
if(!buf) return false;
// Get clipboard id for HTML format...
static int cfid = 0;
if(!cfid) cfid = RegisterClipboardFormat(wxT("HTML Format"));
// Create a template string for the HTML header...
strcpy(buf,
"Version:0.9\r\n"
@@ -358,7 +357,7 @@ bool wxSetClipboardData(wxDataFormat dataFormat,
strcpy(ptr, buf);
GlobalUnlock(hText);
handle = ::SetClipboardData(cfid, hText);
handle = ::SetClipboardData(gs_htmlcfid, hText);
// Free memory...
GlobalFree(hText);
@@ -598,6 +597,10 @@ bool wxClipboard::Flush()
bool wxClipboard::Open()
{
// Get clipboard id for HTML format...
if(!gs_htmlcfid)
gs_htmlcfid = RegisterClipboardFormat(wxT("HTML Format"));
// OLE opens clipboard for us
m_isOpened = true;
#if wxUSE_OLE_CLIPBOARD
@@ -814,6 +817,8 @@ bool wxClipboard::GetData( wxDataObject& data )
// convert to NativeFormat Id
cf = formats[n].GetFormatId();
if (cf == wxDF_HTML)
cf = gs_htmlcfid;
// if the format is not available, try the next one
// this test includes implicit / sythetic formats
if ( !::IsClipboardFormatAvailable(cf) )

View File

@@ -67,6 +67,21 @@
#define GetTymedName(tymed) wxEmptyString
#endif // wxDEBUG_LEVEL/!wxDEBUG_LEVEL
wxDataFormat HtmlFormatFixup(wxDataFormat format)
{
// Since the HTML format is dynamically registered, the wxDF_HTML
// format does not match the native constant in the way other formats do,
// so for the format checks below to work, we must change the native
// id to the wxDF_HTML constant.
wxChar s_szBuf[256];
if (::GetClipboardFormatName(format, s_szBuf, WXSIZEOF(s_szBuf)))
{
if (s_szBuf == wxString("HTML Format"))
format = wxDF_HTML;
}
return format;
}
// ----------------------------------------------------------------------------
// wxIEnumFORMATETC interface implementation
// ----------------------------------------------------------------------------
@@ -183,7 +198,10 @@ wxIEnumFORMATETC::wxIEnumFORMATETC(const wxDataFormat *formats, ULONG nCount)
m_nCount = nCount;
m_formats = new CLIPFORMAT[nCount];
for ( ULONG n = 0; n < nCount; n++ ) {
m_formats[n] = formats[n].GetFormatId();
if (formats[n].GetFormatId() != wxDF_HTML)
m_formats[n] = formats[n].GetFormatId();
else
m_formats[n] = ::RegisterClipboardFormat(wxT("HTML Format"));
}
}
@@ -290,6 +308,7 @@ STDMETHODIMP wxIDataObject::GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium)
// for the bitmaps and metafiles we use the handles instead of global memory
// to pass the data
wxDataFormat format = (wxDataFormat::NativeFormat)pformatetcIn->cfFormat;
format = HtmlFormatFixup(format);
switch ( format )
{
@@ -432,6 +451,8 @@ STDMETHODIMP wxIDataObject::SetData(FORMATETC *pformatetc,
{
wxDataFormat format = pformatetc->cfFormat;
format = HtmlFormatFixup(format);
// this is quite weird, but for file drag and drop, explorer
// calls our SetData() with the formats we do *not* support!
//
@@ -459,6 +480,7 @@ STDMETHODIMP wxIDataObject::SetData(FORMATETC *pformatetc,
size_t size;
switch ( format )
{
case wxDF_HTML:
case CF_TEXT:
case CF_OEMTEXT:
size = strlen((const char *)pBuf);
@@ -567,6 +589,8 @@ STDMETHODIMP wxIDataObject::QueryGetData(FORMATETC *pformatetc)
// and now check the type of data requested
wxDataFormat format = pformatetc->cfFormat;
format = HtmlFormatFixup(format);
if ( m_pDataObject->IsSupportedFormat(format) ) {
wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::QueryGetData: %s ok"),
wxGetFormatName(format));

View File

@@ -128,6 +128,10 @@ void wxDataFormat::SetType( wxDataFormatId dataType )
m_format = (long) CFStringCreateCopy( NULL, CFSTR("public.utf16-plain-text") );
break;
case wxDF_HTML:
m_format = (long) CFStringCreateCopy( NULL, CFSTR("public.html") );
break;
case wxDF_BITMAP:
m_format = (long) CFStringCreateCopy( NULL, CFSTR("public.tiff") );
break;
@@ -158,6 +162,10 @@ void wxDataFormat::SetId( NativeFormat format )
m_format = 0;
}
m_format = (NativeFormat) CFStringCreateCopy(NULL, (CFStringRef)format);
if ( UTTypeConformsTo( (CFStringRef)format, CFSTR("public.html") ) )
{
m_type = wxDF_HTML;
}
if ( UTTypeConformsTo( (CFStringRef)format, CFSTR("public.utf16-plain-text") ) )
{
m_type = wxDF_UNICODETEXT;