From 061b45a785cc8dc9cad97455dc143de365a1f26c Mon Sep 17 00:00:00 2001 From: Johan Wagenheim Date: Tue, 4 Jun 2024 02:10:55 -0400 Subject: [PATCH] Use locale kit for number formatting --- locales/en.catkeys | 10 +-- src/Account.cpp | 6 +- src/Account.h | 7 -- src/AccountSettingsWindow.cpp | 13 ++- src/BudgetWindow.cpp | 23 ++--- src/BudgetWindow.h | 1 + src/CBLocale.h | 27 +----- src/Database.cpp | 117 +++++-------------------- src/Database.h | 1 - src/Locale.cpp | 155 ++++++++++++---------------------- src/PrefWindow.cpp | 118 ++++++-------------------- src/PrefWindow.h | 13 +-- src/QuickTrackerItem.cpp | 8 +- 13 files changed, 135 insertions(+), 364 deletions(-) diff --git a/locales/en.catkeys b/locales/en.catkeys index 6b57c41..47aba0d 100644 --- a/locales/en.catkeys +++ b/locales/en.catkeys @@ -1,4 +1,4 @@ -1 English application/x-vnd.wgp-CapitalBe 3882412825 +1 English application/x-vnd.wgp-CapitalBe 1546978192 Year ReportWindow Year None ReportWindow None Export to QIF file… MainWindow Export to QIF file… @@ -25,7 +25,6 @@ Import from QIF file… MainWindow Import from QIF file… Preview: PrefWindow Preview: Ending date: ReportWindow Ending date: Scheduled transactions MainWindow Scheduled transactions -Separator: PrefWindow Separator: Closed account: PrefWindow Closed account: Help: Report ReportWindow Help: Report Bank charges ReconcileWindow Bank charges @@ -50,6 +49,7 @@ Highest BudgetWindow Highest You need to have at least 2 accounts to perform a transfer. MainWindow You need to have at least 2 accounts to perform a transfer. Monthly ScheduleListWindow Monthly Frequency BudgetWindow Frequency +Decimals: PrefWindow Decimals: CapitalBe didn't understand the amount for 'Bank charges' ReconcileWindow CapitalBe didn't understand the amount for 'Bank charges' You need to enter a check number or transaction type, such as ATM (for debit card transactions and the like), DEP (for deposits), or your own code for some other kind of expense. CheckView You need to enter a check number or transaction type, such as ATM (for debit card transactions and the like), DEP (for deposits), or your own code for some other kind of expense. Uncategorized SplitView Uncategorized @@ -70,8 +70,8 @@ Interest earned ReconcileWindow Interest earned Quit Locale Quit Once deleted, you will not be able to get back any data on this account. MainWindow Once deleted, you will not be able to get back any data on this account. Add category CategoryWindow Add category +Use system currency format Account Use system currency format Could not export your financial data to the file '%%FILENAME%%' MainWindow Could not export your financial data to the file '%%FILENAME%%' -Currency format: PrefWindow Currency format: Name: Account Name: Total deposits: %s ReconcileWindow Total deposits: %s Memo CommonTerms Memo @@ -160,7 +160,6 @@ Total checks: ReconcileWindow Total checks: Remove item SplitView Remove item Transaction MainWindow Transaction Edit transfer TransferWindow Edit transfer -Default account settings PrefWindow Default account settings Reports MainWindow Reports Categories CategoryWindow Categories Account MainWindow Account @@ -169,6 +168,7 @@ Unselected: PrefWindow Unselected: Total deposits: ReconcileWindow Total deposits: Categories… MainWindow Categories… Help: Budget BudgetWindow Help: Budget +Currency format PrefWindow Currency format Payee CommonTerms Payee If you intend to transfer money, it will need to be an amount that is not zero. TransferWindow If you intend to transfer money, it will need to be an amount that is not zero. You can schedule transfers, deposits, or ATM transactions. MainWindow You can schedule transfers, deposits, or ATM transactions. @@ -208,7 +208,6 @@ Starting date: ReportWindow Starting date: Starting balance ReconcileWindow Starting balance Quarterly ScheduleAddWindow Quarterly Reconcile: ReconcileWindow Reconcile: -Use default currency settings Account Use default currency settings Total charges: ReconcileWindow Total charges: Total worth ReportWindow Total worth Expense CashFlowReport Expense @@ -228,7 +227,6 @@ Total checks: %s ReconcileWindow Total checks: %s Quarterly BudgetWindow Quarterly Remove category CategoryWindow Remove category You cannot schedule transactions on a closed account. MainWindow You cannot schedule transactions on a closed account. -Decimal: PrefWindow Decimal: CapitalBe didn't understand the amount for 'Interest earned' ReconcileWindow CapitalBe didn't understand the amount for 'Interest earned' Date is missing ReconcileWindow Date is missing Unknown ScheduleListWindow Unknown diff --git a/src/Account.cpp b/src/Account.cpp index f77b6af..9054e21 100644 --- a/src/Account.cpp +++ b/src/Account.cpp @@ -322,14 +322,12 @@ Account::UseDefaultLocale(const bool& usedefault) BString command; if (fUseDefaultLocale) { - command = "delete from accountlocale where accountid = "; - command << fID << ";"; + command << "DELETE FROM accountlocale WHERE accountid = " << fID << ";"; gDatabase.DBCommand(command.String(), "Account::UseDefaultLocale"); gCurrentLocale = gDefaultLocale; } else { // update the local copy in case it changed since the program was opened - fLocale = gDefaultLocale; - + fLocale = gCurrentLocale; gDatabase.SetAccountLocale(fID, fLocale); } diff --git a/src/Account.h b/src/Account.h index a610f4d..9e947a6 100644 --- a/src/Account.h +++ b/src/Account.h @@ -20,25 +20,19 @@ class Account : public Notifier { ~Account(void); void SetName(const char* name); - const char* Name(void) const { return fName.String(); } void SetID(const time_t& id) { fID = id; } - uint32 GetID(void) const { return fID; } void SetClosed(const bool& value) { fClosed = value; } - bool IsClosed(void) const { return fClosed; } uint32 CurrentTransaction(void) const { return fCurrentTransaction; } - bool SetCurrentTransaction(const uint32& id); uint16 LastCheckNumber(void) const { return fLastCheckNumber; } - uint16 LookupLastCheckNumber(void); - void SetLastCheckNumber(const uint16& value) { fLastCheckNumber = value; } BString AutocompleteCategory(const char* input); @@ -58,7 +52,6 @@ class Account : public Notifier { void (*TransactionIteratorFunc)(const TransactionData&, void*), void* ptr); void UseDefaultLocale(const bool& usedefault); - bool IsUsingDefaultLocale(void) const { return fUseDefaultLocale; } private: diff --git a/src/AccountSettingsWindow.cpp b/src/AccountSettingsWindow.cpp index 089a926..fd73bac 100644 --- a/src/AccountSettingsWindow.cpp +++ b/src/AccountSettingsWindow.cpp @@ -8,7 +8,6 @@ #include "Database.h" #include "PrefWindow.h" - #undef B_TRANSLATION_CONTEXT #define B_TRANSLATION_CONTEXT "Account" @@ -35,7 +34,7 @@ AccountSettingsWindow::AccountSettingsWindow(Account* account) (fAccount ? fAccount->Name() : NULL), new BMessage(M_NAME_CHANGED)); fAccountName->SetCharacterLimit(32); - fUseDefault = new BCheckBox("usedefault", B_TRANSLATE("Use default currency settings"), + fUseDefault = new BCheckBox("usedefault", B_TRANSLATE("Use system currency format"), new BMessage(M_TOGGLE_USE_DEFAULT)); if (!fAccount || fAccount->IsUsingDefaultLocale()) fUseDefault->SetValue(B_CONTROL_ON); @@ -55,9 +54,9 @@ AccountSettingsWindow::AccountSettingsWindow(Account* account) SetDefaultButton(fOK); - if (!fAccount || fAccount->IsUsingDefaultLocale()) { + if (!fAccount || fAccount->IsUsingDefaultLocale()) fPrefView->Hide(); - } + // clang-format off BLayoutBuilder::Group<>(this, B_VERTICAL, B_USE_DEFAULT_SPACING) .SetInsets(B_USE_DEFAULT_SPACING) @@ -86,17 +85,15 @@ AccountSettingsWindow::MessageReceived(BMessage* msg) case M_EDIT_ACCOUNT_SETTINGS: { Locale customLocale; - Locale defaultLocale; + fPrefView->GetSettings(customLocale); if (!fAccount) { - fPrefView->GetSettings(customLocale); gDatabase.AddAccount(fAccountName->Text(), ACCOUNT_BANK, "Open", - defaultLocale == customLocale ? NULL : &customLocale); + fUseDefault->Value() == B_CONTROL_ON ? NULL : &customLocale); } else { if (strcmp(fAccountName->Text(), fAccount->Name()) != 0) gDatabase.RenameAccount(fAccount, fAccountName->Text()); - fPrefView->GetSettings(customLocale); if (fUseDefault->Value() != B_CONTROL_ON) { fAccount->UseDefaultLocale(false); fAccount->SetLocale(customLocale); diff --git a/src/BudgetWindow.cpp b/src/BudgetWindow.cpp index cec6ab4..506925b 100644 --- a/src/BudgetWindow.cpp +++ b/src/BudgetWindow.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "Account.h" @@ -44,6 +45,8 @@ BudgetWindow::BudgetWindow(const BRect& frame) fIncomeGrid(13, 0), fSpendingGrid(13, 0) { + BNumberFormat numberFormatter; + fDecimalSymbol = numberFormatter.GetSeparator(B_DECIMAL_SEPARATOR); fBar = new BMenuBar("menubar"); fBar->AddItem( new BMenuItem(B_TRANSLATE("Recalculate all"), new BMessage(M_BUDGET_RECALCULATE))); @@ -128,7 +131,7 @@ BudgetWindow::MessageReceived(BMessage* msg) break; f.Round(); gDefaultLocale.CurrencyToString(f, str); - str.Truncate(str.FindFirst(gDefaultLocale.CurrencyDecimal())); + str.Truncate(str.FindFirst(fDecimalSymbol)); str.RemoveFirst(gDefaultLocale.CurrencySymbol()); BRow* row = fCategoryList->CurrentSelection(); @@ -251,7 +254,7 @@ BudgetWindow::HandleCategorySelection(void) BString str; gDefaultLocale.CurrencyToString(entry.amount.AbsoluteValue(), str); - str.Truncate(str.FindFirst(gDefaultLocale.CurrencyDecimal())); + str.Truncate(str.FindFirst(fDecimalSymbol)); str.RemoveFirst(gDefaultLocale.CurrencySymbol()); fAmountBox->SetText(str.String()); @@ -306,7 +309,7 @@ BudgetWindow::RefreshCategories(void) BString amountstr; gDefaultLocale.CurrencyToString(amount.AbsoluteValue(), amountstr); - amountstr.Truncate(amountstr.FindFirst(gDefaultLocale.CurrencyDecimal())); + amountstr.Truncate(amountstr.FindFirst(fDecimalSymbol)); amountstr.RemoveFirst(gDefaultLocale.CurrencySymbol()); row->SetField(new BStringField(amountstr.String()), 1); @@ -355,9 +358,9 @@ BudgetWindow::RefreshBudgetSummary(void) gDefaultLocale.CurrencyToString(stotal, stemp); gDefaultLocale.CurrencyToString(mtotal, mtemp); - itemp.Truncate(itemp.FindFirst(gDefaultLocale.CurrencyDecimal())); - stemp.Truncate(stemp.FindFirst(gDefaultLocale.CurrencyDecimal())); - mtemp.Truncate(mtemp.FindFirst(gDefaultLocale.CurrencyDecimal())); + itemp.Truncate(itemp.FindFirst(fDecimalSymbol)); + stemp.Truncate(stemp.FindFirst(fDecimalSymbol)); + mtemp.Truncate(mtemp.FindFirst(fDecimalSymbol)); itemp.RemoveFirst(gDefaultLocale.CurrencySymbol()); stemp.RemoveFirst(gDefaultLocale.CurrencySymbol()); @@ -387,17 +390,17 @@ BudgetWindow::RefreshBudgetSummary(void) BString ttemp; gDefaultLocale.CurrencyToString(irowtotal, ttemp); - ttemp.Truncate(ttemp.FindFirst(gDefaultLocale.CurrencyDecimal())); + ttemp.Truncate(ttemp.FindFirst(fDecimalSymbol)); ttemp.RemoveFirst(gDefaultLocale.CurrencySymbol()); fBudgetSummary->RowAt(0)->SetField(new BStringField(ttemp.String()), 13); gDefaultLocale.CurrencyToString(srowtotal, ttemp); - ttemp.Truncate(ttemp.FindFirst(gDefaultLocale.CurrencyDecimal())); + ttemp.Truncate(ttemp.FindFirst(fDecimalSymbol)); ttemp.RemoveFirst(gDefaultLocale.CurrencySymbol()); fBudgetSummary->RowAt(1)->SetField(new BStringField(ttemp.String()), 13); gDefaultLocale.CurrencyToString(ttotal, ttemp); - ttemp.Truncate(ttemp.FindFirst(gDefaultLocale.CurrencyDecimal())); + ttemp.Truncate(ttemp.FindFirst(fDecimalSymbol)); ttemp.RemoveFirst(gDefaultLocale.CurrencySymbol()); fBudgetSummary->RowAt(2)->SetField(new BStringField(ttemp.String()), 13); @@ -670,7 +673,7 @@ BudgetWindow::SetPeriod(const BudgetPeriod& period) BString str; gDefaultLocale.CurrencyToString(entry.amount, str); - str.Truncate(str.FindFirst(gDefaultLocale.CurrencyDecimal())); + str.Truncate(str.FindFirst(fDecimalSymbol)); str.RemoveFirst(gDefaultLocale.CurrencySymbol()); row->SetField(new BStringField(str.String()), 1); diff --git a/src/BudgetWindow.h b/src/BudgetWindow.h index dbce16d..a04144f 100644 --- a/src/BudgetWindow.h +++ b/src/BudgetWindow.h @@ -57,6 +57,7 @@ class BudgetWindow : public BWindow { BRow *fStatAverageRow, *fStatHighestRow, *fStatLowestRow; ReportGrid fIncomeGrid, fSpendingGrid; + BString fDecimalSymbol; }; #endif diff --git a/src/CBLocale.h b/src/CBLocale.h index df8469a..9d80d65 100644 --- a/src/CBLocale.h +++ b/src/CBLocale.h @@ -8,11 +8,6 @@ #include "DAlert.h" #include "Fixed.h" -typedef enum { - DATE_MDY = 1, - DATE_DMY = 2 -} date_format; - class Locale { public: Locale(void); @@ -31,42 +26,22 @@ class Locale { void NumberToCurrency(const Fixed& number, BString& string); void SetCurrencySymbol(const char* symbol); - const char* CurrencySymbol(void) const { return fCurrencySymbol.String(); } - void SetCurrencySeparator(const char* symbol); - - const char* CurrencySeparator(void) const { return fCurrencySeparator.String(); } - - void SetCurrencyDecimal(const char* symbol); - - const char* CurrencyDecimal(void) const { return fCurrencyDecimal.String(); } - void SetCurrencySymbolPrefix(const bool& value); - bool IsCurrencySymbolPrefix(void) const { return fPrefixSymbol; } - void SetCurrencyDecimalPlace(const uint8& place); - + void SetCurrencyDecimalPlace(const uint8 place); uint8 CurrencyDecimalPlace(void) const { return fCurrencyDecimalPlace; } - void SetDST(const bool& value); - - bool UseDST(void) const { return fUseDST; } - private: friend class CapitalBeParser; void SetDefaults(void); - status_t ConstructDateStringMDY(const char* in, BString& out); - status_t ConstructDateStringDMY(const char* in, BString& out); BString fCurrencySymbol; bool fPrefixSymbol; - BString fCurrencySeparator; - BString fCurrencyDecimal; uint8 fCurrencyDecimalPlace; - bool fUseDST; }; void ShowAlert(const char* header, const char* message, alert_type type = B_INFO_ALERT); diff --git a/src/Database.cpp b/src/Database.cpp index a47f723..03d7b46 100644 --- a/src/Database.cpp +++ b/src/Database.cpp @@ -152,15 +152,6 @@ Database::CreateFile(const char* path) DBCommand("create table categorylist (name varchar(96), type int(2));", "Database::CreateFile:create categorylist"); - // now that the tables have all been created, create the default locale - DBCommand( - "create table defaultlocale (dateformat varchar(8), " - "dateseparator char(6), currencysymbol char(6), " - "currencyseparator char(6), currencydecimal char(6), " - "currencyprefix char(1));", - "Database::CreateFile:create defaultlocale"); - DBCommand("insert into defaultlocale values('mmddyyyy', '/', '$', ',', '.', 'true');", - "Database::CreateFile insert defaultlocale values"); UNLOCK; } @@ -199,7 +190,6 @@ Database::OpenFile(const char* path) while (!query.eof()) { uint32 id = query.getIntField(0); BString name = DeescapeIllegalCharacters(query.getStringField(1)); - // BString type = query.getStringField(2); BString status = DeescapeIllegalCharacters(query.getStringField(3)); Account* account = new Account(name.String(), status.ICompare("open") != 0); @@ -233,8 +223,6 @@ Database::OpenFile(const char* path) acc->SetLastCheckNumber(acc->LookupLastCheckNumber()); } - gDefaultLocale = GetDefaultLocale(); - fCurrent = (Account*)fList.ItemAt(0); UNLOCK; return B_OK; @@ -336,7 +324,7 @@ Database::AddAccount( << AccountTypeToString(type) << "', '" << estatus << "');"; DBCommand(command.String(), "Database::AddAccount:insert accountlist"); - if (locale) + if (locale != NULL) SetAccountLocale(id, *locale); command = ""; @@ -349,7 +337,7 @@ Database::AddAccount( Account* account = new Account(name); account->SetID(id); - account->UseDefaultLocale(!locale); + account->UseDefaultLocale(locale == NULL); if (strcmp(status, "closed") == 0) account->SetClosed(true); fList.AddItem(account); @@ -551,18 +539,21 @@ Database::CountBudgetEntries(void) void Database::SetAccountLocale(const uint32& accountid, const Locale& data) { + // Check if there are any changes, return early if not + if (gCurrentLocale == data) + return; + gCurrentLocale = data; LOCK; - BString command("select accountid from accountlocale where accountid = "); - command << accountid << ";"; + BString command; + command << ("SELECT accountid FROM accountlocale WHERE accountid = ") << accountid << ";"; CppSQLite3Query query = DBQuery(command.String(), "Database::SetAccountLocale:find accountid"); // Todo: remove table columns for date format if (query.eof()) { - command << "insert into accountlocale values(" << accountid << ",'ddmmyyyy','/','" - << data.CurrencySymbol() << "','" << data.CurrencySeparator() << "','" - << data.CurrencyDecimal() << "','" + command << "INSERT INTO accountlocale VALUES(" << accountid << ",'-','-','" + << data.CurrencySymbol() << "','-','" << data.CurrencyDecimalPlace() << "','" << (data.IsCurrencySymbolPrefix() ? "true" : "false") << "');"; DBCommand(command.String(), "Database::SetAccountLocale:insert into accountlocale"); UNLOCK; @@ -572,30 +563,13 @@ Database::SetAccountLocale(const uint32& accountid, const Locale& data) query.finalize(); // This already has the locale data in the table, so we'll just update it and return - command << "update accountlocale set dateformat = 'ddmmyyyy' where accountid = " << accountid - << ";"; - DBCommand(command.String(), "Database::SetAccountLocale:update dateformat"); - - command << "update accountlocale set dateseparator = '/' where accountid = " << accountid - << ";"; - DBCommand(command.String(), "Database::SetAccountLocale:update dateseparator"); - - command << "update accountlocale set currencysymbol = '" << data.CurrencySymbol() - << "' where accountid = " << accountid << ";"; - DBCommand(command.String(), "Database::SetAccountLocale:update currencysymbol"); - - command << "update accountlocale set currencyseparator = '" << data.CurrencySeparator() - << "' where accountid = " << accountid << ";"; - DBCommand(command.String(), "Database::SetAccountLocale:update currencyseparator"); - - command << "update accountlocale set currencydecimal = '" << data.CurrencyDecimal() - << "' where accountid = " << accountid << ";"; - DBCommand(command.String(), "Database::SetAccountLocale:update currencydecimal"); - - command << "update accountlocale set currencyprefix = '" - << (data.IsCurrencySymbolPrefix() ? "true" : "false") - << "' where accountid = " << accountid << ";"; - DBCommand(command.String(), "Database::SetAccountLocale:update currencyprefix"); + command = ""; + command << "UPDATE accountlocale SET " + << "currencysymbol = '" << data.CurrencySymbol() << "', " + << "currencydecimal = '" << data.CurrencyDecimalPlace() << "', " + << "currencyprefix = '" << (data.IsCurrencySymbolPrefix() ? "true" : "false") << "' " + << "WHERE accountid = " << accountid << ";"; + DBCommand(command.String(), "Database::SetAccountLocale:update all fields"); UNLOCK; } @@ -604,7 +578,7 @@ Database::LocaleForAccount(const uint32& id) { LOCK; BString command; - command << "select * from accountlocale where accountid = " << id << ";"; + command << "SELECT * FROM accountlocale WHERE accountid = " << id << ";"; CppSQLite3Query query = DBQuery(command.String(), "Database::LocaleForAccount:find account"); Locale locale; @@ -613,71 +587,22 @@ Database::LocaleForAccount(const uint32& id) return locale; } - BString temp = query.getStringField(1); + BString temp; locale.SetCurrencySymbol(query.getStringField(3)); - locale.SetCurrencySeparator(query.getStringField(4)); - locale.SetCurrencyDecimal(query.getStringField(5)); + locale.SetCurrencyDecimalPlace(query.getIntField(5)); temp = query.getStringField(6); locale.SetCurrencySymbolPrefix(temp.Compare("true") == 0 ? true : false); UNLOCK; return locale; } -void -Database::SetDefaultLocale(const Locale& data) -{ - LOCK; - BString command; - - // This already has the locale data in the table, so we'll just update it and return - command << "update defaultlocale set currencysymbol = '" << data.CurrencySymbol() << "';"; - DBCommand(command.String(), "Database::SetAccountLocale:update currencysymbol"); - - command << "update defaultlocale set currencyseparator = '" << data.CurrencySeparator() << "';"; - DBCommand(command.String(), "Database::SetAccountLocale:update currencyseparator"); - - command << "update defaultlocale set currencydecimal = '" << data.CurrencyDecimal() << "';"; - DBCommand(command.String(), "Database::SetAccountLocale:update currencydecimal"); - - command << "update defaultlocale set currencyprefix = '" - << (data.IsCurrencySymbolPrefix() ? "true" : "false") << "';"; - DBCommand(command.String(), "Database::SetAccountLocale:update currencyprefix"); - - BMessage msg; - msg.AddPointer("locale", &gDefaultLocale); - Notify(WATCH_LOCALE | WATCH_CHANGE, &msg); - UNLOCK; -} - -Locale -Database::GetDefaultLocale(void) -{ - LOCK; - CppSQLite3Query query = DBQuery("select * from defaultlocale;", "Database::GetDefaultLocale"); - - Locale locale; - if (query.eof()) { - UNLOCK; - return locale; - } - - BString temp = query.getStringField(0); - locale.SetCurrencySymbol(query.getStringField(2)); - locale.SetCurrencySeparator(query.getStringField(3)); - locale.SetCurrencyDecimal(query.getStringField(4)); - - temp = query.getStringField(5); - locale.SetCurrencySymbolPrefix(temp.Compare("true") == 0 ? true : false); - UNLOCK; - return locale; -} bool Database::UsesDefaultLocale(const uint32& id) { LOCK; - BString command = "select accountid from accountlocale where accountid = "; + BString command = "SELECT accountid FROM accountlocale WHERE accountid = "; command << id << ";"; CppSQLite3Query query = DBQuery(command.String(), "Database::UsesDefaultLocale"); diff --git a/src/Database.h b/src/Database.h index 5ef299a..ae70ec5 100644 --- a/src/Database.h +++ b/src/Database.h @@ -69,7 +69,6 @@ class Database : public Notifier { void SetAccountLocale(const uint32& accountid, const Locale& data); Locale LocaleForAccount(const uint32& id); - void SetDefaultLocale(const Locale& data); Locale GetDefaultLocale(void); bool UsesDefaultLocale(const uint32& id); diff --git a/src/Locale.cpp b/src/Locale.cpp index b2863bf..bb0268e 100644 --- a/src/Locale.cpp +++ b/src/Locale.cpp @@ -1,8 +1,12 @@ +#include "App.h" +#include "CBLocale.h" #include #include #include #include #include +#include +#include #include #include #include @@ -11,8 +15,6 @@ #include #include #include -#include "App.h" -#include "CBLocale.h" #undef B_TRANSLATION_CONTEXT #define B_TRANSLATION_CONTEXT "Locale" @@ -34,10 +36,8 @@ Locale::operator!=(const Locale& other) const bool Locale::operator==(const Locale& other) const { - if (fCurrencySymbol != other.fCurrencySymbol || fPrefixSymbol != other.fPrefixSymbol || - fCurrencySeparator != other.fCurrencySeparator || - fCurrencyDecimal != other.fCurrencyDecimal || - fCurrencyDecimalPlace != other.fCurrencyDecimalPlace || fUseDST != other.fUseDST) { + if (fCurrencySymbol != other.fCurrencySymbol || fPrefixSymbol != other.fPrefixSymbol + || fCurrencyDecimalPlace != other.fCurrencyDecimalPlace) { return false; } return true; @@ -47,55 +47,68 @@ void Locale::Flatten(BFile* file) { BString str("\t\n"); - str << "\t\t\n"; - str << "\t\t\n"; - str << "\t\t\n"; - str << "\t\t\n"; - if (!fPrefixSymbol) str << "\t\t\n"; - if (fUseDST) - str << "\t\t\n"; str << "\t\n"; - file->Write(str.String(), str.Length()); } status_t Locale::CurrencyToString(const Fixed& amount, BString& string) { - string = ""; - - BString dollars; - dollars << (amount.IsPositive() ? amount.AsLong() : -amount.AsLong()); - - char cents[20]; - BString formatstring("%."); - formatstring << (int)fCurrencyDecimalPlace << "f"; - sprintf(cents, formatstring.String(), amount.DecimalPart()); - - string = cents + ((amount.IsNegative() && amount.DecimalPart() != 0) ? 2 : 1); - if (fCurrencyDecimal != ".") - string.ReplaceSet(".", fCurrencyDecimal.String()); - - for (int32 i = dollars.CountChars() - 3; i > 0; i -= 3) - dollars.Insert(fCurrencySeparator, i); + BNumberFormat numberFormatter; + BString separator = numberFormatter.GetSeparator(B_DECIMAL_SEPARATOR); + + // Determine the formatted number as a string + BString num; + if (strcmp(fCurrencySymbol, "") == 0) { // Using default locale + return numberFormatter.FormatMonetary(string, amount.AsDouble()); + } else { // Using custom locale + if (numberFormatter.Format(num, + fCurrencyDecimalPlace > 0 ? amount.AsDouble() : amount.IntegerPart()) + != B_OK) { + return B_ERROR; + } + } - string.Prepend(dollars); + // Check if the number already has a decimal separator + int32 separatorIndex = num.FindFirst(separator); + if (separatorIndex == B_ERROR) { + // No decimal separator found, append one if needed + if (fCurrencyDecimalPlace > 0) { + num += separator; + for (int i = 0; i < fCurrencyDecimalPlace; ++i) + num += '0'; + } + } else { + // Ensure the number has exactly fCurrencyDecimalPlace decimals + int32 currentDecimals = num.Length() - separatorIndex - 1; + if (currentDecimals < fCurrencyDecimalPlace) { + for (int i = 0; i < fCurrencyDecimalPlace - currentDecimals; ++i) + num += '0'; + } else if (currentDecimals > fCurrencyDecimalPlace) { + num.Truncate(separatorIndex + 1 + fCurrencyDecimalPlace); + } + } + // Append or prepend the currency symbol if (fPrefixSymbol) - string.Prepend(fCurrencySymbol); + num.Prepend(fCurrencySymbol); else - string.Append(fCurrencySymbol); + num.Append(fCurrencySymbol); + // Prepend a negative sign if the amount is negative if (amount < 0) string.Prepend("-"); + // Set the final string + string = num; return B_OK; } + status_t Locale::StringToCurrency(const char* string, Fixed& amount) { @@ -105,12 +118,16 @@ Locale::StringToCurrency(const char* string, Fixed& amount) if (!string) return B_ERROR; + BNumberFormat numberFormatter; + BString decimalSymbol = numberFormatter.GetSeparator(B_DECIMAL_SEPARATOR); + BString groupingSeparator = numberFormatter.GetSeparator(B_GROUPING_SEPARATOR); + BString dollars(string), cents; dollars.RemoveAll(fCurrencySymbol); - dollars.RemoveAll(fCurrencySeparator); + dollars.RemoveAll(groupingSeparator); - int32 index = dollars.FindFirst(fCurrencyDecimal); + int32 index = dollars.FindFirst(decimalSymbol); if (index < 0) { // We're working with whole dollars here. :) cents = "00"; @@ -130,27 +147,6 @@ Locale::StringToCurrency(const char* string, Fixed& amount) return B_OK; } -status_t -Locale::PremultipliedStringToCurrency(const char* string, Fixed& amount) -{ - // This function is an optimized version of StringToCurrency which expects - // the input string to represent the premultiplied version of a Fixed value. - // As a result, everything which is not a number is stripped out, converted - // to a number and added to the amount parameter - if (!string) - return B_ERROR; - - // TODO: See if using the string set version of RemoveAll would be faster - - BString valuestr(string); - valuestr.RemoveAll(fCurrencySymbol); - valuestr.RemoveAll(fCurrencySeparator); - valuestr.RemoveAll(fCurrencyDecimal); - - int32 value = atoi(valuestr.String()); - amount.SetPremultiplied(value); - return B_OK; -} status_t Locale::DateToString(time_t date, BString& string) @@ -182,36 +178,13 @@ Locale::StringToDate(const char* instring, time_t& date) return B_OK; } -void -Locale::NumberToCurrency(const Fixed& number, BString& string) -{ - string = ""; - string << number.IntegerPart(); - - for (int32 i = string.CountChars() - 3; i > 0; i -= 3) - string.Insert(fCurrencySeparator, i); - - string << fCurrencyDecimal; - - // We have to do this to eliminate the leading zero and the decimal point - BString decimal; - decimal << (float)number.DecimalPart(); - - if (number.IsNegative()) - string += decimal.String() + 3; - else - string += decimal.String() + 2; -} void Locale::SetDefaults(void) { - fCurrencySymbol = "$"; + fCurrencySymbol = ""; fPrefixSymbol = true; - fCurrencySeparator = ","; - fCurrencyDecimal = "."; fCurrencyDecimalPlace = 2; - fUseDST = false; } @@ -349,19 +322,6 @@ Locale::SetCurrencySymbol(const char* symbol) fCurrencySymbol = symbol; } -void -Locale::SetCurrencySeparator(const char* symbol) -{ - if (symbol) - fCurrencySeparator = symbol; -} - -void -Locale::SetCurrencyDecimal(const char* symbol) -{ - if (symbol) - fCurrencyDecimal = symbol; -} void Locale::SetCurrencySymbolPrefix(const bool& value) @@ -369,19 +329,14 @@ Locale::SetCurrencySymbolPrefix(const bool& value) fPrefixSymbol = value; } + void -Locale::SetCurrencyDecimalPlace(const uint8& place) +Locale::SetCurrencyDecimalPlace(const uint8 place) { fCurrencyDecimalPlace = place; } -void -Locale::SetDST(const bool& value) -{ - fUseDST = value; -} - const char* GetCurrencyOnlyMask(void) { diff --git a/src/PrefWindow.cpp b/src/PrefWindow.cpp index 61dc360..807c5ab 100644 --- a/src/PrefWindow.cpp +++ b/src/PrefWindow.cpp @@ -24,8 +24,6 @@ PrefWindow::PrefWindow(const BRect& frame, BMessenger target) AddShortcut('W', B_COMMAND_KEY, new BMessage(B_QUIT_REQUESTED)); AddShortcut('Q', B_COMMAND_KEY, new BMessage(B_QUIT_REQUESTED)); - fCurrencyPrefView = new CurrencyPrefView("currencyview", &gDefaultLocale); - fNegNumberView = new NegativeNumberView("negcolor", gNegativeColor); BButton* cancel = @@ -37,7 +35,6 @@ PrefWindow::PrefWindow(const BRect& frame, BMessenger target) // clang-format off BLayoutBuilder::Group<>(this, B_VERTICAL, B_USE_DEFAULT_SPACING) .SetInsets(B_USE_DEFAULT_SPACING) - .Add(fCurrencyPrefView) .Add(fNegNumberView) .AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING) .AddGlue() @@ -54,21 +51,8 @@ void PrefWindow::MessageReceived(BMessage* msg) { switch (msg->what) { - case M_CURRENCY_UPADTED: - { - BMessenger(fNegNumberView).SendMessage(msg); - break; - } case M_EDIT_OPTIONS: { - Locale temp = gDefaultLocale; - fCurrencyPrefView->GetSettings(temp); - - if (temp != gDefaultLocale) { - gDefaultLocale = temp; - gDatabase.SetDefaultLocale(gDefaultLocale); - } - fNegNumberView->GetColor(gNegativeColor); prefsLock.Lock(); gPreferences.RemoveData("negativecolor"); @@ -97,31 +81,20 @@ CurrencyPrefView::CurrencyPrefView(const char* name, Locale* locale, const int32 fLocale = gDefaultLocale; fCurrencyBox = new BBox("CurrencyBox"); - fCurrencyBox->SetLabel(B_TRANSLATE("Default account settings")); - - BStringView* previewLabel = new BStringView("currencylabel", B_TRANSLATE("Currency format:")); - previewLabel->SetAlignment(B_ALIGN_RIGHT); - - BString curstr; - fLocale.CurrencyToString(fSampleAmount, curstr); - fCurrencyPreview = new BStringView("currencypreview", curstr.String()); fCurrencySymbolBox = new AutoTextControl("moneysym", B_TRANSLATE("Symbol:"), fLocale.CurrencySymbol(), new BMessage(M_NEW_CURRENCY_SYMBOL)); fCurrencySymbolBox->SetCharacterLimit(2); fCurrencySymbolPrefix = new BCheckBox( - "prefixcheck", B_TRANSLATE("Appears before amount"), new BMessage(M_TOGGLE_PREFIX)); + "prefixcheck", B_TRANSLATE("Appears before amount"), new BMessage(M_NEW_CURRENCY_SYMBOL)); fCurrencySymbolPrefix->SetValue( (fLocale.IsCurrencySymbolPrefix()) ? B_CONTROL_ON : B_CONTROL_OFF); - fCurrencySeparatorBox = new AutoTextControl("moneysep", B_TRANSLATE("Separator:"), - fLocale.CurrencySeparator(), new BMessage(M_NEW_CURRENCY_SEPARATOR)); - fCurrencySeparatorBox->SetCharacterLimit(2); - - fCurrencyDecimalBox = new AutoTextControl("moneydecimal", B_TRANSLATE("Decimal:"), - fLocale.CurrencyDecimal(), new BMessage(M_NEW_CURRENCY_DECIMAL)); - fCurrencyDecimalBox->SetCharacterLimit(2); + fDecimalSpinner = new BSpinner("width", B_TRANSLATE("Decimals:"), new BMessage(M_NEW_CURRENCY_SYMBOL)); + fDecimalSpinner->SetMinValue(0); + fDecimalSpinner->SetMaxValue(3); + fDecimalSpinner->SetValue(locale->CurrencyDecimalPlace()); // clang-format off BLayoutBuilder::Group<>(fCurrencyBox, B_VERTICAL, B_USE_DEFAULT_SPACING) @@ -130,15 +103,10 @@ CurrencyPrefView::CurrencyPrefView(const char* name, Locale* locale, const int32 .AddGroup(B_HORIZONTAL) .AddGlue() .AddGrid(B_USE_DEFAULT_SPACING, B_USE_SMALL_SPACING) - .Add(previewLabel, 0, 0, 2, 1) - .Add(fCurrencyPreview, 2, 0, 3, 1) .Add(fCurrencySymbolBox->CreateLabelLayoutItem(), 0, 2) .Add(fCurrencySymbolBox->CreateTextViewLayoutItem(), 1, 2) .Add(fCurrencySymbolPrefix, 2, 2, 3, 1) - .Add(fCurrencySeparatorBox->CreateLabelLayoutItem(), 0, 3) - .Add(fCurrencySeparatorBox->CreateTextViewLayoutItem(), 1, 3) - .Add(fCurrencyDecimalBox->CreateLabelLayoutItem(), 2, 3) - .Add(fCurrencyDecimalBox->CreateTextViewLayoutItem(), 3, 3) + .Add(fDecimalSpinner, 0, 3, 2) .End() .AddGlue() .End() @@ -148,15 +116,20 @@ CurrencyPrefView::CurrencyPrefView(const char* name, Locale* locale, const int32 .Add(fCurrencyBox) .End(); // clang-format on + + if (strcmp(locale->CurrencySymbol(), "") == 0){ + fLocale.SetCurrencySymbol("$"); + fCurrencySymbolBox->SetText(fLocale.CurrencySymbol()); + UpdateCurrencyLabel(); + } } void CurrencyPrefView::AttachedToWindow(void) { fCurrencySymbolBox->SetTarget(this); - fCurrencyDecimalBox->SetTarget(this); - fCurrencySeparatorBox->SetTarget(this); fCurrencySymbolPrefix->SetTarget(this); + fDecimalSpinner->SetTarget(this); UpdateCurrencyLabel(); } @@ -171,30 +144,8 @@ CurrencyPrefView::MessageReceived(BMessage* msg) break; fLocale.SetCurrencySymbol(fCurrencySymbolBox->Text()); - UpdateCurrencyLabel(); - break; - } - case M_NEW_CURRENCY_SEPARATOR: - { - if (strlen(fCurrencySeparatorBox->Text()) < 1) - break; - - fLocale.SetCurrencySeparator(fCurrencySeparatorBox->Text()); - UpdateCurrencyLabel(); - break; - } - case M_NEW_CURRENCY_DECIMAL: - { - if (strlen(fCurrencyDecimalBox->Text()) < 1) - break; - - fLocale.SetCurrencyDecimal(fCurrencyDecimalBox->Text()); - UpdateCurrencyLabel(); - break; - } - case M_TOGGLE_PREFIX: - { fLocale.SetCurrencySymbolPrefix(fCurrencySymbolPrefix->Value() == B_CONTROL_ON); + fLocale.SetCurrencyDecimalPlace(fDecimalSpinner->Value()); UpdateCurrencyLabel(); break; } @@ -208,27 +159,18 @@ void CurrencyPrefView::UpdateCurrencyLabel(void) { BString temp, label; + label = B_TRANSLATE("Currency format"); fLocale.CurrencyToString(fSampleAmount, temp); - fCurrencyPreview->SetText(temp.String()); - - // For the neg. number previews we need the fSampleAmount * -1 - fLocale.CurrencyToString(fSampleAmount.InvertAsCopy(), temp); - BMessage msg(M_CURRENCY_UPADTED); - msg.AddString("currency", temp); - Window()->PostMessage(&msg); + label << ": " << temp; + fCurrencyBox->SetLabel(label.String()); } void CurrencyPrefView::GetSettings(Locale& locale) { - if (strlen(fCurrencySeparatorBox->Text()) > 0) - locale.SetCurrencySeparator(fCurrencySeparatorBox->Text()); - if (strlen(fCurrencyDecimalBox->Text()) > 0) - locale.SetCurrencyDecimal(fCurrencyDecimalBox->Text()); - if (strlen(fCurrencySymbolBox->Text()) > 0) - locale.SetCurrencySymbol(fCurrencySymbolBox->Text()); - + locale.SetCurrencySymbol(fCurrencySymbolBox->Text()); locale.SetCurrencySymbolPrefix(fCurrencySymbolPrefix->Value() == B_CONTROL_ON); + locale.SetCurrencyDecimalPlace(fDecimalSpinner->Value()); } @@ -244,6 +186,10 @@ NegativeNumberView::NegativeNumberView(const char* name, rgb_color negColor) fColorPicker->SetValue(negColor); // Preview of the colored text on different background colors + Fixed sample((long)-12345678, true); + BString negativeAmount; + gDefaultLocale.CurrencyToString(sample, negativeAmount); + BStringView* label = new BStringView("label", B_TRANSLATE("Preview:")); label->SetFont(be_bold_font); @@ -251,14 +197,17 @@ NegativeNumberView::NegativeNumberView(const char* name, rgb_color negColor) fUnselectedPreview = new BTextView("unselected"); fUnselectedPreview->SetAlignment(B_ALIGN_CENTER); fUnselectedPreview->SetViewColor(ui_color(B_LIST_BACKGROUND_COLOR)); + fUnselectedPreview->SetText(negativeAmount); fSelectedPreview = new BTextView("selected"); fSelectedPreview->SetAlignment(B_ALIGN_CENTER); fSelectedPreview->SetViewUIColor(B_LIST_SELECTED_BACKGROUND_COLOR); + fSelectedPreview->SetText(negativeAmount); fClosedPreview = new BTextView("unselected-closed"); fClosedPreview->SetAlignment(B_ALIGN_CENTER); fClosedPreview->SetViewColor(ui_color(B_LIST_BACKGROUND_COLOR)); + fClosedPreview->SetText(negativeAmount); UpdateColor(negColor); @@ -300,13 +249,6 @@ NegativeNumberView::MessageReceived(BMessage* msg) UpdateColor(fColorPicker->ValueAsColor()); break; - case M_CURRENCY_UPADTED: - { - BString text; - if (msg->FindString("currency", &text) == B_OK) - UpdateText(text); - break; - } default: BView::MessageReceived(msg); } @@ -318,14 +260,6 @@ NegativeNumberView::GetColor(rgb_color& color) color = fColorPicker->ValueAsColor(); } -void -NegativeNumberView::UpdateText(BString text) -{ - fUnselectedPreview->SetText(text); - fSelectedPreview->SetText(text); - fClosedPreview->SetText(text); -} - void NegativeNumberView::UpdateColor(rgb_color color) { diff --git a/src/PrefWindow.h b/src/PrefWindow.h index 52e21fa..8bfef69 100644 --- a/src/PrefWindow.h +++ b/src/PrefWindow.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -29,13 +30,7 @@ enum { }; // CurrencyPrefView -enum { - M_NEW_CURRENCY_SYMBOL, - M_NEW_CURRENCY_SEPARATOR, - M_NEW_CURRENCY_DECIMAL, - M_TOGGLE_PREFIX, - M_CURRENCY_UPADTED -}; +enum { M_NEW_CURRENCY_SYMBOL, M_TOGGLE_PREFIX, M_CURRENCY_UPDATED, M_CURRENCY_DECIMAL_PLACE }; // NegativeNumberView enum { @@ -70,8 +65,9 @@ class CurrencyPrefView : public BView { void UpdateCurrencyLabel(void); BBox* fCurrencyBox; - AutoTextControl *fCurrencySymbolBox, *fCurrencyDecimalBox, *fCurrencySeparatorBox; + AutoTextControl* fCurrencySymbolBox; BCheckBox* fCurrencySymbolPrefix; + BSpinner* fDecimalSpinner; BStringView* fCurrencyPreview; Locale fLocale; Fixed fSampleAmount; @@ -88,7 +84,6 @@ class NegativeNumberView : public BView { void GetColor(rgb_color& color); private: - void UpdateText(BString text); void UpdateColor(rgb_color color); BColorControl* fColorPicker; diff --git a/src/QuickTrackerItem.cpp b/src/QuickTrackerItem.cpp index 424489c..010ea4f 100644 --- a/src/QuickTrackerItem.cpp +++ b/src/QuickTrackerItem.cpp @@ -81,7 +81,7 @@ QTNetWorthItem::HandleNotify(const uint64& value, const BMessage* msg) Window()->Lock(); BString label, temp; - temp << B_TRANSLATE("Balance") << " (" << gDefaultLocale.CurrencySymbol() << "): "; + temp << B_TRANSLATE("Balance") << ": "; if (gCurrentLocale.CurrencyToString(Fixed(), label) == B_OK) temp << label; SetText(temp.String()); @@ -145,8 +145,7 @@ QTNetWorthItem::Calculate(void) } if (accountsFound && gDefaultLocale.CurrencyToString(balance, balanceText) == B_OK) { - balanceLabel << B_TRANSLATE("Balance") << " (" << gDefaultLocale.CurrencySymbol() - << "): " << balanceText << "\n"; + balanceLabel << B_TRANSLATE("Balance") << ": " << balanceText << "\n"; } // Get sum of other currency accounts: @@ -168,8 +167,7 @@ QTNetWorthItem::Calculate(void) } if (accLocale.CurrencyToString(balance, balanceText) == B_OK) { - balanceLabel << B_TRANSLATE("Balance") << " (" << accLocale.CurrencySymbol() - << "): " << balanceText << "\n"; + balanceLabel << B_TRANSLATE("Balance") << ": " << balanceText << "\n"; } }