Back to index

lightning-sunbird  0.9+nobinonly
nsMsgStatusFeedback.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; 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) 1999
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 of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or 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 "msgCore.h"
00039 
00040 #include "nsXPIDLString.h"
00041 
00042 #include "nsIWebProgress.h"
00043 #include "nsIDOMWindowInternal.h"
00044 #include "nsPIDOMWindow.h"
00045 #include "nsIXULBrowserWindow.h"
00046 #include "nsMsgStatusFeedback.h"
00047 #include "nsIScriptGlobalObject.h"
00048 #include "nsIDocumentViewer.h"
00049 #include "nsIDocument.h"
00050 #include "nsIDOMElement.h"
00051 #include "nsIDocShell.h"
00052 #include "nsIDocShellTreeItem.h"
00053 #include "nsIChannel.h"
00054 #include "prinrval.h"
00055 #include "nsInt64.h"
00056 #include "nsITimelineService.h"
00057 #include "nsIMsgMailNewsUrl.h"
00058 #include "nsIMimeMiscStatus.h"
00059 #include "nsIMsgWindow.h"
00060 #include "nsMsgUtils.h"
00061 #include "nsIMsgHdr.h"
00062 
00063 #define MSGFEEDBACK_TIMER_INTERVAL 500
00064 
00065 nsMsgStatusFeedback::nsMsgStatusFeedback() :
00066   m_lastPercent(0)
00067 {
00068        LL_I2L(m_lastProgressTime, 0);
00069 
00070     nsresult rv;
00071     nsCOMPtr<nsIStringBundleService> bundleService =
00072         do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
00073 
00074     if (NS_SUCCEEDED(rv))
00075         bundleService->CreateBundle("chrome://messenger/locale/messenger.properties",
00076                                     getter_AddRefs(mBundle));
00077 
00078     m_msgLoadedAtom = do_GetAtom("msgLoaded");
00079 }
00080 
00081 nsMsgStatusFeedback::~nsMsgStatusFeedback()
00082 {
00083   mBundle = nsnull;
00084 }
00085 
00086 NS_IMPL_THREADSAFE_ADDREF(nsMsgStatusFeedback)
00087 NS_IMPL_THREADSAFE_RELEASE(nsMsgStatusFeedback)
00088 
00089 NS_INTERFACE_MAP_BEGIN(nsMsgStatusFeedback)
00090    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIMsgStatusFeedback)
00091    NS_INTERFACE_MAP_ENTRY(nsIMsgStatusFeedback)
00092    NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink) 
00093    NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener) 
00094    NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
00095 NS_INTERFACE_MAP_END
00096 
00098 // nsMsgStatusFeedback::nsIWebProgressListener
00100 
00101 NS_IMETHODIMP
00102 nsMsgStatusFeedback::OnProgressChange(nsIWebProgress* aWebProgress,
00103                                       nsIRequest* aRequest,
00104                                       PRInt32 aCurSelfProgress,
00105                                       PRInt32 aMaxSelfProgress, 
00106                                       PRInt32 aCurTotalProgress,
00107                                       PRInt32 aMaxTotalProgress)
00108 {
00109   PRInt32 percentage = 0;
00110   if (aMaxTotalProgress > 0)
00111   {
00112     percentage =  (aCurTotalProgress * 100) / aMaxTotalProgress;
00113     if (percentage)
00114       ShowProgress(percentage);
00115   }
00116 
00117    return NS_OK;
00118 }
00119       
00120 NS_IMETHODIMP
00121 nsMsgStatusFeedback::OnStateChange(nsIWebProgress* aWebProgress,
00122                                    nsIRequest* aRequest,
00123                                    PRUint32 aProgressStateFlags,
00124                                    nsresult aStatus)
00125 {
00126   nsresult rv;
00127 
00128   NS_ENSURE_TRUE(mBundle, NS_ERROR_NULL_POINTER);
00129   if (aProgressStateFlags & STATE_IS_NETWORK)
00130   {
00131     if (aProgressStateFlags & STATE_START)
00132     {
00133       NS_TIMELINE_START_TIMER("Start Msg Loading");
00134       NS_TIMELINE_ENTER("Start Msg Loading in progress");
00135       m_lastPercent = 0;
00136       StartMeteors();
00137       nsXPIDLString loadingDocument;
00138       rv = mBundle->GetStringFromName(NS_LITERAL_STRING("documentLoading").get(),
00139                                       getter_Copies(loadingDocument));
00140       if (NS_SUCCEEDED(rv))
00141         ShowStatusString(loadingDocument);
00142     }
00143     else if (aProgressStateFlags & STATE_STOP)
00144     {
00145       NS_TIMELINE_STOP_TIMER("Start Msg Loading");
00146       NS_TIMELINE_LEAVE("Start Msg Loading is finished");
00147       NS_TIMELINE_MARK_TIMER("Start Msg Loading");
00148       NS_TIMELINE_RESET_TIMER("Start Msg Loading");
00149 
00150       // if we are loading message for display purposes, this STATE_STOP notification is 
00151       // the only notification we get when layout is actually done rendering the message. We need
00152       // to fire the appropriate msgHdrSink notification in this particular case.
00153       nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
00154       if (channel) 
00155       {
00156         nsCOMPtr<nsIURI> uri; 
00157         channel->GetURI(getter_AddRefs(uri));
00158         nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl (do_QueryInterface(uri));
00159         if (mailnewsUrl)
00160         {
00161           // get the url type
00162           PRBool messageDisplayUrl;
00163           mailnewsUrl->IsUrlType(nsIMsgMailNewsUrl::eDisplay, &messageDisplayUrl);
00164 
00165           if (messageDisplayUrl)
00166           {              
00167             // get the header sink
00168             nsCOMPtr<nsIMsgWindow> msgWindow;
00169             mailnewsUrl->GetMsgWindow(getter_AddRefs(msgWindow));
00170             if (msgWindow)
00171             {
00172               nsCOMPtr<nsIMsgHeaderSink> hdrSink;
00173               msgWindow->GetMsgHeaderSink(getter_AddRefs(hdrSink));
00174               if (hdrSink)
00175                 hdrSink->OnEndMsgDownload(mailnewsUrl);
00176             }
00177             // get the folder and notify that the msg has been loaded. We're 
00178             // using NotifyPropertyFlagChanged. To be completely consistent,
00179             // we'd send a similar notification that the old message was
00180             // unloaded.
00181             nsXPIDLCString spec;
00182             nsCOMPtr <nsIMsgDBHdr> msgHdr;
00183             nsCOMPtr <nsIMsgFolder> msgFolder;
00184             mailnewsUrl->GetFolder(getter_AddRefs(msgFolder));
00185             nsCOMPtr <nsIMsgMessageUrl> msgUrl = do_QueryInterface(mailnewsUrl);
00186             if (msgUrl)
00187             {
00188               // not sending this notification is not a fatal error...
00189               (void) msgUrl->GetMessageHeader(getter_AddRefs(msgHdr));
00190               if (msgFolder && msgHdr)
00191                 msgFolder->NotifyPropertyFlagChanged(msgHdr, m_msgLoadedAtom, 0, 1);
00192             }
00193           }
00194         }
00195       }
00196       StopMeteors();
00197       nsXPIDLString documentDone;
00198       rv = mBundle->GetStringFromName(NS_LITERAL_STRING("documentDone").get(),
00199                                       getter_Copies(documentDone));
00200       if (NS_SUCCEEDED(rv))
00201         ShowStatusString(documentDone);
00202     }
00203   }
00204   return NS_OK;
00205 }
00206 
00207 NS_IMETHODIMP nsMsgStatusFeedback::OnLocationChange(nsIWebProgress* aWebProgress,
00208                                                     nsIRequest* aRequest,
00209                                                     nsIURI* aLocation)
00210 {
00211    return NS_OK;
00212 }
00213 
00214 NS_IMETHODIMP 
00215 nsMsgStatusFeedback::OnStatusChange(nsIWebProgress* aWebProgress,
00216                                     nsIRequest* aRequest,
00217                                     nsresult aStatus,
00218                                     const PRUnichar* aMessage)
00219 {
00220     return NS_OK;
00221 }
00222 
00223 
00224 NS_IMETHODIMP 
00225 nsMsgStatusFeedback::OnSecurityChange(nsIWebProgress *aWebProgress, 
00226                                     nsIRequest *aRequest, 
00227                                     PRUint32 state)
00228 {
00229     return NS_OK;
00230 }
00231 
00232 
00233 NS_IMETHODIMP
00234 nsMsgStatusFeedback::ShowStatusString(const PRUnichar *status)
00235 {
00236   if (mStatusFeedback)
00237     mStatusFeedback->ShowStatusString(status);
00238        return NS_OK;
00239 }
00240 
00241 NS_IMETHODIMP
00242 nsMsgStatusFeedback::SetStatusString(const PRUnichar *status)
00243 {
00244   nsCOMPtr <nsIXULBrowserWindow> xulBrowserWindow = do_QueryInterface(mStatusFeedback);
00245   if (xulBrowserWindow)
00246     xulBrowserWindow->SetJSDefaultStatus(status);
00247   return NS_OK;
00248 }
00249 
00250 NS_IMETHODIMP
00251 nsMsgStatusFeedback::ShowProgress(PRInt32 percentage)
00252 {
00253   // if the percentage hasn't changed...OR if we are going from 0 to 100% in one step
00254   // then don't bother....just fall out....
00255        if (percentage == m_lastPercent || (m_lastPercent == 0 && percentage >= 100))
00256               return NS_OK;
00257   
00258   m_lastPercent = percentage;
00259 
00260        PRInt64 nowMS;
00261        LL_I2L(nowMS, 0);
00262        if (percentage < 100)       // always need to do 100%
00263        {
00264               int64 minIntervalBetweenProgress;
00265 
00266               LL_I2L(minIntervalBetweenProgress, 250);
00267               int64 diffSinceLastProgress;
00268               LL_I2L(nowMS, PR_IntervalToMilliseconds(PR_IntervalNow()));
00269               LL_SUB(diffSinceLastProgress, nowMS, m_lastProgressTime); // r = a - b
00270               LL_SUB(diffSinceLastProgress, diffSinceLastProgress, minIntervalBetweenProgress); // r = a - b
00271               if (!LL_GE_ZERO(diffSinceLastProgress))
00272                      return NS_OK;
00273        }
00274 
00275        m_lastProgressTime = nowMS;
00276   
00277   if (mStatusFeedback)
00278     mStatusFeedback->ShowProgress(percentage);
00279        return NS_OK;
00280 }
00281 
00282 NS_IMETHODIMP
00283 nsMsgStatusFeedback::StartMeteors()
00284 {
00285   if (mStatusFeedback)
00286     mStatusFeedback->StartMeteors();
00287   return NS_OK;
00288 }
00289 
00290 NS_IMETHODIMP
00291 nsMsgStatusFeedback::StopMeteors()
00292 {
00293   if (mStatusFeedback)
00294     mStatusFeedback->StopMeteors();
00295   return NS_OK;
00296 }
00297 
00298 NS_IMETHODIMP nsMsgStatusFeedback::CloseWindow()
00299 {
00300   mWindow = nsnull;
00301   mStatusFeedback = nsnull;
00302 
00303   return NS_OK;
00304 }
00305 
00306 NS_IMETHODIMP nsMsgStatusFeedback::SetDocShell(nsIDocShell *shell, nsIDOMWindow *aWindow)
00307 {
00308 
00309   nsCOMPtr<nsPIDOMWindow> piDOMWindow(do_QueryInterface(aWindow));
00310   if (piDOMWindow)
00311   {
00312     nsCOMPtr<nsISupports> xpConnectObj;
00313     piDOMWindow->GetObjectProperty(NS_LITERAL_STRING("MsgStatusFeedback").get(), getter_AddRefs(xpConnectObj));
00314     mStatusFeedback = do_QueryInterface(xpConnectObj);
00315   }
00316 
00317   mWindow = aWindow;
00318   return NS_OK;
00319 }
00320 
00321 NS_IMETHODIMP nsMsgStatusFeedback::OnProgress(nsIRequest *request, nsISupports* ctxt, 
00322                                           PRUint64 aProgress, PRUint64 aProgressMax)
00323 {
00324   // XXX: What should the nsIWebProgress be?
00325   // XXX: this truncates 64-bit to 32-bit
00326   return OnProgressChange(nsnull, request, nsUint64(aProgress), nsUint64(aProgressMax), 
00327                           nsUint64(aProgress) /* current total progress */, nsUint64(aProgressMax) /* max total progress */);
00328 }
00329 
00330 NS_IMETHODIMP nsMsgStatusFeedback::OnStatus(nsIRequest *request, nsISupports* ctxt, 
00331                                             nsresult aStatus, const PRUnichar* aStatusArg)
00332 {
00333   nsresult rv;
00334   nsCOMPtr<nsIStringBundleService> sbs = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
00335   if (NS_FAILED(rv)) return rv;
00336   nsXPIDLString str;
00337   rv = sbs->FormatStatusMessage(aStatus, aStatusArg, getter_Copies(str));
00338   if (NS_FAILED(rv)) return rv;
00339   nsAutoString msg(NS_STATIC_CAST(const PRUnichar*, str));
00340   return ShowStatusString(msg.get());
00341 }