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 #if wxMAC_USE_CORE_GRAPHICS
133 m_format
= (long) CFStringCreateCopy( NULL
, CFSTR("public.tiff") );
135 m_format
= (long) CFStringCreateCopy( NULL
, CFSTR("com.apple.pict") );
139 #if wxMAC_USE_CORE_GRAPHICS
140 m_format
= (long) CFStringCreateCopy( NULL
, CFSTR("com.adobe.pdf") );
142 m_format
= (long) CFStringCreateCopy( NULL
, CFSTR("com.apple.pict") );
147 m_format
= (long) CFStringCreateCopy( NULL
, CFSTR("public.file-url") );
151 wxFAIL_MSG( wxT("invalid data format") );
156 wxString
wxDataFormat::GetId() const
158 wxCHECK_MSG( !IsStandard(), wxEmptyString
,
159 wxT("name of predefined format cannot be retrieved") );
164 void wxDataFormat::SetId( NativeFormat format
)
168 CFRelease( (CFStringRef
) m_format
);
171 m_format
= (NativeFormat
) CFStringCreateCopy(NULL
, (CFStringRef
)format
);
172 if ( UTTypeConformsTo( (CFStringRef
)format
, CFSTR("public.utf16-plain-text") ) )
174 m_type
= wxDF_UNICODETEXT
;
176 else if ( UTTypeConformsTo( (CFStringRef
)format
, CFSTR("public.plain-text") ) )
180 #if wxMAC_USE_CORE_GRAPHICS
181 else if ( UTTypeConformsTo( (CFStringRef
)format
, CFSTR("public.tiff") ) )
183 m_type
= wxDF_BITMAP
;
185 else if ( UTTypeConformsTo( (CFStringRef
)format
, CFSTR("com.adobe.pdf") ) )
187 m_type
= wxDF_METAFILE
;
190 else if ( UTTypeConformsTo( (CFStringRef
)format
, CFSTR("com.apple.pict") ) )
192 m_type
= wxDF_METAFILE
;
195 else if ( UTTypeConformsTo( (CFStringRef
)format
, CFSTR("public.file-url") ) )
197 m_type
= wxDF_FILENAME
;
201 m_type
= wxDF_PRIVATE
;
202 m_id
= wxMacCFStringHolder( (CFStringRef
) CFRetain((CFStringRef
) format
)).AsString();
206 void wxDataFormat::SetId( const wxString
& zId
)
208 m_type
= wxDF_PRIVATE
;
212 CFRelease( (CFStringRef
) m_format
);
215 // since it is private, no need to conform to anything ...
216 m_format
= (long) wxMacCFStringHolder(m_id
).Detach();
219 bool wxDataFormat::operator==(const wxDataFormat
& format
) const
221 if (IsStandard() || format
.IsStandard())
222 return (format
.m_type
== m_type
);
224 return ( UTTypeConformsTo( (CFStringRef
) m_format
, (CFStringRef
) format
.m_format
) );
227 //-------------------------------------------------------------------------
229 //-------------------------------------------------------------------------
231 wxDataObject::wxDataObject()
235 bool wxDataObject::IsSupportedFormat( const wxDataFormat
& rFormat
, Direction vDir
) const
237 size_t nFormatCount
= GetFormatCount( vDir
);
240 if (nFormatCount
== 1)
242 found
= (rFormat
== GetPreferredFormat());
246 wxDataFormat
*pFormats
= new wxDataFormat
[nFormatCount
];
247 GetAllFormats( pFormats
, vDir
);
249 for (size_t n
= 0; n
< nFormatCount
; n
++)
251 if (pFormats
[n
] == rFormat
)
264 void wxDataObject::AddToPasteboard( void * pb
, int itemID
)
266 PasteboardRef pasteboard
= (PasteboardRef
) pb
;
267 // get formats from wxDataObjects
268 wxDataFormat
*array
= new wxDataFormat
[ GetFormatCount() ];
269 GetAllFormats( array
);
271 for (size_t i
= 0; i
< GetFormatCount(); i
++)
273 wxDataFormat thisFormat
= array
[ i
];
275 // add four bytes at the end for data objs like text that
276 // have a datasize = strlen but still need a buffer for the
277 // string including trailing zero
279 size_t datasize
= GetDataSize( thisFormat
);
280 size_t sz
= datasize
+ 4;
281 void* buf
= malloc( sz
);
284 // empty the buffer because in some case GetDataHere does not fill buf
285 memset( buf
, 0, sz
);
286 if ( GetDataHere( array
[ i
], buf
) )
289 if ( thisFormat
.GetType() == wxDF_FILENAME
)
291 // the data is D-normalized UTF8 strings of filenames delimited with \n
292 char *fname
= strtok((char*) buf
,"\n");
293 while (fname
!= NULL
)
295 // translate the filepath into a fileurl and put that into the pasteobard
296 CFStringRef path
= CFStringCreateWithBytes(NULL
,(UInt8
*)fname
,strlen(fname
),kCFStringEncodingUTF8
,false);
297 CFURLRef url
= CFURLCreateWithFileSystemPath(NULL
, path
, kCFURLPOSIXPathStyle
, false);
299 CFDataRef data
= CFURLCreateData(NULL
,url
,kCFStringEncodingUTF8
,true);
301 PasteboardPutItemFlavor( pasteboard
, (PasteboardItemID
) counter
,
302 (CFStringRef
) thisFormat
.GetFormatId() , data
, kPasteboardFlavorNoFlags
);
305 fname
= strtok (NULL
,"\n");
311 CFDataRef data
= CFDataCreate( kCFAllocatorDefault
, (UInt8
*)buf
, datasize
);
312 if ( thisFormat
.GetType() == wxDF_TEXT
)
313 PasteboardPutItemFlavor( pasteboard
, (PasteboardItemID
) itemID
,
314 CFSTR("com.apple.traditional-mac-plain-text") , data
, kPasteboardFlavorNoFlags
);
316 PasteboardPutItemFlavor( pasteboard
, (PasteboardItemID
) itemID
,
317 (CFStringRef
) thisFormat
.GetFormatId() , data
, kPasteboardFlavorNoFlags
);
328 bool wxDataObject::IsFormatInPasteboard( void * pb
, const wxDataFormat
&dataFormat
)
330 PasteboardRef pasteboard
= (PasteboardRef
) pb
;
331 bool hasData
= false;
332 OSStatus err
= noErr
;
335 // we synchronize here once again, so we don't mind which flags get returned
336 PasteboardSynchronize( pasteboard
);
338 err
= PasteboardGetItemCount( pasteboard
, &itemCount
);
341 for( UInt32 itemIndex
= 1; itemIndex
<= itemCount
&& hasData
== false ; itemIndex
++ )
343 PasteboardItemID itemID
;
344 CFArrayRef flavorTypeArray
;
347 err
= PasteboardGetItemIdentifier( pasteboard
, itemIndex
, &itemID
);
351 err
= PasteboardCopyItemFlavors( pasteboard
, itemID
, &flavorTypeArray
);
355 flavorCount
= CFArrayGetCount( flavorTypeArray
);
357 for( CFIndex flavorIndex
= 0; flavorIndex
< flavorCount
&& hasData
== false ; flavorIndex
++ )
359 CFStringRef flavorType
;
361 flavorType
= (CFStringRef
)CFArrayGetValueAtIndex( flavorTypeArray
,
364 wxDataFormat
flavorFormat( (wxDataFormat::NativeFormat
) flavorType
);
365 if ( dataFormat
== flavorFormat
)
367 else if ( dataFormat
.GetType() == wxDF_UNICODETEXT
&& flavorFormat
.GetType() == wxDF_TEXT
)
370 CFRelease (flavorTypeArray
);
377 bool wxDataObject::GetFromPasteboard( void * pb
)
379 PasteboardRef pasteboard
= (PasteboardRef
) pb
;
380 size_t formatcount
= GetFormatCount() + 1;
381 wxDataFormat
*array
= new wxDataFormat
[ formatcount
];
382 array
[0] = GetPreferredFormat();
383 GetAllFormats( &array
[1] );
384 ItemCount itemCount
= 0;
385 wxString filenamesPassed
;
386 bool transferred
= false;
388 // we synchronize here once again, so we don't mind which flags get returned
389 PasteboardSynchronize( pasteboard
);
391 OSStatus err
= PasteboardGetItemCount( pasteboard
, &itemCount
);
394 for (size_t i
= 0; !transferred
&& i
< formatcount
; i
++)
396 // go through the data in our order of preference
397 wxDataFormat dataFormat
= array
[ i
];
399 for( UInt32 itemIndex
= 1; itemIndex
<= itemCount
&& transferred
== false ; itemIndex
++ )
401 PasteboardItemID itemID
= 0;
402 CFArrayRef flavorTypeArray
= NULL
;
403 CFIndex flavorCount
= 0;
405 err
= PasteboardGetItemIdentifier( pasteboard
, itemIndex
, &itemID
);
409 err
= PasteboardCopyItemFlavors( pasteboard
, itemID
, &flavorTypeArray
);
413 flavorCount
= CFArrayGetCount( flavorTypeArray
);
415 for( CFIndex flavorIndex
= 0; !transferred
&& flavorIndex
< flavorCount
; flavorIndex
++ )
417 CFStringRef flavorType
;
418 CFDataRef flavorData
;
419 CFIndex flavorDataSize
;
421 flavorType
= (CFStringRef
)CFArrayGetValueAtIndex( flavorTypeArray
,
424 wxDataFormat
flavorFormat( (wxDataFormat::NativeFormat
) flavorType
);
426 if ( dataFormat
== flavorFormat
)
428 err
= PasteboardCopyItemFlavorData( pasteboard
, itemID
, flavorType
, &flavorData
);
431 flavorDataSize
= CFDataGetLength( flavorData
);
432 if (dataFormat
.GetType() == wxDF_FILENAME
)
434 // revert the translation and decomposition to arrive at a proper utf8 string again
435 CFURLRef url
= CFURLCreateWithBytes( kCFAllocatorDefault
, CFDataGetBytePtr( flavorData
), flavorDataSize
, kCFStringEncodingUTF8
, NULL
);
436 CFStringRef cfString
= CFURLCopyFileSystemPath( url
, kCFURLPOSIXPathStyle
);
438 CFMutableStringRef cfMutableString
= CFStringCreateMutableCopy(NULL
, 0, cfString
);
439 CFRelease( cfString
);
440 CFStringNormalize(cfMutableString
,kCFStringNormalizationFormC
);
441 wxString path
= wxMacCFStringHolder(cfMutableString
).AsString();
443 filenamesPassed
+= path
+ wxT("\n");
447 // because some data implementation expect trailing a trailing NUL, we add some headroom
448 void *buf
= malloc( flavorDataSize
+ 4 );
451 memset( buf
, 0, flavorDataSize
+ 4 );
452 memcpy( buf
, CFDataGetBytePtr( flavorData
), flavorDataSize
);
454 if (dataFormat
.GetType() == wxDF_TEXT
)
455 wxMacConvertNewlines10To13( (char*) buf
);
456 SetData( flavorFormat
, flavorDataSize
, buf
);
461 CFRelease (flavorData
);
464 else if ( dataFormat
.GetType() == wxDF_UNICODETEXT
&& flavorFormat
.GetType() == wxDF_TEXT
)
466 err
= PasteboardCopyItemFlavorData( pasteboard
, itemID
, flavorType
, &flavorData
);
469 flavorDataSize
= CFDataGetLength( flavorData
);
470 void *asciibuf
= malloc( flavorDataSize
+ 1 );
473 memset( asciibuf
, 0, flavorDataSize
+ 1 );
474 memcpy( asciibuf
, CFDataGetBytePtr( flavorData
), flavorDataSize
);
475 CFRelease (flavorData
);
477 SetData( wxDF_TEXT
, flavorDataSize
, asciibuf
);
482 CFRelease (flavorData
);
486 CFRelease( flavorTypeArray
);
488 if (filenamesPassed
.length() > 0)
490 wxCharBuffer buf
= filenamesPassed
.fn_str();
491 SetData( wxDF_FILENAME
, strlen( buf
), (const char*)buf
);
499 bool wxDataObject::HasDataInPasteboard( void * pb
)
501 PasteboardRef pasteboard
= (PasteboardRef
) pb
;
502 size_t formatcount
= GetFormatCount() + 1;
503 wxDataFormat
*array
= new wxDataFormat
[ formatcount
];
504 array
[0] = GetPreferredFormat();
505 GetAllFormats( &array
[1] );
506 ItemCount itemCount
= 0;
507 bool hasData
= false;
509 // we synchronize here once again, so we don't mind which flags get returned
510 PasteboardSynchronize( pasteboard
);
512 OSStatus err
= PasteboardGetItemCount( pasteboard
, &itemCount
);
515 for (size_t i
= 0; !hasData
&& i
< formatcount
; i
++)
517 // go through the data in our order of preference
518 wxDataFormat dataFormat
= array
[ i
];
520 for( UInt32 itemIndex
= 1; itemIndex
<= itemCount
&& hasData
== false ; itemIndex
++ )
522 PasteboardItemID itemID
= 0;
523 CFArrayRef flavorTypeArray
= NULL
;
524 CFIndex flavorCount
= 0;
526 err
= PasteboardGetItemIdentifier( pasteboard
, itemIndex
, &itemID
);
530 err
= PasteboardCopyItemFlavors( pasteboard
, itemID
, &flavorTypeArray
);
534 flavorCount
= CFArrayGetCount( flavorTypeArray
);
536 for( CFIndex flavorIndex
= 0; !hasData
&& flavorIndex
< flavorCount
; flavorIndex
++ )
538 CFStringRef flavorType
;
540 flavorType
= (CFStringRef
)CFArrayGetValueAtIndex( flavorTypeArray
,
543 wxDataFormat
flavorFormat( (wxDataFormat::NativeFormat
) flavorType
);
545 if ( dataFormat
== flavorFormat
||
546 dataFormat
.GetType() == wxDF_UNICODETEXT
&& flavorFormat
.GetType() == wxDF_TEXT
)
551 CFRelease( flavorTypeArray
);
558 // ----------------------------------------------------------------------------
560 // ----------------------------------------------------------------------------
563 void wxTextDataObject::GetAllFormats(wxDataFormat
*formats
,
564 wxDataObjectBase::Direction
WXUNUSED(dir
)) const
566 *formats
++ = wxDataFormat( wxDF_TEXT
);
567 *formats
= wxDataFormat( wxDF_UNICODETEXT
);
571 // ----------------------------------------------------------------------------
573 // ----------------------------------------------------------------------------
575 void wxFileDataObject::GetFileNames( wxCharBuffer
&buf
) const
579 for (size_t i
= 0; i
< m_filenames
.GetCount(); i
++)
581 filenames
+= m_filenames
[i
];
582 filenames
+= wxT('\n');
585 buf
= filenames
.fn_str();
588 bool wxFileDataObject::GetDataHere( void *pBuf
) const
597 buffLength
= strlen( buf
);
598 memcpy( pBuf
, (const char*)buf
, buffLength
+ 1 );
603 size_t wxFileDataObject::GetDataSize() const
609 buffLength
= strlen( buf
);
611 return buffLength
+ 1;
614 bool wxFileDataObject::SetData( size_t WXUNUSED(nSize
), const void *pBuf
)
619 filenames
= wxString( (const char*)pBuf
, *wxConvFileName
);
621 filenames
= wxString (wxConvLocal
.cWC2WX(wxConvFileName
->cMB2WC( (const char*)pBuf
)));
624 m_filenames
= wxStringTokenize( filenames
, wxT("\n"), wxTOKEN_STRTOK
);
629 void wxFileDataObject::AddFile( const wxString
& rFilename
)
631 m_filenames
.Add( rFilename
);
634 // ----------------------------------------------------------------------------
635 // wxBitmapDataObject
636 // ----------------------------------------------------------------------------
638 wxBitmapDataObject::wxBitmapDataObject()
643 wxBitmapDataObject::wxBitmapDataObject( const wxBitmap
& rBitmap
)
644 : wxBitmapDataObjectBase( rBitmap
)
650 #if wxMAC_USE_CORE_GRAPHICS
651 SetBitmap( rBitmap
);
653 m_pictHandle
= m_bitmap
.GetBitmapData()->GetPictHandle();
654 m_pictCreated
= false;
659 wxBitmapDataObject::~wxBitmapDataObject()
664 void wxBitmapDataObject::SetBitmap( const wxBitmap
& rBitmap
)
667 wxBitmapDataObjectBase::SetBitmap( rBitmap
);
670 #if wxMAC_USE_CORE_GRAPHICS
671 CGImageRef cgImageRef
= (CGImageRef
) m_bitmap
.CGImageCreate();
672 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
673 if ( UMAGetSystemVersion() >= 0x1040 )
675 CFMutableDataRef data
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
676 CGImageDestinationRef destination
= CGImageDestinationCreateWithData( data
, kUTTypeTIFF
, 1 , NULL
);
679 CGImageDestinationAddImage( destination
, cgImageRef
, NULL
);
680 CGImageDestinationFinalize( destination
);
681 CFRelease( destination
);
683 m_pictHandle
= NewHandle(CFDataGetLength(data
));
686 memcpy( *(Handle
)m_pictHandle
, (const char *)CFDataGetBytePtr(data
), CFDataGetLength(data
) );
695 GraphicsExportComponent exporter
= 0;
696 OSStatus err
= OpenADefaultComponent(GraphicsExporterComponentType
, kQTFileTypeTIFF
, &exporter
);
699 m_pictHandle
= NewHandle(0);
702 err
= GraphicsExportSetInputCGImage( exporter
, cgImageRef
);
703 err
= GraphicsExportSetOutputHandle(exporter
, (Handle
)m_pictHandle
);
704 err
= GraphicsExportDoExport(exporter
, NULL
);
706 CloseComponent( exporter
);
710 CGImageRelease(cgImageRef
);
712 m_pictHandle
= m_bitmap
.GetBitmapData()->GetPictHandle();
713 m_pictCreated
= false;
718 void wxBitmapDataObject::Init()
721 m_pictCreated
= false;
724 void wxBitmapDataObject::Clear()
726 if (m_pictHandle
!= NULL
)
728 #if wxMAC_USE_CORE_GRAPHICS
729 DisposeHandle( (Handle
) m_pictHandle
);
732 KillPicture( (PicHandle
)m_pictHandle
);
736 m_pictCreated
= false;
739 bool wxBitmapDataObject::GetDataHere( void *pBuf
) const
741 if (m_pictHandle
== NULL
)
743 wxFAIL_MSG( wxT("attempt to copy empty bitmap failed") );
750 memcpy( pBuf
, *(Handle
)m_pictHandle
, GetHandleSize( (Handle
)m_pictHandle
) );
755 size_t wxBitmapDataObject::GetDataSize() const
757 if (m_pictHandle
!= NULL
)
758 return GetHandleSize( (Handle
)m_pictHandle
);
763 Handle
MacCreateDataReferenceHandle(Handle theDataHandle
)
765 Handle dataRef
= NULL
;
768 // Create a data reference handle for our data.
769 err
= PtrToHand( &theDataHandle
, &dataRef
, sizeof(Handle
));
774 bool wxBitmapDataObject::SetData( size_t nSize
, const void *pBuf
)
778 if ((pBuf
== NULL
) || (nSize
== 0))
781 #if wxMAC_USE_CORE_GRAPHICS
782 Handle picHandle
= NewHandle( nSize
);
783 memcpy( *picHandle
, pBuf
, nSize
);
784 m_pictHandle
= picHandle
;
785 CGImageRef cgImageRef
= 0;
786 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
787 if ( UMAGetSystemVersion() >= 0x1040 )
789 CFDataRef data
= CFDataCreateWithBytesNoCopy( kCFAllocatorDefault
, (const UInt8
*) pBuf
, nSize
, kCFAllocatorNull
);
790 CGImageSourceRef source
= CGImageSourceCreateWithData( data
, NULL
);
793 cgImageRef
= CGImageSourceCreateImageAtIndex(source
, 0, NULL
);
803 GraphicsImportComponent importer
= 0;
804 OSStatus err
= OpenADefaultComponent(GraphicsImporterComponentType
, kQTFileTypeTIFF
, &importer
);
809 ComponentResult result
= GraphicsImportSetDataHandle(importer
, picHandle
);
810 if ( result
== noErr
)
813 GraphicsImportGetNaturalBounds( importer
, &frame
);
814 GraphicsImportCreateCGImage( importer
, &cgImageRef
, kGraphicsImportCreateCGImageUsingCurrentSettings
);
817 CloseComponent( importer
);
823 m_bitmap
.Create( CGImageGetWidth(cgImageRef
) , CGImageGetHeight(cgImageRef
) );
824 CGRect r
= CGRectMake( 0 , 0 , CGImageGetWidth(cgImageRef
) , CGImageGetHeight(cgImageRef
) );
825 // since our context is upside down we dont use CGContextDrawImage
826 HIViewDrawCGImage( (CGContextRef
) m_bitmap
.GetHBITMAP() , &r
, cgImageRef
) ;
827 CGImageRelease(cgImageRef
);
831 PicHandle picHandle
= (PicHandle
)NewHandle( nSize
);
832 memcpy( *picHandle
, pBuf
, nSize
);
833 m_pictHandle
= picHandle
;
834 // ownership is transferred to the bitmap
835 m_pictCreated
= false;
838 wxMacGetPictureBounds( picHandle
, &frame
);
841 mf
.SetHMETAFILE( (WXHMETAFILE
)m_pictHandle
);
844 m_bitmap
.Create( frame
.right
- frame
.left
, frame
.bottom
- frame
.top
);
845 mdc
.SelectObject( m_bitmap
);
849 mdc
.SelectObject( wxNullBitmap
);
853 return m_bitmap
.Ok();