Back to index

lightning-sunbird  0.9+nobinonly
nsThrobber.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 Communicator client 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 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 #include "nsThrobber.h"
00038 #include "nsIFactory.h"
00039 #include "nsIWidget.h"
00040 #include "nsVoidArray.h"
00041 #include "nsITimer.h"
00042 #include "nsFont.h"
00043 #include "nsIRenderingContext.h"
00044 #include "nsIFontMetrics.h"
00045 #include "nsIComponentManager.h"
00046 #include "nsWidgetsCID.h"
00047 #include "nsCRT.h"
00048 #include "prprf.h"
00049 #include "nsIDeviceContext.h"
00050 #include "nsGUIEvent.h"
00051 #include "nsIImage.h"
00052 #include "nsReadableUtils.h"
00053 
00054 
00055 static NS_DEFINE_IID(kChildCID, NS_CHILD_CID);
00056 
00057 static NS_DEFINE_IID(kIWidgetIID,        NS_IWIDGET_IID);
00058 
00059 
00060 #define THROB_NUM 14
00061 #define THROBBER_AT "resource:/res/throbber/anims%02d.gif"
00062 
00063 nsThrobber* nsThrobber::NewThrobber()
00064 {
00065   nsThrobber* t = new nsThrobber();
00066   if (t) {
00067     NS_ADDREF(t);
00068   }
00069   return t;
00070 }
00071 
00072 //----------------------------------------------------------------------
00073 
00074 nsVoidArray* nsThrobber::gThrobbers;
00075 
00076 nsThrobber*
00077 nsThrobber::FindThrobberFor(nsIWidget* aWidget)
00078 {
00079   if (gThrobbers) {
00080     PRInt32 i, n = gThrobbers->Count();
00081     for (i = 0; i < n; i++) {
00082       nsThrobber* th = (nsThrobber*) gThrobbers->ElementAt(i);
00083       if (nsnull != th) {
00084         if (th->mWidget == aWidget) {
00085           return th;
00086         }
00087       }
00088     }
00089   }
00090   return nsnull;
00091 }
00092 
00093 void
00094 nsThrobber::AddThrobber(nsThrobber* aThrobber)
00095 {
00096   if (gThrobbers) {
00097     gThrobbers->AppendElement(aThrobber);
00098   }
00099 }
00100 
00101 void
00102 nsThrobber::RemoveThrobber(nsThrobber* aThrobber)
00103 {
00104   if (gThrobbers) {
00105     gThrobbers->RemoveElement(aThrobber);
00106   }
00107 }
00108 
00109 nsEventStatus PR_CALLBACK
00110 nsThrobber::HandleThrobberEvent(nsGUIEvent *aEvent)
00111 {
00112   nsThrobber* throbber = FindThrobberFor(aEvent->widget);
00113   if (nsnull == throbber) {
00114     return nsEventStatus_eIgnore;
00115   }
00116 
00117   switch (aEvent->message)
00118   {
00119     case NS_PAINT:
00120     {
00121 #if 0
00122 
00123       nsPaintEvent *pe = (nsPaintEvent *)aEvent;
00124       nsIRenderingContext *cx = pe->renderingContext;
00125       nsRect bounds;
00126       nsIImageRequest *imgreq;
00127       nsIImage *img;
00128       PRBool clipState;
00129    
00130       pe->widget->GetClientBounds(bounds);
00131 
00132       cx->SetClipRect(*pe->rect, nsClipCombine_kReplace, clipState);
00133 
00134       cx->SetColor(NS_RGB(255, 255, 255));
00135       cx->DrawLine(0, bounds.height - 1, 0, 0);
00136       cx->DrawLine(0, 0, bounds.width, 0);
00137 
00138       cx->SetColor(NS_RGB(128, 128, 128));
00139       cx->DrawLine(bounds.width - 1, 1, bounds.width - 1, bounds.height - 1);
00140       cx->DrawLine(bounds.width - 1, bounds.height - 1, 0, bounds.height - 1);
00141 
00142       imgreq = (nsIImageRequest *)
00143         throbber->mImages->ElementAt(throbber->mIndex);
00144 
00145       if ((nsnull == imgreq) || (nsnull == (img = imgreq->GetImage())))
00146       {
00147         char str[10];
00148         nsFont tfont = nsFont("monospace", 0, 0, 0, 0, 10);
00149         nsIFontMetrics *met;
00150         nscoord w, h;
00151 
00152         cx->SetColor(NS_RGB(0, 0, 0));
00153         cx->FillRect(1, 1, bounds.width - 2, bounds.height - 2);
00154 
00155         PR_snprintf(str, sizeof(str), "%02d", throbber->mIndex);
00156 
00157         cx->SetColor(NS_RGB(255, 255, 255));
00158         cx->SetFont(tfont);
00159         cx->GetFontMetrics(met);
00160         if (nsnull != met)
00161         {
00162           cx->GetWidth(str, w);
00163           met->GetHeight(h);
00164           cx->DrawString(str, PRUint32(2), (bounds.width - w) >> 1, (bounds.height - h) >> 1);
00165           NS_RELEASE(met);
00166         }
00167       }
00168       else
00169       {
00170         cx->DrawImage(img, 1, 1);
00171         NS_RELEASE(img);
00172       }
00173 #endif
00174       break;
00175     }
00176 
00177     case NS_MOUSE_LEFT_BUTTON_UP:
00178       // XXX wire up to API
00179       //gTheViewer->GoTo(nsString("http://www.mozilla.org"));
00180       break;
00181 
00182     case NS_MOUSE_ENTER:
00183       aEvent->widget->SetCursor(eCursor_hyperlink);
00184       break;
00185 
00186     case NS_MOUSE_EXIT:
00187       aEvent->widget->SetCursor(eCursor_standard);
00188       break;
00189   }
00190 
00191   return nsEventStatus_eIgnore;
00192 }
00193 
00194 //----------------------------------------------------------------------
00195 
00196 PRInt32 nsThrobber::gNumThrobbers;
00197 
00198 // Note: operator new zeros our memory
00199 nsThrobber::nsThrobber()
00200 {
00201   if (0 == gNumThrobbers++) {
00202     gThrobbers = new nsVoidArray;
00203   }
00204   AddThrobber(this);
00205 }
00206 
00207 nsThrobber::~nsThrobber()
00208 {
00209   Destroy();
00210 }
00211 
00212 void
00213 nsThrobber::Destroy()
00214 {
00215   if (mWidget) {
00216     mWidget->Destroy();
00217     NS_RELEASE(mWidget);
00218   }
00219   RemoveThrobber(this);
00220   DestroyThrobberImages();
00221 
00222   if (0 == --gNumThrobbers) {
00223     delete gThrobbers;
00224     // Do this in case an event shows up later for the throbber...
00225     gThrobbers = nsnull;
00226   }
00227 }
00228 
00229 NS_IMPL_ISUPPORTS0(nsThrobber)
00230 
00231 nsresult
00232 nsThrobber::Init(nsIWidget* aParent, const nsRect& aBounds, const nsString& aFileNameMask, PRInt32 aNumImages)
00233 {
00234   mWidth     = aBounds.width;
00235   mHeight    = aBounds.height;
00236   mNumImages = aNumImages;
00237 
00238   // Create widget
00239   nsresult rv = CallCreateInstance(kChildCID, &mWidget);
00240   if (NS_OK != rv) {
00241     return rv;
00242   }
00243   mWidget->Create(aParent, aBounds, HandleThrobberEvent, NULL);
00244   return LoadThrobberImages(aFileNameMask, aNumImages);
00245 }
00246 
00247 nsresult
00248 nsThrobber::MoveTo(PRInt32 aX, PRInt32 aY)
00249 {
00250   NS_PRECONDITION(nsnull != mWidget, "no widget");
00251   mWidget->Resize(aX, aY, mWidth, mHeight, PR_TRUE);
00252   return NS_OK;
00253 }
00254 
00255 nsresult
00256 nsThrobber::Show()
00257 {
00258   mWidget->Show(PR_TRUE);
00259   return NS_OK;
00260 }
00261 
00262 nsresult
00263 nsThrobber::Hide()
00264 {
00265   mWidget->Show(PR_FALSE);
00266   return NS_OK;
00267 }
00268 
00269 nsresult
00270 nsThrobber::Start()
00271 {
00272   mRunning = PR_TRUE;
00273   return NS_OK;
00274 }
00275 
00276 nsresult
00277 nsThrobber::Stop()
00278 {
00279   mRunning = PR_FALSE;
00280   mIndex = 0;
00281   mWidget->Invalidate(PR_FALSE);
00282   return NS_OK;
00283 }
00284 
00285 #if 0
00286 void  
00287 nsThrobber::Notify(nsIImageRequest *aImageRequest,
00288                       nsIImage *aImage,
00289                       nsImageNotification aNotificationType,
00290                       PRInt32 aParam1, PRInt32 aParam2,
00291                       void *aParam3)
00292 {
00293   if (aNotificationType == nsImageNotification_kImageComplete) {
00294     mCompletedImages++;
00295 
00296     // Remove ourselves as an observer of the image request object, because
00297     // the image request objects each hold a reference to us. This avoids a
00298     // circular reference problem. If we don't, our ref count will never reach
00299     // 0 and we won't get destroyed and neither will the image request objects
00300     aImageRequest->RemoveObserver((nsIImageRequestObserver*)this);
00301   }
00302 }
00303 
00304 void 
00305 nsThrobber::NotifyError(nsIImageRequest *aImageRequest,
00306                         nsImageError aErrorType)
00307 {
00308 }
00309 #endif
00310 
00311 void
00312 nsThrobber::ThrobTimerCallback(nsITimer *aTimer, void *aClosure)
00313 {
00314   nsThrobber* throbber = (nsThrobber*)aClosure;
00315   throbber->Tick();
00316 }
00317 
00318 void
00319 nsThrobber::Tick()
00320 {
00321   if (mRunning) {
00322     mIndex++;
00323     if (mIndex >= mNumImages)
00324       mIndex = 0;
00325     mWidget->Invalidate(PR_TRUE);
00326   } else if (mCompletedImages == (PRUint32)mNumImages) {
00327     mWidget->Invalidate(PR_TRUE);
00328     mCompletedImages = 0;
00329   }
00330 }
00331 
00332 nsresult
00333 nsThrobber::LoadThrobberImages(const nsString& aFileNameMask, PRInt32 aNumImages)
00334 {
00335 #if 0
00336   nsresult rv;
00337   char url[2000];
00338 
00339   mImages = new nsVoidArray(mNumImages);
00340   if (nsnull == mImages) {
00341     return NS_ERROR_OUT_OF_MEMORY;
00342   }
00343   rv = NS_NewImageGroup(&mImageGroup);
00344   if (NS_OK != rv) {
00345     return rv;
00346   }
00347 
00348   nsIDeviceContext *deviceCtx = mWidget->GetDeviceContext();
00349   mImageGroup->Init(deviceCtx, nsnull);
00350   NS_RELEASE(deviceCtx);
00351 
00352   mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
00353   if (NS_OK != rv) {
00354     return rv;
00355   }
00356   mTimer->InitWithFuncCallback(ThrobTimerCallback, this, 33, nsITimer::TYPE_REPEATING_SLACK);
00357   
00358   char * mask = ToNewCString(aFileNameMask);
00359   for (PRInt32 cnt = 0; cnt < mNumImages; cnt++)
00360   {
00361     PR_snprintf(url, sizeof(url), mask, cnt);
00362     nscolor bgcolor = NS_RGB(0, 0, 0);
00363     mImages->InsertElementAt(mImageGroup->GetImage(url,
00364                                                    (nsIImageRequestObserver *)this,
00365                                                    &bgcolor,
00366                                                    mWidth - 2,
00367                                                    mHeight - 2, 0),
00368                                                    cnt);
00369   }
00370 
00371   if (nsnull != mask)
00372     nsMemory::Free(mask);
00373 
00374   mWidget->Invalidate(PR_TRUE);
00375 
00376   return rv;
00377 #endif
00378 
00379 return NS_OK;
00380 }
00381 
00382 void
00383 nsThrobber::DestroyThrobberImages()
00384 {
00385   if (mTimer) {
00386     mTimer->Cancel();
00387   }
00388 
00389 #if 0
00390   if (mImageGroup) {
00391     mImageGroup->Interrupt();
00392     for (PRInt32 cnt = 0; cnt < mNumImages; cnt++) {
00393       nsIImageRequest *imgreq = (nsIImageRequest*) mImages->ElementAt(cnt);
00394       NS_IF_RELEASE(imgreq);
00395     }
00396     NS_RELEASE(mImageGroup);
00397   }
00398 
00399   if (mImages) {
00400     delete mImages;
00401     mImages = nsnull;
00402   }
00403 #endif
00404 }