* Fixed a ton of minor coding style violations, no functional change intended.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@36586 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -6,7 +6,9 @@
|
|||||||
* Stephan Aßmus <[email protected]>
|
* Stephan Aßmus <[email protected]>
|
||||||
* Adrien Destugues <[email protected]>
|
* Adrien Destugues <[email protected]>
|
||||||
* Oliver Tappe <[email protected]>
|
* Oliver Tappe <[email protected]>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "LanguageListView.h"
|
#include "LanguageListView.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -46,7 +48,6 @@ LanguageListItem::~LanguageListItem()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//MediaListItem - DrawItem
|
|
||||||
void
|
void
|
||||||
LanguageListItem::DrawItem(BView* owner, BRect frame, bool complete)
|
LanguageListItem::DrawItem(BView* owner, BRect frame, bool complete)
|
||||||
{
|
{
|
||||||
@@ -93,6 +94,8 @@ LanguageListItem::DrawItem(BView* owner, BRect frame, bool complete)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
LanguageListView::LanguageListView(const char* name, list_view_type type)
|
LanguageListView::LanguageListView(const char* name, list_view_type type)
|
||||||
:
|
:
|
||||||
@@ -162,7 +165,8 @@ LanguageListView::MoveItems(BList& items, int32 index)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void LanguageListView::MessageReceived (BMessage* message)
|
void
|
||||||
|
LanguageListView::MessageReceived(BMessage* message)
|
||||||
{
|
{
|
||||||
if (message->what == 'DRAG') {
|
if (message->what == 'DRAG') {
|
||||||
// Someone just dropped something on us
|
// Someone just dropped something on us
|
||||||
|
|||||||
@@ -6,9 +6,9 @@
|
|||||||
* Stephan Aßmus <[email protected]>
|
* Stephan Aßmus <[email protected]>
|
||||||
* Adrien Destugues <[email protected]>
|
* Adrien Destugues <[email protected]>
|
||||||
* Oliver Tappe <[email protected]>
|
* Oliver Tappe <[email protected]>
|
||||||
*/
|
*/
|
||||||
#ifndef __LANGUAGE_LIST_VIEW_H
|
#ifndef LANGUAGE_LIST_VIEW_H
|
||||||
#define __LANGUAGE_LIST_VIEW_H
|
#define LANGUAGE_LIST_VIEW_H
|
||||||
|
|
||||||
|
|
||||||
#include <OutlineListView.h>
|
#include <OutlineListView.h>
|
||||||
@@ -53,4 +53,4 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif // LANGUAGE_LIST_VIEW_H
|
||||||
|
|||||||
@@ -19,5 +19,6 @@ static const uint32 kMsgPrefLangInvoked = 'pliv';
|
|||||||
static const uint32 kMsgDefaults = 'dflt';
|
static const uint32 kMsgDefaults = 'dflt';
|
||||||
static const uint32 kMsgRevert = 'revt';
|
static const uint32 kMsgRevert = 'revt';
|
||||||
|
|
||||||
|
|
||||||
#endif /* LOCALE_H */
|
#endif /* LOCALE_H */
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2005-2009, Axel Dörfler, [email protected].
|
* Copyright 2005-2010, Axel Dörfler, [email protected].
|
||||||
|
* Copyright 2009-2010, Adrien Destugues <[email protected]>.
|
||||||
* All rights reserved. Distributed under the terms of the MIT License.
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -52,6 +53,9 @@ compare_typed_list_items(const BListItem* _a, const BListItem* _b)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
LocaleWindow::LocaleWindow()
|
LocaleWindow::LocaleWindow()
|
||||||
:
|
:
|
||||||
BWindow(BRect(0, 0, 0, 0), "Locale", B_TITLED_WINDOW, B_NOT_RESIZABLE
|
BWindow(BRect(0, 0, 0, 0), "Locale", B_TITLED_WINDOW, B_NOT_RESIZABLE
|
||||||
@@ -73,157 +77,149 @@ LocaleWindow::LocaleWindow()
|
|||||||
BView* languageTab = new BView(TR("Language"), B_WILL_DRAW);
|
BView* languageTab = new BView(TR("Language"), B_WILL_DRAW);
|
||||||
languageTab->SetLayout(new BGroupLayout(B_VERTICAL, 0));
|
languageTab->SetLayout(new BGroupLayout(B_VERTICAL, 0));
|
||||||
|
|
||||||
{
|
// first list: available languages
|
||||||
// first list: available languages
|
fLanguageListView = new LanguageListView("available",
|
||||||
fLanguageListView = new LanguageListView("available",
|
B_MULTIPLE_SELECTION_LIST);
|
||||||
B_MULTIPLE_SELECTION_LIST);
|
BScrollView* scrollView = new BScrollView("scroller", fLanguageListView,
|
||||||
BScrollView* scrollView = new BScrollView("scroller", fLanguageListView,
|
B_WILL_DRAW | B_FRAME_EVENTS, false, true);
|
||||||
B_WILL_DRAW | B_FRAME_EVENTS, false, true);
|
|
||||||
|
|
||||||
fLanguageListView->SetInvocationMessage(new BMessage(kMsgLangInvoked));
|
fLanguageListView->SetInvocationMessage(new BMessage(kMsgLangInvoked));
|
||||||
|
|
||||||
// Fill the language list from the LocaleRoster data
|
// Fill the language list from the LocaleRoster data
|
||||||
BMessage installedLanguages;
|
BMessage installedLanguages;
|
||||||
if (be_locale_roster->GetInstalledLanguages(&installedLanguages)
|
if (be_locale_roster->GetInstalledLanguages(&installedLanguages)
|
||||||
== B_OK) {
|
== B_OK) {
|
||||||
|
BString currentLanguageCode;
|
||||||
|
BString currentLanguageName;
|
||||||
|
LanguageListItem* lastAddedItem = NULL;
|
||||||
|
|
||||||
BString currentLanguageCode;
|
for (int i = 0; installedLanguages.FindString("langs",
|
||||||
BString currentLanguageName;
|
i, ¤tLanguageCode) == B_OK; i++) {
|
||||||
LanguageListItem* lastAddedLanguage = NULL;
|
// Now get an human-readable, localized name for each language
|
||||||
for (int i = 0; installedLanguages.FindString("langs",
|
// TODO: sort them using collators.
|
||||||
i, ¤tLanguageCode) == B_OK; i++) {
|
BLanguage* currentLanguage;
|
||||||
|
be_locale_roster->GetLanguage(¤tLanguage,
|
||||||
|
currentLanguageCode.String());
|
||||||
|
|
||||||
// Now get an human-readable, localized name for each language
|
currentLanguageName.Truncate(0);
|
||||||
// TODO: sort them using collators.
|
currentLanguage->GetName(¤tLanguageName);
|
||||||
BLanguage* currentLanguage;
|
|
||||||
be_locale_roster->GetLanguage(¤tLanguage,
|
|
||||||
currentLanguageCode.String());
|
|
||||||
|
|
||||||
currentLanguageName.Truncate(0);
|
LanguageListItem* item = new LanguageListItem(currentLanguageName,
|
||||||
currentLanguage->GetName(¤tLanguageName);
|
currentLanguageCode.String());
|
||||||
|
if (currentLanguage->IsCountry()) {
|
||||||
LanguageListItem* si = new LanguageListItem(currentLanguageName,
|
fLanguageListView->AddUnder(item, lastAddedItem);
|
||||||
currentLanguageCode.String());
|
} else {
|
||||||
if (currentLanguage->IsCountry()) {
|
// This is a language without country, add it at top-level
|
||||||
fLanguageListView->AddUnder(si,lastAddedLanguage);
|
fLanguageListView->AddItem(item);
|
||||||
} else {
|
item->SetExpanded(false);
|
||||||
// This is a language without country, add it at top-level
|
if (lastAddedItem != NULL) {
|
||||||
fLanguageListView->AddItem(si);
|
fLanguageListView->SortItemsUnder(lastAddedItem, true,
|
||||||
si->SetExpanded(false);
|
compare_typed_list_items);
|
||||||
if (lastAddedLanguage != NULL) {
|
|
||||||
fLanguageListView->SortItemsUnder(lastAddedLanguage,
|
|
||||||
true, compare_typed_list_items);
|
|
||||||
}
|
|
||||||
lastAddedLanguage = si;
|
|
||||||
}
|
}
|
||||||
|
lastAddedItem = item;
|
||||||
delete currentLanguage;
|
|
||||||
}
|
}
|
||||||
fLanguageListView->SortItemsUnder(lastAddedLanguage, true,
|
|
||||||
compare_typed_list_items);
|
|
||||||
|
|
||||||
fLanguageListView->SortItems(compare_list_items);
|
delete currentLanguage;
|
||||||
// see previous comment on sort using collators
|
|
||||||
|
|
||||||
} else {
|
|
||||||
BAlert* myAlert = new BAlert("Error",
|
|
||||||
TR("Unable to find the available languages! You can't use this "
|
|
||||||
"preflet!"),
|
|
||||||
TR("OK"), NULL, NULL,
|
|
||||||
B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_STOP_ALERT);
|
|
||||||
myAlert->Go();
|
|
||||||
}
|
}
|
||||||
|
fLanguageListView->SortItemsUnder(lastAddedItem, true,
|
||||||
|
compare_typed_list_items);
|
||||||
|
|
||||||
// Second list: active languages
|
fLanguageListView->SortItems(compare_list_items);
|
||||||
fPreferredListView = new LanguageListView("preferred",
|
// see previous comment on sort using collators
|
||||||
B_MULTIPLE_SELECTION_LIST);
|
|
||||||
BScrollView* scrollViewEnabled = new BScrollView("scroller",
|
|
||||||
fPreferredListView, B_WILL_DRAW | B_FRAME_EVENTS, false, true);
|
|
||||||
|
|
||||||
fPreferredListView
|
} else {
|
||||||
->SetInvocationMessage(new BMessage(kMsgPrefLangInvoked));
|
BAlert* myAlert = new BAlert("Error",
|
||||||
|
TR("Unable to find the available languages! You can't use this "
|
||||||
// get the preferred languages from the Settings. Move them here from
|
"preflet!"),
|
||||||
// the other list.
|
TR("OK"), NULL, NULL,
|
||||||
BMessage msg;
|
B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_STOP_ALERT);
|
||||||
be_locale_roster->GetPreferredLanguages(&msg);
|
myAlert->Go();
|
||||||
BString langCode;
|
|
||||||
for (int index = 0;
|
|
||||||
msg.FindString("language", index, &langCode) == B_OK; index++) {
|
|
||||||
for (int listPos = 0; LanguageListItem* lli
|
|
||||||
= static_cast<LanguageListItem*>
|
|
||||||
(fLanguageListView->FullListItemAt(listPos));
|
|
||||||
listPos++) {
|
|
||||||
if (langCode == lli->LanguageCode()) {
|
|
||||||
// We found the item we were looking for, now move it to
|
|
||||||
// the other list along with all its children
|
|
||||||
static_cast<LanguageListView*>(fPreferredListView)
|
|
||||||
->MoveItemFrom(fLanguageListView,
|
|
||||||
fLanguageListView->FullListIndexOf(lli),
|
|
||||||
fLanguageListView->CountItems());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
languageTab->AddChild(BLayoutBuilder::Group<>(B_HORIZONTAL, 10)
|
|
||||||
.AddGroup(B_VERTICAL, 10)
|
|
||||||
.Add(new BStringView("", TR("Available languages")))
|
|
||||||
.Add(scrollView)
|
|
||||||
.End()
|
|
||||||
.AddGroup(B_VERTICAL, 10)
|
|
||||||
.Add(new BStringView("", TR("Preferred languages")))
|
|
||||||
.Add(scrollViewEnabled)
|
|
||||||
.End()
|
|
||||||
.View());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Second list: active languages
|
||||||
|
fPreferredListView = new LanguageListView("preferred",
|
||||||
|
B_MULTIPLE_SELECTION_LIST);
|
||||||
|
BScrollView* scrollViewEnabled = new BScrollView("scroller",
|
||||||
|
fPreferredListView, B_WILL_DRAW | B_FRAME_EVENTS, false, true);
|
||||||
|
|
||||||
|
fPreferredListView->SetInvocationMessage(new BMessage(kMsgPrefLangInvoked));
|
||||||
|
|
||||||
|
// get the preferred languages from the Settings. Move them here from
|
||||||
|
// the other list.
|
||||||
|
BMessage msg;
|
||||||
|
be_locale_roster->GetPreferredLanguages(&msg);
|
||||||
|
BString langCode;
|
||||||
|
for (int index = 0; msg.FindString("language", index, &langCode) == B_OK;
|
||||||
|
index++) {
|
||||||
|
for (int listPos = 0; LanguageListItem* item
|
||||||
|
= static_cast<LanguageListItem*>
|
||||||
|
(fLanguageListView->FullListItemAt(listPos));
|
||||||
|
listPos++) {
|
||||||
|
if (langCode == item->LanguageCode()) {
|
||||||
|
// We found the item we were looking for, now move it to
|
||||||
|
// the other list along with all its children
|
||||||
|
static_cast<LanguageListView*>(fPreferredListView)
|
||||||
|
->MoveItemFrom(fLanguageListView,
|
||||||
|
fLanguageListView->FullListIndexOf(item),
|
||||||
|
fLanguageListView->CountItems());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
languageTab->AddChild(BLayoutBuilder::Group<>(B_HORIZONTAL, 10)
|
||||||
|
.AddGroup(B_VERTICAL, 10)
|
||||||
|
.Add(new BStringView("", TR("Available languages")))
|
||||||
|
.Add(scrollView)
|
||||||
|
.End()
|
||||||
|
.AddGroup(B_VERTICAL, 10)
|
||||||
|
.Add(new BStringView("", TR("Preferred languages")))
|
||||||
|
.Add(scrollViewEnabled)
|
||||||
|
.End()
|
||||||
|
.View());
|
||||||
|
|
||||||
BView* countryTab = new BView(TR("Country"), B_WILL_DRAW);
|
BView* countryTab = new BView(TR("Country"), B_WILL_DRAW);
|
||||||
countryTab->SetLayout(new BGroupLayout(B_VERTICAL, 0));
|
countryTab->SetLayout(new BGroupLayout(B_VERTICAL, 0));
|
||||||
|
|
||||||
{
|
BListView* listView = new BListView("country", B_SINGLE_SELECTION_LIST);
|
||||||
BListView* listView = new BListView("country", B_SINGLE_SELECTION_LIST);
|
scrollView = new BScrollView("scroller", listView,
|
||||||
BScrollView* scrollView = new BScrollView("scroller",
|
B_WILL_DRAW | B_FRAME_EVENTS, false, true);
|
||||||
listView, B_WILL_DRAW | B_FRAME_EVENTS, false, true);
|
listView->SetSelectionMessage(new BMessage(kMsgCountrySelection));
|
||||||
listView->SetSelectionMessage(new BMessage(kMsgCountrySelection));
|
|
||||||
|
|
||||||
// get all available countries from ICU
|
// get all available countries from ICU
|
||||||
// Use DateFormat::getAvailableLocale so we get only the one we can
|
// Use DateFormat::getAvailableLocale so we get only the one we can
|
||||||
// use. Maybe check the NumberFormat one and see if there is more.
|
// use. Maybe check the NumberFormat one and see if there is more.
|
||||||
int32_t localeCount;
|
int32_t localeCount;
|
||||||
const Locale* currentLocale
|
const Locale* currentLocale = Locale::getAvailableLocales(localeCount);
|
||||||
= Locale::getAvailableLocales(localeCount);
|
|
||||||
|
|
||||||
for (int index = 0; index < localeCount; index++)
|
for (int index = 0; index < localeCount; index++) {
|
||||||
{
|
UnicodeString countryFullName;
|
||||||
UnicodeString countryFullName;
|
BString string;
|
||||||
BString str;
|
BStringByteSink sink(&string);
|
||||||
BStringByteSink bbs(&str);
|
currentLocale[index].getDisplayName(countryFullName);
|
||||||
currentLocale[index].getDisplayName(countryFullName);
|
countryFullName.toUTF8(sink);
|
||||||
countryFullName.toUTF8(bbs);
|
|
||||||
LanguageListItem* si
|
|
||||||
= new LanguageListItem(str, currentLocale[index].getName());
|
|
||||||
listView->AddItem(si);
|
|
||||||
if (strcmp(currentLocale[index].getName(),
|
|
||||||
defaultCountry->Code()) == 0)
|
|
||||||
listView->Select(listView->CountItems() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: find a real solution intead of this hack
|
LanguageListItem* item
|
||||||
listView->SetExplicitMinSize(BSize(300, B_SIZE_UNSET));
|
= new LanguageListItem(string, currentLocale[index].getName());
|
||||||
|
listView->AddItem(item);
|
||||||
fFormatView = new FormatView(defaultCountry);
|
if (!strcmp(currentLocale[index].getName(), defaultCountry->Code()))
|
||||||
|
listView->Select(listView->CountItems() - 1);
|
||||||
countryTab->AddChild(BLayoutBuilder::Group<>(B_HORIZONTAL, 5)
|
|
||||||
.AddGroup(B_VERTICAL, 3)
|
|
||||||
.Add(scrollView)
|
|
||||||
.End()
|
|
||||||
.Add(fFormatView)
|
|
||||||
.View()
|
|
||||||
);
|
|
||||||
|
|
||||||
listView->ScrollToSelection();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: find a real solution intead of this hack
|
||||||
|
listView->SetExplicitMinSize(BSize(300, B_SIZE_UNSET));
|
||||||
|
|
||||||
|
fFormatView = new FormatView(defaultCountry);
|
||||||
|
|
||||||
|
countryTab->AddChild(BLayoutBuilder::Group<>(B_HORIZONTAL, 5)
|
||||||
|
.AddGroup(B_VERTICAL, 3)
|
||||||
|
.Add(scrollView)
|
||||||
|
.End()
|
||||||
|
.Add(fFormatView)
|
||||||
|
.View()
|
||||||
|
);
|
||||||
|
|
||||||
|
listView->ScrollToSelection();
|
||||||
|
|
||||||
tabView->AddTab(languageTab);
|
tabView->AddTab(languageTab);
|
||||||
tabView->AddTab(countryTab);
|
tabView->AddTab(countryTab);
|
||||||
|
|
||||||
@@ -269,9 +265,9 @@ LocaleWindow::MessageReceived(BMessage* message)
|
|||||||
// from them anyway
|
// from them anyway
|
||||||
if (fPreferredListView->Superitem(
|
if (fPreferredListView->Superitem(
|
||||||
fPreferredListView->FullListItemAt(index)) != NULL) {
|
fPreferredListView->FullListItemAt(index)) != NULL) {
|
||||||
update.AddString("language", static_cast<LanguageListItem*>(
|
LanguageListItem* item = static_cast<LanguageListItem*>(
|
||||||
fPreferredListView->FullListItemAt(index))
|
fPreferredListView->FullListItemAt(index));
|
||||||
->LanguageCode());
|
update.AddString("language", item->LanguageCode());
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
@@ -285,16 +281,19 @@ LocaleWindow::MessageReceived(BMessage* message)
|
|||||||
// Country selection changed.
|
// Country selection changed.
|
||||||
// Get the new selected country from the ListView and send it to the
|
// Get the new selected country from the ListView and send it to the
|
||||||
// main app event handler.
|
// main app event handler.
|
||||||
void* ptr;
|
void* listView;
|
||||||
message->FindPointer("source", &ptr);
|
if (message->FindPointer("source", &listView) != B_OK)
|
||||||
BListView* countryList = static_cast<BListView*>(ptr);
|
break;
|
||||||
LanguageListItem* lli = static_cast<LanguageListItem*>
|
|
||||||
|
BListView* countryList = static_cast<BListView*>(listView);
|
||||||
|
|
||||||
|
LanguageListItem* item = static_cast<LanguageListItem*>
|
||||||
(countryList->ItemAt(countryList->CurrentSelection()));
|
(countryList->ItemAt(countryList->CurrentSelection()));
|
||||||
BMessage newMessage(kMsgSettingsChanged);
|
BMessage newMessage(kMsgSettingsChanged);
|
||||||
newMessage.AddString("country",lli->LanguageCode());
|
newMessage.AddString("country", item->LanguageCode());
|
||||||
be_app_messenger.SendMessage(&newMessage);
|
be_app_messenger.SendMessage(&newMessage);
|
||||||
|
|
||||||
BCountry* country = new BCountry(lli->LanguageCode());
|
BCountry* country = new BCountry(item->LanguageCode());
|
||||||
fFormatView->SetCountry(country);
|
fFormatView->SetCountry(country);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -303,9 +302,8 @@ LocaleWindow::MessageReceived(BMessage* message)
|
|||||||
{
|
{
|
||||||
int32 index = 0;
|
int32 index = 0;
|
||||||
if (message->FindInt32("index", &index) == B_OK) {
|
if (message->FindInt32("index", &index) == B_OK) {
|
||||||
LanguageListItem* listItem
|
LanguageListItem* listItem = static_cast<LanguageListItem*>
|
||||||
= static_cast<LanguageListItem*>
|
(fLanguageListView->RemoveItem(index));
|
||||||
(fLanguageListView->RemoveItem(index));
|
|
||||||
fPreferredListView->AddItem(listItem);
|
fPreferredListView->AddItem(listItem);
|
||||||
fPreferredListView->Invoke(fMsgPrefLanguagesChanged);
|
fPreferredListView->Invoke(fMsgPrefLanguagesChanged);
|
||||||
}
|
}
|
||||||
@@ -319,9 +317,8 @@ LocaleWindow::MessageReceived(BMessage* message)
|
|||||||
|
|
||||||
int32 index = 0;
|
int32 index = 0;
|
||||||
if (message->FindInt32("index", &index) == B_OK) {
|
if (message->FindInt32("index", &index) == B_OK) {
|
||||||
LanguageListItem* listItem
|
LanguageListItem* listItem = static_cast<LanguageListItem*>
|
||||||
= static_cast<LanguageListItem*>
|
(fPreferredListView->RemoveItem(index));
|
||||||
(fPreferredListView->RemoveItem(index));
|
|
||||||
fLanguageListView->AddItem(listItem);
|
fLanguageListView->AddItem(listItem);
|
||||||
fLanguageListView->SortItems(compare_list_items);
|
fLanguageListView->SortItems(compare_list_items);
|
||||||
// see previous comment on sort using collators
|
// see previous comment on sort using collators
|
||||||
|
|||||||
@@ -35,28 +35,32 @@
|
|||||||
#define TR_CONTEXT "TimeFormatSettings"
|
#define TR_CONTEXT "TimeFormatSettings"
|
||||||
|
|
||||||
|
|
||||||
BMessage*
|
|
||||||
MenuMessage(const char* format, BMenuField* field)
|
|
||||||
{
|
|
||||||
BMessage* msg = new BMessage(kMenuMessage);
|
|
||||||
msg->AddPointer("dest", field);
|
|
||||||
msg->AddString("format", format);
|
|
||||||
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class DateMenuItem: public BMenuItem {
|
class DateMenuItem: public BMenuItem {
|
||||||
public:
|
public:
|
||||||
DateMenuItem(const char* label, const char* code,
|
DateMenuItem(const char* label, const char* code, BMenuField* field)
|
||||||
BMenuField* field)
|
:
|
||||||
:
|
BMenuItem(label, _MenuMessage(code, field))
|
||||||
BMenuItem(label, MenuMessage(code, field))
|
{
|
||||||
{
|
fIcuCode = code;
|
||||||
fIcuCode = code;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
BString fIcuCode;
|
const BString& ICUCode() const
|
||||||
|
{
|
||||||
|
return fIcuCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static BMessage* _MenuMessage(const char* format, BMenuField* field)
|
||||||
|
{
|
||||||
|
BMessage* msg = new BMessage(kMenuMessage);
|
||||||
|
msg->AddPointer("dest", field);
|
||||||
|
msg->AddString("format", format);
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BString fIcuCode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -116,6 +120,20 @@ CreateDateMenu(BMenuField** field, bool longFormat = true)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
IsSpecialDateChar(char charToTest)
|
||||||
|
{
|
||||||
|
static const char* specials = "dDeEFgMLyYu";
|
||||||
|
for (int i = 0; i < 11; i++)
|
||||||
|
if (charToTest == specials[i])
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
FormatView::FormatView(BCountry* country)
|
FormatView::FormatView(BCountry* country)
|
||||||
:
|
:
|
||||||
BView("WindowsSettingsView", B_FRAME_EVENTS),
|
BView("WindowsSettingsView", B_FRAME_EVENTS),
|
||||||
@@ -335,130 +353,6 @@ FormatView::FormatView(BCountry* country)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool IsSpecialDateChar(char charToTest)
|
|
||||||
{
|
|
||||||
static const char* specials = "dDeEFgMLyYu";
|
|
||||||
for (int i = 0; i < 11; i++)
|
|
||||||
if (charToTest == specials[i])
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Get the date format from ICU and set the date fields accordingly
|
|
||||||
void
|
|
||||||
FormatView::_ParseDateFormat()
|
|
||||||
{
|
|
||||||
// TODO parse the short date too
|
|
||||||
BString dateFormatString;
|
|
||||||
fCountry->DateFormat(dateFormatString, true);
|
|
||||||
const char* dateFormat = dateFormatString.String();
|
|
||||||
|
|
||||||
// Travel trough the string and parse it
|
|
||||||
const char* parsePointer = dateFormat;
|
|
||||||
const char* fieldBegin = dateFormat;
|
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
fieldBegin = parsePointer;
|
|
||||||
while (*parsePointer == *(parsePointer + 1)) parsePointer++ ;
|
|
||||||
parsePointer++;
|
|
||||||
BString str;
|
|
||||||
str.Append(fieldBegin, parsePointer - fieldBegin);
|
|
||||||
|
|
||||||
fLongDateString[i] = str;
|
|
||||||
|
|
||||||
BMenu* subMenu;
|
|
||||||
bool isFound = false;
|
|
||||||
for (int subMenuIndex = 0; subMenuIndex < 3; subMenuIndex++) {
|
|
||||||
subMenu = fLongDateMenu[i]->Menu()->SubmenuAt(subMenuIndex);
|
|
||||||
BMenuItem* item;
|
|
||||||
for (int itemIndex = 0; (item = subMenu->ItemAt(itemIndex)) != NULL;
|
|
||||||
itemIndex++) {
|
|
||||||
if (static_cast<DateMenuItem*>(item)->fIcuCode == str) {
|
|
||||||
item->SetMarked(true);
|
|
||||||
fLongDateMenu[i]->MenuItem()->SetLabel(item->Label());
|
|
||||||
isFound = true;
|
|
||||||
} else
|
|
||||||
item->SetMarked(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isFound)
|
|
||||||
fLongDateMenu[i]->MenuItem()->SetLabel(str.Append("*"));
|
|
||||||
|
|
||||||
fieldBegin = parsePointer;
|
|
||||||
while ((!IsSpecialDateChar(*parsePointer)) && *parsePointer != '\0'
|
|
||||||
&& *(parsePointer - 1) >= 0) {
|
|
||||||
if (*parsePointer == '\'') {
|
|
||||||
parsePointer++;
|
|
||||||
while (*parsePointer != '\'') parsePointer++;
|
|
||||||
}
|
|
||||||
parsePointer++;
|
|
||||||
}
|
|
||||||
str.Truncate(0);
|
|
||||||
str.Append(fieldBegin, parsePointer - fieldBegin);
|
|
||||||
fLongDateSeparator[i]->SetText(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Short date is a bit more tricky, we want to extract the separator
|
|
||||||
dateFormatString.Truncate(0);
|
|
||||||
fCountry->DateFormat(dateFormatString, false);
|
|
||||||
dateFormat = dateFormatString.String();
|
|
||||||
|
|
||||||
// Travel trough the string and parse it
|
|
||||||
parsePointer = dateFormat;
|
|
||||||
fieldBegin = dateFormat;
|
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
fieldBegin = parsePointer;
|
|
||||||
while (*parsePointer == *(parsePointer + 1)) parsePointer++ ;
|
|
||||||
parsePointer++;
|
|
||||||
BString str;
|
|
||||||
str.Append(fieldBegin, parsePointer - fieldBegin);
|
|
||||||
|
|
||||||
fLongDateString[i] = str;
|
|
||||||
|
|
||||||
BMenu* subMenu;
|
|
||||||
bool isFound = false;
|
|
||||||
for (int subMenuIndex = 0; subMenuIndex < 3; subMenuIndex++) {
|
|
||||||
subMenu = fDateMenu[i]->Menu()->SubmenuAt(subMenuIndex);
|
|
||||||
BMenuItem* item;
|
|
||||||
for (int itemIndex = 0; (item = subMenu->ItemAt(itemIndex)) != NULL;
|
|
||||||
itemIndex++) {
|
|
||||||
if (static_cast<DateMenuItem*>(item)->fIcuCode == str) {
|
|
||||||
item->SetMarked(true);
|
|
||||||
fDateMenu[i]->MenuItem()->SetLabel(item->Label());
|
|
||||||
isFound = true;
|
|
||||||
} else
|
|
||||||
item->SetMarked(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isFound) {
|
|
||||||
fDateMenu[i]->MenuItem()->SetLabel(
|
|
||||||
str.Append(TR(" (unknown format)")));
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldBegin = parsePointer;
|
|
||||||
while ((!IsSpecialDateChar(*parsePointer)) && *parsePointer != '\0'
|
|
||||||
&& *(parsePointer - 1) >= 0) {
|
|
||||||
if (*parsePointer == '\'') {
|
|
||||||
parsePointer++;
|
|
||||||
while (*parsePointer != '\'') parsePointer++;
|
|
||||||
}
|
|
||||||
parsePointer++;
|
|
||||||
}
|
|
||||||
if (parsePointer - fieldBegin > 0) {
|
|
||||||
str.Truncate(0);
|
|
||||||
str.Append(fieldBegin, parsePointer - fieldBegin);
|
|
||||||
fSeparatorMenuField->MenuItem()->SetLabel(str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
FormatView::AttachedToWindow()
|
FormatView::AttachedToWindow()
|
||||||
{
|
{
|
||||||
@@ -480,32 +374,6 @@ FormatView::AttachedToWindow()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
FormatView::_UpdateLongDateFormatString()
|
|
||||||
{
|
|
||||||
BString newDateFormat;
|
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
newDateFormat.Append(fLongDateString[i]);
|
|
||||||
newDateFormat.Append(fLongDateSeparator[i]->Text());
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO save this in the settings preflet and make the roster load it back
|
|
||||||
fCountry->SetDateFormat(newDateFormat.String());
|
|
||||||
|
|
||||||
newDateFormat.Truncate(0);
|
|
||||||
|
|
||||||
newDateFormat.Append(fDateString[0]);
|
|
||||||
newDateFormat.Append(fSeparatorMenuField->MenuItem()->Label());
|
|
||||||
newDateFormat.Append(fDateString[1]);
|
|
||||||
newDateFormat.Append(fSeparatorMenuField->MenuItem()->Label());
|
|
||||||
newDateFormat.Append(fDateString[2]);
|
|
||||||
|
|
||||||
// TODO save this in the settings preflet and make the roster load it back
|
|
||||||
fCountry->SetDateFormat(newDateFormat.String(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
FormatView::MessageReceived(BMessage* message)
|
FormatView::MessageReceived(BMessage* message)
|
||||||
{
|
{
|
||||||
@@ -569,7 +437,7 @@ FormatView::MessageReceived(BMessage* message)
|
|||||||
Window()->PostMessage(kSettingsContentsModified);
|
Window()->PostMessage(kSettingsContentsModified);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
BView::MessageReceived(message);
|
BView::MessageReceived(message);
|
||||||
}
|
}
|
||||||
@@ -624,20 +492,6 @@ FormatView::Revert()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
FormatView::_SendNotices()
|
|
||||||
{
|
|
||||||
// Make the notification message and send it to the tracker:
|
|
||||||
/*
|
|
||||||
BMessage notificationMessage;
|
|
||||||
notificationMessage.AddInt32("TimeFormatSeparator", (int32)settings.TimeFormatSeparator());
|
|
||||||
notificationMessage.AddInt32("DateOrderFormat", (int32)settings.DateOrderFormat());
|
|
||||||
notificationMessage.AddBool("24HrClock", settings.ClockIs24Hr());
|
|
||||||
tracker->SendNotices(kDateFormatChanged, ¬ificationMessage);
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
FormatView::SetCountry(BCountry* country)
|
FormatView::SetCountry(BCountry* country)
|
||||||
{
|
{
|
||||||
@@ -722,3 +576,155 @@ FormatView::_UpdateExamples()
|
|||||||
fNumberFormatExampleView->SetText(u_errorName((UErrorCode)Error));
|
fNumberFormatExampleView->SetText(u_errorName((UErrorCode)Error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
FormatView::_SendNotices()
|
||||||
|
{
|
||||||
|
// Make the notification message and send it to the tracker:
|
||||||
|
/*
|
||||||
|
BMessage notificationMessage;
|
||||||
|
notificationMessage.AddInt32("TimeFormatSeparator", (int32)settings.TimeFormatSeparator());
|
||||||
|
notificationMessage.AddInt32("DateOrderFormat", (int32)settings.DateOrderFormat());
|
||||||
|
notificationMessage.AddBool("24HrClock", settings.ClockIs24Hr());
|
||||||
|
tracker->SendNotices(kDateFormatChanged, ¬ificationMessage);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! Get the date format from ICU and set the date fields accordingly
|
||||||
|
void
|
||||||
|
FormatView::_ParseDateFormat()
|
||||||
|
{
|
||||||
|
// TODO parse the short date too
|
||||||
|
BString dateFormatString;
|
||||||
|
fCountry->DateFormat(dateFormatString, true);
|
||||||
|
const char* dateFormat = dateFormatString.String();
|
||||||
|
|
||||||
|
// Travel trough the string and parse it
|
||||||
|
const char* parsePointer = dateFormat;
|
||||||
|
const char* fieldBegin = dateFormat;
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
fieldBegin = parsePointer;
|
||||||
|
while (*parsePointer == *(parsePointer + 1)) parsePointer++ ;
|
||||||
|
parsePointer++;
|
||||||
|
BString str;
|
||||||
|
str.Append(fieldBegin, parsePointer - fieldBegin);
|
||||||
|
|
||||||
|
fLongDateString[i] = str;
|
||||||
|
|
||||||
|
BMenu* subMenu;
|
||||||
|
bool isFound = false;
|
||||||
|
for (int subMenuIndex = 0; subMenuIndex < 3; subMenuIndex++) {
|
||||||
|
subMenu = fLongDateMenu[i]->Menu()->SubmenuAt(subMenuIndex);
|
||||||
|
BMenuItem* item;
|
||||||
|
for (int itemIndex = 0; (item = subMenu->ItemAt(itemIndex)) != NULL;
|
||||||
|
itemIndex++) {
|
||||||
|
if (static_cast<DateMenuItem*>(item)->ICUCode() == str) {
|
||||||
|
item->SetMarked(true);
|
||||||
|
fLongDateMenu[i]->MenuItem()->SetLabel(item->Label());
|
||||||
|
isFound = true;
|
||||||
|
} else
|
||||||
|
item->SetMarked(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isFound)
|
||||||
|
fLongDateMenu[i]->MenuItem()->SetLabel(str.Append("*"));
|
||||||
|
|
||||||
|
fieldBegin = parsePointer;
|
||||||
|
while ((!IsSpecialDateChar(*parsePointer)) && *parsePointer != '\0'
|
||||||
|
&& *(parsePointer - 1) >= 0) {
|
||||||
|
if (*parsePointer == '\'') {
|
||||||
|
parsePointer++;
|
||||||
|
while (*parsePointer != '\'') parsePointer++;
|
||||||
|
}
|
||||||
|
parsePointer++;
|
||||||
|
}
|
||||||
|
str.Truncate(0);
|
||||||
|
str.Append(fieldBegin, parsePointer - fieldBegin);
|
||||||
|
fLongDateSeparator[i]->SetText(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Short date is a bit more tricky, we want to extract the separator
|
||||||
|
dateFormatString.Truncate(0);
|
||||||
|
fCountry->DateFormat(dateFormatString, false);
|
||||||
|
dateFormat = dateFormatString.String();
|
||||||
|
|
||||||
|
// Travel trough the string and parse it
|
||||||
|
parsePointer = dateFormat;
|
||||||
|
fieldBegin = dateFormat;
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
fieldBegin = parsePointer;
|
||||||
|
while (*parsePointer == *(parsePointer + 1)) parsePointer++ ;
|
||||||
|
parsePointer++;
|
||||||
|
BString str;
|
||||||
|
str.Append(fieldBegin, parsePointer - fieldBegin);
|
||||||
|
|
||||||
|
fLongDateString[i] = str;
|
||||||
|
|
||||||
|
BMenu* subMenu;
|
||||||
|
bool isFound = false;
|
||||||
|
for (int subMenuIndex = 0; subMenuIndex < 3; subMenuIndex++) {
|
||||||
|
subMenu = fDateMenu[i]->Menu()->SubmenuAt(subMenuIndex);
|
||||||
|
BMenuItem* item;
|
||||||
|
for (int itemIndex = 0; (item = subMenu->ItemAt(itemIndex)) != NULL;
|
||||||
|
itemIndex++) {
|
||||||
|
if (static_cast<DateMenuItem*>(item)->ICUCode() == str) {
|
||||||
|
item->SetMarked(true);
|
||||||
|
fDateMenu[i]->MenuItem()->SetLabel(item->Label());
|
||||||
|
isFound = true;
|
||||||
|
} else
|
||||||
|
item->SetMarked(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isFound) {
|
||||||
|
fDateMenu[i]->MenuItem()->SetLabel(
|
||||||
|
str.Append(TR(" (unknown format)")));
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldBegin = parsePointer;
|
||||||
|
while ((!IsSpecialDateChar(*parsePointer)) && *parsePointer != '\0'
|
||||||
|
&& *(parsePointer - 1) >= 0) {
|
||||||
|
if (*parsePointer == '\'') {
|
||||||
|
parsePointer++;
|
||||||
|
while (*parsePointer != '\'') parsePointer++;
|
||||||
|
}
|
||||||
|
parsePointer++;
|
||||||
|
}
|
||||||
|
if (parsePointer - fieldBegin > 0) {
|
||||||
|
str.Truncate(0);
|
||||||
|
str.Append(fieldBegin, parsePointer - fieldBegin);
|
||||||
|
fSeparatorMenuField->MenuItem()->SetLabel(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
FormatView::_UpdateLongDateFormatString()
|
||||||
|
{
|
||||||
|
BString newDateFormat;
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
newDateFormat.Append(fLongDateString[i]);
|
||||||
|
newDateFormat.Append(fLongDateSeparator[i]->Text());
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO save this in the settings preflet and make the roster load it back
|
||||||
|
fCountry->SetDateFormat(newDateFormat.String());
|
||||||
|
|
||||||
|
newDateFormat.Truncate(0);
|
||||||
|
|
||||||
|
newDateFormat.Append(fDateString[0]);
|
||||||
|
newDateFormat.Append(fSeparatorMenuField->MenuItem()->Label());
|
||||||
|
newDateFormat.Append(fDateString[1]);
|
||||||
|
newDateFormat.Append(fSeparatorMenuField->MenuItem()->Label());
|
||||||
|
newDateFormat.Append(fDateString[2]);
|
||||||
|
|
||||||
|
// TODO save this in the settings preflet and make the roster load it back
|
||||||
|
fCountry->SetDateFormat(newDateFormat.String(), false);
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
* Copyright 2009, Adrien Destugues, [email protected]. All rights reserved.
|
* Copyright 2009, Adrien Destugues, [email protected]. All rights reserved.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
#ifndef __TIMEFORMATSETTINGS_H__
|
#ifndef TIME_FORMAT_SETTINGS_H
|
||||||
#define __TIMEFORMATSETTINGS_H__
|
#define TIME_FORMAT_SETTINGS_H
|
||||||
|
|
||||||
|
|
||||||
#include <Box.h>
|
#include <Box.h>
|
||||||
@@ -35,54 +35,54 @@ const uint32 kMenuMessage = 'FRMT';
|
|||||||
|
|
||||||
class FormatView : public BView {
|
class FormatView : public BView {
|
||||||
public:
|
public:
|
||||||
FormatView(BCountry* country);
|
FormatView(BCountry* country);
|
||||||
|
|
||||||
virtual void MessageReceived(BMessage* message);
|
virtual void MessageReceived(BMessage* message);
|
||||||
virtual void AttachedToWindow();
|
virtual void AttachedToWindow();
|
||||||
|
|
||||||
virtual void SetDefaults();
|
virtual void SetDefaults();
|
||||||
virtual bool IsDefaultable() const;
|
virtual bool IsDefaultable() const;
|
||||||
virtual void Revert();
|
virtual void Revert();
|
||||||
virtual void SetCountry(BCountry* country);
|
virtual void SetCountry(BCountry* country);
|
||||||
virtual void RecordRevertSettings();
|
virtual void RecordRevertSettings();
|
||||||
virtual bool IsRevertable() const;
|
virtual bool IsRevertable() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _UpdateExamples();
|
void _UpdateExamples();
|
||||||
void _SendNotices();
|
void _SendNotices();
|
||||||
void _ParseDateFormat();
|
void _ParseDateFormat();
|
||||||
void _UpdateLongDateFormatString();
|
void _UpdateLongDateFormatString();
|
||||||
|
|
||||||
BRadioButton* f24HrRadioButton;
|
private:
|
||||||
BRadioButton* f12HrRadioButton;
|
BRadioButton* f24HrRadioButton;
|
||||||
|
BRadioButton* f12HrRadioButton;
|
||||||
|
|
||||||
BMenuField* fLongDateMenu[4];
|
BMenuField* fLongDateMenu[4];
|
||||||
BString fLongDateString[4];
|
BString fLongDateString[4];
|
||||||
BTextControl* fLongDateSeparator[4];
|
BTextControl* fLongDateSeparator[4];
|
||||||
BMenuField* fDateMenu[3];
|
BMenuField* fDateMenu[3];
|
||||||
BString fDateString[3];
|
BString fDateString[3];
|
||||||
|
|
||||||
BMenuField* fSeparatorMenuField;
|
BMenuField* fSeparatorMenuField;
|
||||||
|
|
||||||
BStringView* fLongDateExampleView;
|
BStringView* fLongDateExampleView;
|
||||||
BStringView* fShortDateExampleView;
|
BStringView* fShortDateExampleView;
|
||||||
BStringView* fLongTimeExampleView;
|
BStringView* fLongTimeExampleView;
|
||||||
BStringView* fShortTimeExampleView;
|
BStringView* fShortTimeExampleView;
|
||||||
BStringView* fNumberFormatExampleView;
|
BStringView* fNumberFormatExampleView;
|
||||||
|
|
||||||
bool f24HrClock;
|
bool f24HrClock;
|
||||||
|
|
||||||
FormatSeparator fSeparator;
|
FormatSeparator fSeparator;
|
||||||
BString fDateFormat;
|
BString fDateFormat;
|
||||||
|
|
||||||
BCountry* fCountry;
|
BCountry* fCountry;
|
||||||
|
|
||||||
BBox* fDateBox;
|
BBox* fDateBox;
|
||||||
BBox* fTimeBox;
|
BBox* fTimeBox;
|
||||||
BBox* fNumbersBox;
|
BBox* fNumbersBox;
|
||||||
BBox* fCurrencyBox;
|
BBox* fCurrencyBox;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif // TIME_FORMAT_SETTINGS_H
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user