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  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsDragService.h"
00039 #include "nsITransferable.h"
00040 #include "nsString.h"
00041 #include "nsClipboard.h"
00042 #include "nsIRegion.h"
00043 #include "nsISupportsPrimitives.h"
00044 #include "nsPrimitiveHelpers.h"
00045 #include "nsCOMPtr.h"
00046 #include "nsXPIDLString.h"
00047 
00048 #include "nsWidgetsCID.h"
00049 
00050 NS_IMPL_ADDREF_INHERITED(nsDragService, nsBaseDragService)
00051 NS_IMPL_RELEASE_INHERITED(nsDragService, nsBaseDragService)
00052 NS_IMPL_QUERY_INTERFACE3(nsDragService,
00053                          nsIDragService,
00054                          nsIDragService_1_8_BRANCH,
00055                          nsIDragSession)
00056 
00057 char *nsDragService::mDndEvent = NULL;
00058 int nsDragService::mDndEventLen;
00059 
00060 #define kMimeCustom                "text/_moz_htmlcontext"
00061 
00062 //-------------------------------------------------------------------------
00063 //
00064 // DragService constructor
00065 //
00066 //-------------------------------------------------------------------------
00067 nsDragService::nsDragService()
00068 {
00069   mDndWidget = nsnull;
00070   mDndEvent = nsnull;
00071        mNativeCtrl = nsnull;
00072        mRawData = nsnull;
00073        mFlavourStr = nsnull;
00074        mTransportFile = nsnull;
00075 }
00076 
00077 //-------------------------------------------------------------------------
00078 //
00079 // DragService destructor
00080 //
00081 //-------------------------------------------------------------------------
00082 nsDragService::~nsDragService()
00083 {
00084        if( mNativeCtrl ) PtReleaseTransportCtrl( mNativeCtrl );
00085        if( mFlavourStr ) free( mFlavourStr );
00086        if( mTransportFile ) {
00087               unlink( mTransportFile );
00088               free( mTransportFile );
00089               }
00090 }
00091 
00092 NS_IMETHODIMP nsDragService::SetNativeDndData( PtWidget_t *widget, PhEvent_t *event ) {
00093        mDndWidget = widget;
00094        if( !mDndEvent ) {
00095               mDndEventLen = sizeof( PhEvent_t ) + event->num_rects * sizeof( PhRect_t ) + event->data_len;
00096               mDndEvent = ( char * ) malloc( mDndEventLen );
00097               }
00098        memcpy( mDndEvent, (char*)event, mDndEventLen );
00099        return NS_OK;
00100        }
00101 
00102 NS_IMETHODIMP nsDragService::SetDropData( char *data ) {
00103 
00104        if( mRawData ) free( mRawData );
00105 
00106        /* data is the filename used for passing the data */
00107        FILE *fp = fopen( data, "r" );
00108        PRUint32 n;
00109        fread( &n, sizeof( PRUint32 ), 1, fp );
00110        mRawData = ( char * ) malloc( n );
00111        if( !mRawData ) { fclose( fp ); return NS_ERROR_FAILURE; }
00112 
00113        fseek( fp, 0, SEEK_SET );
00114        fread( mRawData, 1, n, fp );
00115        fclose( fp );
00116 
00117   return NS_OK;
00118   }
00119 
00120 
00121 /* remove this function with the one from libph.so, when it becomes available */
00122 int CancelDrag( PhRid_t rid, unsigned input_group )
00123 {
00124   struct dragevent {
00125       PhEvent_t hdr;
00126       PhDragEvent_t drag;
00127       } ev;
00128   memset( &ev, 0, sizeof(ev) );
00129   ev.hdr.type = Ph_EV_DRAG;
00130   ev.hdr.emitter.rid = Ph_DEV_RID;
00131   ev.hdr.flags = Ph_EVENT_INCLUSIVE | Ph_EMIT_TOWARD;
00132   ev.hdr.data_len = sizeof( ev.drag );
00133   ev.hdr.subtype = Ph_EV_DRAG_COMPLETE;
00134   ev.hdr.input_group = input_group;
00135   ev.drag.rid = rid;
00136   return PhEmit( &ev.hdr, NULL, &ev.drag );
00137 } 
00138 
00139 
00140 //-------------------------------------------------------------------------
00141 NS_IMETHODIMP
00142 nsDragService::InvokeDragSession (nsIDOMNode *aDOMNode,
00143                                   nsISupportsArray * aArrayTransferables,
00144                                   nsIScriptableRegion * aRegion,
00145                                   PRUint32 aActionType)
00146 {
00147 #ifdef DEBUG
00148        printf( "nsDragService::InvokeDragSession\n" );
00149 #endif
00150   nsresult rv = nsBaseDragService::InvokeDragSession(aDOMNode,
00151                                                      aArrayTransferables,
00152                                                      aRegion, aActionType);
00153   NS_ENSURE_SUCCESS(rv, rv);
00154 
00155   if(!aArrayTransferables)
00156     return NS_ERROR_INVALID_ARG;
00157   if(!mDndWidget || !mDndEvent )
00158     return NS_ERROR_FAILURE; // Otherwise we seg fault
00159 
00160   extern char* __progname;
00161   if (__progname && strcmp(__progname, "kwww") == 0) {
00162        //
00163        // In kscope we use dragging to scroll, but due to synthesized mouse
00164        // events coming in to nsViewManager::SynthesizeMouseMove() from
00165        // PresShell::DidDoReflow() we may occasionally end up here when the
00166        // user drags quickly and selects a copy/pastable element like a link.
00167        // We don't want to do anything in this case, or else we will mess up
00168        // a drag scroll in progress.
00169        //
00170     return NS_ERROR_FAILURE;
00171   }
00172 
00173        /*  this will also addref the transferables since we're going to hang onto this beyond the length of this call */
00174        mSourceDataItems = aArrayTransferables;
00175 
00176   PRUint32 numDragItems = 0;
00177   mSourceDataItems->Count(&numDragItems);
00178   if ( ! numDragItems ) return NS_ERROR_FAILURE;
00179 
00180        /* cancel a previous drag ( PhInitDrag ) if one is in place */
00181        CancelDrag( PtWidgetRid( mDndWidget ), ((PhEvent_t*)mDndEvent)->input_group );
00182 
00183        mActionType = aActionType;
00184 
00185        PRUint32 pDataLen = sizeof( PRUint32 ) + sizeof( PRUint32 ), totalItems = 0;
00186        char *pdata = ( char * ) malloc( pDataLen ); /* we reserve space for a total size and totalItems */
00187        if( !pdata ) return NS_ERROR_FAILURE;
00188 
00189 
00190   for(PRUint32 itemIndex = 0; itemIndex < numDragItems; ++itemIndex) {
00191     nsCOMPtr<nsISupports> genericItem;
00192     mSourceDataItems->GetElementAt(itemIndex, getter_AddRefs(genericItem));
00193     nsCOMPtr<nsITransferable> currItem (do_QueryInterface(genericItem));
00194     if(currItem) {
00195       nsCOMPtr <nsISupportsArray> flavorList;
00196       currItem->FlavorsTransferableCanExport(getter_AddRefs(flavorList));
00197       if(flavorList) {
00198         PRUint32 numFlavors;
00199         flavorList->Count( &numFlavors );
00200         for( PRUint32 flavorIndex = 0; flavorIndex < numFlavors ; ++flavorIndex ) {
00201           nsCOMPtr<nsISupports> genericWrapper;
00202           flavorList->GetElementAt (flavorIndex, getter_AddRefs(genericWrapper));
00203           nsCOMPtr<nsISupportsCString> currentFlavor;
00204           currentFlavor = do_QueryInterface(genericWrapper);
00205           if(currentFlavor) {
00206             nsXPIDLCString flavorStr;
00207             currentFlavor->ToString ( getter_Copies(flavorStr) );
00208                                           const char *FlavourStr = ( const char * ) flavorStr;
00209                                           nsCOMPtr<nsISupports> data;
00210                                           PRUint32 tmpDataLen = 0;
00211                                           rv = currItem->GetTransferData( FlavourStr, getter_AddRefs(data), &tmpDataLen );
00212                                           if( NS_SUCCEEDED( rv ) ) {
00213                                                  /* insert FlavourStr, data into the PtTransportCtrl_t */
00214                                                  int len = sizeof( PRUint32 ) + sizeof( PRUint32 ) + strlen( FlavourStr ) + 1 + tmpDataLen;
00215                                                  /* we reserve space for itemIndex|tmpDataLen|flavorStr|data */
00216                                                  len = ( ( len + 3 ) / 4 ) * 4;
00217                                                  pdata = ( char * ) realloc( pdata, len + pDataLen );
00218                                                  if( pdata ) {
00219                                                         char *p = pdata + pDataLen;
00220                                                         PRUint32 *d = ( PRUint32 * ) p;
00221                                                         d[0] = itemIndex; /* copy itemIndex*/
00222                                                         d[1] = tmpDataLen; /* copy PRUint32 tmpDataLen */
00223                                                         strcpy( p + sizeof( PRUint32 ) + sizeof( PRUint32 ), FlavourStr ); /* copy flavorStr */
00224        
00225                                                         void *mem_data;
00226                                                         nsPrimitiveHelpers::CreateDataFromPrimitive ( FlavourStr, data, &mem_data, tmpDataLen );
00227        
00228                                                         memcpy( p + sizeof( PRUint32 ) + sizeof( PRUint32 ) + strlen( FlavourStr ) + 1, mem_data, tmpDataLen ); /* copy the data */
00229                                                         pDataLen += len;
00230                                                         totalItems++;
00231                                                         }
00232                                                  }
00233                                           }
00234           }
00235         }
00236       }
00237     }
00238 
00239        if( totalItems ) {
00240               PRUint32 *p = ( PRUint32 * ) pdata;
00241               p[0] = pDataLen;
00242               p[1] = totalItems;
00243               mNativeCtrl = PtCreateTransportCtrl( );
00244 
00245               if( !mTransportFile ) mTransportFile = strdup( (char*) tmpnam( NULL ) );
00246 
00247               FILE *fp = fopen( mTransportFile, "w" );
00248               fwrite( pdata, 1, pDataLen, fp );
00249               fclose( fp );
00250               free( pdata );
00251 
00252               PtTransportType( mNativeCtrl, "Mozilla", "dnddata", 1, Ph_TRANSPORT_INLINE, "string", (void*)mTransportFile, 0, 0 );
00253               PtInitDnd( mNativeCtrl, mDndWidget, (PhEvent_t*)mDndEvent, NULL, 0 );
00254               }
00255 
00256   return NS_OK;
00257 }
00258 
00259 
00260 
00261 //-------------------------------------------------------------------------
00262 NS_IMETHODIMP nsDragService::GetNumDropItems (PRUint32 * aNumItems)
00263 {
00264   *aNumItems = 1;
00265   return NS_OK;
00266 }
00267 
00268 
00269 //-------------------------------------------------------------------------
00270 NS_IMETHODIMP nsDragService::GetData (nsITransferable * aTransferable, PRUint32 aItemIndex ) {
00271        nsresult rv = NS_ERROR_FAILURE;
00272        nsCOMPtr<nsISupports> genericDataWrapper;
00273 
00274        if( mRawData ) {
00275               PRUint32 *d = ( PRUint32 * ) mRawData, totalItems = d[1];
00276               PRUint32 i, pdataLen = sizeof( PRUint32 ) + sizeof( PRUint32 );
00277 
00278               /* search for aItemIndex */
00279               for( i=0; i<totalItems; i++ ) {
00280                      char *p = mRawData + pdataLen;
00281                      PRUint32 *d = ( PRUint32 * ) p;
00282 
00283                      char *flavorStr = p + sizeof( PRUint32 ) + sizeof( PRUint32 );
00284                      PRUint32 this_len = sizeof( PRUint32 ) + sizeof( PRUint32 ) + strlen( flavorStr ) + 1 + d[1];
00285                      this_len = ( ( this_len + 3 ) / 4 ) * 4;
00286                      char *raw_data = flavorStr + strlen( flavorStr ) + 1;
00287 
00288                      if( d[0] == aItemIndex && mFlavourStr && !strcmp( mFlavourStr, flavorStr ) ) {
00289                             nsPrimitiveHelpers::CreatePrimitiveForData( flavorStr, raw_data, d[1], getter_AddRefs( genericDataWrapper ) );
00290                             rv = aTransferable->SetTransferData( flavorStr, genericDataWrapper, d[1] );
00291                             break;
00292                             }
00293 
00294                      pdataLen += this_len;
00295                      }
00296               }
00297        return rv;
00298        }
00299 
00300 //-------------------------------------------------------------------------
00301 NS_IMETHODIMP nsDragService::IsDataFlavorSupported(const char *aDataFlavor, PRBool *_retval)
00302 {
00303   if (!aDataFlavor || !_retval)
00304     return NS_ERROR_FAILURE;
00305 
00306        // set this to no by default
00307        *_retval = PR_FALSE;
00308 
00309        const char *ask;
00310        if( !strcmp( aDataFlavor, kMimeCustom ) )  ask = kHTMLMime;
00311        else ask = aDataFlavor;
00312 
00313        if(!mSourceDataItems) return NS_OK;
00314        PRUint32 numDragItems = 0;
00315        mSourceDataItems->Count(&numDragItems);
00316        for(PRUint32 itemIndex = 0; itemIndex < numDragItems; ++itemIndex) {
00317        nsCOMPtr<nsISupports> genericItem;
00318        mSourceDataItems->GetElementAt(itemIndex, getter_AddRefs(genericItem));
00319        nsCOMPtr<nsITransferable> currItem (do_QueryInterface(genericItem));
00320        if(currItem) {
00321          nsCOMPtr <nsISupportsArray> flavorList;
00322          currItem->FlavorsTransferableCanExport(getter_AddRefs(flavorList));
00323          if(flavorList) {
00324            PRUint32 numFlavors;
00325            flavorList->Count( &numFlavors );
00326            for( PRUint32 flavorIndex = 0; flavorIndex < numFlavors ; ++flavorIndex ) {
00327              nsCOMPtr<nsISupports> genericWrapper;
00328              flavorList->GetElementAt (flavorIndex, getter_AddRefs(genericWrapper));
00329                   nsCOMPtr<nsISupportsCString> currentFlavor;
00330              currentFlavor = do_QueryInterface(genericWrapper);
00331                     if(currentFlavor) {
00332                nsXPIDLCString flavorStr;
00333                currentFlavor->ToString ( getter_Copies(flavorStr) );
00334                                           if(strcmp(flavorStr, ask) == 0) {
00335                                           *_retval = PR_TRUE;
00336                                                  if( mFlavourStr ) free( mFlavourStr );
00337                                                  mFlavourStr = strdup( ask );
00338                                                  }
00339                                           }
00340                                    }
00341                             }
00342                      }
00343               }
00344 
00345   return NS_OK;
00346 }
00347 
00348 void
00349 nsDragService::SourceEndDrag(void)
00350 {
00351   // this just releases the list of data items that we provide
00352   mSourceDataItems = 0;
00353 }