Bug 455590, use new drag and drop api with trees, r=neil,sr=smaug
authorNeil Deakin <neil@mozilla.com>
Wed, 24 Jun 2009 13:12:33 -0400
changeset 29545 5fca16b4c17fd4f25e7c2932ed33fdb36e5ada72
parent 29544 7f9ef4bef487138d94f350eed689c9bf11b56abb
child 29546 8db1f8aff01cfe00d293b0d0e1494b6a742191bb
push idunknown
push userunknown
push dateunknown
reviewersneil, smaug
bugs455590
milestone1.9.2a1pre
Bug 455590, use new drag and drop api with trees, r=neil,sr=smaug
content/base/public/nsContentUtils.h
content/base/src/nsContentUtils.cpp
content/events/src/nsDOMDataTransfer.h
content/events/src/nsDOMDragEvent.cpp
content/events/src/nsDOMDragEvent.h
content/events/src/nsEventStateManager.cpp
content/xul/templates/public/nsIXULTemplateBuilder.idl
content/xul/templates/src/nsXULTreeBuilder.cpp
layout/inspector/src/inDOMView.cpp
layout/xul/base/src/tree/public/nsITreeView.idl
layout/xul/base/src/tree/src/Makefile.in
layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
layout/xul/base/src/tree/src/nsTreeContentView.cpp
security/manager/pki/src/nsASN1Tree.cpp
security/manager/ssl/src/nsCertTree.cpp
toolkit/components/autocomplete/src/nsAutoCompleteController.cpp
toolkit/components/filepicker/src/nsFileView.cpp
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1252,16 +1252,25 @@ public:
    */
   static void HidePopupsInDocument(nsIDocument* aDocument);
 
   /**
    * Retrieve the current drag session, or null if no drag is currently occuring
    */
   static already_AddRefed<nsIDragSession> GetDragSession();
 
+  /*
+   * Initialize and set the dataTransfer field of an nsDragEvent.
+   */
+  static nsresult SetDataTransferInEvent(nsDragEvent* aDragEvent);
+
+  // filters the drag and drop action to fit within the effects allowed and
+  // returns it.
+  static PRUint32 FilterDropEffect(PRUint32 aAction, PRUint32 aEffectAllowed);
+
   /**
    * Return true if aURI is a local file URI (i.e. file://).
    */
   static PRBool URIIsLocalFile(nsIURI *aURI);
 
   /**
    * If aContent is an HTML element with a DOM level 0 'name', then
    * return the name. Otherwise return null.
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -157,16 +157,18 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_
 #include "nsIUGenCategory.h"
 #include "nsIDragService.h"
 #include "nsIChannelEventSink.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIOfflineCacheUpdate.h"
 #include "nsCPrefetchService.h"
 #include "nsIChromeRegistry.h"
 #include "nsIMIMEHeaderParam.h"
+#include "nsIDOMDragEvent.h"
+#include "nsDOMDataTransfer.h"
 
 #ifdef IBMBIDI
 #include "nsIBidiKeyboard.h"
 #endif
 #include "nsCycleCollectionParticipant.h"
 
 // for ReportToConsole
 #include "nsIStringBundle.h"
@@ -4524,16 +4526,125 @@ nsContentUtils::GetDragSession()
   nsCOMPtr<nsIDragService> dragService =
     do_GetService("@mozilla.org/widget/dragservice;1");
   if (dragService)
     dragService->GetCurrentSession(&dragSession);
   return dragSession;
 }
 
 /* static */
+nsresult
+nsContentUtils::SetDataTransferInEvent(nsDragEvent* aDragEvent)
+{
+  if (aDragEvent->dataTransfer || !NS_IS_TRUSTED_EVENT(aDragEvent))
+    return NS_OK;
+
+  // For draggesture and dragstart events, the data transfer object is
+  // created before the event fires, so it should already be set. For other
+  // drag events, get the object from the drag session.
+  NS_ASSERTION(aDragEvent->message != NS_DRAGDROP_GESTURE &&
+               aDragEvent->message != NS_DRAGDROP_START,
+               "draggesture event created without a dataTransfer");
+
+  nsCOMPtr<nsIDragSession> dragSession = GetDragSession();
+  NS_ENSURE_TRUE(dragSession, NS_OK); // no drag in progress
+
+  nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer;
+  dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer));
+  if (!initialDataTransfer) {
+    // A dataTransfer won't exist when a drag was started by some other
+    // means, for instance calling the drag service directly, or a drag
+    // from another application. In either case, a new dataTransfer should
+    // be created that reflects the data. Pass true to the constructor for
+    // the aIsExternal argument, so that only system access is allowed.
+    PRUint32 action = 0;
+    dragSession->GetDragAction(&action);
+    initialDataTransfer =
+      new nsDOMDataTransfer(aDragEvent->message, action);
+    NS_ENSURE_TRUE(initialDataTransfer, NS_ERROR_OUT_OF_MEMORY);
+
+    // now set it in the drag session so we don't need to create it again
+    dragSession->SetDataTransfer(initialDataTransfer);
+  }
+
+  // each event should use a clone of the original dataTransfer.
+  nsCOMPtr<nsIDOMNSDataTransfer> initialDataTransferNS =
+    do_QueryInterface(initialDataTransfer);
+  NS_ENSURE_TRUE(initialDataTransferNS, NS_ERROR_FAILURE);
+  initialDataTransferNS->Clone(aDragEvent->message, aDragEvent->userCancelled,
+                               getter_AddRefs(aDragEvent->dataTransfer));
+  NS_ENSURE_TRUE(aDragEvent->dataTransfer, NS_ERROR_OUT_OF_MEMORY);
+
+  // for the dragenter and dragover events, initialize the drop effect
+  // from the drop action, which platform specific widget code sets before
+  // the event is fired based on the keyboard state.
+  if (aDragEvent->message == NS_DRAGDROP_ENTER ||
+      aDragEvent->message == NS_DRAGDROP_OVER) {
+    nsCOMPtr<nsIDOMNSDataTransfer> newDataTransfer =
+      do_QueryInterface(aDragEvent->dataTransfer);
+    NS_ENSURE_TRUE(newDataTransfer, NS_ERROR_FAILURE);
+
+    PRUint32 action, effectAllowed;
+    dragSession->GetDragAction(&action);
+    newDataTransfer->GetEffectAllowedInt(&effectAllowed);
+    newDataTransfer->SetDropEffectInt(FilterDropEffect(action, effectAllowed));
+  }
+  else if (aDragEvent->message == NS_DRAGDROP_DROP ||
+           aDragEvent->message == NS_DRAGDROP_DRAGDROP ||
+           aDragEvent->message == NS_DRAGDROP_END) {
+    // For the drop and dragend events, set the drop effect based on the
+    // last value that the dropEffect had. This will have been set in
+    // nsEventStateManager::PostHandleEvent for the last dragenter or
+    // dragover event.
+    nsCOMPtr<nsIDOMNSDataTransfer> newDataTransfer =
+      do_QueryInterface(aDragEvent->dataTransfer);
+    NS_ENSURE_TRUE(newDataTransfer, NS_ERROR_FAILURE);
+
+    PRUint32 dropEffect;
+    initialDataTransferNS->GetDropEffectInt(&dropEffect);
+    newDataTransfer->SetDropEffectInt(dropEffect);
+  }
+
+  return NS_OK;
+}
+
+/* static */
+PRUint32
+nsContentUtils::FilterDropEffect(PRUint32 aAction, PRUint32 aEffectAllowed)
+{
+  // It is possible for the drag action to include more than one action, but
+  // the widget code which sets the action from the keyboard state should only
+  // be including one. If multiple actions were set, we just consider them in
+  //  the following order:
+  //   copy, link, move
+  if (aAction & nsIDragService::DRAGDROP_ACTION_COPY)
+    aAction = nsIDragService::DRAGDROP_ACTION_COPY;
+  else if (aAction & nsIDragService::DRAGDROP_ACTION_LINK)
+    aAction = nsIDragService::DRAGDROP_ACTION_LINK;
+  else if (aAction & nsIDragService::DRAGDROP_ACTION_MOVE)
+    aAction = nsIDragService::DRAGDROP_ACTION_MOVE;
+
+  // Filter the action based on the effectAllowed. If the effectAllowed
+  // doesn't include the action, then that action cannot be done, so adjust
+  // the action to something that is allowed. For a copy, adjust to move or
+  // link. For a move, adjust to copy or link. For a link, adjust to move or
+  // link. Otherwise, use none.
+  if (aAction & aEffectAllowed ||
+      aEffectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED)
+    return aAction;
+  if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_MOVE)
+    return nsIDragService::DRAGDROP_ACTION_MOVE;
+  if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_COPY)
+    return nsIDragService::DRAGDROP_ACTION_COPY;
+  if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_LINK)
+    return nsIDragService::DRAGDROP_ACTION_LINK;
+  return nsIDragService::DRAGDROP_ACTION_NONE;
+}
+
+/* static */
 PRBool
 nsContentUtils::URIIsLocalFile(nsIURI *aURI)
 {
   PRBool isFile;
   nsCOMPtr<nsINetUtil> util = do_QueryInterface(sIOService);
 
   return util && NS_SUCCEEDED(util->ProtocolHasFlags(aURI,
                                 nsIProtocolHandler::URI_IS_LOCAL_FILE,
--- a/content/events/src/nsDOMDataTransfer.h
+++ b/content/events/src/nsDOMDataTransfer.h
@@ -69,16 +69,17 @@ public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_NSIDOMDATATRANSFER
   NS_DECL_NSIDOMNSDATATRANSFER
 
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsDOMDataTransfer, nsIDOMDataTransfer)
 
   friend class nsDOMDragEvent;
   friend class nsEventStateManager;
+  friend class nsContentUtils;
 
 protected:
 
   // the constructors are protected so only our friends can call them
 
   // default constructor used for the dragstart/draggesture event and
   // synthetic events
   nsDOMDataTransfer();
--- a/content/events/src/nsDOMDragEvent.cpp
+++ b/content/events/src/nsDOMDragEvent.cpp
@@ -113,142 +113,38 @@ nsDOMDragEvent::InitDragEventNS(const ns
                                 nsIDOMDataTransfer* aDataTransfer)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 nsDOMDragEvent::GetDataTransfer(nsIDOMDataTransfer** aDataTransfer)
 {
+  // the dataTransfer field of the event caches the DataTransfer associated
+  // with the drag. It is initialized when an attempt is made to retrieve it
+  // rather that when the event is created to avoid duplicating the data when
+  // no listener ever uses it.
   *aDataTransfer = nsnull;
 
   if (!mEvent || mEvent->eventStructType != NS_DRAG_EVENT) {
     NS_WARNING("Tried to get dataTransfer from non-drag event!");
     return NS_OK;
   }
 
-  // the dataTransfer field of the event caches the DataTransfer associated
-  // with the drag. It is initialized when an attempt is made to retrieve it
-  // rather that when the event is created to avoid duplicating the data when
-  // no listener ever uses it.
   nsDragEvent* dragEvent = static_cast<nsDragEvent*>(mEvent);
-  if (dragEvent->dataTransfer) {
-    CallQueryInterface(dragEvent->dataTransfer, aDataTransfer);
-    return NS_OK;
-  }
-
-  // for synthetic events, just use the supplied data transfer object
-  if (mEventIsInternal) {
-    NS_IF_ADDREF(*aDataTransfer = dragEvent->dataTransfer);
-    return NS_OK;
-  }
-
-  // For draggesture and dragstart events, the data transfer object is
-  // created before the event fires, so it should already be set. For other
-  // drag events, get the object from the drag session.
-  NS_ASSERTION(mEvent->message != NS_DRAGDROP_GESTURE &&
-               mEvent->message != NS_DRAGDROP_START,
-               "draggesture event created without a dataTransfer");
-
-  nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
-  NS_ENSURE_TRUE(dragSession, NS_OK); // no drag in progress
-
-  nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer;
-  dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer));
-  if (!initialDataTransfer) {
-    // A dataTransfer won't exist when a drag was started by some other
-    // means, for instance calling the drag service directly, or a drag
-    // from another application. In either case, a new dataTransfer should
-    // be created that reflects the data. Pass true to the constructor for
-    // the aIsExternal argument, so that only system access is allowed.
-    PRUint32 action = 0;
-    dragSession->GetDragAction(&action);
-    initialDataTransfer =
-      new nsDOMDataTransfer(mEvent->message, action);
-    NS_ENSURE_TRUE(initialDataTransfer, NS_ERROR_OUT_OF_MEMORY);
-
-    // now set it in the drag session so we don't need to create it again
-    dragSession->SetDataTransfer(initialDataTransfer);
-  }
-
-  // each event should use a clone of the original dataTransfer.
-  nsCOMPtr<nsIDOMNSDataTransfer> initialDataTransferNS =
-    do_QueryInterface(initialDataTransfer);
-  NS_ENSURE_TRUE(initialDataTransferNS, NS_ERROR_FAILURE);
-  initialDataTransferNS->Clone(mEvent->message, dragEvent->userCancelled,
-                               getter_AddRefs(dragEvent->dataTransfer));
-  NS_ENSURE_TRUE(dragEvent->dataTransfer, NS_ERROR_OUT_OF_MEMORY);
-
-  // for the dragenter and dragover events, initialize the drop effect
-  // from the drop action, which platform specific widget code sets before
-  // the event is fired based on the keyboard state.
-  if (mEvent->message == NS_DRAGDROP_ENTER ||
-      mEvent->message == NS_DRAGDROP_OVER) {
-    nsCOMPtr<nsIDOMNSDataTransfer> newDataTransfer =
-      do_QueryInterface(dragEvent->dataTransfer);
-    NS_ENSURE_TRUE(newDataTransfer, NS_ERROR_FAILURE);
-
-    PRUint32 action, effectAllowed;
-    dragSession->GetDragAction(&action);
-    newDataTransfer->GetEffectAllowedInt(&effectAllowed);
-    newDataTransfer->SetDropEffectInt(FilterDropEffect(action, effectAllowed));
-  }
-  else if (mEvent->message == NS_DRAGDROP_DROP ||
-           mEvent->message == NS_DRAGDROP_DRAGDROP ||
-           mEvent->message == NS_DRAGDROP_END) {
-    // For the drop and dragend events, set the drop effect based on the
-    // last value that the dropEffect had. This will have been set in
-    // nsEventStateManager::PostHandleEvent for the last dragenter or
-    // dragover event.
-    nsCOMPtr<nsIDOMNSDataTransfer> newDataTransfer =
-      do_QueryInterface(dragEvent->dataTransfer);
-    NS_ENSURE_TRUE(newDataTransfer, NS_ERROR_FAILURE);
-
-    PRUint32 dropEffect;
-    initialDataTransferNS->GetDropEffectInt(&dropEffect);
-    newDataTransfer->SetDropEffectInt(dropEffect);
+  // for synthetic events, just use the supplied data transfer object even if null
+  if (!mEventIsInternal) {
+    nsresult rv = nsContentUtils::SetDataTransferInEvent(dragEvent);
+    NS_ENSURE_SUCCESS(rv, rv);
   }
 
   NS_IF_ADDREF(*aDataTransfer = dragEvent->dataTransfer);
   return NS_OK;
 }
 
-// static
-PRUint32
-nsDOMDragEvent::FilterDropEffect(PRUint32 aAction, PRUint32 aEffectAllowed)
-{
-  // It is possible for the drag action to include more than one action, but
-  // the widget code which sets the action from the keyboard state should only
-  // be including one. If multiple actions were set, we just consider them in
-  //  the following order:
-  //   copy, link, move
-  if (aAction & nsIDragService::DRAGDROP_ACTION_COPY)
-    aAction = nsIDragService::DRAGDROP_ACTION_COPY;
-  else if (aAction & nsIDragService::DRAGDROP_ACTION_LINK)
-    aAction = nsIDragService::DRAGDROP_ACTION_LINK;
-  else if (aAction & nsIDragService::DRAGDROP_ACTION_MOVE)
-    aAction = nsIDragService::DRAGDROP_ACTION_MOVE;
-
-  // Filter the action based on the effectAllowed. If the effectAllowed
-  // doesn't include the action, then that action cannot be done, so adjust
-  // the action to something that is allowed. For a copy, adjust to move or
-  // link. For a move, adjust to copy or link. For a link, adjust to move or
-  // link. Otherwise, use none.
-  if (aAction & aEffectAllowed ||
-      aEffectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED)
-    return aAction;
-  if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_MOVE)
-    return nsIDragService::DRAGDROP_ACTION_MOVE;
-  if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_COPY)
-    return nsIDragService::DRAGDROP_ACTION_COPY;
-  if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_LINK)
-    return nsIDragService::DRAGDROP_ACTION_LINK;
-  return nsIDragService::DRAGDROP_ACTION_NONE;
-}
-
 nsresult NS_NewDOMDragEvent(nsIDOMEvent** aInstancePtrResult,
                             nsPresContext* aPresContext,
                             nsDragEvent *aEvent) 
 {
   nsDOMDragEvent* event = new nsDOMDragEvent(aPresContext, aEvent);
   NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
 
   return CallQueryInterface(event, aInstancePtrResult);
--- a/content/events/src/nsDOMDragEvent.h
+++ b/content/events/src/nsDOMDragEvent.h
@@ -52,18 +52,15 @@ public:
   nsDOMDragEvent(nsPresContext* aPresContext, nsInputEvent* aEvent);
   virtual ~nsDOMDragEvent();
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_NSIDOMDRAGEVENT
   
   NS_FORWARD_TO_NSDOMMOUSEEVENT
-
-  // filters the action to fit within the effects allowed and returns it.
-  static PRUint32 FilterDropEffect(PRUint32 aAction, PRUint32 aEffectAllowed);
 };
 
 nsresult NS_NewDOMDragEvent(nsIDOMEvent** aInstancePtrResult,
                             nsPresContext* aPresContext,
                             nsDragEvent* aEvent);
 
 #endif // nsDOMDragEvent_h__
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -2833,17 +2833,17 @@ nsEventStateManager::PostHandleEvent(nsP
           // based on the effectAllowed below.
           dataTransfer = initialDataTransferNS;
 
           PRUint32 action;
           dragSession->GetDragAction(&action);
 
           // filter the drop effect based on the action. Use UNINITIALIZED as
           // any effect is allowed.
-          dropEffect = nsDOMDragEvent::FilterDropEffect(action,
+          dropEffect = nsContentUtils::FilterDropEffect(action,
                          nsIDragService::DRAGDROP_ACTION_UNINITIALIZED);
         }
 
         // At this point, if the dataTransfer is null, it means that the
         // drag was originally started by directly calling the drag service.
         // Just assume that all effects are allowed.
         PRUint32 effectAllowed = nsIDragService::DRAGDROP_ACTION_UNINITIALIZED;
         if (dataTransfer)
--- a/content/xul/templates/public/nsIXULTemplateBuilder.idl
+++ b/content/xul/templates/public/nsIXULTemplateBuilder.idl
@@ -46,16 +46,17 @@
 interface nsIAtom;
 interface nsIContent;
 interface nsIXULBuilderListener;
 interface nsIXULTemplateResult;
 interface nsIXULTemplateRuleFilter;
 interface nsIXULTemplateQueryProcessor;
 interface nsIRDFResource;
 interface nsIRDFCompositeDataSource;
+interface nsIDOMDataTransfer;
 
 /**
  * A template builder, given an input source of data, a template, and a
  * reference point, generates a list of results from the input, and copies
  * part of the template for each result. Templates may generate content
  * recursively, using the same template, but with the previous iteration's
  * results as the reference point. As an example, for an XML datasource the
  * initial reference point would be a specific node in the DOM tree and a
@@ -349,35 +350,35 @@ interface nsIXULTemplateBuilder : nsISup
 };
 
 /**
  * nsIXULTreeBuilderObserver
  *  This interface allows clients of the XULTreeBuilder to define domain 
  *  specific handling of specific nsITreeView methods that 
  *  XULTreeBuilder does not implement.
  */
-[scriptable, uuid(a5480e0d-ac7c-42e5-aca5-d7f0bbffa207)]
+[scriptable, uuid(57CED9A7-EC0B-4A0E-8AEB-5DA32EBE951C)]
 interface nsIXULTreeBuilderObserver : nsISupports
 {
     const long DROP_BEFORE = -1;
     const long DROP_ON = 0;
     const long DROP_AFTER = 1;
     /**
      * Methods used by the drag feedback code to determine if a drag is allowable at
      * the current location. To get the behavior where drops are only allowed on
      * items, such as the mailNews folder pane, always return false whe
      * the orientation is not DROP_ON.
      */
-    boolean canDrop(in long index, in long orientation);
+    boolean canDrop(in long index, in long orientation, in nsIDOMDataTransfer dataTransfer);
 
     /**
      * Called when the user drops something on this view. The |orientation| param
      * specifies before/on/after the given |row|.
      */
-    void onDrop(in long row, in long orientation);
+    void onDrop(in long row, in long orientation, in nsIDOMDataTransfer dataTransfer);
  
     /** 
      * Called when an item is opened or closed. 
      */
     void onToggleOpenState (in long index);
 
     /** 
 	 * Called when a header is clicked.
--- a/content/xul/templates/src/nsXULTreeBuilder.cpp
+++ b/content/xul/templates/src/nsXULTreeBuilder.cpp
@@ -1885,48 +1885,49 @@ nsXULTreeBuilder::SortSubtree(nsTreeRows
     }
 
     return NS_OK;
 }
 
 
 /* boolean canDrop (in long index, in long orientation); */
 NS_IMETHODIMP
-nsXULTreeBuilder::CanDrop(PRInt32 index, PRInt32 orientation, PRBool *_retval)
+nsXULTreeBuilder::CanDrop(PRInt32 index, PRInt32 orientation,
+                          nsIDOMDataTransfer* dataTransfer, PRBool *_retval)
 {
     *_retval = PR_FALSE;
     if (mObservers) {
         PRUint32 count;
         mObservers->Count(&count);
         for (PRUint32 i = 0; i < count; ++i) {
             nsCOMPtr<nsIXULTreeBuilderObserver> observer = do_QueryElementAt(mObservers, i);
             if (observer) {
-                observer->CanDrop(index, orientation, _retval);
+                observer->CanDrop(index, orientation, dataTransfer, _retval);
                 if (*_retval)
                     break;
             }
         }
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
-nsXULTreeBuilder::Drop(PRInt32 row, PRInt32 orient)
+nsXULTreeBuilder::Drop(PRInt32 row, PRInt32 orient, nsIDOMDataTransfer* dataTransfer)
 {
     if (mObservers) {
         PRUint32 count;
         mObservers->Count(&count);
         for (PRUint32 i = 0; i < count; ++i) {
             nsCOMPtr<nsIXULTreeBuilderObserver> observer = do_QueryElementAt(mObservers, i);
             if (observer) {
                 PRBool canDrop = PR_FALSE;
-                observer->CanDrop(row, orient, &canDrop);
+                observer->CanDrop(row, orient, dataTransfer, &canDrop);
                 if (canDrop)
-                    observer->OnDrop(row, orient);
+                    observer->OnDrop(row, orient, dataTransfer);
             }
         }
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/layout/inspector/src/inDOMView.cpp
+++ b/layout/inspector/src/inDOMView.cpp
@@ -655,24 +655,25 @@ inDOMView::IsSeparator(PRInt32 index, PR
 
 NS_IMETHODIMP
 inDOMView::IsSorted(PRBool *_retval)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-inDOMView::CanDrop(PRInt32 index, PRInt32 orientation, PRBool *_retval)
+inDOMView::CanDrop(PRInt32 index, PRInt32 orientation,
+                   nsIDOMDataTransfer* aDataTransfer, PRBool *_retval)
 {
   *_retval = PR_FALSE;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-inDOMView::Drop(PRInt32 row, PRInt32 orientation)
+inDOMView::Drop(PRInt32 row, PRInt32 orientation, nsIDOMDataTransfer* aDataTransfer)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 inDOMView::PerformAction(const PRUnichar *action)
 {
   return NS_OK;
--- a/layout/xul/base/src/tree/public/nsITreeView.idl
+++ b/layout/xul/base/src/tree/public/nsITreeView.idl
@@ -38,18 +38,19 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsITreeBoxObject.idl"
 #include "nsISupportsArray.idl"
 #include "domstubs.idl"
 
 interface nsITreeSelection;
 interface nsITreeColumn;
+interface nsIDOMDataTransfer;
 
-[scriptable, uuid(637276b5-58c0-4eff-89ea-c7f3c5bf0b54)]
+[scriptable, uuid(C06DC4D3-63A2-4422-A0A3-5F2EDDECA8C1)]
 interface nsITreeView : nsISupports
 {
   /**
    * The total number of rows in the tree (including the offscreen rows).
    */
   readonly attribute long rowCount;
 
   /**
@@ -102,24 +103,24 @@ interface nsITreeView : nsISupports
   const short DROP_ON = 0;
   const short DROP_AFTER = 1;
   /**
    * Methods used by the drag feedback code to determine if a drag is allowable at
    * the current location. To get the behavior where drops are only allowed on
    * items, such as the mailNews folder pane, always return false when
    * the orientation is not DROP_ON.
    */
-  boolean canDrop(in long index, in long orientation);
-  
+  boolean canDrop(in long index, in long orientation, in nsIDOMDataTransfer dataTransfer);
+
   /**
    * Called when the user drops something on this view. The |orientation| param
    * specifies before/on/after the given |row|.
    */
-  void drop(in long row, in long orientation); 
-  
+  void drop(in long row, in long orientation, in nsIDOMDataTransfer dataTransfer);
+
   /**
    * Methods used by the tree to draw thread lines in the tree.
    * getParentIndex is used to obtain the index of a parent row.
    * If there is no parent row, getParentIndex returns -1.
    */
   long getParentIndex(in long rowIndex);
 
   /**
--- a/layout/xul/base/src/tree/src/Makefile.in
+++ b/layout/xul/base/src/tree/src/Makefile.in
@@ -79,16 +79,17 @@ CPPSRCS		= \
 
 EXPORTS		= \
 		nsTreeColFrame.h \
 		nsTreeUtils.h \
 		$(NULL)
 
 LOCAL_INCLUDES	= \
 		-I$(srcdir) \
+		-I$(srcdir)/../../../../../../content/events/src \
 		-I$(srcdir)/../../../../base/src \
 		-I$(srcdir)/../../../../../base \
 		-I$(srcdir)/../../../../../generic \
 		-I$(srcdir)/../../../../../style \
 		-I$(srcdir)/../../../../../forms \
 		$(NULL)
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
--- a/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
+++ b/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
@@ -2713,19 +2713,24 @@ nsTreeBodyFrame::HandleEvent(nsPresConte
               // This node isn't expanded, set a timer to expand it.
               CreateTimer(nsILookAndFeel::eMetric_TreeOpenDelay,
                           OpenCallback, nsITimer::TYPE_ONE_SHOT,
                           getter_AddRefs(mSlots->mTimer));
             }
           }
         }
 
+        NS_ASSERTION(aEvent->eventStructType == NS_DRAG_EVENT, "wrong event type");
+        nsDragEvent* dragEvent = static_cast<nsDragEvent*>(aEvent);
+        nsContentUtils::SetDataTransferInEvent(dragEvent);
+
         PRBool canDropAtNewLocation = PR_FALSE;
-        mView->CanDrop(mSlots->mDropRow, mSlots->mDropOrient, &canDropAtNewLocation);
-      
+        mView->CanDrop(mSlots->mDropRow, mSlots->mDropOrient,
+                       dragEvent->dataTransfer, &canDropAtNewLocation);
+
         if (canDropAtNewLocation) {
           // Invalidate row at the new location.
           mSlots->mDropAllowed = canDropAtNewLocation;
           InvalidateDropFeedback(mSlots->mDropRow, mSlots->mDropOrient);
         }
       }
     }
 
@@ -2744,17 +2749,21 @@ nsTreeBodyFrame::HandleEvent(nsPresConte
     // Remove the drop folder and all its parents from the array.
     PRInt32 parentIndex;
     nsresult rv = mView->GetParentIndex(mSlots->mDropRow, &parentIndex);
     while (NS_SUCCEEDED(rv) && parentIndex >= 0) {
       mSlots->mArray.RemoveElement(parentIndex);
       rv = mView->GetParentIndex(parentIndex, &parentIndex);
     }
 
-    mView->Drop(mSlots->mDropRow, mSlots->mDropOrient);
+    NS_ASSERTION(aEvent->eventStructType == NS_DRAG_EVENT, "wrong event type");
+    nsDragEvent* dragEvent = static_cast<nsDragEvent*>(aEvent);
+    nsContentUtils::SetDataTransferInEvent(dragEvent);
+
+    mView->Drop(mSlots->mDropRow, mSlots->mDropOrient, dragEvent->dataTransfer);
     mSlots->mDropRow = -1;
     mSlots->mDropOrient = -1;
     *aEventStatus = nsEventStatus_eConsumeNoDefault; // already handled the drop
   }
   else if (aEvent->message == NS_DRAGDROP_EXIT) {
     // this event was meant for another frame, so ignore it
     if (!mSlots)
       return NS_OK;
--- a/layout/xul/base/src/tree/src/nsTreeContentView.cpp
+++ b/layout/xul/base/src/tree/src/nsTreeContentView.cpp
@@ -330,29 +330,30 @@ NS_IMETHODIMP
 nsTreeContentView::IsSorted(PRBool *_retval)
 {
   *_retval = PR_FALSE;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsTreeContentView::CanDrop(PRInt32 aIndex, PRInt32 aOrientation, PRBool *_retval)
+nsTreeContentView::CanDrop(PRInt32 aIndex, PRInt32 aOrientation,
+                           nsIDOMDataTransfer* aDataTransfer, PRBool *_retval)
 {
   NS_PRECONDITION(aIndex >= 0 && aIndex < PRInt32(mRows.Length()), "bad index");
   if (aIndex < 0 || aIndex >= PRInt32(mRows.Length()))
     return NS_ERROR_INVALID_ARG;   
 
   *_retval = PR_FALSE;
  
   return NS_OK;
 }
  
 NS_IMETHODIMP
-nsTreeContentView::Drop(PRInt32 aRow, PRInt32 aOrientation)
+nsTreeContentView::Drop(PRInt32 aRow, PRInt32 aOrientation, nsIDOMDataTransfer* aDataTransfer)
 {
   NS_PRECONDITION(aRow >= 0 && aRow < PRInt32(mRows.Length()), "bad row");
   if (aRow < 0 || aRow >= PRInt32(mRows.Length()))
     return NS_ERROR_INVALID_ARG;   
 
   return NS_OK;
 }
 
--- a/security/manager/pki/src/nsASN1Tree.cpp
+++ b/security/manager/pki/src/nsASN1Tree.cpp
@@ -446,29 +446,30 @@ nsNSSASN1Tree::PerformActionOnCell(const
                                    nsITreeColumn* col)
 {
   return NS_OK;
 }
 
 //
 // CanDrop
 //
-NS_IMETHODIMP nsNSSASN1Tree::CanDrop(PRInt32 index, PRInt32 orientation, PRBool *_retval)
+NS_IMETHODIMP nsNSSASN1Tree::CanDrop(PRInt32 index, PRInt32 orientation,
+                                     nsIDOMDataTransfer* aDataTransfer, PRBool *_retval)
 {
   NS_ENSURE_ARG_POINTER(_retval);
   *_retval = PR_FALSE;
   
   return NS_OK;
 }
 
 
 //
 // Drop
 //
-NS_IMETHODIMP nsNSSASN1Tree::Drop(PRInt32 row, PRInt32 orient)
+NS_IMETHODIMP nsNSSASN1Tree::Drop(PRInt32 row, PRInt32 orient, nsIDOMDataTransfer* aDataTransfer)
 {
   return NS_OK;
 }
 
 
 //
 // IsSorted
 //
--- a/security/manager/ssl/src/nsCertTree.cpp
+++ b/security/manager/ssl/src/nsCertTree.cpp
@@ -1436,29 +1436,30 @@ nsCertTree::dumpMap()
     }
   }
 }
 #endif
 
 //
 // CanDrop
 //
-NS_IMETHODIMP nsCertTree::CanDrop(PRInt32 index, PRInt32 orientation, PRBool *_retval)
+NS_IMETHODIMP nsCertTree::CanDrop(PRInt32 index, PRInt32 orientation,
+                                  nsIDOMDataTransfer* aDataTransfer, PRBool *_retval)
 {
   NS_ENSURE_ARG_POINTER(_retval);
   *_retval = PR_FALSE;
   
   return NS_OK;
 }
 
 
 //
 // Drop
 //
-NS_IMETHODIMP nsCertTree::Drop(PRInt32 row, PRInt32 orient)
+NS_IMETHODIMP nsCertTree::Drop(PRInt32 row, PRInt32 orient, nsIDOMDataTransfer* aDataTransfer)
 {
   return NS_OK;
 }
 
 
 //
 // IsSorted
 //
--- a/toolkit/components/autocomplete/src/nsAutoCompleteController.cpp
+++ b/toolkit/components/autocomplete/src/nsAutoCompleteController.cpp
@@ -916,23 +916,24 @@ nsAutoCompleteController::IsSeparator(PR
 NS_IMETHODIMP
 nsAutoCompleteController::IsSorted(PRBool *_retval)
 {
   *_retval = PR_FALSE;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsAutoCompleteController::CanDrop(PRInt32 index, PRInt32 orientation, PRBool *_retval)
+nsAutoCompleteController::CanDrop(PRInt32 index, PRInt32 orientation,
+                                  nsIDOMDataTransfer* dataTransfer, PRBool *_retval)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsAutoCompleteController::Drop(PRInt32 row, PRInt32 orientation)
+nsAutoCompleteController::Drop(PRInt32 row, PRInt32 orientation, nsIDOMDataTransfer* dataTransfer)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAutoCompleteController::PerformAction(const PRUnichar *action)
 {
   return NS_OK;
--- a/toolkit/components/filepicker/src/nsFileView.cpp
+++ b/toolkit/components/filepicker/src/nsFileView.cpp
@@ -56,16 +56,18 @@
 #include "nsIAutoCompleteSearch.h"
 #include "nsISimpleEnumerator.h"
 #include "nsAutoPtr.h"
 #include "nsIMutableArray.h"
 #include "nsTArray.h"
 
 #include "nsWildCard.h"
 
+class nsIDOMDataTransfer;
+ 
 #define NS_FILECOMPLETE_CID { 0xcb60980e, 0x18a5, 0x4a77, \
                             { 0x91, 0x10, 0x81, 0x46, 0x61, 0x4c, 0xa7, 0xf0 } }
 #define NS_FILECOMPLETE_CONTRACTID "@mozilla.org/autocomplete/search;1?name=file"
 
 class nsFileResult : public nsIAutoCompleteResult
 {
 public:
   // aSearchString is the text typed into the autocomplete widget
@@ -668,24 +670,25 @@ nsFileView::IsSeparator(PRInt32 aIndex, 
 NS_IMETHODIMP
 nsFileView::IsSorted(PRBool* aIsSorted)
 {
   *aIsSorted = (mSortType >= 0);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsFileView::CanDrop(PRInt32 aIndex, PRInt32 aOrientation, PRBool* aCanDrop)
+nsFileView::CanDrop(PRInt32 aIndex, PRInt32 aOrientation,
+                    nsIDOMDataTransfer* dataTransfer, PRBool* aCanDrop)
 {
   *aCanDrop = PR_FALSE;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsFileView::Drop(PRInt32 aRow, PRInt32 aOrientation)
+nsFileView::Drop(PRInt32 aRow, PRInt32 aOrientation, nsIDOMDataTransfer* dataTransfer)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFileView::GetParentIndex(PRInt32 aRowIndex, PRInt32* aParentIndex)
 {
   *aParentIndex = -1;