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 #include "wx/textbuf.h"
29 // ----------------------------------------------------------------------------
31 // ----------------------------------------------------------------------------
33 #include "wx/listimpl.cpp"
35 WX_DEFINE_LIST(wxSimpleDataObjectList
)
37 // ----------------------------------------------------------------------------
39 // ----------------------------------------------------------------------------
41 static wxDataFormat dataFormatInvalid
;
42 WXDLLEXPORT
const wxDataFormat
& wxFormatInvalid
= dataFormatInvalid
;
44 // ============================================================================
46 // ============================================================================
48 // ----------------------------------------------------------------------------
50 // ----------------------------------------------------------------------------
52 wxDataObjectBase::~wxDataObjectBase()
56 bool wxDataObjectBase::IsSupported(const wxDataFormat
& format
,
59 size_t nFormatCount
= GetFormatCount( dir
);
60 if ( nFormatCount
== 1 )
62 return format
== GetPreferredFormat( dir
);
66 wxDataFormat
*formats
= new wxDataFormat
[nFormatCount
];
67 GetAllFormats( formats
, dir
);
70 for ( n
= 0; n
< nFormatCount
; n
++ )
72 if ( formats
[n
] == format
)
79 return n
< nFormatCount
;
83 // ----------------------------------------------------------------------------
84 // wxDataObjectComposite
85 // ----------------------------------------------------------------------------
87 wxDataObjectComposite::wxDataObjectComposite()
90 m_receivedFormat
= wxFormatInvalid
;
93 wxDataObjectComposite::~wxDataObjectComposite()
95 WX_CLEAR_LIST( wxSimpleDataObjectList
, m_dataObjects
);
99 wxDataObjectComposite::GetObject(const wxDataFormat
& format
, wxDataObjectBase::Direction dir
) const
101 wxSimpleDataObjectList::compatibility_iterator node
= m_dataObjects
.GetFirst();
105 wxDataObjectSimple
*dataObj
= node
->GetData();
107 if (dataObj
->IsSupported(format
,dir
))
109 node
= node
->GetNext();
114 void wxDataObjectComposite::Add(wxDataObjectSimple
*dataObject
, bool preferred
)
117 m_preferred
= m_dataObjects
.GetCount();
119 m_dataObjects
.Append( dataObject
);
122 wxDataFormat
wxDataObjectComposite::GetReceivedFormat() const
124 return m_receivedFormat
;
128 wxDataObjectComposite::GetPreferredFormat(Direction
WXUNUSED(dir
)) const
130 wxSimpleDataObjectList::compatibility_iterator node
= m_dataObjects
.Item( m_preferred
);
132 wxCHECK_MSG( node
, wxFormatInvalid
, wxT("no preferred format") );
134 wxDataObjectSimple
* dataObj
= node
->GetData();
136 return dataObj
->GetFormat();
139 #if defined(__WXMSW__)
141 size_t wxDataObjectComposite::GetBufferOffset( const wxDataFormat
& format
)
143 wxDataObjectSimple
*dataObj
= GetObject(format
);
145 wxCHECK_MSG( dataObj
, 0,
146 wxT("unsupported format in wxDataObjectComposite"));
148 return dataObj
->GetBufferOffset( format
);
152 const void* wxDataObjectComposite::GetSizeFromBuffer( const void* buffer
,
154 const wxDataFormat
& format
)
156 wxDataObjectSimple
*dataObj
= GetObject(format
);
158 wxCHECK_MSG( dataObj
, NULL
,
159 wxT("unsupported format in wxDataObjectComposite"));
161 return dataObj
->GetSizeFromBuffer( buffer
, size
, format
);
165 void* wxDataObjectComposite::SetSizeInBuffer( void* buffer
, size_t size
,
166 const wxDataFormat
& format
)
168 wxDataObjectSimple
*dataObj
= GetObject( format
);
170 wxCHECK_MSG( dataObj
, NULL
,
171 wxT("unsupported format in wxDataObjectComposite"));
173 return dataObj
->SetSizeInBuffer( buffer
, size
, format
);
178 size_t wxDataObjectComposite::GetFormatCount(Direction dir
) const
182 // NOTE: some wxDataObjectSimple objects may return a number greater than 1
183 // from GetFormatCount(): this is the case of e.g. wxTextDataObject
184 // under wxMac and wxGTK
185 wxSimpleDataObjectList::compatibility_iterator node
;
186 for ( node
= m_dataObjects
.GetFirst(); node
; node
= node
->GetNext() )
187 n
+= node
->GetData()->GetFormatCount(dir
);
192 void wxDataObjectComposite::GetAllFormats(wxDataFormat
*formats
,
196 wxSimpleDataObjectList::compatibility_iterator node
;
198 for ( node
= m_dataObjects
.GetFirst(); node
; node
= node
->GetNext() )
200 // NOTE: some wxDataObjectSimple objects may return more than 1 format
201 // from GetAllFormats(): this is the case of e.g. wxTextDataObject
202 // under wxMac and wxGTK
203 node
->GetData()->GetAllFormats(formats
+index
, dir
);
204 index
+= node
->GetData()->GetFormatCount(dir
);
208 size_t wxDataObjectComposite::GetDataSize(const wxDataFormat
& format
) const
210 wxDataObjectSimple
*dataObj
= GetObject(format
);
212 wxCHECK_MSG( dataObj
, 0,
213 wxT("unsupported format in wxDataObjectComposite"));
215 return dataObj
->GetDataSize();
218 bool wxDataObjectComposite::GetDataHere(const wxDataFormat
& format
,
221 wxDataObjectSimple
*dataObj
= GetObject( format
);
223 wxCHECK_MSG( dataObj
, false,
224 wxT("unsupported format in wxDataObjectComposite"));
226 return dataObj
->GetDataHere( buf
);
229 bool wxDataObjectComposite::SetData(const wxDataFormat
& format
,
233 wxDataObjectSimple
*dataObj
= GetObject( format
);
235 wxCHECK_MSG( dataObj
, false,
236 wxT("unsupported format in wxDataObjectComposite"));
238 m_receivedFormat
= format
;
240 // Notice that we must pass "format" here as wxTextDataObject, that we can
241 // have as one of our "simple" sub-objects actually is not that simple and
242 // can support multiple formats (ASCII/UTF-8/UTF-16/...) and so needs to
243 // know which one it is given.
244 return dataObj
->SetData( format
, len
, buf
);
247 // ----------------------------------------------------------------------------
249 // ----------------------------------------------------------------------------
251 #ifdef wxNEEDS_UTF8_FOR_TEXT_DATAOBJ
253 // FIXME-UTF8: we should be able to merge wchar_t and UTF-8 versions once we
254 // have a way to get UTF-8 string (and its length) in both builds
255 // without loss of efficiency (i.e. extra buffer copy/strlen call)
257 #if wxUSE_UNICODE_WCHAR
259 static inline wxMBConv
& GetConv(const wxDataFormat
& format
)
261 // use UTF8 for wxDF_UNICODETEXT and UCS4 for wxDF_TEXT
262 return format
== wxDF_UNICODETEXT
? wxConvUTF8
: wxConvLibc
;
265 size_t wxTextDataObject::GetDataSize(const wxDataFormat
& format
) const
267 wxCharBuffer buffer
= GetConv(format
).cWX2MB( GetText().c_str() );
269 return buffer
? strlen( buffer
) : 0;
272 bool wxTextDataObject::GetDataHere(const wxDataFormat
& format
, void *buf
) const
277 wxCharBuffer buffer
= GetConv(format
).cWX2MB( GetText().c_str() );
281 memcpy( (char*) buf
, buffer
, GetDataSize(format
) );
282 // strcpy( (char*) buf, buffer );
287 bool wxTextDataObject::SetData(const wxDataFormat
& format
,
288 size_t WXUNUSED(len
), const void *buf
)
293 wxWCharBuffer buffer
= GetConv(format
).cMB2WX( (const char*)buf
);
300 #else // wxUSE_UNICODE_UTF8
302 size_t wxTextDataObject::GetDataSize(const wxDataFormat
& format
) const
304 const wxString
& text
= GetText();
305 if ( format
== wxDF_UNICODETEXT
|| wxLocaleIsUtf8
)
307 return text
.utf8_length();
311 const wxCharBuffer
buf(wxConvLocal
.cWC2MB(text
.wc_str()));
312 return buf
? strlen(buf
) : 0;
316 bool wxTextDataObject::GetDataHere(const wxDataFormat
& format
, void *buf
) const
321 const wxString
& text
= GetText();
322 if ( format
== wxDF_UNICODETEXT
|| wxLocaleIsUtf8
)
324 memcpy(buf
, text
.utf8_str(), text
.utf8_length());
328 const wxCharBuffer
bufLocal(wxConvLocal
.cWC2MB(text
.wc_str()));
332 memcpy(buf
, bufLocal
, strlen(bufLocal
));
338 bool wxTextDataObject::SetData(const wxDataFormat
& format
,
339 size_t len
, const void *buf_
)
341 const char * const buf
= static_cast<const char *>(buf_
);
346 if ( format
== wxDF_UNICODETEXT
|| wxLocaleIsUtf8
)
348 // normally the data is in UTF-8 so we could use FromUTF8Unchecked()
349 // but it's not absolutely clear what GTK+ does if the clipboard data
350 // is not in UTF-8 so do an extra check for tranquility, it shouldn't
351 // matter much if we lose a bit of performance when pasting from
353 SetText(wxString::FromUTF8(buf
, len
));
355 else // wxDF_TEXT, convert from current (non-UTF8) locale
357 SetText(wxConvLocal
.cMB2WC(buf
, len
, NULL
));
363 #endif // wxUSE_UNICODE_WCHAR/wxUSE_UNICODE_UTF8
365 #elif defined(wxNEEDS_UTF16_FOR_TEXT_DATAOBJ)
370 inline wxMBConv
& GetConv(const wxDataFormat
& format
)
372 static wxMBConvUTF16 s_UTF16Converter
;
374 return format
== wxDF_UNICODETEXT
? static_cast<wxMBConv
&>(s_UTF16Converter
)
375 : static_cast<wxMBConv
&>(wxConvLocal
);
378 } // anonymous namespace
380 size_t wxTextDataObject::GetDataSize(const wxDataFormat
& format
) const
382 return GetConv(format
).WC2MB(NULL
, GetText().wc_str(), 0);
385 bool wxTextDataObject::GetDataHere(const wxDataFormat
& format
, void *buf
) const
390 wxCharBuffer
buffer(GetConv(format
).cWX2MB(GetText().c_str()));
392 memcpy(buf
, buffer
.data(), buffer
.length());
397 bool wxTextDataObject::SetData(const wxDataFormat
& format
,
398 size_t WXUNUSED(len
),
404 SetText(GetConv(format
).cMB2WX(static_cast<const char*>(buf
)));
409 #else // !wxNEEDS_UTF{8,16}_FOR_TEXT_DATAOBJ
411 // NB: This branch, using native wxChar for the clipboard, is only used under
412 // Windows currently. It's just a coincidence, but Windows is also the only
413 // platform where we need to convert the text to the native EOL format, so
414 // wxTextBuffer::Translate() is only used here and not in the code above.
416 size_t wxTextDataObject::GetDataSize() const
418 return (wxTextBuffer::Translate(GetText()).length() + 1)*sizeof(wxChar
);
421 bool wxTextDataObject::GetDataHere(void *buf
) const
423 const wxString textNative
= wxTextBuffer::Translate(GetText());
425 // NOTE: use wxTmemcpy() instead of wxStrncpy() to allow
426 // retrieval of strings with embedded NULLs
427 wxTmemcpy(static_cast<wxChar
*>(buf
),
429 textNative
.length() + 1);
434 bool wxTextDataObject::SetData(size_t len
, const void *buf
)
437 text
= wxString(static_cast<const wxChar
*>(buf
), len
/sizeof(wxChar
));
438 SetText(wxTextBuffer::Translate(text
, wxTextFileType_Unix
));
443 #endif // different wxTextDataObject implementations
445 // ----------------------------------------------------------------------------
447 // ----------------------------------------------------------------------------
449 size_t wxHTMLDataObject::GetDataSize() const
451 // Ensure that the temporary string returned by GetHTML() is kept alive for
452 // as long as we need it here.
453 const wxString
& htmlStr
= GetHTML();
454 const wxScopedCharBuffer
buffer(htmlStr
.utf8_str());
456 size_t size
= buffer
.length();
459 // On Windows we need to add some stuff to the string to satisfy
460 // its clipboard format requirements.
467 bool wxHTMLDataObject::GetDataHere(void *buf
) const
472 // Windows and Mac always use UTF-8, and docs suggest GTK does as well.
473 const wxString
& htmlStr
= GetHTML();
474 const wxScopedCharBuffer
html(htmlStr
.utf8_str());
478 char* const buffer
= static_cast<char*>(buf
);
481 // add the extra info that the MSW clipboard format requires.
483 // Create a template string for the HTML header...
486 "StartHTML:00000000\r\n"
487 "EndHTML:00000000\r\n"
488 "StartFragment:00000000\r\n"
489 "EndFragment:00000000\r\n"
491 "<!--StartFragment -->\r\n");
493 // Append the HTML...
494 strcat(buffer
, html
);
495 strcat(buffer
, "\r\n");
496 // Finish up the HTML format...
498 "<!--EndFragment-->\r\n"
502 // Now go back, calculate all the lengths, and write out the
503 // necessary header information. Note, wsprintf() truncates the
504 // string when you overwrite it so you follow up with code to replace
505 // the 0 appended at the end with a '\r'...
506 char *ptr
= strstr(buffer
, "StartHTML");
507 sprintf(ptr
+10, "%08u", (unsigned)(strstr(buffer
, "<html>") - buffer
));
510 ptr
= strstr(buffer
, "EndHTML");
511 sprintf(ptr
+8, "%08u", (unsigned)strlen(buffer
));
514 ptr
= strstr(buffer
, "StartFragment");
515 sprintf(ptr
+14, "%08u", (unsigned)(strstr(buffer
, "<!--StartFrag") - buffer
));
518 ptr
= strstr(buffer
, "EndFragment");
519 sprintf(ptr
+12, "%08u", (unsigned)(strstr(buffer
, "<!--EndFrag") - buffer
));
522 strcpy(buffer
, html
);
528 bool wxHTMLDataObject::SetData(size_t WXUNUSED(len
), const void *buf
)
533 // Windows and Mac always use UTF-8, and docs suggest GTK does as well.
534 wxString html
= wxString::FromUTF8(static_cast<const char*>(buf
));
537 // To be consistent with other platforms, we only add the Fragment part
538 // of the Windows HTML clipboard format to the data object.
539 int fragmentStart
= html
.rfind("StartFragment");
540 int fragmentEnd
= html
.rfind("EndFragment");
542 if (fragmentStart
!= wxNOT_FOUND
&& fragmentEnd
!= wxNOT_FOUND
)
544 int startCommentEnd
= html
.find("-->", fragmentStart
) + 3;
545 int endCommentStart
= html
.rfind("<!--", fragmentEnd
);
547 if (startCommentEnd
!= wxNOT_FOUND
&& endCommentStart
!= wxNOT_FOUND
)
548 html
= html
.Mid(startCommentEnd
, endCommentStart
- startCommentEnd
);
558 // ----------------------------------------------------------------------------
559 // wxCustomDataObject
560 // ----------------------------------------------------------------------------
562 wxCustomDataObject::wxCustomDataObject(const wxDataFormat
& format
)
563 : wxDataObjectSimple(format
)
569 wxCustomDataObject::~wxCustomDataObject()
574 void wxCustomDataObject::TakeData(size_t size
, void *data
)
582 void *wxCustomDataObject::Alloc(size_t size
)
584 return (void *)new char[size
];
587 void wxCustomDataObject::Free()
589 delete [] (char*)m_data
;
594 size_t wxCustomDataObject::GetDataSize() const
599 bool wxCustomDataObject::GetDataHere(void *buf
) const
604 void *data
= GetData();
608 memcpy( buf
, data
, GetSize() );
613 bool wxCustomDataObject::SetData(size_t size
, const void *buf
)
617 m_data
= Alloc(size
);
618 if ( m_data
== NULL
)
622 memcpy( m_data
, buf
, m_size
);
627 // ============================================================================
628 // some common dnd related code
629 // ============================================================================
631 #if wxUSE_DRAG_AND_DROP
635 // ----------------------------------------------------------------------------
637 // ----------------------------------------------------------------------------
639 // NB: we can't use "new" in ctor initializer lists because this provokes an
640 // internal compiler error with VC++ 5.0 (hey, even gcc compiles this!),
641 // so use SetDataObject() instead
643 wxTextDropTarget::wxTextDropTarget()
645 SetDataObject(new wxTextDataObject
);
648 wxDragResult
wxTextDropTarget::OnData(wxCoord x
, wxCoord y
, wxDragResult def
)
653 wxTextDataObject
*dobj
= (wxTextDataObject
*)m_dataObject
;
654 return OnDropText( x
, y
, dobj
->GetText() ) ? def
: wxDragNone
;
657 // ----------------------------------------------------------------------------
659 // ----------------------------------------------------------------------------
661 wxFileDropTarget::wxFileDropTarget()
663 SetDataObject(new wxFileDataObject
);
666 wxDragResult
wxFileDropTarget::OnData(wxCoord x
, wxCoord y
, wxDragResult def
)
671 wxFileDataObject
*dobj
= (wxFileDataObject
*)m_dataObject
;
672 return OnDropFiles( x
, y
, dobj
->GetFilenames() ) ? def
: wxDragNone
;
675 #endif // wxUSE_DRAG_AND_DROP
677 #endif // wxUSE_DATAOBJ