1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/mac/carbon/dataobj.cpp
3 // Purpose: implementation of wxDataObject class
4 // Author: Stefan Csomor
8 // Copyright: (c) 1999 Stefan Csomor
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
17 #include "wx/dataobj.h"
22 #include "wx/dcmemory.h"
26 #include "wx/mstream.h"
27 #include "wx/metafile.h"
28 #include "wx/tokenzr.h"
30 #include "wx/mac/uma.h"
33 #include <QuickTime/QuickTime.h>
37 // ----------------------------------------------------------------------------
39 // ----------------------------------------------------------------------------
41 wxDataFormat::wxDataFormat()
43 m_type
= wxDF_INVALID
;
47 wxDataFormat::wxDataFormat( wxDataFormatId vType
)
50 m_type
= wxDF_INVALID
;
54 wxDataFormat::wxDataFormat( const wxChar
*zId
)
57 m_type
= wxDF_INVALID
;
61 wxDataFormat::wxDataFormat( const wxString
& rId
)
64 m_type
= wxDF_INVALID
;
68 wxDataFormat::wxDataFormat(const wxDataFormat
& rFormat
)
70 if ( rFormat
.m_format
)
71 m_format
= (NativeFormat
) CFStringCreateCopy(NULL
, (CFStringRef
)rFormat
.m_format
);
74 m_type
= rFormat
.m_type
;
78 wxDataFormat::wxDataFormat( NativeFormat vFormat
)
81 m_type
= wxDF_INVALID
;
85 wxDataFormat::~wxDataFormat()
89 CFRelease( (CFStringRef
) m_format
);
94 // in order to be correct for 10.3 we restrict to the available types there
95 // http://developer.apple.com/qa/qa2005/qa1406.html
96 // TODO : Use UTCoreTypes.h constants once we support 10.4+ only
98 wxDataFormat
& wxDataFormat::operator=(const wxDataFormat
& rFormat
)
102 CFRelease( (CFStringRef
) m_format
);
105 if ( rFormat
.m_format
)
106 m_format
= (NativeFormat
) CFStringCreateCopy(NULL
, (CFStringRef
)rFormat
.m_format
);
107 m_type
= rFormat
.m_type
;
112 void wxDataFormat::SetType( wxDataFormatId dataType
)
117 CFRelease( (CFStringRef
) m_format
);
124 m_format
= (long) CFStringCreateCopy( NULL
, CFSTR("public.plain-text") );
127 case wxDF_UNICODETEXT
:
128 m_format
= (long) CFStringCreateCopy( NULL
, CFSTR("public.utf16-plain-text") );
132 m_format
= (long) CFStringCreateCopy( NULL
, CFSTR("public.tiff") );
135 m_format
= (long) CFStringCreateCopy( NULL
, CFSTR("com.adobe.pdf") );
139 m_format
= (long) CFStringCreateCopy( NULL
, CFSTR("public.file-url") );
143 wxFAIL_MSG( wxT("invalid data format") );
148 wxString
wxDataFormat::GetId() const
150 wxCHECK_MSG( !IsStandard(), wxEmptyString
,
151 wxT("name of predefined format cannot be retrieved") );
156 void wxDataFormat::SetId( NativeFormat format
)
160 CFRelease( (CFStringRef
) m_format
);
163 m_format
= (NativeFormat
) CFStringCreateCopy(NULL
, (CFStringRef
)format
);
164 if ( UTTypeConformsTo( (CFStringRef
)format
, CFSTR("public.utf16-plain-text") ) )
166 m_type
= wxDF_UNICODETEXT
;
168 else if ( UTTypeConformsTo( (CFStringRef
)format
, CFSTR("public.plain-text") ) )
172 else if ( UTTypeConformsTo( (CFStringRef
)format
, CFSTR("public.tiff") ) )
174 m_type
= wxDF_BITMAP
;
176 else if ( UTTypeConformsTo( (CFStringRef
)format
, CFSTR("com.adobe.pdf") ) )
178 m_type
= wxDF_METAFILE
;
180 else if ( UTTypeConformsTo( (CFStringRef
)format
, CFSTR("public.file-url") ) )
182 m_type
= wxDF_FILENAME
;
186 m_type
= wxDF_PRIVATE
;
187 m_id
= wxMacCFStringHolder( (CFStringRef
) CFRetain((CFStringRef
) format
)).AsString();
191 void wxDataFormat::SetId( const wxString
& zId
)
193 m_type
= wxDF_PRIVATE
;
197 CFRelease( (CFStringRef
) m_format
);
200 // since it is private, no need to conform to anything ...
201 m_format
= (long) wxMacCFStringHolder(m_id
).Detach();
204 bool wxDataFormat::operator==(const wxDataFormat
& format
) const
206 if (IsStandard() || format
.IsStandard())
207 return (format
.m_type
== m_type
);
209 return ( UTTypeConformsTo( (CFStringRef
) m_format
, (CFStringRef
) format
.m_format
) );
212 //-------------------------------------------------------------------------
214 //-------------------------------------------------------------------------
216 wxDataObject::wxDataObject()
220 bool wxDataObject::IsSupportedFormat( const wxDataFormat
& rFormat
, Direction vDir
) const
222 size_t nFormatCount
= GetFormatCount( vDir
);
225 if (nFormatCount
== 1)
227 found
= (rFormat
== GetPreferredFormat());
231 wxDataFormat
*pFormats
= new wxDataFormat
[nFormatCount
];
232 GetAllFormats( pFormats
, vDir
);
234 for (size_t n
= 0; n
< nFormatCount
; n
++)
236 if (pFormats
[n
] == rFormat
)
249 void wxDataObject::AddToPasteboard( void * pb
, int itemID
)
251 PasteboardRef pasteboard
= (PasteboardRef
) pb
;
252 // get formats from wxDataObjects
253 wxDataFormat
*array
= new wxDataFormat
[ GetFormatCount() ];
254 GetAllFormats( array
);
256 for (size_t i
= 0; i
< GetFormatCount(); i
++)
258 wxDataFormat thisFormat
= array
[ i
];
260 // add four bytes at the end for data objs like text that
261 // have a datasize = strlen but still need a buffer for the
262 // string including trailing zero
264 size_t datasize
= GetDataSize( thisFormat
);
265 size_t sz
= datasize
+ 4;
266 void* buf
= malloc( sz
);
269 // empty the buffer because in some case GetDataHere does not fill buf
270 memset( buf
, 0, sz
);
271 if ( GetDataHere( array
[ i
], buf
) )
274 if ( thisFormat
.GetType() == wxDF_FILENAME
)
276 // the data is D-normalized UTF8 strings of filenames delimited with \n
277 char *fname
= strtok((char*) buf
,"\n");
278 while (fname
!= NULL
)
280 // translate the filepath into a fileurl and put that into the pasteobard
281 CFStringRef path
= CFStringCreateWithBytes(NULL
,(UInt8
*)fname
,strlen(fname
),kCFStringEncodingUTF8
,false);
282 CFURLRef url
= CFURLCreateWithFileSystemPath(NULL
, path
, kCFURLPOSIXPathStyle
, false);
284 CFDataRef data
= CFURLCreateData(NULL
,url
,kCFStringEncodingUTF8
,true);
286 PasteboardPutItemFlavor( pasteboard
, (PasteboardItemID
) counter
,
287 (CFStringRef
) thisFormat
.GetFormatId() , data
, kPasteboardFlavorNoFlags
);
290 fname
= strtok (NULL
,"\n");
296 CFDataRef data
= CFDataCreate( kCFAllocatorDefault
, (UInt8
*)buf
, datasize
);
297 if ( thisFormat
.GetType() == wxDF_TEXT
)
298 PasteboardPutItemFlavor( pasteboard
, (PasteboardItemID
) itemID
,
299 CFSTR("com.apple.traditional-mac-plain-text") , data
, kPasteboardFlavorNoFlags
);
301 PasteboardPutItemFlavor( pasteboard
, (PasteboardItemID
) itemID
,
302 (CFStringRef
) thisFormat
.GetFormatId() , data
, kPasteboardFlavorNoFlags
);
313 bool wxDataObject::IsFormatInPasteboard( void * pb
, const wxDataFormat
&dataFormat
)
315 PasteboardRef pasteboard
= (PasteboardRef
) pb
;
316 bool hasData
= false;
317 OSStatus err
= noErr
;
320 // we synchronize here once again, so we don't mind which flags get returned
321 PasteboardSynchronize( pasteboard
);
323 err
= PasteboardGetItemCount( pasteboard
, &itemCount
);
326 for( UInt32 itemIndex
= 1; itemIndex
<= itemCount
&& hasData
== false ; itemIndex
++ )
328 PasteboardItemID itemID
;
329 CFArrayRef flavorTypeArray
;
332 err
= PasteboardGetItemIdentifier( pasteboard
, itemIndex
, &itemID
);
336 err
= PasteboardCopyItemFlavors( pasteboard
, itemID
, &flavorTypeArray
);
340 flavorCount
= CFArrayGetCount( flavorTypeArray
);
342 for( CFIndex flavorIndex
= 0; flavorIndex
< flavorCount
&& hasData
== false ; flavorIndex
++ )
344 CFStringRef flavorType
;
346 flavorType
= (CFStringRef
)CFArrayGetValueAtIndex( flavorTypeArray
,
349 wxDataFormat
flavorFormat( (wxDataFormat::NativeFormat
) flavorType
);
350 if ( dataFormat
== flavorFormat
)
352 else if ( dataFormat
.GetType() == wxDF_UNICODETEXT
&& flavorFormat
.GetType() == wxDF_TEXT
)
355 CFRelease (flavorTypeArray
);
362 bool wxDataObject::GetFromPasteboard( void * pb
)
364 PasteboardRef pasteboard
= (PasteboardRef
) pb
;
365 size_t formatcount
= GetFormatCount() + 1;
366 wxDataFormat
*array
= new wxDataFormat
[ formatcount
];
367 array
[0] = GetPreferredFormat();
368 GetAllFormats( &array
[1] );
369 ItemCount itemCount
= 0;
370 wxString filenamesPassed
;
371 bool transferred
= false;
373 // we synchronize here once again, so we don't mind which flags get returned
374 PasteboardSynchronize( pasteboard
);
376 OSStatus err
= PasteboardGetItemCount( pasteboard
, &itemCount
);
379 for (size_t i
= 0; !transferred
&& i
< formatcount
; i
++)
381 // go through the data in our order of preference
382 wxDataFormat dataFormat
= array
[ i
];
384 for( UInt32 itemIndex
= 1; itemIndex
<= itemCount
&& transferred
== false ; itemIndex
++ )
386 PasteboardItemID itemID
= 0;
387 CFArrayRef flavorTypeArray
= NULL
;
388 CFIndex flavorCount
= 0;
390 err
= PasteboardGetItemIdentifier( pasteboard
, itemIndex
, &itemID
);
394 err
= PasteboardCopyItemFlavors( pasteboard
, itemID
, &flavorTypeArray
);
398 flavorCount
= CFArrayGetCount( flavorTypeArray
);
400 for( CFIndex flavorIndex
= 0; !transferred
&& flavorIndex
< flavorCount
; flavorIndex
++ )
402 CFStringRef flavorType
;
403 CFDataRef flavorData
;
404 CFIndex flavorDataSize
;
406 flavorType
= (CFStringRef
)CFArrayGetValueAtIndex( flavorTypeArray
,
409 wxDataFormat
flavorFormat( (wxDataFormat::NativeFormat
) flavorType
);
411 if ( dataFormat
== flavorFormat
)
413 err
= PasteboardCopyItemFlavorData( pasteboard
, itemID
, flavorType
, &flavorData
);
416 flavorDataSize
= CFDataGetLength( flavorData
);
417 if (dataFormat
.GetType() == wxDF_FILENAME
)
419 // revert the translation and decomposition to arrive at a proper utf8 string again
420 CFURLRef url
= CFURLCreateWithBytes( kCFAllocatorDefault
, CFDataGetBytePtr( flavorData
), flavorDataSize
, kCFStringEncodingUTF8
, NULL
);
421 CFStringRef cfString
= CFURLCopyFileSystemPath( url
, kCFURLPOSIXPathStyle
);
423 CFMutableStringRef cfMutableString
= CFStringCreateMutableCopy(NULL
, 0, cfString
);
424 CFRelease( cfString
);
425 CFStringNormalize(cfMutableString
,kCFStringNormalizationFormC
);
426 wxString path
= wxMacCFStringHolder(cfMutableString
).AsString();
428 filenamesPassed
+= path
+ wxT("\n");
432 // because some data implementation expect trailing a trailing NUL, we add some headroom
433 void *buf
= malloc( flavorDataSize
+ 4 );
436 memset( buf
, 0, flavorDataSize
+ 4 );
437 memcpy( buf
, CFDataGetBytePtr( flavorData
), flavorDataSize
);
439 if (dataFormat
.GetType() == wxDF_TEXT
)
440 wxMacConvertNewlines10To13( (char*) buf
);
441 SetData( flavorFormat
, flavorDataSize
, buf
);
446 CFRelease (flavorData
);
449 else if ( dataFormat
.GetType() == wxDF_UNICODETEXT
&& flavorFormat
.GetType() == wxDF_TEXT
)
451 err
= PasteboardCopyItemFlavorData( pasteboard
, itemID
, flavorType
, &flavorData
);
454 flavorDataSize
= CFDataGetLength( flavorData
);
455 void *asciibuf
= malloc( flavorDataSize
+ 1 );
458 memset( asciibuf
, 0, flavorDataSize
+ 1 );
459 memcpy( asciibuf
, CFDataGetBytePtr( flavorData
), flavorDataSize
);
460 CFRelease (flavorData
);
462 SetData( wxDF_TEXT
, flavorDataSize
, asciibuf
);
467 CFRelease (flavorData
);
471 CFRelease( flavorTypeArray
);
473 if (filenamesPassed
.length() > 0)
475 wxCharBuffer buf
= filenamesPassed
.fn_str();
476 SetData( wxDF_FILENAME
, strlen( buf
), (const char*)buf
);
484 bool wxDataObject::HasDataInPasteboard( void * pb
)
486 PasteboardRef pasteboard
= (PasteboardRef
) pb
;
487 size_t formatcount
= GetFormatCount() + 1;
488 wxDataFormat
*array
= new wxDataFormat
[ formatcount
];
489 array
[0] = GetPreferredFormat();
490 GetAllFormats( &array
[1] );
491 ItemCount itemCount
= 0;
492 bool hasData
= false;
494 // we synchronize here once again, so we don't mind which flags get returned
495 PasteboardSynchronize( pasteboard
);
497 OSStatus err
= PasteboardGetItemCount( pasteboard
, &itemCount
);
500 for (size_t i
= 0; !hasData
&& i
< formatcount
; i
++)
502 // go through the data in our order of preference
503 wxDataFormat dataFormat
= array
[ i
];
505 for( UInt32 itemIndex
= 1; itemIndex
<= itemCount
&& hasData
== false ; itemIndex
++ )
507 PasteboardItemID itemID
= 0;
508 CFArrayRef flavorTypeArray
= NULL
;
509 CFIndex flavorCount
= 0;
511 err
= PasteboardGetItemIdentifier( pasteboard
, itemIndex
, &itemID
);
515 err
= PasteboardCopyItemFlavors( pasteboard
, itemID
, &flavorTypeArray
);
519 flavorCount
= CFArrayGetCount( flavorTypeArray
);
521 for( CFIndex flavorIndex
= 0; !hasData
&& flavorIndex
< flavorCount
; flavorIndex
++ )
523 CFStringRef flavorType
;
525 flavorType
= (CFStringRef
)CFArrayGetValueAtIndex( flavorTypeArray
,
528 wxDataFormat
flavorFormat( (wxDataFormat::NativeFormat
) flavorType
);
530 if ( dataFormat
== flavorFormat
||
531 dataFormat
.GetType() == wxDF_UNICODETEXT
&& flavorFormat
.GetType() == wxDF_TEXT
)
536 CFRelease( flavorTypeArray
);
543 // ----------------------------------------------------------------------------
545 // ----------------------------------------------------------------------------
548 void wxTextDataObject::GetAllFormats(wxDataFormat
*formats
,
549 wxDataObjectBase::Direction
WXUNUSED(dir
)) const
551 *formats
++ = wxDataFormat( wxDF_TEXT
);
552 *formats
= wxDataFormat( wxDF_UNICODETEXT
);
556 // ----------------------------------------------------------------------------
558 // ----------------------------------------------------------------------------
560 void wxFileDataObject::GetFileNames( wxCharBuffer
&buf
) const
564 for (size_t i
= 0; i
< m_filenames
.GetCount(); i
++)
566 filenames
+= m_filenames
[i
];
567 filenames
+= wxT('\n');
570 buf
= filenames
.fn_str();
573 bool wxFileDataObject::GetDataHere( void *pBuf
) const
582 buffLength
= strlen( buf
);
583 memcpy( pBuf
, (const char*)buf
, buffLength
+ 1 );
588 size_t wxFileDataObject::GetDataSize() const
594 buffLength
= strlen( buf
);
596 return buffLength
+ 1;
599 bool wxFileDataObject::SetData( size_t WXUNUSED(nSize
), const void *pBuf
)
604 filenames
= wxString( (const char*)pBuf
, *wxConvFileName
);
606 filenames
= wxString (wxConvLocal
.cWC2WX(wxConvFileName
->cMB2WC( (const char*)pBuf
)));
609 m_filenames
= wxStringTokenize( filenames
, wxT("\n"), wxTOKEN_STRTOK
);
614 void wxFileDataObject::AddFile( const wxString
& rFilename
)
616 m_filenames
.Add( rFilename
);
619 // ----------------------------------------------------------------------------
620 // wxBitmapDataObject
621 // ----------------------------------------------------------------------------
623 wxBitmapDataObject::wxBitmapDataObject()
628 wxBitmapDataObject::wxBitmapDataObject( const wxBitmap
& rBitmap
)
629 : wxBitmapDataObjectBase( rBitmap
)
635 SetBitmap( rBitmap
);
639 wxBitmapDataObject::~wxBitmapDataObject()
644 void wxBitmapDataObject::SetBitmap( const wxBitmap
& rBitmap
)
647 wxBitmapDataObjectBase::SetBitmap( rBitmap
);
650 CGImageRef cgImageRef
= (CGImageRef
) m_bitmap
.CreateCGImage();
652 CFMutableDataRef data
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
653 CGImageDestinationRef destination
= CGImageDestinationCreateWithData( data
, kUTTypeTIFF
, 1 , NULL
);
656 CGImageDestinationAddImage( destination
, cgImageRef
, NULL
);
657 CGImageDestinationFinalize( destination
);
658 CFRelease( destination
);
660 m_pictHandle
= NewHandle(CFDataGetLength(data
));
663 memcpy( *(Handle
)m_pictHandle
, (const char *)CFDataGetBytePtr(data
), CFDataGetLength(data
) );
667 CGImageRelease(cgImageRef
);
671 void wxBitmapDataObject::Init()
674 m_pictCreated
= false;
677 void wxBitmapDataObject::Clear()
679 if (m_pictHandle
!= NULL
)
681 DisposeHandle( (Handle
) m_pictHandle
);
684 m_pictCreated
= false;
687 bool wxBitmapDataObject::GetDataHere( void *pBuf
) const
689 if (m_pictHandle
== NULL
)
691 wxFAIL_MSG( wxT("attempt to copy empty bitmap failed") );
698 memcpy( pBuf
, *(Handle
)m_pictHandle
, GetHandleSize( (Handle
)m_pictHandle
) );
703 size_t wxBitmapDataObject::GetDataSize() const
705 if (m_pictHandle
!= NULL
)
706 return GetHandleSize( (Handle
)m_pictHandle
);
711 Handle
MacCreateDataReferenceHandle(Handle theDataHandle
)
713 Handle dataRef
= NULL
;
716 // Create a data reference handle for our data.
717 err
= PtrToHand( &theDataHandle
, &dataRef
, sizeof(Handle
));
722 bool wxBitmapDataObject::SetData( size_t nSize
, const void *pBuf
)
726 if ((pBuf
== NULL
) || (nSize
== 0))
729 Handle picHandle
= NewHandle( nSize
);
730 memcpy( *picHandle
, pBuf
, nSize
);
731 m_pictHandle
= picHandle
;
732 CGImageRef cgImageRef
= 0;
734 CFDataRef data
= CFDataCreateWithBytesNoCopy( kCFAllocatorDefault
, (const UInt8
*) pBuf
, nSize
, kCFAllocatorNull
);
735 CGImageSourceRef source
= CGImageSourceCreateWithData( data
, NULL
);
738 cgImageRef
= CGImageSourceCreateImageAtIndex(source
, 0, NULL
);
745 m_bitmap
.Create( CGImageGetWidth(cgImageRef
) , CGImageGetHeight(cgImageRef
) );
746 CGRect r
= CGRectMake( 0 , 0 , CGImageGetWidth(cgImageRef
) , CGImageGetHeight(cgImageRef
) );
747 // since our context is upside down we dont use CGContextDrawImage
748 wxMacDrawCGImage( (CGContextRef
) m_bitmap
.GetHBITMAP() , &r
, cgImageRef
) ;
749 CGImageRelease(cgImageRef
);
753 return m_bitmap
.Ok();