Files
wxWidgets/src/osx/carbon/dataobj.cpp
Stefan Csomor 1f0c8f31f4 fixing file paths after renaming
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@54129 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2008-06-11 19:30:52 +00:00

754 lines
24 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Name: src/mac/carbon/dataobj.cpp
// Purpose: implementation of wxDataObject class
// Author: Stefan Csomor
// Modified by:
// Created: 10/21/99
// RCS-ID: $Id$
// Copyright: (c) 1999 Stefan Csomor
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#if wxUSE_DATAOBJ
#include "wx/dataobj.h"
#ifndef WX_PRECOMP
#include "wx/intl.h"
#include "wx/log.h"
#include "wx/dcmemory.h"
#include "wx/image.h"
#endif
#include "wx/mstream.h"
#include "wx/metafile.h"
#include "wx/tokenzr.h"
#include "wx/osx/uma.h"
#ifdef __DARWIN__
#include <QuickTime/QuickTime.h>
#endif
// ----------------------------------------------------------------------------
// wxDataFormat
// ----------------------------------------------------------------------------
wxDataFormat::wxDataFormat()
{
m_type = wxDF_INVALID;
m_format = 0;
}
wxDataFormat::wxDataFormat( wxDataFormatId vType )
{
m_format = 0;
m_type = wxDF_INVALID;
SetType( vType );
}
wxDataFormat::wxDataFormat( const wxChar *zId )
{
m_format = 0;
m_type = wxDF_INVALID;
SetId( zId );
}
wxDataFormat::wxDataFormat( const wxString& rId )
{
m_format = 0;
m_type = wxDF_INVALID;
SetId( rId );
}
wxDataFormat::wxDataFormat(const wxDataFormat& rFormat)
{
if ( rFormat.m_format )
m_format = (NativeFormat) CFStringCreateCopy(NULL, (CFStringRef)rFormat.m_format);
else
m_format = 0;
m_type = rFormat.m_type;
m_id = rFormat.m_id;
}
wxDataFormat::wxDataFormat( NativeFormat vFormat )
{
m_format = 0;
m_type = wxDF_INVALID;
SetId( vFormat );
}
wxDataFormat::~wxDataFormat()
{
if ( m_format != 0 )
{
CFRelease( (CFStringRef) m_format );
m_format = 0;
}
}
// in order to be correct for 10.3 we restrict to the available types there
// http://developer.apple.com/qa/qa2005/qa1406.html
// TODO : Use UTCoreTypes.h constants once we support 10.4+ only
wxDataFormat& wxDataFormat::operator=(const wxDataFormat& rFormat)
{
if ( m_format != 0 )
{
CFRelease( (CFStringRef) m_format );
m_format = 0;
}
if ( rFormat.m_format )
m_format = (NativeFormat) CFStringCreateCopy(NULL, (CFStringRef)rFormat.m_format);
m_type = rFormat.m_type;
m_id = rFormat.m_id;
return *this;
}
void wxDataFormat::SetType( wxDataFormatId dataType )
{
m_type = dataType;
if ( m_format != 0 )
{
CFRelease( (CFStringRef) m_format );
m_format = 0;
}
switch (m_type)
{
case wxDF_TEXT:
m_format = (long) CFStringCreateCopy( NULL, CFSTR("public.plain-text") );
break;
case wxDF_UNICODETEXT:
m_format = (long) CFStringCreateCopy( NULL, CFSTR("public.utf16-plain-text") );
break;
case wxDF_BITMAP:
m_format = (long) CFStringCreateCopy( NULL, CFSTR("public.tiff") );
break;
case wxDF_METAFILE:
m_format = (long) CFStringCreateCopy( NULL, CFSTR("com.adobe.pdf") );
break;
case wxDF_FILENAME:
m_format = (long) CFStringCreateCopy( NULL, CFSTR("public.file-url") );
break;
default:
wxFAIL_MSG( wxT("invalid data format") );
break;
}
}
wxString wxDataFormat::GetId() const
{
return wxCFStringRef(wxCFRetain((CFStringRef)m_format)).AsString();
}
void wxDataFormat::SetId( NativeFormat format )
{
if ( m_format != 0 )
{
CFRelease( (CFStringRef) m_format );
m_format = 0;
}
m_format = (NativeFormat) CFStringCreateCopy(NULL, (CFStringRef)format);
if ( UTTypeConformsTo( (CFStringRef)format, CFSTR("public.utf16-plain-text") ) )
{
m_type = wxDF_UNICODETEXT;
}
else if ( UTTypeConformsTo( (CFStringRef)format, CFSTR("public.plain-text") ) )
{
m_type = wxDF_TEXT;
}
else if ( UTTypeConformsTo( (CFStringRef)format, CFSTR("public.tiff") ) )
{
m_type = wxDF_BITMAP;
}
else if ( UTTypeConformsTo( (CFStringRef)format, CFSTR("com.adobe.pdf") ) )
{
m_type = wxDF_METAFILE;
}
else if ( UTTypeConformsTo( (CFStringRef)format, CFSTR("public.file-url") ) )
{
m_type = wxDF_FILENAME;
}
else
{
m_type = wxDF_PRIVATE;
m_id = wxCFStringRef( (CFStringRef) CFRetain((CFStringRef) format )).AsString();
}
}
void wxDataFormat::SetId( const wxString& zId )
{
m_type = wxDF_PRIVATE;
m_id = zId;
if ( m_format != 0 )
{
CFRelease( (CFStringRef) m_format );
m_format = 0;
}
// since it is private, no need to conform to anything ...
m_format = (long) wxCFRetain( (CFStringRef) wxCFStringRef(m_id) );
}
bool wxDataFormat::operator==(const wxDataFormat& format) const
{
if (IsStandard() || format.IsStandard())
return (format.m_type == m_type);
else
return ( UTTypeConformsTo( (CFStringRef) m_format , (CFStringRef) format.m_format ) );
}
//-------------------------------------------------------------------------
// wxDataObject
//-------------------------------------------------------------------------
wxDataObject::wxDataObject()
{
}
bool wxDataObject::IsSupportedFormat( const wxDataFormat& rFormat, Direction vDir ) const
{
size_t nFormatCount = GetFormatCount( vDir );
bool found = false;
if (nFormatCount == 1)
{
found = (rFormat == GetPreferredFormat());
}
else
{
wxDataFormat *pFormats = new wxDataFormat[nFormatCount];
GetAllFormats( pFormats, vDir );
for (size_t n = 0; n < nFormatCount; n++)
{
if (pFormats[n] == rFormat)
{
found = true;
break;
}
}
delete [] pFormats;
}
return found;
}
void wxDataObject::AddToPasteboard( void * pb, int itemID )
{
PasteboardRef pasteboard = (PasteboardRef) pb;
// get formats from wxDataObjects
wxDataFormat *array = new wxDataFormat[ GetFormatCount() ];
GetAllFormats( array );
for (size_t i = 0; i < GetFormatCount(); i++)
{
wxDataFormat thisFormat = array[ i ];
// add four bytes at the end for data objs like text that
// have a datasize = strlen but still need a buffer for the
// string including trailing zero
size_t datasize = GetDataSize( thisFormat );
size_t sz = datasize + 4;
void* buf = malloc( sz );
if ( buf != NULL )
{
// empty the buffer because in some case GetDataHere does not fill buf
memset( buf, 0, sz );
if ( GetDataHere( array[ i ], buf ) )
{
int counter = 1 ;
if ( thisFormat.GetType() == wxDF_FILENAME )
{
// the data is D-normalized UTF8 strings of filenames delimited with \n
char *fname = strtok((char*) buf,"\n");
while (fname != NULL)
{
// translate the filepath into a fileurl and put that into the pasteobard
CFStringRef path = CFStringCreateWithBytes(NULL,(UInt8*)fname,strlen(fname),kCFStringEncodingUTF8,false);
CFURLRef url = CFURLCreateWithFileSystemPath(NULL, path , kCFURLPOSIXPathStyle, false);
CFRelease(path);
CFDataRef data = CFURLCreateData(NULL,url,kCFStringEncodingUTF8,true);
CFRelease(url);
PasteboardPutItemFlavor( pasteboard, (PasteboardItemID) counter,
(CFStringRef) thisFormat.GetFormatId() , data, kPasteboardFlavorNoFlags);
CFRelease( data );
counter++;
fname = strtok (NULL,"\n");
}
}
else
{
CFDataRef data = CFDataCreate( kCFAllocatorDefault, (UInt8*)buf, datasize );
if ( thisFormat.GetType() == wxDF_TEXT )
PasteboardPutItemFlavor( pasteboard, (PasteboardItemID) itemID,
CFSTR("com.apple.traditional-mac-plain-text") , data, kPasteboardFlavorNoFlags);
else
PasteboardPutItemFlavor( pasteboard, (PasteboardItemID) itemID,
(CFStringRef) thisFormat.GetFormatId() , data, kPasteboardFlavorNoFlags);
CFRelease( data );
}
}
free( buf );
}
}
delete [] array;
}
bool wxDataObject::IsFormatInPasteboard( void * pb, const wxDataFormat &dataFormat )
{
PasteboardRef pasteboard = (PasteboardRef) pb;
bool hasData = false;
OSStatus err = noErr;
ItemCount itemCount;
// we synchronize here once again, so we don't mind which flags get returned
PasteboardSynchronize( pasteboard );
err = PasteboardGetItemCount( pasteboard, &itemCount );
if ( err == noErr )
{
for( UInt32 itemIndex = 1; itemIndex <= itemCount && hasData == false ; itemIndex++ )
{
PasteboardItemID itemID;
CFArrayRef flavorTypeArray;
CFIndex flavorCount;
err = PasteboardGetItemIdentifier( pasteboard, itemIndex, &itemID );
if ( err != noErr )
continue;
err = PasteboardCopyItemFlavors( pasteboard, itemID, &flavorTypeArray );
if ( err != noErr )
continue;
flavorCount = CFArrayGetCount( flavorTypeArray );
for( CFIndex flavorIndex = 0; flavorIndex < flavorCount && hasData == false ; flavorIndex++ )
{
CFStringRef flavorType;
flavorType = (CFStringRef)CFArrayGetValueAtIndex( flavorTypeArray,
flavorIndex );
wxDataFormat flavorFormat( (wxDataFormat::NativeFormat) flavorType );
if ( dataFormat == flavorFormat )
hasData = true;
else if ( dataFormat.GetType() == wxDF_UNICODETEXT && flavorFormat.GetType() == wxDF_TEXT )
hasData = true;
}
CFRelease (flavorTypeArray);
}
}
return hasData;
}
bool wxDataObject::GetFromPasteboard( void * pb )
{
PasteboardRef pasteboard = (PasteboardRef) pb;
size_t formatcount = GetFormatCount() + 1;
wxDataFormat *array = new wxDataFormat[ formatcount ];
array[0] = GetPreferredFormat();
GetAllFormats( &array[1] );
ItemCount itemCount = 0;
wxString filenamesPassed;
bool transferred = false;
// we synchronize here once again, so we don't mind which flags get returned
PasteboardSynchronize( pasteboard );
OSStatus err = PasteboardGetItemCount( pasteboard, &itemCount );
if ( err == noErr )
{
for (size_t i = 0; !transferred && i < formatcount; i++)
{
// go through the data in our order of preference
wxDataFormat dataFormat = array[ i ];
for( UInt32 itemIndex = 1; itemIndex <= itemCount && transferred == false ; itemIndex++ )
{
PasteboardItemID itemID = 0;
CFArrayRef flavorTypeArray = NULL;
CFIndex flavorCount = 0;
err = PasteboardGetItemIdentifier( pasteboard, itemIndex, &itemID );
if ( err != noErr )
continue;
err = PasteboardCopyItemFlavors( pasteboard, itemID, &flavorTypeArray );
if ( err != noErr )
continue;
flavorCount = CFArrayGetCount( flavorTypeArray );
for( CFIndex flavorIndex = 0; !transferred && flavorIndex < flavorCount ; flavorIndex++ )
{
CFStringRef flavorType;
CFDataRef flavorData;
CFIndex flavorDataSize;
flavorType = (CFStringRef)CFArrayGetValueAtIndex( flavorTypeArray,
flavorIndex );
wxDataFormat flavorFormat( (wxDataFormat::NativeFormat) flavorType );
if ( dataFormat == flavorFormat )
{
err = PasteboardCopyItemFlavorData( pasteboard, itemID, flavorType , &flavorData );
if ( err == noErr )
{
flavorDataSize = CFDataGetLength( flavorData );
if (dataFormat.GetType() == wxDF_FILENAME )
{
// revert the translation and decomposition to arrive at a proper utf8 string again
CFURLRef url = CFURLCreateWithBytes( kCFAllocatorDefault, CFDataGetBytePtr( flavorData ), flavorDataSize, kCFStringEncodingUTF8, NULL );
CFStringRef cfString = CFURLCopyFileSystemPath( url, kCFURLPOSIXPathStyle );
CFRelease( url );
CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, cfString);
CFRelease( cfString );
CFStringNormalize(cfMutableString,kCFStringNormalizationFormC);
wxString path = wxCFStringRef(cfMutableString).AsString();
if (!path.empty())
filenamesPassed += path + wxT("\n");
}
else
{
// because some data implementation expect trailing a trailing NUL, we add some headroom
void *buf = malloc( flavorDataSize + 4 );
if ( buf )
{
memset( buf, 0, flavorDataSize + 4 );
memcpy( buf, CFDataGetBytePtr( flavorData ), flavorDataSize );
if (dataFormat.GetType() == wxDF_TEXT)
wxMacConvertNewlines10To13( (char*) buf );
SetData( flavorFormat, flavorDataSize, buf );
transferred = true;
free( buf );
}
}
CFRelease (flavorData);
}
}
else if ( dataFormat.GetType() == wxDF_UNICODETEXT && flavorFormat.GetType() == wxDF_TEXT )
{
err = PasteboardCopyItemFlavorData( pasteboard, itemID, flavorType, &flavorData );
if ( err == noErr )
{
flavorDataSize = CFDataGetLength( flavorData );
void *asciibuf = malloc( flavorDataSize + 1 );
if ( asciibuf )
{
memset( asciibuf, 0, flavorDataSize + 1 );
memcpy( asciibuf, CFDataGetBytePtr( flavorData ), flavorDataSize );
CFRelease (flavorData);
SetData( wxDF_TEXT, flavorDataSize, asciibuf );
transferred = true;
free( asciibuf );
}
else
CFRelease (flavorData);
}
}
}
CFRelease( flavorTypeArray );
}
if (filenamesPassed.length() > 0)
{
wxCharBuffer buf = filenamesPassed.fn_str();
SetData( wxDF_FILENAME, strlen( buf ), (const char*)buf );
transferred = true;
}
}
}
return transferred;
}
bool wxDataObject::HasDataInPasteboard( void * pb )
{
PasteboardRef pasteboard = (PasteboardRef) pb;
size_t formatcount = GetFormatCount() + 1;
wxDataFormat *array = new wxDataFormat[ formatcount ];
array[0] = GetPreferredFormat();
GetAllFormats( &array[1] );
ItemCount itemCount = 0;
bool hasData = false;
// we synchronize here once again, so we don't mind which flags get returned
PasteboardSynchronize( pasteboard );
OSStatus err = PasteboardGetItemCount( pasteboard, &itemCount );
if ( err == noErr )
{
for (size_t i = 0; !hasData && i < formatcount; i++)
{
// go through the data in our order of preference
wxDataFormat dataFormat = array[ i ];
for( UInt32 itemIndex = 1; itemIndex <= itemCount && hasData == false ; itemIndex++ )
{
PasteboardItemID itemID = 0;
CFArrayRef flavorTypeArray = NULL;
CFIndex flavorCount = 0;
err = PasteboardGetItemIdentifier( pasteboard, itemIndex, &itemID );
if ( err != noErr )
continue;
err = PasteboardCopyItemFlavors( pasteboard, itemID, &flavorTypeArray );
if ( err != noErr )
continue;
flavorCount = CFArrayGetCount( flavorTypeArray );
for( CFIndex flavorIndex = 0; !hasData && flavorIndex < flavorCount ; flavorIndex++ )
{
CFStringRef flavorType;
flavorType = (CFStringRef)CFArrayGetValueAtIndex( flavorTypeArray,
flavorIndex );
wxDataFormat flavorFormat( (wxDataFormat::NativeFormat) flavorType );
if ( dataFormat == flavorFormat ||
dataFormat.GetType() == wxDF_UNICODETEXT && flavorFormat.GetType() == wxDF_TEXT )
{
hasData = true;
}
}
CFRelease( flavorTypeArray );
}
}
}
return hasData;
}
// ----------------------------------------------------------------------------
// wxTextDataObject
// ----------------------------------------------------------------------------
#if wxUSE_UNICODE
void wxTextDataObject::GetAllFormats(wxDataFormat *formats,
wxDataObjectBase::Direction WXUNUSED(dir)) const
{
*formats++ = wxDataFormat( wxDF_TEXT );
*formats = wxDataFormat( wxDF_UNICODETEXT );
}
#endif
// ----------------------------------------------------------------------------
// wxFileDataObject
// ----------------------------------------------------------------------------
void wxFileDataObject::GetFileNames( wxCharBuffer &buf ) const
{
wxString filenames;
for (size_t i = 0; i < m_filenames.GetCount(); i++)
{
filenames += m_filenames[i];
filenames += wxT('\n');
}
buf = filenames.fn_str();
}
bool wxFileDataObject::GetDataHere( void *pBuf ) const
{
if (pBuf == NULL)
return false;
wxCharBuffer buf;
size_t buffLength;
GetFileNames( buf );
buffLength = strlen( buf );
memcpy( pBuf, (const char*)buf, buffLength + 1 );
return true;
}
size_t wxFileDataObject::GetDataSize() const
{
wxCharBuffer buf;
size_t buffLength;
GetFileNames( buf );
buffLength = strlen( buf );
// terminating 0
return buffLength + 1;
}
bool wxFileDataObject::SetData( size_t WXUNUSED(nSize), const void *pBuf )
{
wxString filenames;
#if wxUSE_UNICODE
filenames = wxString( (const char*)pBuf, *wxConvFileName );
#else
filenames = wxString (wxConvLocal.cWC2WX(wxConvFileName->cMB2WC( (const char*)pBuf)));
#endif
m_filenames = wxStringTokenize( filenames, wxT("\n"), wxTOKEN_STRTOK );
return true;
}
void wxFileDataObject::AddFile( const wxString& rFilename )
{
m_filenames.Add( rFilename );
}
// ----------------------------------------------------------------------------
// wxBitmapDataObject
// ----------------------------------------------------------------------------
wxBitmapDataObject::wxBitmapDataObject()
{
Init();
}
wxBitmapDataObject::wxBitmapDataObject( const wxBitmap& rBitmap )
: wxBitmapDataObjectBase( rBitmap )
{
Init();
if (m_bitmap.Ok())
{
SetBitmap( rBitmap );
}
}
wxBitmapDataObject::~wxBitmapDataObject()
{
Clear();
}
void wxBitmapDataObject::SetBitmap( const wxBitmap& rBitmap )
{
Clear();
wxBitmapDataObjectBase::SetBitmap( rBitmap );
if (m_bitmap.Ok())
{
CGImageRef cgImageRef = (CGImageRef) m_bitmap.CreateCGImage();
CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0);
CGImageDestinationRef destination = CGImageDestinationCreateWithData( data , kUTTypeTIFF , 1 , NULL );
if ( destination )
{
CGImageDestinationAddImage( destination, cgImageRef, NULL );
CGImageDestinationFinalize( destination );
CFRelease( destination );
}
m_pictHandle = NewHandle(CFDataGetLength(data));
if ( m_pictHandle )
{
memcpy( *(Handle)m_pictHandle, (const char *)CFDataGetBytePtr(data), CFDataGetLength(data) );
}
CFRelease( data );
CGImageRelease(cgImageRef);
}
}
void wxBitmapDataObject::Init()
{
m_pictHandle = NULL;
m_pictCreated = false;
}
void wxBitmapDataObject::Clear()
{
if (m_pictHandle != NULL)
{
DisposeHandle( (Handle) m_pictHandle );
m_pictHandle = NULL;
}
m_pictCreated = false;
}
bool wxBitmapDataObject::GetDataHere( void *pBuf ) const
{
if (m_pictHandle == NULL)
{
wxFAIL_MSG( wxT("attempt to copy empty bitmap failed") );
return false;
}
if (pBuf == NULL)
return false;
memcpy( pBuf, *(Handle)m_pictHandle, GetHandleSize( (Handle)m_pictHandle ) );
return true;
}
size_t wxBitmapDataObject::GetDataSize() const
{
if (m_pictHandle != NULL)
return GetHandleSize( (Handle)m_pictHandle );
else
return 0;
}
Handle MacCreateDataReferenceHandle(Handle theDataHandle)
{
Handle dataRef = NULL;
OSErr err = noErr;
// Create a data reference handle for our data.
err = PtrToHand( &theDataHandle, &dataRef, sizeof(Handle));
return dataRef;
}
bool wxBitmapDataObject::SetData( size_t nSize, const void *pBuf )
{
Clear();
if ((pBuf == NULL) || (nSize == 0))
return false;
Handle picHandle = NewHandle( nSize );
memcpy( *picHandle, pBuf, nSize );
m_pictHandle = picHandle;
CGImageRef cgImageRef = 0;
CFDataRef data = CFDataCreateWithBytesNoCopy( kCFAllocatorDefault, (const UInt8*) pBuf, nSize, kCFAllocatorNull);
CGImageSourceRef source = CGImageSourceCreateWithData( data, NULL );
if ( source )
{
cgImageRef = CGImageSourceCreateImageAtIndex(source, 0, NULL);
}
CFRelease( source );
CFRelease( data );
if ( cgImageRef )
{
m_bitmap.Create( CGImageGetWidth(cgImageRef) , CGImageGetHeight(cgImageRef) );
CGRect r = CGRectMake( 0 , 0 , CGImageGetWidth(cgImageRef) , CGImageGetHeight(cgImageRef) );
// since our context is upside down we dont use CGContextDrawImage
wxMacDrawCGImage( (CGContextRef) m_bitmap.GetHBITMAP() , &r, cgImageRef ) ;
CGImageRelease(cgImageRef);
cgImageRef = NULL;
}
return m_bitmap.Ok();
}
#endif