Add support for IEC and SI size units to wxFileName::GetHumanReadableSize().

Allow choosing the multiplier to use (1000 or 1024) and the names of the units
(SI or IEC). By default, still use traditional convention, i.e. multiplier of
1024 but SI unit names. This will probably need to be changed to use IEC units
in the future.

Also added unit test for this function.

Closes #10673.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@63870 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2010-04-06 14:53:04 +00:00
parent 2028c33ab5
commit b2edb8f3c5
5 changed files with 151 additions and 44 deletions

View File

@ -438,6 +438,7 @@ All:
- Correct bugs when using wxTextInputStream with wxConvAuto (Leon Buikstra).
- Don't crash when input is empty in wxFileConfig ctor (Lukasz Michalski).
- Correct wxSocket::Peek() to not block (Anders Larsen).
- Added IEC and SI units support to GetHumanReadableSize() (Julien Weinzorn).
Unix:

View File

@ -65,6 +65,15 @@ enum wxPathFormat
wxPATH_MAX // Not a valid value for specifying path format
};
// different convention that may be used with GetHumanReadableSize()
enum wxSizeConvention
{
wxSIZE_CONV_TRADIONAL, // 1024 bytes = 1 KB
wxSIZE_CONV_IEC, // 1024 bytes = 1 KiB
wxSIZE_CONV_SI // 1000 bytes = 1 KB
};
// the kind of normalization to do with the file name: these values can be
// or'd together to perform several operations at once
enum wxPathNormalize
@ -540,11 +549,15 @@ public:
static wxULongLong GetSize(const wxString &file);
// returns the size in a human readable form
wxString GetHumanReadableSize(const wxString &nullsize = wxGetTranslation(wxT("Not available")),
int precision = 1) const;
static wxString GetHumanReadableSize(const wxULongLong &sz,
const wxString &nullsize = wxGetTranslation(wxT("Not available")),
int precision = 1);
wxString
GetHumanReadableSize(const wxString& nullsize = _("Not available"),
int precision = 1,
wxSizeConvention conv = wxSIZE_CONV_TRADIONAL) const;
static wxString
GetHumanReadableSize(const wxULongLong& sz,
const wxString& nullsize = _("Not available"),
int precision = 1,
wxSizeConvention conv = wxSIZE_CONV_TRADIONAL);
#endif // wxUSE_LONGLONG

View File

@ -28,6 +28,25 @@ enum wxPathFormat
wxPATH_MAX //!< Not a valid value for specifying path format
};
/**
Different conventions for human readable sizes.
@see wxFileName::GetHumanReadableSize().
@since 2.9.1
*/
enum wxSizeConvention
{
/// 1000 bytes = 1KiB.
wxSIZE_CONV_REAL_SI,
/// 1000 bytes = 1KB.
wxSIZE_CONV_TRAD_1000,
/// 1024 bytes = 1KB.
wxSIZE_CONV_TRAD_1024
};
/**
The kind of normalization to do with the file name: these values can be
@ -522,30 +541,41 @@ public:
*/
static wxString GetHomeDir();
//@{
/**
Returns the size of the file in a human-readable form.
Returns the representation of the file size in a human-readable form.
If the size could not be retrieved the @c failmsg string
is returned. In case of success, the returned string is
a floating-point number with @c precision decimal digits
followed by the size unit (B, kB, MB, GB, TB: respectively
bytes, kilobytes, megabytes, gigabytes, terabytes).
In the first version, the size of this file is used. In the second one,
the specified size @a bytes is used.
If the file size could not be retrieved or @a bytes is ::wxInvalidSize
or zero, the @c failmsg string is returned.
Otherwise the returned string is a floating-point number with @c
precision decimal digits followed by the abbreviation of the unit used.
By default the traditional, although incorrect, convention of using SI
units for multiples of 1024 is used, i.e. returned string will use
suffixes of B, KB, MB, GB, TB for bytes, kilobytes, megabytes,
gigabytes and terabytes respectively. With the IEC convention the names
of the units are changed to B, KiB, MiB, GiB and TiB fofr bytes,
kibibytes, mebibyes, gibibytes and tebibytes. Finally, with SI
convention the same B, KB, MB, GB and TB suffixes are used but in their
correct SI meaning, i.e. as multiples of 1000 and not 1024.
Support for the different size conventions is new in wxWidgets 2.9.1,
in previous versions only the traditional convention was implemented.
*/
wxString GetHumanReadableSize(const wxString& failmsg = "Not available",
int precision = 1) const;
wxString
GetHumanReadableSize(const wxString& failmsg = _("Not available"),
int precision = 1,
wxSizeConvention conv = wxSIZE_CONV_TRADIONAL) const;
/**
Returns the size of the given number of bytes in a human-readable form.
If @a bytes is ::wxInvalidSize or zero, then @a nullsize is returned.
In case of success, the returned string is a floating-point number with
@a precision decimal digits followed by the size unit (B, kB, MB, GB,
TB: respectively bytes, kilobytes, megabytes, gigabytes, terabytes).
*/
static wxString GetHumanReadableSize(const wxULongLong& bytes,
const wxString& nullsize = "Not available",
int precision = 1);
static wxString
GetHumanReadableSize(const wxULongLong& bytes,
const wxString& nullsize = _("Not available"),
int precision = 1,
wxSizeConvention conv = wxSIZE_CONV_REAL_SI);
//@}
/**
Return the long form of the path (returns identity on non-Windows platforms).

View File

@ -2647,27 +2647,53 @@ wxULongLong wxFileName::GetSize(const wxString &filename)
/* static */
wxString wxFileName::GetHumanReadableSize(const wxULongLong &bs,
const wxString &nullsize,
int precision)
int precision,
wxSizeConvention conv)
{
static const double KILOBYTESIZE = 1024.0;
static const double MEGABYTESIZE = 1024.0*KILOBYTESIZE;
static const double GIGABYTESIZE = 1024.0*MEGABYTESIZE;
static const double TERABYTESIZE = 1024.0*GIGABYTESIZE;
if (bs == 0 || bs == wxInvalidSize)
// deal with trivial case first
if ( bs == 0 || bs == wxInvalidSize )
return nullsize;
double bytesize = bs.ToDouble();
if (bytesize < KILOBYTESIZE)
return wxString::Format(_("%s B"), bs.ToString().c_str());
if (bytesize < MEGABYTESIZE)
return wxString::Format(_("%.*f kB"), precision, bytesize/KILOBYTESIZE);
if (bytesize < GIGABYTESIZE)
return wxString::Format(_("%.*f MB"), precision, bytesize/MEGABYTESIZE);
if (bytesize < TERABYTESIZE)
return wxString::Format(_("%.*f GB"), precision, bytesize/GIGABYTESIZE);
// depending on the convention used the multiplier may be either 1000 or
// 1024 and the binary infix may be empty (for "KB") or "i" (for "KiB")
double multiplier;
wxString biInfix;
return wxString::Format(_("%.*f TB"), precision, bytesize/TERABYTESIZE);
switch ( conv )
{
case wxSIZE_CONV_IEC:
biInfix = "i";
// fall through
case wxSIZE_CONV_TRADIONAL:
multiplier = 1024.;
break;
case wxSIZE_CONV_SI:
multiplier = 1000;
break;
}
const double kiloByteSize = multiplier;
const double megaByteSize = multiplier * kiloByteSize;
const double gigaByteSize = multiplier * megaByteSize;
const double teraByteSize = multiplier * gigaByteSize;
const double bytesize = bs.ToDouble();
wxString result;
if ( bytesize < kiloByteSize )
result.Printf("%s B", bs.ToString());
else if ( bytesize < megaByteSize )
result.Printf("%.*f K%sB", precision, bytesize/kiloByteSize, biInfix);
else if (bytesize < gigaByteSize)
result.Printf("%.*f M%sB", precision, bytesize/megaByteSize, biInfix);
else if (bytesize < teraByteSize)
result.Printf("%.*f G%sB", precision, bytesize/gigaByteSize, biInfix);
else
result.Printf("%.*f T%sB", precision, bytesize/teraByteSize, biInfix);
return result;
}
wxULongLong wxFileName::GetSize() const
@ -2675,9 +2701,11 @@ wxULongLong wxFileName::GetSize() const
return GetSize(GetFullPath());
}
wxString wxFileName::GetHumanReadableSize(const wxString &failmsg, int precision) const
wxString wxFileName::GetHumanReadableSize(const wxString& failmsg,
int precision,
wxSizeConvention conv) const
{
return GetHumanReadableSize(GetSize(), failmsg, precision);
return GetHumanReadableSize(GetSize(), failmsg, precision, conv);
}
#endif // wxUSE_LONGLONG

View File

@ -125,6 +125,7 @@ private:
CPPUNIT_TEST( TestStrip );
CPPUNIT_TEST( TestNormalize );
CPPUNIT_TEST( TestReplace );
CPPUNIT_TEST( TestGetHumanReadable );
#ifdef __WINDOWS__
CPPUNIT_TEST( TestShortLongPath );
#endif // __WINDOWS__
@ -139,6 +140,7 @@ private:
void TestStrip();
void TestNormalize();
void TestReplace();
void TestGetHumanReadable();
#ifdef __WINDOWS__
void TestShortLongPath();
#endif // __WINDOWS__
@ -478,6 +480,39 @@ void FileNameTestCase::TestReplace()
fn.GetFullPath(wxPATH_UNIX) );
}
void FileNameTestCase::TestGetHumanReadable()
{
static const struct TestData
{
const char *result;
wxULongLong size;
int prec;
wxSizeConvention conv;
} testData[] =
{
{ "NA", 0, 1, wxSIZE_CONV_TRADIONAL },
{ "2.0 KB", 2000, 1, wxSIZE_CONV_TRADIONAL },
{ "1.953 KiB", 2000, 3, wxSIZE_CONV_IEC },
{ "2.000 KB", 2000, 3, wxSIZE_CONV_SI },
{ "297 KB", 304351, 0, wxSIZE_CONV_TRADIONAL },
{ "304 KB", 304351, 0, wxSIZE_CONV_SI },
};
for ( unsigned n = 0; n < WXSIZEOF(testData); n++ )
{
const TestData& td = testData[n];
CPPUNIT_ASSERT_EQUAL
(
td.result,
wxFileName::GetHumanReadableSize(td.size, "NA", td.prec, td.conv)
);
}
// also test the default convention value
CPPUNIT_ASSERT_EQUAL( "1.4 MB", wxFileName::GetHumanReadableSize(1512993, "") );
}
void FileNameTestCase::TestStrip()
{
CPPUNIT_ASSERT_EQUAL( "", wxFileName::StripExtension("") );