From 122f2d8f5acc8abc237d044b34a4ee530a7cfcdc Mon Sep 17 00:00:00 2001 From: "pinkerton%netscape.com" Date: Thu, 9 Sep 1999 06:27:25 +0000 Subject: [PATCH] turn listener into a capturer and pass more off to JS. --- layout/xul/base/src/nsToolbarDragListener.cpp | 309 +++++++++--------- layout/xul/base/src/nsToolbarDragListener.h | 6 +- layout/xul/base/src/nsToolbarFrame.cpp | 67 +++- layout/xul/base/src/nsToolbarFrame.h | 6 + 4 files changed, 221 insertions(+), 167 deletions(-) diff --git a/layout/xul/base/src/nsToolbarDragListener.cpp b/layout/xul/base/src/nsToolbarDragListener.cpp index 63d6d7f92ac3..d88222063f89 100644 --- a/layout/xul/base/src/nsToolbarDragListener.cpp +++ b/layout/xul/base/src/nsToolbarDragListener.cpp @@ -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 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 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 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 content; nsresult result = childFrame->GetContent(getter_AddRefs(content)); - if (NS_OK == result) { + if ( content ) { nsCOMPtr 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 domElement; - domElement = do_QueryInterface(content); - if (nsnull != domElement ) { + // now check if item is a container + PRBool isContainer = PR_FALSE; + nsCOMPtr 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 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 c; +mToolbar->GetContent ( getter_AddRefs(c) ); +nsCOMPtr d ( do_QueryInterface(c) ); +nsCOMPtr 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 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 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 c; +mToolbar->GetContent ( getter_AddRefs(c) ); +nsCOMPtr d ( do_QueryInterface(c) ); +nsCOMPtr t; +aDragEvent->GetTarget ( getter_AddRefs(t) ); +printf ( "DRAGEXIT:: toolbar DOMNode %ld, target is %ld\n", d, t ); - return rv; + nsCOMPtr 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 toolbarDOMNode ( do_QueryInterface(content) ); + nsCOMPtr 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 } diff --git a/layout/xul/base/src/nsToolbarDragListener.h b/layout/xul/base/src/nsToolbarDragListener.h index 94f9b38cc032..76862523ab82 100644 --- a/layout/xul/base/src/nsToolbarDragListener.h +++ b/layout/xul/base/src/nsToolbarDragListener.h @@ -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 diff --git a/layout/xul/base/src/nsToolbarFrame.cpp b/layout/xul/base/src/nsToolbarFrame.cpp index 144ac98ed479..353ed95a6d01 100644 --- a/layout/xul/base/src/nsToolbarFrame.cpp +++ b/layout/xul/base/src/nsToolbarFrame.cpp @@ -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 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 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 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 \ No newline at end of file diff --git a/layout/xul/base/src/nsToolbarFrame.h b/layout/xul/base/src/nsToolbarFrame.h index 992c2cc9d6d8..07034df03f74 100644 --- a/layout/xul/base/src/nsToolbarFrame.h +++ b/layout/xul/base/src/nsToolbarFrame.h @@ -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: