aboutsummaryrefslogblamecommitdiffstats
path: root/embed/mozilla/ProgressListener.cpp
blob: b5ed9815c17b16dafc4318f730987ec79451432d (plain) (tree)























                                                                              
                              
                                  





                                



                        
                                                                                                 
           
                                                                                                 
           
                                                                                                



















                                                                             
                             











                                                                            



















                                                    








                                                                              










                                                                   
                       











































































































































































































































                                                                                          


                                                                        



































                                                                                        













































































                                                                               






                                                               
                                                               






















































































                                                                                                                             
                       


















                                            
                      
















                                             


                                                   


















                                                                               
                                        
         
                           
         
                                     




                                        







                                                                

 
           
                                                                                                
 


                                  


           
                                                                                                
 


                                   


           
                                                                                               
 


                                  
 
/*
 *  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.
 */

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

#include "ProgressListener.h"

#include "ephy-file-helpers.h"
#include "mozilla-embed-persist.h"

#include <unistd.h>
#include <libgnome/gnome-exec.h>
#include <libgnome/gnome-i18n.h>

#include "nsXPIDLString.h"
#include "nsIMIMEInfo.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 noDialog,
                          PRInt64 aTimeDownloadStarted)
{
    nsresult rv;
    /* fill in download details */
    mAction = aAction;
    mParent = aParent;
    mNoDialog = noDialog;
    mUri = aURI;
    mFile = aFile;
    mPersist = aPersist;
    mTimeDownloadStarted = aTimeDownloadStarted;
    mEphyPersist = ephyPersist;

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

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

    /* done */
    return rv;
}

NS_METHOD GProgressListener::PrivateInit (void)
{
    nsresult rv;

    /* setup this download */
    mInterval            = 500000;     /* in microsecs == 500ms == 0.5s */
    mPriorKRate          = 0;
    mRateChanges         = 0;
    mRateChangeLimit     = 2;          /* only update rate every second */
    mIsPaused            = PR_FALSE;
    mAbort               = PR_FALSE;
    PRInt64 now          = PR_Now ();
    mLastUpdate          = now;

//  mStartTime           = (mTimeDownloadStarted != 0 ? 
//              mTimeDownloadStarted : now);
    mStartTime           = now; //Stupid mozilla race condition

    mElapsed             = now - mStartTime;

    if (!mNoDialog)
    {
        gchar *filename, *source, *dest;
        nsAutoString uTmp;
        nsCAutoString cTmp;

        rv = mFile->GetLeafName (uTmp);
        filename = g_strdup (NS_ConvertUCS2toUTF8(uTmp).get());

        rv = mFile->GetPath (uTmp);
        dest = g_strdup (NS_ConvertUCS2toUTF8(uTmp).get());

        rv = mUri->GetSpec (cTmp);
        source = g_strdup (cTmp.get());
        DownloaderView *dv;
        dv = ephy_embed_shell_get_downloader_view (embed_shell);
        downloader_view_add_download (dv, filename, source, dest, (gpointer)this);
        g_signal_connect (G_OBJECT (dv), 
                  "download_remove",
                  G_CALLBACK (download_remove_cb),
                  this);
        g_signal_connect (G_OBJECT (dv), 
                  "download_pause",
                  G_CALLBACK (download_pause_cb),
                  this);
        g_signal_connect (G_OBJECT (dv), 
                  "download_resume",
                  G_CALLBACK (download_resume_cb),
                  this);
        mDownloaderView = dv;
    }

    /* done */
    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;
        }
    }
        mNoDialog = 0;

        return PrivateInit();
}

NS_IMETHODIMP GProgressListener::Open(nsIDOMWindow *aParent)
{
        mParent = aParent;
        mNoDialog = 0;

        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)
    {
        switch (mAction)
                {
        case ACTION_SAVEFORHELPER:
            LaunchHelperApp();
            break;
            
        case ACTION_NONE:
            if (mLauncher)
            {
                mLauncher->CloseProgressWindow ();
            }
            break;
        case ACTION_OBJECT_NOTIFY:

            g_return_val_if_fail (IS_EPHY_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)); 
        }
        
        if (!mNoDialog)
        {
            downloader_view_set_download_status (mDownloaderView, 
                                 DOWNLOAD_STATUS_COMPLETED, 
                                 (gpointer)this);
        }
    }

    /* done */
    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 (mNoDialog) 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;
    }

    /* compute elapsed time */
    mLastUpdate = now;
    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)
    {
        if (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 +.5);
    }

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

    /* done */
    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;

        if (mIsPaused)
        {
                Resume ();
        }

        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();
    }
}