Back to index

lightning-sunbird  0.9+nobinonly
nsDragService.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *   Paul Ashford
00025  *   Fredrik Holmqvist <thesuckiestemail@yahoo.se>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either the GNU General Public License Version 2 or later (the "GPL"), or
00029  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 #include <stdio.h>
00042 #include "nsDragService.h"
00043 #include "nsIDocument.h"
00044 #include "nsIRegion.h"
00045 #include "nsITransferable.h"
00046 #include "nsIServiceManager.h"
00047 #include "nsISupportsPrimitives.h"
00048 #include "nsVoidArray.h"
00049 #include "nsXPIDLString.h"
00050 #include "nsPrimitiveHelpers.h"
00051 #include "nsUnitConversion.h"
00052 #include "nsWidgetsCID.h"
00053 #include "nsCRT.h"
00054 
00055 // if we want to do Image-dragging, also need to change Makefile.in
00056 // to add
00057 //            -I$(topsrcdir)/gfx/src/beos \
00058 // in INCLUDES
00059 // and bug 294234 to be done.
00060 // #include "nsIImage.h"
00061 // #include "nsIImageBeOS.h"
00062 //#include <Bitmap.h>
00063 
00064 #include <AppDefs.h>
00065 #include <TypeConstants.h>
00066 #include <DataIO.h>
00067 #include <Mime.h>
00068 #include <Rect.h>
00069 #include <Region.h>
00070 #include <String.h>
00071 #include <View.h>
00072 
00073 #include "prlog.h"
00074 #include "nsIPresShell.h"
00075 #include "nsPresContext.h"
00076 #include "nsIFrame.h"
00077 #include "nsIView.h"
00078 #include "nsIWidget.h"
00079   
00080 static NS_DEFINE_CID(kCDragServiceCID,   NS_DRAGSERVICE_CID);
00081   
00082 static PRLogModuleInfo *sDragLm = NULL;
00083 
00084 static nsIFrame*
00085 GetPrimaryFrameFor(nsIDOMNode *aDOMNode)
00086 {
00087     nsCOMPtr<nsIContent> aContent = do_QueryInterface(aDOMNode);
00088     if (nsnull == aContent)
00089         return nsnull;
00090 
00091     nsIDocument* doc = aContent->GetCurrentDoc();
00092     if (nsnull == doc)
00093         return nsnull;
00094     nsIPresShell* presShell = doc->GetShellAt(0);
00095     if ( nsnull == presShell) 
00096         return nsnull;
00097     nsIFrame *frame;
00098     presShell->GetPrimaryFrameFor(aContent, &frame);
00099        return frame;
00100 }
00101 
00102 static bool 
00103 IsInternalDrag(BMessage * aMsg)
00104 {
00105     BString orig;
00106     // We started this drag if originater is 'BeZilla'
00107     return (nsnull != aMsg && B_OK == aMsg->FindString("be:originator", &orig) &&
00108            0 == orig.Compare("BeZilla"));
00109 }
00110 
00111 NS_IMPL_THREADSAFE_ISUPPORTS4(nsDragService, nsIDragService,
00112                               nsIDragService_1_8_BRANCH, nsIDragSession,
00113                               nsIDragSessionBeOS)
00114 //NS_IMPL_THREADSAFE_ISUPPORTS1(nsBaseDragService, nsIDragSessionBeOS)
00115 
00116 //-------------------------------------------------------------------------
00117 //
00118 // DragService constructor
00119 // Enable logging: 'export NSPR_LOG_MODULES=nsDragService:5'
00120 //-------------------------------------------------------------------------
00121 nsDragService::nsDragService()
00122 {
00123     // set up our logging module
00124     if (!sDragLm)
00125         sDragLm = PR_NewLogModule("nsDragService");
00126     PR_LOG(sDragLm, PR_LOG_DEBUG, ("\n\nnsDragService::nsDragService"));
00127 
00128     mDragMessage = NULL;
00129     mCanDrop = PR_FALSE;
00130 }
00131 
00132 //-------------------------------------------------------------------------
00133 //
00134 // DragService destructor
00135 //
00136 //-------------------------------------------------------------------------
00137 nsDragService::~nsDragService()
00138 {
00139     PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::~nsDragService"));
00140     ResetDragInfo();
00141 }
00142 
00143 //-------------------------------------------------------------------------
00144 //
00145 // nsIDragService : InvokeDragSession
00146 //
00147 // Called when a drag is being initiated from within mozilla 
00148 // The code here gets the BView, the dragRect, builds the DragMessage and 
00149 // starts the drag.
00150 //
00151 //-------------------------------------------------------------------------
00152 NS_IMETHODIMP
00153 nsDragService::InvokeDragSession (nsIDOMNode *aDOMNode,
00154                                   nsISupportsArray * aArrayTransferables,
00155                                   nsIScriptableRegion * aRegion,
00156                                   PRUint32 aActionType)
00157 {
00158     PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::InvokeDragSession"));
00159     nsresult rv = nsBaseDragService::InvokeDragSession(aDOMNode,
00160                                                        aArrayTransferables,
00161                                                        aRegion, aActionType);
00162     NS_ENSURE_SUCCESS(rv, rv);
00163 
00164     ResetDragInfo();       
00165     // make sure that we have an array of transferables to use
00166     if (nsnull == aArrayTransferables)
00167         return NS_ERROR_INVALID_ARG;
00168 
00169     // set our reference to the transferables.  this will also addref
00170     // the transferables since we're going to hang onto this beyond the
00171     // length of this call
00172     mSourceDataItems = aArrayTransferables;
00173 
00174     // Get a box or a bitmap to drag
00175     bool haveRect = false;
00176     BRect dragRect;
00177        
00178     if (nsnull != aRegion)
00179     {
00180         PRInt32 aX, aY, aWidth, aHeight;
00181         // TODO. Region may represent multiple rects - when dragging multiple items.
00182         aRegion->GetBoundingBox(&aX, &aY, &aWidth, &aHeight);
00183         dragRect.Set( aX, aY, aX + aWidth, aY + aHeight);
00184         haveRect = true;
00185         // does this need to be offset?
00186     } 
00187     
00188     // Get the frame for this content node (note: frames are not refcounted)
00189     nsIFrame *aFrame = GetPrimaryFrameFor(aDOMNode);
00190     if (nsnull == aFrame)
00191         return PR_FALSE;
00192     
00193     // Now that we have the frame, we have to convert its coordinates into global screen
00194     // coordinates.
00195     nsRect aRect = aFrame->GetRect();
00196 
00197     // Find offset from our view
00198     nsIView *containingView = nsnull;
00199     nsPoint viewOffset(0,0);
00200     aFrame->GetOffsetFromView(viewOffset, &containingView);
00201     NS_ASSERTION(containingView, "No containing view!");
00202     if (nsnull == containingView)
00203         return PR_FALSE;
00204 
00205     // get the widget associated with the containing view. 
00206     nsPoint aWidgetOffset;
00207     nsCOMPtr<nsIWidget> aWidget = containingView->GetNearestWidget(&aWidgetOffset);
00208     if (nsnull == aWidget)
00209         return PR_FALSE;
00210 
00211     BView *view = (BView *) aWidget->GetNativeData(NS_NATIVE_WIDGET);
00212     // Don't have the rect yet, try to get it from the dom node
00213     if (nsnull==haveRect)
00214     {
00215         float t2p =  aFrame->GetPresContext()->TwipsToPixels(); 
00216         // GetOffsetFromWidget() actually returns the _parent's_ offset from its widget, so we
00217         // still have to add in the offset to |containingView|'s parent ourselves.
00218         nsPoint aViewPos = containingView->GetPosition();
00219     
00220         // Shift our offset rect by offset into our view, the view's offset to its parent, and
00221         // the parent's offset to the closest widget. Then convert that to global coordinates. 
00222         // Recall that WidgetToScreen() will give us the global coordinates of the rectangle we 
00223         // give it, but it expects  everything to be in pixels.
00224         nsRect screenOffset;
00225         screenOffset.MoveBy ( NSTwipsToIntPixels(aWidgetOffset.x + aViewPos.x + viewOffset.x, t2p),
00226                             NSTwipsToIntPixels(aWidgetOffset.y + aViewPos.y + viewOffset.y, t2p));
00227         aWidget->WidgetToScreen ( screenOffset, screenOffset );
00228 
00229         dragRect.Set(screenOffset.x, screenOffset.y, 
00230                            screenOffset.x + NSTwipsToIntPixels(aRect.width, t2p),
00231                            screenOffset.y + NSTwipsToIntPixels(aRect.height, t2p));
00232         haveRect = true;
00233     }
00234 
00235     mDragAction = aActionType;
00236     mDragMessage = CreateDragMessage();
00237 
00238     if (!view || !mDragMessage)
00239         return PR_FALSE;
00240         
00241     // Set the original click location, how to get this or is it needed ?
00242     // sourceMessage->AddPoint("click_location", mPoint);
00243     
00244     if (!view->LockLooper())
00245         return PR_FALSE;
00246         
00247     // Well, let's just use the view frame, maybe?
00248     if (!haveRect) 
00249     {
00250         dragRect = view->Frame();
00251         // do we need to offset?
00252     }
00253         
00254     PR_LOG(sDragLm, PR_LOG_DEBUG, ("invoking mDragView->DragMessage"));
00255     bool noBitmap = true;
00256 
00257 //This is the code for image-dragging, currently disabled. See comments in beginning of file.
00258 # ifdef 0
00259     do
00260     {
00261         PRUint32 dataSize;
00262         PRUint32 noItems;
00263         mSourceDataItems->Count(&noItems);
00264         if (noItems!=1) 
00265         {
00266             PR_LOG(sDragLm, PR_LOG_DEBUG, ("Transferables are not ==1, no drag bitmap!"));
00267             break;
00268         }
00269         
00270         nsCOMPtr<nsISupports> genericItem;
00271         aArrayTransferables->GetElementAt(0, getter_AddRefs(genericItem));
00272         nsCOMPtr<nsITransferable> aTransferable (do_QueryInterface(genericItem));
00273         
00274         nsCOMPtr<nsISupports> genericDataWrapper;
00275         nsresult rv = aTransferable->GetTransferData(kNativeImageMime, getter_AddRefs(genericDataWrapper), &dataSize);
00276         if (NS_FAILED(rv))
00277         {
00278             PR_LOG(sDragLm, PR_LOG_DEBUG, ("Could not get nativeimage, no drag bitmap!"));
00279             break;
00280         }
00281 
00282         nsCOMPtr<nsISupportsInterfacePointer> ptrPrimitive (do_QueryInterface(genericDataWrapper));
00283         if (ptrPrimitive == NULL) 
00284         {
00285             PR_LOG(sDragLm, PR_LOG_DEBUG, ("Could not get ptrPrimitive, no drag bitmap!"));
00286             break;
00287         }
00288 
00289         nsCOMPtr<nsISupports> genericData;
00290         ptrPrimitive->GetData(getter_AddRefs(genericData));
00291         if (genericData == NULL) 
00292         {
00293             PR_LOG(sDragLm, PR_LOG_DEBUG, ("Could not get data, no drag bitmap!"));
00294             break;
00295         }
00296 
00297         //dependent on bug 294234 and how it's implemented. This code was for attachment 183634.
00298         nsCOMPtr<nsIImageBeOS> image (do_QueryInterface(genericData));
00299         if (image == NULL)
00300         {
00301             PR_LOG(sDragLm, PR_LOG_DEBUG, ("Could not get nsImage, no drag bitmap!"));
00302             break;
00303         }
00304 
00305         BBitmap *aBitmap;
00306         image->GetBitmap(&aBitmap);
00307         if (aBitmap==NULL || !aBitmap->IsValid()) {
00308             PR_LOG(sDragLm, PR_LOG_DEBUG, ("Could not get BBitmap, no drag bitmap %s!", aBitmap==NULL?"(null)":"(not valid)" ));
00309             break;        
00310         }
00311 
00312         view->DragMessage(mDragMessage, aBitmap, B_OP_OVER, BPoint(-4,-4), view); 
00313         noBitmap = false;
00314     } while(false);
00315 # endif    
00316     
00317     if (noBitmap) 
00318         view->DragMessage(mDragMessage, dragRect, view);
00319     
00320     StartDragSession();
00321     view->UnlockLooper();
00322     return NS_OK;
00323 }
00324 
00325 //-------------------------------------------------------------------------
00326 //
00327 // nsIDragService : StartDragSession
00328 //
00329 // We overwrite this so we can log it
00330 //
00331 //-------------------------------------------------------------------------
00332 NS_IMETHODIMP
00333 nsDragService::StartDragSession()
00334 {
00335     PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::StartDragSession()"));
00336     return nsBaseDragService::StartDragSession();
00337 }
00338 
00339 //-------------------------------------------------------------------------
00340 //
00341 // nsIDragService : EndDragSession
00342 //
00343 // We overwrite this so we can log it
00344 //
00345 //-------------------------------------------------------------------------
00346 NS_IMETHODIMP
00347 nsDragService::EndDragSession()
00348 {
00349     PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::EndDragSession()"));
00350     //Don't reset drag info, keep it until there is a new drag, in case a negotiated drag'n'drop wants the info.
00351     //We need the draginfo as we are ending starting the dragsession
00352     //on entering/exiting different views (nsWindows) now.
00353     //That way the dragsession is always ended when we go outside mozilla windows, but we do throw away the 
00354     // mSourceDocument and mSourceNode. We do hold on to the nsTransferable if it was a internal drag. 
00355     //ResetDragInfo();
00356     return nsBaseDragService::EndDragSession();
00357 }
00358 
00359 //-------------------------------------------------------------------------
00360 //
00361 // nsIDragSession : SetCanDrop
00362 //
00363 // We overwrite this so we can log it
00364 //
00365 //-------------------------------------------------------------------------
00366 NS_IMETHODIMP
00367 nsDragService::SetCanDrop(PRBool aCanDrop)
00368 {
00369     PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::SetCanDrop(%s)",
00370                                   aCanDrop == PR_TRUE?"TRUE":"FALSE"));
00371     return nsBaseDragService::SetCanDrop(aCanDrop);
00372 }
00373 
00374 
00375 //-------------------------------------------------------------------------
00376 //
00377 // nsIDragSession : GetCanDrop
00378 //
00379 // We overwrite this so we can log it
00380 //
00381 //-------------------------------------------------------------------------
00382 NS_IMETHODIMP
00383 nsDragService::GetCanDrop(PRBool *aCanDrop)
00384 {
00385     PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::GetCanDrop()"));
00386     return nsBaseDragService::GetCanDrop(aCanDrop);
00387 }
00388 
00389 //-------------------------------------------------------------------------
00390 //
00391 // nsIDragSession : GetNumDropItems
00392 //
00393 // Gets the number of items currently being dragged
00394 //
00395 //-------------------------------------------------------------------------
00396 NS_IMETHODIMP
00397 nsDragService::GetNumDropItems(PRUint32 * aNumItems)
00398 {
00399     PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::GetNumDropItems()"));
00400     if (nsnull == mDragMessage)
00401     {
00402         *aNumItems = 0;
00403         PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::GetNumDropItems(): WARNING! No dragmessage"));
00404         return NS_OK;
00405     } 
00406     // Did we start this drag?
00407     if (IsInternalDrag(mDragMessage))
00408         mSourceDataItems->Count(aNumItems);
00409     else
00410         // The only thing native that I can think of that may have multiple items
00411         // would be file references, DND-docs don't say anything about multiple items.
00412         *aNumItems = 1;
00413 
00414 
00415     PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::GetNumDropItems():%d", *aNumItems));
00416     return NS_OK;
00417 }
00418 
00419 
00420 //-------------------------------------------------------------------------
00421 //
00422 // nsIDragSession : GetData
00423 //
00424 // Copies the data at the given index into the given nsITransferable
00425 //
00426 // This is usually called on Drop, but can be called before that
00427 //
00428 //-------------------------------------------------------------------------
00429 NS_IMETHODIMP
00430 nsDragService::GetData(nsITransferable * aTransferable, PRUint32 aItemIndex)
00431 {
00432     PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::GetData %d", aItemIndex));
00433 
00434     if (nsnull==mDragMessage)
00435         return NS_ERROR_INVALID_ARG;
00436 
00437     // get flavor list that includes all acceptable flavors (including
00438     // ones obtained through conversion). Flavors are nsISupportsStrings
00439     // so that they can be seen from JS.
00440     nsresult rv = NS_ERROR_FAILURE;
00441     nsCOMPtr<nsISupportsArray> flavorList;
00442     rv = aTransferable->FlavorsTransferableCanImport(getter_AddRefs(flavorList));
00443     if (NS_FAILED(rv))
00444         return rv;
00445 
00446     // count the number of flavors
00447     PRUint32 cnt;
00448     flavorList->Count (&cnt);
00449 
00450     nsCOMPtr<nsISupports> genericWrapper;
00451     nsCOMPtr<nsISupportsCString> currentFlavor;
00452     nsXPIDLCString flavorStr;
00453     nsCOMPtr<nsISupports> genericItem;   
00454     nsCOMPtr<nsISupports> data;
00455     PRUint32 tmpDataLen = 0;
00456     for (unsigned int i= 0; i < cnt; ++i )
00457     {
00458         flavorList->GetElementAt(i, getter_AddRefs(genericWrapper));
00459         currentFlavor = do_QueryInterface(genericWrapper);
00460         if (!currentFlavor)
00461             continue;
00462         currentFlavor->ToString(getter_Copies(flavorStr));
00463         
00464         PR_LOG(sDragLm, PR_LOG_DEBUG, ("tnsDragService::GetData trying to get transfer data for %s",
00465                         (const char *)flavorStr));
00466                         
00467         if (IsInternalDrag(mDragMessage))
00468         {
00469             mSourceDataItems->GetElementAt(aItemIndex, getter_AddRefs(genericItem));
00470             nsCOMPtr<nsITransferable> item (do_QueryInterface(genericItem));
00471             if (!item)
00472                 continue;
00473             rv = item->GetTransferData(flavorStr, getter_AddRefs(data), &tmpDataLen);
00474             if (NS_FAILED(rv))
00475                 continue;
00476             PR_LOG(sDragLm, PR_LOG_DEBUG, ("tnsDragService::GetData setting data."));
00477             return aTransferable->SetTransferData(flavorStr, data, tmpDataLen);
00478         } 
00479         else
00480         {
00481             //Check if transfer message is simple_data or older type of DND
00482             //Check if message has data else continue
00483             //Negotiate for data (if possible) or get data
00484                //set and return
00485         }
00486     }
00487     PR_LOG(sDragLm, PR_LOG_DEBUG, ("tnsDragService::GetData failed"));
00488     return NS_ERROR_FAILURE;
00489 }
00490 
00491 
00492 //-------------------------------------------------------------------------
00493 //
00494 // nsIDragSession : IsDataFlavorSupported
00495 //
00496 // Tells whether the given flavor is supported by the current drag object
00497 //
00498 // Called on MouseOver events
00499 //
00500 //-------------------------------------------------------------------------
00501 NS_IMETHODIMP
00502 nsDragService::IsDataFlavorSupported (const char *aDataFlavor,
00503                                       PRBool *_retval)
00504 {
00505     PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::IsDataFlavorSupported %s", aDataFlavor));
00506     if (!_retval)
00507         return NS_ERROR_INVALID_ARG;
00508 
00509     // set this to no by default
00510     *_retval = PR_FALSE;
00511 
00512     // check to make sure that we have a drag object set, here
00513     if (nsnull == mDragMessage) {
00514         PR_LOG(sDragLm, PR_LOG_DEBUG, ("*** warning: IsDataFlavorSupported called without a valid drag context!"));
00515         return NS_OK;
00516     }
00517 
00518     if (IsInternalDrag(mDragMessage))
00519     {
00520         PRUint32 numDragItems = 0;
00521         // if we don't have mDataItems we didn't start this drag so it's
00522         // an external client trying to fool us.
00523         if (nsnull == mSourceDataItems)
00524             return NS_OK;
00525         mSourceDataItems->Count(&numDragItems);
00526         if (0 == numDragItems)
00527             PR_LOG(sDragLm, PR_LOG_DEBUG, ("*** warning: Number of dragged items is zero!"));
00528 
00529         // For all dragged items compare their flavors to the one wanted. If there is a match DataFlavor is supported.
00530         nsCOMPtr<nsISupports> genericItem;
00531         nsCOMPtr <nsISupportsArray> flavorList;
00532         PRUint32 numFlavors;
00533         for (PRUint32 itemIndex = 0; itemIndex < numDragItems; ++itemIndex)
00534         {
00535             mSourceDataItems->GetElementAt(itemIndex, getter_AddRefs(genericItem));
00536             nsCOMPtr<nsITransferable> currItem (do_QueryInterface(genericItem));
00537             if (nsnull == currItem)
00538                 continue;
00539             currItem->FlavorsTransferableCanExport(getter_AddRefs(flavorList));
00540             if (nsnull == flavorList)
00541                 continue;
00542             flavorList->Count( &numFlavors );
00543             
00544             nsCOMPtr<nsISupports> genericWrapper;
00545             nsXPIDLCString flavorStr;
00546             for ( PRUint32 flavorIndex = 0; flavorIndex < numFlavors ; ++flavorIndex ) {
00547                 flavorList->GetElementAt (flavorIndex, getter_AddRefs(genericWrapper));
00548                 nsCOMPtr<nsISupportsCString> currentFlavor = do_QueryInterface(genericWrapper);
00549                 if (nsnull == currentFlavor)
00550                     continue;
00551                 currentFlavor->ToString ( getter_Copies(flavorStr) );
00552                 PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::IsDataFlavorSupported checking %s against %s", (const char *)flavorStr, aDataFlavor));
00553                 if (0 != strcmp(flavorStr, aDataFlavor))
00554                     continue;
00555                 PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::IsDataFlavorSupported Got the flavor!"));
00556                 *_retval = PR_TRUE;
00557                 return NS_OK;
00558             }
00559         }
00560     }
00561     else 
00562     {
00563         PR_LOG(sDragLm, PR_LOG_DEBUG, ("*** warning: Native drag not implemented."));
00564         // TODO: implement native checking
00565     }
00566     PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::IsDataFlavorSupported FALSE"));
00567     return NS_OK;
00568 }
00569 
00570 //-------------------------------------------------------------------------
00571 //
00572 // nsDragServoce : CreateDragMessage
00573 //
00574 // Builds the drag message needed for BeOS negotiated DND.
00575 //
00576 //-------------------------------------------------------------------------
00577 BMessage *
00578 nsDragService::CreateDragMessage()
00579 {
00580     PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::GetInitialDragMessage"));
00581     if (nsnull == mSourceDataItems)
00582         return NULL;
00583     
00584     unsigned int numDragItems = 0;
00585     mSourceDataItems->Count(&numDragItems);
00586     
00587     BMessage * returnMsg = new BMessage(B_SIMPLE_DATA);
00588     
00589     returnMsg->AddString("be:originator", "BeZilla");
00590     returnMsg->AddString("be:clip_name","BeZilla Drag Item");
00591   
00592     if (mDragAction & DRAGDROP_ACTION_COPY)
00593         returnMsg->AddInt32("be:actions",B_COPY_TARGET);
00594     if (mDragAction & DRAGDROP_ACTION_MOVE)
00595         returnMsg->AddInt32("be:actions",B_MOVE_TARGET);
00596     if (mDragAction & DRAGDROP_ACTION_LINK)
00597         returnMsg->AddInt32("be:actions",B_LINK_TARGET);
00598   
00599     // Check to see if we're dragging > 1 item.  If we are then we use
00600     // an internal only type.
00601     if (numDragItems > 1)
00602     {
00603         PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService:: Dragging a list of items ..."));
00604 //        returnMsg->AddString("be:types", gMimeListType);
00605 //        returnMsg->AddString("be:types", B_FILE_MIME_TYPE);
00606 //        returnMsg->AddString("be:filetypes", gMimeListType);
00607 //        returnMsg->AddString("be:type_descriptions", gMimeListType);        
00608         return returnMsg;
00609     }
00610 
00611     PRBool addedType = PR_FALSE;
00612 
00613     nsCOMPtr<nsISupports> genericItem;
00614     nsCOMPtr <nsISupportsArray> flavorList;
00615     PRUint32 numFlavors;
00616     nsCOMPtr<nsISupports> genericWrapper;
00617     nsXPIDLCString flavorStr;
00618 
00619     for (unsigned int itemIndex = 0; itemIndex < numDragItems; ++itemIndex)
00620     {
00621         mSourceDataItems->GetElementAt(itemIndex, getter_AddRefs(genericItem));
00622         nsCOMPtr<nsITransferable> currItem (do_QueryInterface(genericItem));
00623         if (nsnull == currItem) 
00624             continue;
00625 
00626         currItem->FlavorsTransferableCanExport(getter_AddRefs(flavorList));
00627         if (nsnull == flavorList)
00628             continue;
00629         flavorList->Count( &numFlavors );
00630         for (PRUint32 flavorIndex = 0; flavorIndex < numFlavors ; ++flavorIndex )
00631         {
00632             flavorList->GetElementAt(flavorIndex, getter_AddRefs(genericWrapper));
00633             nsCOMPtr<nsISupportsCString> currentFlavor = do_QueryInterface(genericWrapper);
00634             if (nsnull == currentFlavor)
00635                 continue;
00636             currentFlavor->ToString ( getter_Copies(flavorStr) );
00637             
00638             PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService:: Adding a flavor to our message: %s",flavorStr.get()));
00639             
00640             type_code aCode;
00641             if (B_OK == returnMsg->GetInfo(flavorStr.get(), &aCode))
00642                 continue;
00643             returnMsg->AddString("be:types",flavorStr.get());
00644             
00645             //returnMsg->AddString("be:types", B_FILE_MIME_TYPE);
00646             returnMsg->AddString("be:filetypes",flavorStr.get());
00647             returnMsg->AddString("be:type_descriptions",flavorStr.get());
00648             
00649             addedType = PR_TRUE;            
00650             // Check to see if this is text/unicode.  If it is, add
00651             // text/plain since we automatically support text/plain if
00652             // we support text/unicode.
00653             //tqh: but this may cause duplicates?
00654             if (0 == strcmp(flavorStr, kUnicodeMime))
00655             {
00656                 PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService:: Adding a TextMime for the UnicodeMime"));
00657                 returnMsg->AddString("be:types",kTextMime);
00658                 //returnMsg->AddString("be:types", B_FILE_MIME_TYPE);
00659                 returnMsg->AddString("be:filetypes",kTextMime);
00660                 returnMsg->AddString("be:type_descriptions",kTextMime);
00661             }
00662         }
00663     }
00664     
00665     if (addedType) {
00666         returnMsg->AddString("be:types", B_FILE_MIME_TYPE);
00667     }
00668     returnMsg->PrintToStream();
00669     // If we did not add a type, we can't drag
00670     NS_ASSERTION(addedType == PR_TRUE, "No flavor/mime in the drag message!");
00671     return returnMsg;
00672 }
00673 
00674 //-------------------------------------------------------------------------
00675 //
00676 // nsIDragSessionBeOS : UpdateDragMessageIfNeeded
00677 //
00678 // Updates the drag message from the old one if we enter a mozilla view with
00679 // a dragmessage from outside. IE one where "be:originator"-key != "BeZilla"
00680 //
00681 //-------------------------------------------------------------------------
00682 NS_IMETHODIMP
00683 nsDragService::UpdateDragMessageIfNeeded(BMessage *aDragMessage)
00684 {
00685     PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::UpdateDragMessageIfNeeded()"));
00686     if (aDragMessage == mDragMessage) 
00687         return NS_OK;
00688     
00689     // Did we start this drag?
00690     //It's already set properly by InvokeDragSession, so don't do anything and avoid throwing away
00691     //mSourceDataItems
00692     if (IsInternalDrag(aDragMessage))
00693         return NS_OK;
00694 
00695     PR_LOG(sDragLm, PR_LOG_DEBUG, ("updating."));
00696     ResetDragInfo();
00697     mDragMessage = aDragMessage;
00698     return NS_OK;
00699 }
00700 
00701 
00702 //-------------------------------------------------------------------------
00703 //
00704 // nsIDragSessionBeOS : TransmitData
00705 //
00706 // When a negotiated drag'n'drop to another app occurs nsWindow
00707 // calls this method with the other apps message which contains
00708 // the info on what data the app wants. This function checks the 
00709 // message and transmits the data to the app, thereby ending the
00710 // drag'n'drop to another app.
00711 //-------------------------------------------------------------------------
00712 NS_IMETHODIMP
00713 nsDragService::TransmitData(BMessage *aNegotiationReply)
00714 {
00715     PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::TransmitData()"));
00716 /*
00717     unsigned int numDragItems = 0;
00718     mSourceDataItems->Count(&numDragItems);
00719     
00720     returnMsg->AddString("be:originator", "BeZilla");
00721     returnMsg->AddString("be:clip_name","BeZilla Drag Item");
00722   
00723     // Check to see if we're dragging > 1 item.  If we are then we use
00724     // an internal only type.
00725     if (numDragItems > 1)
00726     {
00727         PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService:: Dragging a list of items ..."));
00728         delete aNegotiationReply;
00729         return;
00730     }
00731     BMessage aReply = new BMessage(B_MIME_DATA);
00732     char * aMimeType;
00733     aNegotiationReply->FindString("be:types", &aMimeType);
00734      nsCOMPtr<nsITransferable> item;
00735      item->addDataFlavor(aMimeType);
00736     GetData(item, 0);
00737     aReply->AddData(aMimeType, item->);
00738   */  
00739     aNegotiationReply->PrintToStream();
00740     delete aNegotiationReply;
00741     return NS_OK;
00742 }
00743 
00744 //-------------------------------------------------------------------------
00745 //
00746 // nsIDragService : ResetDragInfo
00747 //
00748 // Resets the stored drag information.
00749 //
00750 //-------------------------------------------------------------------------
00751 void
00752 nsDragService::ResetDragInfo()
00753 {
00754     PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::ResetDragInfo()"));
00755     if (nsnull != mDragMessage) delete mDragMessage;
00756     mDragMessage = NULL;
00757     mSourceDataItems = NULL;
00758 }
00759 
00760 const char *
00761 nsDragService::FlavorToBeMime(const char * flavor)
00762 {
00763     //text/plain ok
00764     //text/unicode -> text/plain
00765     if (0 == strcmp(flavor,kUnicodeMime)) return kTextMime;    
00766     //text/html ok
00767     //AOLMAIL ignore!!     
00768     //image/png ok
00769     //image/jpg
00770     if (0 == strcmp(flavor,kJPEGImageMime)) return "image/jpeg";
00771     //image/gif ok
00772     //application/x-moz-file
00773     if (0 == strcmp(flavor,kFileMime)) return "application/octet-stream";
00774     //text/x-moz-url (only support this as a filetype (Be bookmark))
00775     if (0 == strcmp(flavor,kURLMime)) return "application/x-vnd.Be-bookmark";
00776     //text/x-moz-url-data - we need to read data to find out what type of URL.
00777     //text/x-moz-url-desc - a url-description (same as title?)
00778     //kNativeImageMime - don't support as BeOS image
00779     //kNativeHTMLMime - don't support on BeOS side
00780     //kFilePromiseURLMime
00781     //kFilePromiseDestFilename
00782     //kFilePromiseMime
00783     //kFilePromiseDirectoryMime
00784     
00785 //    if (0==strcmp(flavor,kUnicodeMime))
00786 }