From 672b3839a43f274ee1ae5982ff675efb34dd42ca Mon Sep 17 00:00:00 2001 From: "brade%netscape.com" Date: Thu, 17 Apr 2003 13:18:51 +0000 Subject: [PATCH] editor changes for drag/drop/copy/paste hooks (bug 197121) r=jfrancis, sr=smfr git-svn-id: svn://10.0.0.236/trunk@141304 18797224-902f-48f8-a5cc-f745e15eee43 --- .../libeditor/html/nsHTMLDataTransfer.cpp | 299 +++++-------- mozilla/editor/libeditor/html/nsHTMLEditor.h | 1 + mozilla/editor/libeditor/text/Makefile.in | 1 + .../text/nsPlaintextDataTransfer.cpp | 411 +++++++++++++----- .../editor/libeditor/text/nsPlaintextEditor.h | 6 + 5 files changed, 414 insertions(+), 304 deletions(-) diff --git a/mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp b/mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp index 11b8433b72e..a13968ea82e 100644 --- a/mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp +++ b/mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp @@ -1163,6 +1163,12 @@ NS_IMETHODIMP nsHTMLEditor::InsertFromDrop(nsIDOMEvent* aDropEvent) dragService->GetCurrentSession(getter_AddRefs(dragSession)); if (!dragSession) return NS_OK; + // transferable hooks here + PRBool isAllowed = PR_TRUE; + DoAllowDropHook(aDropEvent, dragSession, &isAllowed); + if (!isAllowed) + return NS_OK; + // find out if we have our internal html flavor on the clipboard. We don't want to mess // around with cfhtml if we do. PRBool bHavePrivateHTMLFlavor = PR_FALSE; @@ -1302,7 +1308,6 @@ NS_IMETHODIMP nsHTMLEditor::InsertFromDrop(nsIDOMEvent* aDropEvent) } // We never have to delete if selection is already collapsed - PRBool deleteSelection = PR_FALSE; PRBool cursorIsInSelection = PR_FALSE; // Check if mouse is in the selection @@ -1370,232 +1375,120 @@ NS_IMETHODIMP nsHTMLEditor::InsertFromDrop(nsIDOMEvent* aDropEvent) NS_IMETHODIMP nsHTMLEditor::CanDrag(nsIDOMEvent *aDragEvent, PRBool *aCanDrag) { - if (!aCanDrag) - return NS_ERROR_NULL_POINTER; - - /* we really should be checking the XY coordinates of the mouseevent and ensure that - * that particular point is actually within the selection (not just that there is a selection) - */ - *aCanDrag = PR_FALSE; - - // KLUDGE to work around bug 50703 - // After double click and object property editing, - // we get a spurious drag event - if (mIgnoreSpuriousDragEvent) - { -#ifdef DEBUG_cmanske - printf(" *** IGNORING SPURIOUS DRAG EVENT!\n"); -#endif - mIgnoreSpuriousDragEvent = PR_FALSE; - return NS_OK; - } - - nsCOMPtr selection; - nsresult res = GetSelection(getter_AddRefs(selection)); - if (NS_FAILED(res)) return res; - - PRBool isCollapsed; - res = selection->GetIsCollapsed(&isCollapsed); - if (NS_FAILED(res)) return res; - - // if we are collapsed, we have no selection so nothing to drag - if (isCollapsed) - return NS_OK; - - nsCOMPtr eventTarget; - - nsCOMPtr nsevent(do_QueryInterface(aDragEvent)); - - if (nsevent) - { - res = nsevent->GetExplicitOriginalTarget(getter_AddRefs(eventTarget)); - if (NS_FAILED(res)) - { - return res; - } - } - - if (eventTarget) - { - nsCOMPtr eventTargetDomNode = do_QueryInterface(eventTarget); - if (eventTargetDomNode) - { - PRBool isTargetedCorrectly = PR_FALSE; - res = selection->ContainsNode(eventTargetDomNode, PR_FALSE, &isTargetedCorrectly); - if (NS_FAILED(res)) return res; - - *aCanDrag = isTargetedCorrectly; - } - } - - return NS_OK; + return nsPlaintextEditor::CanDrag(aDragEvent, aCanDrag); } -NS_IMETHODIMP nsHTMLEditor::DoDrag(nsIDOMEvent *aDragEvent) +nsresult +nsHTMLEditor::PutDragDataInTransferable(nsITransferable **aTransferable) { - nsresult rv; - - nsCOMPtr eventTarget; - rv = aDragEvent->GetTarget(getter_AddRefs(eventTarget)); + NS_ENSURE_ARG_POINTER(aTransferable); + *aTransferable = nsnull; + nsCOMPtr docEncoder; + nsresult rv = SetupDocEncoder(getter_AddRefs(docEncoder)); if (NS_FAILED(rv)) return rv; - nsCOMPtr domnode = do_QueryInterface(eventTarget); + NS_ENSURE_TRUE(docEncoder, NS_ERROR_FAILURE); - /* get the selection to be dragged */ - nsCOMPtr selection; - rv = GetSelection(getter_AddRefs(selection)); + // grab a string + nsAutoString buffer, parents, info; + + // find out if we're a plaintext control or not + PRUint32 editorFlags = 0; + rv = GetFlags(&editorFlags); if (NS_FAILED(rv)) return rv; - /* create an array of transferables */ - nsCOMPtr transferableArray; - NS_NewISupportsArray(getter_AddRefs(transferableArray)); - if (transferableArray == nsnull) - return NS_ERROR_OUT_OF_MEMORY; + PRBool bIsPlainTextControl = ((editorFlags & eEditorPlaintextMask) != 0); + if (!bIsPlainTextControl) + { + // 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 drag service */ - nsCOMPtr dragService = - do_GetService("@mozilla.org/widget/dragservice;1", &rv); + // if we have an empty string, we're done; otherwise continue + if ( buffer.IsEmpty() ) + return NS_OK; + + nsCOMPtr dataWrapper, contextWrapper, infoWrapper; + + dataWrapper = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + rv = dataWrapper->SetData(buffer); if (NS_FAILED(rv)) return rv; /* create html flavor transferable */ nsCOMPtr trans = do_CreateInstance(kCTransferableCID); NS_ENSURE_TRUE(trans, NS_ERROR_FAILURE); - nsCOMPtr domdoc; - rv = GetDocument(getter_AddRefs(domdoc)); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr doc = do_QueryInterface(domdoc); - if (doc) + if (bIsPlainTextControl) { - // find out if we're a plaintext control or not - PRUint32 editorFlags = 0; - rv = GetFlags(&editorFlags); + // Add the unicode flavor to the transferable + rv = trans->AddDataFlavor(kUnicodeMime); if (NS_FAILED(rv)) return rv; - PRBool bIsPlainTextControl = ((editorFlags & eEditorPlaintextMask) != 0); - - // get correct mimeType and document encoder flags set - nsAutoString mimeType; - PRUint32 docEncoderFlags = 0; - if (bIsPlainTextControl) - { - docEncoderFlags |= nsIDocumentEncoder::OutputBodyOnly | nsIDocumentEncoder::OutputPreformatted; - mimeType = NS_LITERAL_STRING(kUnicodeMime); - } - else - mimeType = NS_LITERAL_STRING(kHTMLMime); - - // set up docEncoder - nsCOMPtr docEncoder = do_CreateInstance(NS_HTMLCOPY_ENCODER_CONTRACTID); - NS_ENSURE_TRUE(docEncoder, NS_ERROR_FAILURE); - - rv = docEncoder->Init(doc, mimeType, docEncoderFlags); + // QI the data object an |nsISupports| so that when the transferable holds + // onto it, it will addref the correct interface. + nsCOMPtr genericDataObj(do_QueryInterface(dataWrapper)); + rv = trans->SetTransferData(kUnicodeMime, genericDataObj, + buffer.Length() * sizeof(PRUnichar)); if (NS_FAILED(rv)) return rv; - - rv = docEncoder->SetSelection(selection); + } + else + { + 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); + + contextWrapper->SetData(parents); + infoWrapper->SetData(info); + + rv = trans->AddDataFlavor(kHTMLMime); if (NS_FAILED(rv)) return rv; - // grab a string - nsAutoString buffer, parents, info; + nsCOMPtr htmlConverter = do_CreateInstance(kCHTMLFormatConverterCID); + NS_ENSURE_TRUE(htmlConverter, NS_ERROR_FAILURE); - if (!bIsPlainTextControl) + rv = trans->SetConverter(htmlConverter); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr genericDataObj(do_QueryInterface(dataWrapper)); + rv = trans->SetTransferData(kHTMLMime, genericDataObj, + buffer.Length() * sizeof(PRUnichar)); + if (NS_FAILED(rv)) return rv; + + if (!parents.IsEmpty()) { - // encode the selection as html with contextual info - rv = docEncoder->EncodeToStringWithContext(buffer, parents, info); - if (NS_FAILED(rv)) return rv; + // Add the htmlcontext DataFlavor to the transferable + trans->AddDataFlavor(kHTMLContext); + genericDataObj = do_QueryInterface(contextWrapper); + trans->SetTransferData(kHTMLContext, genericDataObj, + parents.Length() * sizeof(PRUnichar)); } - else + if (!info.IsEmpty()) { - // encode the selection - rv = docEncoder->EncodeToString(buffer); - if (NS_FAILED(rv)) return rv; - } - - // if we have an empty string, we're done; otherwise continue - if (!buffer.IsEmpty()) - { - nsCOMPtr dataWrapper, contextWrapper, infoWrapper; - - dataWrapper = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID); - NS_ENSURE_TRUE(dataWrapper, NS_ERROR_FAILURE); - rv = dataWrapper->SetData(buffer); - if (NS_FAILED(rv)) return rv; - - if (bIsPlainTextControl) - { - // Add the unicode flavor to the transferable - rv = trans->AddDataFlavor(kUnicodeMime); - if (NS_FAILED(rv)) return rv; - - // QI the data object an |nsISupports| so that when the transferable holds - // onto it, it will addref the correct interface. - nsCOMPtr genericDataObj(do_QueryInterface(dataWrapper)); - rv = trans->SetTransferData(kUnicodeMime, genericDataObj, buffer.Length() * 2); - if (NS_FAILED(rv)) return rv; - } - else - { - 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); - - contextWrapper->SetData(parents); - infoWrapper->SetData(info); - - rv = trans->AddDataFlavor(kHTMLMime); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr htmlConverter = do_CreateInstance(kCHTMLFormatConverterCID); - NS_ENSURE_TRUE(htmlConverter, NS_ERROR_FAILURE); - - rv = trans->SetConverter(htmlConverter); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr genericDataObj(do_QueryInterface(dataWrapper)); - rv = trans->SetTransferData(kHTMLMime, genericDataObj, buffer.Length() * 2); - if (NS_FAILED(rv)) return rv; - - if (parents.Length()) - { - // Add the htmlcontext DataFlavor to the transferable - trans->AddDataFlavor(kHTMLContext); - genericDataObj = do_QueryInterface(contextWrapper); - trans->SetTransferData(kHTMLContext, genericDataObj, parents.Length()*2); - } - if (info.Length()) - { - // Add the htmlinfo DataFlavor to the transferable - trans->AddDataFlavor(kHTMLInfo); - genericDataObj = do_QueryInterface(infoWrapper); - trans->SetTransferData(kHTMLInfo, genericDataObj, info.Length()*2); - } - } - - /* add the transferable to the array */ - rv = transferableArray->AppendElement(trans); - if (NS_FAILED(rv)) return rv; - - /* invoke drag */ - unsigned int flags; - // in some cases we'll want to cut rather than copy... hmmmmm... - flags = nsIDragService::DRAGDROP_ACTION_COPY + nsIDragService::DRAGDROP_ACTION_MOVE; - - rv = dragService->InvokeDragSession(domnode, transferableArray, nsnull, flags); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr nsevent(do_QueryInterface(aDragEvent)); - - if (nsevent) - { - nsevent->PreventBubble(); - } + // Add the htmlinfo DataFlavor to the transferable + trans->AddDataFlavor(kHTMLInfo); + genericDataObj = do_QueryInterface(infoWrapper); + trans->SetTransferData(kHTMLInfo, genericDataObj, + info.Length() * sizeof(PRUnichar)); } } - return rv; + *aTransferable = trans; + NS_ADDREF(*aTransferable); + return NS_OK; } +NS_IMETHODIMP nsHTMLEditor::DoDrag(nsIDOMEvent *aDragEvent) +{ + return nsPlaintextEditor::DoDrag(aDragEvent); +} PRBool nsHTMLEditor::HavePrivateHTMLFlavor(nsIClipboard *aClipboard) { @@ -1642,6 +1535,12 @@ NS_IMETHODIMP nsHTMLEditor::Paste(PRInt32 aSelectionType) rv = PrepareHTMLTransferable(getter_AddRefs(trans), bHavePrivateHTMLFlavor); if (NS_SUCCEEDED(rv) && trans) { + // handle transferable hooks + PRBool doInsert = PR_TRUE; + DoInsertionHook(nsnull, trans, &doInsert); + if (!doInsert) + return NS_OK; + // Get the Data from the clipboard if (NS_SUCCEEDED(clipboard->GetData(trans, aSelectionType)) && IsModifiable()) { @@ -2267,7 +2166,7 @@ nsresult nsHTMLEditor::CreateDOMFragmentFromPaste(const nsAString &aInputString, nsCOMPtr contextfrag; nsCOMPtr contextLeaf, junk; PRInt32 contextDepth = 0; - if (aContextStr.Length()) + if (!aContextStr.IsEmpty()) { res = ParseFragment(aContextStr, tagStack, doc, address_of(contextAsNode)); NS_ENSURE_SUCCESS(res, res); @@ -2317,7 +2216,7 @@ nsresult nsHTMLEditor::CreateDOMFragmentFromPaste(const nsAString &aInputString, // get the infoString contents nsAutoString numstr1, numstr2; - if (aInfoStr.Length()) + if (!aInfoStr.IsEmpty()) { PRInt32 err, sep; sep = aInfoStr.FindChar((PRUnichar)','); diff --git a/mozilla/editor/libeditor/html/nsHTMLEditor.h b/mozilla/editor/libeditor/html/nsHTMLEditor.h index 03d8cf3a11d..07f9c796eb9 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditor.h +++ b/mozilla/editor/libeditor/html/nsHTMLEditor.h @@ -672,6 +672,7 @@ protected: // factored methods for handling insertion of data from transferables (drag&drop or clipboard) NS_IMETHOD PrepareTransferable(nsITransferable **transferable); NS_IMETHOD PrepareHTMLTransferable(nsITransferable **transferable, PRBool havePrivFlavor); + nsresult PutDragDataInTransferable(nsITransferable **aTransferable); NS_IMETHOD InsertFromTransferable(nsITransferable *transferable, const nsAString & aContextStr, const nsAString & aInfoStr, diff --git a/mozilla/editor/libeditor/text/Makefile.in b/mozilla/editor/libeditor/text/Makefile.in index 4670c77b2ec..fac4c15b94b 100644 --- a/mozilla/editor/libeditor/text/Makefile.in +++ b/mozilla/editor/libeditor/text/Makefile.in @@ -45,6 +45,7 @@ REQUIRES = xpcom \ gfx \ widget \ unicharutil \ + docshell \ $(NULL) CPPSRCS = \ diff --git a/mozilla/editor/libeditor/text/nsPlaintextDataTransfer.cpp b/mozilla/editor/libeditor/text/nsPlaintextDataTransfer.cpp index 46a6cf12ae7..7e0c9e9887c 100644 --- a/mozilla/editor/libeditor/text/nsPlaintextDataTransfer.cpp +++ b/mozilla/editor/libeditor/text/nsPlaintextDataTransfer.cpp @@ -100,6 +100,10 @@ #include "nsITransferable.h" #include "nsIDragService.h" #include "nsIDOMNSUIEvent.h" +#include "nsIDocShell.h" +#include "nsIClipboardDragDropHooks.h" +#include "nsIClipboardDragDropHookList.h" +#include "nsISimpleEnumerator.h" // Misc #include "nsEditorUtils.h" @@ -182,12 +186,23 @@ NS_IMETHODIMP nsPlaintextEditor::InsertFromDrop(nsIDOMEvent* aDropEvent) dragService->GetCurrentSession(getter_AddRefs(dragSession)); if (!dragSession) return NS_OK; + // transferable hooks + PRBool isAllowed = PR_TRUE; + DoAllowDropHook(aDropEvent, dragSession, &isAllowed); + if (!isAllowed) + return NS_OK; + // Get the nsITransferable interface for getting the data from the drop nsCOMPtr trans; rv = PrepareTransferable(getter_AddRefs(trans)); if (NS_FAILED(rv)) return rv; if (!trans) return NS_OK; // NS_ERROR_FAILURE; SHOULD WE FAIL? + PRBool doInsert = PR_TRUE; + DoInsertionHook(aDropEvent, trans, &doInsert); + if (!doInsert) + return NS_OK; + PRUint32 numItems = 0; rv = dragSession->GetNumDropItems(&numItems); if (NS_FAILED(rv)) return rv; @@ -366,13 +381,11 @@ NS_IMETHODIMP nsPlaintextEditor::CanDrag(nsIDOMEvent *aDragEvent, PRBool *aCanDr nsCOMPtr nsevent(do_QueryInterface(aDragEvent)); if (nsevent) { - res = nsevent->GetOriginalTarget(getter_AddRefs(eventTarget)); - if (NS_FAILED(res)) { - return res; - } + res = nsevent->GetExplicitOriginalTarget(getter_AddRefs(eventTarget)); + if (NS_FAILED(res)) return res; } - if ( eventTarget ) + if (eventTarget) { nsCOMPtr eventTargetDomNode = do_QueryInterface(eventTarget); if ( eventTargetDomNode ) @@ -385,6 +398,42 @@ NS_IMETHODIMP nsPlaintextEditor::CanDrag(nsIDOMEvent *aDragEvent, PRBool *aCanDr } } + if (NS_FAILED(res)) return res; + if (!*aCanDrag) return NS_OK; + + nsCOMPtr domdoc; + GetDocument(getter_AddRefs(domdoc)); + nsCOMPtr doc = do_QueryInterface(domdoc); + if (!doc) return NS_ERROR_FAILURE; + + nsCOMPtr isupp; + doc->GetContainer(getter_AddRefs(isupp)); + nsCOMPtr docShell = do_QueryInterface(isupp); + nsCOMPtr hookObj = do_GetInterface(docShell); + if (!hookObj) return NS_ERROR_FAILURE; + + nsCOMPtr enumerator; + hookObj->GetHookEnumerator(getter_AddRefs(enumerator)); + if (!enumerator) return NS_ERROR_FAILURE; + + nsCOMPtr override; + PRBool hasMoreHooks = PR_FALSE; + while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreHooks)) + && hasMoreHooks) + { + res = enumerator->GetNext(getter_AddRefs(isupp)); + if (NS_FAILED(res)) break; + override = do_QueryInterface(isupp); + if (override) + { + res = override->AllowStartDrag(aDragEvent, aCanDrag); + NS_ASSERTION(NS_SUCCEEDED(res), "hook failure in AllowStartDrag"); + } + + if (!*aCanDrag) + break; + } + return NS_OK; } @@ -392,14 +441,14 @@ NS_IMETHODIMP nsPlaintextEditor::DoDrag(nsIDOMEvent *aDragEvent) { nsresult rv; - nsCOMPtr eventTarget; - rv = aDragEvent->GetTarget(getter_AddRefs(eventTarget)); + nsCOMPtr trans; + rv = PutDragDataInTransferable(getter_AddRefs(trans)); if (NS_FAILED(rv)) return rv; - nsCOMPtr domnode = do_QueryInterface(eventTarget); + if (!trans) return NS_OK; // maybe there was nothing to copy? - /* get the selection to be dragged */ - nsCOMPtr selection; - rv = GetSelection(getter_AddRefs(selection)); + /* get the drag service */ + nsCOMPtr dragService = + do_GetService("@mozilla.org/widget/dragservice;1", &rv); if (NS_FAILED(rv)) return rv; /* create an array of transferables */ @@ -408,109 +457,63 @@ NS_IMETHODIMP nsPlaintextEditor::DoDrag(nsIDOMEvent *aDragEvent) if (transferableArray == nsnull) return NS_ERROR_OUT_OF_MEMORY; - /* get the drag service */ - nsCOMPtr dragService = - do_GetService("@mozilla.org/widget/dragservice;1", &rv); + /* add the transferable to the array */ + rv = transferableArray->AppendElement(trans); if (NS_FAILED(rv)) return rv; - /* create html flavor transferable */ - nsCOMPtr trans = do_CreateInstance(kCTransferableCID); - NS_ENSURE_TRUE(trans, NS_ERROR_FAILURE); - + // check our transferable hooks (if any) nsCOMPtr domdoc; - rv = GetDocument(getter_AddRefs(domdoc)); - if (NS_FAILED(rv)) return rv; - + GetDocument(getter_AddRefs(domdoc)); nsCOMPtr doc = do_QueryInterface(domdoc); - if (doc) + if (!doc) return NS_ERROR_FAILURE; + + nsCOMPtr isupp; + doc->GetContainer(getter_AddRefs(isupp)); + nsCOMPtr docShell = do_QueryInterface(isupp); + nsCOMPtr hookObj = do_GetInterface(docShell); + if (!hookObj) return NS_ERROR_FAILURE; + + nsCOMPtr enumerator; + hookObj->GetHookEnumerator(getter_AddRefs(enumerator)); + if (!enumerator) return NS_ERROR_FAILURE; + + nsCOMPtr override; + PRBool canInvokeDrag = PR_TRUE; + PRBool hasMoreHooks = PR_FALSE; + while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreHooks)) + && hasMoreHooks) { - // find out if we're a plaintext control or not - PRUint32 editorFlags = 0; - rv = GetFlags(&editorFlags); - if (NS_FAILED(rv)) return rv; - - PRBool bIsPlainTextControl = ((editorFlags & eEditorPlaintextMask) != 0); - - // get correct mimeType and document encoder flags set - nsAutoString mimeType; - PRUint32 docEncoderFlags = 0; - if (bIsPlainTextControl) + rv = enumerator->GetNext(getter_AddRefs(isupp)); + if (NS_FAILED(rv)) break; + override = do_QueryInterface(isupp); + if (override) { - docEncoderFlags |= nsIDocumentEncoder::OutputBodyOnly | nsIDocumentEncoder::OutputPreformatted; - mimeType = NS_LITERAL_STRING(kUnicodeMime); + nsresult hookResult = override->OnCopyOrDrag(trans, &canInvokeDrag); + NS_ASSERTION(NS_SUCCEEDED(hookResult), "hook failure in OnCopyOrDrag"); } - else - mimeType = NS_LITERAL_STRING(kHTMLMime); - - // set up docEncoder - nsCOMPtr docEncoder = do_CreateInstance(NS_HTMLCOPY_ENCODER_CONTRACTID); - NS_ENSURE_TRUE(docEncoder, NS_ERROR_FAILURE); - rv = docEncoder->Init(doc, mimeType, docEncoderFlags); - if (NS_FAILED(rv)) return rv; - - rv = docEncoder->SetSelection(selection); - if (NS_FAILED(rv)) return rv; - - // grab a string - nsAutoString buffer; - rv = docEncoder->EncodeToString(buffer); - if (NS_FAILED(rv)) return rv; - - // if we have an empty string, we're done; otherwise continue - if ( !buffer.IsEmpty() ) - { - nsCOMPtr dataWrapper = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID); - NS_ENSURE_TRUE(dataWrapper, NS_ERROR_FAILURE); - - rv = dataWrapper->SetData( buffer ); - if (NS_FAILED(rv)) return rv; - - if (bIsPlainTextControl) - { - // Add the unicode flavor to the transferable - rv = trans->AddDataFlavor(kUnicodeMime); - if (NS_FAILED(rv)) return rv; - } - else - { - rv = trans->AddDataFlavor(kHTMLMime); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr htmlConverter = do_CreateInstance(kCHTMLFormatConverterCID); - NS_ENSURE_TRUE(htmlConverter, NS_ERROR_FAILURE); - - rv = trans->SetConverter(htmlConverter); - if (NS_FAILED(rv)) return rv; - } - - // QI the data object an |nsISupports| so that when the transferable holds - // onto it, it will addref the correct interface. - nsCOMPtr nsisupportsDataWrapper ( do_QueryInterface(dataWrapper) ); - rv = trans->SetTransferData(bIsPlainTextControl ? kUnicodeMime : kHTMLMime, - nsisupportsDataWrapper, buffer.Length() * 2); - if (NS_FAILED(rv)) return rv; - - /* add the transferable to the array */ - rv = transferableArray->AppendElement(trans); - if (NS_FAILED(rv)) return rv; - - /* invoke drag */ - unsigned int flags; - // in some cases we'll want to cut rather than copy... hmmmmm... - flags = nsIDragService::DRAGDROP_ACTION_COPY + nsIDragService::DRAGDROP_ACTION_MOVE; - - rv = dragService->InvokeDragSession( domnode, transferableArray, nsnull, flags); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr nsevent(do_QueryInterface(aDragEvent)); - - if (nsevent) { - nsevent->PreventBubble(); - } - } + // if one of our overrides says we can't invoke drag, return now + if (!canInvokeDrag) + return NS_OK; } + /* invoke drag */ + nsCOMPtr eventTarget; + rv = aDragEvent->GetTarget(getter_AddRefs(eventTarget)); + if (NS_FAILED(rv)) return rv; + nsCOMPtr domnode = do_QueryInterface(eventTarget); + + unsigned int flags; + // in some cases we'll want to cut rather than copy... hmmmmm... + flags = nsIDragService::DRAGDROP_ACTION_COPY + nsIDragService::DRAGDROP_ACTION_MOVE; + + rv = dragService->InvokeDragSession(domnode, transferableArray, nsnull, flags); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr nsevent(do_QueryInterface(aDragEvent)); + if (nsevent) + nsevent->PreventBubble(); + return rv; } @@ -529,6 +532,12 @@ NS_IMETHODIMP nsPlaintextEditor::Paste(PRInt32 aSelectionType) rv = PrepareTransferable(getter_AddRefs(trans)); if (NS_SUCCEEDED(rv) && trans) { + // handle transferable hooks + PRBool doInsert = PR_TRUE; + DoInsertionHook(nsnull, trans, &doInsert); + if (!doInsert) + return NS_OK; + // Get the Data from the clipboard if (NS_SUCCEEDED(clipboard->GetData(trans, aSelectionType)) && IsModifiable()) { @@ -585,3 +594,197 @@ NS_IMETHODIMP nsPlaintextEditor::CanPaste(PRInt32 aSelectionType, PRBool *aCanPa *aCanPaste = haveFlavors; return NS_OK; } + +nsresult +nsPlaintextEditor::SetupDocEncoder(nsIDocumentEncoder **aDocEncoder) +{ + nsCOMPtr domdoc; + nsresult rv = GetDocument(getter_AddRefs(domdoc)); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr doc = do_QueryInterface(domdoc); + if (!doc) return NS_ERROR_FAILURE; + + // find out if we're a plaintext control or not + PRUint32 editorFlags = 0; + rv = GetFlags(&editorFlags); + if (NS_FAILED(rv)) return rv; + + PRBool bIsPlainTextControl = ((editorFlags & eEditorPlaintextMask) != 0); + + // get correct mimeType and document encoder flags set + nsAutoString mimeType; + PRUint32 docEncoderFlags = 0; + if (bIsPlainTextControl) + { + docEncoderFlags |= nsIDocumentEncoder::OutputBodyOnly | nsIDocumentEncoder::OutputPreformatted; + mimeType = NS_LITERAL_STRING(kUnicodeMime); + } + else + mimeType = NS_LITERAL_STRING(kHTMLMime); + + // set up docEncoder + nsCOMPtr encoder = do_CreateInstance(NS_HTMLCOPY_ENCODER_CONTRACTID); + if (!encoder) + return NS_ERROR_OUT_OF_MEMORY; + + rv = encoder->Init(doc, mimeType, docEncoderFlags); + if (NS_FAILED(rv)) return rv; + + /* get the selection to be dragged */ + nsCOMPtr selection; + rv = GetSelection(getter_AddRefs(selection)); + if (NS_FAILED(rv)) return rv; + + rv = encoder->SetSelection(selection); + if (NS_FAILED(rv)) return rv; + + *aDocEncoder = encoder; + NS_ADDREF(*aDocEncoder); + return NS_OK; +} + +nsresult +nsPlaintextEditor::PutDragDataInTransferable(nsITransferable **aTransferable) +{ + *aTransferable = nsnull; + nsCOMPtr docEncoder; + nsresult rv = SetupDocEncoder(getter_AddRefs(docEncoder)); + if (NS_FAILED(rv)) return rv; + + // grab a string + nsAutoString buffer; + rv = docEncoder->EncodeToString(buffer); + if (NS_FAILED(rv)) return rv; + + // if we have an empty string, we're done; otherwise continue + if (buffer.IsEmpty()) + return NS_OK; + + nsCOMPtr dataWrapper = + do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = dataWrapper->SetData(buffer); + if (NS_FAILED(rv)) return rv; + + /* create html flavor transferable */ + nsCOMPtr trans = do_CreateInstance(kCTransferableCID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + // find out if we're a plaintext control or not + PRUint32 editorFlags = 0; + rv = GetFlags(&editorFlags); + if (NS_FAILED(rv)) return rv; + + PRBool bIsPlainTextControl = ((editorFlags & eEditorPlaintextMask) != 0); + if (bIsPlainTextControl) + { + // Add the unicode flavor to the transferable + rv = trans->AddDataFlavor(kUnicodeMime); + if (NS_FAILED(rv)) return rv; + } + else + { + rv = trans->AddDataFlavor(kHTMLMime); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr htmlConverter = do_CreateInstance(kCHTMLFormatConverterCID); + NS_ENSURE_TRUE(htmlConverter, NS_ERROR_FAILURE); + + rv = trans->SetConverter(htmlConverter); + if (NS_FAILED(rv)) return rv; + } + + // QI the data object an |nsISupports| so that when the transferable holds + // onto it, it will addref the correct interface. + nsCOMPtr nsisupportsDataWrapper = do_QueryInterface(dataWrapper); + rv = trans->SetTransferData(bIsPlainTextControl ? kUnicodeMime : kHTMLMime, + nsisupportsDataWrapper, buffer.Length() * sizeof(PRUnichar)); + if (NS_FAILED(rv)) return rv; + + *aTransferable = trans; + NS_ADDREF(*aTransferable); + return NS_OK; +} + +nsresult +nsPlaintextEditor::DoAllowDropHook(nsIDOMEvent* aDropEvent, + nsIDragSession *aSession, PRBool *aAllowDrop) +{ + *aAllowDrop = PR_TRUE; + + nsCOMPtr domdoc; + GetDocument(getter_AddRefs(domdoc)); + nsCOMPtr doc = do_QueryInterface(domdoc); + if (!doc) return NS_ERROR_FAILURE; + + nsCOMPtr isupp; + doc->GetContainer(getter_AddRefs(isupp)); + nsCOMPtr docShell = do_QueryInterface(isupp); + nsCOMPtr hookObj = do_GetInterface(docShell); + if (!hookObj) return NS_ERROR_FAILURE; + + nsCOMPtr enumerator; + hookObj->GetHookEnumerator(getter_AddRefs(enumerator)); + if (!enumerator) return NS_ERROR_FAILURE; + + nsCOMPtr override; + PRBool hasMoreHooks = PR_FALSE; + nsresult res = NS_OK; + while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreHooks)) && hasMoreHooks) + { + res = enumerator->GetNext(getter_AddRefs(isupp)); + if (NS_FAILED(res)) break; + override = do_QueryInterface(isupp); + if (override) + { + nsresult hookResult = override->AllowDrop(aDropEvent, aSession, aAllowDrop); + NS_ASSERTION(NS_SUCCEEDED(hookResult), "hook failure in AllowDrop"); + } + + if (!*aAllowDrop) + break; + } + + return res; +} + + +nsresult +nsPlaintextEditor::DoInsertionHook(nsIDOMEvent* aDropEvent, + nsITransferable *aTrans, PRBool *aDoInsert) +{ + nsCOMPtr domdoc; + GetDocument(getter_AddRefs(domdoc)); + nsCOMPtr doc = do_QueryInterface(domdoc); + if (!doc) return NS_ERROR_FAILURE; + + nsCOMPtr isupp; + doc->GetContainer(getter_AddRefs(isupp)); + nsCOMPtr docShell = do_QueryInterface(isupp); + nsCOMPtr hookObj = do_GetInterface(docShell); + if (!hookObj) return NS_ERROR_FAILURE; + + nsCOMPtr enumerator; + hookObj->GetHookEnumerator(getter_AddRefs(enumerator)); + if (!enumerator) return NS_ERROR_FAILURE; + + nsCOMPtr override; + PRBool hasMoreHooks = PR_FALSE; + nsresult res = NS_OK; + while (*aDoInsert && + NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreHooks)) && hasMoreHooks) + { + res = enumerator->GetNext(getter_AddRefs(isupp)); + if (NS_FAILED(res)) break; + override = do_QueryInterface(isupp); + if (override) + { + nsresult hookResult = override->OnPasteOrDrop(aDropEvent, aTrans, aDoInsert); + NS_ASSERTION(NS_SUCCEEDED(hookResult), "hook failure in OnPasteOrDrop"); + } + } + + return res; +} diff --git a/mozilla/editor/libeditor/text/nsPlaintextEditor.h b/mozilla/editor/libeditor/text/nsPlaintextEditor.h index cdbcdd893a1..aaeb10f84b8 100644 --- a/mozilla/editor/libeditor/text/nsPlaintextEditor.h +++ b/mozilla/editor/libeditor/text/nsPlaintextEditor.h @@ -55,6 +55,7 @@ class nsIDOMKeyEvent; class nsITransferable; class nsIDOMEventReceiver; class nsIDocumentEncoder; +class nsIDragSession; /** * The text editor implementation. @@ -226,6 +227,11 @@ protected: // factored methods for handling insertion of data from transferables (drag&drop or clipboard) NS_IMETHOD PrepareTransferable(nsITransferable **transferable); NS_IMETHOD InsertTextFromTransferable(nsITransferable *transferable); + virtual nsresult SetupDocEncoder(nsIDocumentEncoder **aDocEncoder); + virtual nsresult PutDragDataInTransferable(nsITransferable **aTransferable); + virtual nsresult DoAllowDropHook(nsIDOMEvent* aDropEvent, nsIDragSession *aSession, PRBool *aAllowDrop); + virtual nsresult DoInsertionHook(nsIDOMEvent* aDropEvent, + nsITransferable *aTrans, PRBool *aDoInsert); /** simple utility to handle any error with event listener allocation or registration */ void HandleEventListenerError();