1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/dataobj.cpp
3 // Purpose: wxDataObject class
4 // Author: Robert Roebling
5 // Copyright: (c) 1998 Robert Roebling
6 // Licence: wxWindows licence
7 ///////////////////////////////////////////////////////////////////////////////
9 // For compilers that support precompilation, includes "wx.h".
10 #include "wx/wxprec.h"
14 #include "wx/dataobj.h"
22 #include "wx/mstream.h"
25 #include "wx/gtk/private.h"
27 //-------------------------------------------------------------------------
29 //-------------------------------------------------------------------------
31 GdkAtom g_textAtom
= 0;
32 GdkAtom g_altTextAtom
= 0;
33 GdkAtom g_pngAtom
= 0;
34 GdkAtom g_fileAtom
= 0;
35 GdkAtom g_htmlAtom
= 0;
37 //-------------------------------------------------------------------------
39 //-------------------------------------------------------------------------
41 wxDataFormat::wxDataFormat()
43 // do *not* call PrepareFormats() from here for 2 reasons:
45 // 1. we will have time to do it later because some other Set function
46 // must be called before we really need them
48 // 2. doing so prevents us from declaring global wxDataFormats because
49 // calling PrepareFormats (and thus gdk_atom_intern) before GDK is
50 // initialised will result in a crash
51 m_type
= wxDF_INVALID
;
52 m_format
= (GdkAtom
) 0;
55 wxDataFormat::wxDataFormat( wxDataFormatId type
)
61 void wxDataFormat::InitFromString( const wxString
&id
)
67 wxDataFormat::wxDataFormat( NativeFormat format
)
73 void wxDataFormat::SetType( wxDataFormatId type
)
80 if (m_type
== wxDF_UNICODETEXT
)
81 m_format
= g_textAtom
;
82 else if (m_type
== wxDF_TEXT
)
83 m_format
= g_altTextAtom
;
84 #else // !wxUSE_UNICODE
85 // notice that we don't map wxDF_UNICODETEXT to g_textAtom here, this
86 // would lead the code elsewhere to treat data objects with this format as
87 // containing UTF-8 data which is not true
88 if (m_type
== wxDF_TEXT
)
89 m_format
= g_textAtom
;
90 #endif // wxUSE_UNICODE/!wxUSE_UNICODE
92 if (m_type
== wxDF_BITMAP
)
95 if (m_type
== wxDF_FILENAME
)
96 m_format
= g_fileAtom
;
98 if (m_type
== wxDF_HTML
)
99 m_format
= g_htmlAtom
;
102 wxFAIL_MSG( wxT("invalid dataformat") );
106 wxDataFormatId
wxDataFormat::GetType() const
111 wxString
wxDataFormat::GetId() const
113 wxGtkString
atom_name(gdk_atom_name(m_format
));
114 return wxString::FromAscii(atom_name
);
117 void wxDataFormat::SetId( NativeFormat format
)
122 if (m_format
== g_textAtom
)
124 m_type
= wxDF_UNICODETEXT
;
129 if (m_format
== g_altTextAtom
)
132 if (m_format
== g_pngAtom
)
133 m_type
= wxDF_BITMAP
;
135 if (m_format
== g_fileAtom
)
136 m_type
= wxDF_FILENAME
;
138 if (m_format
== g_htmlAtom
)
141 m_type
= wxDF_PRIVATE
;
144 void wxDataFormat::SetId( const wxString
& id
)
147 m_type
= wxDF_PRIVATE
;
148 m_format
= gdk_atom_intern( id
.ToAscii(), FALSE
);
151 void wxDataFormat::PrepareFormats()
153 // VZ: GNOME included in RedHat 6.1 uses the MIME types below and not the
154 // atoms STRING and file:ALL as the old code was, but normal X apps
155 // use STRING for text selection when transferring the data via
156 // clipboard, for example, so do use STRING for now (GNOME apps will
157 // probably support STRING as well for compatibility anyhow), but use
158 // text/uri-list for file dnd because compatibility is not important
163 g_textAtom
= gdk_atom_intern( "UTF8_STRING", FALSE
);
164 g_altTextAtom
= gdk_atom_intern( "STRING", FALSE
);
166 g_textAtom
= gdk_atom_intern( "STRING" /* "text/plain" */, FALSE
);
170 g_pngAtom
= gdk_atom_intern( "image/png", FALSE
);
172 g_fileAtom
= gdk_atom_intern( "text/uri-list", FALSE
);
174 g_htmlAtom
= gdk_atom_intern( "text/html", FALSE
);
177 //-------------------------------------------------------------------------
179 //-------------------------------------------------------------------------
181 wxDataObject::wxDataObject()
185 wxDataObject::~wxDataObject()
187 // dtor is empty but needed for Darwin and AIX -- otherwise it doesn't link
190 bool wxDataObject::IsSupportedFormat(const wxDataFormat
& format
, Direction dir
) const
192 size_t nFormatCount
= GetFormatCount(dir
);
193 if ( nFormatCount
== 1 )
195 return format
== GetPreferredFormat();
199 wxDataFormat
*formats
= new wxDataFormat
[nFormatCount
];
200 GetAllFormats(formats
,dir
);
203 for ( n
= 0; n
< nFormatCount
; n
++ )
205 if ( formats
[n
] == format
)
212 return n
< nFormatCount
;
216 // ----------------------------------------------------------------------------
218 // ----------------------------------------------------------------------------
223 wxTextDataObject::GetAllFormats(wxDataFormat
*formats
,
224 wxDataObjectBase::Direction
WXUNUSED(dir
)) const
226 *formats
++ = GetPreferredFormat();
227 *formats
= g_altTextAtom
;
230 #endif // wxUSE_UNICODE
232 // ----------------------------------------------------------------------------
234 // ----------------------------------------------------------------------------
236 bool wxFileDataObject::GetDataHere(void *buf
) const
240 for (size_t i
= 0; i
< m_filenames
.GetCount(); i
++)
242 filenames
+= wxT("file:");
243 filenames
+= m_filenames
[i
];
244 filenames
+= wxT("\r\n");
247 memcpy( buf
, filenames
.mbc_str(), filenames
.length() + 1 );
252 size_t wxFileDataObject::GetDataSize() const
256 for (size_t i
= 0; i
< m_filenames
.GetCount(); i
++)
258 // This is junk in UTF-8
259 res
+= m_filenames
[i
].length();
260 res
+= 5 + 2; // "file:" (5) + "\r\n" (2)
266 bool wxFileDataObject::SetData(size_t WXUNUSED(size
), const void *buf
)
268 // we get data in the text/uri-list format, i.e. as a sequence of URIs
269 // (filenames prefixed by "file:") delimited by "\r\n". size includes
270 // the trailing zero (in theory, not for Nautilus in early GNOME
275 const gchar
*nexttemp
= (const gchar
*) buf
;
279 const gchar
*temp
= nexttemp
;
286 // if an app omits '\r''\n'
293 if (temp
[len
] == '\r')
295 if (temp
[len
+1] == '\n')
296 nexttemp
= temp
+len
+2;
298 nexttemp
= temp
+len
+1;
307 // required to give it a trailing zero
308 gchar
*uri
= g_strndup( temp
, len
);
310 gchar
*fn
= g_filename_from_uri( uri
, NULL
, NULL
);
316 AddFile( wxConvFileName
->cMB2WX( fn
) );
324 void wxFileDataObject::AddFile( const wxString
&filename
)
326 m_filenames
.Add( filename
);
329 // ----------------------------------------------------------------------------
330 // wxBitmapDataObject
331 // ----------------------------------------------------------------------------
333 wxBitmapDataObject::wxBitmapDataObject()
338 wxBitmapDataObject::wxBitmapDataObject( const wxBitmap
& bitmap
)
339 : wxBitmapDataObjectBase(bitmap
)
346 wxBitmapDataObject::~wxBitmapDataObject()
351 void wxBitmapDataObject::SetBitmap( const wxBitmap
&bitmap
)
355 wxBitmapDataObjectBase::SetBitmap(bitmap
);
360 bool wxBitmapDataObject::GetDataHere(void *buf
) const
364 wxFAIL_MSG( wxT("attempt to copy empty bitmap failed") );
369 memcpy(buf
, m_pngData
, m_pngSize
);
374 bool wxBitmapDataObject::SetData(size_t size
, const void *buf
)
378 wxCHECK_MSG( wxImage::FindHandler(wxBITMAP_TYPE_PNG
) != NULL
,
379 false, wxT("You must call wxImage::AddHandler(new wxPNGHandler); to be able to use clipboard with bitmaps!") );
382 m_pngData
= malloc(m_pngSize
);
384 memcpy(m_pngData
, buf
, m_pngSize
);
386 wxMemoryInputStream
mstream((char*) m_pngData
, m_pngSize
);
388 if ( !image
.LoadFile( mstream
, wxBITMAP_TYPE_PNG
) )
393 m_bitmap
= wxBitmap(image
);
395 return m_bitmap
.IsOk();
398 void wxBitmapDataObject::DoConvertToPng()
400 if ( !m_bitmap
.IsOk() )
403 wxCHECK_RET( wxImage::FindHandler(wxBITMAP_TYPE_PNG
) != NULL
,
404 wxT("You must call wxImage::AddHandler(new wxPNGHandler); to be able to use clipboard with bitmaps!") );
406 wxImage image
= m_bitmap
.ConvertToImage();
408 wxCountingOutputStream count
;
409 image
.SaveFile(count
, wxBITMAP_TYPE_PNG
);
411 m_pngSize
= count
.GetSize() + 100; // sometimes the size seems to vary ???
412 m_pngData
= malloc(m_pngSize
);
414 wxMemoryOutputStream
mstream((char*) m_pngData
, m_pngSize
);
415 image
.SaveFile(mstream
, wxBITMAP_TYPE_PNG
);
418 // ----------------------------------------------------------------------------
420 // ----------------------------------------------------------------------------
422 class wxTextURIListDataObject
: public wxDataObjectSimple
425 wxTextURIListDataObject(const wxString
& url
)
426 : wxDataObjectSimple(wxDataFormat(g_fileAtom
)),
431 const wxString
& GetURL() const { return m_url
; }
432 void SetURL(const wxString
& url
) { m_url
= url
; }
435 virtual size_t GetDataSize() const
437 // It is not totally clear whether we should include "\r\n" at the end
438 // of the string if there is only one URL or not, but not doing it
439 // doesn't seem to create any problems, so keep things simple.
440 return strlen(m_url
.utf8_str()) + 1;
443 virtual bool GetDataHere(void *buf
) const
445 char* const dst
= static_cast<char*>(buf
);
447 strcpy(dst
, m_url
.utf8_str());
452 virtual bool SetData(size_t len
, const void *buf
)
454 const char* const src
= static_cast<const char*>(buf
);
456 // The string might be "\r\n"-terminated but this is not necessarily
457 // the case (e.g. when dragging an URL from Firefox, it isn't).
458 if ( len
> 1 && src
[len
- 1] == '\n' )
460 if ( len
> 2 && src
[len
- 2] == '\r' )
466 m_url
= wxString::FromUTF8(src
, len
);
471 // Must provide overloads to avoid hiding them (and warnings about it)
472 virtual size_t GetDataSize(const wxDataFormat
&) const
474 return GetDataSize();
476 virtual bool GetDataHere(const wxDataFormat
&, void *buf
) const
478 return GetDataHere(buf
);
480 virtual bool SetData(const wxDataFormat
&, size_t len
, const void *buf
)
482 return SetData(len
, buf
);
489 wxURLDataObject::wxURLDataObject(const wxString
& url
) :
490 m_dobjURIList(new wxTextURIListDataObject(url
)),
491 m_dobjText(new wxTextDataObject(url
))
493 // Use both URL-specific format and a plain text one to ensure that URLs
494 // can be pasted into any application.
495 Add(m_dobjURIList
, true /* preferred */);
499 void wxURLDataObject::SetURL(const wxString
& url
)
501 m_dobjURIList
->SetURL(url
);
502 m_dobjText
->SetText(url
);
505 wxString
wxURLDataObject::GetURL() const
507 if ( GetReceivedFormat() == g_fileAtom
)
509 // If we received the URL as an URI, use it.
510 return m_dobjURIList
->GetURL();
512 else // Otherwise we either got it as text or didn't get anything yet.
514 // In either case using the text format should be fine.
515 return m_dobjText
->GetText();
519 #endif // wxUSE_DATAOBJ