mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
Fix for bug 74404 -- show caret drag feedback. r=brade, sr=kin
This commit is contained in:
parent
511b311820
commit
e1fbf0bdbe
@ -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<nsIDragService> dragService =
|
||||
do_GetService( "@mozilla.org/widget/dragservice;1", &rv );
|
||||
if ( NS_SUCCEEDED(rv) ) {
|
||||
nsCOMPtr<nsIDragSession> 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<nsIDragService> dragService = do_GetService("@mozilla.org/widget/dragservice;1", &rv);
|
||||
if (!dragService) return rv;
|
||||
|
||||
// does the drag have flavors we can accept?
|
||||
nsCOMPtr<nsIDragSession> 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<nsIDragService> 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<nsIDragSession> 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<nsIDOMNSUIEvent> nsuiEvent (do_QueryInterface(aMouseEvent));
|
||||
if (!nsuiEvent) return NS_OK;
|
||||
|
||||
//some day we want to use another way to stop this from bubbling.
|
||||
nsCOMPtr<nsIDOMNSEvent> 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<nsISelection> selection;
|
||||
rv = mEditor->GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
if (!selection)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> domdoc;
|
||||
rv = mEditor->GetDocument(getter_AddRefs(domdoc));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> 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<nsIDOMNSUIEvent> nsuiEvent (do_QueryInterface(aDragEvent));
|
||||
if (nsuiEvent)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> 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<nsIDOMRange> range;
|
||||
|
||||
rv = selection->GetRangeAt(i, getter_AddRefs(range));
|
||||
if (NS_FAILED(rv) || !range)
|
||||
continue;//dont bail yet, iterate through them all
|
||||
|
||||
nsCOMPtr<nsIDOMNSRange> 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<nsIDOMNSEvent> 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<nsIDragService> dragService = do_GetService("@mozilla.org/widget/dragservice;1", &rv);
|
||||
if (!dragService) return PR_FALSE;
|
||||
|
||||
// does the drag have flavors we can accept?
|
||||
nsCOMPtr<nsIDragSession> 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<nsISelection> selection;
|
||||
rv = mEditor->GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(rv) || !selection)
|
||||
return PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> domdoc;
|
||||
rv = mEditor->GetDocument(getter_AddRefs(domdoc));
|
||||
if (NS_FAILED(rv)) return PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> 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<nsIDOMNSUIEvent> nsuiEvent (do_QueryInterface(aEvent));
|
||||
if (!nsuiEvent) return PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> 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<nsIDOMRange> range;
|
||||
rv = selection->GetRangeAt(i, getter_AddRefs(range));
|
||||
if (NS_FAILED(rv) || !range)
|
||||
continue; //dont bail yet, iterate through them all
|
||||
|
||||
nsCOMPtr<nsIDOMNSRange> 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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user