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