Back to index

lightning-sunbird  0.9+nobinonly
nsBrowserStatusFilter.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 2002
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Darin Fisher <darin@netscape.com>
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 "nsBrowserStatusFilter.h"
00039 #include "nsIChannel.h"
00040 #include "nsITimer.h"
00041 #include "nsIServiceManager.h"
00042 #include "nsString.h"
00043 
00044 // XXX
00045 // XXX  DO NOT TOUCH THIS CODE UNLESS YOU KNOW WHAT YOU'RE DOING !!!
00046 // XXX
00047 
00048 //-----------------------------------------------------------------------------
00049 // nsBrowserStatusFilter <public>
00050 //-----------------------------------------------------------------------------
00051 
00052 nsBrowserStatusFilter::nsBrowserStatusFilter()
00053     : mTotalRequests(0)
00054     , mFinishedRequests(0)
00055     , mUseRealProgressFlag(PR_FALSE)
00056     , mDelayedStatus(PR_FALSE)
00057     , mDelayedProgress(PR_FALSE)
00058 {
00059 }
00060 
00061 nsBrowserStatusFilter::~nsBrowserStatusFilter()
00062 {
00063     if (mTimer) {
00064         mTimer->Cancel();
00065     }
00066 }
00067 
00068 //-----------------------------------------------------------------------------
00069 // nsBrowserStatusFilter::nsISupports
00070 //-----------------------------------------------------------------------------
00071 
00072 NS_IMPL_ISUPPORTS3(nsBrowserStatusFilter,
00073                    nsIWebProgress,
00074                    nsIWebProgressListener,
00075                    nsISupportsWeakReference)
00076 
00077 //-----------------------------------------------------------------------------
00078 // nsBrowserStatusFilter::nsIWebProgress
00079 //-----------------------------------------------------------------------------
00080 
00081 NS_IMETHODIMP
00082 nsBrowserStatusFilter::AddProgressListener(nsIWebProgressListener *aListener,
00083                                            PRUint32 aNotifyMask)
00084 {
00085     mListener = aListener;
00086     return NS_OK;
00087 }
00088 
00089 NS_IMETHODIMP
00090 nsBrowserStatusFilter::RemoveProgressListener(nsIWebProgressListener *aListener)
00091 {
00092     if (aListener == mListener)
00093         mListener = nsnull;
00094     return NS_OK;
00095 }
00096 
00097 NS_IMETHODIMP
00098 nsBrowserStatusFilter::GetDOMWindow(nsIDOMWindow **aResult)
00099 {
00100     NS_NOTREACHED("nsBrowserStatusFilter::GetDOMWindow");
00101     return NS_ERROR_NOT_IMPLEMENTED;
00102 }
00103 
00104 NS_IMETHODIMP
00105 nsBrowserStatusFilter::GetIsLoadingDocument(PRBool *aIsLoadingDocument)
00106 {
00107     NS_NOTREACHED("nsBrowserStatusFilter::GetIsLoadingDocument");
00108     return NS_ERROR_NOT_IMPLEMENTED;
00109 }
00110 
00111 
00112 //-----------------------------------------------------------------------------
00113 // nsBrowserStatusFilter::nsIWebProgressListener
00114 //-----------------------------------------------------------------------------
00115 
00116 NS_IMETHODIMP
00117 nsBrowserStatusFilter::OnStateChange(nsIWebProgress *aWebProgress,
00118                                      nsIRequest *aRequest,
00119                                      PRUint32 aStateFlags,
00120                                      nsresult aStatus)
00121 {
00122     if (!mListener)
00123         return NS_OK;
00124 
00125     if (aStateFlags & STATE_START) {
00126         if (aStateFlags & STATE_IS_NETWORK) {
00127             mTotalRequests = 0;
00128             mFinishedRequests = 0;
00129             mUseRealProgressFlag = PR_FALSE;
00130         }
00131         if (aStateFlags & STATE_IS_REQUEST) {
00132             ++mTotalRequests;
00133 
00134             // if the total requests exceeds 1, then we'll base our progress
00135             // notifications on the percentage of completed requests.
00136             // otherwise, progress for the single request will be reported.
00137             mUseRealProgressFlag = (mTotalRequests == 1);
00138         }
00139     }
00140     else if (aStateFlags & STATE_STOP) {
00141         if (aStateFlags & STATE_IS_REQUEST) {
00142             ++mFinishedRequests;
00143             // Note: Do not return from here. This is necessary so that the
00144             // STATE_STOP can still be relayed to the listener if needed
00145             // (bug 209330)
00146             if (!mUseRealProgressFlag && mTotalRequests)
00147                 OnProgressChange(nsnull, nsnull, 0, 0,
00148                                  mFinishedRequests, mTotalRequests);
00149         }
00150     }
00151     else if (aStateFlags & STATE_TRANSFERRING) {
00152         if (aStateFlags & STATE_IS_REQUEST) {
00153             if (!mUseRealProgressFlag && mTotalRequests)
00154                 return OnProgressChange(nsnull, nsnull, 0, 0, mFinishedRequests, mTotalRequests);
00155         }
00156 
00157         // no need to forward this state change
00158         return NS_OK;
00159     } else {
00160         // no need to forward this state change
00161         return NS_OK;
00162     }
00163 
00164     // If we're here, we have either STATE_START or STATE_STOP.  The
00165     // listener only cares about these in certain conditions.
00166     PRBool isLoadingDocument = PR_FALSE;
00167     if ((aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK ||
00168          (aStateFlags & nsIWebProgressListener::STATE_IS_REQUEST &&
00169           mFinishedRequests == mTotalRequests &&
00170           (aWebProgress->GetIsLoadingDocument(&isLoadingDocument),
00171            !isLoadingDocument)))) {
00172         if (mTimer && (aStateFlags & nsIWebProgressListener::STATE_STOP)) {
00173             mTimer->Cancel();
00174             ProcessTimeout();
00175         }
00176 
00177         return mListener->OnStateChange(aWebProgress, aRequest, aStateFlags,
00178                                         aStatus);
00179     }
00180 
00181     return NS_OK;
00182 }
00183 
00184 NS_IMETHODIMP
00185 nsBrowserStatusFilter::OnProgressChange(nsIWebProgress *aWebProgress,
00186                                         nsIRequest *aRequest,
00187                                         PRInt32 aCurSelfProgress,
00188                                         PRInt32 aMaxSelfProgress,
00189                                         PRInt32 aCurTotalProgress,
00190                                         PRInt32 aMaxTotalProgress)
00191 {
00192     if (!mListener)
00193         return NS_OK;
00194 
00195     if (!mUseRealProgressFlag && aRequest)
00196         return NS_OK;
00197 
00198     //
00199     // limit frequency of calls to OnProgressChange
00200     //
00201 
00202     mCurProgress = aCurTotalProgress;
00203     mMaxProgress = aMaxTotalProgress;
00204 
00205     if (mDelayedProgress)
00206         return NS_OK;
00207 
00208     if (!mDelayedStatus) {
00209         mListener->OnProgressChange(nsnull, nsnull, 0, 0, mCurProgress, mMaxProgress);
00210         StartDelayTimer();
00211     }
00212 
00213     mDelayedProgress = PR_TRUE;
00214 
00215     return NS_OK;
00216 }
00217 
00218 NS_IMETHODIMP
00219 nsBrowserStatusFilter::OnLocationChange(nsIWebProgress *aWebProgress,
00220                                         nsIRequest *aRequest,
00221                                         nsIURI *aLocation)
00222 {
00223     if (!mListener)
00224         return NS_OK;
00225 
00226     return mListener->OnLocationChange(aWebProgress, aRequest, aLocation);
00227 }
00228 
00229 NS_IMETHODIMP
00230 nsBrowserStatusFilter::OnStatusChange(nsIWebProgress *aWebProgress,
00231                                       nsIRequest *aRequest,
00232                                       nsresult aStatus,
00233                                       const PRUnichar *aMessage)
00234 {
00235     if (!mListener)
00236         return NS_OK;
00237 
00238     //
00239     // limit frequency of calls to OnStatusChange
00240     //
00241 
00242     mStatusMsg = aMessage;
00243 
00244     if (mDelayedStatus)
00245         return NS_OK;
00246 
00247     if (!mDelayedProgress) {
00248         mListener->OnStatusChange(nsnull, nsnull, 0, aMessage);
00249         StartDelayTimer();
00250     }
00251 
00252     mDelayedStatus = PR_TRUE;
00253 
00254     return NS_OK;
00255 }
00256 
00257 NS_IMETHODIMP
00258 nsBrowserStatusFilter::OnSecurityChange(nsIWebProgress *aWebProgress,
00259                                         nsIRequest *aRequest,
00260                                         PRUint32 aState)
00261 {
00262     if (!mListener)
00263         return NS_OK;
00264 
00265     return mListener->OnSecurityChange(aWebProgress, aRequest, aState);
00266 }
00267 
00268 //-----------------------------------------------------------------------------
00269 // nsBrowserStatusFilter <private>
00270 //-----------------------------------------------------------------------------
00271 
00272 nsresult
00273 nsBrowserStatusFilter::StartDelayTimer()
00274 {
00275     NS_ASSERTION(!DelayInEffect(), "delay should not be in effect");
00276 
00277     mTimer = do_CreateInstance("@mozilla.org/timer;1");
00278     if (!mTimer)
00279       return NS_ERROR_FAILURE;
00280 
00281     return mTimer->InitWithFuncCallback(TimeoutHandler, this, 40, 
00282                                         nsITimer::TYPE_ONE_SHOT);
00283 }
00284 
00285 void
00286 nsBrowserStatusFilter::ProcessTimeout()
00287 {
00288     mTimer = nsnull;
00289 
00290     if (!mListener)
00291         return;
00292 
00293     if (mDelayedStatus) {
00294         mDelayedStatus = PR_FALSE;
00295         mListener->OnStatusChange(nsnull, nsnull, 0, mStatusMsg.get());
00296     }
00297 
00298     if (mDelayedProgress) {
00299         mDelayedProgress = PR_FALSE;
00300         mListener->OnProgressChange(nsnull, nsnull, 0, 0, mCurProgress, mMaxProgress);
00301     }
00302 }
00303 
00304 void
00305 nsBrowserStatusFilter::TimeoutHandler(nsITimer *aTimer, void *aClosure)
00306 {
00307     nsBrowserStatusFilter *self = NS_REINTERPRET_CAST(nsBrowserStatusFilter *, aClosure);
00308     if (!self) {
00309         NS_ERROR("no self");
00310         return;
00311     }
00312 
00313     self->ProcessTimeout();
00314 }