tcp: Fix 64 bit build with debugging features enabled.
[haiku.git] / src / preferences / locale / LocaleWindow.cpp
blobef8c2de6cecc7955ff37d4e45acefd45953d44eb
1 /*
2 * Copyright 2005-2010, Axel Dörfler, axeld@pinc-software.de.
3 * Copyright 2009-2010, Adrien Destugues <pulkomandy@gmail.com>.
4 * All rights reserved. Distributed under the terms of the MIT License.
5 */
8 #include "LocaleWindow.h"
10 #include <iostream>
12 #include <Alert.h>
13 #include <Application.h>
14 #include <Button.h>
15 #include <Catalog.h>
16 #include <CheckBox.h>
17 #include <ControlLook.h>
18 #include <FormattingConventions.h>
19 #include <GroupLayout.h>
20 #include <LayoutBuilder.h>
21 #include <Locale.h>
22 #include <MutableLocaleRoster.h>
23 #include <Screen.h>
24 #include <ScrollView.h>
25 #include <StringView.h>
26 #include <TabView.h>
27 #include <UnicodeChar.h>
29 #include "FormatSettingsView.h"
30 #include "LocalePreflet.h"
31 #include "LanguageListView.h"
34 using BPrivate::MutableLocaleRoster;
37 #undef B_TRANSLATION_CONTEXT
38 #define B_TRANSLATION_CONTEXT "Locale Preflet Window"
41 static const uint32 kMsgLanguageInvoked = 'LaIv';
42 static const uint32 kMsgLanguageDragged = 'LaDr';
43 static const uint32 kMsgPreferredLanguageInvoked = 'PLIv';
44 static const uint32 kMsgPreferredLanguageDragged = 'PLDr';
45 static const uint32 kMsgPreferredLanguageDeleted = 'PLDl';
46 static const uint32 kMsgConventionsSelection = 'csel';
47 static const uint32 kMsgDefaults = 'dflt';
49 static const uint32 kMsgPreferredLanguagesChanged = 'lang';
50 static const uint32 kMsgFilesystemTranslationChanged = 'fsys';
53 static int
54 compare_typed_list_items(const BListItem* _a, const BListItem* _b)
56 static BCollator collator;
58 LanguageListItem* a = (LanguageListItem*)_a;
59 LanguageListItem* b = (LanguageListItem*)_b;
61 return collator.Compare(a->Text(), b->Text());
65 // #pragma mark -
67 LocaleWindow::LocaleWindow()
69 BWindow(BRect(0, 0, 0, 0), B_TRANSLATE_SYSTEM_NAME("Locale"), B_TITLED_WINDOW,
70 B_QUIT_ON_WINDOW_CLOSE | B_ASYNCHRONOUS_CONTROLS
71 | B_AUTO_UPDATE_SIZE_LIMITS),
72 fInitialConventionsItem(NULL),
73 fDefaultConventionsItem(NULL),
74 fFilesystemTranslationCheckbox(NULL)
76 SetLayout(new BGroupLayout(B_HORIZONTAL));
78 float spacing = be_control_look->DefaultItemSpacing();
80 BTabView* tabView = new BTabView("tabview", B_WIDTH_FROM_WIDEST);
81 BGroupView* languageTab = new BGroupView(B_TRANSLATE("Language"),
82 B_HORIZONTAL, spacing);
84 // first list: available languages
85 fLanguageListView = new LanguageListView("available",
86 B_MULTIPLE_SELECTION_LIST);
87 BScrollView* scrollView = new BScrollView("scroller", fLanguageListView,
88 B_WILL_DRAW | B_FRAME_EVENTS, true, true);
90 fLanguageListView->SetInvocationMessage(new BMessage(kMsgLanguageInvoked));
91 fLanguageListView->SetDragMessage(new BMessage(kMsgLanguageDragged));
92 fLanguageListView->SetGlobalDropTargetIndicator(true);
94 BFont font;
95 fLanguageListView->GetFont(&font);
97 // Fill the language list from the LocaleRoster data
98 BMessage availableLanguages;
99 if (BLocaleRoster::Default()->GetAvailableLanguages(&availableLanguages)
100 == B_OK) {
101 BString currentID;
102 LanguageListItem* currentToplevelItem = NULL;
104 for (int i = 0; availableLanguages.FindString("language", i, &currentID)
105 == B_OK; i++) {
106 // Now get the human-readable, native name for each language
107 BString name;
108 BLanguage currentLanguage(currentID.String());
109 currentLanguage.GetNativeName(name);
111 // TODO: the following block fails to detect a couple of language
112 // names as containing glyphs we can't render. Why's that?
113 bool hasGlyphs[name.CountChars()];
114 font.GetHasGlyphs(name.String(), name.CountChars(), hasGlyphs);
115 for (int32 i = 0; i < name.CountChars(); ++i) {
116 if (!hasGlyphs[i]) {
117 // replace by name translated to current language
118 currentLanguage.GetName(name);
119 break;
123 LanguageListItem* item;
124 if (currentLanguage.IsCountrySpecific()) {
125 item = new LanguageListItemWithFlag(name, currentID.String(),
126 currentLanguage.Code(), currentLanguage.CountryCode());
127 } else {
128 item = new LanguageListItem(name, currentID.String(),
129 currentLanguage.Code());
131 if (currentLanguage.IsCountrySpecific()
132 && currentToplevelItem != NULL
133 && currentToplevelItem->Code() == item->Code()) {
134 fLanguageListView->AddUnder(item, currentToplevelItem);
135 } else {
136 // This is a generic language, add it at top-level
137 fLanguageListView->AddItem(item);
138 item->SetExpanded(false);
139 currentToplevelItem = item;
143 fLanguageListView->FullListSortItems(compare_typed_list_items);
144 } else {
145 BAlert* alert = new BAlert("Error",
146 B_TRANSLATE("Unable to find the available languages! You can't "
147 "use this preflet!"),
148 B_TRANSLATE("OK"), NULL, NULL,
149 B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_STOP_ALERT);
150 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
151 alert->Go();
154 // Second list: active languages
155 fPreferredListView = new LanguageListView("preferred",
156 B_MULTIPLE_SELECTION_LIST);
157 BScrollView* scrollViewEnabled = new BScrollView("scroller",
158 fPreferredListView, B_WILL_DRAW | B_FRAME_EVENTS, true, true);
160 fPreferredListView->SetInvocationMessage(
161 new BMessage(kMsgPreferredLanguageInvoked));
162 fPreferredListView->SetDeleteMessage(
163 new BMessage(kMsgPreferredLanguageDeleted));
164 fPreferredListView->SetDragMessage(
165 new BMessage(kMsgPreferredLanguageDragged));
167 BLayoutBuilder::Group<>(languageTab)
168 .AddGroup(B_VERTICAL, spacing)
169 .Add(new BStringView("", B_TRANSLATE("Available languages")))
170 .Add(scrollView)
171 .End()
172 .AddGroup(B_VERTICAL, spacing)
173 .Add(new BStringView("", B_TRANSLATE("Preferred languages")))
174 .Add(scrollViewEnabled)
175 .End()
176 .SetInsets(spacing, spacing, spacing, spacing);
178 BView* countryTab = new BView(B_TRANSLATE("Formatting"), B_WILL_DRAW);
179 countryTab->SetLayout(new BGroupLayout(B_VERTICAL, 0));
181 fConventionsListView = new LanguageListView("formatting",
182 B_SINGLE_SELECTION_LIST);
183 scrollView = new BScrollView("scroller", fConventionsListView,
184 B_WILL_DRAW | B_FRAME_EVENTS, true, true);
185 fConventionsListView->SetSelectionMessage(
186 new BMessage(kMsgConventionsSelection));
188 // get all available formatting conventions (by language)
189 BFormattingConventions initialConventions;
190 BLocale::Default()->GetFormattingConventions(&initialConventions);
191 BString conventionsID;
192 fInitialConventionsItem = NULL;
193 LanguageListItem* currentToplevelItem = NULL;
194 for (int i = 0;
195 availableLanguages.FindString("language", i, &conventionsID) == B_OK;
196 i++) {
197 BFormattingConventions conventions(conventionsID);
198 BString conventionsName;
199 conventions.GetName(conventionsName);
201 LanguageListItem* item;
202 if (conventions.AreCountrySpecific()) {
203 item = new LanguageListItemWithFlag(conventionsName, conventionsID,
204 conventions.LanguageCode(), conventions.CountryCode());
205 } else {
206 item = new LanguageListItem(conventionsName, conventionsID,
207 conventions.LanguageCode());
209 if (!strcmp(conventionsID, "en_US"))
210 fDefaultConventionsItem = item;
211 if (conventions.AreCountrySpecific()
212 && currentToplevelItem != NULL
213 && currentToplevelItem->Code() == item->Code()) {
214 if (!strcmp(conventionsID, initialConventions.ID())) {
215 fConventionsListView->Expand(currentToplevelItem);
216 fInitialConventionsItem = item;
218 fConventionsListView->AddUnder(item, currentToplevelItem);
219 } else {
220 // This conventions-item isn't country-specific, add it at top-level
221 fConventionsListView->AddItem(item);
222 item->SetExpanded(false);
223 currentToplevelItem = item;
224 if (!strcmp(conventionsID, initialConventions.ID()))
225 fInitialConventionsItem = item;
229 fConventionsListView->FullListSortItems(compare_typed_list_items);
230 if (fInitialConventionsItem != NULL) {
231 fConventionsListView->Select(fConventionsListView->IndexOf(
232 fInitialConventionsItem));
235 fConventionsListView->SetExplicitMinSize(BSize(20 * be_plain_font->Size(),
236 B_SIZE_UNSET));
238 fFormatView = new FormatSettingsView();
240 countryTab->AddChild(BLayoutBuilder::Group<>(B_HORIZONTAL, spacing)
241 .AddGroup(B_VERTICAL, 3)
242 .Add(scrollView)
243 .End()
244 .Add(fFormatView)
245 .SetInsets(spacing, spacing, spacing, spacing));
247 BView* optionsTab = new BView(B_TRANSLATE("Options"), B_WILL_DRAW);
248 optionsTab->SetLayout(new BGroupLayout(B_VERTICAL, 0));
250 fFilesystemTranslationCheckbox = new BCheckBox("filesystemTranslation",
251 B_TRANSLATE("Translate application and folder names in Deskbar and Tracker."),
252 new BMessage(kMsgFilesystemTranslationChanged));
254 fFilesystemTranslationCheckbox->SetValue(
255 BLocaleRoster::Default()->IsFilesystemTranslationPreferred());
257 optionsTab->AddChild(BLayoutBuilder::Group<>(B_VERTICAL, spacing)
258 .Add(fFilesystemTranslationCheckbox)
259 .AddGlue()
260 .SetInsets(spacing, spacing, spacing, spacing));
262 tabView->AddTab(languageTab);
263 tabView->AddTab(countryTab);
264 tabView->AddTab(optionsTab);
266 BButton* button
267 = new BButton(B_TRANSLATE("Defaults"), new BMessage(kMsgDefaults));
269 fRevertButton
270 = new BButton(B_TRANSLATE("Revert"), new BMessage(kMsgRevert));
271 fRevertButton->SetEnabled(false);
273 BLayoutBuilder::Group<>(this, B_VERTICAL, spacing)
274 .Add(tabView)
275 .AddGroup(B_HORIZONTAL, spacing)
276 .Add(button)
277 .Add(fRevertButton)
278 .AddGlue()
279 .End()
280 .SetInsets(spacing, spacing, spacing, spacing)
281 .End();
283 _Refresh(true);
284 _SettingsReverted();
285 CenterOnScreen();
289 LocaleWindow::~LocaleWindow()
294 void
295 LocaleWindow::MessageReceived(BMessage* message)
297 switch (message->what) {
298 case B_LOCALE_CHANGED:
299 fFormatView->MessageReceived(message);
300 break;
302 case kMsgDefaults:
303 _Defaults();
304 break;
306 case kMsgRevert:
308 _Revert();
309 fFormatView->Revert();
310 fConventionsListView->DeselectAll();
311 if (fInitialConventionsItem != NULL) {
312 BListItem* superitem
313 = fConventionsListView->Superitem(fInitialConventionsItem);
314 if (superitem != NULL)
315 superitem->SetExpanded(true);
316 fConventionsListView->Select(fConventionsListView->IndexOf(
317 fInitialConventionsItem));
318 fConventionsListView->ScrollToSelection();
320 _SettingsReverted();
321 break;
324 case kMsgSettingsChanged:
325 _SettingsChanged();
326 break;
328 case kMsgLanguageDragged:
330 void* target = NULL;
331 if (message->FindPointer("drop_target", &target) != B_OK
332 || target != fPreferredListView)
333 break;
335 // Add from available languages to preferred languages
336 int32 dropIndex;
337 if (message->FindInt32("drop_index", &dropIndex) != B_OK)
338 dropIndex = fPreferredListView->CountItems();
340 int32 index = 0;
341 for (int32 i = 0; message->FindInt32("index", i, &index) == B_OK;
342 i++) {
343 LanguageListItem* item = static_cast<LanguageListItem*>(
344 fLanguageListView->ItemAt(index));
345 _InsertPreferredLanguage(item, dropIndex++);
347 break;
349 case kMsgLanguageInvoked:
351 int32 index = 0;
352 for (int32 i = 0; message->FindInt32("index", i, &index) == B_OK;
353 i++) {
354 LanguageListItem* item = static_cast<LanguageListItem*>(
355 fLanguageListView->ItemAt(index));
356 _InsertPreferredLanguage(item);
358 break;
361 case kMsgPreferredLanguageDragged:
363 void* target = NULL;
364 if (fPreferredListView->CountItems() == 1
365 || message->FindPointer("drop_target", &target) != B_OK)
366 break;
368 if (target == fPreferredListView) {
369 // change ordering
370 int32 dropIndex = message->FindInt32("drop_index");
371 int32 index = 0;
372 for (int32 i = 0;
373 message->FindInt32("index", i, &index) == B_OK;
374 i++, dropIndex++) {
375 if (dropIndex > index) {
376 dropIndex--;
377 index -= i;
379 BListItem* item = fPreferredListView->RemoveItem(index);
380 fPreferredListView->AddItem(item, dropIndex);
383 _PreferredLanguagesChanged();
384 break;
387 // supposed to fall through - remove item
389 case kMsgPreferredLanguageDeleted:
390 case kMsgPreferredLanguageInvoked:
392 if (fPreferredListView->CountItems() == 1)
393 break;
395 // Remove from preferred languages
396 int32 index = 0;
397 for (int32 i = 0; message->FindInt32("index", i, &index) == B_OK;
398 i++) {
399 delete fPreferredListView->RemoveItem(index - i);
401 if (message->what == kMsgPreferredLanguageDeleted) {
402 int32 count = fPreferredListView->CountItems();
403 fPreferredListView->Select(
404 index < count ? index : count - 1);
408 _PreferredLanguagesChanged();
409 break;
412 case kMsgConventionsSelection:
414 // Country selection changed.
415 // Get the new selected country from the ListView and send it to the
416 // main app event handler.
417 void* listView;
418 if (message->FindPointer("source", &listView) != B_OK)
419 break;
421 BListView* conventionsList = static_cast<BListView*>(listView);
422 if (conventionsList == NULL)
423 break;
425 LanguageListItem* item = static_cast<LanguageListItem*>
426 (conventionsList->ItemAt(conventionsList->CurrentSelection()));
427 if (item == NULL)
428 break;
430 BFormattingConventions conventions(item->ID());
431 MutableLocaleRoster::Default()->SetDefaultFormattingConventions(
432 conventions);
434 _SettingsChanged();
435 fFormatView->Refresh();
436 break;
439 case kMsgFilesystemTranslationChanged:
441 MutableLocaleRoster::Default()->SetFilesystemTranslationPreferred(
442 fFilesystemTranslationCheckbox->Value());
444 BAlert* alert = new BAlert(B_TRANSLATE("Locale"),
445 B_TRANSLATE("Deskbar and Tracker need to be restarted for this "
446 "change to take effect. Would you like to restart them now?"),
447 B_TRANSLATE("Cancel"), B_TRANSLATE("Restart"), NULL,
448 B_WIDTH_FROM_WIDEST, B_IDEA_ALERT);
449 alert->SetShortcut(0, B_ESCAPE);
450 alert->Go(new BInvoker(new BMessage(kMsgRestartTrackerAndDeskbar),
451 NULL, be_app));
452 break;
455 default:
456 BWindow::MessageReceived(message);
457 break;
462 bool
463 LocaleWindow::QuitRequested()
465 return true;
469 void
470 LocaleWindow::Show()
472 BWindow::Show();
474 Lock();
475 if (IsLocked()) {
476 fConventionsListView->ScrollToSelection();
477 Unlock();
482 void
483 LocaleWindow::_SettingsChanged()
485 fRevertButton->SetEnabled(fFormatView->IsReversible() || _IsReversible());
489 void
490 LocaleWindow::_SettingsReverted()
492 fRevertButton->SetEnabled(false);
496 bool
497 LocaleWindow::_IsReversible() const
499 BMessage preferredLanguages;
500 BLocaleRoster::Default()->GetPreferredLanguages(&preferredLanguages);
502 return !preferredLanguages.HasSameData(fInitialPreferredLanguages);
506 void
507 LocaleWindow::_PreferredLanguagesChanged()
509 BMessage preferredLanguages;
510 int index = 0;
511 while (index < fPreferredListView->CountItems()) {
512 LanguageListItem* item = static_cast<LanguageListItem*>(
513 fPreferredListView->ItemAt(index));
514 if (item != NULL)
515 preferredLanguages.AddString("language", item->ID());
516 index++;
518 MutableLocaleRoster::Default()->SetPreferredLanguages(&preferredLanguages);
520 _EnableDisableLanguages();
524 void
525 LocaleWindow::_EnableDisableLanguages()
527 DisableUpdates();
529 for (int32 i = 0; i < fLanguageListView->FullListCountItems(); i++) {
530 LanguageListItem* item = static_cast<LanguageListItem*>(
531 fLanguageListView->FullListItemAt(i));
533 bool enable = fPreferredListView->ItemForLanguageID(item->ID()) == NULL;
534 if (item->IsEnabled() != enable) {
535 item->SetEnabled(enable);
537 int32 visibleIndex = fLanguageListView->IndexOf(item);
538 if (visibleIndex >= 0) {
539 if (!enable)
540 fLanguageListView->Deselect(visibleIndex);
541 fLanguageListView->InvalidateItem(visibleIndex);
546 EnableUpdates();
550 void
551 LocaleWindow::_Refresh(bool setInitial)
553 BMessage preferredLanguages;
554 BLocaleRoster::Default()->GetPreferredLanguages(&preferredLanguages);
555 if (setInitial)
556 fInitialPreferredLanguages = preferredLanguages;
558 _SetPreferredLanguages(preferredLanguages);
562 void
563 LocaleWindow::_Revert()
565 _SetPreferredLanguages(fInitialPreferredLanguages);
569 void
570 LocaleWindow::_SetPreferredLanguages(const BMessage& languages)
572 DisableUpdates();
574 // Delete all existing items
575 for (int32 index = fPreferredListView->CountItems(); index-- > 0; ) {
576 delete fPreferredListView->ItemAt(index);
578 fPreferredListView->MakeEmpty();
580 BString languageID;
581 for (int32 index = 0;
582 languages.FindString("language", index, &languageID) == B_OK; index++) {
583 int32 listIndex;
584 LanguageListItem* item = fLanguageListView->ItemForLanguageID(
585 languageID.String(), &listIndex);
586 if (item != NULL) {
587 // We found the item we were looking for, now copy it to
588 // the other list
589 fPreferredListView->AddItem(new LanguageListItem(*item));
593 _EnableDisableLanguages();
594 EnableUpdates();
598 void
599 LocaleWindow::_InsertPreferredLanguage(LanguageListItem* item, int32 atIndex)
601 if (item == NULL || fPreferredListView->ItemForLanguageID(
602 item->ID().String()) != NULL)
603 return;
605 if (atIndex == -1)
606 atIndex = fPreferredListView->CountItems();
608 BLanguage language(item->Code());
609 LanguageListItem* baseItem
610 = fPreferredListView->ItemForLanguageCode(language.Code(), &atIndex);
612 DisableUpdates();
614 fPreferredListView->AddItem(new LanguageListItem(*item), atIndex);
616 // Replace other languages sharing the same base
617 if (baseItem != NULL) {
618 fPreferredListView->RemoveItem(baseItem);
619 delete baseItem;
622 _PreferredLanguagesChanged();
624 EnableUpdates();
628 void
629 LocaleWindow::_Defaults()
631 BMessage preferredLanguages;
632 preferredLanguages.AddString("language", "en");
633 MutableLocaleRoster::Default()->SetPreferredLanguages(&preferredLanguages);
634 _SetPreferredLanguages(preferredLanguages);
636 BFormattingConventions conventions("en_US");
637 MutableLocaleRoster::Default()->SetDefaultFormattingConventions(
638 conventions);
640 fConventionsListView->DeselectAll();
641 if (fDefaultConventionsItem != NULL) {
642 BListItem* superitem
643 = fConventionsListView->Superitem(fDefaultConventionsItem);
644 if (superitem != NULL && !superitem->IsExpanded())
645 fConventionsListView->Expand(superitem);
646 fConventionsListView->Select(fConventionsListView->IndexOf(
647 fDefaultConventionsItem));
648 fConventionsListView->ScrollToSelection();