]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/clipbrd.cpp
Fixed [ 1558015 ] No deselection event from wxGenericTreeCtrl::SelectItem()
[wxWidgets.git] / src / mac / carbon / clipbrd.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/mac/carbon/clipbrd.cpp
3 // Purpose: Clipboard functionality
4 // Author: Stefan Csomor;
5 // Generalized clipboard implementation by Matthew Flatt
6 // Modified by:
7 // Created: 1998-01-01
8 // RCS-ID: $Id$
9 // Copyright: (c) Stefan Csomor
10 // Licence: wxWindows licence
11 /////////////////////////////////////////////////////////////////////////////
12
13 #include "wx/wxprec.h"
14
15 #if wxUSE_CLIPBOARD
16
17 #include "wx/clipbrd.h"
18
19 #ifndef WX_PRECOMP
20 #include "wx/intl.h"
21 #include "wx/log.h"
22 #include "wx/app.h"
23 #include "wx/utils.h"
24 #include "wx/frame.h"
25 #include "wx/bitmap.h"
26 #endif
27
28 #include "wx/metafile.h"
29
30 #ifndef __DARWIN__
31 #include <Scrap.h>
32 #endif
33
34 #include "wx/mac/uma.h"
35
36 #define wxUSE_DATAOBJ 1
37
38 #include <string.h>
39
40
41 // the trace mask we use with wxLogTrace() - call
42 // wxLog::AddTraceMask(TRACE_CLIPBOARD) to enable the trace messages from here
43 // (there will be a *lot* of them!)
44 static const wxChar *TRACE_CLIPBOARD = wxT("clipboard");
45
46
47 void * wxGetClipboardData( wxDataFormat dataFormat, long *len )
48 {
49 OSStatus err = noErr;
50 void * data = NULL;
51 Size byteCount;
52
53 switch (dataFormat.GetType())
54 {
55 case wxDF_OEMTEXT:
56 dataFormat = wxDF_TEXT;
57 break;
58
59 case wxDF_TEXT:
60 case wxDF_UNICODETEXT:
61 break;
62
63 case wxDF_BITMAP:
64 case wxDF_METAFILE:
65 break;
66
67 default:
68 // custom datatype
69 break;
70 }
71
72 #if TARGET_CARBON
73 ScrapRef scrapRef;
74
75 err = GetCurrentScrap( &scrapRef );
76 if ( err != noTypeErr && err != memFullErr )
77 {
78 ScrapFlavorFlags flavorFlags;
79
80 err = GetScrapFlavorFlags( scrapRef, dataFormat.GetFormatId(), &flavorFlags );
81 if (err == noErr)
82 {
83 err = GetScrapFlavorSize( scrapRef, dataFormat.GetFormatId(), &byteCount );
84 if (err == noErr)
85 {
86 Size allocSize = byteCount;
87 if ( dataFormat.GetType() == wxDF_TEXT )
88 allocSize += 1;
89 else if ( dataFormat.GetType() == wxDF_UNICODETEXT )
90 allocSize += 2;
91
92 data = new char[ allocSize ];
93
94 if (( err = GetScrapFlavorData( scrapRef, dataFormat.GetFormatId(), &byteCount , data )) == noErr )
95 {
96 *len = allocSize;
97 if ( dataFormat.GetType() == wxDF_TEXT )
98 ((char*)data)[ byteCount ] = 0;
99 if ( dataFormat.GetType() == wxDF_UNICODETEXT )
100 {
101 // "data" format is UTF16, so 2 bytes = one character
102 // wxChar size depends on platform, so just clear last 2 bytes
103 ((char*)data)[ byteCount + 0 ] =
104 ((char*)data)[ byteCount + 1 ] = 0;
105 }
106 }
107 else
108 {
109 delete [] (char*)data;
110 data = NULL;
111 }
112 }
113 }
114 }
115
116 #else
117 long offset;
118 Handle datahandle = NewHandle( 0 );
119 HLock( datahandle );
120 err = (OSStatus)GetScrap( datahandle, dataFormat.GetFormatId(), &offset );
121 HUnlock( datahandle );
122 if ( GetHandleSize( datahandle ) > 0 )
123 {
124 byteCount = GetHandleSize( datahandle );
125 Size allocSize = byteCount;
126 if ( dataFormat.GetType() == wxDF_TEXT )
127 allocSize += 1;
128 else if ( dataFormat.GetType() == wxDF_UNICODETEXT )
129 allocSize += 2;
130
131 data = new char[ allocSize ];
132
133 memcpy( (char*) data, (char*) *datahandle, byteCount );
134 if ( dataFormat.GetType() == wxDF_TEXT )
135 ((char*)data)[ byteCount ] = 0;
136 else if ( dataFormat.GetType() == wxDF_UNICODETEXT )
137 ((wxChar*)data)[ byteCount / 2 ] = 0;
138 *len = byteCount;
139 }
140
141 DisposeHandle( datahandle );
142 #endif
143
144 if (err != noErr)
145 {
146 wxLogSysError(wxT("Failed to get clipboard data."));
147
148 return NULL;
149 }
150
151 if (dataFormat.GetType() == wxDF_TEXT)
152 wxMacConvertNewlines10To13( (char*)data );
153
154 return data;
155 }
156
157 IMPLEMENT_DYNAMIC_CLASS(wxClipboard, wxObject)
158
159 wxClipboard::wxClipboard()
160 {
161 m_open = false;
162 m_data = NULL;
163 }
164
165 wxClipboard::~wxClipboard()
166 {
167 if (m_data != NULL)
168 {
169 delete m_data;
170 m_data = NULL;
171 }
172 }
173
174 void wxClipboard::Clear()
175 {
176 if (m_data != NULL)
177 {
178 delete m_data;
179 m_data = NULL;
180 }
181
182 #if TARGET_CARBON
183 OSStatus err;
184 err = ClearCurrentScrap();
185 #else
186 OSErr err;
187 err = ZeroScrap();
188 #endif
189
190 if (err != noErr)
191 {
192 wxLogSysError( wxT("Failed to empty the clipboard.") );
193 }
194 }
195
196 bool wxClipboard::Flush()
197 {
198 return false;
199 }
200
201 bool wxClipboard::Open()
202 {
203 wxCHECK_MSG( !m_open, false, wxT("clipboard already open") );
204
205 m_open = true;
206
207 return true;
208 }
209
210 bool wxClipboard::IsOpened() const
211 {
212 return m_open;
213 }
214
215 bool wxClipboard::SetData( wxDataObject *data )
216 {
217 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
218 wxCHECK_MSG( data, false, wxT("data is invalid") );
219
220 Clear();
221
222 // as we can only store one wxDataObject,
223 // this is the same in this implementation
224 return AddData( data );
225 }
226
227 bool wxClipboard::AddData( wxDataObject *data )
228 {
229 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
230 wxCHECK_MSG( data, false, wxT("data is invalid") );
231
232 // we can only store one wxDataObject
233 Clear();
234
235 m_data = data;
236
237 // get formats from wxDataObjects
238 wxDataFormat *array = new wxDataFormat[ m_data->GetFormatCount() ];
239 m_data->GetAllFormats( array );
240
241 for (size_t i = 0; i < m_data->GetFormatCount(); i++)
242 {
243 if (array[i].IsStandard())
244 {
245 wxLogTrace( TRACE_CLIPBOARD,
246 wxT("wxClipboard now supports standard atom type %d"),
247 array[i].GetType() );
248 }
249 else
250 {
251 wxLogTrace( TRACE_CLIPBOARD,
252 wxT("wxClipboard now supports atom %s"),
253 array[i].GetId().c_str() );
254 }
255
256 size_t sz = data->GetDataSize( array[ i ] );
257 void* buf = malloc( sz + 1 );
258 if ( buf != NULL )
259 {
260 // empty the buffer because in some case GetDataHere does not fill buf
261 memset( buf, 0, sz + 1 );
262 data->GetDataHere( array[ i ], buf );
263 OSType mactype = 0;
264 switch ( array[i].GetType() )
265 {
266 case wxDF_TEXT:
267 case wxDF_OEMTEXT:
268 mactype = kScrapFlavorTypeText;
269 sz -= 1;
270 break;
271
272 #if wxUSE_UNICODE
273 case wxDF_UNICODETEXT:
274 mactype = kScrapFlavorTypeUnicode;
275 sz -= 2;
276 break;
277 #endif
278
279 #if wxUSE_DRAG_AND_DROP
280 case wxDF_METAFILE:
281 mactype = kScrapFlavorTypePicture;
282 break;
283 #endif
284
285 case wxDF_BITMAP:
286 case wxDF_DIB:
287 mactype = kScrapFlavorTypePicture;
288 break;
289
290 default:
291 mactype = (OSType)(array[ i ].GetFormatId());
292 break;
293 }
294
295 UMAPutScrap( sz , mactype , buf );
296 free( buf );
297 }
298 }
299
300 delete [] array;
301
302 return true;
303 }
304
305 void wxClipboard::Close()
306 {
307 wxCHECK_RET( m_open, wxT("clipboard not open") );
308
309 m_open = false;
310
311 // Get rid of cached object.
312 // If this is not done, copying data from
313 // another application will only work once
314 if (m_data)
315 {
316 delete m_data;
317 m_data = (wxDataObject*) NULL;
318 }
319 }
320
321 bool wxClipboard::IsSupported( const wxDataFormat &dataFormat )
322 {
323 if ( m_data )
324 return m_data->IsSupported( dataFormat );
325
326 bool hasData = false;
327
328 #if TARGET_CARBON
329 OSStatus err = noErr;
330 ScrapRef scrapRef;
331
332 err = GetCurrentScrap( &scrapRef );
333 if ( err != noTypeErr && err != memFullErr )
334 {
335 ScrapFlavorFlags flavorFlags;
336 Size byteCount;
337
338 err = GetScrapFlavorFlags( scrapRef, dataFormat.GetFormatId(), &flavorFlags );
339 if (err == noErr)
340 {
341 err = GetScrapFlavorSize( scrapRef, dataFormat.GetFormatId(), &byteCount );
342 if (err == noErr)
343 hasData = true;
344 }
345 else if ( dataFormat.GetType() == wxDF_UNICODETEXT )
346 {
347 err = GetScrapFlavorFlags( scrapRef, 'TEXT', &flavorFlags );
348 if (err == noErr)
349 {
350 err = GetScrapFlavorSize( scrapRef, 'TEXT', &byteCount );
351 if (err == noErr)
352 hasData = true;
353 }
354 }
355 }
356
357 #else
358
359 long offset = 0;
360 Handle datahandle = NewHandle( 0 );
361 HLock( datahandle );
362 GetScrap( datahandle, dataFormat.GetFormatId(), &offset );
363 HUnlock( datahandle );
364 hasData = GetHandleSize( datahandle ) > 0;
365 DisposeHandle( datahandle );
366 #endif
367
368 return hasData;
369 }
370
371 bool wxClipboard::GetData( wxDataObject& data )
372 {
373 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
374
375 size_t formatcount = data.GetFormatCount() + 1;
376 wxDataFormat *array = new wxDataFormat[ formatcount ];
377 array[0] = data.GetPreferredFormat();
378 data.GetAllFormats( &array[1] );
379
380 bool transferred = false;
381
382 if ( m_data )
383 {
384 for (size_t i = 0; !transferred && i < formatcount; i++)
385 {
386 wxDataFormat format = array[ i ];
387 if ( m_data->IsSupported( format ) )
388 {
389 int dataSize = m_data->GetDataSize( format );
390 transferred = true;
391
392 if (dataSize == 0)
393 {
394 data.SetData( format, 0, 0 );
395 }
396 else
397 {
398 char *d = new char[ dataSize ];
399 m_data->GetDataHere( format, (void*)d );
400 data.SetData( format, dataSize, d );
401 delete [] d;
402 }
403 }
404 }
405 }
406
407 // get formats from wxDataObjects
408 if ( !transferred )
409 {
410 for (size_t i = 0; !transferred && i < formatcount; i++)
411 {
412 wxDataFormat format = array[ i ];
413
414 switch ( format.GetType() )
415 {
416 // NOTE: this is usable for all data types
417 case wxDF_TEXT:
418 case wxDF_UNICODETEXT:
419 case wxDF_OEMTEXT:
420 case wxDF_BITMAP:
421 case wxDF_METAFILE:
422 default:
423 {
424 long len;
425 char* s = (char*)wxGetClipboardData( format, &len );
426 if (s != NULL)
427 {
428 data.SetData( format, len, s );
429 delete [] s;
430
431 transferred = true;
432 }
433 }
434 break;
435 }
436 }
437 }
438
439 delete [] array;
440
441 return transferred;
442 }
443
444 #endif