Fix for bug 74404 -- show caret drag feedback. r=brade, sr=kin

This commit is contained in:
sfraser%netscape.com 2003-02-27 23:20:15 +00:00
parent 511b311820
commit e1fbf0bdbe

View File

@ -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);
}