aboutsummaryrefslogblamecommitdiffstats
path: root/embed/mozilla/ProgressListener.cpp
blob: 433b2234c8f8ca2c54d95995055553a5de176ec0 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16















                                                                              

        






                             
                              
                            
                                  
                          


                     
                                                                                                 
           
                                                                                                 
           
                                                                                                



















                                                                             
                             


                                                                            






                                                                           

                    


                                      
                         











                                                    


                  

                                               
                                                                   


                                                                              

                                        

                                          
                                 
 
                    



                                                
                            

                                               
                                                            


                                                                       
                                                            


                                                                   
                                                            
                                               
 
                                                      
                                                                             






                                                                                


                                                                  
                                                              


                                                                 
                                                              


                                                                  

         

























                                                                             
                       






                                                            
                       



























































































                                                                                          
                                        



                                                                                         
                                        



































                                                                             


                                                                     




                                                             
 
                            





                                                                                        













                                                                  
                                                                                   











                                                                  

                                                       
                                                                       
                                

         






















                                                                       
                                   
 










                                                    
                          

                                  




















                                                                            
                                                                                  





                                
                                      
         

                                                                       
                 
                                                               
                         

                                                           


                            
                                                           
                         
                 



                                         

                                     




                                                   


                                                                           

         
                                                               
                                                                  




                                                             
                                                               
 







                                                                                                         
                     







                                                                                                                             
                     







                                                                                                    
                     

























































                                                                                   
                       


















                                            
                      
















                                             
                      
                                                   
                              











                                                                               
                                        
         
                           
         
                                     




                                        







                                                                

 
           
                                                                                                
 


                                  


           
                                                                                                
 


                                   


           
                                                                                               
 


                                  
 
/*
 *  Copyright (C) 2001 Philip Langdale, Matthew Aubury
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 *  $Id$
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "ProgressListener.h"
#include "ephy-file-helpers.h"
#include "downloader-view.h"
#include "mozilla-embed-persist.h"
#include "nsXPIDLString.h"
#include "nsCOMPtr.h"

static void
download_remove_cb (DownloaderView *dv, GProgressListener *Changed, GProgressListener *Progress);
static void
download_resume_cb (DownloaderView *dv, GProgressListener *Changed, GProgressListener *Progress);
static void
download_pause_cb (DownloaderView *dv, GProgressListener *Changed, GProgressListener *Progress);

NS_IMPL_ISUPPORTS4 (GProgressListener, nsIDownload, nsIWebProgressListener,
            nsIProgressDialog, nsISupportsWeakReference)

//---------------------------------------------------------------------------

//---------------------------------------------------------------------------

GProgressListener::GProgressListener () : mLauncher(nsnull),
                      mPersist(nsnull),
                          mHandler(nsnull),
                      mObserver(nsnull),
                      mMIMEInfo(nsnull),
                      mPercentComplete(0)
{
    NS_INIT_ISUPPORTS ();
}

GProgressListener::~GProgressListener ()
{
    /* destructor code */
}

NS_METHOD GProgressListener::InitForPersist (nsIWebBrowserPersist *aPersist,
                         nsIDOMWindow *aParent, 
                         nsIURI *aURI,
                         nsIFile *aFile,
                         DownloadAction aAction,
                         EphyEmbedPersist *ephyPersist,
                         PRBool Dialog,
                         PRInt64 aTimeDownloadStarted)
{
    nsresult rv;
    /* fill in download details */
    mAction = aAction;
    mParent = aParent;
    mDialog = Dialog;
    mUri = aURI;
    mFile = aFile;
    mPersist = aPersist;
    mTimeDownloadStarted = aTimeDownloadStarted;
    mEphyPersist = ephyPersist;

    /* do remaining init */
    rv = PrivateInit ();

    /* pick up progress messages */
    mPersist->SetProgressListener (this);

    return rv;
}

NS_METHOD GProgressListener::PrivateInit (void)
{
    mInterval            = 500000;     /* in microsecs, 0.5s */
    mPriorKRate          = 0;
    mRateChanges         = 0;
    mRateChangeLimit     = 2;          /* only update rate every second */
    mIsPaused            = PR_FALSE;
    mAbort               = PR_FALSE;
    mStartTime           = PR_Now ();
    mLastUpdate          = mStartTime;
    mElapsed             = 0;

    if (mDialog)
    {
        gchar *filename, *source, *dest;
        nsAutoString uTmp;
        nsCAutoString cTmp;
        nsresult rv;

        rv = mFile->GetLeafName (uTmp);
        if (NS_FAILED (rv)) return NS_ERROR_FAILURE;
        filename = g_strdup (NS_ConvertUCS2toUTF8(uTmp).get());

        rv = mFile->GetPath (uTmp);
        if (NS_FAILED (rv)) return NS_ERROR_FAILURE;
        dest = g_strdup (NS_ConvertUCS2toUTF8(uTmp).get());

        rv = mUri->GetSpec (cTmp);
        if (NS_FAILED (rv)) return NS_ERROR_FAILURE;
        source = g_strdup (cTmp.get());

        mDownloaderView = EPHY_DOWNLOADER_VIEW
            (ephy_embed_shell_get_downloader_view (embed_shell));
        downloader_view_add_download (mDownloaderView, filename, source,
                          dest, (gpointer)this);
        g_free (source);
        g_free (dest);
        g_free (filename);

        g_signal_connect (G_OBJECT (mDownloaderView), 
                  "download_remove",
                  G_CALLBACK (download_remove_cb),
                  this);
        g_signal_connect (G_OBJECT (mDownloaderView), 
                  "download_pause",
                  G_CALLBACK (download_pause_cb),
                  this);
        g_signal_connect (G_OBJECT (mDownloaderView), 
                  "download_resume",
                  G_CALLBACK (download_resume_cb),
                  this);
    }

    return NS_OK;
}

NS_IMETHODIMP GProgressListener::Init(nsIURI *aSource,
                                      nsILocalFile *aTarget,
                                      const PRUnichar *aDisplayName,
                      nsIMIMEInfo *aMIMEInfo,
                                      PRInt64 aStartTime,
                                      nsIWebBrowserPersist *aPersist)
{
        mUri = aSource;
        mFile = aTarget;
        mTimeDownloadStarted = aStartTime;
        mStartTime = aStartTime;
        mPersist = aPersist;
    mMIMEInfo = aMIMEInfo;
        mAction = ACTION_NONE;
    if(mMIMEInfo)
    {
        nsMIMEInfoHandleAction mimeAction;
        if(NS_SUCCEEDED(mMIMEInfo->GetPreferredAction(&mimeAction)))
        {
            mAction = (mimeAction == nsIMIMEInfo::useHelperApp) ?
                  ACTION_SAVEFORHELPER : ACTION_NONE;
        }
    }
        mDialog = TRUE;

        return PrivateInit();
}

NS_IMETHODIMP GProgressListener::Open(nsIDOMWindow *aParent)
{
        mParent = aParent;
        mDialog = TRUE;

        return NS_OK;
}

/* attribute long long startTime; */
NS_IMETHODIMP GProgressListener::GetStartTime(PRInt64 *aStartTime)
{
        *aStartTime = mStartTime;
        return NS_OK;
}

/* attribute nsIURI source; */
NS_IMETHODIMP GProgressListener::GetSource(nsIURI * *aSource)
{
        NS_IF_ADDREF(*aSource = mUri);
        return NS_OK;
}

/* attribute nsILocalFile target; */
NS_IMETHODIMP GProgressListener::GetTarget(nsILocalFile * *aTarget)
{
        nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(mFile);
        NS_IF_ADDREF(*aTarget = localFile);
        return NS_OK;
}

NS_IMETHODIMP GProgressListener::GetMIMEInfo(nsIMIMEInfo * *aMIMEInfo)
{
    NS_IF_ADDREF(*aMIMEInfo = mMIMEInfo);
    return NS_OK;
}

/* attribute nsIObserver observer; */
NS_IMETHODIMP GProgressListener::GetObserver(nsIObserver * *aObserver)
{
        NS_IF_ADDREF(*aObserver = mObserver);
        return NS_OK;
}
NS_IMETHODIMP GProgressListener::SetObserver(nsIObserver * aObserver)
{
        mObserver = aObserver;
        return NS_OK;
}

/* attribute nsIWebProgressListener listener; */
NS_IMETHODIMP GProgressListener::GetListener(nsIWebProgressListener * *aListener)
{
        *aListener = nsnull;
        return NS_OK;
}
NS_IMETHODIMP GProgressListener::SetListener(nsIWebProgressListener * aListener)
{
        return NS_OK;
}

/* readonly attribute PRInt32 percentComplete; */
NS_IMETHODIMP GProgressListener::GetPercentComplete(PRInt32 *aPercentComplete)
{
        return *aPercentComplete = mPercentComplete;
}

/* attribute wstring displayName; */
NS_IMETHODIMP GProgressListener::GetDisplayName(PRUnichar * *aDisplayName)
{
        *aDisplayName = nsnull;
        return NS_OK;
}
NS_IMETHODIMP GProgressListener::SetDisplayName(const PRUnichar * aDisplayName)
{
        return NS_OK;
}

NS_IMETHODIMP GProgressListener::GetPersist(nsIWebBrowserPersist * *aPersist)
{
        NS_IF_ADDREF(*aPersist = mPersist);
        return NS_OK;
}

NS_IMETHODIMP GProgressListener::SetDialog(nsIDOMWindow *aDialog)
{
        return NS_OK;
}

NS_IMETHODIMP GProgressListener::GetDialog(nsIDOMWindow * *aDialog)
{
        *aDialog = nsnull;
        return NS_OK;
}

/* attribute PRBool cancelDownloadOnClose; */
NS_IMETHODIMP  GProgressListener::GetCancelDownloadOnClose(PRBool *aCancelDownloadOnClose)
{
    return NS_ERROR_NOT_IMPLEMENTED;
}

NS_IMETHODIMP  GProgressListener::SetCancelDownloadOnClose(PRBool aCancelDownloadOnClose)
{
    return NS_ERROR_NOT_IMPLEMENTED;
}

NS_IMETHODIMP GProgressListener::LaunchHandler (PersistHandlerInfo *handler)
{
    nsresult rv;
    nsCOMPtr<nsIExternalHelperAppService> helperService =
        do_GetService (NS_EXTERNALHELPERAPPSERVICE_CONTRACTID);

    nsCOMPtr<nsPIExternalAppLauncher> appLauncher =
        do_QueryInterface (helperService, &rv);
    if (NS_SUCCEEDED(rv))
    {
        appLauncher->DeleteTemporaryFileOnExit(mFile);
    }

    nsAutoString uFileName;
        
    mFile->GetPath(uFileName);
        const nsACString &cFileName = NS_ConvertUCS2toUTF8(uFileName);
    
    char *fname = g_strdup(PromiseFlatCString(cFileName).get());
    ephy_file_launch_application (handler->command,
                      fname,
                      handler->need_terminal);
    g_free (fname);

    return NS_OK;
}

/*
 * void onStateChange (in nsIWebProgress aWebProgress, 
 *                     in nsIRequest aRequest, 
 *             in long aStateFlags, 
 *             in unsigned long aStatus);
 */
NS_IMETHODIMP GProgressListener::OnStateChange (nsIWebProgress *aWebProgress,
                        nsIRequest *aRequest,
                        PRUint32 aStateFlags,
                        PRUint32 aStatus)
{
    if (mAbort) return NS_ERROR_FAILURE;

    if (aStateFlags & nsIWebProgressListener::STATE_STOP)
    {

        if (mDialog)
        {
            downloader_view_set_download_status (mDownloaderView, 
                                 DOWNLOAD_STATUS_COMPLETED, 
                                 (gpointer)this);
        }

        switch (mAction)
                {
        case ACTION_SAVEFORHELPER:
            LaunchHelperApp();
            break;
            
        case ACTION_NONE:
            if (mLauncher)
            {
                mLauncher->CloseProgressWindow ();
            }
            break;
        case ACTION_OBJECT_NOTIFY:

            g_return_val_if_fail (EPHY_IS_EMBED_PERSIST (mEphyPersist),
                          NS_ERROR_FAILURE);
            
            PersistHandlerInfo *handler;
            
            g_object_get (mEphyPersist,
                          "handler", &handler,        
                          NULL);

            if (handler)
            {
                LaunchHandler (handler);
            }
        
            mozilla_embed_persist_completed
                (MOZILLA_EMBED_PERSIST (mEphyPersist));
        }       
    }

    return NS_OK;
}

/*
 * void onProgressChange (in nsIWebProgress aWebProgress, 
 *                        in nsIRequest aRequest, 
 *                        in long aCurSelfProgress, 
 *                        in long aMaxSelfProgress, 
 *                        in long aCurTotalProgress, 
 *                        in long aMaxTotalProgress); 
 */
NS_IMETHODIMP GProgressListener::
            OnProgressChange (nsIWebProgress *aWebProgress,
                      nsIRequest *aRequest,
                      PRInt32 aCurSelfProgress,
                      PRInt32 aMaxSelfProgress,
                      PRInt32 aCurTotalProgress,
                      PRInt32 aMaxTotalProgress)
{
    if (mAbort) return NS_ERROR_FAILURE;

    /* FIXME maxsize check here */

    if (!mDialog) return NS_OK;

    mRequest = aRequest;

    PRInt64 now = PR_Now ();

    /* get out if we're updating too quickly */
    if ((now - mLastUpdate < mInterval) && 
        (aMaxTotalProgress != -1) &&  
        (aCurTotalProgress < aMaxTotalProgress))
    {
        return NS_OK;
    }
    mLastUpdate = now;

    /* compute elapsed time */
    mElapsed = now - mStartTime;

    /* compute size done */
    PRInt32 currentKBytes = (PRInt32)(aCurTotalProgress / 1024.0 + 0.5);

    /* compute total size */
    PRInt32 totalKBytes = (PRInt32)(aMaxTotalProgress / 1024.0 + 0.5);

    /* compute progress value */
    gfloat progress = -1;
    if (aMaxTotalProgress > 0)
    {
        progress = (gfloat)aCurTotalProgress /
            (gfloat)aMaxTotalProgress;
    }

    /* compute download rate */
    gfloat speed = -1;
    PRInt64 currentRate;
    if (mElapsed)
    {
        currentRate = ((PRInt64)(aCurTotalProgress)) * 1000000 / mElapsed;
    }
    else
    {
        currentRate = 0;
    }       

    if (!mIsPaused && currentRate)
    {
        PRFloat64 currentKRate = ((PRFloat64)currentRate)/1024;
        if (currentKRate != mPriorKRate)
        {
            if (mRateChanges++ == mRateChangeLimit)
            {
                mPriorKRate = currentKRate;
                mRateChanges = 0;
            }
            else
            {
                currentKRate = mPriorKRate;
            }
        }
        else
        {
            mRateChanges = 0;
        }

        speed = currentKRate;
    }
    
    /* compute time remaining */
    gint remaining = -1;
    if (currentRate && (aMaxTotalProgress > 0))
    {
         remaining = (gint)((aMaxTotalProgress - aCurTotalProgress)
                 /currentRate + 0.5);
    }

    downloader_view_set_download_progress (mDownloaderView,
                           mElapsed / 1000000,
                           remaining,
                           speed,
                           totalKBytes,
                           currentKBytes,
                           progress,
                           (gpointer)this);

    return NS_OK;
}

/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
NS_IMETHODIMP GProgressListener::
            OnLocationChange(nsIWebProgress *aWebProgress,
                     nsIRequest *aRequest, nsIURI *location)
{
    return NS_OK;
}

/* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */
NS_IMETHODIMP GProgressListener::
            OnStatusChange(nsIWebProgress *aWebProgress,
                       nsIRequest *aRequest, nsresult aStatus,
                       const PRUnichar *aMessage)
{
    return NS_OK;
}

/* void onSecurityChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long state); */
NS_IMETHODIMP GProgressListener::
            OnSecurityChange(nsIWebProgress *aWebProgress,
                     nsIRequest *aRequest,
                     PRUint32 state)
{
    return NS_OK;
}

//---------------------------------------------------------------------------

NS_METHOD GProgressListener::LaunchHelperApp (void)
{
    if (!mMIMEInfo)
        return NS_ERROR_FAILURE;

    nsresult rv;

    nsCOMPtr<nsIFile> helperFile;
    rv = mMIMEInfo->GetPreferredApplicationHandler(getter_AddRefs(helperFile));
    if(NS_FAILED(rv)) return NS_ERROR_FAILURE;

    nsCAutoString helperFileName;
    rv = helperFile->GetNativePath(helperFileName);
    if(NS_FAILED(rv)) return NS_ERROR_FAILURE;

    nsMIMEInfoHandleAction mimeAction;
    rv = mMIMEInfo->GetPreferredAction(&mimeAction);
    if(NS_FAILED(rv)) return NS_ERROR_FAILURE;

    nsCOMPtr<nsIExternalHelperAppService> helperService =
        do_GetService (NS_EXTERNALHELPERAPPSERVICE_CONTRACTID, &rv);
    if (NS_SUCCEEDED(rv))
    {
        nsCOMPtr<nsPIExternalAppLauncher> appLauncher =
            do_QueryInterface (helperService, &rv);
        if (NS_SUCCEEDED(rv))
        {
            appLauncher->DeleteTemporaryFileOnExit(mFile);
        }
    }

    nsCAutoString cFileName;
    mFile->GetNativePath(cFileName);
    if(NS_FAILED(rv)) return NS_ERROR_FAILURE;

    nsXPIDLString helperDesc;
    rv = mMIMEInfo->GetApplicationDescription(getter_Copies(helperDesc));
    if(NS_FAILED(rv)) return NS_ERROR_FAILURE;

    gboolean terminalHelper = 
        helperDesc.Equals(NS_LITERAL_STRING("runInTerminal")) ?
        TRUE : FALSE;

    ephy_file_launch_application (helperFileName.get(),
                      cFileName.get(),
                      terminalHelper);

    return NS_OK;
}

nsresult GProgressListener::Pause (void)
{
        nsresult rv;

        if (!mIsPaused)
        {
                rv = mRequest->Suspend ();
                if (NS_SUCCEEDED (rv))
                {
                        mIsPaused = PR_TRUE;
                }
        }
        else
        {
                rv = NS_ERROR_FAILURE;
        }

        return rv;
}

nsresult GProgressListener::Resume (void)
{
        nsresult rv;

        if (mIsPaused)
        {
                rv = mRequest->Resume ();
                if (NS_SUCCEEDED (rv))
                {
                        mIsPaused = PR_FALSE;
                }
        }
        else
        {
                rv = NS_ERROR_FAILURE;
        }

        return rv;
}

nsresult GProgressListener::Abort (void)
{
    PRBool notify;
    notify = (mAction == ACTION_OBJECT_NOTIFY);
        mAction = ACTION_NONE;
        mAbort = PR_TRUE;

        if (mObserver)
        {
                mObserver->Observe(NS_ISUPPORTS_CAST(nsIProgressDialog*, this),
                                             "oncancel", nsnull);
                OnStateChange(nsnull, nsnull,
                              nsIWebProgressListener::STATE_STOP, 0);
        }

        if (mPersist)
        {
                mPersist->CancelSave ();
        }
        else if (mLauncher)
        {
                mLauncher->Cancel ();
        }
        else
        {
                return NS_ERROR_FAILURE;
        }

    if (notify)
    {   
        mozilla_embed_persist_cancelled
            (MOZILLA_EMBED_PERSIST (mEphyPersist)); 
    }

    return NS_OK;
}

static void
download_remove_cb (DownloaderView *dv, GProgressListener *Changed, GProgressListener *Progress)
{
    if (Changed == Progress){
        Progress->Abort();
    }
}

static void
download_resume_cb (DownloaderView *dv, GProgressListener *Changed, GProgressListener *Progress)
{
    if (Changed == Progress) {
        Progress->Resume();
    }
}

static void
download_pause_cb (DownloaderView *dv, GProgressListener *Changed, GProgressListener *Progress)
{
    if (Changed == Progress) {
        Progress->Pause();
    }
}