Lots more Unicode fixes.
[wxWidgets.git] / src / gtk1 / dataobj.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: dataobj.cpp
3 // Purpose: wxDataObject class
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
9
10 #ifdef __GNUG__
11 #pragma implementation "dataobj.h"
12 #endif
13
14 #include "wx/dataobj.h"
15 #include "wx/app.h"
16 #include "wx/debug.h"
17 #include "wx/mstream.h"
18 #include "wx/image.h"
19
20 #include <gdk/gdk.h>
21
22 //-------------------------------------------------------------------------
23 // global data
24 //-------------------------------------------------------------------------
25
26 GdkAtom g_textAtom = 0;
27 GdkAtom g_pngAtom = 0;
28 GdkAtom g_fileAtom = 0;
29
30 //-------------------------------------------------------------------------
31 // wxDataFormat
32 //-------------------------------------------------------------------------
33
34 wxDataFormat::wxDataFormat()
35 {
36 // do *not* call PrepareFormats() from here for 2 reasons:
37 //
38 // 1. we will have time to do it later because some other Set function
39 // must be called before we really need them
40 //
41 // 2. doing so prevents us from declaring global wxDataFormats because
42 // calling PrepareFormats (and thus gdk_atom_intern) before GDK is
43 // initialised will result in a crash
44 m_type = wxDF_INVALID;
45 m_format = (GdkAtom) 0;
46 }
47
48 wxDataFormat::wxDataFormat( wxDataFormatId type )
49 {
50 PrepareFormats();
51 SetType( type );
52 }
53
54 wxDataFormat::wxDataFormat( const wxChar *id )
55 {
56 PrepareFormats();
57 SetId( id );
58 }
59
60 wxDataFormat::wxDataFormat( const wxString &id )
61 {
62 PrepareFormats();
63 SetId( id );
64 }
65
66 wxDataFormat::wxDataFormat( NativeFormat format )
67 {
68 PrepareFormats();
69 SetId( format );
70 }
71
72 void wxDataFormat::SetType( wxDataFormatId type )
73 {
74 PrepareFormats();
75
76 if (type == wxDF_UNICODETEXT)
77 type = wxDF_TEXT;
78
79 m_type = type;
80
81 if (m_type == wxDF_TEXT)
82 m_format = g_textAtom;
83 else
84 if (m_type == wxDF_BITMAP)
85 m_format = g_pngAtom;
86 else
87 if (m_type == wxDF_FILENAME)
88 m_format = g_fileAtom;
89 else
90 {
91 wxFAIL_MSG( wxT("invalid dataformat") );
92 }
93 }
94
95 wxDataFormatId wxDataFormat::GetType() const
96 {
97 return m_type;
98 }
99
100 wxString wxDataFormat::GetId() const
101 {
102 wxString ret = wxString::FromAscii( gdk_atom_name( m_format ) );
103 return ret;
104 }
105
106 void wxDataFormat::SetId( NativeFormat format )
107 {
108 PrepareFormats();
109 m_format = format;
110
111 if (m_format == g_textAtom)
112 m_type = wxDF_TEXT;
113 else
114 if (m_format == g_pngAtom)
115 m_type = wxDF_BITMAP;
116 else
117 if (m_format == g_fileAtom)
118 m_type = wxDF_FILENAME;
119 else
120 m_type = wxDF_PRIVATE;
121 }
122
123 void wxDataFormat::SetId( const wxChar *id )
124 {
125 PrepareFormats();
126 m_type = wxDF_PRIVATE;
127 wxString tmp( id );
128 m_format = gdk_atom_intern( (const char*) tmp.ToAscii(), FALSE );
129 }
130
131 void wxDataFormat::PrepareFormats()
132 {
133 // VZ: GNOME included in RedHat 6.1 uses the MIME types below and not the
134 // atoms STRING and file:ALL as the old code was, but normal X apps
135 // use STRING for text selection when transfering the data via
136 // clipboard, for example, so do use STRING for now (GNOME apps will
137 // probably support STRING as well for compatibility anyhow), but use
138 // text/uri-list for file dnd because compatibility is not important
139 // here (with whom?)
140 if (!g_textAtom)
141 #if wxUSE_UNICODE
142 g_textAtom = gdk_atom_intern( "UTF8_STRING", FALSE );
143 #else
144 g_textAtom = gdk_atom_intern( "STRING" /* "text/plain" */, FALSE );
145 #endif
146 if (!g_pngAtom)
147 g_pngAtom = gdk_atom_intern( "image/png", FALSE );
148 if (!g_fileAtom)
149 g_fileAtom = gdk_atom_intern( "text/uri-list", FALSE );
150 }
151
152 //-------------------------------------------------------------------------
153 // wxDataObject
154 //-------------------------------------------------------------------------
155
156 wxDataObject::wxDataObject()
157 {
158 }
159
160 bool wxDataObject::IsSupportedFormat(const wxDataFormat& format, Direction dir) const
161 {
162 size_t nFormatCount = GetFormatCount(dir);
163 if ( nFormatCount == 1 )
164 {
165 return format == GetPreferredFormat();
166 }
167 else
168 {
169 wxDataFormat *formats = new wxDataFormat[nFormatCount];
170 GetAllFormats(formats,dir);
171
172 size_t n;
173 for ( n = 0; n < nFormatCount; n++ )
174 {
175 if ( formats[n] == format )
176 break;
177 }
178
179 delete [] formats;
180
181 // found?
182 return n < nFormatCount;
183 }
184 }
185
186 // ----------------------------------------------------------------------------
187 // wxFileDataObject
188 // ----------------------------------------------------------------------------
189
190 bool wxFileDataObject::GetDataHere(void *buf) const
191 {
192 wxString filenames;
193
194 for (size_t i = 0; i < m_filenames.GetCount(); i++)
195 {
196 filenames += m_filenames[i];
197 filenames += (wxChar) 0;
198 }
199
200 memcpy( buf, filenames.mbc_str(), filenames.Len() + 1 );
201
202 return TRUE;
203 }
204
205 size_t wxFileDataObject::GetDataSize() const
206 {
207 size_t res = 0;
208
209 for (size_t i = 0; i < m_filenames.GetCount(); i++)
210 {
211 res += m_filenames[i].Len();
212 res += 1;
213 }
214
215 return res + 1;
216 }
217
218 bool wxFileDataObject::SetData(size_t WXUNUSED(size), const void *buf)
219 {
220 // VZ: old format
221 #if 0
222 // filenames are stores as a string with #0 as deliminators
223 const char *filenames = (const char*) buf;
224 size_t pos = 0;
225 for(;;)
226 {
227 if (filenames[0] == 0)
228 break;
229 if (pos >= size)
230 break;
231 wxString file( filenames ); // this returns the first file
232 AddFile( file );
233 pos += file.Len()+1;
234 filenames += file.Len()+1;
235 }
236 #else // 1
237 m_filenames.Empty();
238
239 // the text/uri-list format is a sequence of URIs (filenames prefixed by
240 // "file:" as far as I see) delimited by "\r\n" of total length size
241 // (I wonder what happens if the file has '\n' in its filename??)
242 wxString filename;
243 for ( const char *p = (const char *)buf; ; p++ )
244 {
245 // some broken programs (testdnd GTK+ sample!) omit the trailing
246 // "\r\n", so check for '\0' explicitly here instead of doing it in
247 // the loop statement to account for it
248 if ( (*p == '\r' && *(p+1) == '\n') || !*p )
249 {
250 size_t lenPrefix = 5; // strlen("file:")
251 if ( filename.Left(lenPrefix).MakeLower() == _T("file:") )
252 {
253 // sometimes the syntax is "file:filename", sometimes it's
254 // URL-like: "file://filename" - deal with both
255 if ( filename[lenPrefix] == _T('/') &&
256 filename[lenPrefix + 1] == _T('/') )
257 {
258 // skip the slashes
259 lenPrefix += 2;
260 }
261
262 AddFile(filename.c_str() + lenPrefix);
263 filename.Empty();
264 }
265 else
266 {
267 wxLogDebug(_T("Unsupported URI '%s' in wxFileDataObject"),
268 filename.c_str());
269 }
270
271 if ( !*p )
272 break;
273
274 // skip '\r'
275 p++;
276 }
277 else
278 {
279 filename += *p;
280 }
281 }
282 #endif // 0/1
283
284 return TRUE;
285 }
286
287 void wxFileDataObject::AddFile( const wxString &filename )
288 {
289 m_filenames.Add( filename );
290 }
291
292 // ----------------------------------------------------------------------------
293 // wxBitmapDataObject
294 // ----------------------------------------------------------------------------
295
296 wxBitmapDataObject::wxBitmapDataObject()
297 {
298 Init();
299 }
300
301 wxBitmapDataObject::wxBitmapDataObject( const wxBitmap& bitmap )
302 : wxBitmapDataObjectBase(bitmap)
303 {
304 Init();
305
306 DoConvertToPng();
307 }
308
309 wxBitmapDataObject::~wxBitmapDataObject()
310 {
311 Clear();
312 }
313
314 void wxBitmapDataObject::SetBitmap( const wxBitmap &bitmap )
315 {
316 ClearAll();
317
318 wxBitmapDataObjectBase::SetBitmap(bitmap);
319
320 DoConvertToPng();
321 }
322
323 bool wxBitmapDataObject::GetDataHere(void *buf) const
324 {
325 if ( !m_pngSize )
326 {
327 wxFAIL_MSG( wxT("attempt to copy empty bitmap failed") );
328
329 return FALSE;
330 }
331
332 memcpy(buf, m_pngData, m_pngSize);
333
334 return TRUE;
335 }
336
337 bool wxBitmapDataObject::SetData(size_t size, const void *buf)
338 {
339 Clear();
340
341 wxCHECK_MSG( wxImage::FindHandler(wxBITMAP_TYPE_PNG) != NULL,
342 FALSE, wxT("You must call wxImage::AddHandler(new wxPNGHandler); to be able to use clipboard with bitmaps!") );
343
344 m_pngSize = size;
345 m_pngData = malloc(m_pngSize);
346
347 memcpy(m_pngData, buf, m_pngSize);
348
349 wxMemoryInputStream mstream((char*) m_pngData, m_pngSize);
350 wxImage image;
351 if ( !image.LoadFile( mstream, wxBITMAP_TYPE_PNG ) )
352 {
353 return FALSE;
354 }
355
356 m_bitmap = wxBitmap(image);
357
358 return m_bitmap.Ok();
359 }
360
361 void wxBitmapDataObject::DoConvertToPng()
362 {
363 if ( !m_bitmap.Ok() )
364 return;
365
366 wxCHECK_RET( wxImage::FindHandler(wxBITMAP_TYPE_PNG) != NULL,
367 wxT("You must call wxImage::AddHandler(new wxPNGHandler); to be able to use clipboard with bitmaps!") );
368
369 wxImage image = m_bitmap.ConvertToImage();
370
371 wxCountingOutputStream count;
372 image.SaveFile(count, wxBITMAP_TYPE_PNG);
373
374 m_pngSize = count.GetSize() + 100; // sometimes the size seems to vary ???
375 m_pngData = malloc(m_pngSize);
376
377 wxMemoryOutputStream mstream((char*) m_pngData, m_pngSize);
378 image.SaveFile(mstream, wxBITMAP_TYPE_PNG);
379 }
380
381