From f52e39941fe51f7b97efd398cfcac4177065651d Mon Sep 17 00:00:00 2001 From: "sfraser%netscape.com" Date: Thu, 27 Feb 2003 23:20:15 +0000 Subject: [PATCH] Fix for bug 74404 -- show caret drag feedback. r=brade, sr=kin git-svn-id: svn://10.0.0.236/trunk@138644 18797224-902f-48f8-a5cc-f745e15eee43 --- .../libeditor/text/nsEditorEventListeners.cpp | 376 ++++++++++-------- 1 file changed, 207 insertions(+), 169 deletions(-) diff --git a/mozilla/editor/libeditor/text/nsEditorEventListeners.cpp b/mozilla/editor/libeditor/text/nsEditorEventListeners.cpp index ddf69c4af49..81b0ad42b69 100644 --- a/mozilla/editor/libeditor/text/nsEditorEventListeners.cpp +++ b/mozilla/editor/libeditor/text/nsEditorEventListeners.cpp @@ -66,6 +66,7 @@ #include "nsILookAndFeel.h" #include "nsIPresContext.h" #include "nsGUIEvent.h" +#include "nsICaret.h" // for repainting hack only #include "nsIView.h" #include "nsIViewManager.h" @@ -88,6 +89,7 @@ // Drag & Drop, Clipboard Support static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID); +static NS_DEFINE_CID(kCaretCID, NS_CARET_CID); //#define DEBUG_IME @@ -600,12 +602,10 @@ nsTextEditorTextListener::HandleText(nsIDOMEvent* aTextEvent) * nsTextEditorDragListener implementation */ -NS_IMPL_ADDREF(nsTextEditorDragListener) - -NS_IMPL_RELEASE(nsTextEditorDragListener) - - nsTextEditorDragListener::nsTextEditorDragListener() +: mEditor(nsnull) +, mPresShell(nsnull) +, mCaretDrawn(PR_FALSE) { } @@ -613,32 +613,7 @@ nsTextEditorDragListener::~nsTextEditorDragListener() { } -nsresult -nsTextEditorDragListener::QueryInterface(REFNSIID aIID, void** aInstancePtr) -{ - if (nsnull == aInstancePtr) { - return NS_ERROR_NULL_POINTER; - } - - if (aIID.Equals(NS_GET_IID(nsISupports))) { - *aInstancePtr = (void*)(nsISupports*)this; - NS_ADDREF_THIS(); - return NS_OK; - } - if (aIID.Equals(NS_GET_IID(nsIDOMEventListener))) { - *aInstancePtr = (void*)(nsIDOMEventListener*)this; - NS_ADDREF_THIS(); - return NS_OK; - } - if (aIID.Equals(NS_GET_IID(nsIDOMDragListener))) { - *aInstancePtr = (void*)(nsIDOMDragListener*)this; - NS_ADDREF_THIS(); - return NS_OK; - } - return NS_NOINTERFACE; -} - - +NS_IMPL_ISUPPORTS2(nsTextEditorDragListener, nsIDOMEventListener, nsIDOMDragListener); nsresult nsTextEditorDragListener::HandleEvent(nsIDOMEvent* aEvent) @@ -666,6 +641,20 @@ nsTextEditorDragListener::DragGesture(nsIDOMEvent* aDragEvent) nsresult nsTextEditorDragListener::DragEnter(nsIDOMEvent* aDragEvent) { + if (mPresShell) + { + if (!mCaret) + { + mCaret = do_CreateInstance(kCaretCID); + if (mCaret) + { + mCaret->Init(mPresShell); + mCaret->SetCaretReadOnly(PR_TRUE); + } + mCaretDrawn = PR_FALSE; + } + } + return DragOver(aDragEvent); } @@ -673,124 +662,29 @@ nsTextEditorDragListener::DragEnter(nsIDOMEvent* aDragEvent) nsresult nsTextEditorDragListener::DragOver(nsIDOMEvent* aDragEvent) { + // XXX cache this between drag events? nsresult rv; - nsCOMPtr dragService = - do_GetService( "@mozilla.org/widget/dragservice;1", &rv ); - if ( NS_SUCCEEDED(rv) ) { - nsCOMPtr dragSession; - dragService->GetCurrentSession(getter_AddRefs(dragSession)); - if ( dragSession ) { - PRUint32 flags; - if (NS_SUCCEEDED(mEditor->GetFlags(&flags))) { - if ((flags & nsIPlaintextEditor::eEditorDisabledMask) || - (flags & nsIPlaintextEditor::eEditorReadonlyMask)) { - dragSession->SetCanDrop(PR_FALSE); - aDragEvent->PreventDefault(); // consumed - return NS_OK; - } - } - PRBool flavorSupported = PR_FALSE; - dragSession->IsDataFlavorSupported(kUnicodeMime, &flavorSupported); - if ( !flavorSupported ) - dragSession->IsDataFlavorSupported(kHTMLMime, &flavorSupported); - if ( !flavorSupported ) - dragSession->IsDataFlavorSupported(kFileMime, &flavorSupported); - if ( !flavorSupported ) - dragSession->IsDataFlavorSupported(kJPEGImageMime, &flavorSupported); - if ( flavorSupported ) { - dragSession->SetCanDrop(PR_TRUE); - aDragEvent->PreventDefault(); - } - } + nsCOMPtr dragService = do_GetService("@mozilla.org/widget/dragservice;1", &rv); + if (!dragService) return rv; + + // does the drag have flavors we can accept? + nsCOMPtr dragSession; + dragService->GetCurrentSession(getter_AddRefs(dragSession)); + if (!dragSession) return NS_ERROR_FAILURE; + + PRBool canDrop = CanDrop(aDragEvent); + dragSession->SetCanDrop(canDrop); + if (!canDrop) { + aDragEvent->PreventDefault(); // consumed + return NS_OK; } - - return NS_OK; -} - - -nsresult -nsTextEditorDragListener::DragExit(nsIDOMEvent* aDragEvent) -{ - return NS_OK; -} - - - -nsresult -nsTextEditorDragListener::DragDrop(nsIDOMEvent* aMouseEvent) -{ - if ( mEditor ) - { - nsresult rv; - nsCOMPtr dragService = - do_GetService("@mozilla.org/widget/dragservice;1", &rv); - if (NS_FAILED(rv)) return rv; - - PRUint32 flags; - if (NS_SUCCEEDED(mEditor->GetFlags(&flags)) - && ((flags & nsIPlaintextEditor::eEditorDisabledMask) - || (flags & nsIPlaintextEditor::eEditorReadonlyMask)) ) - { - return aMouseEvent->StopPropagation(); // it was decided to "eat" the event as this is the "least surprise" - // since someone else handling it might be unintentional and the - // user could probably re-drag to be not over the disabled/readonly - // editfields if that is what is desired. - } - - nsCOMPtr dragSession; - dragService->GetCurrentSession(getter_AddRefs(dragSession)); - if (dragSession) - { - PRBool flavorSupported = PR_FALSE; - dragSession->IsDataFlavorSupported(kUnicodeMime, &flavorSupported); - if ( !flavorSupported ) - dragSession->IsDataFlavorSupported(kHTMLMime, &flavorSupported); - if ( !flavorSupported ) - dragSession->IsDataFlavorSupported(kFileMime, &flavorSupported); - if ( !flavorSupported ) - dragSession->IsDataFlavorSupported(kJPEGImageMime, &flavorSupported); - if (! flavorSupported ) - return NS_OK; - } - - nsCOMPtr nsuiEvent (do_QueryInterface(aMouseEvent)); - if (!nsuiEvent) return NS_OK; - - //some day we want to use another way to stop this from bubbling. - nsCOMPtr nsevent(do_QueryInterface(aMouseEvent)); - - if (nsevent) { - nsevent->PreventBubble(); - } - - aMouseEvent->PreventDefault(); - - /* for bug 47399, when dropping a drag session, if you are over your original - selection, nothing should happen. - cmanske: But do this only if drag source is not the same as target (current) document! - */ - nsCOMPtr selection; - rv = mEditor->GetSelection(getter_AddRefs(selection)); - if (NS_FAILED(rv)) - return rv; - if (!selection) - return NS_ERROR_FAILURE; - nsCOMPtr domdoc; - rv = mEditor->GetDocument(getter_AddRefs(domdoc)); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr sourceDoc; - rv = dragSession->GetSourceDocument(getter_AddRefs(sourceDoc)); - if (NS_FAILED(rv)) return rv; - if (domdoc == sourceDoc) + if (canDrop) + { + if (mCaret) { - PRBool isCollapsed; - rv = selection->GetIsCollapsed(&isCollapsed); - if (NS_FAILED(rv)) return rv; - - // Don't bother if collapsed - can always drop - if (!isCollapsed) + nsCOMPtr nsuiEvent (do_QueryInterface(aDragEvent)); + if (nsuiEvent) { nsCOMPtr parent; rv = nsuiEvent->GetRangeParent(getter_AddRefs(parent)); @@ -801,37 +695,180 @@ nsTextEditorDragListener::DragDrop(nsIDOMEvent* aMouseEvent) rv = nsuiEvent->GetRangeOffset(&offset); if (NS_FAILED(rv)) return rv; - PRInt32 rangeCount; - rv = selection->GetRangeCount(&rangeCount); - if (NS_FAILED(rv)) return rv; - - for (PRInt32 i = 0; i < rangeCount; i++) - { - nsCOMPtr range; - - rv = selection->GetRangeAt(i, getter_AddRefs(range)); - if (NS_FAILED(rv) || !range) - continue;//dont bail yet, iterate through them all - - nsCOMPtr nsrange(do_QueryInterface(range)); - if (NS_FAILED(rv) || !nsrange) - continue;//dont bail yet, iterate through them all - - PRBool inrange; - rv = nsrange->IsPointInRange(parent, offset, &inrange); - if(inrange) - return NS_ERROR_FAILURE;//okay, now you can bail, we are over the orginal selection - } + // to avoid flicker, we could track the node and offset to see if we moved + if (mCaretDrawn) + mCaret->EraseCaret(); + + //mCaret->SetCaretVisible(PR_TRUE); // make sure it's visible + mCaret->DrawAtPosition(parent, offset); + mCaretDrawn = PR_TRUE; } } - // if we are not over orginal selection, drop that baby! - return mEditor->InsertFromDrop(aMouseEvent); + } + else + { + if (mCaret && mCaretDrawn) + { + mCaret->EraseCaret(); + mCaretDrawn = PR_FALSE; + } } return NS_OK; } +nsresult +nsTextEditorDragListener::DragExit(nsIDOMEvent* aDragEvent) +{ + if (mCaret) + { + if (mCaretDrawn) + mCaret->EraseCaret(); + mCaretDrawn = PR_FALSE; + } + + return NS_OK; +} + + + +nsresult +nsTextEditorDragListener::DragDrop(nsIDOMEvent* aMouseEvent) +{ + if (mCaret) + { + if (mCaretDrawn) + mCaret->EraseCaret(); + mCaretDrawn = PR_FALSE; + mCaret->SetCaretVisible(PR_FALSE); // hide it, so that it turns off its timer + mCaret = nsnull; // release it + } + + if (!mEditor) + return NS_ERROR_FAILURE; + + PRBool canDrop = CanDrop(aMouseEvent); + if (!canDrop) + { + // was it because we're read-only? + + PRUint32 flags; + if (NS_SUCCEEDED(mEditor->GetFlags(&flags)) + && ((flags & nsIPlaintextEditor::eEditorDisabledMask) || + (flags & nsIPlaintextEditor::eEditorReadonlyMask)) ) + { + // it was decided to "eat" the event as this is the "least surprise" + // since someone else handling it might be unintentional and the + // user could probably re-drag to be not over the disabled/readonly + // editfields if that is what is desired. + return aMouseEvent->StopPropagation(); + } + return NS_OK; + } + + //some day we want to use another way to stop this from bubbling. + nsCOMPtr nsevent(do_QueryInterface(aMouseEvent)); + if (nsevent) + nsevent->PreventBubble(); + + aMouseEvent->PreventDefault(); + return mEditor->InsertFromDrop(aMouseEvent); +} + +PRBool +nsTextEditorDragListener::CanDrop(nsIDOMEvent* aEvent) +{ + // if the target doc is read-only, we can't drop + PRUint32 flags = 0; + nsresult rv = mEditor->GetFlags(&flags); + if (NS_FAILED(rv)) return PR_FALSE; + + if ((flags & nsIPlaintextEditor::eEditorDisabledMask) || + (flags & nsIPlaintextEditor::eEditorReadonlyMask)) { + return PR_FALSE; + } + + // XXX cache this between drag events? + nsCOMPtr dragService = do_GetService("@mozilla.org/widget/dragservice;1", &rv); + if (!dragService) return PR_FALSE; + + // does the drag have flavors we can accept? + nsCOMPtr dragSession; + dragService->GetCurrentSession(getter_AddRefs(dragSession)); + if (!dragSession) return PR_FALSE; + + // XXX should we filter out some types for plaintext-only editors? + PRBool flavorSupported = PR_FALSE; + dragSession->IsDataFlavorSupported(kUnicodeMime, &flavorSupported); + if (!flavorSupported) + dragSession->IsDataFlavorSupported(kHTMLMime, &flavorSupported); + if (!flavorSupported) + dragSession->IsDataFlavorSupported(kFileMime, &flavorSupported); + if (!flavorSupported) + dragSession->IsDataFlavorSupported(kJPEGImageMime, &flavorSupported); + if (!flavorSupported) + return PR_FALSE; + + nsCOMPtr selection; + rv = mEditor->GetSelection(getter_AddRefs(selection)); + if (NS_FAILED(rv) || !selection) + return PR_FALSE; + + nsCOMPtr domdoc; + rv = mEditor->GetDocument(getter_AddRefs(domdoc)); + if (NS_FAILED(rv)) return PR_FALSE; + + nsCOMPtr sourceDoc; + rv = dragSession->GetSourceDocument(getter_AddRefs(sourceDoc)); + if (NS_FAILED(rv)) return PR_FALSE; + if (domdoc == sourceDoc) // source and dest are the same document; disallow drops within the selection + { + PRBool isCollapsed; + rv = selection->GetIsCollapsed(&isCollapsed); + if (NS_FAILED(rv)) return PR_FALSE; + + // Don't bother if collapsed - can always drop + if (!isCollapsed) + { + nsCOMPtr nsuiEvent (do_QueryInterface(aEvent)); + if (!nsuiEvent) return PR_FALSE; + + nsCOMPtr parent; + rv = nsuiEvent->GetRangeParent(getter_AddRefs(parent)); + if (NS_FAILED(rv) || !parent) return PR_FALSE; + + PRInt32 offset = 0; + rv = nsuiEvent->GetRangeOffset(&offset); + if (NS_FAILED(rv)) return PR_FALSE; + + PRInt32 rangeCount; + rv = selection->GetRangeCount(&rangeCount); + if (NS_FAILED(rv)) return PR_FALSE; + + for (PRInt32 i = 0; i < rangeCount; i++) + { + nsCOMPtr range; + rv = selection->GetRangeAt(i, getter_AddRefs(range)); + if (NS_FAILED(rv) || !range) + continue; //dont bail yet, iterate through them all + + nsCOMPtr nsrange(do_QueryInterface(range)); + if (NS_FAILED(rv) || !nsrange) + continue; //dont bail yet, iterate through them all + + PRBool inRange = PR_TRUE; + (void)nsrange->IsPointInRange(parent, offset, &inRange); + if (inRange) + return PR_FALSE; //okay, now you can bail, we are over the orginal selection + } + } + } + + return PR_TRUE; +} + + nsTextEditorCompositionListener::nsTextEditorCompositionListener() { } @@ -1002,7 +1039,7 @@ NS_NewEditorTextListener(nsIDOMEventListener** aInstancePtrResult, nsIEditor* aE nsresult -NS_NewEditorDragListener(nsIDOMEventListener ** aInstancePtrResult, +NS_NewEditorDragListener(nsIDOMEventListener ** aInstancePtrResult, nsIPresShell* aPresShell, nsIEditor *aEditor) { nsTextEditorDragListener* it = new nsTextEditorDragListener(); @@ -1011,6 +1048,7 @@ NS_NewEditorDragListener(nsIDOMEventListener ** aInstancePtrResult, } it->SetEditor(aEditor); + it->SetPresShell(aPresShell); return it->QueryInterface(NS_GET_IID(nsIDOMEventListener), (void **) aInstancePtrResult); }