Bug 244685 Implement SourceURL for CF_HTML clipboard copy/drag'n'drop p=david.gardiner@unisa.edu.au r=dean_tessman sr=me

This commit is contained in:
neil%parkwaycc.co.uk 2004-12-07 14:13:54 +00:00
parent 0343a92091
commit c4c3378210
6 changed files with 175 additions and 76 deletions

View File

@ -21,6 +21,7 @@
*
* Contributor(s):
* Kathleen Brade <brade@netscape.com>
* David Gardiner <david.gardiner@unisa.edu.au>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -78,48 +79,70 @@ nsresult nsCopySupport::HTMLCopy(nsISelection *aSel, nsIDocument *aDoc, PRInt16
{
nsresult rv = NS_OK;
PRBool bIsPlainTextContext = PR_FALSE;
rv = IsPlainTextContext(aSel, aDoc, &bIsPlainTextContext);
if (NS_FAILED(rv))
return rv;
PRBool bIsHTMLCopy = !bIsPlainTextContext;
nsAutoString mimeType;
nsCOMPtr<nsIDocumentEncoder> docEncoder;
docEncoder = do_CreateInstance(NS_HTMLCOPY_ENCODER_CONTRACTID);
NS_ENSURE_TRUE(docEncoder, NS_ERROR_FAILURE);
PRBool bIsPlainTextContext = PR_FALSE;
rv = IsPlainTextContext(aSel, aDoc, &bIsPlainTextContext);
if (NS_FAILED(rv)) return rv;
PRBool bIsHTMLCopy = !bIsPlainTextContext;
PRUint32 flags = 0;
nsAutoString mimeType;
if (bIsHTMLCopy)
mimeType.AssignLiteral(kHTMLMime);
else
{
flags |= nsIDocumentEncoder::OutputBodyOnly | nsIDocumentEncoder::OutputPreformatted;
mimeType.AssignLiteral(kUnicodeMime);
}
// We always require a plaintext version
mimeType.AssignLiteral(kUnicodeMime);
PRUint32 flags = nsIDocumentEncoder::OutputPreformatted;
rv = docEncoder->Init(aDoc, mimeType, flags);
if (NS_FAILED(rv)) return rv;
if (NS_FAILED(rv))
return rv;
rv = docEncoder->SetSelection(aSel);
if (NS_FAILED(rv)) return rv;
nsAutoString buffer, parents, info;
if (NS_FAILED(rv))
return rv;
nsAutoString buffer, parents, info, shortcut, textBuffer, plaintextBuffer;
rv = docEncoder->EncodeToString(textBuffer);
if (NS_FAILED(rv))
return rv;
// this string may still contain HTML formatting, so we need to remove that too.
nsCOMPtr<nsIFormatConverter> htmlConverter = do_CreateInstance(kHTMLConverterCID);
NS_ENSURE_TRUE(htmlConverter, NS_ERROR_FAILURE);
nsCOMPtr<nsISupportsString> plainHTML;
plainHTML = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
NS_ENSURE_TRUE(plainHTML, NS_ERROR_FAILURE);
nsresult plainhtml_rv = plainHTML->SetData(textBuffer);
nsCOMPtr<nsISupportsString> ConvertedData;
PRUint32 ConvertedLen;
htmlConverter->Convert(kHTMLMime, plainHTML, textBuffer.Length() * 2, kUnicodeMime, getter_AddRefs(ConvertedData), &ConvertedLen);
nsresult converted_rv = ConvertedData->GetData(plaintextBuffer);
// sometimes we also need the HTML version
if (bIsHTMLCopy) {
mimeType.AssignLiteral(kHTMLMime);
flags = 0;
rv = docEncoder->Init(aDoc, mimeType, flags);
if (NS_FAILED(rv))
return rv;
rv = docEncoder->SetSelection(aSel);
if (NS_FAILED(rv))
return rv;
if (bIsHTMLCopy)
{
// encode the selection as html with contextual info
rv = docEncoder->EncodeToStringWithContext(buffer, parents, info);
if (NS_FAILED(rv))
return rv;
}
else
{
// encode the selection
rv = docEncoder->EncodeToString(buffer);
if (NS_FAILED(rv))
return rv;
}
// Get the Clipboard
@ -133,47 +156,58 @@ nsresult nsCopySupport::HTMLCopy(nsISelection *aSel, nsIDocument *aDoc, PRInt16
nsCOMPtr<nsITransferable> trans = do_CreateInstance(kCTransferableCID);
if ( trans )
{
nsCOMPtr<nsISupportsString> textWrapper;
textWrapper = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
NS_ENSURE_TRUE(textWrapper, NS_ERROR_FAILURE);
nsresult text_rv = textWrapper->SetData(plaintextBuffer);
if (bIsHTMLCopy)
{
// set up the data converter
nsCOMPtr<nsIFormatConverter> htmlConverter = do_CreateInstance(kHTMLConverterCID);
NS_ENSURE_TRUE(htmlConverter, NS_ERROR_FAILURE);
trans->SetConverter(htmlConverter);
}
// get wStrings to hold clip data
nsCOMPtr<nsISupportsString> dataWrapper, contextWrapper, infoWrapper;
dataWrapper = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
NS_ENSURE_TRUE(dataWrapper, NS_ERROR_FAILURE);
if (bIsHTMLCopy)
{
// get wStrings to hold clip data
nsCOMPtr<nsISupportsString> dataWrapper, contextWrapper, infoWrapper, urlWrapper;
dataWrapper = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
NS_ENSURE_TRUE(dataWrapper, NS_ERROR_FAILURE);
contextWrapper = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
NS_ENSURE_TRUE(contextWrapper, NS_ERROR_FAILURE);
infoWrapper = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
NS_ENSURE_TRUE(infoWrapper, NS_ERROR_FAILURE);
}
// populate the strings
nsresult data_rv = NS_OK, context_rv = NS_OK, info_rv = NS_OK;
data_rv =
dataWrapper->SetData(buffer);
if (bIsHTMLCopy)
{
context_rv =
contextWrapper->SetData(parents);
info_rv =
infoWrapper->SetData(info);
}
// QI the data object an |nsISupports| so that when the transferable holds
// onto it, it will addref the correct interface.
nsCOMPtr<nsISupports> genericDataObj ( do_QueryInterface(dataWrapper) );
if (bIsHTMLCopy)
{
urlWrapper = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
NS_ENSURE_TRUE(urlWrapper, NS_ERROR_FAILURE);
// populate the strings
nsresult data_rv = dataWrapper->SetData(buffer);
nsresult context_rv = contextWrapper->SetData(parents);
nsresult info_rv = infoWrapper->SetData(info);
// Try and get source URI of the items that are being dragged
nsIURI *uri = aDoc->GetDocumentURI();
nsCAutoString spec;
uri->GetSpec(spec);
AppendUTF8toUTF16(spec, shortcut);
shortcut.Append(PRUnichar('\n'));
// and get document title
shortcut.Append(aDoc->GetDocumentTitle());
nsresult url_rv = urlWrapper->SetData(shortcut);
// QI the data object an |nsISupports| so that when the transferable holds
// onto it, it will addref the correct interface.
nsCOMPtr<nsISupports> genericDataObj;
if (!buffer.IsEmpty() && NS_SUCCEEDED(data_rv))
{
// Add the html DataFlavor to the transferable
trans->AddDataFlavor(kHTMLMime);
genericDataObj = do_QueryInterface(dataWrapper);
trans->SetTransferData(kHTMLMime, genericDataObj, buffer.Length()*2);
}
if (!parents.IsEmpty() && NS_SUCCEEDED(context_rv))
@ -190,14 +224,37 @@ nsresult nsCopySupport::HTMLCopy(nsISelection *aSel, nsIDocument *aDoc, PRInt16
genericDataObj = do_QueryInterface(infoWrapper);
trans->SetTransferData(kHTMLInfo, genericDataObj, info.Length()*2);
}
if (!plaintextBuffer.IsEmpty() && NS_SUCCEEDED(text_rv))
{
// unicode text
// Add the unicode DataFlavor to the transferable
// If we didn't have this, then nsDataObj::GetData matches text/unicode against
// the kURLMime flavour which is not desirable (eg. when pasting into Notepad)
trans->AddDataFlavor(kUnicodeMime);
genericDataObj = do_QueryInterface(textWrapper);
trans->SetTransferData(kUnicodeMime, genericDataObj, plaintextBuffer.Length()*2);
}
// url
if (!shortcut.IsEmpty() && NS_SUCCEEDED(url_rv))
{
// Add the URL DataFlavor to the transferable
trans->AddDataFlavor(kURLMime);
genericDataObj = do_QueryInterface(urlWrapper);
trans->SetTransferData(kURLMime, genericDataObj, shortcut.Length()*2);
}
}
else
{
if (!buffer.IsEmpty() && NS_SUCCEEDED(data_rv))
// QI the data object an |nsISupports| so that when the transferable holds
// onto it, it will addref the correct interface.
nsCOMPtr<nsISupports> genericDataObj ( do_QueryInterface(textWrapper) );
if (!plaintextBuffer.IsEmpty() && NS_SUCCEEDED(text_rv))
{
// Add the unicode DataFlavor to the transferable
trans->AddDataFlavor(kUnicodeMime);
trans->SetTransferData(kUnicodeMime, genericDataObj, buffer.Length()*2);
trans->SetTransferData(kUnicodeMime, genericDataObj, plaintextBuffer.Length()*2);
}
}

View File

@ -22,6 +22,7 @@
* Contributor(s):
* Pierre Phaneuf <pp@ludusdesign.com>
* Sean Echevarria <sean@beatnik.com>
* David Gardiner <david.gardiner@unisa.edu.au>
*
* 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
@ -130,7 +131,7 @@ UINT nsClipboard::GetFormat(const char* aMimeStr)
}
//-------------------------------------------------------------------------
nsresult nsClipboard::CreateNativeDataObject(nsITransferable * aTransferable, IDataObject ** aDataObj)
nsresult nsClipboard::CreateNativeDataObject(nsITransferable * aTransferable, IDataObject ** aDataObj, nsIURI * uri)
{
if (nsnull == aTransferable) {
return NS_ERROR_FAILURE;
@ -138,8 +139,11 @@ nsresult nsClipboard::CreateNativeDataObject(nsITransferable * aTransferable, ID
// Create our native DataObject that implements
// the OLE IDataObject interface
nsDataObj * dataObj;
dataObj = new nsDataObj();
nsDataObj * dataObj = new nsDataObj(uri);
if (!dataObj)
return NS_ERROR_OUT_OF_MEMORY;
dataObj->AddRef();
// No set it up with all the right data flavors & enums
@ -270,7 +274,7 @@ NS_IMETHODIMP nsClipboard::SetNativeClipboardData ( PRInt32 aWhichClipboard )
::OleSetClipboard(NULL);
IDataObject * dataObj;
if ( NS_SUCCEEDED(CreateNativeDataObject(mTransferable, &dataObj)) ) { // this add refs
if ( NS_SUCCEEDED(CreateNativeDataObject(mTransferable, &dataObj, NULL)) ) { // this add refs dataObj
::OleSetClipboard(dataObj);
dataObj->Release();
}

View File

@ -40,6 +40,7 @@
#include "nsBaseClipboard.h"
#include "nsIObserver.h"
#include "nsIURI.h"
#include <windows.h>
class nsITransferable;
@ -70,7 +71,8 @@ public:
// Internal Native Routines
static nsresult CreateNativeDataObject(nsITransferable * aTransferable,
IDataObject ** aDataObj);
IDataObject ** aDataObj,
nsIURI * uri);
static nsresult SetupNativeDataObject(nsITransferable * aTransferable,
IDataObject * aDataObj);
static nsresult GetDataFromDataObject(IDataObject * aDataObject,

View File

@ -24,6 +24,7 @@
* Blake Ross <blaker@netscape.com>
* Brodie Thiesfield <brofield@jellycan.com>
* Masayuki Nakano <masayuki@d-toybox.com>
* David Gardiner <david.gardiner@unisa.edu.au>
*
* 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
@ -104,16 +105,21 @@ EXTERN_C GUID CDECL CLSID_nsDataObj =
//-----------------------------------------------------
// construction
//-----------------------------------------------------
nsDataObj::nsDataObj()
nsDataObj::nsDataObj(nsIURI * uri)
: m_cRef(0), mTransferable(nsnull)
{
m_cRef = 0;
mTransferable = nsnull;
mDataFlavors = new nsVoidArray();
m_enumFE = new CEnumFormatEtc(32);
m_enumFE->AddRef();
m_enumFE = new CEnumFormatEtc(32);
m_enumFE->AddRef();
if (uri) {
// A URI was obtained, so pass this through to the DataObject
// so it can create a SourceURL for CF_HTML flavour
uri->GetSpec(mSourceURL);
}
}
//-----------------------------------------------------
// destruction
//-----------------------------------------------------
@ -1189,8 +1195,18 @@ nsDataObj :: BuildPlatformHTML ( const char* inOurHTML, char** outPlatformHTML )
const char* const endHTMLPrefix = "\r\nEndHTML:";
const char* const startFragPrefix = "\r\nStartFragment:";
const char* const endFragPrefix = "\r\nEndFragment:";
const char* const startSourceURLPrefix = "\r\nSourceURL:";
const char* const endFragTrailer = "\r\n";
// Do we already have mSourceURL from a drag?
if (mSourceURL.IsEmpty()) {
nsAutoString url;
ExtractShortcutURL(url);
AppendUTF16toUTF8(url, mSourceURL);
}
const PRInt32 kSourceURLLength = mSourceURL.Length();
const PRInt32 kNumberLength = strlen(numPlaceholder);
const PRInt32 kTotalHeaderLen = strlen(startHTMLPrefix) +
@ -1198,6 +1214,8 @@ nsDataObj :: BuildPlatformHTML ( const char* inOurHTML, char** outPlatformHTML )
strlen(startFragPrefix) +
strlen(endFragPrefix) +
strlen(endFragTrailer) +
(kSourceURLLength > 0 ? strlen(startSourceURLPrefix) : 0) +
kSourceURLLength +
(4 * kNumberLength);
NS_NAMED_LITERAL_CSTRING(htmlHeaderString, "<html><body>\r\n");
@ -1237,6 +1255,9 @@ nsDataObj :: BuildPlatformHTML ( const char* inOurHTML, char** outPlatformHTML )
clipboardString.Append(endFragPrefix);
clipboardString.Append(nsPrintfCString("%08u", endFragOffset));
clipboardString.Append(startSourceURLPrefix);
clipboardString.Append(mSourceURL);
clipboardString.Append(endFragTrailer);
clipboardString.Append(htmlHeaderString);

View File

@ -47,6 +47,7 @@
//#include "Ddforw.h"
#include "nsString.h"
#include "nsILocalFile.h"
#include "nsIURI.h"
#define MAX_FORMATS 32
@ -73,9 +74,9 @@ class nsITransferable;
*/
class nsDataObj : public IDataObject
{
public: // construction, destruction
nsDataObj();
~nsDataObj();
public: // construction, destruction
nsDataObj(nsIURI *uri = nsnull);
~nsDataObj();
public: // IUnknown methods - see iunknown.h for documentation
STDMETHODIMP_(ULONG) AddRef ();
@ -182,6 +183,9 @@ class nsDataObj : public IDataObject
// munge our HTML data to win32's CF_HTML spec. Will null terminate
nsresult BuildPlatformHTML ( const char* inOurHTML, char** outPlatformHTML ) ;
// Used for the SourceURL part of CF_HTML
nsCString mSourceURL;
nsString mStringData;
BOOL FormatsMatch(const FORMATETC& source, const FORMATETC& target) const;

View File

@ -22,6 +22,7 @@
* Contributor(s):
* Mike Pinkerton (pinkerton@netscape.com)
* Mark Hammond (MarkH@ActiveState.com)
* David Gardiner <david.gardiner@unisa.edu.au>
*
* 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
@ -53,6 +54,7 @@
#include "nsNativeDragSource.h"
#include "nsClipboard.h"
#include "nsISupportsArray.h"
#include "nsIDocument.h"
#include "nsDataObjCollection.h"
#include "nsAutoPtr.h"
@ -89,6 +91,15 @@ NS_IMETHODIMP nsDragService::InvokeDragSession (nsIDOMNode *aDOMNode, nsISupport
nsBaseDragService::InvokeDragSession ( aDOMNode, anArrayTransferables, aRegion, aActionType );
nsresult rv;
// Try and get source URI of the items that are being dragged
nsIURI *uri = nsnull;
nsCOMPtr<nsIDocument> doc(do_QueryInterface(mSourceDocument));
if (doc) {
uri = doc->GetDocumentURI();
}
PRUint32 numItemsToDrag = 0;
rv = anArrayTransferables->Count(&numItemsToDrag);
if ( !numItemsToDrag )
@ -112,7 +123,7 @@ NS_IMETHODIMP nsDragService::InvokeDragSession (nsIDOMNode *aDOMNode, nsISupport
nsCOMPtr<nsITransferable> trans(do_QueryInterface(supports));
if ( trans ) {
nsRefPtr<IDataObject> dataObj;
if ( NS_SUCCEEDED(nsClipboard::CreateNativeDataObject(trans, getter_AddRefs(dataObj))) ) {
if ( NS_SUCCEEDED(nsClipboard::CreateNativeDataObject(trans, getter_AddRefs(dataObj), uri)) ) {
dataObjCollection->AddDataObject(dataObj);
}
else
@ -125,7 +136,7 @@ NS_IMETHODIMP nsDragService::InvokeDragSession (nsIDOMNode *aDOMNode, nsISupport
anArrayTransferables->GetElementAt(0, getter_AddRefs(supports));
nsCOMPtr<nsITransferable> trans(do_QueryInterface(supports));
if ( trans ) {
if ( NS_FAILED(nsClipboard::CreateNativeDataObject(trans, getter_AddRefs(itemToDrag))) )
if ( NS_FAILED(nsClipboard::CreateNativeDataObject(trans, getter_AddRefs(itemToDrag), uri)) )
return NS_ERROR_FAILURE;
}
} // else dragging a single object