BColumnListView: use automatic formatting for i18n

Use BDateTimeFormat, BDateFormat, and BNumberFormat for
various date, time, decimal, and percent formatting.

Change-Id: I994563d207db8bd28342ca6543b69a356ced38af
Reviewed-on: https://review.haiku-os.org/c/haiku/+/7505
Tested-by: Commit checker robot <[email protected]>
Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
Emir SARI
2024-03-31 08:33:21 +00:00
committed by Adrien Destugues
parent f42b1cb118
commit 058be77bec
2 changed files with 93 additions and 91 deletions
+10 -2
View File
@@ -16,9 +16,12 @@
#include "ColumnListView.h" #include "ColumnListView.h"
#include <String.h>
#include <Font.h>
#include <Bitmap.h> #include <Bitmap.h>
#include <DateFormat.h>
#include <DateTimeFormat.h>
#include <Font.h>
#include <NumberFormat.h>
#include <String.h>
//===================================================================== //=====================================================================
@@ -40,6 +43,9 @@ public:
virtual float GetPreferredWidth(BField* field, BView* parent) const; virtual float GetPreferredWidth(BField* field, BView* parent) const;
protected:
BNumberFormat fNumberFormat;
private: private:
float fFontHeight; float fFontHeight;
BString fTitle; BString fTitle;
@@ -122,6 +128,8 @@ public:
virtual int CompareFields(BField* field1, BField* field2); virtual int CompareFields(BField* field1, BField* field2);
private: private:
BDateTimeFormat fDateTimeFormat;
BDateFormat fDateFormat;
BString fTitle; BString fTitle;
}; };
+83 -89
View File
@@ -6,34 +6,29 @@
/ data types for use in BColumnListView. / data types for use in BColumnListView.
/ /
/ Copyright 2000+, Be Incorporated, All Rights Reserved / Copyright 2000+, Be Incorporated, All Rights Reserved
/ Copyright 2024, Haiku, Inc. All Rights Reserved
/ /
*******************************************************************************/ *******************************************************************************/
#include "ColumnTypes.h" #include "ColumnTypes.h"
#include <StringFormat.h>
#include <SystemCatalog.h>
#include <View.h> #include <View.h>
#include <parsedate.h>
#include <stdio.h> #include <stdio.h>
using BPrivate::gSystemCatalog;
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "ColumnTypes"
#define kTEXT_MARGIN 8 #define kTEXT_MARGIN 8
const int64 kKB_SIZE = 1024;
const int64 kMB_SIZE = 1048576;
const int64 kGB_SIZE = 1073741824;
const int64 kTB_SIZE = kGB_SIZE * kKB_SIZE;
const char* kSIZE_FORMATS[] = {
"%.2f %s",
"%.1f %s",
"%.f %s",
"%.f%s",
0
};
BTitledColumn::BTitledColumn(const char* title, float width, float minWidth, BTitledColumn::BTitledColumn(const char* title, float width, float minWidth,
float maxWidth, alignment align) float maxWidth, alignment align)
: :
@@ -320,17 +315,6 @@ BDateColumn::BDateColumn(const char* title, float width, float minWidth,
} }
const char *kTIME_FORMATS[] = {
"%A, %B %d %Y, %I:%M:%S %p", // Monday, July 09 1997, 05:08:15 PM
"%a, %b %d %Y, %I:%M:%S %p", // Mon, Jul 09 1997, 05:08:15 PM
"%a, %b %d %Y, %I:%M %p", // Mon, Jul 09 1997, 05:08 PM
"%b %d %Y, %I:%M %p", // Jul 09 1997, 05:08 PM
"%m/%d/%y, %I:%M %p", // 07/09/97, 05:08 PM
"%m/%d/%y", // 07/09/97
NULL
};
void void
BDateColumn::DrawField(BField* _field, BRect rect, BView* parent) BDateColumn::DrawField(BField* _field, BRect rect, BView* parent)
{ {
@@ -346,15 +330,28 @@ BDateColumn::DrawField(BField* _field, BRect rect, BView* parent)
parent->GetFont(&font); parent->GetFont(&font);
localtime_r(&currentTime, &time_data); localtime_r(&currentTime, &time_data);
for (int32 index = 0; ; index++) { // dateStyles[] and timeStyles[] must be the same length
if (!kTIME_FORMATS[index]) const BDateFormatStyle dateStyles[] = {
break; B_FULL_DATE_FORMAT, B_FULL_DATE_FORMAT, B_LONG_DATE_FORMAT, B_LONG_DATE_FORMAT,
B_MEDIUM_DATE_FORMAT, B_SHORT_DATE_FORMAT,
};
strftime(dateString, 256, kTIME_FORMATS[index], &time_data); const BTimeFormatStyle timeStyles[] = {
if (font.StringWidth(dateString) <= width) B_MEDIUM_TIME_FORMAT, B_SHORT_TIME_FORMAT, B_MEDIUM_TIME_FORMAT, B_SHORT_TIME_FORMAT,
B_SHORT_TIME_FORMAT, B_SHORT_TIME_FORMAT,
};
size_t index;
for (index = 0; index < B_COUNT_OF(dateStyles); index++) {
ssize_t output = fDateTimeFormat.Format(dateString, sizeof(dateString), currentTime,
dateStyles[index], timeStyles[index]);
if (output >= 0 && font.StringWidth(dateString) <= width)
break; break;
} }
if (index == B_COUNT_OF(dateStyles))
fDateFormat.Format(dateString, sizeof(dateString), currentTime, B_SHORT_DATE_FORMAT);
if (font.StringWidth(dateString) > width) { if (font.StringWidth(dateString) > width) {
BString out_string(dateString); BString out_string(dateString);
@@ -414,58 +411,55 @@ BSizeColumn::BSizeColumn(const char* title, float width, float minWidth,
void void
BSizeColumn::DrawField(BField* _field, BRect rect, BView* parent) BSizeColumn::DrawField(BField* _field, BRect rect, BView* parent)
{ {
char str[256];
float width = rect.Width() - (2 * kTEXT_MARGIN);
BFont font; BFont font;
BString printedSize;
BString string; BString string;
off_t size = ((BSizeField*)_field)->Size();
float width = rect.Width() - (2 * kTEXT_MARGIN);
double value = ((BSizeField*)_field)->Size() / 1024.0;
parent->GetFont(&font); parent->GetFont(&font);
if (size < kKB_SIZE) { // we cannot use string_for_size due to the precision/cell width logic
sprintf(str, "%" B_PRId64 " bytes", size); if (value < 1024.0) {
if (font.StringWidth(str) > width) BStringFormat format(B_TRANSLATE_MARK_ALL("{0, plural, one{# byte} other{# bytes}}",
sprintf(str, "%" B_PRId64 " B", size); B_TRANSLATION_CONTEXT, "unit size"));
format.Format(printedSize, value);
string = gSystemCatalog.GetString(printedSize, B_TRANSLATION_CONTEXT, "unit size");
if (font.StringWidth(string) > width) {
BString tmp = B_TRANSLATE_MARK_ALL("%s B", B_TRANSLATION_CONTEXT, "unit size");
fNumberFormat.Format(printedSize, value);
string.SetToFormat(gSystemCatalog.GetString(tmp, B_TRANSLATION_CONTEXT, "unit size"),
printedSize.String());
}
} else { } else {
const char* suffix; const char* kFormats[] = {
float float_value; B_TRANSLATE_MARK_ALL("%s KiB", B_TRANSLATION_CONTEXT, "unit size"),
if (size >= kTB_SIZE) { B_TRANSLATE_MARK_ALL("%s MiB", B_TRANSLATION_CONTEXT, "unit size"),
suffix = "TB"; B_TRANSLATE_MARK_ALL("%s GiB", B_TRANSLATION_CONTEXT, "unit size"),
float_value = (float)size / kTB_SIZE; B_TRANSLATE_MARK_ALL("%s TiB", B_TRANSLATION_CONTEXT, "unit size")
} else if (size >= kGB_SIZE) { };
suffix = "GB";
float_value = (float)size / kGB_SIZE; size_t index = 0;
} else if (size >= kMB_SIZE) { while (index < B_COUNT_OF(kFormats) && value >= 1024.0) {
suffix = "MB"; value /= 1024.0;
float_value = (float)size / kMB_SIZE; index++;
} else {
suffix = "KB";
float_value = (float)size / kKB_SIZE;
} }
for (int32 index = 0; ; index++) { int precision = 2;
if (!kSIZE_FORMATS[index]) while (precision >= 0) {
double formattedSize = value;
fNumberFormat.SetPrecision(precision);
fNumberFormat.Format(printedSize, formattedSize);
string.SetToFormat(
gSystemCatalog.GetString(kFormats[index], B_TRANSLATION_CONTEXT, "unit size"),
printedSize.String());
if (font.StringWidth(string) <= width)
break; break;
sprintf(str, kSIZE_FORMATS[index], float_value, suffix); precision--;
// strip off an insignificant zero so we don't get readings
// such as 1.00
char *period = 0;
char *tmp (NULL);
for (tmp = str; *tmp; tmp++) {
if (*tmp == '.')
period = tmp;
}
if (period && period[1] && period[2] == '0') {
// move the rest of the string over the insignificant zero
for (tmp = &period[2]; *tmp; tmp++)
*tmp = tmp[1];
}
if (font.StringWidth(str) <= width)
break;
} }
} }
string = str;
parent->TruncateString(&string, B_TRUNCATE_MIDDLE, width + 2); parent->TruncateString(&string, B_TRUNCATE_MIDDLE, width + 2);
DrawString(string.String(), parent, rect); DrawString(string.String(), parent, rect);
} }
@@ -521,13 +515,10 @@ BIntegerColumn::BIntegerColumn(const char* title, float width, float minWidth,
void void
BIntegerColumn::DrawField(BField *field, BRect rect, BView* parent) BIntegerColumn::DrawField(BField *field, BRect rect, BView* parent)
{ {
char formatted[256];
float width = rect.Width() - (2 * kTEXT_MARGIN);
BString string; BString string;
sprintf(formatted, "%d", (int)((BIntegerField*)field)->Value()); fNumberFormat.Format(string, (int32)((BIntegerField*)field)->Value());
float width = rect.Width() - (2 * kTEXT_MARGIN);
string = formatted;
parent->TruncateString(&string, B_TRUNCATE_MIDDLE, width + 2); parent->TruncateString(&string, B_TRUNCATE_MIDDLE, width + 2);
DrawString(string.String(), parent, rect); DrawString(string.String(), parent, rect);
} }
@@ -554,32 +545,35 @@ GraphColumn::GraphColumn(const char* name, float width, float minWidth,
void void
GraphColumn::DrawField(BField* field, BRect rect, BView* parent) GraphColumn::DrawField(BField* field, BRect rect, BView* parent)
{ {
int number = ((BIntegerField*)field)->Value(); double fieldValue = ((BIntegerField*)field)->Value();
double percentValue = fieldValue / 100.0;
if (number > 100) if (percentValue > 1.0)
number = 100; percentValue = 1.0;
else if (number < 0) else if (percentValue < 0.0)
number = 0; percentValue = 0.0;
BRect graphRect(rect); BRect graphRect(rect);
graphRect.InsetBy(5, 3); graphRect.InsetBy(5, 3);
parent->StrokeRect(graphRect); parent->StrokeRoundRect(graphRect, 2.5, 2.5);
if (number > 0) {
if (percentValue > 0.0) {
graphRect.InsetBy(1, 1); graphRect.InsetBy(1, 1);
float value = graphRect.Width() * (float)number / 100; double value = graphRect.Width() * percentValue;
graphRect.right = graphRect.left + value; graphRect.right = graphRect.left + value;
parent->SetHighColor(0, 0, 190); parent->SetHighUIColor(B_NAVIGATION_BASE_COLOR);
parent->FillRect(graphRect); parent->FillRect(graphRect);
} }
parent->SetDrawingMode(B_OP_INVERT); parent->SetDrawingMode(B_OP_INVERT);
parent->SetHighColor(128, 128, 128); parent->SetHighColor(128, 128, 128);
char numberString[256];
sprintf(numberString, "%d%%", number);
float width = be_plain_font->StringWidth(numberString); BString percentString;
fNumberFormat.FormatPercent(percentString, percentValue);
float width = be_plain_font->StringWidth(percentString);
parent->MovePenTo(rect.left + rect.Width() / 2 - width / 2, rect.bottom - FontHeight()); parent->MovePenTo(rect.left + rect.Width() / 2 - width / 2, rect.bottom - FontHeight());
parent->DrawString(numberString); parent->DrawString(percentString.String());
} }