1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/common/dobjcmn.cpp 
   3 // Purpose:     implementation of data object methods common to all platforms 
   4 // Author:      Vadim Zeitlin, Robert Roebling 
   8 // Copyright:   (c) wxWidgets Team 
   9 // Licence:     wxWindows licence 
  10 /////////////////////////////////////////////////////////////////////////////// 
  12 // For compilers that support precompilation, includes "wx.h". 
  13 #include "wx/wxprec.h" 
  21 #include "wx/dataobj.h" 
  27 // ---------------------------------------------------------------------------- 
  29 // ---------------------------------------------------------------------------- 
  31 #include "wx/listimpl.cpp" 
  33 WX_DEFINE_LIST(wxSimpleDataObjectList
) 
  35 // ---------------------------------------------------------------------------- 
  37 // ---------------------------------------------------------------------------- 
  39 static wxDataFormat dataFormatInvalid
; 
  40 WXDLLEXPORT 
const wxDataFormat
& wxFormatInvalid 
= dataFormatInvalid
; 
  42 // ============================================================================ 
  44 // ============================================================================ 
  46 // ---------------------------------------------------------------------------- 
  48 // ---------------------------------------------------------------------------- 
  50 wxDataObjectBase::~wxDataObjectBase() 
  54 bool wxDataObjectBase::IsSupported(const wxDataFormat
& format
, 
  57     size_t nFormatCount 
= GetFormatCount( dir 
); 
  58     if ( nFormatCount 
== 1 ) 
  60         return format 
== GetPreferredFormat( dir 
); 
  64         wxDataFormat 
*formats 
= new wxDataFormat
[nFormatCount
]; 
  65         GetAllFormats( formats
, dir 
); 
  68         for ( n 
= 0; n 
< nFormatCount
; n
++ ) 
  70             if ( formats
[n
] == format 
) 
  77         return n 
< nFormatCount
; 
  81 // ---------------------------------------------------------------------------- 
  82 // wxDataObjectComposite 
  83 // ---------------------------------------------------------------------------- 
  85 wxDataObjectComposite::wxDataObjectComposite() 
  88     m_receivedFormat 
= wxFormatInvalid
; 
  91 wxDataObjectComposite::~wxDataObjectComposite() 
  93     WX_CLEAR_LIST( wxSimpleDataObjectList
, m_dataObjects 
); 
  97 wxDataObjectComposite::GetObject(const wxDataFormat
& format
, wxDataObjectBase::Direction dir
) const 
  99     wxSimpleDataObjectList::compatibility_iterator node 
= m_dataObjects
.GetFirst(); 
 103         wxDataObjectSimple 
*dataObj 
= node
->GetData(); 
 105         if (dataObj
->IsSupported(format
,dir
)) 
 107         node 
= node
->GetNext(); 
 112 void wxDataObjectComposite::Add(wxDataObjectSimple 
*dataObject
, bool preferred
) 
 114    // check if the data format of the passed object already exists in the composite data object, if this is the case 
 115    // do not add the data object and display a message in debug mode (otherwise this method fails silently): 
 116    // start checking if the data format exists for the 'GET' direction: 
 119     wxDataFormat
* formats
; 
 121     noOfFormats 
= dataObject
->GetFormatCount(wxDataObjectBase::Get
); 
 122     formats 
= new wxDataFormat
[noOfFormats
]; 
 123     for (indexFormats
=0; indexFormats
<noOfFormats
; ++indexFormats
) 
 124       wxCHECK_RET(this->GetObject(formats
[indexFormats
],wxDataObjectBase::Get
) == NULL
, 
 125                   _("The data format for the GET-direction of the to be added data object already exists")); 
 127    // do the same with the 'SET' direction: 
 128     noOfFormats 
= dataObject
->GetFormatCount(wxDataObjectBase::Set
); 
 130     formats 
= new wxDataFormat
[noOfFormats
]; 
 131     for (indexFormats
=0; indexFormats
<noOfFormats
; ++indexFormats
) 
 132       wxCHECK_RET(this->GetObject(formats
[indexFormats
],wxDataObjectBase::Set
) == NULL
, 
 133                   _("The data format for the SET-direction of the to be added data object already exists")); 
 136    // if we reach this location the data object can simply be appended: 
 138         m_preferred 
= m_dataObjects
.GetCount(); 
 139     m_dataObjects
.Append( dataObject 
); 
 142 wxDataFormat 
wxDataObjectComposite::GetReceivedFormat() const 
 144     return m_receivedFormat
; 
 148 wxDataObjectComposite::GetPreferredFormat(Direction 
WXUNUSED(dir
)) const 
 150     wxSimpleDataObjectList::compatibility_iterator node 
= m_dataObjects
.Item( m_preferred 
); 
 152     wxCHECK_MSG( node
, wxFormatInvalid
, wxT("no preferred format") ); 
 154     wxDataObjectSimple
* dataObj 
= node
->GetData(); 
 156     return dataObj
->GetFormat(); 
 159 #if defined(__WXMSW__) 
 161 size_t wxDataObjectComposite::GetBufferOffset( const wxDataFormat
& format 
) 
 163     wxDataObjectSimple 
*dataObj 
= GetObject(format
); 
 165     wxCHECK_MSG( dataObj
, 0, 
 166                  wxT("unsupported format in wxDataObjectComposite")); 
 168     return dataObj
->GetBufferOffset( format 
); 
 172 const void* wxDataObjectComposite::GetSizeFromBuffer( const void* buffer
, 
 174                                                       const wxDataFormat
& format 
) 
 176     wxDataObjectSimple 
*dataObj 
= GetObject(format
); 
 178     wxCHECK_MSG( dataObj
, NULL
, 
 179                  wxT("unsupported format in wxDataObjectComposite")); 
 181     return dataObj
->GetSizeFromBuffer( buffer
, size
, format 
); 
 185 void* wxDataObjectComposite::SetSizeInBuffer( void* buffer
, size_t size
, 
 186                                               const wxDataFormat
& format 
) 
 188     wxDataObjectSimple 
*dataObj 
= GetObject( format 
); 
 190     wxCHECK_MSG( dataObj
, NULL
, 
 191                  wxT("unsupported format in wxDataObjectComposite")); 
 193     return dataObj
->SetSizeInBuffer( buffer
, size
, format 
); 
 198 size_t wxDataObjectComposite::GetFormatCount(Direction dir
) const 
 202     // NOTE: some wxDataObjectSimple objects may return a number greater than 1 
 203     //       from GetFormatCount(): this is the case of e.g. wxTextDataObject 
 204     //       under wxMac and wxGTK 
 205     wxSimpleDataObjectList::compatibility_iterator node
; 
 206     for ( node 
= m_dataObjects
.GetFirst(); node
; node 
= node
->GetNext() ) 
 207         n 
+= node
->GetData()->GetFormatCount(dir
); 
 212 void wxDataObjectComposite::GetAllFormats(wxDataFormat 
*formats
, 
 216     wxSimpleDataObjectList::compatibility_iterator node
; 
 218     for ( node 
= m_dataObjects
.GetFirst(); node
; node 
= node
->GetNext() ) 
 220         // NOTE: some wxDataObjectSimple objects may return more than 1 format 
 221         //       from GetAllFormats(): this is the case of e.g. wxTextDataObject 
 222         //       under wxMac and wxGTK 
 223         node
->GetData()->GetAllFormats(formats
+index
, dir
); 
 224         index 
+= node
->GetData()->GetFormatCount(dir
); 
 228 size_t wxDataObjectComposite::GetDataSize(const wxDataFormat
& format
) const 
 230     wxDataObjectSimple 
*dataObj 
= GetObject(format
); 
 232     wxCHECK_MSG( dataObj
, 0, 
 233                  wxT("unsupported format in wxDataObjectComposite")); 
 235     return dataObj
->GetDataSize(); 
 238 bool wxDataObjectComposite::GetDataHere(const wxDataFormat
& format
, 
 241     wxDataObjectSimple 
*dataObj 
= GetObject( format 
); 
 243     wxCHECK_MSG( dataObj
, false, 
 244                  wxT("unsupported format in wxDataObjectComposite")); 
 246     return dataObj
->GetDataHere( buf 
); 
 249 bool wxDataObjectComposite::SetData(const wxDataFormat
& format
, 
 253     wxDataObjectSimple 
*dataObj 
= GetObject( format 
); 
 255     wxCHECK_MSG( dataObj
, false, 
 256                  wxT("unsupported format in wxDataObjectComposite")); 
 258     m_receivedFormat 
= format
; 
 259     return dataObj
->SetData( len
, buf 
); 
 262 // ---------------------------------------------------------------------------- 
 264 // ---------------------------------------------------------------------------- 
 266 #ifdef wxNEEDS_UTF8_FOR_TEXT_DATAOBJ 
 268 // FIXME-UTF8: we should be able to merge wchar_t and UTF-8 versions once we 
 269 //             have a way to get UTF-8 string (and its length) in both builds 
 270 //             without loss of efficiency (i.e. extra buffer copy/strlen call) 
 272 #if wxUSE_UNICODE_WCHAR 
 274 static inline wxMBConv
& GetConv(const wxDataFormat
& format
) 
 276     // use UTF8 for wxDF_UNICODETEXT and UCS4 for wxDF_TEXT 
 277     return format 
== wxDF_UNICODETEXT 
? wxConvUTF8 
: wxConvLibc
; 
 280 size_t wxTextDataObject::GetDataSize(const wxDataFormat
& format
) const 
 282     wxCharBuffer buffer 
= GetConv(format
).cWX2MB( GetText().c_str() ); 
 284     return buffer 
? strlen( buffer 
) : 0; 
 287 bool wxTextDataObject::GetDataHere(const wxDataFormat
& format
, void *buf
) const 
 292     wxCharBuffer buffer 
= GetConv(format
).cWX2MB( GetText().c_str() ); 
 296     memcpy( (char*) buf
, buffer
, GetDataSize(format
) ); 
 297     // strcpy( (char*) buf, buffer ); 
 302 bool wxTextDataObject::SetData(const wxDataFormat
& format
, 
 303                                size_t WXUNUSED(len
), const void *buf
) 
 308     wxWCharBuffer buffer 
= GetConv(format
).cMB2WX( (const char*)buf 
); 
 315 #else // wxUSE_UNICODE_UTF8 
 317 size_t wxTextDataObject::GetDataSize(const wxDataFormat
& format
) const 
 319     if ( format 
== wxDF_UNICODETEXT 
|| wxLocaleIsUtf8 
) 
 321         return m_text
.utf8_length(); 
 325         const wxCharBuffer 
buf(wxConvLocal
.cWC2MB(m_text
.wc_str())); 
 326         return buf 
? strlen(buf
) : 0; 
 330 bool wxTextDataObject::GetDataHere(const wxDataFormat
& format
, void *buf
) const 
 335     if ( format 
== wxDF_UNICODETEXT 
|| wxLocaleIsUtf8 
) 
 337         memcpy(buf
, m_text
.utf8_str(), m_text
.utf8_length()); 
 341         const wxCharBuffer 
bufLocal(wxConvLocal
.cWC2MB(m_text
.wc_str())); 
 345         memcpy(buf
, bufLocal
, strlen(bufLocal
)); 
 351 bool wxTextDataObject::SetData(const wxDataFormat
& format
, 
 352                                size_t len
, const void *buf_
) 
 354     const char * const buf 
= static_cast<const char *>(buf_
); 
 359     if ( format 
== wxDF_UNICODETEXT 
|| wxLocaleIsUtf8 
) 
 361         // normally the data is in UTF-8 so we could use FromUTF8Unchecked() 
 362         // but it's not absolutely clear what GTK+ does if the clipboard data 
 363         // is not in UTF-8 so do an extra check for tranquility, it shouldn't 
 364         // matter much if we lose a bit of performance when pasting from 
 366         m_text 
= wxString::FromUTF8(buf
, len
); 
 368     else // wxDF_TEXT, convert from current (non-UTF8) locale 
 370         m_text 
= wxConvLocal
.cMB2WC(buf
, len
, NULL
); 
 376 #endif // wxUSE_UNICODE_WCHAR/wxUSE_UNICODE_UTF8 
 378 #elif defined(wxNEEDS_UTF16_FOR_TEXT_DATAOBJ) 
 380 static wxMBConvUTF16 sUTF16Converter
; 
 382 static inline wxMBConv
& GetConv(const wxDataFormat
& format
) 
 385         format 
== wxDF_UNICODETEXT
 
 386         ? (wxMBConv
&) sUTF16Converter
 
 387         : (wxMBConv
&) wxConvLocal
; 
 390 size_t wxTextDataObject::GetDataSize(const wxDataFormat
& format
) const 
 392     size_t len 
= GetConv(format
).WC2MB( NULL
, GetText().c_str(), 0 ); 
 393     len 
+= (format 
== wxDF_UNICODETEXT 
? 2 : 1); 
 398 bool wxTextDataObject::GetDataHere(const wxDataFormat
& format
, void *buf
) const 
 403     wxCharBuffer buffer 
= GetConv(format
).cWX2MB( GetText().c_str() ); 
 405     size_t len 
= GetConv(format
).WC2MB( NULL
, GetText().c_str(), 0 ); 
 406     len 
+= (format 
== wxDF_UNICODETEXT 
? 2 : 1); 
 408     // trailing (uni)char 0 
 409     memcpy( (char*)buf
, (const char*)buffer
, len 
); 
 414 bool wxTextDataObject::SetData(const wxDataFormat
& format
, 
 415                                size_t WXUNUSED(len
), const void *buf
) 
 420     wxWCharBuffer buffer 
= GetConv(format
).cMB2WX( (const char*)buf 
); 
 427 #else // !wxNEEDS_UTF{8,16}_FOR_TEXT_DATAOBJ 
 429 size_t wxTextDataObject::GetDataSize() const 
 431     return GetTextLength() * sizeof(wxChar
); 
 434 bool wxTextDataObject::GetDataHere(void *buf
) const 
 436     // NOTE: use wxTmemcpy() instead of wxStrncpy() to allow 
 437     //       retrieval of strings with embedded NULLs 
 438     wxTmemcpy( (wxChar
*)buf
, GetText().c_str(), GetTextLength() ); 
 443 bool wxTextDataObject::SetData(size_t len
, const void *buf
) 
 445     SetText( wxString((const wxChar
*)buf
, len
/sizeof(wxChar
)) ); 
 450 #endif // different wxTextDataObject implementations 
 452 // ---------------------------------------------------------------------------- 
 453 // wxCustomDataObject 
 454 // ---------------------------------------------------------------------------- 
 456 wxCustomDataObject::wxCustomDataObject(const wxDataFormat
& format
) 
 457     : wxDataObjectSimple(format
) 
 463 wxCustomDataObject::~wxCustomDataObject() 
 468 void wxCustomDataObject::TakeData(size_t size
, void *data
) 
 476 void *wxCustomDataObject::Alloc(size_t size
) 
 478     return (void *)new char[size
]; 
 481 void wxCustomDataObject::Free() 
 483     delete [] (char*)m_data
; 
 488 size_t wxCustomDataObject::GetDataSize() const 
 493 bool wxCustomDataObject::GetDataHere(void *buf
) const 
 498     void *data 
= GetData(); 
 502     memcpy( buf
, data
, GetSize() ); 
 507 bool wxCustomDataObject::SetData(size_t size
, const void *buf
) 
 511     m_data 
= Alloc(size
); 
 512     if ( m_data 
== NULL 
) 
 516     memcpy( m_data
, buf
, m_size 
); 
 521 // ============================================================================ 
 522 // some common dnd related code 
 523 // ============================================================================ 
 525 #if wxUSE_DRAG_AND_DROP 
 529 // ---------------------------------------------------------------------------- 
 531 // ---------------------------------------------------------------------------- 
 533 // NB: we can't use "new" in ctor initializer lists because this provokes an 
 534 //     internal compiler error with VC++ 5.0 (hey, even gcc compiles this!), 
 535 //     so use SetDataObject() instead 
 537 wxTextDropTarget::wxTextDropTarget() 
 539     SetDataObject(new wxTextDataObject
); 
 542 wxDragResult 
wxTextDropTarget::OnData(wxCoord x
, wxCoord y
, wxDragResult def
) 
 547     wxTextDataObject 
*dobj 
= (wxTextDataObject 
*)m_dataObject
; 
 548     return OnDropText( x
, y
, dobj
->GetText() ) ? def 
: wxDragNone
; 
 551 // ---------------------------------------------------------------------------- 
 553 // ---------------------------------------------------------------------------- 
 555 wxFileDropTarget::wxFileDropTarget() 
 557     SetDataObject(new wxFileDataObject
); 
 560 wxDragResult 
wxFileDropTarget::OnData(wxCoord x
, wxCoord y
, wxDragResult def
) 
 565     wxFileDataObject 
*dobj 
= (wxFileDataObject 
*)m_dataObject
; 
 566     return OnDropFiles( x
, y
, dobj
->GetFilenames() ) ? def 
: wxDragNone
; 
 569 #endif // wxUSE_DRAG_AND_DROP 
 571 #endif // wxUSE_DATAOBJ