Bug 513464: Add support for multiple drags outside of Gecko r=jimm

--HG--
extra : rebase_source : a7b2f1d7b81946baa47793a8c5cdf8da59c42fd4
This commit is contained in:
Kyle Huey 2010-02-20 08:44:02 -05:00
parent 8038a1962b
commit 87cb614d99
5 changed files with 872 additions and 314 deletions

View File

@ -725,6 +725,7 @@ STDMETHODIMP nsDataObj::EnumFormatEtc(DWORD dwDir, LPENUMFORMATETC *ppEnum)
if (NULL == *ppEnum)
return ResultFromScode(E_FAIL);
(*ppEnum)->Reset();
// Clone already AddRefed the result so don't addref it again.
return NOERROR;
}

View File

@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Kyle Huey <me@kylehuey.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -35,47 +36,27 @@
*
* ***** END LICENSE BLOCK ***** */
#include <shlobj.h>
#include "nsDataObjCollection.h"
#include "nsITransferable.h"
#include "nsClipboard.h"
#include "IEnumFE.h"
#include <ole2.h>
#if 0
#define PRNTDEBUG(_x) printf(_x);
#define PRNTDEBUG2(_x1, _x2) printf(_x1, _x2);
#define PRNTDEBUG3(_x1, _x2, _x3) printf(_x1, _x2, _x3);
#else
#define PRNTDEBUG(_x) // printf(_x);
#define PRNTDEBUG2(_x1, _x2) // printf(_x1, _x2);
#define PRNTDEBUG3(_x1, _x2, _x3) // printf(_x1, _x2, _x3);
#endif
EXTERN_C GUID CDECL CLSID_nsDataObjCollection =
{ 0x2d851b91, 0xd4c, 0x11d3, { 0x96, 0xd4, 0x0, 0x60, 0xb0, 0xfb, 0x99, 0x56 } };
/*
* Class nsDataObjCollection
*/
//-----------------------------------------------------
// construction
//-----------------------------------------------------
nsDataObjCollection::nsDataObjCollection()
: m_cRef(0), mTransferable(nsnull)
: m_cRef(0), mIsAsyncMode(FALSE), mIsInOperation(FALSE)
{
m_enumFE = new CEnumFormatEtc();
m_enumFE->AddRef();
}
//-----------------------------------------------------
// destruction
//-----------------------------------------------------
nsDataObjCollection::~nsDataObjCollection()
{
NS_IF_RELEASE(mTransferable);
mDataFlavors.Clear();
mDataObjects.Clear();
@ -83,104 +64,94 @@ nsDataObjCollection::~nsDataObjCollection()
}
//-----------------------------------------------------
// IUnknown interface methods - see inknown.h for documentation
//-----------------------------------------------------
// IUnknown interface methods - see iunknown.h for documentation
STDMETHODIMP nsDataObjCollection::QueryInterface(REFIID riid, void** ppv)
{
*ppv=NULL;
*ppv=NULL;
if ( (IID_IUnknown == riid) || (IID_IDataObject == riid) ) {
*ppv = static_cast<IDataObject*>(this);
AddRef();
return NOERROR;
}
if ( IID_IDataObjCollection == riid ) {
*ppv = static_cast<nsIDataObjCollection*>(this);
AddRef();
return NOERROR;
}
return ResultFromScode(E_NOINTERFACE);
}
//-----------------------------------------------------
STDMETHODIMP_(ULONG) nsDataObjCollection::AddRef()
{
//PRNTDEBUG3("nsDataObjCollection::AddRef >>>>>>>>>>>>>>>>>> %d on %p\n", (m_cRef+1), this);
return ++m_cRef;
}
//-----------------------------------------------------
STDMETHODIMP_(ULONG) nsDataObjCollection::Release()
{
//PRNTDEBUG3("nsDataObjCollection::Release >>>>>>>>>>>>>>>>>> %d on %p\n", (m_cRef-1), this);
if (0 != --m_cRef)
return m_cRef;
delete this;
return 0;
}
//-----------------------------------------------------
BOOL nsDataObjCollection::FormatsMatch(const FORMATETC& source, const FORMATETC& target) const
{
if ((source.cfFormat == target.cfFormat) &&
(source.dwAspect & target.dwAspect) &&
(source.tymed & target.tymed)) {
return TRUE;
} else {
return FALSE;
}
}
//-----------------------------------------------------
// IDataObject methods
//-----------------------------------------------------
STDMETHODIMP nsDataObjCollection::GetData(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
{
PRNTDEBUG("nsDataObjCollection::GetData\n");
PRNTDEBUG3(" format: %d Text: %d\n", pFE->cfFormat, CF_TEXT);
for (PRUint32 i = 0; i < mDataObjects.Length(); ++i) {
IDataObject * dataObj = mDataObjects.ElementAt(i);
if (S_OK == dataObj->GetData(pFE, pSTM)) {
return S_OK;
}
if ( (IID_IUnknown == riid) || (IID_IDataObject == riid) ) {
*ppv = static_cast<IDataObject*>(this);
AddRef();
return NOERROR;
}
return ResultFromScode(DATA_E_FORMATETC);
if ( IID_IDataObjCollection == riid ) {
*ppv = static_cast<nsIDataObjCollection*>(this);
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) nsDataObjCollection::AddRef()
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG) nsDataObjCollection::Release()
{
if (0 != --m_cRef)
return m_cRef;
delete this;
return 0;
}
BOOL nsDataObjCollection::FormatsMatch(const FORMATETC& source,
const FORMATETC& target) const
{
if ((source.cfFormat == target.cfFormat) &&
(source.dwAspect & target.dwAspect) &&
(source.tymed & target.tymed)) {
return TRUE;
} else {
return FALSE;
}
}
// IDataObject methods
STDMETHODIMP nsDataObjCollection::GetData(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
{
static CLIPFORMAT fileDescriptorFlavorA =
::RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA);
static CLIPFORMAT fileDescriptorFlavorW =
::RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW);
static CLIPFORMAT fileFlavor = ::RegisterClipboardFormat(CFSTR_FILECONTENTS);
switch (pFE->cfFormat) {
case CF_TEXT:
case CF_UNICODETEXT:
return GetText(pFE, pSTM);
case CF_HDROP:
return GetFile(pFE, pSTM);
default:
if (pFE->cfFormat == fileDescriptorFlavorA ||
pFE->cfFormat == fileDescriptorFlavorW) {
return GetFileDescriptors(pFE, pSTM);
}
if (pFE->cfFormat == fileFlavor) {
return GetFileContents(pFE, pSTM);
}
}
return GetFirstSupporting(pFE, pSTM);
}
//-----------------------------------------------------
STDMETHODIMP nsDataObjCollection::GetDataHere(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
{
PRNTDEBUG("nsDataObjCollection::GetDataHere\n");
return ResultFromScode(E_FAIL);
return E_FAIL;
}
//-----------------------------------------------------
// Other objects querying to see if we support a
// particular format
//-----------------------------------------------------
// Other objects querying to see if we support a particular format
STDMETHODIMP nsDataObjCollection::QueryGetData(LPFORMATETC pFE)
{
UINT format = nsClipboard::GetFormat(MULTI_MIME);
PRNTDEBUG("nsDataObjCollection::QueryGetData ");
PRNTDEBUG3("format: %d Mulitple: %d\n", pFE->cfFormat, format);
if (format == pFE->cfFormat) {
return S_OK;
}
for (PRUint32 i = 0; i < mDataObjects.Length(); ++i) {
IDataObject * dataObj = mDataObjects.ElementAt(i);
if (S_OK == dataObj->QueryGetData(pFE)) {
@ -188,142 +159,379 @@ STDMETHODIMP nsDataObjCollection::QueryGetData(LPFORMATETC pFE)
}
}
PRNTDEBUG2("***** nsDataObjCollection::QueryGetData - Unknown format %d\n", pFE->cfFormat);
return ResultFromScode(E_FAIL);
return DV_E_FORMATETC;
}
//-----------------------------------------------------
STDMETHODIMP nsDataObjCollection::GetCanonicalFormatEtc
(LPFORMATETC pFEIn, LPFORMATETC pFEOut)
STDMETHODIMP nsDataObjCollection::GetCanonicalFormatEtc(LPFORMATETC pFEIn,
LPFORMATETC pFEOut)
{
PRNTDEBUG("nsDataObjCollection::GetCanonicalFormatEtc\n");
return ResultFromScode(E_FAIL);
return E_NOTIMPL;
}
//-----------------------------------------------------
STDMETHODIMP nsDataObjCollection::SetData(LPFORMATETC pFE, LPSTGMEDIUM pSTM, BOOL fRelease)
STDMETHODIMP nsDataObjCollection::SetData(LPFORMATETC pFE,
LPSTGMEDIUM pSTM,
BOOL fRelease)
{
PRNTDEBUG("nsDataObjCollection::SetData\n");
return ResultFromScode(E_FAIL);
// Set arbitrary data formats on the first object in the collection and let
// it handle the heavy lifting
if (mDataObjects.Length() == 0)
return E_FAIL;
return mDataObjects.ElementAt(0)->SetData(pFE, pSTM, fRelease);
}
//-----------------------------------------------------
STDMETHODIMP nsDataObjCollection::EnumFormatEtc(DWORD dwDir, LPENUMFORMATETC *ppEnum)
STDMETHODIMP nsDataObjCollection::EnumFormatEtc(DWORD dwDir,
LPENUMFORMATETC *ppEnum)
{
PRNTDEBUG("nsDataObjCollection::EnumFormatEtc\n");
if (dwDir == DATADIR_GET) {
// Clone addref's the new enumerator.
return m_enumFE->Clone(ppEnum);
m_enumFE->Clone(ppEnum);
if (!(*ppEnum))
return E_FAIL;
(*ppEnum)->Reset();
return S_OK;
}
return E_NOTIMPL;
}
//-----------------------------------------------------
STDMETHODIMP nsDataObjCollection::DAdvise(LPFORMATETC pFE, DWORD dwFlags,
LPADVISESINK pIAdviseSink, DWORD* pdwConn)
STDMETHODIMP nsDataObjCollection::DAdvise(LPFORMATETC pFE,
DWORD dwFlags,
LPADVISESINK pIAdviseSink,
DWORD* pdwConn)
{
PRNTDEBUG("nsDataObjCollection::DAdvise\n");
return ResultFromScode(E_FAIL);
return OLE_E_ADVISENOTSUPPORTED;
}
//-----------------------------------------------------
STDMETHODIMP nsDataObjCollection::DUnadvise(DWORD dwConn)
{
PRNTDEBUG("nsDataObjCollection::DUnadvise\n");
return ResultFromScode(E_FAIL);
return OLE_E_ADVISENOTSUPPORTED;
}
//-----------------------------------------------------
STDMETHODIMP nsDataObjCollection::EnumDAdvise(LPENUMSTATDATA *ppEnum)
{
PRNTDEBUG("nsDataObjCollection::EnumDAdvise\n");
return ResultFromScode(E_FAIL);
return OLE_E_ADVISENOTSUPPORTED;
}
//-----------------------------------------------------
// GetData and SetData helper functions
//-----------------------------------------------------
HRESULT nsDataObjCollection::AddSetFormat(FORMATETC& aFE)
{
PRNTDEBUG("nsDataObjCollection::AddSetFormat\n");
return ResultFromScode(S_OK);
return S_OK;
}
//-----------------------------------------------------
HRESULT nsDataObjCollection::AddGetFormat(FORMATETC& aFE)
{
PRNTDEBUG("nsDataObjCollection::AddGetFormat\n");
return ResultFromScode(S_OK);
return S_OK;
}
//-----------------------------------------------------
HRESULT nsDataObjCollection::GetBitmap(FORMATETC&, STGMEDIUM&)
// Registers a DataFlavor/FE pair
void nsDataObjCollection::AddDataFlavor(const char * aDataFlavor,
LPFORMATETC aFE)
{
PRNTDEBUG("nsDataObjCollection::GetBitmap\n");
return ResultFromScode(E_NOTIMPL);
}
//-----------------------------------------------------
HRESULT nsDataObjCollection::GetDib(FORMATETC&, STGMEDIUM&)
{
PRNTDEBUG("nsDataObjCollection::GetDib\n");
return ResultFromScode(E_NOTIMPL);
}
//-----------------------------------------------------
HRESULT nsDataObjCollection::GetMetafilePict(FORMATETC&, STGMEDIUM&)
{
return ResultFromScode(E_NOTIMPL);
}
//-----------------------------------------------------
HRESULT nsDataObjCollection::SetBitmap(FORMATETC&, STGMEDIUM&)
{
return ResultFromScode(E_NOTIMPL);
}
//-----------------------------------------------------
HRESULT nsDataObjCollection::SetDib (FORMATETC&, STGMEDIUM&)
{
return ResultFromScode(E_FAIL);
}
//-----------------------------------------------------
HRESULT nsDataObjCollection::SetMetafilePict (FORMATETC&, STGMEDIUM&)
{
return ResultFromScode(E_FAIL);
}
//-----------------------------------------------------
//-----------------------------------------------------
CLSID nsDataObjCollection::GetClassID() const
{
return CLSID_nsDataObjCollection;
}
//-----------------------------------------------------
// Registers a the DataFlavor/FE pair
//-----------------------------------------------------
void nsDataObjCollection::AddDataFlavor(nsString * aDataFlavor, LPFORMATETC aFE)
{
// These two lists are the mapping to and from data flavors and FEs
// Later, OLE will tell us it's needs a certain type of FORMATETC (text, unicode, etc)
// so we will look up data flavor that corresponds to the FE
// and then ask the transferable for that type of data
mDataFlavors.AppendElement(*aDataFlavor);
// Add the FormatEtc to our list if it's not already there. We don't care
// about the internal aDataFlavor because nsDataObj handles that.
IEnumFORMATETC * ifEtc;
FORMATETC fEtc;
ULONG num;
if (S_OK != this->EnumFormatEtc(DATADIR_GET, &ifEtc))
return;
while (S_OK == ifEtc->Next(1, &fEtc, &num)) {
NS_ASSERTION(1 == num,
"Bit off more than we can chew in nsDataObjCollection::AddDataFlavor");
if (FormatsMatch(fEtc, *aFE)) {
ifEtc->Release();
return;
}
} // If we didn't find a matching format, add this one
ifEtc->Release();
m_enumFE->AddFormatEtc(aFE);
}
//-----------------------------------------------------
// Registers a the DataFlavor/FE pair
//-----------------------------------------------------
// We accept ownership of the nsDataObj which we free on destruction
void nsDataObjCollection::AddDataObject(IDataObject * aDataObj)
{
mDataObjects.AppendElement(aDataObj);
nsDataObj* dataObj = reinterpret_cast<nsDataObj*>(aDataObj);
mDataObjects.AppendElement(dataObj);
}
// IAsyncOperation methods
STDMETHODIMP nsDataObjCollection::EndOperation(HRESULT hResult,
IBindCtx *pbcReserved,
DWORD dwEffects)
{
mIsInOperation = FALSE;
Release();
return S_OK;
}
STDMETHODIMP nsDataObjCollection::GetAsyncMode(BOOL *pfIsOpAsync)
{
if (!pfIsOpAsync)
return E_FAIL;
*pfIsOpAsync = mIsAsyncMode;
return S_OK;
}
STDMETHODIMP nsDataObjCollection::InOperation(BOOL *pfInAsyncOp)
{
if (!pfInAsyncOp)
return E_FAIL;
*pfInAsyncOp = mIsInOperation;
return S_OK;
}
STDMETHODIMP nsDataObjCollection::SetAsyncMode(BOOL fDoOpAsync)
{
mIsAsyncMode = fDoOpAsync;
return S_OK;
}
STDMETHODIMP nsDataObjCollection::StartOperation(IBindCtx *pbcReserved)
{
mIsInOperation = TRUE;
return S_OK;
}
// Methods for getting data
HRESULT nsDataObjCollection::GetFile(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
{
STGMEDIUM workingmedium;
FORMATETC fe = *pFE;
HGLOBAL hGlobalMemory;
HRESULT hr;
// Make enough space for the header and the trailing null
PRUint32 buffersize = sizeof(DROPFILES) + sizeof(PRUnichar);
PRUint32 alloclen = 0;
PRUnichar* realbuffer;
nsAutoString filename;
hGlobalMemory = GlobalAlloc(GHND, buffersize);
for (PRUint32 i = 0; i < mDataObjects.Length(); ++i) {
nsDataObj* dataObj = mDataObjects.ElementAt(i);
hr = dataObj->GetData(&fe, &workingmedium);
if (hr != S_OK) {
switch (hr) {
case DV_E_FORMATETC:
continue;
default:
return hr;
}
}
// Now we need to pull out the filename
PRUnichar* buffer = (PRUnichar*)GlobalLock(workingmedium.hGlobal);
if (buffer == NULL)
return E_FAIL;
buffer += sizeof(DROPFILES)/sizeof(PRUnichar);
filename = buffer;
GlobalUnlock(workingmedium.hGlobal);
ReleaseStgMedium(&workingmedium);
// Now put the filename into our buffer
alloclen = (filename.Length() + 1) * sizeof(PRUnichar);
hGlobalMemory = ::GlobalReAlloc(hGlobalMemory, buffersize + alloclen, GHND);
if (hGlobalMemory == NULL)
return E_FAIL;
realbuffer = (PRUnichar*)((char*)GlobalLock(hGlobalMemory) + buffersize);
if (!realbuffer)
return E_FAIL;
realbuffer--; // Overwrite the preceding null
memcpy(realbuffer, filename.get(), alloclen);
GlobalUnlock(hGlobalMemory);
buffersize += alloclen;
}
// We get the last null (on the double null terminator) for free since we used
// the zero memory flag when we allocated. All we need to do is fill the
// DROPFILES structure
DROPFILES* df = (DROPFILES*)GlobalLock(hGlobalMemory);
if (!df)
return E_FAIL;
df->pFiles = sizeof(DROPFILES); //Offset to start of file name string
df->fNC = 0;
df->pt.x = 0;
df->pt.y = 0;
df->fWide = TRUE; // utf-16 chars
GlobalUnlock(hGlobalMemory);
// Finally fill out the STGMEDIUM struct
pSTM->tymed = TYMED_HGLOBAL;
pSTM->pUnkForRelease = NULL; // Caller gets to free the data
pSTM->hGlobal = hGlobalMemory;
return S_OK;
}
HRESULT nsDataObjCollection::GetText(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
{
STGMEDIUM workingmedium;
FORMATETC fe = *pFE;
HGLOBAL hGlobalMemory;
HRESULT hr;
PRUint32 buffersize = 1;
PRUint32 alloclen = 0;
hGlobalMemory = GlobalAlloc(GHND, buffersize);
if (pFE->cfFormat == CF_TEXT) {
nsCAutoString text;
for (PRUint32 i = 0; i < mDataObjects.Length(); ++i) {
nsDataObj* dataObj = mDataObjects.ElementAt(i);
hr = dataObj->GetData(&fe, &workingmedium);
if (hr != S_OK) {
switch (hr) {
case DV_E_FORMATETC:
continue;
default:
return hr;
}
}
// Now we need to pull out the text
char* buffer = (char*)GlobalLock(workingmedium.hGlobal);
if (buffer == NULL)
return E_FAIL;
text = buffer;
GlobalUnlock(workingmedium.hGlobal);
ReleaseStgMedium(&workingmedium);
// Now put the text into our buffer
alloclen = text.Length();
hGlobalMemory = ::GlobalReAlloc(hGlobalMemory, buffersize + alloclen,
GHND);
if (hGlobalMemory == NULL)
return E_FAIL;
buffer = ((char*)GlobalLock(hGlobalMemory) + buffersize);
if (!buffer)
return E_FAIL;
buffer--; // Overwrite the preceding null
memcpy(buffer, text.get(), alloclen);
GlobalUnlock(hGlobalMemory);
buffersize += alloclen;
}
pSTM->tymed = TYMED_HGLOBAL;
pSTM->pUnkForRelease = NULL; // Caller gets to free the data
pSTM->hGlobal = hGlobalMemory;
return S_OK;
}
if (pFE->cfFormat == CF_UNICODETEXT) {
buffersize = sizeof(PRUnichar);
nsAutoString text;
for (PRUint32 i = 0; i < mDataObjects.Length(); ++i) {
nsDataObj* dataObj = mDataObjects.ElementAt(i);
hr = dataObj->GetData(&fe, &workingmedium);
if (hr != S_OK) {
switch (hr) {
case DV_E_FORMATETC:
continue;
default:
return hr;
}
}
// Now we need to pull out the text
PRUnichar* buffer = (PRUnichar*)GlobalLock(workingmedium.hGlobal);
if (buffer == NULL)
return E_FAIL;
text = buffer;
GlobalUnlock(workingmedium.hGlobal);
ReleaseStgMedium(&workingmedium);
// Now put the text into our buffer
alloclen = text.Length() * sizeof(PRUnichar);
hGlobalMemory = ::GlobalReAlloc(hGlobalMemory, buffersize + alloclen,
GHND);
if (hGlobalMemory == NULL)
return E_FAIL;
buffer = (PRUnichar*)((char*)GlobalLock(hGlobalMemory) + buffersize);
if (!buffer)
return E_FAIL;
buffer--; // Overwrite the preceding null
memcpy(buffer, text.get(), alloclen);
GlobalUnlock(hGlobalMemory);
buffersize += alloclen;
}
pSTM->tymed = TYMED_HGLOBAL;
pSTM->pUnkForRelease = NULL; // Caller gets to free the data
pSTM->hGlobal = hGlobalMemory;
return S_OK;
}
return E_FAIL;
}
HRESULT nsDataObjCollection::GetFileDescriptors(LPFORMATETC pFE,
LPSTGMEDIUM pSTM)
{
STGMEDIUM workingmedium;
FORMATETC fe = *pFE;
HGLOBAL hGlobalMemory;
HRESULT hr;
PRUint32 buffersize = sizeof(FILEGROUPDESCRIPTOR);
PRUint32 alloclen = sizeof(FILEDESCRIPTOR);
hGlobalMemory = GlobalAlloc(GHND, buffersize);
for (PRUint32 i = 0; i < mDataObjects.Length(); ++i) {
nsDataObj* dataObj = mDataObjects.ElementAt(i);
hr = dataObj->GetData(&fe, &workingmedium);
if (hr != S_OK) {
switch (hr) {
case DV_E_FORMATETC:
continue;
default:
return hr;
}
}
// Now we need to pull out the filedescriptor
FILEDESCRIPTOR* buffer =
(FILEDESCRIPTOR*)((char*)GlobalLock(workingmedium.hGlobal) + sizeof(UINT));
if (buffer == NULL)
return E_FAIL;
hGlobalMemory = ::GlobalReAlloc(hGlobalMemory, buffersize + alloclen, GHND);
if (hGlobalMemory == NULL)
return E_FAIL;
FILEGROUPDESCRIPTOR* realbuffer =
(FILEGROUPDESCRIPTOR*)GlobalLock(hGlobalMemory);
if (!realbuffer)
return E_FAIL;
FILEDESCRIPTOR* copyloc = (FILEDESCRIPTOR*)((char*)realbuffer + buffersize);
memcpy(copyloc, buffer, sizeof(FILEDESCRIPTOR));
realbuffer->cItems++;
GlobalUnlock(hGlobalMemory);
GlobalUnlock(workingmedium.hGlobal);
ReleaseStgMedium(&workingmedium);
buffersize += alloclen;
}
pSTM->tymed = TYMED_HGLOBAL;
pSTM->pUnkForRelease = NULL; // Caller gets to free the data
pSTM->hGlobal = hGlobalMemory;
return S_OK;
}
HRESULT nsDataObjCollection::GetFileContents(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
{
ULONG num = 0;
ULONG numwanted = (pFE->lindex == -1) ? 0 : pFE->lindex;
FORMATETC fEtc = *pFE;
fEtc.lindex = -1; // We're lying to the data object so it thinks it's alone
// The key for this data type is to figure out which data object the index
// corresponds to and then just pass it along
for (PRUint32 i = 0; i < mDataObjects.Length(); ++i) {
nsDataObj* dataObj = mDataObjects.ElementAt(i);
if (dataObj->QueryGetData(&fEtc) != S_OK)
continue;
if (num == numwanted)
return dataObj->GetData(pFE, pSTM);
numwanted++;
}
return DV_E_LINDEX;
}
HRESULT nsDataObjCollection::GetFirstSupporting(LPFORMATETC pFE,
LPSTGMEDIUM pSTM)
{
// There is no way to pass more than one of this, so just find the first data
// object that supports it and pass it along
for (PRUint32 i = 0; i < mDataObjects.Length(); ++i) {
if (mDataObjects.ElementAt(i)->QueryGetData(pFE) == S_OK)
return mDataObjects.ElementAt(i)->GetData(pFE, pSTM);
}
return DV_E_FORMATETC;
}

View File

@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Kyle Huey <me@kylehuey.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -38,7 +39,7 @@
#ifndef _NSDATAOBJCOLLECTION_H_
#define _NSDATAOBJCOLLECTION_H_
#define INITGUID // needed for initializing the IID_IDataObjCollection GUID
#include <initguid.h>
#ifdef __MINGW32__
#include <unknwn.h>
@ -50,29 +51,12 @@
#include "nsString.h"
#include "nsTArray.h"
#include "nsAutoPtr.h"
#include "nsDataObj.h"
class CEnumFormatEtc;
class nsITransferable;
#define MULTI_MIME "Mozilla/IDataObjectCollectionFormat"
#if NOT_YET
// {6e99c280-d820-11d3-bb6f-bbf26bfe623c}
EXTERN_C GUID CDECL IID_DATA_OBJ_COLLECTION =
{ 0x6e99c280, 0xd820, 0x11d3, { 0xbb, 0x6f, 0xbb, 0xf2, 0x6b, 0xfe, 0x62, 0x3c } };
class nsPIDataObjCollection : IUnknown
{
public:
STDMETHODIMP AddDataObject(IDataObject * aDataObj) = 0;
STDMETHODIMP GetNumDataObjects(PRInt32* outNum) = 0;
STDMETHODIMP GetDataObjectAt(PRUint32 aItem, IDataObject** outItem) = 0;
};
#endif
// {25589C3E-1FAC-47b9-BF43-CAEA89B79533}
DEFINE_GUID(IID_IDataObjCollection,
0x25589c3e, 0x1fac, 0x47b9, 0xbf, 0x43, 0xca, 0xea, 0x89, 0xb7, 0x95, 0x33);
@ -90,118 +74,111 @@ public:
* associated with instances via SetDragDrop().
*/
class nsDataObjCollection : public IDataObject, public nsIDataObjCollection //, public nsPIDataObjCollection
class nsDataObjCollection : public nsIDataObjCollection, public nsDataObj
{
public: // construction, destruction
nsDataObjCollection();
~nsDataObjCollection();
public:
nsDataObjCollection();
~nsDataObjCollection();
public: // IUnknown methods - see iunknown.h for documentation
STDMETHODIMP_(ULONG) AddRef ();
STDMETHODIMP QueryInterface(REFIID, void**);
STDMETHODIMP_(ULONG) Release ();
public: // IUnknown methods - see iunknown.h for documentation
STDMETHODIMP_(ULONG) AddRef ();
STDMETHODIMP QueryInterface(REFIID, void**);
STDMETHODIMP_(ULONG) Release ();
public: // DataGet and DataSet helper methods
virtual HRESULT AddSetFormat(FORMATETC& FE);
virtual HRESULT AddGetFormat(FORMATETC& FE);
public: // DataGet and DataSet helper methods
virtual HRESULT AddSetFormat(FORMATETC& FE);
virtual HRESULT AddGetFormat(FORMATETC& FE);
virtual HRESULT GetBitmap(FORMATETC& FE, STGMEDIUM& STM);
virtual HRESULT GetDib (FORMATETC& FE, STGMEDIUM& STM);
virtual HRESULT GetMetafilePict(FORMATETC& FE, STGMEDIUM& STM);
virtual HRESULT SetBitmap(FORMATETC& FE, STGMEDIUM& STM);
virtual HRESULT SetDib (FORMATETC& FE, STGMEDIUM& STM);
virtual HRESULT SetMetafilePict(FORMATETC& FE, STGMEDIUM& STM);
virtual HRESULT GetFile(LPFORMATETC pFE, LPSTGMEDIUM pSTM);
virtual HRESULT GetText(LPFORMATETC pFE, LPSTGMEDIUM pSTM);
virtual HRESULT GetFileDescriptors(LPFORMATETC pFE, LPSTGMEDIUM pSTM);
virtual HRESULT GetFileContents(LPFORMATETC pFE, LPSTGMEDIUM pSTM);
virtual HRESULT GetFirstSupporting(LPFORMATETC pFE, LPSTGMEDIUM pSTM);
// support for clipboard
void AddDataFlavor(nsString * aDataFlavor, LPFORMATETC aFE);
void SetTransferable(nsITransferable * aTransferable);
#if NOT_YET
// from nsPIDataObjCollection
STDMETHODIMP AddDataObject(IDataObject * aDataObj);
STDMETHODIMP GetNumDataObjects(PRInt32* outNum) { *outNum = mDataObjects.Length(); }
STDMETHODIMP GetDataObjectAt(PRUint32 aItem, IDataObject** outItem) { *outItem = mDataObjects.SafeElementAt(aItem, nsRefPtr<IDataObject>()); }
#endif
void AddDataFlavor(const char * aDataFlavor, LPFORMATETC aFE);
// from nsPIDataObjCollection
void AddDataObject(IDataObject * aDataObj);
PRInt32 GetNumDataObjects() { return mDataObjects.Length(); }
IDataObject* GetDataObjectAt(PRUint32 aItem) { return mDataObjects.SafeElementAt(aItem, nsRefPtr<IDataObject>()); }
nsDataObj* GetDataObjectAt(PRUint32 aItem)
{ return mDataObjects.SafeElementAt(aItem, nsRefPtr<nsDataObj>()); }
// Return the registered OLE class ID of this object's CfDataObj.
CLSID GetClassID() const;
// Return the registered OLE class ID of this object's CfDataObj.
CLSID GetClassID() const;
public: // IDataObject methods - these are general comments. see CfDragDrop
// for overriding behavior
public:
// Store data in pSTM according to the format specified by pFE, if the
// format is supported (supported formats are specified in CfDragDrop::
// GetFormats) and return NOERROR; otherwise return DATA_E_FORMATETC. It
// is the callers responsibility to free pSTM if NOERROR is returned.
STDMETHODIMP GetData (LPFORMATETC pFE, LPSTGMEDIUM pSTM);
// Store data in pSTM according to the format specified by pFE, if the
// format is supported (supported formats are specified in CfDragDrop::
// GetFormats) and return NOERROR; otherwise return DATA_E_FORMATETC. It
// is the callers responsibility to free pSTM if NOERROR is returned.
STDMETHODIMP GetData (LPFORMATETC pFE, LPSTGMEDIUM pSTM);
// Similar to GetData except that the caller allocates the structure
// referenced by pSTM.
STDMETHODIMP GetDataHere (LPFORMATETC pFE, LPSTGMEDIUM pSTM);
// Similar to GetData except that the caller allocates the structure
// referenced by pSTM.
STDMETHODIMP GetDataHere (LPFORMATETC pFE, LPSTGMEDIUM pSTM);
// Returns S_TRUE if this object supports the format specified by pSTM,
// S_FALSE otherwise.
STDMETHODIMP QueryGetData (LPFORMATETC pFE);
// Returns S_TRUE if this object supports the format specified by pSTM,
// S_FALSE otherwise.
STDMETHODIMP QueryGetData (LPFORMATETC pFE);
// Set pCanonFE to the canonical format of pFE if one exists and return
// NOERROR, otherwise return DATA_S_SAMEFORMATETC. A canonical format
// implies an identical rendering.
STDMETHODIMP GetCanonicalFormatEtc (LPFORMATETC pFE, LPFORMATETC pCanonFE);
// Set pCanonFE to the canonical format of pFE if one exists and return
// NOERROR, otherwise return DATA_S_SAMEFORMATETC. A canonical format
// implies an identical rendering.
STDMETHODIMP GetCanonicalFormatEtc (LPFORMATETC pFE, LPFORMATETC pCanonFE);
// Set this objects data according to the format specified by pFE and
// the storage medium specified by pSTM and return NOERROR, if the format
// is supported. If release is TRUE this object must release the storage
// associated with pSTM.
STDMETHODIMP SetData (LPFORMATETC pFE, LPSTGMEDIUM pSTM, BOOL release);
// Set this objects data according to the format specified by pFE and
// the storage medium specified by pSTM and return NOERROR, if the format
// is supported. If release is TRUE this object must release the storage
// associated with pSTM.
STDMETHODIMP SetData (LPFORMATETC pFE, LPSTGMEDIUM pSTM, BOOL release);
// Set ppEnum to an IEnumFORMATETC object which will iterate all of the
// data formats that this object supports. direction is either DATADIR_GET
// or DATADIR_SET.
STDMETHODIMP EnumFormatEtc (DWORD direction, LPENUMFORMATETC* ppEnum);
// Set ppEnum to an IEnumFORMATETC object which will iterate all of the
// data formats that this object supports. direction is either DATADIR_GET
// or DATADIR_SET.
STDMETHODIMP EnumFormatEtc (DWORD direction, LPENUMFORMATETC* ppEnum);
// Set up an advisory connection to this object based on the format specified
// by pFE, flags, and the pAdvise. Set pConn to the established advise
// connection.
STDMETHODIMP DAdvise (LPFORMATETC pFE, DWORD flags, LPADVISESINK pAdvise,
DWORD* pConn);
// Set up an advisory connection to this object based on the format specified
// by pFE, flags, and the pAdvise. Set pConn to the established advise
// connection.
STDMETHODIMP DAdvise (LPFORMATETC pFE, DWORD flags, LPADVISESINK pAdvise,
DWORD* pConn);
// Turn off advising of a previous call to DAdvise which set pConn.
STDMETHODIMP DUnadvise (DWORD pConn);
// Turn off advising of a previous call to DAdvise which set pConn.
STDMETHODIMP DUnadvise (DWORD pConn);
// Set ppEnum to an IEnumSTATDATA object which will iterate over the
// existing objects which have established advisory connections to this
// Set ppEnum to an IEnumSTATDATA object which will iterate over the
// existing objects which have established advisory connections to this
// object.
STDMETHODIMP EnumDAdvise (LPENUMSTATDATA *ppEnum);
STDMETHODIMP EnumDAdvise (LPENUMSTATDATA *ppEnum);
public: // other methods
public:
// Set the adapter to dragDrop
//void SetDragDrop(CfDragDrop& dragDrop);
// Set the adapter to dragDrop
//void SetDragDrop(CfDragDrop& dragDrop);
// Return the adapter
//CfDragDrop& GetDragDrop() const;
// IAsyncOperation methods
STDMETHOD(EndOperation)(HRESULT hResult, IBindCtx *pbcReserved,
DWORD dwEffects);
STDMETHOD(GetAsyncMode)(BOOL *pfIsOpAsync);
STDMETHOD(InOperation)(BOOL *pfInAsyncOp);
STDMETHOD(SetAsyncMode)(BOOL fDoOpAsync);
STDMETHOD(StartOperation)(IBindCtx *pbcReserved);
// Return the adapter
//CfDragDrop& GetDragDrop() const;
protected:
protected:
BOOL FormatsMatch(const FORMATETC& source, const FORMATETC& target) const;
ULONG m_cRef; // the reference count
ULONG m_cRef; // the reference count
nsTArray<nsString> mDataFlavors;
// nsDataObjCollection owns and ref counts CEnumFormatEtc
CEnumFormatEtc * m_enumFE;
nsITransferable * mTransferable; // nsDataObjCollection owns and ref counts nsITransferable,
// the nsITransferable does know anything about the nsDataObjCollection
CEnumFormatEtc * m_enumFE; // Ownership Rules:
// nsDataObjCollection owns and ref counts CEnumFormatEtc,
nsTArray<nsRefPtr<IDataObject> > mDataObjects;
nsTArray<nsRefPtr<nsDataObj> > mDataObjects;
BOOL mIsAsyncMode;
BOOL mIsInOperation;
};
#endif //

View File

@ -230,6 +230,9 @@ nsDragService::InvokeDragSession(nsIDOMNode *aDOMNode,
rv = nsClipboard::CreateNativeDataObject(trans,
getter_AddRefs(dataObj), uri);
NS_ENSURE_SUCCESS(rv, rv);
// Add the flavors to the collection object too
rv = nsClipboard::SetupNativeDataObject(trans, dataObjCollection);
NS_ENSURE_SUCCESS(rv, rv);
dataObjCollection->AddDataObject(dataObj);
}

View File

@ -73,16 +73,21 @@ nsresult CheckValidHDROP(STGMEDIUM* pSTG)
fail("Received data is not Unicode");
return NS_ERROR_UNEXPECTED;
}
nsString s;
s = (PRUnichar*)((char*)pDropFiles + pDropFiles->pFiles);
nsresult rv;
nsCOMPtr<nsILocalFile> localFile(
do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
rv = localFile->InitWithPath(s);
if (NS_FAILED(rv)) {
fail("File could not be opened");
return NS_ERROR_UNEXPECTED;
unsigned long offset = 0;
while (1) {
s = (PRUnichar*)((char*)pDropFiles + pDropFiles->pFiles + offset);
if (s.IsEmpty())
break;
nsresult rv;
nsCOMPtr<nsILocalFile> localFile(
do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
rv = localFile->InitWithPath(s);
if (NS_FAILED(rv)) {
fail("File could not be opened");
return NS_ERROR_UNEXPECTED;
}
offset += sizeof(PRUnichar) * (s.Length() + 1);
}
return NS_OK;
}
@ -112,6 +117,31 @@ nsresult CheckValidTEXT(STGMEDIUM* pSTG)
return NS_OK;
}
nsresult CheckValidTEXTTwo(STGMEDIUM* pSTG)
{
if (pSTG->tymed != TYMED_HGLOBAL) {
fail("Received data is not in an HGLOBAL");
return NS_ERROR_UNEXPECTED;
}
HGLOBAL hGlobal = pSTG->hGlobal;
char* pText;
pText = (char*)GlobalLock(hGlobal);
if (!pText) {
fail("There is no data at the given HGLOBAL");
return NS_ERROR_UNEXPECTED;
}
nsCString string;
string = pText;
if (!string.Equals(NS_LITERAL_CSTRING("Mozilla can drag and drop twice over"))) {
fail("Text passed through drop object wrong");
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
}
nsresult CheckValidUNICODE(STGMEDIUM* pSTG)
{
if (pSTG->tymed != TYMED_HGLOBAL) {
@ -137,6 +167,31 @@ nsresult CheckValidUNICODE(STGMEDIUM* pSTG)
return NS_OK;
}
nsresult CheckValidUNICODETwo(STGMEDIUM* pSTG)
{
if (pSTG->tymed != TYMED_HGLOBAL) {
fail("Received data is not in an HGLOBAL");
return NS_ERROR_UNEXPECTED;
}
HGLOBAL hGlobal = pSTG->hGlobal;
PRUnichar* pText;
pText = (PRUnichar*)GlobalLock(hGlobal);
if (!pText) {
fail("There is no data at the given HGLOBAL");
return NS_ERROR_UNEXPECTED;
}
nsString string;
string = pText;
if (!string.Equals(NS_LITERAL_STRING("Mozilla can drag and drop twice over"))) {
fail("Text passed through drop object wrong");
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
}
nsresult GetTransferableFile(nsCOMPtr<nsITransferable>& pTransferable)
{
nsresult rv;
@ -166,6 +221,23 @@ nsresult GetTransferableText(nsCOMPtr<nsITransferable>& pTransferable)
return rv;
}
nsresult GetTransferableTextTwo(nsCOMPtr<nsITransferable>& pTransferable)
{
nsresult rv;
NS_NAMED_LITERAL_STRING(mozString, " twice over");
nsCOMPtr<nsISupportsString> xferString =
do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
rv = xferString->SetData(mozString);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsISupports> genericWrapper = do_QueryInterface(xferString);
pTransferable = do_CreateInstance("@mozilla.org/widget/transferable;1");
rv = pTransferable->SetTransferData("text/unicode", genericWrapper,
mozString.Length() * sizeof(PRUnichar));
return rv;
}
nsresult GetTransferableURI(nsCOMPtr<nsITransferable>& pTransferable)
{
nsresult rv;
@ -286,7 +358,75 @@ nsresult Do_CheckOneFile()
ReleaseStgMedium(stg);
return S_OK;
return NS_OK;
}
nsresult Do_CheckTwoFiles()
{
nsresult rv;
nsCOMPtr<nsITransferable> transferable;
nsCOMPtr<nsISupportsArray> transferableArray;
nsCOMPtr<nsISupports> genericWrapper;
nsRefPtr<IDataObject> dataObj;
rv = NS_NewISupportsArray(getter_AddRefs(transferableArray));
if (NS_FAILED(rv)) {
fail("Could not create the necessary nsISupportsArray");
return rv;
}
rv = GetTransferableFile(transferable);
if (NS_FAILED(rv)) {
fail("Could not create the proper nsITransferable!");
return rv;
}
genericWrapper = do_QueryInterface(transferable);
rv = transferableArray->AppendElement(genericWrapper);
if (NS_FAILED(rv)) {
fail("Could not append element to transferable array");
return rv;
}
rv = GetTransferableFile(transferable);
if (NS_FAILED(rv)) {
fail("Could not create the proper nsITransferable!");
return rv;
}
genericWrapper = do_QueryInterface(transferable);
rv = transferableArray->AppendElement(genericWrapper);
if (NS_FAILED(rv)) {
fail("Could not append element to transferable array");
return rv;
}
rv = MakeDataObject(transferableArray, dataObj);
if (NS_FAILED(rv)) {
fail("Could not create data object");
return rv;
}
FORMATETC fe;
SET_FORMATETC(fe, CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
if (dataObj->QueryGetData(&fe) != S_OK) {
fail("File data object does not support the file data type!");
return NS_ERROR_UNEXPECTED;
}
STGMEDIUM* stg;
stg = (STGMEDIUM*)CoTaskMemAlloc(sizeof(STGMEDIUM));
if (dataObj->GetData(&fe, stg) != S_OK) {
fail("File data object did not provide data on request");
return NS_ERROR_UNEXPECTED;
}
rv = CheckValidHDROP(stg);
if (NS_FAILED(rv)) {
fail("HDROP was invalid");
return rv;
}
ReleaseStgMedium(stg);
return NS_OK;
}
nsresult Do_CheckOneString()
@ -329,8 +469,7 @@ nsresult Do_CheckOneString()
STGMEDIUM* stg;
stg = (STGMEDIUM*)CoTaskMemAlloc(sizeof(STGMEDIUM));
HRESULT hr;
if ((hr = dataObj->GetData(&fe, stg)) != S_OK) {
if (dataObj->GetData(&fe, stg) != S_OK) {
fail("String data object did not provide ASCII data on request");
return NS_ERROR_UNEXPECTED;
}
@ -360,7 +499,178 @@ nsresult Do_CheckOneString()
return rv;
}
return S_OK;
return NS_OK;
}
nsresult Do_CheckTwoStrings()
{
nsresult rv;
nsCOMPtr<nsITransferable> transferable;
nsCOMPtr<nsISupportsArray> transferableArray;
nsCOMPtr<nsISupports> genericWrapper;
nsRefPtr<IDataObject> dataObj;
rv = NS_NewISupportsArray(getter_AddRefs(transferableArray));
if (NS_FAILED(rv)) {
fail("Could not create the necessary nsISupportsArray");
return rv;
}
rv = GetTransferableText(transferable);
if (NS_FAILED(rv)) {
fail("Could not create the proper nsITransferable!");
return rv;
}
genericWrapper = do_QueryInterface(transferable);
rv = transferableArray->AppendElement(genericWrapper);
if (NS_FAILED(rv)) {
fail("Could not append element to transferable array");
return rv;
}
rv = GetTransferableTextTwo(transferable);
if (NS_FAILED(rv)) {
fail("Could not create the proper nsITransferable!");
return rv;
}
genericWrapper = do_QueryInterface(transferable);
rv = transferableArray->AppendElement(genericWrapper);
if (NS_FAILED(rv)) {
fail("Could not append element to transferable array");
return rv;
}
rv = MakeDataObject(transferableArray, dataObj);
if (NS_FAILED(rv)) {
fail("Could not create data object");
return rv;
}
FORMATETC fe;
SET_FORMATETC(fe, CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
if (dataObj->QueryGetData(&fe) != S_OK) {
fail("String data object does not support the ASCII text data type!");
return NS_ERROR_UNEXPECTED;
}
STGMEDIUM* stg;
stg = (STGMEDIUM*)CoTaskMemAlloc(sizeof(STGMEDIUM));
if (dataObj->GetData(&fe, stg) != S_OK) {
fail("String data object did not provide ASCII data on request");
return NS_ERROR_UNEXPECTED;
}
rv = CheckValidTEXTTwo(stg);
if (NS_FAILED(rv)) {
fail("TEXT was invalid");
return rv;
}
ReleaseStgMedium(stg);
SET_FORMATETC(fe, CF_UNICODETEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
if (dataObj->QueryGetData(&fe) != S_OK) {
fail("String data object does not support the wide text data type!");
return NS_ERROR_UNEXPECTED;
}
if (dataObj->GetData(&fe, stg) != S_OK) {
fail("String data object did not provide wide data on request");
return NS_ERROR_UNEXPECTED;
}
rv = CheckValidUNICODETwo(stg);
if (NS_FAILED(rv)) {
fail("UNICODE was invalid");
return rv;
}
return NS_OK;
}
nsresult Do_CheckSetArbitraryData(PRBool aMultiple)
{
nsresult rv;
nsCOMPtr<nsITransferable> transferable;
nsCOMPtr<nsISupportsArray> transferableArray;
nsCOMPtr<nsISupports> genericWrapper;
nsRefPtr<IDataObject> dataObj;
rv = NS_NewISupportsArray(getter_AddRefs(transferableArray));
if (NS_FAILED(rv)) {
fail("Could not create the necessary nsISupportsArray");
return rv;
}
rv = GetTransferableText(transferable);
if (NS_FAILED(rv)) {
fail("Could not create the proper nsITransferable!");
return rv;
}
genericWrapper = do_QueryInterface(transferable);
rv = transferableArray->AppendElement(genericWrapper);
if (NS_FAILED(rv)) {
fail("Could not append element to transferable array");
return rv;
}
if (aMultiple) {
rv = GetTransferableText(transferable);
if (NS_FAILED(rv)) {
fail("Could not create the proper nsITransferable!");
return rv;
}
genericWrapper = do_QueryInterface(transferable);
rv = transferableArray->AppendElement(genericWrapper);
if (NS_FAILED(rv)) {
fail("Could not append element to transferable array");
return rv;
}
}
rv = MakeDataObject(transferableArray, dataObj);
if (NS_FAILED(rv)) {
fail("Could not create data object");
return rv;
}
static CLIPFORMAT mozArbitraryFormat =
::RegisterClipboardFormatW(L"MozillaTestFormat");
FORMATETC fe;
STGMEDIUM stg;
SET_FORMATETC(fe, mozArbitraryFormat, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
HGLOBAL hg = GlobalAlloc(GPTR, 1024);
stg.tymed = TYMED_HGLOBAL;
stg.hGlobal = hg;
stg.pUnkForRelease = NULL;
if (dataObj->SetData(&fe, &stg, true) != S_OK) {
if (aMultiple) {
fail("Unable to set arbitrary data type on data object collection!");
} else {
fail("Unable to set arbitrary data type on data object!");
}
return NS_ERROR_UNEXPECTED;
}
if (dataObj->QueryGetData(&fe) != S_OK) {
fail("Arbitrary data set on data object is not advertised!");
return NS_ERROR_UNEXPECTED;
}
STGMEDIUM* stg2;
stg2 = (STGMEDIUM*)CoTaskMemAlloc(sizeof(STGMEDIUM));
if (dataObj->GetData(&fe, stg2) != S_OK) {
fail("Data object did not provide arbitrary data upon request!");
return NS_ERROR_UNEXPECTED;
}
if (stg2->hGlobal != hg) {
fail("Arbitrary data was not returned properly!");
return rv;
}
ReleaseStgMedium(stg2);
return NS_OK;
}
// This function performs basic drop tests, testing a data object consisting
@ -386,6 +696,59 @@ nsresult Do_Test1()
passed("Successfully created a working string drag object!");
}
workingrv = Do_CheckSetArbitraryData(false);
if (NS_FAILED(workingrv)) {
fail("Drag object tests failed on setting arbitrary data");
rv = NS_ERROR_UNEXPECTED;
} else {
passed("Successfully set arbitrary data on a drag object");
}
return rv;
}
// This function performs basic drop tests, testing a data object consisting of
// two transferables.
nsresult Do_Test2()
{
nsresult rv = NS_OK;
nsresult workingrv;
workingrv = Do_CheckTwoFiles();
if (NS_FAILED(workingrv)) {
fail("Drag object tests failed on multiple files");
rv = NS_ERROR_UNEXPECTED;
} else {
passed("Successfully created a working multiple file drag object!");
}
workingrv = Do_CheckTwoStrings();
if (NS_FAILED(workingrv)) {
fail("Drag object tests failed on multiple strings");
rv = NS_ERROR_UNEXPECTED;
} else {
passed("Successfully created a working multiple string drag object!");
}
workingrv = Do_CheckSetArbitraryData(true);
if (NS_FAILED(workingrv)) {
fail("Drag object tests failed on setting arbitrary data");
rv = NS_ERROR_UNEXPECTED;
} else {
passed("Successfully set arbitrary data on a drag object");
}
return rv;
}
// This function performs advanced drag and drop tests, testing a data object
// consisting of multiple transferables that have different data types
nsresult Do_Test3()
{
nsresult rv = NS_OK;
nsresult workingrv;
// XXX TODO Write more advanced tests in Bug 535860
return rv;
}
@ -398,7 +761,13 @@ int main(int argc, char** argv)
xferFile = file;
if (NS_SUCCEEDED(Do_Test1()))
passed("Basic Drag and Drop data type tests succeeded!");
passed("Basic Drag and Drop data type tests (single transferable) succeeded!");
if (NS_SUCCEEDED(Do_Test2()))
passed("Basic Drag and Drop data type tests (multiple transferables) succeeded!");
//if (NS_SUCCEEDED(Do_Test3()))
// passed("Advanced Drag and Drop data type tests succeeded!");
return gFailCount;
}