turn listener into a capturer and pass more off to JS.

This commit is contained in:
pinkerton%netscape.com 1999-09-09 06:27:25 +00:00
parent e5d030d873
commit 122f2d8f5a
4 changed files with 221 additions and 167 deletions

View File

@ -20,11 +20,6 @@
#include "nsToolbarDragListener.h"
#include "nsToolbarFrame.h"
#include "nsIServiceManager.h"
#include "nsWidgetsCID.h"
#include "nsIDragService.h"
#include "nsIDragSession.h"
#include "nsITransferable.h"
#include "nsCOMPtr.h"
#include "nsIDOMUIEvent.h"
#include "nsIPresContext.h"
@ -33,16 +28,7 @@
#include "nsXULAtoms.h"
#include "nsIEventStateManager.h"
#include "nsISupportsPrimitives.h"
#include "nsISupportsArray.h"
#include "nsIViewManager.h"
#include "nsIView.h"
// Drag & Drop, Clipboard Support
static NS_DEFINE_CID(kCDragServiceCID, NS_DRAGSERVICE_CID);
static NS_DEFINE_CID(kCTransferableCID, NS_TRANSFERABLE_CID);
static NS_DEFINE_IID(kCDataFlavorCID, NS_DATAFLAVOR_CID);
#include "nsINameSpaceManager.h"
NS_IMPL_ADDREF(nsToolbarDragListener)
@ -103,30 +89,6 @@ nsToolbarDragListener::QueryInterface(REFNSIID aIID, void** aInstancePtr)
}
////////////////////////////////////////////////////////////////////////
// This is temporary until the bubling of event for CSS actions work
////////////////////////////////////////////////////////////////////////
static void ForceDrawFrame(nsIFrame * aFrame)
{
if (aFrame == nsnull) {
return;
}
nsRect rect;
nsIView * view;
nsPoint pnt;
aFrame->GetOffsetFromView(pnt, &view);
aFrame->GetRect(rect);
rect.x = pnt.x;
rect.y = pnt.y;
if (view) {
nsCOMPtr<nsIViewManager> viewMgr;
view->GetViewManager(*getter_AddRefs(viewMgr));
if (viewMgr)
viewMgr->UpdateView(view, rect, NS_VMREFRESH_AUTO_DOUBLE_BUFFER | NS_VMREFRESH_IMMEDIATE);
}
}
////////////////////////////////////////////////////////////////////////
nsresult
nsToolbarDragListener::HandleEvent(nsIDOMEvent* aEvent)
@ -148,36 +110,25 @@ nsToolbarDragListener::DragGesture(nsIDOMEvent* aDragEvent)
nsresult
nsToolbarDragListener::DragEnter(nsIDOMEvent* aDragEvent)
{
mCurrentDropLoc = -1;
nsresult rv;
NS_WITH_SERVICE ( nsIDragService, dragService, kCDragServiceCID, &rv );
if ( NS_SUCCEEDED(rv) ) {
nsCOMPtr<nsIDragSession> dragSession(do_QueryInterface(dragService));
if ( dragSession ) {
PRBool flavorSupported = PR_FALSE;
dragSession->IsDataFlavorSupported ( TOOLBARITEM_MIME, &flavorSupported );
if ( flavorSupported ) {
dragSession->SetCanDrop(PR_TRUE);
rv = NS_ERROR_BASE; // consume event
}
else
rv = NS_OK; // don't consume event
}
}
else
rv = NS_OK;
return rv;
// We don't need to do anything special here. If anything does need to be done,
// the code should all be in JS.
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
PRBool
nsToolbarDragListener::IsOnToolbarItem(nsIDOMEvent* aDragEvent, nscoord& aXLoc, PRBool& aIsLegalChild)
//
// ItemMouseIsOver
//
// Figure out which child item mouse is over. |outIndex| is the index of the item the object
// should be dropped _before_. Therefore if the item should be dropped at the end, the index
// will be greater than the number of items in the list. |outOnChild| is true if the item
// is a container and the drop would be "on" that item.
//
void
nsToolbarDragListener :: ItemMouseIsOver ( nsIDOMEvent* aDragEvent, nscoord* outXLoc,
PRUint32* outIndex, PRBool* outOnChild )
{
aIsLegalChild = PR_FALSE;
*outOnChild = PR_FALSE;
nsCOMPtr<nsIDOMUIEvent> uiEvent(do_QueryInterface(aDragEvent));
PRInt32 x,y = 0;
@ -188,8 +139,7 @@ nsToolbarDragListener::IsOnToolbarItem(nsIDOMEvent* aDragEvent, nscoord& aXLoc,
// The mPresContext is set into this class from the nsToolbarFrame
// It's needed here for figuring out twips &
// resetting the active state in the event manager after the drop takes place.
if ( !mPresContext )
return NS_OK;
NS_ASSERTION ( mPresContext, "no pres context set on listener" );
// translate the mouse coords into twips
float p2t;
@ -203,15 +153,15 @@ nsToolbarDragListener::IsOnToolbarItem(nsIDOMEvent* aDragEvent, nscoord& aXLoc,
nsRect tbRect;
mToolbar->GetRect(tbRect);
nscoord count = 0;
PRUint32 count = 0;
PRBool found = PR_FALSE;
nsIFrame* childFrame;
nsRect rect; // child frame's rect
nsRect prevRect(-1, -1, 0, 0);
PRBool found = PR_FALSE;
// Now lop through the child and see if the mouse is over a child
// Now loop through the child and see if the mouse is over a child
mToolbar->FirstChild(nsnull, &childFrame);
while (nsnull != childFrame) {
while ( childFrame ) {
// The mouse coords are in the toolbar's domain
// Get child's rect and adjust to the toolbar's domain
@ -219,15 +169,14 @@ nsToolbarDragListener::IsOnToolbarItem(nsIDOMEvent* aDragEvent, nscoord& aXLoc,
rect.MoveBy(tbRect.x, tbRect.y);
// remember the previous child x location
if (pnt.x < rect.x && prevRect.x == -1) {
if (pnt.x < rect.x && prevRect.x == -1)
prevRect = rect;
}
// now check to see if the mouse inside an items bounds
if (rect.Contains(pnt)) {
nsCOMPtr<nsIContent> content;
nsresult result = childFrame->GetContent(getter_AddRefs(content));
if (NS_OK == result) {
if ( content ) {
nsCOMPtr<nsIAtom> tag;
content->GetTag(*getter_AddRefs(tag));
@ -235,105 +184,122 @@ nsToolbarDragListener::IsOnToolbarItem(nsIDOMEvent* aDragEvent, nscoord& aXLoc,
// XXX but the check for titlebutton should be removed in the future
if (tag.get() == nsXULAtoms::titledbutton || tag.get() == nsXULAtoms::toolbaritem) {
// now check for natural order
PRBool naturalOrder = PR_FALSE;
nsCOMPtr<nsIDOMElement> domElement;
domElement = do_QueryInterface(content);
if (nsnull != domElement ) {
// now check if item is a container
PRBool isContainer = PR_FALSE;
nsCOMPtr<nsIDOMElement> domElement ( do_QueryInterface(content) );
if ( domElement ) {
nsAutoString value;
// maybe naturalorder needs to be an atom
domElement->GetAttribute(nsAutoString("naturalorder"), value);
naturalOrder = value.Equals("true");
domElement->GetAttribute(nsAutoString("container"), value); // can't use an atom here =(
isContainer = value.Equals("true");
}
else
NS_WARNING("Not a DOM element");
// if we have a container, the area is broken up into 3 pieces (left, middle, right). If
// it isn't it's only broken up into two (left and right)
PRInt32 xc = -1;
if ( isContainer ) {
if (pnt.x <= (rect.x + (rect.width / 4))) {
*outIndex = count;
xc = rect.x - tbRect.x;
}
else if (pnt.x >= (rect.x + PRInt32(float(rect.width) *0.75))) {
*outIndex = count + 1;
xc = rect.x - tbRect.x + rect.width - onePixel;
}
else {
// we're on a container, don't draw anything so xc shouldn't get set.
*outIndex = count;
*outOnChild = PR_TRUE;
}
} else {
printf("Not a DOM element\n");
if (pnt.x <= (rect.x + (rect.width / 2))) {
*outIndex = count;
xc = rect.x - tbRect.x;
}
else {
*outIndex = count + 1;
xc = rect.x - tbRect.x + rect.width + onePixel;
}
}
found = PR_TRUE;
// if naturalorder than figure out if it is in the
// left, middle, or right hand side of the item
PRInt32 xc = -1;
if (naturalOrder) {
if (pnt.x <= (rect.x + (rect.width / 4))) {
xc = rect.x-tbRect.x;
} else if (pnt.x >= (rect.x + PRInt32(float(rect.width) *0.75))) {
xc = rect.x-tbRect.x+rect.width-onePixel;
} else {
//printf("no-op\n");
}
} else {
xc = rect.x-tbRect.x;
}
aXLoc = xc;
aIsLegalChild = PR_TRUE;
*outXLoc = xc;
}
return PR_TRUE;
else {
// mouse is over something (probably a spacer) so return the left side of
// the spacer.
found = PR_TRUE;
*outXLoc = rect.x - tbRect.x;
*outIndex = count;
}
// found something, break out of the loop
break;
}
}
} // if mouse is in an item
nsresult rv = childFrame->GetNextSibling(&childFrame);
NS_ASSERTION(rv == NS_OK,"failed to get next child");
count++;
}
} // foreach child
if (!found) {
aXLoc = prevRect.x - tbRect.x;
*outIndex = count; // already incremented past last item
*outXLoc = prevRect.x - tbRect.x + rect.width + onePixel;
}
return PR_FALSE;
}
//
// DragOver
//
// The mouse has moved over the toolbar. Update the drop feedback
// The mouse has moved over the toolbar while a drag is happening. We really just want to
// "annotate" the toolbar with the current drop location. We don't want to make any judgement
// as this stage as to whether or not the drag should be accepted or draw any feedback.
//
//¥¥¥ rewrite to not re-load the service on each mouse moved event. That
//¥¥¥ seriously blows.
nsresult
nsToolbarDragListener::DragOver(nsIDOMEvent* aDragEvent)
{
// now tell the drag session whether we can drop here
nsIDragService* dragService;
nsresult rv = nsServiceManager::GetService(kCDragServiceCID,
nsIDragService::GetIID(),
(nsISupports **)&dragService);
if ( NS_SUCCEEDED(rv) ) {
nsCOMPtr<nsIDragSession> dragSession(do_QueryInterface(dragService));
if ( dragSession ) {
PRBool flavorSupported = PR_FALSE;
dragSession->IsDataFlavorSupported(TOOLBARITEM_MIME, &flavorSupported);
if ( flavorSupported ) {
dragSession->SetCanDrop(PR_TRUE);
// Check to see if the mouse is over an item
nscoord xLoc;
PRBool isLegalChild;
IsOnToolbarItem(aDragEvent, xLoc, isLegalChild);
#if 0
nsCOMPtr<nsIContent> c;
mToolbar->GetContent ( getter_AddRefs(c) );
nsCOMPtr<nsIDOMNode> d ( do_QueryInterface(c) );
nsCOMPtr<nsIDOMNode> t;
aDragEvent->GetTarget ( getter_AddRefs(t) );
printf ( "DRAGOVER:: toolbar content is %ld, as DOMNode %ld, target is %ld\n", c, d, t );
#endif
if (xLoc != mCurrentDropLoc) {
mToolbar->SetDropfeedbackLocation(xLoc);
// force the toolbar frame to redraw
ForceDrawFrame(mToolbar);
// cache the current drop location
mCurrentDropLoc = xLoc;
rv = NS_ERROR_BASE; // means I am consuming the event
}
}
}
nsServiceManager::ReleaseService(kCDragServiceCID, dragService);
}
else
rv = NS_OK; // don't consume event
// NS_OK means event is NOT consumed
return rv;
// Check to see if the mouse is over an item and which one it is.
nscoord xLoc = 0;
PRBool onChild;
PRUint32 beforeIndex = 0;
ItemMouseIsOver(aDragEvent, &xLoc, &beforeIndex, &onChild);
if ( xLoc != mCurrentDropLoc ) {
// stash the new location in the toolbar's content model. Note that the toolbar code doesn't
// care at all about "tb-droplocation", only the coordinate so there is no need to send the
// AttributeChanged() about that attribute.
nsCOMPtr<nsIContent> content;
mToolbar->GetContent ( getter_AddRefs(content) );
if ( content ) {
char buffer[10];
sprintf(buffer, "%ld", xLoc);
content->SetAttribute ( kNameSpaceID_None, nsXULAtoms::tbDropLocationCoord, buffer, PR_TRUE );
sprintf(buffer, "%ld", beforeIndex);
content->SetAttribute ( kNameSpaceID_None, nsXULAtoms::tbDropLocation, "1", PR_FALSE );
content->SetAttribute ( kNameSpaceID_None, nsXULAtoms::tbDropOn, onChild ? "true" : "false", PR_FALSE );
}
// cache the current drop location
mCurrentDropLoc = xLoc;
}
// NS_OK means event is NOT consumed. We want to make sure JS gets this so it
// can determine if the drag is allowed.
return NS_OK;
}
@ -341,25 +307,42 @@ nsToolbarDragListener::DragOver(nsIDOMEvent* aDragEvent)
nsresult
nsToolbarDragListener::DragExit(nsIDOMEvent* aDragEvent)
{
// now tell the drag session whether we can drop here
nsresult rv;
NS_WITH_SERVICE ( nsIDragService, dragService, kCDragServiceCID, &rv );
if ( NS_SUCCEEDED(rv) ) {
nsCOMPtr<nsIDragSession> dragSession(do_QueryInterface(dragService));
if ( dragSession ) {
PRBool flavorSupported = PR_FALSE;
dragSession->IsDataFlavorSupported(TOOLBARITEM_MIME, &flavorSupported);
if ( flavorSupported ) {
mToolbar->SetDropfeedbackLocation(-1); // clears drawing of marker
ForceDrawFrame(mToolbar);
rv = NS_ERROR_BASE; // consume event
}
}
}
else
rv = NS_OK; // don't consume event
// there are some bugs that cause us to not be able to correctly track dragExit events
// so until then we just get on our knees and pray we don't get fooled again.
#if 0
nsCOMPtr<nsIContent> c;
mToolbar->GetContent ( getter_AddRefs(c) );
nsCOMPtr<nsIDOMNode> d ( do_QueryInterface(c) );
nsCOMPtr<nsIDOMNode> t;
aDragEvent->GetTarget ( getter_AddRefs(t) );
printf ( "DRAGEXIT:: toolbar DOMNode %ld, target is %ld\n", d, t );
return rv;
nsCOMPtr<nsIContent> content;
mToolbar->GetContent ( getter_AddRefs(content) );
// we will get a drag exit event on sub items because we catch the event on the way down. If
// the target is not our toolbar, then ignore it.
nsCOMPtr<nsIDOMNode> toolbarDOMNode ( do_QueryInterface(content) );
nsCOMPtr<nsIDOMNode> eventTarget;
aDragEvent->GetTarget ( getter_AddRefs(eventTarget) );
if ( eventTarget != toolbarDOMNode )
return NS_OK;
printf("***REAL EXIT EVENT\n");
// tell the toolbar to not do any more drop feedback. Note that the toolbar code doesn't
// care at all about "tb-droplocation", only the coordinate so there is no need to send the
// AttributeChanged() about that attribute.
char buffer[10];
sprintf(buffer, "%ld", -1);
content->SetAttribute ( kNameSpaceID_None, nsXULAtoms::tbDropLocationCoord, buffer, PR_TRUE );
content->SetAttribute ( kNameSpaceID_None, nsXULAtoms::tbDropLocation, buffer, PR_FALSE );
// cache the current drop location
mCurrentDropLoc = -1;
#endif
return NS_OK; // don't consume event
}

View File

@ -50,7 +50,11 @@ public:
protected:
PRBool IsOnToolbarItem(nsIDOMEvent* aDragEvent, nscoord& aXLoc, PRBool& aIsLegalChild);
// Figure out which child item mouse is over. |outIndex| is the index of the item the object
// should be dropped _before_. Therefore if the item should be dropped at the end, the index
// will be greater than the number of items in the list. |outOnChild| is true if the item
// is a container and the drop would be "on" that item.
void ItemMouseIsOver(nsIDOMEvent* aDragEvent, nscoord* outXLoc, PRUint32* outIndex, PRBool* outOnChild);
nsToolbarFrame * mToolbar; // toolbar owns me, don't be circular
nsIPresContext * mPresContext; // weak reference

View File

@ -33,6 +33,9 @@
#include "nsIContent.h"
#include "nsIPresContext.h"
#include "nsIStyleContext.h"
#include "nsIViewManager.h"
#include "nsXULAtoms.h"
#include "nsINameSpaceManager.h"
#define TEMP_HACK_FOR_BUG_11291 1
#if TEMP_HACK_FOR_BUG_11291
@ -220,8 +223,12 @@ nsToolbarFrame::Init ( nsIPresContext& aPresContext, nsIContent* aContent,
GetContent(getter_AddRefs(content));
nsCOMPtr<nsIDOMEventReceiver> receiver(do_QueryInterface(content));
// register our drag over and exit capturers. These annotate the content object
// with enough info to determine where the drop would happen so that JS can
// do the right thing.
mDragListener = new nsToolbarDragListener(this, &aPresContext);
receiver->AddEventListenerByIID((nsIDOMDragListener *)mDragListener, nsIDOMDragListener::GetIID());
receiver->AddEventListener("dragover", mDragListener, PR_TRUE);
receiver->AddEventListener("dragexit", mDragListener, PR_TRUE);
#if TEMP_HACK_FOR_BUG_11291
// Ok, this is a hack until Ender lands. We need to have a mouse listener on text widgets
@ -266,7 +273,6 @@ nsToolbarFrame :: Paint ( nsIPresContext& aPresContext,
nsresult res = nsBoxFrame::Paint ( aPresContext, aRenderingContext, aDirtyRect, aWhichLayer );
if (mXDropLoc != -1) {
//printf("mXDropLoc: %d\n", mXDropLoc);
// XXX this is temporary
if (!mMarkerStyle) {
nsCOMPtr<nsIAtom> atom ( getter_AddRefs(NS_NewAtom(":-moz-drop-marker")) );
@ -281,7 +287,6 @@ nsToolbarFrame :: Paint ( nsIPresContext& aPresContext,
} else {
color = NS_RGB(0,0,0);
}
//printf("paint %d\n", mXDropLoc);
aRenderingContext.SetColor(color);
aRenderingContext.DrawLine(mXDropLoc, 0, mXDropLoc, mRect.height);
}
@ -376,3 +381,59 @@ nsToolbarFrame::ReResolveStyles(nsIPresContext& aPresContext,
}
#endif
////////////////////////////////////////////////////////////////////////
// This is temporary until the bubling of event for CSS actions work
////////////////////////////////////////////////////////////////////////
static void ForceDrawFrame(nsIFrame * aFrame);
static void ForceDrawFrame(nsIFrame * aFrame)
{
if (aFrame == nsnull) {
return;
}
nsRect rect;
nsIView * view;
nsPoint pnt;
aFrame->GetOffsetFromView(pnt, &view);
aFrame->GetRect(rect);
rect.x = pnt.x;
rect.y = pnt.y;
if (view) {
nsCOMPtr<nsIViewManager> viewMgr;
view->GetViewManager(*getter_AddRefs(viewMgr));
if (viewMgr)
viewMgr->UpdateView(view, rect, NS_VMREFRESH_AUTO_DOUBLE_BUFFER | NS_VMREFRESH_IMMEDIATE);
}
}
//
// AttributeChanged
//
// Track several attributes set by the d&d drop feedback tracking mechanism. The first
// is the "tb-triggerrepaint" attribute so JS can trigger a repaint when it
// needs up update the drop feedback. The second is the x (or y, if bar is vertical)
// coordinate of where the drop feedback bar should be drawn.
//
NS_IMETHODIMP
nsToolbarFrame :: AttributeChanged ( nsIPresContext* aPresContext, nsIContent* aChild,
nsIAtom* aAttribute, PRInt32 aHint)
{
nsresult rv = NS_OK;
if ( aAttribute == nsXULAtoms::tbTriggerRepaint )
ForceDrawFrame ( this );
else if ( aAttribute == nsXULAtoms::tbDropLocationCoord ) {
nsAutoString attribute;
aChild->GetAttribute ( kNameSpaceID_None, aAttribute, attribute );
char* iHateNSString = attribute.ToNewCString();
mXDropLoc = atoi( iHateNSString );
nsAllocator::Free ( iHateNSString );
}
else
rv = nsBoxFrame::AttributeChanged ( aPresContext, aChild, aAttribute, aHint );
return rv;
} // AttributeChanged

View File

@ -76,6 +76,10 @@ public:
NS_IMETHOD HandleEvent(nsIPresContext& aPresContext,
nsGUIEvent* aEvent,
nsEventStatus& aEventStatus);
NS_IMETHOD AttributeChanged(nsIPresContext* aPresContext,
nsIContent* aChild,
nsIAtom* aAttribute,
PRInt32 aHint) ;
#if WTF_IS_THIS
//¥¥¥ not sure at all where this comes from. I asked rods, no reply yet.
@ -85,7 +89,9 @@ public:
PRInt32* aLocalChange);
#endif
#if 0
void SetDropfeedbackLocation(nscoord aX) { mXDropLoc = aX; }
#endif
protected: