mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 513464: Add support for multiple drags outside of Gecko r=jimm
--HG-- extra : rebase_source : a7b2f1d7b81946baa47793a8c5cdf8da59c42fd4
This commit is contained in:
parent
8038a1962b
commit
87cb614d99
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
@ -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 //
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user