#3298:Prettier formating of percentages

This commit is contained in:
Daniel Lee 2010-06-22 22:30:58 +00:00
parent 7e9ba59807
commit bbe9e9843a
15 changed files with 169 additions and 96 deletions

View File

@ -113,6 +113,12 @@ static const double KiB = 1024.0;
static const double MiB = 1024.0 * 1024.0;
static const double GiB = 1024.0 * 1024.0 * 1024.0;
static char*
strlpercent( char * buf, double x, size_t buflen )
{
return tr_strpercent( buf, x, buflen );
}
static char*
strlratio2( char * buf, double ratio, size_t buflen )
{
@ -785,7 +791,7 @@ printDetails( tr_benc * top )
if( tr_bencDictFindInt( t, "sizeWhenDone", &i )
&& tr_bencDictFindInt( t, "leftUntilDone", &j ) )
{
strlratio( buf, 100.0 * ( i - j ), i, sizeof( buf ) );
strlpercent( buf, 100.0 * ( i - j ) / i, sizeof( buf ) );
printf( " Percent Done: %s%%\n", buf );
}
@ -811,7 +817,8 @@ printDetails( tr_benc * top )
&& tr_bencDictFindInt( t, "leftUntilDone", &k) )
{
j += i - k;
printf( " Availability: %.1f%%\n", ( 100 * j ) / (double) i );
strlpercent( buf, 100.0 * j / i, sizeof( buf ) );
printf( " Availability: %s%%\n", buf );
}
if( tr_bencDictFindInt( t, "totalSize", &j ) )
{

View File

@ -796,14 +796,15 @@ refreshInfo( struct DetailsImpl * di, tr_torrent ** torrents, int n )
if( !haveValid && !haveUnchecked )
str = none;
else {
char unver[64], total[64];
char buf2[32], unver[64], total[64];
const double ratio = 100.0 * ( leftUntilDone ? ( haveValid + haveUnchecked ) / sizeWhenDone : 1 );
tr_strlpercent( buf2, ratio, sizeof( buf2 ) );
tr_strlsize( total, haveUnchecked + haveValid, sizeof( total ) );
tr_strlsize( unver, haveUnchecked, sizeof( unver ) );
if( haveUnchecked )
g_snprintf( buf, sizeof( buf ), _( "%1$s (%2$.1f%%); %3$s Unverified" ), total, tr_truncd( ratio, 1 ), unver );
g_snprintf( buf, sizeof( buf ), _( "%1$s (%2$s%%); %3$s Unverified" ), total, buf2, unver );
else
g_snprintf( buf, sizeof( buf ), _( "%1$s (%2$.1f%%)" ), total, tr_truncd( ratio, 1 ) );
g_snprintf( buf, sizeof( buf ), _( "%1$s (%2$s%%)" ), total, buf2 );
str = buf;
}
}
@ -813,8 +814,10 @@ refreshInfo( struct DetailsImpl * di, tr_torrent ** torrents, int n )
if( !sizeWhenDone )
str = none;
else {
char buf2[32];
const double d = ( 100.0 * available ) / sizeWhenDone;
g_snprintf( buf, sizeof( buf ), _( "%1$.1f%%" ), d );
tr_strlpercent( buf2, d, sizeof( buf2 ) );
g_snprintf( buf, sizeof( buf ), _( "%1$s%%" ), buf2 );
str = buf;
}
gtr_label_set_text( GTK_LABEL( di->availability_lb ), str );

View File

@ -49,7 +49,7 @@ getProgressString( const tr_torrent * tor,
const int isDone = torStat->leftUntilDone == 0;
const uint64_t haveTotal = torStat->haveUnchecked + torStat->haveValid;
const int isSeed = torStat->haveValid >= info->totalSize;
char buf1[32], buf2[32], buf3[32], buf4[32], buf5[32];
char buf1[32], buf2[32], buf3[32], buf4[32], buf5[32], buf6[32];
char * str;
double seedRatio;
const gboolean hasSeedRatio = tr_torrentGetSeedRatio( tor, &seedRatio );
@ -59,11 +59,11 @@ getProgressString( const tr_torrent * tor,
str = g_strdup_printf(
/* %1$s is how much we've got,
%2$s is how much we'll have when done,
%3$.2f%% is a percentage of the two */
_( "%1$s of %2$s (%3$.2f%%)" ),
%3$s%% is a percentage of the two */
_( "%1$s of %2$s (%3$s%%)" ),
tr_strlsize( buf1, haveTotal, sizeof( buf1 ) ),
tr_strlsize( buf2, torStat->sizeWhenDone, sizeof( buf2 ) ),
tr_truncd( torStat->percentDone * 100.0, 2 ) );
tr_strlpercent( buf3, torStat->percentDone * 100.0, sizeof( buf3 ) ) );
}
else if( !isSeed ) /* partial seeds */
{
@ -72,32 +72,32 @@ getProgressString( const tr_torrent * tor,
str = g_strdup_printf(
/* %1$s is how much we've got,
%2$s is the torrent's total size,
%3$.2f%% is a percentage of the two,
%3$s%% is a percentage of the two,
%4$s is how much we've uploaded,
%5$s is our upload-to-download ratio,
%6$s is the ratio we want to reach before we stop uploading */
_( "%1$s of %2$s (%3$.2f%%), uploaded %4$s (Ratio: %5$s Goal: %6$s)" ),
_( "%1$s of %2$s (%3$s%%), uploaded %4$s (Ratio: %5$s Goal: %6$s)" ),
tr_strlsize( buf1, haveTotal, sizeof( buf1 ) ),
tr_strlsize( buf2, info->totalSize, sizeof( buf2 ) ),
tr_truncd( torStat->percentComplete * 100.0, 2 ),
tr_strlsize( buf3, torStat->uploadedEver, sizeof( buf3 ) ),
tr_strlratio( buf4, torStat->ratio, sizeof( buf4 ) ),
tr_strlratio( buf5, seedRatio, sizeof( buf5 ) ) );
tr_strlpercent( buf3, torStat->percentComplete * 100.0, sizeof( buf3 ) ),
tr_strlsize( buf4, torStat->uploadedEver, sizeof( buf4 ) ),
tr_strlratio( buf5, torStat->ratio, sizeof( buf5 ) ),
tr_strlratio( buf6, seedRatio, sizeof( buf6 ) ) );
}
else
{
str = g_strdup_printf(
/* %1$s is how much we've got,
%2$s is the torrent's total size,
%3$.2f%% is a percentage of the two,
%3$s%% is a percentage of the two,
%4$s is how much we've uploaded,
%5$s is our upload-to-download ratio */
_( "%1$s of %2$s (%3$.2f%%), uploaded %4$s (Ratio: %5$s)" ),
_( "%1$s of %2$s (%3$s%%), uploaded %4$s (Ratio: %5$s)" ),
tr_strlsize( buf1, haveTotal, sizeof( buf1 ) ),
tr_strlsize( buf2, info->totalSize, sizeof( buf2 ) ),
tr_truncd( torStat->percentComplete * 100.0, 2 ),
tr_strlsize( buf3, torStat->uploadedEver, sizeof( buf3 ) ),
tr_strlratio( buf4, torStat->ratio, sizeof( buf4 ) ) );
tr_strlpercent( buf3, torStat->percentComplete * 100.0, sizeof( buf3 ) ),
tr_strlsize( buf4, torStat->uploadedEver, sizeof( buf4 ) ),
tr_strlratio( buf5, torStat->ratio, sizeof( buf5 ) ) );
}
}
else /* seeding */

View File

@ -105,6 +105,12 @@ tr_strlratio( char * buf, double ratio, size_t buflen )
return tr_strratio( buf, buflen, ratio, gtr_get_unicode_string( GTR_UNICODE_INF ) );
}
char*
tr_strlpercent( char * buf, double x, size_t buflen )
{
return tr_strpercent( buf, x, buflen );
}
char*
tr_strlsize( char * buf, guint64 bytes, size_t buflen )
{

View File

@ -39,6 +39,8 @@ enum
};
const char * gtr_get_unicode_string( int );
/* return a percent formatted string of either x.xx, xx.x or xxx */
char* tr_strlpercent( char * buf, double x, size_t buflen );
/* return a human-readable string for the size given in bytes. */
char* tr_strlsize( char * buf, guint64 size, size_t buflen );

View File

@ -1364,6 +1364,18 @@ tr_truncd( double x, int decimal_places )
return x2 / i;
}
char*
tr_strpercent( char * buf, double x, size_t buflen )
{
if( x < 10.0 )
tr_strtruncd( buf, x, 2, buflen );
else if( x < 100.0 )
tr_strtruncd( buf, x, 1, buflen );
else
tr_strtruncd( buf, x, 0, buflen );
return buf;
}
char*
tr_strratio( char * buf, size_t buflen, double ratio, const char * infinity )
{
@ -1371,12 +1383,16 @@ tr_strratio( char * buf, size_t buflen, double ratio, const char * infinity )
tr_strlcpy( buf, _( "None" ), buflen );
else if( (int)ratio == TR_RATIO_INF )
tr_strlcpy( buf, infinity, buflen );
else if( ratio < 10.0 )
tr_snprintf( buf, buflen, "%.2f", tr_truncd( ratio, 2 ) );
else if( ratio < 100.0 )
tr_snprintf( buf, buflen, "%.1f", tr_truncd( ratio, 1 ) );
else
tr_snprintf( buf, buflen, "%'.0f", ratio );
tr_strpercent( buf, ratio, buflen );
return buf;
}
char*
tr_strtruncd( char * buf, double x, int precision, size_t buflen )
{
tr_snprintf( buf, buflen, "%.*f", precision, tr_truncd( x, precision ) );
return buf;
}

View File

@ -494,6 +494,9 @@ int* tr_parseNumberRange( const char * str,
*/
double tr_truncd( double x, int decimal_places );
/* return a percent formatted string of either x.xx, xx.x or xxx */
char* tr_strpercent( char * buf, double x, size_t buflen );
/**
* @param buf the buffer to write the string to
* @param buflef buf's size
@ -502,6 +505,9 @@ double tr_truncd( double x, int decimal_places );
*/
char* tr_strratio( char * buf, size_t buflen, double ratio, const char * infinity ) TR_GNUC_NONNULL(1,4);
/* return a truncated double as a string */
char* tr_strtruncd( char * buf, double x, int precision, size_t buflen );
/** @brief Portability wrapper for localtime_r() that uses the system implementation if available */
struct tm * tr_localtime_r( const time_t *_clock, struct tm *_result );

View File

@ -26,7 +26,6 @@
#include <QHBoxLayout>
#include <QHeaderView>
#include <QLabel>
#include <QLocale>
#include <QPushButton>
#include <QRadioButton>
#include <QResizeEvent>
@ -233,7 +232,6 @@ Details :: onTorrentChanged( )
void
Details :: refresh( )
{
QLocale locale;
const int n = myIds.size( );
const bool single = n == 1;
const QString blank;
@ -310,7 +308,7 @@ Details :: refresh( )
string = none;
else {
const double d = 100.0 * ( sizeWhenDone ? ( sizeWhenDone - leftUntilDone ) / sizeWhenDone : 1 );
QString pct = locale.toString( d, 'f', 2 );
QString pct = Utils::percentToString( d );
if( !haveUnverified )
string = tr( "%1 (%2%)" )
.arg( Utils :: sizeToString( haveVerified + haveUnverified ) )
@ -325,10 +323,14 @@ Details :: refresh( )
myHaveLabel->setText( string );
// myAvailabilityLabel
if( sizeWhenDone < 1 )
if( torrents.empty( ) )
string = none;
else
string.sprintf( "%'.1f%%", ( 100.0 * available ) / sizeWhenDone );
else {
if( sizeWhenDone == 0 )
string = none;
else
string = QString( "%1%" ).arg( Utils::percentToString( ( 100.0 * available ) / sizeWhenDone ) );
}
myAvailabilityLabel->setText( string );
// myDownloadedLabel
@ -859,7 +861,7 @@ Details :: refresh( )
item->setText( COL_UP, peer.rateToPeer.isZero() ? "" : Utils::speedToString( peer.rateToPeer ) );
item->setText( COL_DOWN, peer.rateToClient.isZero() ? "" : Utils::speedToString( peer.rateToClient ) );
item->setText( COL_PERCENT, peer.progress > 0 ? QString( "%1%" ).arg( locale.toString((int)(peer.progress*100.0))) : "" );
item->setText( COL_PERCENT, peer.progress > 0 ? QString( "%1%" ).arg( (int)( peer.progress * 100.0 ) ) : "" );
item->setText( COL_STATUS, code );
item->setToolTip( COL_STATUS, codeTip );

View File

@ -74,7 +74,7 @@ TorrentDelegate :: progressString( const Torrent& tor ) const
{
/* %1 is the percentage of torrent metadata downloaded */
str = tr( "Magnetized transfer - retrieving metadata (%1%)" )
.arg( tor.metadataPercentDone() * 100.0, 0, 'f', 2 );
.arg( Utils::percentToString( tor.metadataPercentDone() * 100.0 ) );
}
else if( !isDone ) // downloading
{
@ -83,7 +83,7 @@ TorrentDelegate :: progressString( const Torrent& tor ) const
%3 is a percentage of the two */
str = tr( "%1 of %2 (%3%)" ).arg( Utils::sizeToString( haveTotal ) )
.arg( Utils::sizeToString( tor.sizeWhenDone( ) ) )
.arg( tor.percentDone( ) * 100.0, 0, 'f', 2 );
.arg( Utils::percentToString( tor.percentDone( ) * 100.0 ) );
}
else if( !isSeed ) // partial seed
{
@ -98,7 +98,7 @@ TorrentDelegate :: progressString( const Torrent& tor ) const
str = tr( "%1 of %2 (%3%), uploaded %4 (Ratio: %5 Goal: %6)" )
.arg( Utils::sizeToString( haveTotal ) )
.arg( Utils::sizeToString( tor.totalSize( ) ) )
.arg( tor.percentComplete( ) * 100.0, 0, 'f', 2 )
.arg( Utils::percentToString( tor.percentComplete( ) * 100.0 ) )
.arg( Utils::sizeToString( tor.uploadedEver( ) ) )
.arg( Utils::ratioToString( tor.ratio( ) ) )
.arg( Utils::ratioToString( seedRatio ) );
@ -113,7 +113,7 @@ TorrentDelegate :: progressString( const Torrent& tor ) const
str = tr( "%1 of %2 (%3%), uploaded %4 (Ratio: %5)" )
.arg( Utils::sizeToString( haveTotal ) )
.arg( Utils::sizeToString( tor.totalSize( ) ) )
.arg( tor.percentComplete( ) * 100.0, 0, 'f', 2 )
.arg( Utils::percentToString( tor.percentComplete( ) * 100.0 ) )
.arg( Utils::sizeToString( tor.uploadedEver( ) ) )
.arg( Utils::ratioToString( tor.ratio( ) ) );
}
@ -190,7 +190,7 @@ TorrentDelegate :: shortStatusString( const Torrent& tor ) const
switch( tor.getActivity( ) )
{
case TR_STATUS_CHECK:
str = tr( "Verifying local data (%1% tested)" ).arg( tor.getVerifyProgress()*100.0, 0, 'f', 1 );
str = tr( "Verifying local data (%1% tested)" ).arg( Utils::percentToString( tor.getVerifyProgress()*100.0 ) );
break;
case TR_STATUS_DOWNLOAD:
@ -231,7 +231,7 @@ TorrentDelegate :: statusString( const Torrent& tor ) const
.arg( tor.peersWeAreDownloadingFrom( ) );
else
str = tr( "Downloading metadata from %n peer(s) (%1% done)", 0, tor.peersWeAreDownloadingFrom( ) )
.arg( int(100.0 * tor.metadataPercentDone( ) ) );
.arg( Utils::percentToString( 100.0 * tor.metadataPercentDone( ) ) );
break;
case TR_STATUS_SEED:

View File

@ -47,7 +47,7 @@ Utils :: remoteFileChooser( QWidget * parent, const QString& title, const QStrin
}
QString
Utils :: sizeToString( double bytes )
Utils :: sizeToString( double bytes )
{
if( !bytes )
return tr( "None" );
@ -70,34 +70,18 @@ Utils :: speedToString( const Speed& speed )
}
}
QString
Utils :: percentToString( double x )
{
char buf[128];
return QString( tr_strpercent( buf, x, sizeof(buf) ) );
}
QString
Utils :: ratioToString( double ratio )
{
QString buf;
if( (int)ratio == TR_RATIO_NA )
buf = tr( "None" );
else if( (int)ratio == TR_RATIO_INF )
buf = QString::fromUtf8( "\xE2\x88\x9E" );
else
{
QStringList temp;
temp = QString().sprintf( "%f", ratio ).split( "." );
if( ratio < 100.0 )
{
if( ratio < 10.0 )
temp[1].truncate( 2 );
else
temp[1].truncate( 1 );
buf = temp.join( "." );
}
else
buf = QString( temp[0] );
}
return buf;
char buf[128];
return QString::fromUtf8( tr_strratio( buf, sizeof(buf), ratio, "\xE2\x88\x9E" ) );
}
QString

View File

@ -30,6 +30,7 @@ class Utils: public QObject
static QString remoteFileChooser( QWidget * parent, const QString& title, const QString& myPath, bool dir, bool local );
static QString sizeToString( double bytes );
static QString speedToString( const Speed& speed );
static QString percentToString( double x );
static QString ratioToString( double ratio );
static QString timeToString( int seconds );
static const QIcon& guessMimeIcon( const QString& filename );

View File

@ -116,28 +116,43 @@ function setInnerHTML( e, html )
* @returns float
*/
Math.roundWithPrecision = function(floatnum, precision) {
return Math.round ( floatnum * Math.pow ( 10, precision ) ) / Math.pow ( 10, precision );
return Math.round( floatnum * Math.pow ( 10, precision ) ) / Math.pow( 10, precision );
};
/*
* Given a numerator and denominator, return a ratio string
*/
Math.ratio = function( numerator, denominator )
{
Math.ratio = function( numerator, denominator ) {
var result = Math.floor(100 * numerator / denominator) / 100;
// check for special cases
if (isNaN(result)) result = 0;
if (result=="Infinity") result = "&infin;";
// Add the decimals if this is an integer
if ((result % 1) == 0)
result = result + '.00';
if(result==Number.POSITIVE_INFINITY || result==Number.NEGATIVE_INFINITY) result = -2;
else if(isNaN(result)) result = -1;
return result;
};
/*
* Truncate a float to a specified number of decimal
* places, stripping trailing zeroes
*
* @param float floatnum
* @param integer precision
* @returns float
*/
Math.truncateWithPrecision = function(floatnum, precision) {
return Math.floor( floatnum * Math.pow ( 10, precision ) ) / Math.pow( 10, precision );
};
/*
* Round a string of a number to a specified number of decimal
* places
*/
Number.prototype.toTruncFixed = function( place ) {
var ret = Math.truncateWithPrecision( this, place );
return ret.toFixed( place );
}
/*
* Trim whitespace from a string
*/

View File

@ -18,6 +18,30 @@ Transmission.fmt = (function()
MODE_IEC: 1,
MODE_SI: 2,
/*
* Format a percentage to a string
*/
percentString: function( x ) {
if( x < 10.0 )
return x.toTruncFixed( 2 );
else if( x < 100.0 )
return x.toTruncFixed( 1 );
else
return x.toTruncFixed( 0 );
},
/*
* Format a ratio to a string
*/
ratioString: function( x ) {
if( x == -1 )
return "None";
else if( x == -2 )
return '&infin;';
else
return this.percentString( x );
},
setMode: function( mode ) {
if( mode == MODE_IEC ) {
this.KB_val = 1024;

View File

@ -246,8 +246,7 @@ Torrent.prototype =
return ( this._sizeWhenDone - this._leftUntilDone ) / this._sizeWhenDone;
},
getPercentDoneStr: function() {
return Math.floor(100 * Math.ratio( 100 * ( this._sizeWhenDone - this._leftUntilDone ),
this._sizeWhenDone )) / 100;
return Transmission.fmt.percentString( 100 * this.getPercentDone() );
},
size: function() { return this._size; },
state: function() { return this._state; },
@ -492,7 +491,7 @@ Torrent.prototype =
case Torrent._StatusChecking:
// 'Verifying local data (40% tested)'
c = 'Verifying local data (';
c += Math.roundWithPrecision( 100.0 * this._recheckProgress, 0 );
c += Transmission.fmt.percentString( 100.0 * this._recheckProgress );
c += '% tested)';
break;
}
@ -529,9 +528,9 @@ Torrent.prototype =
notDone = false ;
if( this.needsMetaData() ){
var metaPercentComplete = this._metadataPercentComplete * 1000 / 100
var metaPercentComplete = this._metadataPercentComplete * 100;
progress_details = "Magnetized transfer - retrieving metadata (";
progress_details += metaPercentComplete;
progress_details += Transmission.fmt.percentString( metaPercentComplete );
progress_details += "%)";
var empty = "";
@ -543,7 +542,6 @@ Torrent.prototype =
root._progress_incomplete_container.style.width = 100 - metaPercentComplete + "%"
root._progress_incomplete_container.className = 'torrent_progress_bar incomplete compact meta'+compact;
root._progress_incomplete_container.style.display = 'block';
}
else if( notDone )
{
@ -570,7 +568,7 @@ Torrent.prototype =
progress_details = c;
// Figure out the percent completed
var css_completed_width = Math.floor( this.getPercentDone() * 100 * MaxBarWidth ) / 100;
var css_completed_width = ( this.getPercentDone() * MaxBarWidth ).toTruncFixed( 2 );
// Update the 'in progress' bar
e = root._progress_complete_container;
@ -600,17 +598,26 @@ Torrent.prototype =
}
// Create the 'progress details' label
// Eg: '698.05 MiB, uploaded 8.59 GiB (Ratio: 12.3)'
c = Transmission.fmt.size( this._size );
// Partial seed
if( this._size != this._sizeWhenDone ) {
// Eg: '127.21 MiB of 698.05 MiB (18.2%)'
c = Transmission.fmt.size( this._sizeWhenDone );
c += ' of ';
c += Transmission.fmt.size( this._size );
c += ' (';
c += Transmission.fmt.percentString( 100.0 * this._sizeWhenDone / this._size );
c += '%)';
}
// Regular seed
else {
// Eg: '698.05 MiB'
c = Transmission.fmt.size( this._size );
}
// Eg:', uploaded 8.59 GiB (Ratio: 12.3)'
c += ', uploaded ';
c += Transmission.fmt.size( this._upload_total );
c += ' (Ratio ';
if(this._upload_ratio > -1)
c += Math.round(this._upload_ratio*100)/100;
else if(this._upload_ratio == -2)
c += 'Inf';
else
c += '0';
c += Transmission.fmt.ratioString( this._upload_ratio );
c += ')';
c += eta;
progress_details = c;
@ -961,7 +968,7 @@ TorrentFile.prototype = {
c += ' of ';
c += Transmission.fmt.size(this._size);
c += ' (';
c += Math.ratio(100 * this._done, this._size);
c += this._size ? Transmission.fmt.percentString(100 * this._done / this._size) : '100';
c += '%)';
setInnerHTML(this._progress[0], c);
},

View File

@ -1004,12 +1004,12 @@ Transmission.prototype =
setInnerHTML( $('#stats_session_uploaded')[0], Transmission.fmt.size(session["uploadedBytes"]) );
setInnerHTML( $('#stats_session_downloaded')[0], Transmission.fmt.size(session["downloadedBytes"]) );
setInnerHTML( $('#stats_session_ratio')[0], Math.ratio(session["uploadedBytes"],session["downloadedBytes"]));
setInnerHTML( $('#stats_session_ratio')[0], Transmission.fmt.ratioString(Math.ratio(session["uploadedBytes"],session["downloadedBytes"])));
setInnerHTML( $('#stats_session_duration')[0], Transmission.fmt.timeInterval(session["secondsActive"]) );
setInnerHTML( $('#stats_total_count')[0], total["sessionCount"] + " times" );
setInnerHTML( $('#stats_total_uploaded')[0], Transmission.fmt.size(total["uploadedBytes"]) );
setInnerHTML( $('#stats_total_downloaded')[0], Transmission.fmt.size(total["downloadedBytes"]) );
setInnerHTML( $('#stats_total_ratio')[0], Math.ratio(total["uploadedBytes"],total["downloadedBytes"]));
setInnerHTML( $('#stats_total_ratio')[0], Transmission.fmt.ratioString(Math.ratio(total["uploadedBytes"],total["downloadedBytes"])));
setInnerHTML( $('#stats_total_duration')[0], Transmission.fmt.timeInterval(total["secondsActive"]) );
},
@ -1267,14 +1267,14 @@ Transmission.prototype =
setInnerHTML( tab.upload_speed, torrents.length ? Transmission.fmt.speed( total_upload_speed ) : na );
setInnerHTML( tab.uploaded, torrents.length ? Transmission.fmt.size( total_upload ) : na );
setInnerHTML( tab.downloaded, torrents.length ? Transmission.fmt.size( total_download ) : na );
setInnerHTML( tab.availability, torrents.length ? Math.ratio( total_availability*100, sizeWhenDone ) + '%' : na );
setInnerHTML( tab.ratio, torrents.length ? Math.ratio( total_upload, total_download ) : na );
setInnerHTML( tab.availability, torrents.length ? Transmission.fmt.percentString(Math.ratio( total_availability*100, sizeWhenDone )) + '%' : na );
setInnerHTML( tab.ratio, torrents.length ? Transmission.fmt.ratioString(Math.ratio( total_upload, total_download )) : na );
setInnerHTML( tab.have, torrents.length ? Transmission.fmt.size(total_completed) + ' (' + Transmission.fmt.size(total_verified) + ' verified)' : na );
setInnerHTML( tab.upload_to, torrents.length ? total_upload_peers : na );
setInnerHTML( tab.download_from, torrents.length ? total_download_peers : na );
setInnerHTML( tab.secure, private_string );
setInnerHTML( tab.creator_date, date_created );
setInnerHTML( tab.progress, torrents.length ? Math.ratio( sizeDone*100, sizeWhenDone ) + '%' : na );
setInnerHTML( tab.progress, torrents.length ? Transmission.fmt.percentString(Math.ratio( sizeDone*100, sizeWhenDone )) + '%' : na );
setInnerHTML( tab.comment, comment == na ? comment : comment.replace(/\//g, '/&#8203;') );
setInnerHTML( tab.creator, creator );
setInnerHTML( tab.download_dir, download_dir == na ? download_dir : download_dir.replace(/([\/_\.])/g, "$1&#8203;") );