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
)
115 m_preferred
= m_dataObjects
.GetCount();
117 m_dataObjects
.Append( dataObject
);
120 wxDataFormat
wxDataObjectComposite::GetReceivedFormat() const
122 return m_receivedFormat
;
126 wxDataObjectComposite::GetPreferredFormat(Direction
WXUNUSED(dir
)) const
128 wxSimpleDataObjectList::compatibility_iterator node
= m_dataObjects
.Item( m_preferred
);
130 wxCHECK_MSG( node
, wxFormatInvalid
, wxT("no preferred format") );
132 wxDataObjectSimple
* dataObj
= node
->GetData();
134 return dataObj
->GetFormat();
137 #if defined(__WXMSW__)
139 size_t wxDataObjectComposite::GetBufferOffset( const wxDataFormat
& format
)
141 wxDataObjectSimple
*dataObj
= GetObject(format
);
143 wxCHECK_MSG( dataObj
, 0,
144 wxT("unsupported format in wxDataObjectComposite"));
146 return dataObj
->GetBufferOffset( format
);
150 const void* wxDataObjectComposite::GetSizeFromBuffer( const void* buffer
,
152 const wxDataFormat
& format
)
154 wxDataObjectSimple
*dataObj
= GetObject(format
);
156 wxCHECK_MSG( dataObj
, NULL
,
157 wxT("unsupported format in wxDataObjectComposite"));
159 return dataObj
->GetSizeFromBuffer( buffer
, size
, format
);
163 void* wxDataObjectComposite::SetSizeInBuffer( void* buffer
, size_t size
,
164 const wxDataFormat
& format
)
166 wxDataObjectSimple
*dataObj
= GetObject( format
);
168 wxCHECK_MSG( dataObj
, NULL
,
169 wxT("unsupported format in wxDataObjectComposite"));
171 return dataObj
->SetSizeInBuffer( buffer
, size
, format
);
176 size_t wxDataObjectComposite::GetFormatCount(Direction dir
) const
180 // NOTE: some wxDataObjectSimple objects may return a number greater than 1
181 // from GetFormatCount(): this is the case of e.g. wxTextDataObject
182 // under wxMac and wxGTK
183 wxSimpleDataObjectList::compatibility_iterator node
;
184 for ( node
= m_dataObjects
.GetFirst(); node
; node
= node
->GetNext() )
185 n
+= node
->GetData()->GetFormatCount(dir
);
190 void wxDataObjectComposite::GetAllFormats(wxDataFormat
*formats
,
194 wxSimpleDataObjectList::compatibility_iterator node
;
196 for ( node
= m_dataObjects
.GetFirst(); node
; node
= node
->GetNext() )
198 // NOTE: some wxDataObjectSimple objects may return more than 1 format
199 // from GetAllFormats(): this is the case of e.g. wxTextDataObject
200 // under wxMac and wxGTK
201 node
->GetData()->GetAllFormats(formats
+index
, dir
);
202 index
+= node
->GetData()->GetFormatCount(dir
);
206 size_t wxDataObjectComposite::GetDataSize(const wxDataFormat
& format
) const
208 wxDataObjectSimple
*dataObj
= GetObject(format
);
210 wxCHECK_MSG( dataObj
, 0,
211 wxT("unsupported format in wxDataObjectComposite"));
213 return dataObj
->GetDataSize();
216 bool wxDataObjectComposite::GetDataHere(const wxDataFormat
& format
,
219 wxDataObjectSimple
*dataObj
= GetObject( format
);
221 wxCHECK_MSG( dataObj
, false,
222 wxT("unsupported format in wxDataObjectComposite"));
224 return dataObj
->GetDataHere( buf
);
227 bool wxDataObjectComposite::SetData(const wxDataFormat
& format
,
231 wxDataObjectSimple
*dataObj
= GetObject( format
);
233 wxCHECK_MSG( dataObj
, false,
234 wxT("unsupported format in wxDataObjectComposite"));
236 m_receivedFormat
= format
;
238 // Notice that we must pass "format" here as wxTextDataObject, that we can
239 // have as one of our "simple" sub-objects actually is not that simple and
240 // can support multiple formats (ASCII/UTF-8/UTF-16/...) and so needs to
241 // know which one it is given.
242 return dataObj
->SetData( format
, len
, buf
);
245 // ----------------------------------------------------------------------------
247 // ----------------------------------------------------------------------------
249 #ifdef wxNEEDS_UTF8_FOR_TEXT_DATAOBJ
251 // FIXME-UTF8: we should be able to merge wchar_t and UTF-8 versions once we
252 // have a way to get UTF-8 string (and its length) in both builds
253 // without loss of efficiency (i.e. extra buffer copy/strlen call)
255 #if wxUSE_UNICODE_WCHAR
257 static inline wxMBConv
& GetConv(const wxDataFormat
& format
)
259 // use UTF8 for wxDF_UNICODETEXT and UCS4 for wxDF_TEXT
260 return format
== wxDF_UNICODETEXT
? wxConvUTF8
: wxConvLibc
;
263 size_t wxTextDataObject::GetDataSize(const wxDataFormat
& format
) const
265 wxCharBuffer buffer
= GetConv(format
).cWX2MB( GetText().c_str() );
267 return buffer
? strlen( buffer
) : 0;
270 bool wxTextDataObject::GetDataHere(const wxDataFormat
& format
, void *buf
) const
275 wxCharBuffer buffer
= GetConv(format
).cWX2MB( GetText().c_str() );
279 memcpy( (char*) buf
, buffer
, GetDataSize(format
) );
280 // strcpy( (char*) buf, buffer );
285 bool wxTextDataObject::SetData(const wxDataFormat
& format
,
286 size_t WXUNUSED(len
), const void *buf
)
291 wxWCharBuffer buffer
= GetConv(format
).cMB2WX( (const char*)buf
);
298 #else // wxUSE_UNICODE_UTF8
300 size_t wxTextDataObject::GetDataSize(const wxDataFormat
& format
) const
302 const wxString
& text
= GetText();
303 if ( format
== wxDF_UNICODETEXT
|| wxLocaleIsUtf8
)
305 return text
.utf8_length();
309 const wxCharBuffer
buf(wxConvLocal
.cWC2MB(text
.wc_str()));
310 return buf
? strlen(buf
) : 0;
314 bool wxTextDataObject::GetDataHere(const wxDataFormat
& format
, void *buf
) const
319 const wxString
& text
= GetText();
320 if ( format
== wxDF_UNICODETEXT
|| wxLocaleIsUtf8
)
322 memcpy(buf
, text
.utf8_str(), text
.utf8_length());
326 const wxCharBuffer
bufLocal(wxConvLocal
.cWC2MB(text
.wc_str()));
330 memcpy(buf
, bufLocal
, strlen(bufLocal
));
336 bool wxTextDataObject::SetData(const wxDataFormat
& format
,
337 size_t len
, const void *buf_
)
339 const char * const buf
= static_cast<const char *>(buf_
);
344 if ( format
== wxDF_UNICODETEXT
|| wxLocaleIsUtf8
)
346 // normally the data is in UTF-8 so we could use FromUTF8Unchecked()
347 // but it's not absolutely clear what GTK+ does if the clipboard data
348 // is not in UTF-8 so do an extra check for tranquility, it shouldn't
349 // matter much if we lose a bit of performance when pasting from
351 SetText(wxString::FromUTF8(buf
, len
));
353 else // wxDF_TEXT, convert from current (non-UTF8) locale
355 SetText(wxConvLocal
.cMB2WC(buf
, len
, NULL
));
361 #endif // wxUSE_UNICODE_WCHAR/wxUSE_UNICODE_UTF8
363 #elif defined(wxNEEDS_UTF16_FOR_TEXT_DATAOBJ)
368 inline wxMBConv
& GetConv(const wxDataFormat
& format
)
370 static wxMBConvUTF16 s_UTF16Converter
;
372 return format
== wxDF_UNICODETEXT
? static_cast<wxMBConv
&>(s_UTF16Converter
)
373 : static_cast<wxMBConv
&>(wxConvLocal
);
376 } // anonymous namespace
378 size_t wxTextDataObject::GetDataSize(const wxDataFormat
& format
) const
380 return GetConv(format
).WC2MB(NULL
, GetText().wc_str(), 0);
383 bool wxTextDataObject::GetDataHere(const wxDataFormat
& format
, void *buf
) const
388 wxCharBuffer
buffer(GetConv(format
).cWX2MB(GetText().c_str()));
390 memcpy(buf
, buffer
.data(), buffer
.length());
395 bool wxTextDataObject::SetData(const wxDataFormat
& format
,
396 size_t WXUNUSED(len
),
402 SetText(GetConv(format
).cMB2WX(static_cast<const char*>(buf
)));
407 #else // !wxNEEDS_UTF{8,16}_FOR_TEXT_DATAOBJ
409 size_t wxTextDataObject::GetDataSize() const
411 return GetTextLength() * sizeof(wxChar
);
414 bool wxTextDataObject::GetDataHere(void *buf
) const
416 // NOTE: use wxTmemcpy() instead of wxStrncpy() to allow
417 // retrieval of strings with embedded NULLs
418 wxTmemcpy( (wxChar
*)buf
, GetText().c_str(), GetTextLength() );
423 bool wxTextDataObject::SetData(size_t len
, const void *buf
)
425 SetText( wxString((const wxChar
*)buf
, len
/sizeof(wxChar
)) );
430 #endif // different wxTextDataObject implementations
432 size_t wxHTMLDataObject::GetDataSize() const
434 const wxScopedCharBuffer
buffer(GetHTML().utf8_str());
436 size_t size
= buffer
.length();
439 // On Windows we need to add some stuff to the string to satisfy
440 // its clipboard format requirements.
447 bool wxHTMLDataObject::GetDataHere(void *buf
) const
452 // Windows and Mac always use UTF-8, and docs suggest GTK does as well.
453 const wxScopedCharBuffer
html(GetHTML().utf8_str());
457 char* const buffer
= static_cast<char*>(buf
);
460 // add the extra info that the MSW clipboard format requires.
462 // Create a template string for the HTML header...
465 "StartHTML:00000000\r\n"
466 "EndHTML:00000000\r\n"
467 "StartFragment:00000000\r\n"
468 "EndFragment:00000000\r\n"
470 "<!--StartFragment -->\r\n");
472 // Append the HTML...
473 strcat(buffer
, html
);
474 strcat(buffer
, "\r\n");
475 // Finish up the HTML format...
477 "<!--EndFragment-->\r\n"
481 // Now go back, calculate all the lengths, and write out the
482 // necessary header information. Note, wsprintf() truncates the
483 // string when you overwrite it so you follow up with code to replace
484 // the 0 appended at the end with a '\r'...
485 char *ptr
= strstr(buffer
, "StartHTML");
486 sprintf(ptr
+10, "%08u", (unsigned)(strstr(buffer
, "<html>") - buffer
));
489 ptr
= strstr(buffer
, "EndHTML");
490 sprintf(ptr
+8, "%08u", (unsigned)strlen(buffer
));
493 ptr
= strstr(buffer
, "StartFragment");
494 sprintf(ptr
+14, "%08u", (unsigned)(strstr(buffer
, "<!--StartFrag") - buffer
));
497 ptr
= strstr(buffer
, "EndFragment");
498 sprintf(ptr
+12, "%08u", (unsigned)(strstr(buffer
, "<!--EndFrag") - buffer
));
501 strcpy(buffer
, html
);
507 bool wxHTMLDataObject::SetData(size_t WXUNUSED(len
), const void *buf
)
512 // Windows and Mac always use UTF-8, and docs suggest GTK does as well.
513 wxString html
= wxString::FromUTF8(static_cast<const char*>(buf
));
516 // To be consistent with other platforms, we only add the Fragment part
517 // of the Windows HTML clipboard format to the data object.
518 int fragmentStart
= html
.rfind("StartFragment");
519 int fragmentEnd
= html
.rfind("EndFragment");
521 if (fragmentStart
!= wxNOT_FOUND
&& fragmentEnd
!= wxNOT_FOUND
)
523 int startCommentEnd
= html
.find("-->", fragmentStart
) + 3;
524 int endCommentStart
= html
.rfind("<!--", fragmentEnd
);
526 if (startCommentEnd
!= wxNOT_FOUND
&& endCommentStart
!= wxNOT_FOUND
)
527 html
= html
.Mid(startCommentEnd
, endCommentStart
- startCommentEnd
);
537 // ----------------------------------------------------------------------------
538 // wxCustomDataObject
539 // ----------------------------------------------------------------------------
541 wxCustomDataObject::wxCustomDataObject(const wxDataFormat
& format
)
542 : wxDataObjectSimple(format
)
548 wxCustomDataObject::~wxCustomDataObject()
553 void wxCustomDataObject::TakeData(size_t size
, void *data
)
561 void *wxCustomDataObject::Alloc(size_t size
)
563 return (void *)new char[size
];
566 void wxCustomDataObject::Free()
568 delete [] (char*)m_data
;
573 size_t wxCustomDataObject::GetDataSize() const
578 bool wxCustomDataObject::GetDataHere(void *buf
) const
583 void *data
= GetData();
587 memcpy( buf
, data
, GetSize() );
592 bool wxCustomDataObject::SetData(size_t size
, const void *buf
)
596 m_data
= Alloc(size
);
597 if ( m_data
== NULL
)
601 memcpy( m_data
, buf
, m_size
);
606 // ============================================================================
607 // some common dnd related code
608 // ============================================================================
610 #if wxUSE_DRAG_AND_DROP
614 // ----------------------------------------------------------------------------
616 // ----------------------------------------------------------------------------
618 // NB: we can't use "new" in ctor initializer lists because this provokes an
619 // internal compiler error with VC++ 5.0 (hey, even gcc compiles this!),
620 // so use SetDataObject() instead
622 wxTextDropTarget::wxTextDropTarget()
624 SetDataObject(new wxTextDataObject
);
627 wxDragResult
wxTextDropTarget::OnData(wxCoord x
, wxCoord y
, wxDragResult def
)
632 wxTextDataObject
*dobj
= (wxTextDataObject
*)m_dataObject
;
633 return OnDropText( x
, y
, dobj
->GetText() ) ? def
: wxDragNone
;
636 // ----------------------------------------------------------------------------
638 // ----------------------------------------------------------------------------
640 wxFileDropTarget::wxFileDropTarget()
642 SetDataObject(new wxFileDataObject
);
645 wxDragResult
wxFileDropTarget::OnData(wxCoord x
, wxCoord y
, wxDragResult def
)
650 wxFileDataObject
*dobj
= (wxFileDataObject
*)m_dataObject
;
651 return OnDropFiles( x
, y
, dobj
->GetFilenames() ) ? def
: wxDragNone
;
654 #endif // wxUSE_DRAG_AND_DROP
656 #endif // wxUSE_DATAOBJ