Touch down progress bar changes from PROGRESS_19981006_BRANCH.

This commit is contained in:
waterson%netscape.com 1998-10-09 04:34:47 +00:00
Родитель 1dfaa4ce03
Коммит c36d1640ce
11 изменённых файлов: 1344 добавлений и 11 удалений

Просмотреть файл

@ -3,3 +3,6 @@
# #
pw_public.h pw_public.h
nsITransferListener.h
nsProgressManager.h
progress.h

Просмотреть файл

@ -21,4 +21,12 @@ MODULE = progress
EXPORTS = pw_public.h EXPORTS = pw_public.h
ifdef MOZ_SMOOTH_PROGRESS
EXPORTS += \
nsITransferListener.h \
nsProgressManager.h \
progress.h \
$(NULL)
endif
include $(DEPTH)/config/rules.mk include $(DEPTH)/config/rules.mk

Просмотреть файл

@ -20,7 +20,15 @@ IGNORE_MANIFEST=1
MODULE=progress MODULE=progress
DEPTH=..\..\.. DEPTH=..\..\..
EXPORTS=pw_public.h
EXPORTS=\
!ifdef MOZ_SMOOTH_PROGRESS
nsITransferListener.h \
nsProgressManager.h \
progress.h \
!endif
pw_public.h \
$(NULL)
include <$(DEPTH)/config/rules.mak> include <$(DEPTH)/config/rules.mak>

Просмотреть файл

@ -22,7 +22,20 @@ LIBRARY_NAME = prgrss
REQUIRES = progress nspr dbm img layer util REQUIRES = progress nspr dbm img layer util
ifdef MOZ_SMOOTH_PROGRESS
REQUIRES += raptor xpcom
endif
# all code is platform specific right now # all code is platform specific right now
CPPSRCS = pw_win.cpp pw_unix.cpp pwcommon.cpp CPPSRCS = pw_win.cpp pw_unix.cpp pwcommon.cpp
ifdef MOZ_SMOOTH_PROGRESS
CPPSRCS += nsProgressManager.cpp \
nsTopProgressManager.cpp \
nsSubProgressManager.cpp \
nsTransfer.cpp \
progress.cpp \
$(NULL)
endif
include $(DEPTH)/config/rules.mk include $(DEPTH)/config/rules.mk

Просмотреть файл

@ -26,28 +26,63 @@ MAKE_OBJ_TYPE=EXE
MODULE=progress MODULE=progress
REQUIRES=progress nspr dbm img layer util REQUIRES=progress nspr dbm img layer util xpcom
LIBRARY_NAME=prgrss LIBRARY_NAME=prgrss
DEPTH=..\..\.. DEPTH=..\..\..
CPPSRCS=pw_win.cpp pw_unix.cpp pwcommon.cpp
CPP_OBJS=.\$(OBJDIR)\pw_win.obj .\$(OBJDIR)\pw_unix.obj \ CPPSRCS=\
.\$(OBJDIR)\pwcommon.obj pw_win.cpp \
pw_unix.cpp \
pwcommon.cpp \
!ifdef MOZ_SMOOTH_PROGRESS
nsProgressManager.cpp \
nsSubProgressManager.cpp \
nsTopProgressManager.cpp \
nsTransfer.cpp \
progress.cpp \
!endif
$(NULL)
CPP_OBJS=\
.\$(OBJDIR)\pw_win.obj \
.\$(OBJDIR)\pw_unix.obj \
.\$(OBJDIR)\pwcommon.obj \
!ifdef MOZ_SMOOTH_PROGRESS
.\$(OBJDIR)\nsProgressManager.obj \
.\$(OBJDIR)\nsTopProgressManager.obj \
.\$(OBJDIR)\nsSubProgressManager.obj \
.\$(OBJDIR)\nsTransfer.obj \
.\$(OBJDIR)\progress.obj \
!endif
$(NULL)
!if "$(MOZ_BITS)" != "16" !if "$(MOZ_BITS)" != "16"
LINCS=-I$(XPDIST)\public\progress -I$(XPDIST)\public\nspr \ LINCS=\
-I$(XPDIST)\public\dbm -I$(XPDIST)\public\img \ -I$(XPDIST)\public\progress \
-I$(XPDIST)\public\layer -I$(XPDIST)\public\util -I$(XPDIST)\public\nspr \
-I$(XPDIST)\public\dbm \
-I$(XPDIST)\public\img \
-I$(XPDIST)\public\layer \
-I$(XPDIST)\public\util \
!ifdef MOZ_SMOOTH_PROGRESS
-I$(XPDIST)\public\network \
-I$(XPDIST)\public\raptor \
-I$(XPDIST)\public\xpcom \
!endif
$(NULL)
!endif !endif
include <$(DEPTH)\config\rules.mak> include <$(DEPTH)\config\rules.mak>
# XXX this should not be required, but mantomake doesnt grok J?I yet # XXX this should not be required, but mantomake doesnt grok J?I yet
# also, -I..\public should be -I$(PUBLIC)\progress # also, -I..\public should be -I$(PUBLIC)\progress
LINCS= $(LINCS) \ LINCS=$(LINCS) \
-I$(DEPTH)/cmd/winfe \ -I$(DEPTH)/cmd/winfe \
-I..\public -I..\public
libs:: $(LIBRARY) libs:: $(LIBRARY)
$(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib $(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib
clobber:: clobber::
$(RM) $(DIST)\lib\$(LIBRARY) $(RM) $(DIST)\lib\$(LIBRARY)

Просмотреть файл

@ -0,0 +1,123 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsSubProgressManager.h"
////////////////////////////////////////////////////////////////////////
nsSubProgressManager::nsSubProgressManager(MWContext* context)
: nsProgressManager(context)
{
// Grab a reference to the parent context's progress manager
nsITransferListener* pm = fContext->grid_parent->progressManager;
PR_ASSERT(pm);
if (pm)
pm->AddRef();
}
nsSubProgressManager::~nsSubProgressManager(void)
{
// Release the reference on the parent context's progress manager
nsITransferListener* pm = fContext->grid_parent->progressManager;
if (pm)
pm->Release();
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsSubProgressManager::OnStartBinding(const URL_Struct* url)
{
nsITransferListener* pm = fContext->grid_parent->progressManager;
PR_ASSERT(pm);
if (! pm)
return NS_ERROR_NULL_POINTER;
return pm->OnStartBinding(url);
}
NS_IMETHODIMP
nsSubProgressManager::OnProgress(const URL_Struct* url,
PRUint32 bytesReceived,
PRUint32 contentLength)
{
nsITransferListener* pm = fContext->grid_parent->progressManager;
PR_ASSERT(pm);
if (! pm)
return NS_ERROR_NULL_POINTER;
return pm->OnProgress(url, bytesReceived, contentLength);
}
NS_IMETHODIMP
nsSubProgressManager::OnStatus(const URL_Struct* url, const char* message)
{
nsITransferListener* pm = fContext->grid_parent->progressManager;
PR_ASSERT(pm);
if (! pm)
return NS_ERROR_NULL_POINTER;
return pm->OnStatus(url, message);
}
NS_IMETHODIMP
nsSubProgressManager::OnSuspend(const URL_Struct* url)
{
nsITransferListener* pm = fContext->grid_parent->progressManager;
PR_ASSERT(pm);
if (! pm)
return NS_ERROR_NULL_POINTER;
return pm->OnSuspend(url);
}
NS_IMETHODIMP
nsSubProgressManager::OnResume(const URL_Struct* url)
{
nsITransferListener* pm = fContext->grid_parent->progressManager;
PR_ASSERT(pm);
if (! pm)
return NS_ERROR_NULL_POINTER;
return pm->OnResume(url);
}
NS_IMETHODIMP
nsSubProgressManager::OnStopBinding(const URL_Struct* url,
PRInt32 status,
const char* message)
{
nsITransferListener* pm = fContext->grid_parent->progressManager;
PR_ASSERT(pm);
if (! pm)
return NS_ERROR_NULL_POINTER;
return pm->OnStopBinding(url, status, message);
}

Просмотреть файл

@ -0,0 +1,59 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsSubProgressManager_h__
#define nsSubProgressManager_h__
#include "nsProgressManager.h"
/**
* The <b>nsSubProgressManager</b> is a progress manager that gets created
* in a grid (frame cell) context. It simply delegates all of the operations
* in the <b>nsITransferListener</b> interface to it's grid parent's
* progress manager.
*/
class nsSubProgressManager : public nsProgressManager
{
public:
nsSubProgressManager(MWContext* context);
virtual ~nsSubProgressManager(void);
NS_IMETHOD
OnStartBinding(const URL_Struct* url);
NS_IMETHOD
OnProgress(const URL_Struct* url, PRUint32 bytesReceived, PRUint32 contentLength);
NS_IMETHOD
OnStatus(const URL_Struct* url, const char* message);
NS_IMETHOD
OnSuspend(const URL_Struct* url);
NS_IMETHOD
OnResume(const URL_Struct* url);
NS_IMETHOD
OnStopBinding(const URL_Struct* url, PRInt32 status, const char* message);
};
#endif // nsSubProgressManager_h__

Просмотреть файл

@ -0,0 +1,691 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsTopProgressManager.h"
#include "nsTransfer.h"
#include "xp.h" // for FE_* callbacks
#include "xpgetstr.h"
#include "prprf.h"
#include "prmem.h"
#include "plstr.h"
#define OBJECT_TABLE_INIT_SIZE 32
////////////////////////////////////////////////////////////////////////
//
// Debugging garbage
//
//
#if 0 /* defined(DEBUG) */
#define TRACE_PROGRESS(args) pm_TraceProgress args
static void
pm_TraceProgress(const char* fmtstr, ...)
{
char buf[256];
va_list ap;
va_start(ap, fmtstr);
PR_vsnprintf(buf, sizeof(buf), fmtstr, ap);
va_end(ap);
#if defined(XP_WIN)
OutputDebugString(buf);
#elif defined(XP_UNIX)
#elif defined(XP_MAC)
#endif
}
#else /* defined(DEBUG) */
#define TRACE_PROGRESS(args)
#endif /* defined(DEBUG) */
////////////////////////////////////////////////////////////////////////
//
// Hash table allocation routines
//
//
static PR_CALLBACK void*
AllocTable(void* pool, PRSize size)
{
return PR_MALLOC(size);
}
static PR_CALLBACK void
FreeTable(void* pool, void* item)
{
PR_DELETE(item);
}
static PR_CALLBACK PLHashEntry*
AllocEntry(void* pool, const void* key)
{
return PR_NEW(PLHashEntry);
}
static PR_CALLBACK void
FreeEntry(void* pool, PLHashEntry* he, PRUintn flag)
{
if (flag == HT_FREE_VALUE) {
if (he->value) {
nsTransfer* obj = (nsTransfer*) he->value;
obj->Release();
}
}
else if (flag == HT_FREE_ENTRY) {
// we don't own the key, so leave it alone...
if (he->value) {
nsTransfer* obj = (nsTransfer*) he->value;
obj->Release();
}
PR_DELETE(he);
}
}
static PLHashAllocOps AllocOps = {
AllocTable,
FreeTable,
AllocEntry,
FreeEntry
};
static PLHashNumber
pm_HashURL(const void* key)
{
return (PLHashNumber) key;
}
static int
pm_CompareURLs(const void* v1, const void* v2)
{
return v1 == v2;
}
////////////////////////////////////////////////////////////////////////
//
// Hash table iterators
//
//
static PRIntn
pm_AggregateTransferInfo(PLHashEntry* he, PRIntn i, void* closure)
{
AggregateTransferInfo* info = (AggregateTransferInfo*) closure;
++(info->ObjectCount);
if (he->value) {
nsTransfer* transfer = (nsTransfer*) he->value;
if (transfer->IsComplete())
++(info->CompleteCount);
if (transfer->IsSuspended())
++(info->SuspendedCount);
info->MSecRemaining += transfer->GetMSecRemaining();
info->BytesReceived += transfer->GetBytesReceived();
info->ContentLength += transfer->GetContentLength();
if (! transfer->IsComplete() &&
transfer->GetContentLength() == transfer->GetBytesReceived())
++(info->UnknownLengthCount);
}
return HT_ENUMERATE_NEXT;
}
////////////////////////////////////////////////////////////////////////
//
// nsTopProgressManager
//
//
////////////////////////////////////////////////////////////////////////
nsTopProgressManager::nsTopProgressManager(MWContext* context)
: nsProgressManager(context),
fActualStart(PR_Now()),
fProgressBarStart(PR_Now()),
fDefaultStatus(NULL)
{
fURLs = PL_NewHashTable(OBJECT_TABLE_INIT_SIZE,
pm_HashURL,
pm_CompareURLs,
PL_CompareValues,
&AllocOps,
NULL);
// Start the progress manager
fTimeout = FE_SetTimeout(nsTopProgressManager::TimeoutCallback, (void*) this, 500);
PR_ASSERT(fTimeout);
// to avoid "strobe" mode...
fProgress = 1;
FE_SetProgressBarPercent(fContext, fProgress);
}
nsTopProgressManager::~nsTopProgressManager(void)
{
if (fDefaultStatus) {
PL_strfree(fDefaultStatus);
fDefaultStatus = NULL;
}
if (fURLs) {
PL_HashTableDestroy(fURLs);
fURLs = NULL;
}
if (fTimeout) {
FE_ClearTimeout(fTimeout);
fTimeout = NULL;
}
// XXX Needs to go to allxpstr.h
FE_Progress(fContext, "Done.");
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsTopProgressManager::OnStartBinding(const URL_Struct* url)
{
PR_ASSERT(url);
if (! url)
return NS_ERROR_NULL_POINTER;
PR_ASSERT(fURLs);
if (! fURLs)
return NS_ERROR_NULL_POINTER;
TRACE_PROGRESS(("OnStartBinding(%s)\n", url->address));
PL_HashTableAdd(fURLs, url, new nsTransfer(url));
return NS_OK;
}
NS_IMETHODIMP
nsTopProgressManager::OnProgress(const URL_Struct* url,
PRUint32 bytesReceived,
PRUint32 contentLength)
{
// Some sanity checks...
PR_ASSERT(url);
if (! url)
return NS_ERROR_NULL_POINTER;
TRACE_PROGRESS(("OnProgress(%s, %ld, %ld)\n", url->address, bytesReceived, contentLength));
PR_ASSERT(fURLs);
if (! fURLs)
return NS_ERROR_NULL_POINTER;
nsTransfer* transfer = (nsTransfer*) PL_HashTableLookup(fURLs, url);
PR_ASSERT(transfer);
if (!transfer)
return NS_ERROR_NULL_POINTER;
transfer->SetProgress(bytesReceived, contentLength);
return NS_OK;
}
NS_IMETHODIMP
nsTopProgressManager::OnStatus(const URL_Struct* url, const char* message)
{
TRACE_PROGRESS(("OnStatus(%s, %s)\n", (url ? url->address : NULL), message));
// There are cases when transfer may be null, and that's ok.
if (url) {
PR_ASSERT(fURLs);
if (! fURLs)
return NS_ERROR_NULL_POINTER;
nsTransfer* transfer = (nsTransfer*) PL_HashTableLookup(fURLs, url);
PR_ASSERT(transfer);
if (transfer)
transfer->SetStatus(message);
}
if (fDefaultStatus)
PL_strfree(fDefaultStatus);
fDefaultStatus = PL_strdup(message);
return NS_OK;
}
NS_IMETHODIMP
nsTopProgressManager::OnSuspend(const URL_Struct* url)
{
PR_ASSERT(url);
if (! url)
return NS_ERROR_NULL_POINTER;
TRACE_PROGRESS(("OnSuspend(%s)\n", url->address));
PR_ASSERT(fURLs);
if (! fURLs)
return NS_ERROR_NULL_POINTER;
nsTransfer* transfer = (nsTransfer*) PL_HashTableLookup(fURLs, url);
PR_ASSERT(transfer);
if (!transfer)
return NS_ERROR_NULL_POINTER;
transfer->Suspend();
return NS_OK;
}
NS_IMETHODIMP
nsTopProgressManager::OnResume(const URL_Struct* url)
{
PR_ASSERT(url);
if (! url)
return NS_ERROR_NULL_POINTER;
TRACE_PROGRESS(("OnResume(%s)\n", url->address));
PR_ASSERT(fURLs);
if (! fURLs)
return NS_ERROR_NULL_POINTER;
nsTransfer* transfer = (nsTransfer*) PL_HashTableLookup(fURLs, url);
PR_ASSERT(transfer);
if (!transfer)
return NS_ERROR_NULL_POINTER;
transfer->Resume();
return NS_OK;
}
NS_IMETHODIMP
nsTopProgressManager::OnStopBinding(const URL_Struct* url,
PRInt32 status,
const char* message)
{
PR_ASSERT(url);
if (! url)
return NS_ERROR_NULL_POINTER;
TRACE_PROGRESS(("OnStatus(%s, %d, %s)\n", url->address, status, message));
PR_ASSERT(fURLs);
if (! fURLs)
return NS_ERROR_NULL_POINTER;
nsTransfer* transfer = (nsTransfer*) PL_HashTableLookup(fURLs, url);
PR_ASSERT(transfer);
if (!transfer)
return NS_ERROR_NULL_POINTER;
transfer->MarkComplete(status);
transfer->SetStatus(message);
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
void
nsTopProgressManager::TimeoutCallback(void* closure)
{
nsTopProgressManager* self = (nsTopProgressManager*) closure;
self->Tick();
}
void
nsTopProgressManager::Tick(void)
{
TRACE_PROGRESS(("nsProgressManager.Tick: aggregating information for active objects\n"));
AggregateTransferInfo info = { 0, 0, 0, 0, 0, 0, 0 };
PL_HashTableEnumerateEntries(fURLs, pm_AggregateTransferInfo, (void*) &info);
TRACE_PROGRESS(("nsProgressManager.Tick: %ld of %ld objects complete, "
"%ldms left, "
"%ld of %ld bytes xferred\n",
info.CompleteCount, info.ObjectCount,
info.MSecRemaining,
info.BytesReceived, info.ContentLength));
PR_ASSERT(info.ObjectCount > 0);
if (info.ObjectCount == 0)
return;
UpdateProgressBar(info);
UpdateStatusMessage(info);
// Check to see if we're done.
if (info.CompleteCount == info.ObjectCount) {
TRACE_PROGRESS(("Complete: %ld/%ld objects loaded\n",
info.CompleteCount,
info.ObjectCount));
// XXX needs to go to allxpstr.h
FE_Progress(fContext, " ");
PL_HashTableDestroy(fURLs);
fURLs = NULL;
fTimeout = NULL;
}
else {
// Reset the timeout to fire again...
fTimeout = FE_SetTimeout(nsTopProgressManager::TimeoutCallback,
(void*) this, 500);
}
}
void
nsTopProgressManager::UpdateProgressBar(AggregateTransferInfo& info)
{
if (info.MSecRemaining == 0)
return;
if (info.SuspendedCount > 0) {
// turn on the strobe...
FE_SetProgressBarPercent(fContext, 0);
return;
}
nsInt64 dt = nsTime(PR_Now()) - fProgressBarStart;
PRUint32 elapsed = dt / nsInt64((PRUint32) PR_USEC_PER_MSEC);
// Compute the percent complete, that is, elapsed / (elapsed + remaining)
double p = ((double) elapsed) / ((double) (elapsed + info.MSecRemaining));
PRUint32 pctComplete = (PRUint32) (100.0 * p);
#define MONOTONIC_PROGRESS_BAR
#if defined(MONOTONIC_PROGRESS_BAR)
// This hackery is a kludge to make the progress bar
// monotonically increase rather than slipping backwards as we
// discover that there's more content to download. It works by
// adjusting the progress manager's start time backwards to
// make the elapsed time (time we've waited so far) seem
// larger in proportion to the amount of time that appears to
// be left.
if (pctComplete < fProgress) {
PRUint32 newElapsed =
(PRUint32) ((p * ((double) info.MSecRemaining))
/ (1.0 - p));
PRInt32 dMSec = newElapsed - elapsed;
if (dMSec > 0)
fProgressBarStart -= nsInt64(dMSec * ((PRUint32) PR_USEC_PER_MSEC));
// Progress bar hasn't changed -- don't bother updating it.
return;
}
#endif
fProgress = pctComplete;
FE_SetProgressBarPercent(fContext, fProgress);
}
////////////////////////////////////////////////////////////////////////
//
// The bulk of the following code was pulled over from lib/xp/xp_thermo.c
//
#ifdef XP_MAC
#include "allxpstr.h"
#else
PR_BEGIN_EXTERN_C
extern int XP_THERMO_BYTE_FORMAT;
extern int XP_THERMO_KBYTE_FORMAT;
extern int XP_THERMO_HOURS_FORMAT;
extern int XP_THERMO_MINUTES_FORMAT;
extern int XP_THERMO_SECONDS_FORMAT;
extern int XP_THERMO_SINGULAR_FORMAT;
extern int XP_THERMO_PLURAL_FORMAT;
extern int XP_THERMO_PERCENTAGE_FORMAT;
extern int XP_THERMO_UH;
extern int XP_THERMO_PERCENT_FORM;
extern int XP_THERMO_PERCENT_RATE_FORM;
extern int XP_THERMO_RAW_COUNT_FORM;
extern int XP_THERMO_BYTE_RATE_FORMAT;
extern int XP_THERMO_K_RATE_FORMAT;
extern int XP_THERMO_M_RATE_FORMAT;
extern int XP_THERMO_STALLED_FORMAT;
extern int XP_THERMO_RATE_REMAINING_FORM;
extern int XP_THERMO_RATE_FORM;
PR_END_EXTERN_C
#endif // XP_MAC
#define KILOBYTE (1024L)
#define MINUTE (60L)
#define HOUR (MINUTE * MINUTE)
#define IS_PLURAL(x) (((x) == 1) ? "" : XP_GetString(XP_THERMO_PLURAL_FORMAT)) /* L10N? */
#define ENOUGH_TIME_TO_GUESS 10 /* in seconds */
#define TIME_UNTIL_DETAILS 5
////////////////////////////////////////////////////////////////////////
static void
formatRate(char* buf, PRUint32 len, double bytes_per_sec)
{
if (bytes_per_sec > 0) {
if (bytes_per_sec < KILOBYTE)
PR_snprintf(buf, len, XP_GetString(XP_THERMO_BYTE_RATE_FORMAT),
(PRUint32) bytes_per_sec);
else
PR_snprintf(buf, len, XP_GetString(XP_THERMO_K_RATE_FORMAT),
(bytes_per_sec / ((double) KILOBYTE)));
}
}
static void
formatKnownContentLength(char* buf,
PRUint32 len,
PRUint32 bytesReceived,
PRUint32 contentLength,
PRUint32 elapsed)
{
char rate[32];
*rate = 0;
// the transfer rate
double bytes_per_sec = 0;
if (elapsed > 0)
bytes_per_sec = ((double) bytesReceived) / ((double) elapsed);
formatRate(rate, sizeof(rate), bytes_per_sec);
// format the content length
char length[32];
*length = 0;
if (contentLength < KILOBYTE)
PR_snprintf(length, sizeof(length), XP_GetString(XP_THERMO_BYTE_FORMAT), contentLength);
else
PR_snprintf(length, sizeof(length), XP_GetString(XP_THERMO_KBYTE_FORMAT), contentLength / KILOBYTE);
// the percentage complete
char percent[32];
PRUint32 p = (bytesReceived * 100) / contentLength;
if (p >= 100 && bytesReceived != contentLength)
p = 99;
PR_snprintf(percent, sizeof(percent), XP_GetString(XP_THERMO_PERCENTAGE_FORMAT), p);
// the amount of time remaining
char tleft[32];
*tleft = 0;
if (bytes_per_sec >= KILOBYTE && elapsed >= ENOUGH_TIME_TO_GUESS) {
PRUint32 secs_left =
(PRUint32) (((double) (contentLength - bytesReceived)) / bytes_per_sec);
if (secs_left >= HOUR) {
PR_snprintf(tleft, sizeof(tleft),
XP_GetString(XP_THERMO_HOURS_FORMAT),
secs_left / HOUR,
(secs_left / MINUTE) % MINUTE,
secs_left % MINUTE);
}
else if (secs_left >= MINUTE) {
PR_snprintf(tleft, sizeof(tleft),
XP_GetString(XP_THERMO_MINUTES_FORMAT),
secs_left / MINUTE,
secs_left % MINUTE);
}
else if (secs_left > 0) {
PR_snprintf(tleft, sizeof(tleft),
XP_GetString(XP_THERMO_SECONDS_FORMAT),
secs_left,
IS_PLURAL(secs_left));
}
}
if (*tleft) {
/* "%s of %s (at %s, %s remaining)" */
PR_snprintf(buf, len,
XP_GetString(XP_THERMO_RATE_REMAINING_FORM),
percent, length, rate, tleft);
}
else if (*rate) {
/* "%s of %s (at %s)" */
PR_snprintf(buf, len,
XP_GetString(XP_THERMO_RATE_FORM),
percent, length, rate);
}
else {
/* "%s of %s" */
PR_snprintf(buf, len,
XP_GetString(XP_THERMO_PERCENT_FORM),
percent, length);
}
}
static void
formatUnknownContentLength(char* buf, PRUint32 len, PRUint32 bytesReceived, PRUint32 elapsed)
{
char rate[32];
*rate = 0;
// the transfer rate
double bytes_per_sec = 0;
if (elapsed > 0)
bytes_per_sec = ((double) bytesReceived) / ((double) elapsed);
formatRate(rate, sizeof(rate), bytes_per_sec);
// the number of bytes received
char bytes_received[32];
if (bytesReceived < KILOBYTE)
PR_snprintf(bytes_received, sizeof(bytes_received),
XP_GetString(XP_THERMO_UH),
bytesReceived, IS_PLURAL(bytesReceived));
else
PR_snprintf(bytes_received, sizeof(bytes_received),
XP_GetString(XP_THERMO_KBYTE_FORMAT),
bytesReceived / KILOBYTE);
if (*rate) {
/* "%s read (at %s)" */
PR_snprintf(buf, len, XP_GetString(XP_THERMO_PERCENT_RATE_FORM), bytes_received, rate);
}
else {
PR_snprintf(buf, len, XP_GetString(XP_THERMO_RAW_COUNT_FORM), bytes_received);
}
}
void
nsTopProgressManager::UpdateStatusMessage(AggregateTransferInfo& info)
{
// Compute how much time has elapsed
nsInt64 dt = nsTime(PR_Now()) - fActualStart;
PRUint32 elapsed = dt / nsInt64((PRUint32) PR_USEC_PER_SEC);
char buf[256];
*buf = 0;
if (info.ObjectCount == 1 || info.CompleteCount == 0) {
// If we only have one object that we're transferring, or if
// nothing has completed yet, show the default status message
PL_strncpy(buf, fDefaultStatus, sizeof(buf));
}
if (elapsed > TIME_UNTIL_DETAILS) {
char details[256];
*details = 0;
if (!info.UnknownLengthCount && info.ContentLength > 0) {
formatKnownContentLength(details, sizeof(details),
info.BytesReceived,
info.ContentLength,
elapsed);
}
else if (info.BytesReceived > 0) {
formatUnknownContentLength(details, sizeof(details),
info.BytesReceived,
elapsed);
}
if (*details) {
// XXX needs to go to allxpstr.h
if (*buf)
PL_strcatn(buf, sizeof(buf), ", ");
PL_strcatn(buf, sizeof(buf), details);
}
}
FE_Progress(fContext, buf);
}

Просмотреть файл

@ -0,0 +1,130 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsTopProgressManager_h__
#define nsTopProgressManager_h__
#include "nsProgressManager.h"
#include "nsTime.h"
struct AggregateTransferInfo {
PRUint32 ObjectCount;
PRUint32 CompleteCount;
PRUint32 SuspendedCount;
PRUint32 MSecRemaining;
PRUint32 BytesReceived;
PRUint32 ContentLength;
PRUint32 UnknownLengthCount;
};
/**
* An <b>nsTopProgressManager</b> is a progress manager that is associated
* with a top-level window context. It does the dirty work of managing the
* progress bar and the status text.
*/
class nsTopProgressManager : public nsProgressManager
{
protected:
/**
* A table of URLs that we are monitoring progress for. The table is
* keyed by <b>URL_Structs</b>, the values are <b>nsTransfer</b>
* objects.
*/
PLHashTable* fURLs;
/**
* The time at which the progress manager was created.
*/
nsTime fActualStart;
/**
* The time at which the progress bar thinks we were created. This is used
* with to make progress seem "monotonic": it is "slipped" backwards
* when a transfer stalls so that the percentage complete stays constant.
*/
nsTime fProgressBarStart;
/**
* The current amount of progress shown on the chrome's progress bar
*/
PRUint16 fProgress;
/**
* The default status message to display if nothing more appropriate
* is around.
*/
char* fDefaultStatus;
/**
* An FE timeout object that is used to periodically update the
* status bar.
*/
void* fTimeout;
/**
* The FE timeout callback.
*/
static void TimeoutCallback(void* self);
/**
* Called to update the status bar.
*/
virtual void Tick(void);
/**
* Update the progress bar
*/
virtual void UpdateProgressBar(AggregateTransferInfo& info);
/**
* Update the status message
*/
virtual void UpdateStatusMessage(AggregateTransferInfo& info);
public:
nsTopProgressManager(MWContext* context);
virtual ~nsTopProgressManager(void);
NS_IMETHOD
OnStartBinding(const URL_Struct* url);
NS_IMETHOD
OnProgress(const URL_Struct* url, PRUint32 bytesReceived, PRUint32 contentLength);
NS_IMETHOD
OnStatus(const URL_Struct* url, const char* message);
NS_IMETHOD
OnSuspend(const URL_Struct* url);
NS_IMETHOD
OnResume(const URL_Struct* url);
NS_IMETHOD
OnStopBinding(const URL_Struct* url, PRInt32 status, const char* message);
};
#endif // nsTopProgressManager_h__

Просмотреть файл

@ -0,0 +1,192 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsTransfer.h"
#include "plstr.h"
#include "prtime.h"
////////////////////////////////////////////////////////////////////////
PRUint32 nsTransfer::DefaultMSecRemaining = 1000;
nsTransfer::nsTransfer(const URL_Struct* url)
: fURL(url),
fBytesReceived(0),
fContentLength(0),
fStart(PR_Now()),
fIsSuspended(PR_FALSE),
fStatus(NULL),
fComplete(PR_FALSE),
fResultCode(0)
{
}
nsTransfer::~nsTransfer(void)
{
if (fStatus) {
PL_strfree(fStatus);
fStatus = NULL;
}
}
NS_IMPL_ISUPPORTS(nsTransfer, kISupportsIID);
void
nsTransfer::SetProgress(PRUint32 bytesReceived, PRUint32 contentLength)
{
fBytesReceived = bytesReceived;
fContentLength = contentLength;
if (fContentLength < fBytesReceived)
fContentLength = fBytesReceived;
}
PRUint32
nsTransfer::GetBytesReceived(void)
{
return fBytesReceived;
}
PRUint32
nsTransfer::GetContentLength(void)
{
return fContentLength;
}
double
nsTransfer::GetTransferRate(void)
{
if (fContentLength == 0 || fBytesReceived == 0)
return 0;
nsInt64 dt = nsTime(PR_Now()) - fStart;
PRUint32 dtMSec = dt / nsInt64((PRUint32) PR_USEC_PER_MSEC);
if (dtMSec == 0)
return 0;
return ((double) fBytesReceived) / ((double) dtMSec);
}
PRUint32
nsTransfer::GetMSecRemaining(void)
{
if (IsComplete())
return 0;
if (fContentLength == 0 || fBytesReceived == 0)
// no content length and/or no bytes received
return DefaultMSecRemaining;
PRUint32 cbRemaining = fContentLength - fBytesReceived;
if (cbRemaining == 0)
// not complete, but content length == bytes received.
return DefaultMSecRemaining;
double bytesPerMSec = GetTransferRate();
if (bytesPerMSec == 0)
return DefaultMSecRemaining;
PRUint32 msecRemaining = (PRUint32) (((double) cbRemaining) / bytesPerMSec);
return msecRemaining;
}
void
nsTransfer::SetStatus(const char* message)
{
if (fStatus)
PL_strfree(fStatus);
fStatus = PL_strdup(message);
}
const char*
nsTransfer::GetStatus(void)
{
return fStatus;
}
void
nsTransfer::Suspend(void)
{
if (fIsSuspended)
return;
fSuspendStart = PR_Now();
}
void
nsTransfer::Resume(void)
{
if (! fIsSuspended)
return;
nsInt64 dt = nsTime(PR_Now()) - fSuspendStart;
fStart += dt;
}
PRBool
nsTransfer::IsSuspended(void)
{
return fIsSuspended;
}
void
nsTransfer::MarkComplete(PRInt32 resultCode)
{
fComplete = PR_TRUE;
fResultCode = resultCode;
if (fResultCode >= 0) {
nsInt64 elapsed = nsTime(PR_Now()) - fStart;
PRUint32 elapsedMSec= (PRUint32) (elapsed / nsInt64((PRUint32) PR_USEC_PER_MSEC));
UpdateDefaultMSecRemaining(elapsedMSec);
}
}
PRBool
nsTransfer::IsComplete(void)
{
return fComplete;
}
void
nsTransfer::UpdateDefaultMSecRemaining(PRUint32 msec)
{
// very simple. just maintain a rolling average.
DefaultMSecRemaining += msec;
DefaultMSecRemaining /= 2;
}

Просмотреть файл

@ -0,0 +1,71 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsTransfer_h__
#define nsTransfer_h__
#include "prtypes.h"
#include "structs.h"
#include "nsISupports.h"
#include "nsTime.h"
/**
* This class encapsulates the transfer state for each stream that will
* be transferring data, is currently transferring data, or has previously
* transferred data in the current context.
*/
class nsTransfer
{
protected:
const URL_Struct* fURL;
PRUint32 fBytesReceived;
PRUint32 fContentLength;
nsTime fStart;
nsTime fSuspendStart;
PRBool fIsSuspended;
char* fStatus;
PRBool fComplete;
PRInt32 fResultCode;
static PRUint32 DefaultMSecRemaining;
static void UpdateDefaultMSecRemaining(PRUint32 time);
public:
nsTransfer(const URL_Struct* url);
virtual ~nsTransfer(void);
NS_DECL_ISUPPORTS
void SetProgress(PRUint32 bytesReceived, PRUint32 contentLength);
PRUint32 GetBytesReceived(void);
PRUint32 GetContentLength(void);
double GetTransferRate(void);
PRUint32 GetMSecRemaining(void);
void SetStatus(const char* message);
const char* GetStatus(void);
void Suspend(void);
void Resume(void);
PRBool IsSuspended(void);
void MarkComplete(PRInt32 resultCode);
PRBool IsComplete(void);
};
#endif // nsTransfer_h__